builtins-array-gen.cc 150 KB
Newer Older
1 2 3 4
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/builtins/builtins-iterator-gen.h"
6
#include "src/builtins/builtins-string-gen.h"
7
#include "src/builtins/builtins-typedarray-gen.h"
8 9 10
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
11
#include "src/factory-inl.h"
12
#include "src/frame-constants.h"
13

14 15
#include "src/builtins/builtins-array-gen.h"

16 17 18
namespace v8 {
namespace internal {

19
using Node = compiler::Node;
20

21 22 23 24 25 26 27
ArrayBuiltinsAssembler::ArrayBuiltinsAssembler(
    compiler::CodeAssemblerState* state)
    : CodeStubAssembler(state),
      k_(this, MachineRepresentation::kTagged),
      a_(this, MachineRepresentation::kTagged),
      to_(this, MachineRepresentation::kTagged, SmiConstant(0)),
      fully_spec_compliant_(this, {&k_, &a_, &to_}) {}
28

29 30 31
void ArrayBuiltinsAssembler::FindResultGenerator() {
  a_.Bind(UndefinedConstant());
}
32

33 34 35 36 37 38 39 40 41
Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
  Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
                       this_arg(), k_value, k, o());
  Label false_continue(this), return_true(this);
  BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
  BIND(&return_true);
  ReturnFromBuiltin(k_value);
  BIND(&false_continue);
  return a();
42 43
  }

44 45 46
  void ArrayBuiltinsAssembler::FindIndexResultGenerator() {
    a_.Bind(SmiConstant(-1));
  }
47

48
  Node* ArrayBuiltinsAssembler::FindIndexProcessor(Node* k_value, Node* k) {
49 50 51 52 53 54 55 56 57 58
    Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
                         this_arg(), k_value, k, o());
    Label false_continue(this), return_true(this);
    BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
    BIND(&return_true);
    ReturnFromBuiltin(k);
    BIND(&false_continue);
    return a();
  }

59 60 61
  void ArrayBuiltinsAssembler::ForEachResultGenerator() {
    a_.Bind(UndefinedConstant());
  }
62

63
  Node* ArrayBuiltinsAssembler::ForEachProcessor(Node* k_value, Node* k) {
64 65 66 67 68
    CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(),
           k_value, k, o());
    return a();
  }

69 70 71
  void ArrayBuiltinsAssembler::SomeResultGenerator() {
    a_.Bind(FalseConstant());
  }
72

73
  Node* ArrayBuiltinsAssembler::SomeProcessor(Node* k_value, Node* k) {
74 75 76 77
    Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
                         this_arg(), k_value, k, o());
    Label false_continue(this), return_true(this);
    BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
78
    BIND(&return_true);
79
    ReturnFromBuiltin(TrueConstant());
80
    BIND(&false_continue);
81 82 83
    return a();
  }

84 85 86
  void ArrayBuiltinsAssembler::EveryResultGenerator() {
    a_.Bind(TrueConstant());
  }
87

88
  Node* ArrayBuiltinsAssembler::EveryProcessor(Node* k_value, Node* k) {
89 90 91 92
    Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
                         this_arg(), k_value, k, o());
    Label true_continue(this), return_false(this);
    BranchIfToBooleanIsTrue(value, &true_continue, &return_false);
93
    BIND(&return_false);
94
    ReturnFromBuiltin(FalseConstant());
95
    BIND(&true_continue);
96 97 98
    return a();
  }

99 100 101
  void ArrayBuiltinsAssembler::ReduceResultGenerator() {
    return a_.Bind(this_arg());
  }
102

103
  Node* ArrayBuiltinsAssembler::ReduceProcessor(Node* k_value, Node* k) {
104
    VARIABLE(result, MachineRepresentation::kTagged);
105 106 107 108 109 110
    Label done(this, {&result}), initial(this);
    GotoIf(WordEqual(a(), TheHoleConstant()), &initial);
    result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
                       UndefinedConstant(), a(), k_value, k, o()));
    Goto(&done);

111
    BIND(&initial);
112 113 114
    result.Bind(k_value);
    Goto(&done);

115
    BIND(&done);
116 117 118
    return result.value();
  }

119
  void ArrayBuiltinsAssembler::ReducePostLoopAction() {
120 121
    Label ok(this);
    GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok);
122
    ThrowTypeError(context(), MessageTemplate::kReduceNoInitial);
123
    BIND(&ok);
124 125
  }

126
  void ArrayBuiltinsAssembler::FilterResultGenerator() {
127
    // 7. Let A be ArraySpeciesCreate(O, 0).
128 129
    // This version of ArraySpeciesCreate will create with the correct
    // ElementsKind in the fast case.
130
    GenerateArraySpeciesCreate();
131 132
  }

133
  Node* ArrayBuiltinsAssembler::FilterProcessor(Node* k_value, Node* k) {
134 135 136
    // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)).
    Node* selected = CallJS(CodeFactory::Call(isolate()), context(),
                            callbackfn(), this_arg(), k_value, k, o());
137
    Label true_continue(this, &to_), false_continue(this);
138
    BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue);
139
    BIND(&true_continue);
140 141
    // iii. If selected is true, then...
    {
142 143 144 145 146 147 148
      Label after_work(this, &to_);
      Node* kind = nullptr;

      // If a() is a JSArray, we can have a fast path.
      Label fast(this);
      Label runtime(this);
      Label object_push_pre(this), object_push(this), double_push(this);
149
      BranchIfFastJSArray(a(), context(), &fast, &runtime);
150 151 152

      BIND(&fast);
      {
153
        GotoIf(SmiNotEqual(LoadJSArrayLength(a()), to_.value()), &runtime);
154
        kind = EnsureArrayPushable(a(), &runtime);
155
        GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
156 157
               &object_push_pre);

158
        BuildAppendJSArray(HOLEY_SMI_ELEMENTS, a(), k_value, &runtime);
159 160 161 162 163
        Goto(&after_work);
      }

      BIND(&object_push_pre);
      {
164 165
        Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push,
               &object_push);
166 167 168 169
      }

      BIND(&object_push);
      {
170
        BuildAppendJSArray(HOLEY_ELEMENTS, a(), k_value, &runtime);
171 172 173 174 175
        Goto(&after_work);
      }

      BIND(&double_push);
      {
176
        BuildAppendJSArray(HOLEY_DOUBLE_ELEMENTS, a(), k_value, &runtime);
177 178 179 180 181 182 183 184 185 186
        Goto(&after_work);
      }

      BIND(&runtime);
      {
        // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
        CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(),
                    k_value);
        Goto(&after_work);
      }
187

188 189 190 191 192 193
      BIND(&after_work);
      {
        // 2. Increase to by 1.
        to_.Bind(NumberInc(to_.value()));
        Goto(&false_continue);
      }
194
    }
195
    BIND(&false_continue);
196 197 198
    return a();
  }

199 200 201
  void ArrayBuiltinsAssembler::MapResultGenerator() {
    GenerateArraySpeciesCreate(len_);
  }
202

203
  void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() {
204
    // 6. Let A be ? TypedArraySpeciesCreate(O, len).
205 206 207 208 209 210
    TNode<JSTypedArray> original_array = CAST(o());
    TNode<Smi> length = CAST(len_);
    const char* method_name = "%TypedArray%.prototype.map";

    TypedArrayBuiltinsAssembler typedarray_asm(state());
    TNode<JSTypedArray> a = typedarray_asm.SpeciesCreateByLength(
211
        context(), original_array, length, method_name);
212
    // In the Spec and our current implementation, the length check is already
213 214 215 216
    // performed in TypedArraySpeciesCreate.
    CSA_ASSERT(this,
               SmiLessThanOrEqual(
                   len_, LoadObjectField(a, JSTypedArray::kLengthOffset)));
217 218 219
    fast_typed_array_target_ =
        Word32Equal(LoadInstanceType(LoadElements(original_array)),
                    LoadInstanceType(LoadElements(a)));
220 221 222
    a_.Bind(a);
  }

223 224
  Node* ArrayBuiltinsAssembler::SpecCompliantMapProcessor(Node* k_value,
                                                          Node* k) {
225 226
    //  i. Let kValue be ? Get(O, Pk). Performed by the caller of
    //  SpecCompliantMapProcessor.
227 228 229
    // ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
    Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
                                callbackfn(), this_arg(), k_value, k, o());
230

231 232
    // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
    CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mapped_value);
233
    return a();
234 235
  }

236
  Node* ArrayBuiltinsAssembler::FastMapProcessor(Node* k_value, Node* k) {
237 238
    //  i. Let kValue be ? Get(O, Pk). Performed by the caller of
    //  FastMapProcessor.
239 240 241
    // ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
    Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
                                callbackfn(), this_arg(), k_value, k, o());
242

243 244
    // mode is SMI_PARAMETERS because k has tagged representation.
    ParameterMode mode = SMI_PARAMETERS;
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
    Label runtime(this), finished(this);
    Label transition_pre(this), transition_smi_fast(this),
        transition_smi_double(this);
    Label array_not_smi(this), array_fast(this), array_double(this);

    Node* kind = LoadMapElementsKind(LoadMap(a()));
    Node* elements = LoadElements(a());
    GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS), &array_not_smi);
    TryStoreArrayElement(HOLEY_SMI_ELEMENTS, mode, &transition_pre, elements, k,
                         mapped_value);
    Goto(&finished);

    BIND(&transition_pre);
    {
      // array is smi. Value is either tagged or a heap number.
      CSA_ASSERT(this, TaggedIsNotSmi(mapped_value));
      GotoIf(IsHeapNumberMap(LoadMap(mapped_value)), &transition_smi_double);
      Goto(&transition_smi_fast);
    }
264

265
    BIND(&array_not_smi);
266
    {
267 268
      Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &array_double,
             &array_fast);
269 270
    }

271
    BIND(&transition_smi_fast);
272
    {
273 274 275 276 277 278 279 280 281 282
      // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
      Node* const native_context = LoadNativeContext(context());
      Node* const fast_map = LoadContextElement(
          native_context, Context::JS_ARRAY_HOLEY_ELEMENTS_MAP_INDEX);

      // Since this transition is only a map change, just do it right here.
      // Since a() doesn't have an allocation site, it's safe to do the
      // map store directly, otherwise I'd call TransitionElementsKind().
      StoreMap(a(), fast_map);
      Goto(&array_fast);
283 284
    }

285
    BIND(&array_fast);
286
    {
287 288
      TryStoreArrayElement(HOLEY_ELEMENTS, mode, &runtime, elements, k,
                           mapped_value);
289 290 291
      Goto(&finished);
    }

292
    BIND(&transition_smi_double);
293
    {
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
      // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
      Node* const native_context = LoadNativeContext(context());
      Node* const double_map = LoadContextElement(
          native_context, Context::JS_ARRAY_HOLEY_DOUBLE_ELEMENTS_MAP_INDEX);
      CallStub(CodeFactory::TransitionElementsKind(
                   isolate(), HOLEY_SMI_ELEMENTS, HOLEY_DOUBLE_ELEMENTS, true),
               context(), a(), double_map);
      Goto(&array_double);
    }

    BIND(&array_double);
    {
      // TODO(mvstanton): If we use a variable for elements and bind it
      // appropriately, we can avoid an extra load of elements by binding the
      // value only after a transition from smi to double.
      elements = LoadElements(a());
      // If the mapped_value isn't a number, this will bail out to the runtime
      // to make the transition.
      TryStoreArrayElement(HOLEY_DOUBLE_ELEMENTS, mode, &runtime, elements, k,
                           mapped_value);
314 315 316 317 318
      Goto(&finished);
    }

    BIND(&runtime);
    {
319 320 321
      // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
      CallRuntime(Runtime::kCreateDataProperty, context(), a(), k,
                  mapped_value);
322 323 324 325
      Goto(&finished);
    }

    BIND(&finished);
326 327 328
    return a();
  }

329
  // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map.
330
  Node* ArrayBuiltinsAssembler::TypedArrayMapProcessor(Node* k_value, Node* k) {
331 332 333
    // 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »).
    Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
                                callbackfn(), this_arg(), k_value, k, o());
334 335
    Label fast(this), slow(this), done(this), detached(this, Label::kDeferred);

336
    // 8. d. Perform ? Set(A, Pk, mapped_value, true).
337 338 339 340 341 342
    // Since we know that A is a TypedArray, this always ends up in
    // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then
    // tc39.github.io/ecma262/#sec-integerindexedelementset .
    Branch(fast_typed_array_target_, &fast, &slow);

    BIND(&fast);
343 344 345 346 347 348 349 350 351 352 353
    // #sec-integerindexedelementset
    // 5. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let
    // numValue be ? ToBigInt(v).
    // 6. Otherwise, let numValue be ? ToNumber(value).
    Node* num_value;
    if (source_elements_kind_ == BIGINT64_ELEMENTS ||
        source_elements_kind_ == BIGUINT64_ELEMENTS) {
      num_value = ToBigInt(context(), mapped_value);
    } else {
      num_value = ToNumber_Inline(context(), mapped_value);
    }
354
    // The only way how this can bailout is because of a detached buffer.
355
    EmitElementStore(a(), k, num_value, false, source_elements_kind_,
356 357
                     KeyedAccessStoreMode::STANDARD_STORE, &detached,
                     context());
358 359 360
    Goto(&done);

    BIND(&slow);
361
    CallRuntime(Runtime::kSetProperty, context(), a(), k, mapped_value,
362
                SmiConstant(LanguageMode::kStrict));
363 364 365
    Goto(&done);

    BIND(&detached);
366
    // tc39.github.io/ecma262/#sec-integerindexedelementset
367
    // 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
368
    ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
369 370 371 372 373

    BIND(&done);
    return a();
  }

374 375 376
  void ArrayBuiltinsAssembler::NullPostLoopAction() {}

  void ArrayBuiltinsAssembler::ReturnFromBuiltin(Node* value) {
377 378 379 380 381 382 383 384 385
    if (argc_ == nullptr) {
      Return(value);
    } else {
      // argc_ doesn't include the receiver, so it has to be added back in
      // manually.
      PopAndReturn(IntPtrAdd(argc_, IntPtrConstant(1)), value);
    }
  }

386
  void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinBody(
387 388
      TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
      Node* this_arg, Node* new_target, TNode<IntPtrT> argc) {
389 390 391 392 393
    context_ = context;
    receiver_ = receiver;
    new_target_ = new_target;
    callbackfn_ = callbackfn;
    this_arg_ = this_arg;
394
    argc_ = argc;
395
  }
396

397
  void ArrayBuiltinsAssembler::GenerateIteratingArrayBuiltinBody(
398 399
      const char* name, const BuiltinResultGenerator& generator,
      const CallResultProcessor& processor, const PostLoopAction& action,
400
      const Callable& slow_case_continuation,
401
      MissingPropertyMode missing_property_mode, ForEachDirection direction) {
402
    Label non_array(this), array_changes(this, {&k_, &a_, &to_});
403 404 405 406

    // TODO(danno): Seriously? Do we really need to throw the exact error
    // message on null and undefined so that the webkit tests pass?
    Label throw_null_undefined_exception(this, Label::kDeferred);
407
    GotoIf(IsNullOrUndefined(receiver()), &throw_null_undefined_exception);
408 409 410 411 412

    // By the book: taken directly from the ECMAScript 2015 specification

    // 1. Let O be ToObject(this value).
    // 2. ReturnIfAbrupt(O)
413
    o_ = ToObject(context(), receiver());
414 415 416

    // 3. Let len be ToLength(Get(O, "length")).
    // 4. ReturnIfAbrupt(len).
417
    TVARIABLE(Number, merged_length);
418
    Label has_length(this, &merged_length), not_js_array(this);
419
    GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), &not_js_array);
420
    merged_length = LoadJSArrayLength(CAST(o()));
421
    Goto(&has_length);
422
    BIND(&not_js_array);
423
    Node* len_property =
424
        GetProperty(context(), o(), isolate()->factory()->length_string());
425
    merged_length = ToLength_Inline(context(), len_property);
426
    Goto(&has_length);
427
    BIND(&has_length);
428
    len_ = merged_length.value();
429 430 431 432

    // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
    Label type_exception(this, Label::kDeferred);
    Label done(this);
433 434
    GotoIf(TaggedIsSmi(callbackfn()), &type_exception);
    Branch(IsCallableMap(LoadMap(callbackfn())), &done, &type_exception);
435

436
    BIND(&throw_null_undefined_exception);
437
    ThrowTypeError(context(), MessageTemplate::kCalledOnNullOrUndefined, name);
438

439
    BIND(&type_exception);
440 441
    ThrowTypeError(context(), MessageTemplate::kCalledNonCallable,
                   callbackfn());
442

443
    BIND(&done);
444 445 446 447

    // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
    // [Already done by the arguments adapter]

448 449 450 451
    if (direction == ForEachDirection::kForward) {
      // 7. Let k be 0.
      k_.Bind(SmiConstant(0));
    } else {
452
      k_.Bind(NumberDec(len()));
453
    }
454

455
    generator(this);
456

457 458
    HandleFastElements(processor, action, &fully_spec_compliant_, direction,
                       missing_property_mode);
459

460
    BIND(&fully_spec_compliant_);
461

462 463 464 465
    Node* result =
        CallStub(slow_case_continuation, context(), receiver(), callbackfn(),
                 this_arg(), a_.value(), o(), k_.value(), len(), to_.value());
    ReturnFromBuiltin(result);
466 467
  }

468
  void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinLoopContinuation(
469
      TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
470 471
      Node* this_arg, Node* a, TNode<JSReceiver> o, Node* initial_k,
      TNode<Number> len, Node* to) {
472 473 474 475 476 477 478
    context_ = context;
    this_arg_ = this_arg;
    callbackfn_ = callbackfn;
    a_.Bind(a);
    k_.Bind(initial_k);
    o_ = o;
    len_ = len;
479
    to_.Bind(to);
480 481
  }

482
  void ArrayBuiltinsAssembler::GenerateIteratingTypedArrayBuiltinBody(
483
      const char* name, const BuiltinResultGenerator& generator,
484
      const CallResultProcessor& processor, const PostLoopAction& action,
485
      ForEachDirection direction) {
486
    name_ = name;
487 488 489 490 491 492 493

    // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray

    Label throw_not_typed_array(this, Label::kDeferred),
        throw_detached(this, Label::kDeferred);

    GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
494
    GotoIfNot(HasInstanceType(CAST(receiver_), JS_TYPED_ARRAY_TYPE),
495 496
              &throw_not_typed_array);

497 498 499 500 501
    TNode<JSTypedArray> typed_array = CAST(receiver_);
    o_ = typed_array;

    Node* array_buffer =
        LoadObjectField(typed_array, JSTypedArray::kBufferOffset);
502 503
    GotoIf(IsDetachedBuffer(array_buffer), &throw_detached);

504
    len_ = LoadObjectField<Smi>(typed_array, JSTypedArray::kLengthOffset);
505 506 507 508 509 510 511

    Label throw_not_callable(this, Label::kDeferred);
    Label distinguish_types(this);
    GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable);
    Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types,
           &throw_not_callable);

512
    BIND(&throw_not_typed_array);
513
    ThrowTypeError(context_, MessageTemplate::kNotTypedArray);
514

515
    BIND(&throw_detached);
516
    ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
517

518
    BIND(&throw_not_callable);
519
    ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_);
520 521

    Label unexpected_instance_type(this);
522
    BIND(&unexpected_instance_type);
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
    Unreachable();

    std::vector<int32_t> instance_types = {
#define INSTANCE_TYPE(Type, type, TYPE, ctype, size) FIXED_##TYPE##_ARRAY_TYPE,
        TYPED_ARRAYS(INSTANCE_TYPE)
#undef INSTANCE_TYPE
    };
    std::vector<Label> labels;
    for (size_t i = 0; i < instance_types.size(); ++i) {
      labels.push_back(Label(this));
    }
    std::vector<Label*> label_ptrs;
    for (Label& label : labels) {
      label_ptrs.push_back(&label);
    }

539
    BIND(&distinguish_types);
540

541 542
    generator(this);

543 544 545 546 547
    if (direction == ForEachDirection::kForward) {
      k_.Bind(SmiConstant(0));
    } else {
      k_.Bind(NumberDec(len()));
    }
548
    Node* instance_type = LoadInstanceType(LoadElements(typed_array));
549
    Switch(instance_type, &unexpected_instance_type, instance_types.data(),
550 551 552
           label_ptrs.data(), labels.size());

    for (size_t i = 0; i < labels.size(); ++i) {
553
      BIND(&labels[i]);
554
      Label done(this);
555 556
      source_elements_kind_ = ElementsKindForInstanceType(
          static_cast<InstanceType>(instance_types[i]));
557
      // TODO(tebbi): Silently cancelling the loop on buffer detachment is a
558 559
      // spec violation. Should go to &throw_detached and throw a TypeError
      // instead.
560 561
      VisitAllTypedArrayElements(array_buffer, processor, &done, direction,
                                 typed_array);
562 563
      Goto(&done);
      // No exception, return success
564
      BIND(&done);
565
      action(this);
566
      ReturnFromBuiltin(a_.value());
567 568 569
    }
  }

570
  void ArrayBuiltinsAssembler::GenerateIteratingArrayBuiltinLoopContinuation(
571
      const CallResultProcessor& processor, const PostLoopAction& action,
572
      MissingPropertyMode missing_property_mode, ForEachDirection direction) {
573
    Label loop(this, {&k_, &a_, &to_});
574 575
    Label after_loop(this);
    Goto(&loop);
576
    BIND(&loop);
577
    {
578 579
      if (direction == ForEachDirection::kForward) {
        // 8. Repeat, while k < len
580
        GotoIfNumberGreaterThanOrEqual(k(), len_, &after_loop);
581 582 583
      } else {
        // OR
        // 10. Repeat, while k >= 0
584
        GotoIfNumberGreaterThanOrEqual(SmiConstant(-1), k(), &after_loop);
585
      }
586

587
      Label done_element(this, &to_);
588
      // a. Let Pk be ToString(k).
589 590 591 592
      // We never have to perform a ToString conversion as the above guards
      // guarantee that we have a positive {k} which also is a valid array
      // index in the range [0, 2^32-1).
      CSA_ASSERT(this, IsNumberArrayIndex(k()));
593

594 595 596
      if (missing_property_mode == MissingPropertyMode::kSkip) {
        // b. Let kPresent be HasProperty(O, Pk).
        // c. ReturnIfAbrupt(kPresent).
597 598
        TNode<Oddball> k_present =
            HasProperty(o(), k(), context(), kHasProperty);
599

600
        // d. If kPresent is true, then
601
        GotoIf(IsFalse(k_present), &done_element);
602
      }
603 604 605

      // i. Let kValue be Get(O, Pk).
      // ii. ReturnIfAbrupt(kValue).
606
      Node* k_value = GetProperty(context(), o(), k());
607 608 609

      // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
      // iv. ReturnIfAbrupt(funcResult).
610
      a_.Bind(processor(this, k_value, k()));
611
      Goto(&done_element);
612

613
      BIND(&done_element);
614

615 616 617 618 619 620 621
      if (direction == ForEachDirection::kForward) {
        // e. Increase k by 1.
        k_.Bind(NumberInc(k()));
      } else {
        // e. Decrease k by 1.
        k_.Bind(NumberDec(k()));
      }
622 623
      Goto(&loop);
    }
624
    BIND(&after_loop);
625

626 627
    action(this);
    Return(a_.value());
628 629
  }

630 631
  ElementsKind ArrayBuiltinsAssembler::ElementsKindForInstanceType(
      InstanceType type) {
632 633 634 635 636 637 638 639 640 641 642 643 644
    switch (type) {
#define INSTANCE_TYPE_TO_ELEMENTS_KIND(Type, type, TYPE, ctype, size) \
  case FIXED_##TYPE##_ARRAY_TYPE:                                     \
    return TYPE##_ELEMENTS;

      TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND)
#undef INSTANCE_TYPE_TO_ELEMENTS_KIND

      default:
        UNREACHABLE();
    }
  }

645 646
  void ArrayBuiltinsAssembler::VisitAllTypedArrayElements(
      Node* array_buffer, const CallResultProcessor& processor, Label* detached,
647
      ForEachDirection direction, TNode<JSTypedArray> typed_array) {
648 649 650 651
    VariableList list({&a_, &k_, &to_}, zone());

    FastLoopBody body = [&](Node* index) {
      GotoIf(IsDetachedBuffer(array_buffer), detached);
652
      Node* elements = LoadElements(typed_array);
653 654 655 656 657 658
      Node* base_ptr =
          LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
      Node* external_ptr =
          LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
                          MachineType::Pointer());
      Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
659 660
      Node* value = LoadFixedTypedArrayElementAsTagged(
          data_ptr, index, source_elements_kind_, SMI_PARAMETERS);
661 662 663
      k_.Bind(index);
      a_.Bind(processor(this, value, index));
    };
664 665 666 667 668 669 670 671 672 673 674
    Node* start = SmiConstant(0);
    Node* end = len_;
    IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost;
    int incr = 1;
    if (direction == ForEachDirection::kReverse) {
      std::swap(start, end);
      advance_mode = IndexAdvanceMode::kPre;
      incr = -1;
    }
    BuildFastLoop(list, start, end, body, incr, ParameterMode::SMI_PARAMETERS,
                  advance_mode);
675 676
  }

677 678 679
  void ArrayBuiltinsAssembler::VisitAllFastElementsOneKind(
      ElementsKind kind, const CallResultProcessor& processor,
      Label* array_changed, ParameterMode mode, ForEachDirection direction,
680
      MissingPropertyMode missing_property_mode, TNode<Smi> length) {
681
    Comment("begin VisitAllFastElementsOneKind");
682
    VARIABLE(original_map, MachineRepresentation::kTagged);
683 684
    original_map.Bind(LoadMap(o()));
    VariableList list({&original_map, &a_, &k_, &to_}, zone());
685
    Node* start = IntPtrOrSmiConstant(0, mode);
686
    Node* end = TaggedToParameter(length, mode);
687 688 689 690
    IndexAdvanceMode advance_mode = direction == ForEachDirection::kReverse
                                        ? IndexAdvanceMode::kPre
                                        : IndexAdvanceMode::kPost;
    if (direction == ForEachDirection::kReverse) std::swap(start, end);
691
    BuildFastLoop(
692
        list, start, end,
693 694
        [=, &original_map](Node* index) {
          k_.Bind(ParameterToTagged(index, mode));
695 696
          Label one_element_done(this), hole_element(this),
              process_element(this);
697 698 699 700

          // Check if o's map has changed during the callback. If so, we have to
          // fall back to the slower spec implementation for the rest of the
          // iteration.
701
          Node* o_map = LoadMap(o());
702 703
          GotoIf(WordNotEqual(o_map, original_map.value()), array_changed);

704
          TNode<JSArray> o_array = CAST(o());
705 706
          // Check if o's length has changed during the callback and if the
          // index is now out of range of the new length.
707
          GotoIf(SmiGreaterThanOrEqual(k_.value(), LoadJSArrayLength(o_array)),
708 709 710
                 array_changed);

          // Re-load the elements array. If may have been resized.
711
          Node* elements = LoadElements(o_array);
712 713 714

          // Fast case: load the element directly from the elements FixedArray
          // and call the callback if the element is not the hole.
715 716
          DCHECK(kind == PACKED_ELEMENTS || kind == PACKED_DOUBLE_ELEMENTS);
          int base_size = kind == PACKED_ELEMENTS
717 718 719
                              ? FixedArray::kHeaderSize
                              : (FixedArray::kHeaderSize - kHeapObjectTag);
          Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size);
720
          VARIABLE(value, MachineRepresentation::kTagged);
721
          if (kind == PACKED_ELEMENTS) {
722 723
            value.Bind(LoadObjectField(elements, offset));
            GotoIf(WordEqual(value.value(), TheHoleConstant()), &hole_element);
724 725 726
          } else {
            Node* double_value =
                LoadDoubleWithHoleCheck(elements, offset, &hole_element);
727
            value.Bind(AllocateHeapNumberWithValue(double_value));
728
          }
729
          Goto(&process_element);
730

731
          BIND(&hole_element);
732 733 734 735 736 737 738 739 740 741 742 743 744 745
          if (missing_property_mode == MissingPropertyMode::kSkip) {
            // Check if o's prototype change unexpectedly has elements after
            // the callback in the case of a hole.
            BranchIfPrototypesHaveNoElements(o_map, &one_element_done,
                                             array_changed);
          } else {
            value.Bind(UndefinedConstant());
            Goto(&process_element);
          }
          BIND(&process_element);
          {
            a_.Bind(processor(this, value.value(), k()));
            Goto(&one_element_done);
          }
746
          BIND(&one_element_done);
747
        },
748
        1, mode, advance_mode);
749 750 751
    Comment("end VisitAllFastElementsOneKind");
  }

752 753 754 755
  void ArrayBuiltinsAssembler::HandleFastElements(
      const CallResultProcessor& processor, const PostLoopAction& action,
      Label* slow, ForEachDirection direction,
      MissingPropertyMode missing_property_mode) {
756 757 758 759 760
    Label switch_on_elements_kind(this), fast_elements(this),
        maybe_double_elements(this), fast_double_elements(this);

    Comment("begin HandleFastElements");
    // Non-smi lengths must use the slow path.
761
    GotoIf(TaggedIsNotSmi(len()), slow);
762

763
    BranchIfFastJSArray(o(), context(),
764 765
                        &switch_on_elements_kind, slow);

766
    BIND(&switch_on_elements_kind);
767
    TNode<Smi> smi_len = CAST(len());
768
    // Select by ElementsKind
769
    Node* o_map = LoadMap(o());
770 771
    Node* bit_field2 = LoadMapBitField2(o_map);
    Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
772
    Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
773 774 775
           &maybe_double_elements, &fast_elements);

    ParameterMode mode = OptimalParameterMode();
776
    BIND(&fast_elements);
777
    {
778
      VisitAllFastElementsOneKind(PACKED_ELEMENTS, processor, slow, mode,
779
                                  direction, missing_property_mode, smi_len);
780

781
      action(this);
782

783
      // No exception, return success
784
      ReturnFromBuiltin(a_.value());
785 786
    }

787
    BIND(&maybe_double_elements);
788
    Branch(IsElementsKindGreaterThan(kind, HOLEY_DOUBLE_ELEMENTS), slow,
789
           &fast_double_elements);
790

791
    BIND(&fast_double_elements);
792
    {
793
      VisitAllFastElementsOneKind(PACKED_DOUBLE_ELEMENTS, processor, slow, mode,
794
                                  direction, missing_property_mode, smi_len);
795

796
      action(this);
797

798
      // No exception, return success
799
      ReturnFromBuiltin(a_.value());
800 801
    }
  }
802

803
  // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
804 805
  // This version is specialized to create a zero length array
  // of the elements kind of the input array.
806
  void ArrayBuiltinsAssembler::GenerateArraySpeciesCreate() {
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
    Label runtime(this, Label::kDeferred), done(this);

    TNode<Smi> len = SmiConstant(0);
    TNode<Map> original_map = LoadMap(o());
    GotoIfNot(
        InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
        &runtime);

    GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
              &runtime);

    Node* species_protector = SpeciesProtectorConstant();
    Node* value =
        LoadObjectField(species_protector, PropertyCell::kValueOffset);
    TNode<Smi> const protector_invalid =
        SmiConstant(Isolate::kProtectorInvalid);
    GotoIf(WordEqual(value, protector_invalid), &runtime);

    // Respect the ElementsKind of the input array.
    TNode<Int32T> elements_kind = LoadMapElementsKind(original_map);
    GotoIfNot(IsFastElementsKind(elements_kind), &runtime);
828
    TNode<Context> native_context = LoadNativeContext(context());
829
    TNode<Map> array_map =
830
        LoadJSArrayElementsMap(elements_kind, native_context);
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
    TNode<JSArray> array =
        CAST(AllocateJSArray(GetInitialFastElementsKind(), array_map, len, len,
                             nullptr, CodeStubAssembler::SMI_PARAMETERS));
    a_.Bind(array);

    Goto(&done);

    BIND(&runtime);
    {
      // 5. Let A be ? ArraySpeciesCreate(O, len).
      Node* constructor =
          CallRuntime(Runtime::kArraySpeciesConstructor, context(), o());
      a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(),
                          constructor, len));
      Goto(&fully_spec_compliant_);
    }

    BIND(&done);
  }

  // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
852
  void ArrayBuiltinsAssembler::GenerateArraySpeciesCreate(TNode<Number> len) {
853 854 855
    Label runtime(this, Label::kDeferred), done(this);

    Node* const original_map = LoadMap(o());
856 857 858
    GotoIfNot(
        InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
        &runtime);
859

860 861
    GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
              &runtime);
862 863

    Node* species_protector = SpeciesProtectorConstant();
864 865
    Node* value =
        LoadObjectField(species_protector, PropertyCell::kValueOffset);
866 867 868 869 870 871 872
    Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
    GotoIf(WordEqual(value, protector_invalid), &runtime);

    GotoIfNot(TaggedIsPositiveSmi(len), &runtime);
    GotoIf(SmiAbove(len, SmiConstant(JSArray::kInitialMaxFastElementArray)),
           &runtime);

873
    // We need to be conservative and start with holey because the builtins
874
    // that create output arrays aren't guaranteed to be called for every
875
    // element in the input array (maybe the callback deletes an element).
876 877
    const ElementsKind elements_kind =
        GetHoleyElementsKind(GetInitialFastElementsKind());
878
    TNode<Context> native_context = LoadNativeContext(context());
879
    TNode<Map> array_map =
880
        LoadJSArrayElementsMap(elements_kind, native_context);
881
    a_.Bind(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, len, len, nullptr,
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
                            CodeStubAssembler::SMI_PARAMETERS));

    Goto(&done);

    BIND(&runtime);
    {
      // 5. Let A be ? ArraySpeciesCreate(O, len).
      Node* constructor =
          CallRuntime(Runtime::kArraySpeciesConstructor, context(), o());
      a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(),
                          constructor, len));
      Goto(&fully_spec_compliant_);
    }

    BIND(&done);
  }

899
TF_BUILTIN(ArrayPrototypePop, CodeStubAssembler) {
900 901 902
  TNode<Int32T> argc =
      UncheckedCast<Int32T>(Parameter(BuiltinDescriptor::kArgumentsCount));
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
903
  CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget)));
904 905

  CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
906
  TNode<Object> receiver = args.GetReceiver();
907 908 909 910 911 912 913 914 915 916 917

  Label runtime(this, Label::kDeferred);
  Label fast(this);

  // Only pop in this stub if
  // 1) the array has fast elements
  // 2) the length is writable,
  // 3) the elements backing store isn't copy-on-write,
  // 4) we aren't supposed to shrink the backing store.

  // 1) Check that the array has fast elements.
918
  BranchIfFastJSArray(receiver, context, &fast, &runtime);
919 920 921

  BIND(&fast);
  {
922 923 924 925
    TNode<JSArray> array_receiver = CAST(receiver);
    CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver)));
    Node* length =
        LoadAndUntagObjectField(array_receiver, JSArray::kLengthOffset);
926 927 928
    Label return_undefined(this), fast_elements(this);
    GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);

929
    // 2) Ensure that the length is writable.
930
    EnsureArrayLengthWritable(LoadMap(array_receiver), &runtime);
931 932

    // 3) Check that the elements backing store isn't copy-on-write.
933
    Node* elements = LoadElements(array_receiver);
934 935 936 937 938 939
    GotoIf(WordEqual(LoadMap(elements),
                     LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
           &runtime);

    Node* new_length = IntPtrSub(length, IntPtrConstant(1));

940 941
    // 4) Check that we're not supposed to shrink the backing store, as
    //    implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
942
    Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
943 944 945 946
    GotoIf(IntPtrLessThan(
               IntPtrAdd(IntPtrAdd(new_length, new_length),
                         IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
               capacity),
947 948
           &runtime);

949
    StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset,
950 951
                                   SmiTag(new_length));

952
    Node* elements_kind = LoadMapElementsKind(LoadMap(array_receiver));
953 954 955 956 957 958 959 960 961
    GotoIf(Int32LessThanOrEqual(elements_kind,
                                Int32Constant(TERMINAL_FAST_ELEMENTS_KIND)),
           &fast_elements);

    Node* value = LoadFixedDoubleArrayElement(
        elements, new_length, MachineType::Float64(), 0, INTPTR_PARAMETERS,
        &return_undefined);

    int32_t header_size = FixedDoubleArray::kHeaderSize - kHeapObjectTag;
962 963
    Node* offset = ElementOffsetFromIndex(new_length, HOLEY_DOUBLE_ELEMENTS,
                                          INTPTR_PARAMETERS, header_size);
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
    if (Is64()) {
      Node* double_hole = Int64Constant(kHoleNanInt64);
      StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset,
                          double_hole);
    } else {
      STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32);
      Node* double_hole = Int32Constant(kHoleNanLower32);
      StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
                          double_hole);
      StoreNoWriteBarrier(MachineRepresentation::kWord32, elements,
                          IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
                          double_hole);
    }
    args.PopAndReturn(AllocateHeapNumberWithValue(value));

979
    BIND(&fast_elements);
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999
    {
      Node* value = LoadFixedArrayElement(elements, new_length);
      StoreFixedArrayElement(elements, new_length, TheHoleConstant());
      GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
      args.PopAndReturn(value);
    }

    BIND(&return_undefined);
    { args.PopAndReturn(UndefinedConstant()); }
  }

  BIND(&runtime);
  {
    Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
                                 MachineType::TaggedPointer());
    TailCallStub(CodeFactory::ArrayPop(isolate()), context, target,
                 UndefinedConstant(), argc);
  }
}

1000
TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
1001
  TVARIABLE(IntPtrT, arg_index);
1002 1003 1004 1005 1006 1007 1008 1009
  Label default_label(this, &arg_index);
  Label smi_transition(this);
  Label object_push_pre(this);
  Label object_push(this, &arg_index);
  Label double_push(this, &arg_index);
  Label double_transition(this);
  Label runtime(this, Label::kDeferred);

1010 1011
  // TODO(ishell): use constants from Descriptor once the JSFunction linkage
  // arguments are reordered.
1012 1013 1014
  TNode<Int32T> argc =
      UncheckedCast<Int32T>(Parameter(BuiltinDescriptor::kArgumentsCount));
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
1015
  CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget)));
1016 1017

  CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
1018 1019
  TNode<Object> receiver = args.GetReceiver();
  TNode<JSArray> array_receiver;
1020 1021 1022
  Node* kind = nullptr;

  Label fast(this);
1023
  BranchIfFastJSArray(receiver, context, &fast, &runtime);
1024

1025
  BIND(&fast);
1026
  {
1027
    array_receiver = CAST(receiver);
1028
    arg_index = IntPtrConstant(0);
1029
    kind = EnsureArrayPushable(array_receiver, &runtime);
1030
    GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
1031 1032
           &object_push_pre);

1033 1034
    Node* new_length = BuildAppendJSArray(PACKED_SMI_ELEMENTS, array_receiver,
                                          &args, &arg_index, &smi_transition);
1035 1036 1037 1038 1039 1040 1041
    args.PopAndReturn(new_length);
  }

  // If the argument is not a smi, then use a heavyweight SetProperty to
  // transition the array for only the single next element. If the argument is
  // a smi, the failure is due to some other reason and we should fall back on
  // the most generic implementation for the rest of the array.
1042
  BIND(&smi_transition);
1043
  {
1044
    Node* arg = args.AtIndex(arg_index.value());
1045
    GotoIf(TaggedIsSmi(arg), &default_label);
1046
    Node* length = LoadJSArrayLength(array_receiver);
1047 1048
    // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
    // calling into the runtime to do the elements transition is overkill.
1049
    CallRuntime(Runtime::kSetProperty, context, array_receiver, length, arg,
1050
                SmiConstant(LanguageMode::kStrict));
1051
    Increment(&arg_index);
1052 1053
    // The runtime SetProperty call could have converted the array to dictionary
    // mode, which must be detected to abort the fast-path.
1054
    Node* map = LoadMap(array_receiver);
1055 1056 1057 1058 1059 1060 1061 1062 1063
    Node* bit_field2 = LoadMapBitField2(map);
    Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
    GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
           &default_label);

    GotoIfNotNumber(arg, &object_push);
    Goto(&double_push);
  }

1064
  BIND(&object_push_pre);
1065
  {
1066
    Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push,
1067
           &object_push);
1068 1069
  }

1070
  BIND(&object_push);
1071
  {
1072 1073
    Node* new_length = BuildAppendJSArray(PACKED_ELEMENTS, array_receiver,
                                          &args, &arg_index, &default_label);
1074 1075 1076
    args.PopAndReturn(new_length);
  }

1077
  BIND(&double_push);
1078
  {
1079
    Node* new_length =
1080 1081
        BuildAppendJSArray(PACKED_DOUBLE_ELEMENTS, array_receiver, &args,
                           &arg_index, &double_transition);
1082 1083 1084 1085 1086 1087 1088
    args.PopAndReturn(new_length);
  }

  // If the argument is not a double, then use a heavyweight SetProperty to
  // transition the array for only the single next element. If the argument is
  // a double, the failure is due to some other reason and we should fall back
  // on the most generic implementation for the rest of the array.
1089
  BIND(&double_transition);
1090
  {
1091
    Node* arg = args.AtIndex(arg_index.value());
1092
    GotoIfNumber(arg, &default_label);
1093
    Node* length = LoadJSArrayLength(array_receiver);
1094 1095
    // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
    // calling into the runtime to do the elements transition is overkill.
1096
    CallRuntime(Runtime::kSetProperty, context, array_receiver, length, arg,
1097
                SmiConstant(LanguageMode::kStrict));
1098
    Increment(&arg_index);
1099 1100
    // The runtime SetProperty call could have converted the array to dictionary
    // mode, which must be detected to abort the fast-path.
1101
    Node* map = LoadMap(array_receiver);
1102 1103 1104 1105 1106 1107 1108 1109 1110
    Node* bit_field2 = LoadMapBitField2(map);
    Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
    GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
           &default_label);
    Goto(&object_push);
  }

  // Fallback that stores un-processed arguments using the full, heavyweight
  // SetProperty machinery.
1111
  BIND(&default_label);
1112 1113
  {
    args.ForEach(
1114 1115 1116 1117
        [this, array_receiver, context](Node* arg) {
          Node* length = LoadJSArrayLength(array_receiver);
          CallRuntime(Runtime::kSetProperty, context, array_receiver, length,
                      arg, SmiConstant(LanguageMode::kStrict));
1118
        },
1119
        arg_index.value());
1120
    args.PopAndReturn(LoadJSArrayLength(array_receiver));
1121 1122
  }

1123
  BIND(&runtime);
1124 1125 1126
  {
    Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
                                 MachineType::TaggedPointer());
1127 1128
    TailCallStub(CodeFactory::ArrayPush(isolate()), context, target,
                 UndefinedConstant(), argc);
1129 1130 1131
  }
}

1132
class ArrayPrototypeSliceCodeStubAssembler : public CodeStubAssembler {
1133
 public:
1134 1135
  explicit ArrayPrototypeSliceCodeStubAssembler(
      compiler::CodeAssemblerState* state)
1136 1137
      : CodeStubAssembler(state) {}

1138 1139
  Node* HandleFastSlice(TNode<Context> context, Node* array, Node* from,
                        Node* count, Label* slow) {
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
    VARIABLE(result, MachineRepresentation::kTagged);
    Label done(this);

    GotoIf(TaggedIsNotSmi(from), slow);
    GotoIf(TaggedIsNotSmi(count), slow);

    Label try_fast_arguments(this), try_simple_slice(this);

    Node* map = LoadMap(array);
    GotoIfNot(IsJSArrayMap(map), &try_fast_arguments);

    // Check prototype chain if receiver does not have packed elements
    GotoIfNot(IsPrototypeInitialArrayPrototype(context, map), slow);

1154
    GotoIf(IsNoElementsProtectorCellInvalid(), slow);
1155 1156 1157 1158 1159 1160 1161

    GotoIf(IsSpeciesProtectorCellInvalid(), slow);

    // Bailout if receiver has slow elements.
    Node* elements_kind = LoadMapElementsKind(map);
    GotoIfNot(IsFastElementsKind(elements_kind), &try_simple_slice);

1162 1163 1164 1165 1166
    // Make sure that the length hasn't been changed by side-effect.
    Node* array_length = LoadJSArrayLength(array);
    GotoIf(TaggedIsNotSmi(array_length), slow);
    GotoIf(SmiAbove(SmiAdd(from, count), array_length), slow);

1167 1168
    CSA_ASSERT(this, SmiGreaterThanOrEqual(from, SmiConstant(0)));

1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
    result.Bind(CallStub(CodeFactory::ExtractFastJSArray(isolate()), context,
                         array, from, count));
    Goto(&done);

    BIND(&try_fast_arguments);

    Node* const native_context = LoadNativeContext(context);
    Node* const fast_aliasted_arguments_map = LoadContextElement(
        native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
    GotoIf(WordNotEqual(map, fast_aliasted_arguments_map), &try_simple_slice);

    Node* sloppy_elements = LoadElements(array);
    Node* sloppy_elements_length = LoadFixedArrayBaseLength(sloppy_elements);
    Node* parameter_map_length =
        SmiSub(sloppy_elements_length,
               SmiConstant(SloppyArgumentsElements::kParameterMapStart));
    VARIABLE(index_out, MachineType::PointerRepresentation());

    int max_fast_elements =
        (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize -
         AllocationMemento::kSize) /
        kPointerSize;
    GotoIf(SmiAboveOrEqual(count, SmiConstant(max_fast_elements)),
           &try_simple_slice);

1194 1195
    GotoIf(SmiLessThan(from, SmiConstant(0)), slow);

1196 1197 1198 1199 1200 1201 1202
    Node* end = SmiAdd(from, count);

    Node* unmapped_elements = LoadFixedArrayElement(
        sloppy_elements, SloppyArgumentsElements::kArgumentsIndex);
    Node* unmapped_elements_length =
        LoadFixedArrayBaseLength(unmapped_elements);

1203
    GotoIf(SmiAbove(end, unmapped_elements_length), slow);
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218

    Node* array_map = LoadJSArrayElementsMap(HOLEY_ELEMENTS, native_context);
    result.Bind(AllocateJSArray(HOLEY_ELEMENTS, array_map, count, count,
                                nullptr, SMI_PARAMETERS));

    index_out.Bind(IntPtrConstant(0));
    Node* result_elements = LoadElements(result.value());
    Node* from_mapped = SmiMin(parameter_map_length, from);
    Node* to = SmiMin(parameter_map_length, end);
    Node* arguments_context = LoadFixedArrayElement(
        sloppy_elements, SloppyArgumentsElements::kContextIndex);
    VariableList var_list({&index_out}, zone());
    BuildFastLoop(
        var_list, from_mapped, to,
        [this, result_elements, arguments_context, sloppy_elements,
1219
         unmapped_elements, &index_out](Node* current) {
1220 1221 1222 1223
          Node* context_index = LoadFixedArrayElement(
              sloppy_elements, current,
              kPointerSize * SloppyArgumentsElements::kParameterMapStart,
              SMI_PARAMETERS);
1224 1225 1226
          Label is_the_hole(this), done(this);
          GotoIf(IsTheHole(context_index), &is_the_hole);
          Node* mapped_argument =
1227
              LoadContextElement(arguments_context, SmiUntag(context_index));
1228 1229 1230 1231 1232 1233
          StoreFixedArrayElement(result_elements, index_out.value(),
                                 mapped_argument, SKIP_WRITE_BARRIER);
          Goto(&done);
          BIND(&is_the_hole);
          Node* argument = LoadFixedArrayElement(unmapped_elements, current, 0,
                                                 SMI_PARAMETERS);
1234 1235
          StoreFixedArrayElement(result_elements, index_out.value(), argument,
                                 SKIP_WRITE_BARRIER);
1236 1237
          Goto(&done);
          BIND(&done);
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
          index_out.Bind(IntPtrAdd(index_out.value(), IntPtrConstant(1)));
        },
        1, SMI_PARAMETERS, IndexAdvanceMode::kPost);

    Node* unmapped_from = SmiMin(SmiMax(parameter_map_length, from), end);

    BuildFastLoop(
        var_list, unmapped_from, end,
        [this, unmapped_elements, result_elements, &index_out](Node* current) {
          Node* argument = LoadFixedArrayElement(unmapped_elements, current, 0,
                                                 SMI_PARAMETERS);
          StoreFixedArrayElement(result_elements, index_out.value(), argument,
                                 SKIP_WRITE_BARRIER);
          index_out.Bind(IntPtrAdd(index_out.value(), IntPtrConstant(1)));
        },
        1, SMI_PARAMETERS, IndexAdvanceMode::kPost);

    Goto(&done);

    BIND(&try_simple_slice);
    Node* simple_result = CallRuntime(Runtime::kTrySliceSimpleNonFastElements,
                                      context, array, from, count);
    GotoIfNumber(simple_result, slow);
    result.Bind(simple_result);

    Goto(&done);

    BIND(&done);
    return result.value();
  }

1269 1270
  void CopyOneElement(TNode<Context> context, Node* o, Node* a, Node* p_k,
                      Variable& n) {
1271 1272
    // b. Let kPresent be HasProperty(O, Pk).
    // c. ReturnIfAbrupt(kPresent).
1273
    TNode<Oddball> k_present = HasProperty(o, p_k, context, kHasProperty);
1274 1275 1276

    // d. If kPresent is true, then
    Label done_element(this);
1277
    GotoIf(IsFalse(k_present), &done_element);
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291

    // i. Let kValue be Get(O, Pk).
    // ii. ReturnIfAbrupt(kValue).
    Node* k_value = GetProperty(context, o, p_k);

    // iii. Let status be CreateDataPropertyOrThrow(A, ToString(n), kValue).
    // iv. ReturnIfAbrupt(status).
    CallRuntime(Runtime::kCreateDataProperty, context, a, n.value(), k_value);

    Goto(&done_element);
    BIND(&done_element);
  }
};

1292
TF_BUILTIN(ArrayPrototypeSlice, ArrayPrototypeSliceCodeStubAssembler) {
1293 1294
  Node* const argc =
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1295
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
1296 1297 1298
  Label slow(this, Label::kDeferred), fast_elements_kind(this);

  CodeStubArguments args(this, argc);
1299
  TNode<Object> receiver = args.GetReceiver();
1300

1301
  TVARIABLE(JSReceiver, o);
1302 1303 1304 1305 1306 1307 1308
  VARIABLE(len, MachineRepresentation::kTagged);
  Label length_done(this), generic_length(this), check_arguments_length(this),
      load_arguments_length(this);

  GotoIf(TaggedIsSmi(receiver), &generic_length);
  GotoIfNot(IsJSArray(receiver), &check_arguments_length);

1309 1310 1311
  TNode<JSArray> array_receiver = CAST(receiver);
  o = array_receiver;
  len.Bind(LoadJSArrayLength(array_receiver));
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326

  // Check for the array clone case. There can be no arguments to slice, the
  // array prototype chain must be intact and have no elements, the array has to
  // have fast elements.
  GotoIf(WordNotEqual(argc, IntPtrConstant(0)), &length_done);

  Label clone(this);
  BranchIfFastJSArrayForCopy(receiver, context, &clone, &length_done);
  BIND(&clone);

  args.PopAndReturn(
      CallStub(CodeFactory::CloneFastJSArray(isolate()), context, receiver));

  BIND(&check_arguments_length);

1327
  Node* map = LoadMap(array_receiver);
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
  Node* native_context = LoadNativeContext(context);
  GotoIfContextElementEqual(map, native_context,
                            Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX,
                            &load_arguments_length);
  GotoIfContextElementEqual(map, native_context,
                            Context::SLOW_ALIASED_ARGUMENTS_MAP_INDEX,
                            &load_arguments_length);
  GotoIfContextElementEqual(map, native_context,
                            Context::STRICT_ARGUMENTS_MAP_INDEX,
                            &load_arguments_length);
  GotoIfContextElementEqual(map, native_context,
                            Context::SLOPPY_ARGUMENTS_MAP_INDEX,
                            &load_arguments_length);

  Goto(&generic_length);

  BIND(&load_arguments_length);
  Node* arguments_length =
1346
      LoadObjectField(array_receiver, JSArgumentsObject::kLengthOffset);
1347
  GotoIf(TaggedIsNotSmi(arguments_length), &generic_length);
1348
  o = CAST(receiver);
1349 1350 1351 1352 1353 1354
  len.Bind(arguments_length);
  Goto(&length_done);

  BIND(&generic_length);
  // 1. Let O be ToObject(this value).
  // 2. ReturnIfAbrupt(O).
1355
  o = ToObject(context, receiver);
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367

  // 3. Let len be ToLength(Get(O, "length")).
  // 4. ReturnIfAbrupt(len).
  len.Bind(ToLength_Inline(
      context,
      GetProperty(context, o.value(), isolate()->factory()->length_string())));
  Goto(&length_done);

  BIND(&length_done);

  // 5. Let relativeStart be ToInteger(start).
  // 6. ReturnIfAbrupt(relativeStart).
1368
  TNode<Object> arg0 = args.GetOptionalArgumentValue(0, SmiConstant(0));
1369
  Node* relative_start = ToInteger_Inline(context, arg0);
1370 1371 1372 1373 1374

  // 7. If relativeStart < 0, let k be max((len + relativeStart),0);
  //    else let k be min(relativeStart, len.value()).
  VARIABLE(k, MachineRepresentation::kTagged);
  Label relative_start_positive(this), relative_start_done(this);
1375 1376
  GotoIfNumberGreaterThanOrEqual(relative_start, SmiConstant(0),
                                 &relative_start_positive);
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
  k.Bind(NumberMax(NumberAdd(len.value(), relative_start), NumberConstant(0)));
  Goto(&relative_start_done);
  BIND(&relative_start_positive);
  k.Bind(NumberMin(relative_start, len.value()));
  Goto(&relative_start_done);
  BIND(&relative_start_done);

  // 8. If end is undefined, let relativeEnd be len;
  //    else let relativeEnd be ToInteger(end).
  // 9. ReturnIfAbrupt(relativeEnd).
1387
  TNode<Object> end = args.GetOptionalArgumentValue(1, UndefinedConstant());
1388 1389 1390
  Label end_undefined(this), end_done(this);
  VARIABLE(relative_end, MachineRepresentation::kTagged);
  GotoIf(WordEqual(end, UndefinedConstant()), &end_undefined);
1391
  relative_end.Bind(ToInteger_Inline(context, end));
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
  Goto(&end_done);
  BIND(&end_undefined);
  relative_end.Bind(len.value());
  Goto(&end_done);
  BIND(&end_done);

  // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0);
  //     else let final be min(relativeEnd, len).
  VARIABLE(final, MachineRepresentation::kTagged);
  Label relative_end_positive(this), relative_end_done(this);
1402 1403
  GotoIfNumberGreaterThanOrEqual(relative_end.value(), NumberConstant(0),
                                 &relative_end_positive);
1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
  final.Bind(NumberMax(NumberAdd(len.value(), relative_end.value()),
                       NumberConstant(0)));
  Goto(&relative_end_done);
  BIND(&relative_end_positive);
  final.Bind(NumberMin(relative_end.value(), len.value()));
  Goto(&relative_end_done);
  BIND(&relative_end_done);

  // 11. Let count be max(final – k, 0).
  Node* count =
      NumberMax(NumberSub(final.value(), k.value()), NumberConstant(0));

  // Handle FAST_ELEMENTS
  Label non_fast(this);
  Node* fast_result =
      HandleFastSlice(context, o.value(), k.value(), count, &non_fast);
  args.PopAndReturn(fast_result);

  // 12. Let A be ArraySpeciesCreate(O, count).
  // 13. ReturnIfAbrupt(A).
  BIND(&non_fast);

  Node* constructor =
      CallRuntime(Runtime::kArraySpeciesConstructor, context, o.value());
  Node* a = ConstructJS(CodeFactory::Construct(isolate()), context, constructor,
                        count);

  // 14. Let n be 0.
  VARIABLE(n, MachineRepresentation::kTagged);
  n.Bind(SmiConstant(0));

  Label loop(this, {&k, &n});
  Label after_loop(this);
  Goto(&loop);
  BIND(&loop);
  {
    // 15. Repeat, while k < final
1441
    GotoIfNumberGreaterThanOrEqual(k.value(), final.value(), &after_loop);
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466

    Node* p_k = k.value();  //  ToString(context, k.value()) is no-op

    CopyOneElement(context, o.value(), a, p_k, n);

    // e. Increase k by 1.
    k.Bind(NumberInc(k.value()));

    // f. Increase n by 1.
    n.Bind(NumberInc(n.value()));

    Goto(&loop);
  }

  BIND(&after_loop);

  // 16. Let setStatus be Set(A, "length", n, true).
  // 17. ReturnIfAbrupt(setStatus).
  CallRuntime(Runtime::kSetProperty, context, a,
              HeapConstant(isolate()->factory()->length_string()), n.value(),
              SmiConstant(static_cast<int>(LanguageMode::kStrict)));

  args.PopAndReturn(a);
}

1467
TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
1468 1469 1470
  TNode<Int32T> argc =
      UncheckedCast<Int32T>(Parameter(BuiltinDescriptor::kArgumentsCount));
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
1471
  CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget)));
1472 1473

  CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
1474
  TNode<Object> receiver = args.GetReceiver();
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486

  Label runtime(this, Label::kDeferred);
  Label fast(this);

  // Only shift in this stub if
  // 1) the array has fast elements
  // 2) the length is writable,
  // 3) the elements backing store isn't copy-on-write,
  // 4) we aren't supposed to shrink the backing store,
  // 5) we aren't supposed to left-trim the backing store.

  // 1) Check that the array has fast elements.
1487
  BranchIfFastJSArray(receiver, context, &fast, &runtime);
1488 1489 1490

  BIND(&fast);
  {
1491 1492 1493 1494
    TNode<JSArray> array_receiver = CAST(receiver);
    CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver)));
    Node* length =
        LoadAndUntagObjectField(array_receiver, JSArray::kLengthOffset);
1495
    Label return_undefined(this), fast_elements_tagged(this),
1496
        fast_elements_smi(this);
1497 1498 1499
    GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);

    // 2) Ensure that the length is writable.
1500
    EnsureArrayLengthWritable(LoadMap(array_receiver), &runtime);
1501 1502

    // 3) Check that the elements backing store isn't copy-on-write.
1503
    Node* elements = LoadElements(array_receiver);
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524
    GotoIf(WordEqual(LoadMap(elements),
                     LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
           &runtime);

    Node* new_length = IntPtrSub(length, IntPtrConstant(1));

    // 4) Check that we're not supposed to right-trim the backing store, as
    //    implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
    Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
    GotoIf(IntPtrLessThan(
               IntPtrAdd(IntPtrAdd(new_length, new_length),
                         IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
               capacity),
           &runtime);

    // 5) Check that we're not supposed to left-trim the backing store, as
    //    implemented in elements.cc:FastElementsAccessor::MoveElements.
    GotoIf(IntPtrGreaterThan(new_length,
                             IntPtrConstant(JSArray::kMaxCopyElements)),
           &runtime);

1525
    StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset,
1526 1527
                                   SmiTag(new_length));

1528
    Node* elements_kind = LoadMapElementsKind(LoadMap(array_receiver));
1529 1530
    GotoIf(
        Int32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_SMI_ELEMENTS)),
1531 1532
        &fast_elements_smi);
    GotoIf(Int32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
1533 1534
           &fast_elements_tagged);

1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576
    // Fast double elements kind:
    {
      CSA_ASSERT(this,
                 Int32LessThanOrEqual(elements_kind,
                                      Int32Constant(HOLEY_DOUBLE_ELEMENTS)));

      VARIABLE(result, MachineRepresentation::kTagged, UndefinedConstant());

      Label move_elements(this);
      result.Bind(AllocateHeapNumberWithValue(LoadFixedDoubleArrayElement(
          elements, IntPtrConstant(0), MachineType::Float64(), 0,
          INTPTR_PARAMETERS, &move_elements)));
      Goto(&move_elements);
      BIND(&move_elements);

      int32_t header_size = FixedDoubleArray::kHeaderSize - kHeapObjectTag;
      Node* memmove =
          ExternalConstant(ExternalReference::libc_memmove_function(isolate()));
      Node* start = IntPtrAdd(
          BitcastTaggedToWord(elements),
          ElementOffsetFromIndex(IntPtrConstant(0), HOLEY_DOUBLE_ELEMENTS,
                                 INTPTR_PARAMETERS, header_size));
      CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
                     MachineType::Pointer(), MachineType::UintPtr(), memmove,
                     start, IntPtrAdd(start, IntPtrConstant(kDoubleSize)),
                     IntPtrMul(new_length, IntPtrConstant(kDoubleSize)));
      Node* offset = ElementOffsetFromIndex(new_length, HOLEY_DOUBLE_ELEMENTS,
                                            INTPTR_PARAMETERS, header_size);
      if (Is64()) {
        Node* double_hole = Int64Constant(kHoleNanInt64);
        StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset,
                            double_hole);
      } else {
        STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32);
        Node* double_hole = Int32Constant(kHoleNanLower32);
        StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
                            double_hole);
        StoreNoWriteBarrier(MachineRepresentation::kWord32, elements,
                            IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
                            double_hole);
      }
      args.PopAndReturn(result.value());
1577 1578
    }

1579
    BIND(&fast_elements_tagged);
1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
    {
      Node* value = LoadFixedArrayElement(elements, 0);
      BuildFastLoop(IntPtrConstant(0), new_length,
                    [&](Node* index) {
                      StoreFixedArrayElement(
                          elements, index,
                          LoadFixedArrayElement(
                              elements, IntPtrAdd(index, IntPtrConstant(1))));
                    },
                    1, ParameterMode::INTPTR_PARAMETERS,
                    IndexAdvanceMode::kPost);
      StoreFixedArrayElement(elements, new_length, TheHoleConstant());
      GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
      args.PopAndReturn(value);
    }

1596
    BIND(&fast_elements_smi);
1597 1598
    {
      Node* value = LoadFixedArrayElement(elements, 0);
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
      BuildFastLoop(IntPtrConstant(0), new_length,
                    [&](Node* index) {
                      StoreFixedArrayElement(
                          elements, index,
                          LoadFixedArrayElement(
                              elements, IntPtrAdd(index, IntPtrConstant(1))),
                          SKIP_WRITE_BARRIER);
                    },
                    1, ParameterMode::INTPTR_PARAMETERS,
                    IndexAdvanceMode::kPost);
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
      StoreFixedArrayElement(elements, new_length, TheHoleConstant());
      GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
      args.PopAndReturn(value);
    }

    BIND(&return_undefined);
    { args.PopAndReturn(UndefinedConstant()); }
  }

  BIND(&runtime);
  {
    Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
                                 MachineType::TaggedPointer());
    TailCallStub(CodeFactory::ArrayShift(isolate()), context, target,
                 UndefinedConstant(), argc);
  }
}

1627
TF_BUILTIN(ExtractFastJSArray, ArrayBuiltinsAssembler) {
1628
  ParameterMode mode = OptimalParameterMode();
1629
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1630 1631 1632 1633 1634
  Node* array = Parameter(Descriptor::kSource);
  Node* begin = TaggedToParameter(Parameter(Descriptor::kBegin), mode);
  Node* count = TaggedToParameter(Parameter(Descriptor::kCount), mode);

  CSA_ASSERT(this, IsJSArray(array));
1635
  CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid()));
1636 1637 1638 1639

  Return(ExtractFastJSArray(context, array, begin, count, mode));
}

1640
TF_BUILTIN(CloneFastJSArray, ArrayBuiltinsAssembler) {
1641
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1642 1643 1644
  Node* array = Parameter(Descriptor::kSource);

  CSA_ASSERT(this, IsJSArray(array));
1645
  CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid()));
1646 1647 1648 1649 1650

  ParameterMode mode = OptimalParameterMode();
  Return(CloneFastJSArray(context, array, mode));
}

1651
TF_BUILTIN(ArrayFindLoopContinuation, ArrayBuiltinsAssembler) {
1652 1653
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1654 1655 1656
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
1657
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
1658
  Node* initial_k = Parameter(Descriptor::kInitialK);
1659
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1660 1661 1662 1663 1664 1665 1666
  Node* to = Parameter(Descriptor::kTo);

  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, array, object, initial_k,
                                            len, to);

  GenerateIteratingArrayBuiltinLoopContinuation(
1667 1668
      &ArrayBuiltinsAssembler::FindProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
1669 1670 1671
      MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
}

1672 1673
// Continuation that is called after an eager deoptimization from TF (ex. the
// array changes during iteration).
1674
TF_BUILTIN(ArrayFindLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
1675 1676
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1677 1678 1679
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
1680
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1681

1682 1683 1684
  Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
                     callbackfn, this_arg, UndefinedConstant(), receiver,
                     initial_k, len, UndefinedConstant()));
1685 1686
}

1687 1688
// Continuation that is called after a lazy deoptimization from TF (ex. the
// callback function is no longer callable).
1689
TF_BUILTIN(ArrayFindLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
1690 1691
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1692 1693 1694
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
1695
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1696

1697 1698 1699
  Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
                     callbackfn, this_arg, UndefinedConstant(), receiver,
                     initial_k, len, UndefinedConstant()));
1700 1701
}

1702 1703 1704
// Continuation that is called after a lazy deoptimization from TF that happens
// right after the callback and it's returned value must be handled before
// iteration continues.
1705
TF_BUILTIN(ArrayFindLoopAfterCallbackLazyDeoptContinuation,
1706
           ArrayBuiltinsAssembler) {
1707 1708
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1709 1710 1711
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
1712
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1713 1714
  Node* found_value = Parameter(Descriptor::kFoundValue);
  Node* is_found = Parameter(Descriptor::kIsFound);
1715 1716 1717 1718 1719 1720

  // This custom lazy deopt point is right after the callback. find() needs
  // to pick up at the next step, which is returning the element if the callback
  // value is truthy.  Otherwise, continue the search by calling the
  // continuation.
  Label if_true(this), if_false(this);
1721
  BranchIfToBooleanIsTrue(is_found, &if_true, &if_false);
1722
  BIND(&if_true);
1723
  Return(found_value);
1724
  BIND(&if_false);
1725 1726 1727
  Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
                     callbackfn, this_arg, UndefinedConstant(), receiver,
                     initial_k, len, UndefinedConstant()));
1728 1729
}

1730
// ES #sec-get-%typedarray%.prototype.find
1731
TF_BUILTIN(ArrayPrototypeFind, ArrayBuiltinsAssembler) {
1732
  TNode<IntPtrT> argc =
1733 1734
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
1735
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
1736
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1737
  TNode<Object> receiver = args.GetReceiver();
1738 1739 1740 1741 1742 1743 1744
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
                                new_target, argc);

  GenerateIteratingArrayBuiltinBody(
1745 1746 1747
      "Array.prototype.find", &ArrayBuiltinsAssembler::FindResultGenerator,
      &ArrayBuiltinsAssembler::FindProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
1748 1749 1750 1751
      Builtins::CallableFor(isolate(), Builtins::kArrayFindLoopContinuation),
      MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
}

1752
TF_BUILTIN(ArrayFindIndexLoopContinuation, ArrayBuiltinsAssembler) {
1753 1754
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1755 1756 1757
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
1758
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
1759
  Node* initial_k = Parameter(Descriptor::kInitialK);
1760
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1761 1762 1763 1764 1765 1766 1767
  Node* to = Parameter(Descriptor::kTo);

  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, array, object, initial_k,
                                            len, to);

  GenerateIteratingArrayBuiltinLoopContinuation(
1768 1769
      &ArrayBuiltinsAssembler::FindIndexProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
1770 1771 1772
      MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
}

1773
TF_BUILTIN(ArrayFindIndexLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
1774 1775
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1776 1777 1778
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
1779
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1780 1781 1782 1783 1784 1785

  Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
                     receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
                     initial_k, len, UndefinedConstant()));
}

1786
TF_BUILTIN(ArrayFindIndexLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
1787 1788
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1789 1790 1791
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
1792
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1793 1794 1795 1796 1797 1798 1799

  Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
                     receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
                     initial_k, len, UndefinedConstant()));
}

TF_BUILTIN(ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation,
1800
           ArrayBuiltinsAssembler) {
1801 1802
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1803 1804 1805
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
1806
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
  Node* found_value = Parameter(Descriptor::kFoundValue);
  Node* is_found = Parameter(Descriptor::kIsFound);

  // This custom lazy deopt point is right after the callback. find() needs
  // to pick up at the next step, which is returning the element if the callback
  // value is truthy.  Otherwise, continue the search by calling the
  // continuation.
  Label if_true(this), if_false(this);
  BranchIfToBooleanIsTrue(is_found, &if_true, &if_false);
  BIND(&if_true);
  Return(found_value);
  BIND(&if_false);
  Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
                     receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
                     initial_k, len, UndefinedConstant()));
}

1824
// ES #sec-get-%typedarray%.prototype.findIndex
1825
TF_BUILTIN(ArrayPrototypeFindIndex, ArrayBuiltinsAssembler) {
1826
  TNode<IntPtrT> argc =
1827 1828
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
1829
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
1830
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1831
  TNode<Object> receiver = args.GetReceiver();
1832 1833 1834 1835 1836 1837 1838 1839
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
                                new_target, argc);

  GenerateIteratingArrayBuiltinBody(
      "Array.prototype.findIndex",
1840 1841 1842
      &ArrayBuiltinsAssembler::FindIndexResultGenerator,
      &ArrayBuiltinsAssembler::FindIndexProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
1843 1844 1845 1846 1847
      Builtins::CallableFor(isolate(),
                            Builtins::kArrayFindIndexLoopContinuation),
      MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
}

1848 1849 1850 1851
class ArrayPopulatorAssembler : public CodeStubAssembler {
 public:
  explicit ArrayPopulatorAssembler(compiler::CodeAssemblerState* state)
      : CodeStubAssembler(state) {}
1852

1853 1854 1855 1856 1857 1858
  TNode<Object> ConstructArrayLike(TNode<Context> context,
                                   TNode<Object> receiver) {
    TVARIABLE(Object, array);
    Label is_constructor(this), is_not_constructor(this), done(this);
    GotoIf(TaggedIsSmi(receiver), &is_not_constructor);
    Branch(IsConstructor(receiver), &is_constructor, &is_not_constructor);
1859

1860 1861 1862 1863 1864 1865
    BIND(&is_constructor);
    {
      array = CAST(
          ConstructJS(CodeFactory::Construct(isolate()), context, receiver));
      Goto(&done);
    }
1866

1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880
    BIND(&is_not_constructor);
    {
      Label allocate_js_array(this);

      TNode<Map> array_map = CAST(LoadContextElement(
          context, Context::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX));

      array = CAST(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map,
                                   SmiConstant(0), SmiConstant(0), nullptr,
                                   ParameterMode::SMI_PARAMETERS));
      Goto(&done);
    }

    BIND(&done);
1881
    return array.value();
1882 1883 1884 1885 1886 1887 1888 1889
  }

  TNode<Object> ConstructArrayLike(TNode<Context> context,
                                   TNode<Object> receiver,
                                   TNode<Number> length) {
    TVARIABLE(Object, array);
    Label is_constructor(this), is_not_constructor(this), done(this);
    CSA_ASSERT(this, IsNumberNormalized(length));
1890 1891 1892 1893 1894 1895 1896
    GotoIf(TaggedIsSmi(receiver), &is_not_constructor);
    Branch(IsConstructor(receiver), &is_constructor, &is_not_constructor);

    BIND(&is_constructor);
    {
      array = CAST(ConstructJS(CodeFactory::Construct(isolate()), context,
                               receiver, length));
1897
      Goto(&done);
1898 1899 1900 1901
    }

    BIND(&is_not_constructor);
    {
1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914
      Label allocate_js_array(this);

      Label next(this), runtime(this, Label::kDeferred);
      TNode<Smi> limit = SmiConstant(JSArray::kInitialMaxFastElementArray);
      CSA_ASSERT_BRANCH(this, [=](Label* ok, Label* not_ok) {
        BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual,
                                           length, SmiConstant(0), ok, not_ok);
      });
      // This check also transitively covers the case where length is too big
      // to be representable by a SMI and so is not usable with
      // AllocateJSArray.
      BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, length,
                                         limit, &runtime, &next);
1915 1916 1917 1918 1919 1920 1921 1922

      BIND(&runtime);
      {
        TNode<Context> native_context = LoadNativeContext(context);
        TNode<JSFunction> array_function = CAST(
            LoadContextElement(native_context, Context::ARRAY_FUNCTION_INDEX));
        array = CallRuntime(Runtime::kNewArray, context, array_function, length,
                            array_function, UndefinedConstant());
1923
        Goto(&done);
1924
      }
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938

      BIND(&next);
      CSA_ASSERT(this, TaggedIsSmi(length));

      TNode<Map> array_map = CAST(LoadContextElement(
          context, Context::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX));

      // TODO(delphick): Consider using
      // AllocateUninitializedJSArrayWithElements to avoid initializing an
      // array and then writing over it.
      array = CAST(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, length,
                                   SmiConstant(0), nullptr,
                                   ParameterMode::SMI_PARAMETERS));
      Goto(&done);
1939 1940
    }

1941
    BIND(&done);
1942
    return array.value();
1943 1944
  }

1945 1946 1947
  void GenerateSetLength(TNode<Context> context, TNode<Object> array,
                         TNode<Number> length) {
    Label fast(this), runtime(this), done(this);
1948 1949 1950 1951
    // There's no need to set the length, if
    // 1) the array is a fast JS array and
    // 2) the new length is equal to the old length.
    // as the set is not observable. Otherwise fall back to the run-time.
1952 1953

    // 1) Check that the array has fast elements.
1954 1955
    // TODO(delphick): Consider changing this since it does an an unnecessary
    // check for SMIs.
1956 1957
    // TODO(delphick): Also we could hoist this to after the array construction
    // and copy the args into array in the same way as the Array constructor.
1958
    BranchIfFastJSArray(array, context, &fast, &runtime);
1959

1960
    BIND(&fast);
1961
    {
1962 1963
      TNode<JSArray> fast_array = CAST(array);

1964 1965 1966
      TNode<Smi> length_smi = CAST(length);
      TNode<Smi> old_length = LoadFastJSArrayLength(fast_array);
      CSA_ASSERT(this, TaggedIsPositiveSmi(old_length));
1967

1968 1969 1970 1971 1972
      // 2) If the created array's length matches the required length, then
      //    there's nothing else to do. Otherwise use the runtime to set the
      //    property as that will insert holes into excess elements or shrink
      //    the backing store as appropriate.
      Branch(SmiNotEqual(length_smi, old_length), &runtime, &done);
1973 1974
    }

1975
    BIND(&runtime);
1976 1977 1978 1979
    {
      CallRuntime(Runtime::kSetProperty, context, static_cast<Node*>(array),
                  CodeStubAssembler::LengthStringConstant(), length,
                  SmiConstant(LanguageMode::kStrict));
1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015
      Goto(&done);
    }

    BIND(&done);
  }
};

// ES #sec-array.from
TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
  TNode<Int32T> argc =
      UncheckedCast<Int32T>(Parameter(BuiltinDescriptor::kArgumentsCount));

  CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));

  TNode<Object> map_function = args.GetOptionalArgumentValue(1);

  // If map_function is not undefined, then ensure it's callable else throw.
  {
    Label no_error(this), error(this);
    GotoIf(IsUndefined(map_function), &no_error);
    GotoIf(TaggedIsSmi(map_function), &error);
    Branch(IsCallable(map_function), &no_error, &error);

    BIND(&error);
    ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_function);

    BIND(&no_error);
  }

  Label iterable(this), not_iterable(this), finished(this), if_exception(this);

  TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
  TNode<Object> items = args.GetOptionalArgumentValue(0);
  // The spec doesn't require ToObject to be called directly on the iterable
  // branch, but it's part of GetMethod that is in the spec.
2016
  TNode<JSReceiver> array_like = ToObject(context, items);
2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039

  TVARIABLE(Object, array);
  TVARIABLE(Number, length);

  // Determine whether items[Symbol.iterator] is defined:
  IteratorBuiltinsAssembler iterator_assembler(state());
  Node* iterator_method =
      iterator_assembler.GetIteratorMethod(context, array_like);
  Branch(IsNullOrUndefined(iterator_method), &not_iterable, &iterable);

  BIND(&iterable);
  {
    TVARIABLE(Number, index, SmiConstant(0));
    TVARIABLE(Object, var_exception);
    Label loop(this, &index), loop_done(this),
        on_exception(this, Label::kDeferred),
        index_overflow(this, Label::kDeferred);

    // Check that the method is callable.
    {
      Label get_method_not_callable(this, Label::kDeferred), next(this);
      GotoIf(TaggedIsSmi(iterator_method), &get_method_not_callable);
      GotoIfNot(IsCallable(iterator_method), &get_method_not_callable);
2040
      Goto(&next);
2041 2042 2043 2044 2045 2046

      BIND(&get_method_not_callable);
      ThrowTypeError(context, MessageTemplate::kCalledNonCallable,
                     iterator_method);

      BIND(&next);
2047 2048
    }

2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080
    // Construct the output array with empty length.
    array = ConstructArrayLike(context, args.GetReceiver());

    // Actually get the iterator and throw if the iterator method does not yield
    // one.
    IteratorRecord iterator_record =
        iterator_assembler.GetIterator(context, items, iterator_method);

    TNode<Context> native_context = LoadNativeContext(context);
    TNode<Object> fast_iterator_result_map =
        LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);

    Goto(&loop);

    BIND(&loop);
    {
      // Loop while iterator is not done.
      TNode<Object> next = CAST(iterator_assembler.IteratorStep(
          context, iterator_record, &loop_done, fast_iterator_result_map));
      TVARIABLE(Object, value,
                CAST(iterator_assembler.IteratorValue(
                    context, next, fast_iterator_result_map)));

      // If a map_function is supplied then call it (using this_arg as
      // receiver), on the value returned from the iterator. Exceptions are
      // caught so the iterator can be closed.
      {
        Label next(this);
        GotoIf(IsUndefined(map_function), &next);

        CSA_ASSERT(this, IsCallable(map_function));
        Node* v = CallJS(CodeFactory::Call(isolate()), context, map_function,
2081
                         this_arg, value.value(), index.value());
2082 2083 2084 2085 2086 2087 2088 2089
        GotoIfException(v, &on_exception, &var_exception);
        value = CAST(v);
        Goto(&next);
        BIND(&next);
      }

      // Store the result in the output object (catching any exceptions so the
      // iterator can be closed).
2090 2091 2092
      Node* define_status =
          CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
                      index.value(), value.value());
2093 2094
      GotoIfException(define_status, &on_exception, &var_exception);

2095
      index = NumberInc(index.value());
2096 2097 2098 2099 2100 2101 2102 2103

      // The spec requires that we throw an exception if index reaches 2^53-1,
      // but an empty loop would take >100 days to do this many iterations. To
      // actually run for that long would require an iterator that never set
      // done to true and a target array which somehow never ran out of memory,
      // e.g. a proxy that discarded the values. Ignoring this case just means
      // we would repeatedly call CreateDataProperty with index = 2^53.
      CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
2104
        BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123
                                           NumberConstant(kMaxSafeInteger), ok,
                                           not_ok);
      });
      Goto(&loop);
    }

    BIND(&loop_done);
    {
      length = index;
      Goto(&finished);
    }

    BIND(&on_exception);
    {
      // Close the iterator, rethrowing either the passed exception or
      // exceptions thrown during the close.
      iterator_assembler.IteratorCloseOnException(context, iterator_record,
                                                  &var_exception);
    }
2124
  }
2125 2126 2127 2128 2129 2130 2131

  // Since there's no iterator, items cannot be a Fast JS Array.
  BIND(&not_iterable);
  {
    CSA_ASSERT(this, Word32BinaryNot(IsFastJSArray(array_like, context)));

    // Treat array_like as an array and try to get its length.
2132 2133
    length = ToLength_Inline(
        context, GetProperty(context, array_like, factory()->length_string()));
2134 2135 2136

    // Construct an array using the receiver as constructor with the same length
    // as the input array.
2137
    array = ConstructArrayLike(context, args.GetReceiver(), length.value());
2138 2139 2140

    TVARIABLE(Number, index, SmiConstant(0));

2141
    GotoIf(SmiEqual(length.value(), SmiConstant(0)), &finished);
2142 2143 2144 2145 2146 2147 2148 2149

    // Loop from 0 to length-1.
    {
      Label loop(this, &index);
      Goto(&loop);
      BIND(&loop);
      TVARIABLE(Object, value);

2150
      value = GetProperty(context, array_like, index.value());
2151 2152 2153 2154 2155 2156 2157 2158 2159

      // If a map_function is supplied then call it (using this_arg as
      // receiver), on the value retrieved from the array.
      {
        Label next(this);
        GotoIf(IsUndefined(map_function), &next);

        CSA_ASSERT(this, IsCallable(map_function));
        value = CAST(CallJS(CodeFactory::Call(isolate()), context, map_function,
2160
                            this_arg, value.value(), index.value()));
2161 2162 2163 2164 2165
        Goto(&next);
        BIND(&next);
      }

      // Store the result in the output object.
2166 2167
      CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
                  index.value(), value.value());
2168
      index = NumberInc(index.value());
2169 2170
      BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
                                         length.value(), &loop, &finished);
2171 2172 2173 2174 2175 2176
    }
  }

  BIND(&finished);

  // Finally set the length on the output and return it.
2177 2178
  GenerateSetLength(context, array.value(), length.value());
  args.PopAndReturn(array.value());
2179 2180 2181 2182 2183 2184
}

// ES #sec-array.of
TF_BUILTIN(ArrayOf, ArrayPopulatorAssembler) {
  TNode<Int32T> argc =
      UncheckedCast<Int32T>(Parameter(BuiltinDescriptor::kArgumentsCount));
2185
  TNode<Smi> length = SmiFromInt32(argc);
2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203

  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));

  CodeStubArguments args(this, length, nullptr, ParameterMode::SMI_PARAMETERS);

  TNode<Object> array = ConstructArrayLike(context, args.GetReceiver(), length);

  // TODO(delphick): Avoid using CreateDataProperty on the fast path.
  BuildFastLoop(SmiConstant(0), length,
                [=](Node* index) {
                  CallRuntime(
                      Runtime::kCreateDataProperty, context,
                      static_cast<Node*>(array), index,
                      args.AtIndex(index, ParameterMode::SMI_PARAMETERS));
                },
                1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);

  GenerateSetLength(context, array, length);
2204 2205 2206
  args.PopAndReturn(array);
}

2207
// ES #sec-get-%typedarray%.prototype.find
2208
TF_BUILTIN(TypedArrayPrototypeFind, ArrayBuiltinsAssembler) {
2209
  TNode<IntPtrT> argc =
2210 2211
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2212
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2213
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2214
  TNode<Object> receiver = args.GetReceiver();
2215 2216 2217 2218 2219 2220 2221 2222
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
                                new_target, argc);

  GenerateIteratingTypedArrayBuiltinBody(
      "%TypedArray%.prototype.find",
2223 2224 2225
      &ArrayBuiltinsAssembler::FindResultGenerator,
      &ArrayBuiltinsAssembler::FindProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction);
2226 2227
}

2228
// ES #sec-get-%typedarray%.prototype.findIndex
2229
TF_BUILTIN(TypedArrayPrototypeFindIndex, ArrayBuiltinsAssembler) {
2230
  TNode<IntPtrT> argc =
2231 2232
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2233
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2234
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2235
  TNode<Object> receiver = args.GetReceiver();
2236 2237 2238 2239 2240 2241 2242 2243
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
                                new_target, argc);

  GenerateIteratingTypedArrayBuiltinBody(
      "%TypedArray%.prototype.findIndex",
2244 2245 2246
      &ArrayBuiltinsAssembler::FindIndexResultGenerator,
      &ArrayBuiltinsAssembler::FindIndexProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction);
2247 2248
}

2249
TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinsAssembler) {
2250 2251
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2252 2253 2254
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
2255
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2256
  Node* initial_k = Parameter(Descriptor::kInitialK);
2257
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2258
  Node* to = Parameter(Descriptor::kTo);
2259

2260 2261 2262
  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, array, object, initial_k,
                                            len, to);
2263

2264
  GenerateIteratingArrayBuiltinLoopContinuation(
2265 2266
      &ArrayBuiltinsAssembler::ForEachProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2267
}
2268

2269
TF_BUILTIN(ArrayForEachLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2270 2271
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2272 2273 2274
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2275
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2276

2277 2278 2279
  Return(CallBuiltin(Builtins::kArrayForEachLoopContinuation, context, receiver,
                     callbackfn, this_arg, UndefinedConstant(), receiver,
                     initial_k, len, UndefinedConstant()));
2280 2281
}

2282
TF_BUILTIN(ArrayForEachLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2283 2284
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2285 2286 2287
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2288
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2289

2290 2291 2292
  Return(CallBuiltin(Builtins::kArrayForEachLoopContinuation, context, receiver,
                     callbackfn, this_arg, UndefinedConstant(), receiver,
                     initial_k, len, UndefinedConstant()));
2293 2294
}

2295
TF_BUILTIN(ArrayForEach, ArrayBuiltinsAssembler) {
2296
  TNode<IntPtrT> argc =
2297 2298
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2299
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2300
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2301
  TNode<Object> receiver = args.GetReceiver();
2302 2303
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2304 2305

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
2306
                                new_target, argc);
2307

2308 2309
  GenerateIteratingArrayBuiltinBody(
      "Array.prototype.forEach",
2310 2311 2312
      &ArrayBuiltinsAssembler::ForEachResultGenerator,
      &ArrayBuiltinsAssembler::ForEachProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
2313 2314
      Builtins::CallableFor(isolate(), Builtins::kArrayForEachLoopContinuation),
      MissingPropertyMode::kSkip);
2315 2316
}

2317
TF_BUILTIN(TypedArrayPrototypeForEach, ArrayBuiltinsAssembler) {
2318
  TNode<IntPtrT> argc =
2319 2320
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2321
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2322
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2323
  TNode<Object> receiver = args.GetReceiver();
2324 2325
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2326 2327 2328 2329 2330 2331

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
                                new_target, argc);

  GenerateIteratingTypedArrayBuiltinBody(
      "%TypedArray%.prototype.forEach",
2332 2333 2334
      &ArrayBuiltinsAssembler::ForEachResultGenerator,
      &ArrayBuiltinsAssembler::ForEachProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction);
2335 2336
}

2337
TF_BUILTIN(ArraySomeLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2338 2339
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2340 2341 2342
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2343
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365
  Node* result = Parameter(Descriptor::kResult);

  // This custom lazy deopt point is right after the callback. every() needs
  // to pick up at the next step, which is either continuing to the next
  // array element or returning false if {result} is false.
  Label true_continue(this), false_continue(this);

  // iii. If selected is true, then...
  BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
  BIND(&true_continue);
  { Return(TrueConstant()); }
  BIND(&false_continue);
  {
    // Increment k.
    initial_k = NumberInc(initial_k);

    Return(CallBuiltin(Builtins::kArraySomeLoopContinuation, context, receiver,
                       callbackfn, this_arg, FalseConstant(), receiver,
                       initial_k, len, UndefinedConstant()));
  }
}

2366
TF_BUILTIN(ArraySomeLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2367 2368
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2369 2370 2371
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2372
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2373 2374 2375 2376 2377 2378

  Return(CallBuiltin(Builtins::kArraySomeLoopContinuation, context, receiver,
                     callbackfn, this_arg, FalseConstant(), receiver, initial_k,
                     len, UndefinedConstant()));
}

2379
TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinsAssembler) {
2380 2381
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2382 2383 2384
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
2385
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2386
  Node* initial_k = Parameter(Descriptor::kInitialK);
2387
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2388
  Node* to = Parameter(Descriptor::kTo);
2389

2390 2391 2392
  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, array, object, initial_k,
                                            len, to);
2393

2394
  GenerateIteratingArrayBuiltinLoopContinuation(
2395 2396
      &ArrayBuiltinsAssembler::SomeProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2397 2398
}

2399
TF_BUILTIN(ArraySome, ArrayBuiltinsAssembler) {
2400
  TNode<IntPtrT> argc =
2401 2402
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2403
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2404
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2405
  TNode<Object> receiver = args.GetReceiver();
2406 2407
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2408 2409

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
2410
                                new_target, argc);
2411

2412
  GenerateIteratingArrayBuiltinBody(
2413 2414 2415
      "Array.prototype.some", &ArrayBuiltinsAssembler::SomeResultGenerator,
      &ArrayBuiltinsAssembler::SomeProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
2416 2417
      Builtins::CallableFor(isolate(), Builtins::kArraySomeLoopContinuation),
      MissingPropertyMode::kSkip);
2418 2419
}

2420
TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinsAssembler) {
2421
  TNode<IntPtrT> argc =
2422 2423
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2424
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2425
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2426
  TNode<Object> receiver = args.GetReceiver();
2427 2428
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2429 2430

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
2431
                                new_target, argc);
2432 2433 2434

  GenerateIteratingTypedArrayBuiltinBody(
      "%TypedArray%.prototype.some",
2435 2436 2437
      &ArrayBuiltinsAssembler::SomeResultGenerator,
      &ArrayBuiltinsAssembler::SomeProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction);
2438 2439
}

2440
TF_BUILTIN(ArrayEveryLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2441 2442
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2443 2444 2445
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2446
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
  Node* result = Parameter(Descriptor::kResult);

  // This custom lazy deopt point is right after the callback. every() needs
  // to pick up at the next step, which is either continuing to the next
  // array element or returning false if {result} is false.
  Label true_continue(this), false_continue(this);

  // iii. If selected is true, then...
  BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
  BIND(&true_continue);
  {
    // Increment k.
    initial_k = NumberInc(initial_k);

    Return(CallBuiltin(Builtins::kArrayEveryLoopContinuation, context, receiver,
                       callbackfn, this_arg, TrueConstant(), receiver,
                       initial_k, len, UndefinedConstant()));
  }
  BIND(&false_continue);
  { Return(FalseConstant()); }
}

2469
TF_BUILTIN(ArrayEveryLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2470 2471
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2472 2473 2474
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2475
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2476 2477 2478 2479 2480 2481

  Return(CallBuiltin(Builtins::kArrayEveryLoopContinuation, context, receiver,
                     callbackfn, this_arg, TrueConstant(), receiver, initial_k,
                     len, UndefinedConstant()));
}

2482
TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinsAssembler) {
2483 2484
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2485 2486 2487
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
2488
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2489
  Node* initial_k = Parameter(Descriptor::kInitialK);
2490
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2491
  Node* to = Parameter(Descriptor::kTo);
2492

2493 2494 2495
  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, array, object, initial_k,
                                            len, to);
2496

2497
  GenerateIteratingArrayBuiltinLoopContinuation(
2498 2499
      &ArrayBuiltinsAssembler::EveryProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2500 2501
}

2502
TF_BUILTIN(ArrayEvery, ArrayBuiltinsAssembler) {
2503
  TNode<IntPtrT> argc =
2504 2505
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2506
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2507
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2508
  TNode<Object> receiver = args.GetReceiver();
2509 2510
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2511 2512

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
2513
                                new_target, argc);
2514

2515
  GenerateIteratingArrayBuiltinBody(
2516 2517 2518
      "Array.prototype.every", &ArrayBuiltinsAssembler::EveryResultGenerator,
      &ArrayBuiltinsAssembler::EveryProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
2519 2520
      Builtins::CallableFor(isolate(), Builtins::kArrayEveryLoopContinuation),
      MissingPropertyMode::kSkip);
2521 2522
}

2523
TF_BUILTIN(TypedArrayPrototypeEvery, ArrayBuiltinsAssembler) {
2524
  TNode<IntPtrT> argc =
2525 2526
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2527
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2528
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2529
  TNode<Object> receiver = args.GetReceiver();
2530 2531
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2532 2533

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
2534
                                new_target, argc);
2535 2536 2537

  GenerateIteratingTypedArrayBuiltinBody(
      "%TypedArray%.prototype.every",
2538 2539 2540
      &ArrayBuiltinsAssembler::EveryResultGenerator,
      &ArrayBuiltinsAssembler::EveryProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction);
2541 2542
}

2543
TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinsAssembler) {
2544 2545
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2546 2547 2548
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* accumulator = Parameter(Descriptor::kAccumulator);
2549
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2550
  Node* initial_k = Parameter(Descriptor::kInitialK);
2551
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2552
  Node* to = Parameter(Descriptor::kTo);
2553 2554 2555

  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, accumulator, object,
2556
                                            initial_k, len, to);
2557

2558
  GenerateIteratingArrayBuiltinLoopContinuation(
2559 2560
      &ArrayBuiltinsAssembler::ReduceProcessor,
      &ArrayBuiltinsAssembler::ReducePostLoopAction,
2561
      MissingPropertyMode::kSkip);
2562 2563
}

2564
TF_BUILTIN(ArrayReducePreLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2565 2566
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2567
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2568
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2569 2570 2571 2572

  // Simulate starting the loop at 0, but ensuring that the accumulator is
  // the hole. The continuation stub will search for the initial non-hole
  // element, rightly throwing an exception if not found.
2573 2574 2575
  Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
                     callbackfn, UndefinedConstant(), TheHoleConstant(),
                     receiver, SmiConstant(0), len, UndefinedConstant()));
2576 2577
}

2578
TF_BUILTIN(ArrayReduceLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2579 2580
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2581 2582 2583
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* accumulator = Parameter(Descriptor::kAccumulator);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2584
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2585

2586 2587 2588
  Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
                     callbackfn, UndefinedConstant(), accumulator, receiver,
                     initial_k, len, UndefinedConstant()));
2589 2590
}

2591
TF_BUILTIN(ArrayReduceLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2592 2593
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2594 2595
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2596
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2597 2598
  Node* result = Parameter(Descriptor::kResult);

2599 2600 2601
  Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
                     callbackfn, UndefinedConstant(), result, receiver,
                     initial_k, len, UndefinedConstant()));
2602 2603
}

2604
TF_BUILTIN(ArrayReduce, ArrayBuiltinsAssembler) {
2605
  TNode<IntPtrT> argc =
2606 2607
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2608
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2609
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2610
  TNode<Object> receiver = args.GetReceiver();
2611
  Node* callbackfn = args.GetOptionalArgumentValue(0);
2612
  Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
2613 2614

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
2615
                                new_target, argc);
2616

2617
  GenerateIteratingArrayBuiltinBody(
2618 2619 2620
      "Array.prototype.reduce", &ArrayBuiltinsAssembler::ReduceResultGenerator,
      &ArrayBuiltinsAssembler::ReduceProcessor,
      &ArrayBuiltinsAssembler::ReducePostLoopAction,
2621 2622
      Builtins::CallableFor(isolate(), Builtins::kArrayReduceLoopContinuation),
      MissingPropertyMode::kSkip);
2623 2624
}

2625
TF_BUILTIN(TypedArrayPrototypeReduce, ArrayBuiltinsAssembler) {
2626
  TNode<IntPtrT> argc =
2627 2628
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2629
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2630
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2631
  TNode<Object> receiver = args.GetReceiver();
2632
  Node* callbackfn = args.GetOptionalArgumentValue(0);
2633
  Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
2634 2635

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
2636
                                new_target, argc);
2637 2638 2639

  GenerateIteratingTypedArrayBuiltinBody(
      "%TypedArray%.prototype.reduce",
2640 2641 2642
      &ArrayBuiltinsAssembler::ReduceResultGenerator,
      &ArrayBuiltinsAssembler::ReduceProcessor,
      &ArrayBuiltinsAssembler::ReducePostLoopAction);
2643 2644
}

2645
TF_BUILTIN(ArrayReduceRightLoopContinuation, ArrayBuiltinsAssembler) {
2646 2647
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2648 2649 2650
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* accumulator = Parameter(Descriptor::kAccumulator);
2651
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2652
  Node* initial_k = Parameter(Descriptor::kInitialK);
2653
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2654 2655 2656 2657 2658 2659 2660
  Node* to = Parameter(Descriptor::kTo);

  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, accumulator, object,
                                            initial_k, len, to);

  GenerateIteratingArrayBuiltinLoopContinuation(
2661 2662 2663
      &ArrayBuiltinsAssembler::ReduceProcessor,
      &ArrayBuiltinsAssembler::ReducePostLoopAction, MissingPropertyMode::kSkip,
      ForEachDirection::kReverse);
2664 2665
}

2666 2667
TF_BUILTIN(ArrayReduceRightPreLoopEagerDeoptContinuation,
           ArrayBuiltinsAssembler) {
2668 2669
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2670
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2671
  TNode<Smi> len = CAST(Parameter(Descriptor::kLength));
2672 2673 2674 2675

  // Simulate starting the loop at 0, but ensuring that the accumulator is
  // the hole. The continuation stub will search for the initial non-hole
  // element, rightly throwing an exception if not found.
2676 2677 2678 2679
  Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
                     receiver, callbackfn, UndefinedConstant(),
                     TheHoleConstant(), receiver, SmiSub(len, SmiConstant(1)),
                     len, UndefinedConstant()));
2680 2681
}

2682
TF_BUILTIN(ArrayReduceRightLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2683 2684
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2685 2686 2687
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* accumulator = Parameter(Descriptor::kAccumulator);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2688
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2689

2690 2691 2692
  Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
                     receiver, callbackfn, UndefinedConstant(), accumulator,
                     receiver, initial_k, len, UndefinedConstant()));
2693 2694
}

2695
TF_BUILTIN(ArrayReduceRightLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2696 2697
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2698 2699
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2700
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2701 2702
  Node* result = Parameter(Descriptor::kResult);

2703 2704 2705
  Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
                     receiver, callbackfn, UndefinedConstant(), result,
                     receiver, initial_k, len, UndefinedConstant()));
2706 2707
}

2708
TF_BUILTIN(ArrayReduceRight, ArrayBuiltinsAssembler) {
2709
  TNode<IntPtrT> argc =
2710 2711
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2712
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2713
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2714
  TNode<Object> receiver = args.GetReceiver();
2715
  Node* callbackfn = args.GetOptionalArgumentValue(0);
2716
  Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
2717 2718

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
2719
                                new_target, argc);
2720 2721 2722

  GenerateIteratingArrayBuiltinBody(
      "Array.prototype.reduceRight",
2723 2724 2725
      &ArrayBuiltinsAssembler::ReduceResultGenerator,
      &ArrayBuiltinsAssembler::ReduceProcessor,
      &ArrayBuiltinsAssembler::ReducePostLoopAction,
2726 2727
      Builtins::CallableFor(isolate(),
                            Builtins::kArrayReduceRightLoopContinuation),
2728
      MissingPropertyMode::kSkip, ForEachDirection::kReverse);
2729 2730
}

2731
TF_BUILTIN(TypedArrayPrototypeReduceRight, ArrayBuiltinsAssembler) {
2732
  TNode<IntPtrT> argc =
2733 2734
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2735
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2736
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2737
  TNode<Object> receiver = args.GetReceiver();
2738
  Node* callbackfn = args.GetOptionalArgumentValue(0);
2739
  Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
2740 2741

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
2742
                                new_target, argc);
2743 2744 2745

  GenerateIteratingTypedArrayBuiltinBody(
      "%TypedArray%.prototype.reduceRight",
2746 2747 2748
      &ArrayBuiltinsAssembler::ReduceResultGenerator,
      &ArrayBuiltinsAssembler::ReduceProcessor,
      &ArrayBuiltinsAssembler::ReducePostLoopAction,
2749 2750 2751
      ForEachDirection::kReverse);
}

2752
TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinsAssembler) {
2753 2754
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2755 2756 2757
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
2758
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2759
  Node* initial_k = Parameter(Descriptor::kInitialK);
2760
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2761
  Node* to = Parameter(Descriptor::kTo);
2762

2763 2764 2765
  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, array, object, initial_k,
                                            len, to);
2766

2767
  GenerateIteratingArrayBuiltinLoopContinuation(
2768 2769
      &ArrayBuiltinsAssembler::FilterProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2770
}
2771

2772
TF_BUILTIN(ArrayFilterLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2773 2774
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2775 2776 2777 2778
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2779
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2780 2781
  Node* to = Parameter(Descriptor::kTo);

2782 2783 2784
  Return(CallBuiltin(Builtins::kArrayFilterLoopContinuation, context, receiver,
                     callbackfn, this_arg, array, receiver, initial_k, len,
                     to));
2785 2786
}

2787
TF_BUILTIN(ArrayFilterLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2788 2789
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2790 2791 2792 2793
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2794
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
  Node* value_k = Parameter(Descriptor::kValueK);
  Node* result = Parameter(Descriptor::kResult);

  VARIABLE(to, MachineRepresentation::kTagged, Parameter(Descriptor::kTo));

  // This custom lazy deopt point is right after the callback. filter() needs
  // to pick up at the next step, which is setting the callback result in
  // the output array. After incrementing k and to, we can glide into the loop
  // continuation builtin.

  Label true_continue(this, &to), false_continue(this);

  // iii. If selected is true, then...
  BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
  BIND(&true_continue);
  {
    // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
    CallRuntime(Runtime::kCreateDataProperty, context, array, to.value(),
                value_k);
    // 2. Increase to by 1.
    to.Bind(NumberInc(to.value()));
    Goto(&false_continue);
  }
  BIND(&false_continue);

  // Increment k.
  initial_k = NumberInc(initial_k);

2823 2824 2825
  Return(CallBuiltin(Builtins::kArrayFilterLoopContinuation, context, receiver,
                     callbackfn, this_arg, array, receiver, initial_k, len,
                     to.value()));
2826 2827
}

2828
TF_BUILTIN(ArrayFilter, ArrayBuiltinsAssembler) {
2829
  TNode<IntPtrT> argc =
2830 2831
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2832
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2833
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2834
  TNode<Object> receiver = args.GetReceiver();
2835 2836
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2837 2838

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
2839
                                new_target, argc);
2840

2841
  GenerateIteratingArrayBuiltinBody(
2842 2843 2844
      "Array.prototype.filter", &ArrayBuiltinsAssembler::FilterResultGenerator,
      &ArrayBuiltinsAssembler::FilterProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
2845 2846
      Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation),
      MissingPropertyMode::kSkip);
2847 2848
}

2849
TF_BUILTIN(ArrayMapLoopContinuation, ArrayBuiltinsAssembler) {
2850 2851
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2852 2853 2854
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
2855
  TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2856
  Node* initial_k = Parameter(Descriptor::kInitialK);
2857
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2858 2859 2860 2861 2862 2863 2864
  Node* to = Parameter(Descriptor::kTo);

  InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
                                            this_arg, array, object, initial_k,
                                            len, to);

  GenerateIteratingArrayBuiltinLoopContinuation(
2865 2866
      &ArrayBuiltinsAssembler::SpecCompliantMapProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2867 2868
}

2869
TF_BUILTIN(ArrayMapLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2870 2871
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2872 2873 2874 2875
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2876
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2877

2878 2879 2880
  Return(CallBuiltin(Builtins::kArrayMapLoopContinuation, context, receiver,
                     callbackfn, this_arg, array, receiver, initial_k, len,
                     UndefinedConstant()));
2881 2882
}

2883
TF_BUILTIN(ArrayMapLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2884 2885
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2886 2887 2888 2889
  Node* callbackfn = Parameter(Descriptor::kCallbackFn);
  Node* this_arg = Parameter(Descriptor::kThisArg);
  Node* array = Parameter(Descriptor::kArray);
  Node* initial_k = Parameter(Descriptor::kInitialK);
2890
  TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902
  Node* result = Parameter(Descriptor::kResult);

  // This custom lazy deopt point is right after the callback. map() needs
  // to pick up at the next step, which is setting the callback result in
  // the output array. After incrementing k, we can glide into the loop
  // continuation builtin.

  // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
  CallRuntime(Runtime::kCreateDataProperty, context, array, initial_k, result);
  // Then we have to increment k before going on.
  initial_k = NumberInc(initial_k);

2903 2904 2905
  Return(CallBuiltin(Builtins::kArrayMapLoopContinuation, context, receiver,
                     callbackfn, this_arg, array, receiver, initial_k, len,
                     UndefinedConstant()));
2906 2907
}

2908
TF_BUILTIN(ArrayMap, ArrayBuiltinsAssembler) {
2909
  TNode<IntPtrT> argc =
2910 2911
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2912
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2913
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2914
  TNode<Object> receiver = args.GetReceiver();
2915 2916
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2917 2918

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
2919
                                new_target, argc);
2920 2921

  GenerateIteratingArrayBuiltinBody(
2922 2923 2924
      "Array.prototype.map", &ArrayBuiltinsAssembler::MapResultGenerator,
      &ArrayBuiltinsAssembler::FastMapProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction,
2925 2926
      Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation),
      MissingPropertyMode::kSkip);
2927 2928
}

2929
TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
2930
  TNode<IntPtrT> argc =
2931 2932
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);
2933
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
2934
  Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
2935
  TNode<Object> receiver = args.GetReceiver();
2936 2937
  Node* callbackfn = args.GetOptionalArgumentValue(0);
  Node* this_arg = args.GetOptionalArgumentValue(1);
2938 2939 2940 2941 2942 2943

  InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
                                new_target, argc);

  GenerateIteratingTypedArrayBuiltinBody(
      "%TypedArray%.prototype.map",
2944 2945 2946
      &ArrayBuiltinsAssembler::TypedArrayMapResultGenerator,
      &ArrayBuiltinsAssembler::TypedArrayMapProcessor,
      &ArrayBuiltinsAssembler::NullPostLoopAction);
2947 2948
}

2949
TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
2950 2951
  TNode<Object> object = CAST(Parameter(Descriptor::kArg));
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2952 2953 2954 2955

  Label call_runtime(this), return_true(this), return_false(this);

  GotoIf(TaggedIsSmi(object), &return_false);
2956
  TNode<Int32T> instance_type = LoadInstanceType(CAST(object));
2957

2958
  GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &return_true);
2959 2960

  // TODO(verwaest): Handle proxies in-place.
2961 2962
  Branch(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), &call_runtime,
         &return_false);
2963

2964
  BIND(&return_true);
2965
  Return(TrueConstant());
2966

2967
  BIND(&return_false);
2968
  Return(FalseConstant());
2969

2970
  BIND(&call_runtime);
2971 2972 2973
  Return(CallRuntime(Runtime::kArrayIsArray, context, object));
}

2974 2975 2976 2977
class ArrayIncludesIndexofAssembler : public CodeStubAssembler {
 public:
  explicit ArrayIncludesIndexofAssembler(compiler::CodeAssemblerState* state)
      : CodeStubAssembler(state) {}
2978

2979
  enum SearchVariant { kIncludes, kIndexOf };
2980

2981
  void Generate(SearchVariant variant);
2982 2983 2984 2985 2986 2987 2988 2989 2990
  void GenerateSmiOrObject(SearchVariant variant, Node* context, Node* elements,
                           Node* search_element, Node* array_length,
                           Node* from_index);
  void GeneratePackedDoubles(SearchVariant variant, Node* elements,
                             Node* search_element, Node* array_length,
                             Node* from_index);
  void GenerateHoleyDoubles(SearchVariant variant, Node* elements,
                            Node* search_element, Node* array_length,
                            Node* from_index);
2991
};
2992

2993
void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant) {
2994 2995 2996
  const int kSearchElementArg = 0;
  const int kFromIndexArg = 1;

2997
  TNode<IntPtrT> argc =
2998 2999 3000
      ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
  CodeStubArguments args(this, argc);

3001 3002 3003
  TNode<Object> receiver = args.GetReceiver();
  TNode<Object> search_element =
      args.GetOptionalArgumentValue(kSearchElementArg);
3004
  TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
3005 3006 3007

  Node* intptr_zero = IntPtrConstant(0);

3008
  Label init_index(this), return_not_found(this), call_runtime(this);
3009 3010 3011

  // Take slow path if not a JSArray, if retrieving elements requires
  // traversing prototype, or if access checks are required.
3012
  BranchIfFastJSArray(receiver, context, &init_index, &call_runtime);
3013

3014 3015
  BIND(&init_index);
  VARIABLE(index_var, MachineType::PointerRepresentation(), intptr_zero);
3016
  TNode<JSArray> array = CAST(receiver);
3017

3018 3019
  // JSArray length is always a positive Smi for fast arrays.
  CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array)));
3020 3021
  Node* array_length = LoadFastJSArrayLength(array);
  Node* array_length_untagged = SmiUntag(array_length);
3022 3023

  {
3024 3025
    // Initialize fromIndex.
    Label is_smi(this), is_nonsmi(this), done(this);
3026

3027 3028
    // If no fromIndex was passed, default to 0.
    GotoIf(IntPtrLessThanOrEqual(argc, IntPtrConstant(kFromIndexArg)), &done);
3029

3030
    Node* start_from = args.AtIndex(kFromIndexArg);
3031 3032 3033 3034 3035
    // Handle Smis and undefined here and everything else in runtime.
    // We must be very careful with side effects from the ToInteger conversion,
    // as the side effects might render previously checked assumptions about
    // the receiver being a fast JSArray and its length invalid.
    Branch(TaggedIsSmi(start_from), &is_smi, &is_nonsmi);
3036

3037
    BIND(&is_nonsmi);
3038
    {
3039 3040 3041 3042 3043 3044 3045 3046 3047 3048
      GotoIfNot(IsUndefined(start_from), &call_runtime);
      Goto(&done);
    }
    BIND(&is_smi);
    {
      Node* intptr_start_from = SmiUntag(start_from);
      index_var.Bind(intptr_start_from);

      GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
      // The fromIndex is negative: add it to the array's length.
3049
      index_var.Bind(IntPtrAdd(array_length_untagged, index_var.value()));
3050 3051 3052
      // Clamp negative results at zero.
      GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
      index_var.Bind(intptr_zero);
3053
      Goto(&done);
3054
    }
3055
    BIND(&done);
3056 3057
  }

3058
  // Fail early if startIndex >= array.length.
3059
  GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), array_length_untagged),
3060 3061
         &return_not_found);

3062 3063
  Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);

3064
  Node* elements_kind = LoadMapElementsKind(LoadMap(array));
3065
  Node* elements = LoadElements(array);
3066 3067 3068 3069 3070 3071 3072
  STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
  STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
  STATIC_ASSERT(PACKED_ELEMENTS == 2);
  STATIC_ASSERT(HOLEY_ELEMENTS == 3);
  GotoIf(Uint32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
         &if_smiorobjects);
  GotoIf(Word32Equal(elements_kind, Int32Constant(PACKED_DOUBLE_ELEMENTS)),
3073
         &if_packed_doubles);
3074
  GotoIf(Word32Equal(elements_kind, Int32Constant(HOLEY_DOUBLE_ELEMENTS)),
3075 3076
         &if_holey_doubles);
  Goto(&return_not_found);
3077

3078
  BIND(&if_smiorobjects);
3079
  {
3080 3081 3082 3083 3084 3085 3086 3087 3088 3089
    Callable callable =
        (variant == kIncludes)
            ? Builtins::CallableFor(isolate(),
                                    Builtins::kArrayIncludesSmiOrObject)
            : Builtins::CallableFor(isolate(),
                                    Builtins::kArrayIndexOfSmiOrObject);
    Node* result = CallStub(callable, context, elements, search_element,
                            array_length, SmiTag(index_var.value()));
    args.PopAndReturn(result);
  }
3090

3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102
  BIND(&if_packed_doubles);
  {
    Callable callable =
        (variant == kIncludes)
            ? Builtins::CallableFor(isolate(),
                                    Builtins::kArrayIncludesPackedDoubles)
            : Builtins::CallableFor(isolate(),
                                    Builtins::kArrayIndexOfPackedDoubles);
    Node* result = CallStub(callable, context, elements, search_element,
                            array_length, SmiTag(index_var.value()));
    args.PopAndReturn(result);
  }
3103

3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115
  BIND(&if_holey_doubles);
  {
    Callable callable =
        (variant == kIncludes)
            ? Builtins::CallableFor(isolate(),
                                    Builtins::kArrayIncludesHoleyDoubles)
            : Builtins::CallableFor(isolate(),
                                    Builtins::kArrayIndexOfHoleyDoubles);
    Node* result = CallStub(callable, context, elements, search_element,
                            array_length, SmiTag(index_var.value()));
    args.PopAndReturn(result);
  }
3116

3117 3118 3119 3120 3121 3122
  BIND(&return_not_found);
  if (variant == kIncludes) {
    args.PopAndReturn(FalseConstant());
  } else {
    args.PopAndReturn(NumberConstant(-1));
  }
3123

3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134
  BIND(&call_runtime);
  {
    Node* start_from =
        args.GetOptionalArgumentValue(kFromIndexArg, UndefinedConstant());
    Runtime::FunctionId function = variant == kIncludes
                                       ? Runtime::kArrayIncludes_Slow
                                       : Runtime::kArrayIndexOf;
    args.PopAndReturn(
        CallRuntime(function, context, array, search_element, start_from));
  }
}
3135

3136 3137 3138 3139 3140 3141 3142
void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
    SearchVariant variant, Node* context, Node* elements, Node* search_element,
    Node* array_length, Node* from_index) {
  VARIABLE(index_var, MachineType::PointerRepresentation(),
           SmiUntag(from_index));
  VARIABLE(search_num, MachineRepresentation::kFloat64);
  Node* array_length_untagged = SmiUntag(array_length);
3143

3144 3145 3146 3147
  Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
      string_loop(this), bigint_loop(this, &index_var),
      undef_loop(this, &index_var), not_smi(this), not_heap_num(this),
      return_found(this), return_not_found(this);
3148

3149 3150 3151
  GotoIfNot(TaggedIsSmi(search_element), &not_smi);
  search_num.Bind(SmiToFloat64(search_element));
  Goto(&heap_num_loop);
3152

3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173
  BIND(&not_smi);
  if (variant == kIncludes) {
    GotoIf(IsUndefined(search_element), &undef_loop);
  }
  Node* map = LoadMap(search_element);
  GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
  search_num.Bind(LoadHeapNumberValue(search_element));
  Goto(&heap_num_loop);

  BIND(&not_heap_num);
  Node* search_type = LoadMapInstanceType(map);
  GotoIf(IsStringInstanceType(search_type), &string_loop);
  GotoIf(IsBigIntInstanceType(search_type), &bigint_loop);
  Goto(&ident_loop);

  BIND(&ident_loop);
  {
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);
    Node* element_k = LoadFixedArrayElement(elements, index_var.value());
    GotoIf(WordEqual(element_k, search_element), &return_found);
3174

3175 3176 3177
    Increment(&index_var);
    Goto(&ident_loop);
  }
3178

3179 3180
  if (variant == kIncludes) {
    BIND(&undef_loop);
3181

3182 3183 3184 3185 3186
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);
    Node* element_k = LoadFixedArrayElement(elements, index_var.value());
    GotoIf(IsUndefined(element_k), &return_found);
    GotoIf(IsTheHole(element_k), &return_found);
3187

3188 3189
    Increment(&index_var);
    Goto(&undef_loop);
3190 3191
  }

3192
  BIND(&heap_num_loop);
3193
  {
3194
    Label nan_loop(this, &index_var), not_nan_loop(this, &index_var);
3195 3196
    Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
    BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
3197

3198
    BIND(&not_nan_loop);
3199
    {
3200 3201
      Label continue_loop(this), not_smi(this);
      GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3202
                &return_not_found);
3203 3204 3205 3206 3207 3208 3209 3210 3211 3212
      Node* element_k = LoadFixedArrayElement(elements, index_var.value());
      GotoIfNot(TaggedIsSmi(element_k), &not_smi);
      Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
             &return_found, &continue_loop);

      BIND(&not_smi);
      GotoIfNot(IsHeapNumber(element_k), &continue_loop);
      Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
             &return_found, &continue_loop);

3213
      BIND(&continue_loop);
3214
      Increment(&index_var);
3215 3216
      Goto(&not_nan_loop);
    }
3217 3218 3219 3220 3221

    // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
    if (variant == kIncludes) {
      BIND(&nan_loop);
      Label continue_loop(this);
3222
      GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3223
                &return_not_found);
3224 3225 3226 3227 3228 3229
      Node* element_k = LoadFixedArrayElement(elements, index_var.value());
      GotoIf(TaggedIsSmi(element_k), &continue_loop);
      GotoIfNot(IsHeapNumber(element_k), &continue_loop);
      BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_found,
                           &continue_loop);

3230
      BIND(&continue_loop);
3231
      Increment(&index_var);
3232 3233
      Goto(&nan_loop);
    }
3234 3235
  }

3236
  BIND(&string_loop);
3237
  {
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
    TNode<String> search_element_string = CAST(search_element);
    Label continue_loop(this), next_iteration(this, &index_var),
        slow_compare(this), runtime(this, Label::kDeferred);
    TNode<IntPtrT> search_length =
        LoadStringLengthAsWord(search_element_string);
    Goto(&next_iteration);
    BIND(&next_iteration);
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);
    Node* element_k = LoadFixedArrayElement(elements, index_var.value());
    GotoIf(TaggedIsSmi(element_k), &continue_loop);
    GotoIf(WordEqual(search_element_string, element_k), &return_found);
    Node* element_k_type = LoadInstanceType(element_k);
    GotoIfNot(IsStringInstanceType(element_k_type), &continue_loop);
    Branch(WordEqual(search_length, LoadStringLengthAsWord(element_k)),
           &slow_compare, &continue_loop);

    BIND(&slow_compare);
    StringBuiltinsAssembler string_asm(state());
    string_asm.StringEqual_Core(context, search_element_string, search_type,
                                element_k, element_k_type, search_length,
                                &return_found, &continue_loop, &runtime);
    BIND(&runtime);
    TNode<Object> result = CallRuntime(Runtime::kStringEqual, context,
                                       search_element_string, element_k);
    Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
3264

3265 3266 3267 3268
    BIND(&continue_loop);
    Increment(&index_var);
    Goto(&next_iteration);
  }
3269

3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292
  BIND(&bigint_loop);
  {
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);

    Node* element_k = LoadFixedArrayElement(elements, index_var.value());
    Label continue_loop(this);
    GotoIf(TaggedIsSmi(element_k), &continue_loop);
    GotoIfNot(IsBigInt(element_k), &continue_loop);
    TNode<Object> result = CallRuntime(Runtime::kBigIntEqualToBigInt, context,
                                       search_element, element_k);
    Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);

    BIND(&continue_loop);
    Increment(&index_var);
    Goto(&bigint_loop);
  }
  BIND(&return_found);
  if (variant == kIncludes) {
    Return(TrueConstant());
  } else {
    Return(SmiTag(index_var.value()));
  }
3293

3294 3295 3296 3297 3298 3299 3300
  BIND(&return_not_found);
  if (variant == kIncludes) {
    Return(FalseConstant());
  } else {
    Return(NumberConstant(-1));
  }
}
3301

3302 3303 3304 3305 3306 3307 3308 3309
void ArrayIncludesIndexofAssembler::GeneratePackedDoubles(SearchVariant variant,
                                                          Node* elements,
                                                          Node* search_element,
                                                          Node* array_length,
                                                          Node* from_index) {
  VARIABLE(index_var, MachineType::PointerRepresentation(),
           SmiUntag(from_index));
  Node* array_length_untagged = SmiUntag(array_length);
3310

3311 3312 3313 3314 3315
  Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
      hole_loop(this, &index_var), search_notnan(this), return_found(this),
      return_not_found(this);
  VARIABLE(search_num, MachineRepresentation::kFloat64);
  search_num.Bind(Float64Constant(0));
3316

3317 3318 3319
  GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
  search_num.Bind(SmiToFloat64(search_element));
  Goto(&not_nan_loop);
3320

3321 3322
  BIND(&search_notnan);
  GotoIfNot(IsHeapNumber(search_element), &return_not_found);
3323

3324
  search_num.Bind(LoadHeapNumberValue(search_element));
3325

3326 3327
  Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
  BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
3328

3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341
  BIND(&not_nan_loop);
  {
    Label continue_loop(this);
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);
    Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
                                                  MachineType::Float64());
    Branch(Float64Equal(element_k, search_num.value()), &return_found,
           &continue_loop);
    BIND(&continue_loop);
    Increment(&index_var);
    Goto(&not_nan_loop);
  }
3342

3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354
  // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
  if (variant == kIncludes) {
    BIND(&nan_loop);
    Label continue_loop(this);
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);
    Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
                                                  MachineType::Float64());
    BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
    BIND(&continue_loop);
    Increment(&index_var);
    Goto(&nan_loop);
3355 3356
  }

3357
  BIND(&return_found);
3358
  if (variant == kIncludes) {
3359
    Return(TrueConstant());
3360
  } else {
3361
    Return(SmiTag(index_var.value()));
3362
  }
3363

3364
  BIND(&return_not_found);
3365
  if (variant == kIncludes) {
3366
    Return(FalseConstant());
3367
  } else {
3368
    Return(NumberConstant(-1));
3369
  }
3370
}
3371

3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402
void ArrayIncludesIndexofAssembler::GenerateHoleyDoubles(SearchVariant variant,
                                                         Node* elements,
                                                         Node* search_element,
                                                         Node* array_length,
                                                         Node* from_index) {
  VARIABLE(index_var, MachineType::PointerRepresentation(),
           SmiUntag(from_index));
  Node* array_length_untagged = SmiUntag(array_length);

  Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
      hole_loop(this, &index_var), search_notnan(this), return_found(this),
      return_not_found(this);
  VARIABLE(search_num, MachineRepresentation::kFloat64);
  search_num.Bind(Float64Constant(0));

  GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
  search_num.Bind(SmiToFloat64(search_element));
  Goto(&not_nan_loop);

  BIND(&search_notnan);
  if (variant == kIncludes) {
    GotoIf(IsUndefined(search_element), &hole_loop);
  }
  GotoIfNot(IsHeapNumber(search_element), &return_not_found);

  search_num.Bind(LoadHeapNumberValue(search_element));

  Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
  BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);

  BIND(&not_nan_loop);
3403
  {
3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464
    Label continue_loop(this);
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);

    // No need for hole checking here; the following Float64Equal will
    // return 'not equal' for holes anyway.
    Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
                                                  MachineType::Float64());

    Branch(Float64Equal(element_k, search_num.value()), &return_found,
           &continue_loop);
    BIND(&continue_loop);
    Increment(&index_var);
    Goto(&not_nan_loop);
  }

  // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
  if (variant == kIncludes) {
    BIND(&nan_loop);
    Label continue_loop(this);
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);

    // Load double value or continue if it's the hole NaN.
    Node* element_k = LoadFixedDoubleArrayElement(
        elements, index_var.value(), MachineType::Float64(), 0,
        INTPTR_PARAMETERS, &continue_loop);

    BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
    BIND(&continue_loop);
    Increment(&index_var);
    Goto(&nan_loop);
  }

  // Array.p.includes treats the hole as undefined.
  if (variant == kIncludes) {
    BIND(&hole_loop);
    GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
              &return_not_found);

    // Check if the element is a double hole, but don't load it.
    LoadFixedDoubleArrayElement(elements, index_var.value(),
                                MachineType::None(), 0, INTPTR_PARAMETERS,
                                &return_found);

    Increment(&index_var);
    Goto(&hole_loop);
  }

  BIND(&return_found);
  if (variant == kIncludes) {
    Return(TrueConstant());
  } else {
    Return(SmiTag(index_var.value()));
  }

  BIND(&return_not_found);
  if (variant == kIncludes) {
    Return(FalseConstant());
  } else {
    Return(NumberConstant(-1));
3465
  }
3466 3467
}

3468 3469 3470 3471
TF_BUILTIN(ArrayIncludes, ArrayIncludesIndexofAssembler) {
  Generate(kIncludes);
}

3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502
TF_BUILTIN(ArrayIncludesSmiOrObject, ArrayIncludesIndexofAssembler) {
  Node* context = Parameter(Descriptor::kContext);
  Node* elements = Parameter(Descriptor::kElements);
  Node* search_element = Parameter(Descriptor::kSearchElement);
  Node* array_length = Parameter(Descriptor::kLength);
  Node* from_index = Parameter(Descriptor::kFromIndex);

  GenerateSmiOrObject(kIncludes, context, elements, search_element,
                      array_length, from_index);
}

TF_BUILTIN(ArrayIncludesPackedDoubles, ArrayIncludesIndexofAssembler) {
  Node* elements = Parameter(Descriptor::kElements);
  Node* search_element = Parameter(Descriptor::kSearchElement);
  Node* array_length = Parameter(Descriptor::kLength);
  Node* from_index = Parameter(Descriptor::kFromIndex);

  GeneratePackedDoubles(kIncludes, elements, search_element, array_length,
                        from_index);
}

TF_BUILTIN(ArrayIncludesHoleyDoubles, ArrayIncludesIndexofAssembler) {
  Node* elements = Parameter(Descriptor::kElements);
  Node* search_element = Parameter(Descriptor::kSearchElement);
  Node* array_length = Parameter(Descriptor::kLength);
  Node* from_index = Parameter(Descriptor::kFromIndex);

  GenerateHoleyDoubles(kIncludes, elements, search_element, array_length,
                       from_index);
}

3503 3504
TF_BUILTIN(ArrayIndexOf, ArrayIncludesIndexofAssembler) { Generate(kIndexOf); }

3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535
TF_BUILTIN(ArrayIndexOfSmiOrObject, ArrayIncludesIndexofAssembler) {
  Node* context = Parameter(Descriptor::kContext);
  Node* elements = Parameter(Descriptor::kElements);
  Node* search_element = Parameter(Descriptor::kSearchElement);
  Node* array_length = Parameter(Descriptor::kLength);
  Node* from_index = Parameter(Descriptor::kFromIndex);

  GenerateSmiOrObject(kIndexOf, context, elements, search_element, array_length,
                      from_index);
}

TF_BUILTIN(ArrayIndexOfPackedDoubles, ArrayIncludesIndexofAssembler) {
  Node* elements = Parameter(Descriptor::kElements);
  Node* search_element = Parameter(Descriptor::kSearchElement);
  Node* array_length = Parameter(Descriptor::kLength);
  Node* from_index = Parameter(Descriptor::kFromIndex);

  GeneratePackedDoubles(kIndexOf, elements, search_element, array_length,
                        from_index);
}

TF_BUILTIN(ArrayIndexOfHoleyDoubles, ArrayIncludesIndexofAssembler) {
  Node* elements = Parameter(Descriptor::kElements);
  Node* search_element = Parameter(Descriptor::kSearchElement);
  Node* array_length = Parameter(Descriptor::kLength);
  Node* from_index = Parameter(Descriptor::kFromIndex);

  GenerateHoleyDoubles(kIndexOf, elements, search_element, array_length,
                       from_index);
}

3536 3537
// ES #sec-array.prototype.values
TF_BUILTIN(ArrayPrototypeValues, CodeStubAssembler) {
3538 3539
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
3540 3541
  Return(CreateArrayIterator(context, ToObject(context, receiver),
                             IterationKind::kValues));
3542 3543
}

3544 3545
// ES #sec-array.prototype.entries
TF_BUILTIN(ArrayPrototypeEntries, CodeStubAssembler) {
3546 3547
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
3548 3549
  Return(CreateArrayIterator(context, ToObject(context, receiver),
                             IterationKind::kEntries));
3550 3551
}

3552 3553
// ES #sec-array.prototype.keys
TF_BUILTIN(ArrayPrototypeKeys, CodeStubAssembler) {
3554 3555
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
  TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
3556 3557
  Return(CreateArrayIterator(context, ToObject(context, receiver),
                             IterationKind::kKeys));
3558 3559
}

3560
// ES #sec-%arrayiteratorprototype%.next
3561
TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
3562
  const char* method_name = "Array Iterator.prototype.next";
3563

3564
  TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3565
  Node* iterator = Parameter(Descriptor::kReceiver);
3566

3567 3568
  VARIABLE(var_value, MachineRepresentation::kTagged);
  VARIABLE(var_done, MachineRepresentation::kTagged);
3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582

  // Required, or else `throw_bad_receiver` fails a DCHECK due to these
  // variables not being bound along all paths, despite not being used.
  var_done.Bind(TrueConstant());
  var_value.Bind(UndefinedConstant());

  Label throw_bad_receiver(this, Label::kDeferred);
  Label set_done(this);
  Label allocate_entry_if_needed(this);
  Label allocate_iterator_result(this);

  // If O does not have all of the internal slots of an Array Iterator Instance
  // (22.1.5.3), throw a TypeError exception
  GotoIf(TaggedIsSmi(iterator), &throw_bad_receiver);
3583
  GotoIfNot(IsJSArrayIterator(iterator), &throw_bad_receiver);
3584 3585 3586 3587 3588 3589 3590 3591 3592

  // Let a be O.[[IteratedObject]].
  Node* array =
      LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset);

  // Let index be O.[[ArrayIteratorNextIndex]].
  Node* index = LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset);
  Node* array_map = LoadMap(array);

3593 3594 3595 3596
  Label if_detached(this, Label::kDeferred);

  Label if_typedarray(this), if_other(this, Label::kDeferred), if_array(this),
      if_generic(this, Label::kDeferred);
3597

3598 3599 3600 3601
  Node* array_type = LoadInstanceType(array);
  GotoIf(InstanceTypeEqual(array_type, JS_ARRAY_TYPE), &if_array);
  Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_typedarray,
         &if_other);
3602

3603
  BIND(&if_array);
3604
  {
3605 3606 3607
    // We can only handle fast elements here.
    Node* elements_kind = LoadMapElementsKind(array_map);
    GotoIfNot(IsFastElementsKind(elements_kind), &if_other);
3608

3609
    Node* length = LoadJSArrayLength(array);
3610 3611 3612 3613 3614 3615

    CSA_ASSERT(this, TaggedIsSmi(length));
    CSA_ASSERT(this, TaggedIsSmi(index));

    GotoIfNot(SmiBelow(index, length), &set_done);

3616
    var_value.Bind(index);
3617
    Node* one = SmiConstant(1);
3618 3619 3620 3621
    StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
                                   SmiAdd(index, one));
    var_done.Bind(FalseConstant());

3622 3623 3624 3625
    GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
                           iterator, JSArrayIterator::kKindOffset),
                       Int32Constant(static_cast<int>(IterationKind::kKeys))),
           &allocate_iterator_result);
3626

3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648
    Node* elements = LoadElements(array);
    Label if_packed(this), if_holey(this), if_packed_double(this),
        if_holey_double(this), if_unknown_kind(this, Label::kDeferred);
    int32_t kinds[] = {// Handled by if_packed.
                       PACKED_SMI_ELEMENTS, PACKED_ELEMENTS,
                       // Handled by if_holey.
                       HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS,
                       // Handled by if_packed_double.
                       PACKED_DOUBLE_ELEMENTS,
                       // Handled by if_holey_double.
                       HOLEY_DOUBLE_ELEMENTS};
    Label* labels[] = {// PACKED_{SMI,}_ELEMENTS
                       &if_packed, &if_packed,
                       // HOLEY_{SMI,}_ELEMENTS
                       &if_holey, &if_holey,
                       // PACKED_DOUBLE_ELEMENTS
                       &if_packed_double,
                       // HOLEY_DOUBLE_ELEMENTS
                       &if_holey_double};
    Switch(elements_kind, &if_unknown_kind, kinds, labels, arraysize(kinds));

    BIND(&if_packed);
3649 3650 3651 3652 3653
    {
      var_value.Bind(LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS));
      Goto(&allocate_entry_if_needed);
    }

3654
    BIND(&if_holey);
3655
    {
3656 3657 3658 3659 3660 3661
      Node* element = LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS);
      var_value.Bind(element);
      GotoIfNot(WordEqual(element, TheHoleConstant()),
                &allocate_entry_if_needed);
      GotoIf(IsNoElementsProtectorCellInvalid(), &if_generic);
      var_value.Bind(UndefinedConstant());
3662 3663 3664
      Goto(&allocate_entry_if_needed);
    }

3665
    BIND(&if_packed_double);
3666
    {
3667 3668 3669
      Node* value = LoadFixedDoubleArrayElement(
          elements, index, MachineType::Float64(), 0, SMI_PARAMETERS);
      var_value.Bind(AllocateHeapNumberWithValue(value));
3670 3671 3672
      Goto(&allocate_entry_if_needed);
    }

3673
    BIND(&if_holey_double);
3674
    {
3675
      Label if_hole(this, Label::kDeferred);
3676
      Node* value = LoadFixedDoubleArrayElement(
3677
          elements, index, MachineType::Float64(), 0, SMI_PARAMETERS, &if_hole);
3678 3679
      var_value.Bind(AllocateHeapNumberWithValue(value));
      Goto(&allocate_entry_if_needed);
3680 3681 3682 3683
      BIND(&if_hole);
      GotoIf(IsNoElementsProtectorCellInvalid(), &if_generic);
      var_value.Bind(UndefinedConstant());
      Goto(&allocate_entry_if_needed);
3684
    }
3685 3686 3687

    BIND(&if_unknown_kind);
    Unreachable();
3688 3689
  }

3690
  BIND(&if_other);
3691 3692
  {
    // If a is undefined, return CreateIterResultObject(undefined, true)
3693
    GotoIf(IsUndefined(array), &allocate_iterator_result);
3694

3695 3696 3697
    Node* length =
        CallBuiltin(Builtins::kToLength, context,
                    GetProperty(context, array, factory()->length_string()));
3698

3699
    GotoIfNumberGreaterThanOrEqual(index, length, &set_done);
3700

3701 3702 3703 3704
    var_value.Bind(index);
    StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset,
                     NumberInc(index));
    var_done.Bind(FalseConstant());
3705

3706 3707 3708 3709 3710 3711
    GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
                           iterator, JSArrayIterator::kKindOffset),
                       Int32Constant(static_cast<int>(IterationKind::kKeys))),
           &allocate_iterator_result);
    Goto(&if_generic);
  }
3712

3713 3714 3715 3716 3717
  BIND(&if_generic);
  {
    var_value.Bind(GetProperty(context, array, index));
    Goto(&allocate_entry_if_needed);
  }
3718

3719 3720 3721 3722
  BIND(&if_typedarray);
  {
    Node* buffer = LoadObjectField(array, JSTypedArray::kBufferOffset);
    GotoIf(IsDetachedBuffer(buffer), &if_detached);
3723

3724
    Node* length = LoadObjectField(array, JSTypedArray::kLengthOffset);
3725

3726 3727
    CSA_ASSERT(this, TaggedIsSmi(length));
    CSA_ASSERT(this, TaggedIsSmi(index));
3728

3729
    GotoIfNot(SmiBelow(index, length), &set_done);
3730

3731 3732 3733 3734 3735
    var_value.Bind(index);
    Node* one = SmiConstant(1);
    StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
                                   SmiAdd(index, one));
    var_done.Bind(FalseConstant());
3736

3737 3738 3739 3740
    GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
                           iterator, JSArrayIterator::kKindOffset),
                       Int32Constant(static_cast<int>(IterationKind::kKeys))),
           &allocate_iterator_result);
3741

3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756
    Node* elements_kind = LoadMapElementsKind(array_map);
    Node* elements = LoadElements(array);
    Node* base_ptr =
        LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
    Node* external_ptr =
        LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
                        MachineType::Pointer());
    Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);

    Label if_unknown_type(this, Label::kDeferred);
    int32_t elements_kinds[] = {
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) TYPE##_ELEMENTS,
        TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
    };
3757

3758 3759 3760 3761
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
  Label if_##type##array(this);
    TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
3762

3763 3764 3765 3766 3767 3768
    Label* elements_kind_labels[] = {
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) &if_##type##array,
        TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
    };
    STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
3769

3770 3771
    Switch(elements_kind, &if_unknown_type, elements_kinds,
           elements_kind_labels, arraysize(elements_kinds));
3772

3773 3774
    BIND(&if_unknown_type);
    Unreachable();
3775

3776 3777 3778 3779 3780 3781 3782 3783 3784
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)     \
  BIND(&if_##type##array);                                  \
  {                                                         \
    var_value.Bind(LoadFixedTypedArrayElementAsTagged(      \
        data_ptr, index, TYPE##_ELEMENTS, SMI_PARAMETERS)); \
    Goto(&allocate_entry_if_needed);                        \
  }
    TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
3785

3786 3787
    BIND(&if_detached);
    ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
3788 3789
  }

3790
  BIND(&set_done);
3791 3792 3793 3794 3795 3796
  {
    StoreObjectFieldNoWriteBarrier(
        iterator, JSArrayIterator::kIteratedObjectOffset, UndefinedConstant());
    Goto(&allocate_iterator_result);
  }

3797
  BIND(&allocate_entry_if_needed);
3798
  {
3799 3800 3801
    GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
                           iterator, JSArrayIterator::kKindOffset),
                       Int32Constant(static_cast<int>(IterationKind::kValues))),
3802 3803
           &allocate_iterator_result);

3804
    Node* elements = AllocateFixedArray(PACKED_ELEMENTS, IntPtrConstant(2));
3805 3806 3807 3808 3809
    StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER);
    StoreFixedArrayElement(elements, 1, var_value.value(), SKIP_WRITE_BARRIER);

    Node* entry = Allocate(JSArray::kSize);
    Node* map = LoadContextElement(LoadNativeContext(context),
3810
                                   Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
3811 3812

    StoreMapNoWriteBarrier(entry, map);
3813
    StoreObjectFieldRoot(entry, JSArray::kPropertiesOrHashOffset,
3814 3815 3816
                         Heap::kEmptyFixedArrayRootIndex);
    StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset, elements);
    StoreObjectFieldNoWriteBarrier(entry, JSArray::kLengthOffset,
3817
                                   SmiConstant(2));
3818 3819 3820 3821 3822

    var_value.Bind(entry);
    Goto(&allocate_iterator_result);
  }

3823
  BIND(&allocate_iterator_result);
3824 3825 3826 3827 3828
  {
    Node* result = Allocate(JSIteratorResult::kSize);
    Node* map = LoadContextElement(LoadNativeContext(context),
                                   Context::ITERATOR_RESULT_MAP_INDEX);
    StoreMapNoWriteBarrier(result, map);
3829
    StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOrHashOffset,
3830 3831 3832 3833 3834 3835 3836 3837 3838 3839
                         Heap::kEmptyFixedArrayRootIndex);
    StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
                         Heap::kEmptyFixedArrayRootIndex);
    StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset,
                                   var_value.value());
    StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset,
                                   var_done.value());
    Return(result);
  }

3840
  BIND(&throw_bad_receiver);
3841 3842
  {
    // The {receiver} is not a valid JSArrayIterator.
3843 3844
    ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver,
                   StringConstant(method_name), iterator);
3845 3846 3847 3848 3849
  }
}

}  // namespace internal
}  // namespace v8