Home | History | Annotate | Download | only in builtins
      1 // Copyright 2016 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/builtins/builtins.h"
      6 #include "src/builtins/builtins-utils.h"
      7 
      8 #include "src/code-factory.h"
      9 #include "src/code-stub-assembler.h"
     10 #include "src/contexts.h"
     11 #include "src/counters.h"
     12 #include "src/elements.h"
     13 #include "src/isolate.h"
     14 #include "src/lookup.h"
     15 #include "src/objects-inl.h"
     16 #include "src/prototype.h"
     17 
     18 namespace v8 {
     19 namespace internal {
     20 
     21 namespace {
     22 
     23 inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) {
     24   // This is an extended version of ECMA-262 7.1.11 handling signed values
     25   // Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
     26   if (object->IsSmi()) {
     27     *out = Smi::cast(object)->value();
     28     return true;
     29   } else if (object->IsHeapNumber()) {
     30     double value = HeapNumber::cast(object)->value();
     31     if (std::isnan(value)) {
     32       *out = 0;
     33     } else if (value > kMaxInt) {
     34       *out = kMaxInt;
     35     } else if (value < kMinInt) {
     36       *out = kMinInt;
     37     } else {
     38       *out = static_cast<int>(value);
     39     }
     40     return true;
     41   } else if (object->IsNullOrUndefined(isolate)) {
     42     *out = 0;
     43     return true;
     44   } else if (object->IsBoolean()) {
     45     *out = object->IsTrue(isolate);
     46     return true;
     47   }
     48   return false;
     49 }
     50 
     51 inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object,
     52                                      int* out) {
     53   Context* context = *isolate->native_context();
     54   Map* map = object->map();
     55   if (map != context->sloppy_arguments_map() &&
     56       map != context->strict_arguments_map() &&
     57       map != context->fast_aliased_arguments_map()) {
     58     return false;
     59   }
     60   DCHECK(object->HasFastElements() || object->HasFastArgumentsElements());
     61   Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex);
     62   if (!len_obj->IsSmi()) return false;
     63   *out = Max(0, Smi::cast(len_obj)->value());
     64 
     65   FixedArray* parameters = FixedArray::cast(object->elements());
     66   if (object->HasSloppyArgumentsElements()) {
     67     FixedArray* arguments = FixedArray::cast(parameters->get(1));
     68     return *out <= arguments->length();
     69   }
     70   return *out <= parameters->length();
     71 }
     72 
     73 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
     74                                               JSArray* receiver) {
     75   return JSObject::PrototypeHasNoElements(isolate, receiver);
     76 }
     77 
     78 inline bool HasSimpleElements(JSObject* current) {
     79   return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER &&
     80          !current->GetElementsAccessor()->HasAccessors(current);
     81 }
     82 
     83 inline bool HasOnlySimpleReceiverElements(Isolate* isolate,
     84                                           JSObject* receiver) {
     85   // Check that we have no accessors on the receiver's elements.
     86   if (!HasSimpleElements(receiver)) return false;
     87   return JSObject::PrototypeHasNoElements(isolate, receiver);
     88 }
     89 
     90 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) {
     91   DisallowHeapAllocation no_gc;
     92   PrototypeIterator iter(isolate, receiver, kStartAtReceiver);
     93   for (; !iter.IsAtEnd(); iter.Advance()) {
     94     if (iter.GetCurrent()->IsJSProxy()) return false;
     95     JSObject* current = iter.GetCurrent<JSObject>();
     96     if (!HasSimpleElements(current)) return false;
     97   }
     98   return true;
     99 }
    100 
    101 // Returns |false| if not applicable.
    102 MUST_USE_RESULT
    103 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate,
    104                                                   Handle<Object> receiver,
    105                                                   BuiltinArguments* args,
    106                                                   int first_added_arg) {
    107   if (!receiver->IsJSArray()) return false;
    108   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
    109   ElementsKind origin_kind = array->GetElementsKind();
    110   if (IsDictionaryElementsKind(origin_kind)) return false;
    111   if (!array->map()->is_extensible()) return false;
    112   if (args == nullptr) return true;
    113 
    114   // If there may be elements accessors in the prototype chain, the fast path
    115   // cannot be used if there arguments to add to the array.
    116   if (!IsJSArrayFastElementMovingAllowed(isolate, *array)) return false;
    117 
    118   // Adding elements to the array prototype would break code that makes sure
    119   // it has no elements. Handle that elsewhere.
    120   if (isolate->IsAnyInitialArrayPrototype(array)) return false;
    121 
    122   // Need to ensure that the arguments passed in args can be contained in
    123   // the array.
    124   int args_length = args->length();
    125   if (first_added_arg >= args_length) return true;
    126 
    127   if (IsFastObjectElementsKind(origin_kind)) return true;
    128   ElementsKind target_kind = origin_kind;
    129   {
    130     DisallowHeapAllocation no_gc;
    131     for (int i = first_added_arg; i < args_length; i++) {
    132       Object* arg = (*args)[i];
    133       if (arg->IsHeapObject()) {
    134         if (arg->IsHeapNumber()) {
    135           target_kind = FAST_DOUBLE_ELEMENTS;
    136         } else {
    137           target_kind = FAST_ELEMENTS;
    138           break;
    139         }
    140       }
    141     }
    142   }
    143   if (target_kind != origin_kind) {
    144     // Use a short-lived HandleScope to avoid creating several copies of the
    145     // elements handle which would cause issues when left-trimming later-on.
    146     HandleScope scope(isolate);
    147     JSObject::TransitionElementsKind(array, target_kind);
    148   }
    149   return true;
    150 }
    151 
    152 MUST_USE_RESULT static Object* CallJsIntrinsic(Isolate* isolate,
    153                                                Handle<JSFunction> function,
    154                                                BuiltinArguments args) {
    155   HandleScope handleScope(isolate);
    156   int argc = args.length() - 1;
    157   ScopedVector<Handle<Object>> argv(argc);
    158   for (int i = 0; i < argc; ++i) {
    159     argv[i] = args.at(i + 1);
    160   }
    161   RETURN_RESULT_OR_FAILURE(
    162       isolate,
    163       Execution::Call(isolate, function, args.receiver(), argc, argv.start()));
    164 }
    165 }  // namespace
    166 
    167 BUILTIN(ArrayPush) {
    168   HandleScope scope(isolate);
    169   Handle<Object> receiver = args.receiver();
    170   if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) {
    171     return CallJsIntrinsic(isolate, isolate->array_push(), args);
    172   }
    173   // Fast Elements Path
    174   int to_add = args.length() - 1;
    175   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
    176   int len = Smi::cast(array->length())->value();
    177   if (to_add == 0) return Smi::FromInt(len);
    178 
    179   // Currently fixed arrays cannot grow too big, so we should never hit this.
    180   DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value());
    181 
    182   if (JSArray::HasReadOnlyLength(array)) {
    183     return CallJsIntrinsic(isolate, isolate->array_push(), args);
    184   }
    185 
    186   ElementsAccessor* accessor = array->GetElementsAccessor();
    187   int new_length = accessor->Push(array, &args, to_add);
    188   return Smi::FromInt(new_length);
    189 }
    190 
    191 void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) {
    192   typedef compiler::Node Node;
    193   typedef CodeStubAssembler::Label Label;
    194   typedef CodeStubAssembler::Variable Variable;
    195   CodeStubAssembler assembler(state);
    196   Variable arg_index(&assembler, MachineType::PointerRepresentation());
    197   Label default_label(&assembler, &arg_index);
    198   Label smi_transition(&assembler);
    199   Label object_push_pre(&assembler);
    200   Label object_push(&assembler, &arg_index);
    201   Label double_push(&assembler, &arg_index);
    202   Label double_transition(&assembler);
    203   Label runtime(&assembler, Label::kDeferred);
    204 
    205   Node* argc = assembler.Parameter(BuiltinDescriptor::kArgumentsCount);
    206   Node* context = assembler.Parameter(BuiltinDescriptor::kContext);
    207   Node* new_target = assembler.Parameter(BuiltinDescriptor::kNewTarget);
    208 
    209   CodeStubArguments args(&assembler, assembler.ChangeInt32ToIntPtr(argc));
    210   Node* receiver = args.GetReceiver();
    211   Node* kind = nullptr;
    212 
    213   Label fast(&assembler);
    214   {
    215     assembler.BranchIfFastJSArray(
    216         receiver, context, CodeStubAssembler::FastJSArrayAccessMode::ANY_ACCESS,
    217         &fast, &runtime);
    218   }
    219 
    220   assembler.Bind(&fast);
    221   {
    222     // Disallow pushing onto prototypes. It might be the JSArray prototype.
    223     // Disallow pushing onto non-extensible objects.
    224     assembler.Comment("Disallow pushing onto prototypes");
    225     Node* map = assembler.LoadMap(receiver);
    226     Node* bit_field2 = assembler.LoadMapBitField2(map);
    227     int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
    228                (1 << Map::kIsExtensible);
    229     Node* test = assembler.Word32And(bit_field2, assembler.Int32Constant(mask));
    230     assembler.GotoIf(
    231         assembler.Word32NotEqual(
    232             test, assembler.Int32Constant(1 << Map::kIsExtensible)),
    233         &runtime);
    234 
    235     // Disallow pushing onto arrays in dictionary named property mode. We need
    236     // to figure out whether the length property is still writable.
    237     assembler.Comment(
    238         "Disallow pushing onto arrays in dictionary named property mode");
    239     assembler.GotoIf(assembler.IsDictionaryMap(map), &runtime);
    240 
    241     // Check whether the length property is writable. The length property is the
    242     // only default named property on arrays. It's nonconfigurable, hence is
    243     // guaranteed to stay the first property.
    244     Node* descriptors = assembler.LoadMapDescriptors(map);
    245     Node* details = assembler.LoadFixedArrayElement(
    246         descriptors, DescriptorArray::ToDetailsIndex(0));
    247     assembler.GotoIf(
    248         assembler.IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask),
    249         &runtime);
    250 
    251     arg_index.Bind(assembler.IntPtrConstant(0));
    252     kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2);
    253 
    254     assembler.GotoIf(
    255         assembler.Int32GreaterThan(
    256             kind, assembler.Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
    257         &object_push_pre);
    258 
    259     Node* new_length = assembler.BuildAppendJSArray(
    260         FAST_SMI_ELEMENTS, context, receiver, args, arg_index, &smi_transition);
    261     args.PopAndReturn(new_length);
    262   }
    263 
    264   // If the argument is not a smi, then use a heavyweight SetProperty to
    265   // transition the array for only the single next element. If the argument is
    266   // a smi, the failure is due to some other reason and we should fall back on
    267   // the most generic implementation for the rest of the array.
    268   assembler.Bind(&smi_transition);
    269   {
    270     Node* arg = args.AtIndex(arg_index.value());
    271     assembler.GotoIf(assembler.TaggedIsSmi(arg), &default_label);
    272     Node* length = assembler.LoadJSArrayLength(receiver);
    273     // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
    274     // calling into the runtime to do the elements transition is overkill.
    275     assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
    276                           assembler.SmiConstant(STRICT));
    277     assembler.Increment(arg_index);
    278     // The runtime SetProperty call could have converted the array to dictionary
    279     // mode, which must be detected to abort the fast-path.
    280     Node* map = assembler.LoadMap(receiver);
    281     Node* bit_field2 = assembler.LoadMapBitField2(map);
    282     Node* kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2);
    283     assembler.GotoIf(assembler.Word32Equal(
    284                          kind, assembler.Int32Constant(DICTIONARY_ELEMENTS)),
    285                      &default_label);
    286 
    287     assembler.GotoIfNotNumber(arg, &object_push);
    288     assembler.Goto(&double_push);
    289   }
    290 
    291   assembler.Bind(&object_push_pre);
    292   {
    293     assembler.Branch(assembler.Int32GreaterThan(
    294                          kind, assembler.Int32Constant(FAST_HOLEY_ELEMENTS)),
    295                      &double_push, &object_push);
    296   }
    297 
    298   assembler.Bind(&object_push);
    299   {
    300     Node* new_length = assembler.BuildAppendJSArray(
    301         FAST_ELEMENTS, context, receiver, args, arg_index, &default_label);
    302     args.PopAndReturn(new_length);
    303   }
    304 
    305   assembler.Bind(&double_push);
    306   {
    307     Node* new_length =
    308         assembler.BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver,
    309                                      args, arg_index, &double_transition);
    310     args.PopAndReturn(new_length);
    311   }
    312 
    313   // If the argument is not a double, then use a heavyweight SetProperty to
    314   // transition the array for only the single next element. If the argument is
    315   // a double, the failure is due to some other reason and we should fall back
    316   // on the most generic implementation for the rest of the array.
    317   assembler.Bind(&double_transition);
    318   {
    319     Node* arg = args.AtIndex(arg_index.value());
    320     assembler.GotoIfNumber(arg, &default_label);
    321     Node* length = assembler.LoadJSArrayLength(receiver);
    322     // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
    323     // calling into the runtime to do the elements transition is overkill.
    324     assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
    325                           assembler.SmiConstant(STRICT));
    326     assembler.Increment(arg_index);
    327     // The runtime SetProperty call could have converted the array to dictionary
    328     // mode, which must be detected to abort the fast-path.
    329     Node* map = assembler.LoadMap(receiver);
    330     Node* bit_field2 = assembler.LoadMapBitField2(map);
    331     Node* kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2);
    332     assembler.GotoIf(assembler.Word32Equal(
    333                          kind, assembler.Int32Constant(DICTIONARY_ELEMENTS)),
    334                      &default_label);
    335     assembler.Goto(&object_push);
    336   }
    337 
    338   // Fallback that stores un-processed arguments using the full, heavyweight
    339   // SetProperty machinery.
    340   assembler.Bind(&default_label);
    341   {
    342     args.ForEach(
    343         [&assembler, receiver, context](Node* arg) {
    344           Node* length = assembler.LoadJSArrayLength(receiver);
    345           assembler.CallRuntime(Runtime::kSetProperty, context, receiver,
    346                                 length, arg, assembler.SmiConstant(STRICT));
    347         },
    348         arg_index.value());
    349     args.PopAndReturn(assembler.LoadJSArrayLength(receiver));
    350   }
    351 
    352   assembler.Bind(&runtime);
    353   {
    354     Node* target = assembler.LoadFromFrame(
    355         StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer());
    356     assembler.TailCallStub(CodeFactory::ArrayPush(assembler.isolate()), context,
    357                            target, new_target, argc);
    358   }
    359 }
    360 
    361 BUILTIN(ArrayPop) {
    362   HandleScope scope(isolate);
    363   Handle<Object> receiver = args.receiver();
    364   if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) {
    365     return CallJsIntrinsic(isolate, isolate->array_pop(), args);
    366   }
    367 
    368   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
    369 
    370   uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value());
    371   if (len == 0) return isolate->heap()->undefined_value();
    372 
    373   if (JSArray::HasReadOnlyLength(array)) {
    374     return CallJsIntrinsic(isolate, isolate->array_pop(), args);
    375   }
    376 
    377   Handle<Object> result;
    378   if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
    379     // Fast Elements Path
    380     result = array->GetElementsAccessor()->Pop(array);
    381   } else {
    382     // Use Slow Lookup otherwise
    383     uint32_t new_length = len - 1;
    384     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    385         isolate, result, JSReceiver::GetElement(isolate, array, new_length));
    386     JSArray::SetLength(array, new_length);
    387   }
    388   return *result;
    389 }
    390 
    391 BUILTIN(ArrayShift) {
    392   HandleScope scope(isolate);
    393   Heap* heap = isolate->heap();
    394   Handle<Object> receiver = args.receiver();
    395   if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0) ||
    396       !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
    397     return CallJsIntrinsic(isolate, isolate->array_shift(), args);
    398   }
    399   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
    400 
    401   int len = Smi::cast(array->length())->value();
    402   if (len == 0) return heap->undefined_value();
    403 
    404   if (JSArray::HasReadOnlyLength(array)) {
    405     return CallJsIntrinsic(isolate, isolate->array_shift(), args);
    406   }
    407 
    408   Handle<Object> first = array->GetElementsAccessor()->Shift(array);
    409   return *first;
    410 }
    411 
    412 BUILTIN(ArrayUnshift) {
    413   HandleScope scope(isolate);
    414   Handle<Object> receiver = args.receiver();
    415   if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) {
    416     return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
    417   }
    418   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
    419   int to_add = args.length() - 1;
    420   if (to_add == 0) return array->length();
    421 
    422   // Currently fixed arrays cannot grow too big, so we should never hit this.
    423   DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value());
    424 
    425   if (JSArray::HasReadOnlyLength(array)) {
    426     return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
    427   }
    428 
    429   ElementsAccessor* accessor = array->GetElementsAccessor();
    430   int new_length = accessor->Unshift(array, &args, to_add);
    431   return Smi::FromInt(new_length);
    432 }
    433 
    434 class ForEachCodeStubAssembler : public CodeStubAssembler {
    435  public:
    436   explicit ForEachCodeStubAssembler(compiler::CodeAssemblerState* state)
    437       : CodeStubAssembler(state) {}
    438 
    439   void VisitOneElement(Node* context, Node* this_arg, Node* o, Node* k,
    440                        Node* callbackfn) {
    441     Comment("begin VisitOneElement");
    442 
    443     // a. Let Pk be ToString(k).
    444     Node* p_k = ToString(context, k);
    445 
    446     // b. Let kPresent be HasProperty(O, Pk).
    447     // c. ReturnIfAbrupt(kPresent).
    448     Node* k_present =
    449         CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o);
    450 
    451     // d. If kPresent is true, then
    452     Label not_present(this);
    453     GotoIf(WordNotEqual(k_present, TrueConstant()), &not_present);
    454 
    455     // i. Let kValue be Get(O, Pk).
    456     // ii. ReturnIfAbrupt(kValue).
    457     Node* k_value =
    458         CallStub(CodeFactory::GetProperty(isolate()), context, o, k);
    459 
    460     // iii. Let funcResult be Call(callbackfn, T, kValue, k, O).
    461     // iv. ReturnIfAbrupt(funcResult).
    462     CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, k_value,
    463            k, o);
    464 
    465     Goto(&not_present);
    466     Bind(&not_present);
    467     Comment("end VisitOneElement");
    468   }
    469 
    470   void VisitAllFastElements(Node* context, ElementsKind kind, Node* this_arg,
    471                             Node* o, Node* len, Node* callbackfn,
    472                             ParameterMode mode) {
    473     Comment("begin VisitAllFastElements");
    474     Variable original_map(this, MachineRepresentation::kTagged);
    475     original_map.Bind(LoadMap(o));
    476     VariableList list({&original_map}, zone());
    477     BuildFastLoop(
    478         list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode),
    479         [context, kind, this, o, &original_map, callbackfn, this_arg,
    480          mode](Node* index) {
    481           Label one_element_done(this), array_changed(this, Label::kDeferred),
    482               hole_element(this);
    483 
    484           // Check if o's map has changed during the callback. If so, we have to
    485           // fall back to the slower spec implementation for the rest of the
    486           // iteration.
    487           Node* o_map = LoadMap(o);
    488           GotoIf(WordNotEqual(o_map, original_map.value()), &array_changed);
    489 
    490           // Check if o's length has changed during the callback and if the
    491           // index is now out of range of the new length.
    492           Node* tagged_index = ParameterToTagged(index, mode);
    493           GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)),
    494                  &array_changed);
    495 
    496           // Re-load the elements array. If may have been resized.
    497           Node* elements = LoadElements(o);
    498 
    499           // Fast case: load the element directly from the elements FixedArray
    500           // and call the callback if the element is not the hole.
    501           DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS);
    502           int base_size = kind == FAST_ELEMENTS
    503                               ? FixedArray::kHeaderSize
    504                               : (FixedArray::kHeaderSize - kHeapObjectTag);
    505           Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size);
    506           Node* value = nullptr;
    507           if (kind == FAST_ELEMENTS) {
    508             value = LoadObjectField(elements, offset);
    509             GotoIf(WordEqual(value, TheHoleConstant()), &hole_element);
    510           } else {
    511             Node* double_value =
    512                 LoadDoubleWithHoleCheck(elements, offset, &hole_element);
    513             value = AllocateHeapNumberWithValue(double_value);
    514           }
    515           CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg,
    516                  value, tagged_index, o);
    517           Goto(&one_element_done);
    518 
    519           Bind(&hole_element);
    520           BranchIfPrototypesHaveNoElements(o_map, &one_element_done,
    521                                            &array_changed);
    522 
    523           // O's changed during the forEach. Use the implementation precisely
    524           // specified in the spec for the rest of the iteration, also making
    525           // the failed original_map sticky in case of a subseuent change that
    526           // goes back to the original map.
    527           Bind(&array_changed);
    528           VisitOneElement(context, this_arg, o, ParameterToTagged(index, mode),
    529                           callbackfn);
    530           original_map.Bind(UndefinedConstant());
    531           Goto(&one_element_done);
    532 
    533           Bind(&one_element_done);
    534         },
    535         1, mode, IndexAdvanceMode::kPost);
    536     Comment("end VisitAllFastElements");
    537   }
    538 };
    539 
    540 TF_BUILTIN(ArrayForEach, ForEachCodeStubAssembler) {
    541   Label non_array(this), examine_elements(this), fast_elements(this),
    542       slow(this), maybe_double_elements(this), fast_double_elements(this);
    543 
    544   Node* receiver = Parameter(ForEachDescriptor::kReceiver);
    545   Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
    546   Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
    547   Node* context = Parameter(ForEachDescriptor::kContext);
    548 
    549   // TODO(danno): Seriously? Do we really need to throw the exact error message
    550   // on null and undefined so that the webkit tests pass?
    551   Label throw_null_undefined_exception(this, Label::kDeferred);
    552   GotoIf(WordEqual(receiver, NullConstant()), &throw_null_undefined_exception);
    553   GotoIf(WordEqual(receiver, UndefinedConstant()),
    554          &throw_null_undefined_exception);
    555 
    556   // By the book: taken directly from the ECMAScript 2015 specification
    557 
    558   // 1. Let O be ToObject(this value).
    559   // 2. ReturnIfAbrupt(O)
    560   Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver);
    561 
    562   // 3. Let len be ToLength(Get(O, "length")).
    563   // 4. ReturnIfAbrupt(len).
    564   Variable merged_length(this, MachineRepresentation::kTagged);
    565   Label has_length(this, &merged_length), not_js_array(this);
    566   GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), &not_js_array);
    567   merged_length.Bind(LoadJSArrayLength(o));
    568   Goto(&has_length);
    569   Bind(&not_js_array);
    570   Node* len_property =
    571       CallStub(CodeFactory::GetProperty(isolate()), context, o,
    572                HeapConstant(isolate()->factory()->length_string()));
    573   merged_length.Bind(
    574       CallStub(CodeFactory::ToLength(isolate()), context, len_property));
    575   Goto(&has_length);
    576   Bind(&has_length);
    577   Node* len = merged_length.value();
    578 
    579   // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
    580   Label type_exception(this, Label::kDeferred);
    581   GotoIf(TaggedIsSmi(callbackfn), &type_exception);
    582   GotoIfNot(IsCallableMap(LoadMap(callbackfn)), &type_exception);
    583 
    584   // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
    585   // [Already done by the arguments adapter]
    586 
    587   // Non-smi lengths must use the slow path.
    588   GotoIf(TaggedIsNotSmi(len), &slow);
    589 
    590   BranchIfFastJSArray(o, context,
    591                       CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
    592                       &examine_elements, &slow);
    593 
    594   Bind(&examine_elements);
    595 
    596   ParameterMode mode = OptimalParameterMode();
    597 
    598   // Select by ElementsKind
    599   Node* o_map = LoadMap(o);
    600   Node* bit_field2 = LoadMapBitField2(o_map);
    601   Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
    602   Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
    603          &maybe_double_elements, &fast_elements);
    604 
    605   Bind(&fast_elements);
    606   {
    607     VisitAllFastElements(context, FAST_ELEMENTS, this_arg, o, len, callbackfn,
    608                          mode);
    609 
    610     // No exception, return success
    611     Return(UndefinedConstant());
    612   }
    613 
    614   Bind(&maybe_double_elements);
    615   Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)),
    616          &slow, &fast_double_elements);
    617 
    618   Bind(&fast_double_elements);
    619   {
    620     VisitAllFastElements(context, FAST_DOUBLE_ELEMENTS, this_arg, o, len,
    621                          callbackfn, mode);
    622 
    623     // No exception, return success
    624     Return(UndefinedConstant());
    625   }
    626 
    627   Bind(&slow);
    628   {
    629     // By the book: taken from the ECMAScript 2015 specification (cont.)
    630 
    631     // 7. Let k be 0.
    632     Variable k(this, MachineRepresentation::kTagged);
    633     k.Bind(SmiConstant(0));
    634 
    635     // 8. Repeat, while k < len
    636     Label loop(this, &k);
    637     Label after_loop(this);
    638     Goto(&loop);
    639     Bind(&loop);
    640     {
    641       GotoUnlessNumberLessThan(k.value(), len, &after_loop);
    642 
    643       VisitOneElement(context, this_arg, o, k.value(), callbackfn);
    644 
    645       // e. Increase k by 1.
    646       k.Bind(NumberInc(k.value()));
    647       Goto(&loop);
    648     }
    649     Bind(&after_loop);
    650     Return(UndefinedConstant());
    651   }
    652 
    653   Bind(&throw_null_undefined_exception);
    654   {
    655     CallRuntime(Runtime::kThrowTypeError, context,
    656                 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined),
    657                 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(
    658                     "Array.prototype.forEach")));
    659     Unreachable();
    660   }
    661 
    662   Bind(&type_exception);
    663   {
    664     CallRuntime(Runtime::kThrowTypeError, context,
    665                 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn);
    666     Unreachable();
    667   }
    668 }
    669 
    670 BUILTIN(ArraySlice) {
    671   HandleScope scope(isolate);
    672   Handle<Object> receiver = args.receiver();
    673   int len = -1;
    674   int relative_start = 0;
    675   int relative_end = 0;
    676 
    677   if (receiver->IsJSArray()) {
    678     DisallowHeapAllocation no_gc;
    679     JSArray* array = JSArray::cast(*receiver);
    680     if (V8_UNLIKELY(!array->HasFastElements() ||
    681                     !IsJSArrayFastElementMovingAllowed(isolate, array) ||
    682                     !isolate->IsArraySpeciesLookupChainIntact() ||
    683                     // If this is a subclass of Array, then call out to JS
    684                     !array->HasArrayPrototype(isolate))) {
    685       AllowHeapAllocation allow_allocation;
    686       return CallJsIntrinsic(isolate, isolate->array_slice(), args);
    687     }
    688     len = Smi::cast(array->length())->value();
    689   } else if (receiver->IsJSObject() &&
    690              GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver),
    691                                       &len)) {
    692     // Array.prototype.slice.call(arguments, ...) is quite a common idiom
    693     // (notably more than 50% of invocations in Web apps).
    694     // Treat it in C++ as well.
    695     DCHECK(JSObject::cast(*receiver)->HasFastElements() ||
    696            JSObject::cast(*receiver)->HasFastArgumentsElements());
    697   } else {
    698     AllowHeapAllocation allow_allocation;
    699     return CallJsIntrinsic(isolate, isolate->array_slice(), args);
    700   }
    701   DCHECK_LE(0, len);
    702   int argument_count = args.length() - 1;
    703   // Note carefully chosen defaults---if argument is missing,
    704   // it's undefined which gets converted to 0 for relative_start
    705   // and to len for relative_end.
    706   relative_start = 0;
    707   relative_end = len;
    708   if (argument_count > 0) {
    709     DisallowHeapAllocation no_gc;
    710     if (!ClampedToInteger(isolate, args[1], &relative_start)) {
    711       AllowHeapAllocation allow_allocation;
    712       return CallJsIntrinsic(isolate, isolate->array_slice(), args);
    713     }
    714     if (argument_count > 1) {
    715       Object* end_arg = args[2];
    716       // slice handles the end_arg specially
    717       if (end_arg->IsUndefined(isolate)) {
    718         relative_end = len;
    719       } else if (!ClampedToInteger(isolate, end_arg, &relative_end)) {
    720         AllowHeapAllocation allow_allocation;
    721         return CallJsIntrinsic(isolate, isolate->array_slice(), args);
    722       }
    723     }
    724   }
    725 
    726   // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
    727   uint32_t actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
    728                                                : Min(relative_start, len);
    729 
    730   // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
    731   uint32_t actual_end =
    732       (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len);
    733 
    734   Handle<JSObject> object = Handle<JSObject>::cast(receiver);
    735   ElementsAccessor* accessor = object->GetElementsAccessor();
    736   return *accessor->Slice(object, actual_start, actual_end);
    737 }
    738 
    739 BUILTIN(ArraySplice) {
    740   HandleScope scope(isolate);
    741   Handle<Object> receiver = args.receiver();
    742   if (V8_UNLIKELY(
    743           !EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3) ||
    744           // If this is a subclass of Array, then call out to JS.
    745           !Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) ||
    746           // If anything with @@species has been messed with, call out to JS.
    747           !isolate->IsArraySpeciesLookupChainIntact())) {
    748     return CallJsIntrinsic(isolate, isolate->array_splice(), args);
    749   }
    750   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
    751 
    752   int argument_count = args.length() - 1;
    753   int relative_start = 0;
    754   if (argument_count > 0) {
    755     DisallowHeapAllocation no_gc;
    756     if (!ClampedToInteger(isolate, args[1], &relative_start)) {
    757       AllowHeapAllocation allow_allocation;
    758       return CallJsIntrinsic(isolate, isolate->array_splice(), args);
    759     }
    760   }
    761   int len = Smi::cast(array->length())->value();
    762   // clip relative start to [0, len]
    763   int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
    764                                           : Min(relative_start, len);
    765 
    766   int actual_delete_count;
    767   if (argument_count == 1) {
    768     // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
    769     // given as a request to delete all the elements from the start.
    770     // And it differs from the case of undefined delete count.
    771     // This does not follow ECMA-262, but we do the same for compatibility.
    772     DCHECK(len - actual_start >= 0);
    773     actual_delete_count = len - actual_start;
    774   } else {
    775     int delete_count = 0;
    776     DisallowHeapAllocation no_gc;
    777     if (argument_count > 1) {
    778       if (!ClampedToInteger(isolate, args[2], &delete_count)) {
    779         AllowHeapAllocation allow_allocation;
    780         return CallJsIntrinsic(isolate, isolate->array_splice(), args);
    781       }
    782     }
    783     actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
    784   }
    785 
    786   int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
    787   int new_length = len - actual_delete_count + add_count;
    788 
    789   if (new_length != len && JSArray::HasReadOnlyLength(array)) {
    790     AllowHeapAllocation allow_allocation;
    791     return CallJsIntrinsic(isolate, isolate->array_splice(), args);
    792   }
    793   ElementsAccessor* accessor = array->GetElementsAccessor();
    794   Handle<JSArray> result_array = accessor->Splice(
    795       array, actual_start, actual_delete_count, &args, add_count);
    796   return *result_array;
    797 }
    798 
    799 // Array Concat -------------------------------------------------------------
    800 
    801 namespace {
    802 
    803 /**
    804  * A simple visitor visits every element of Array's.
    805  * The backend storage can be a fixed array for fast elements case,
    806  * or a dictionary for sparse array. Since Dictionary is a subtype
    807  * of FixedArray, the class can be used by both fast and slow cases.
    808  * The second parameter of the constructor, fast_elements, specifies
    809  * whether the storage is a FixedArray or Dictionary.
    810  *
    811  * An index limit is used to deal with the situation that a result array
    812  * length overflows 32-bit non-negative integer.
    813  */
    814 class ArrayConcatVisitor {
    815  public:
    816   ArrayConcatVisitor(Isolate* isolate, Handle<HeapObject> storage,
    817                      bool fast_elements)
    818       : isolate_(isolate),
    819         storage_(isolate->global_handles()->Create(*storage)),
    820         index_offset_(0u),
    821         bit_field_(
    822             FastElementsField::encode(fast_elements) |
    823             ExceedsLimitField::encode(false) |
    824             IsFixedArrayField::encode(storage->IsFixedArray()) |
    825             HasSimpleElementsField::encode(storage->IsFixedArray() ||
    826                                            storage->map()->instance_type() >
    827                                                LAST_CUSTOM_ELEMENTS_RECEIVER)) {
    828     DCHECK(!(this->fast_elements() && !is_fixed_array()));
    829   }
    830 
    831   ~ArrayConcatVisitor() { clear_storage(); }
    832 
    833   MUST_USE_RESULT bool visit(uint32_t i, Handle<Object> elm) {
    834     uint32_t index = index_offset_ + i;
    835 
    836     if (i >= JSObject::kMaxElementCount - index_offset_) {
    837       set_exceeds_array_limit(true);
    838       // Exception hasn't been thrown at this point. Return true to
    839       // break out, and caller will throw. !visit would imply that
    840       // there is already a pending exception.
    841       return true;
    842     }
    843 
    844     if (!is_fixed_array()) {
    845       LookupIterator it(isolate_, storage_, index, LookupIterator::OWN);
    846       MAYBE_RETURN(
    847           JSReceiver::CreateDataProperty(&it, elm, Object::THROW_ON_ERROR),
    848           false);
    849       return true;
    850     }
    851 
    852     if (fast_elements()) {
    853       if (index < static_cast<uint32_t>(storage_fixed_array()->length())) {
    854         storage_fixed_array()->set(index, *elm);
    855         return true;
    856       }
    857       // Our initial estimate of length was foiled, possibly by
    858       // getters on the arrays increasing the length of later arrays
    859       // during iteration.
    860       // This shouldn't happen in anything but pathological cases.
    861       SetDictionaryMode();
    862       // Fall-through to dictionary mode.
    863     }
    864     DCHECK(!fast_elements());
    865     Handle<SeededNumberDictionary> dict(
    866         SeededNumberDictionary::cast(*storage_));
    867     // The object holding this backing store has just been allocated, so
    868     // it cannot yet be used as a prototype.
    869     Handle<JSObject> not_a_prototype_holder;
    870     Handle<SeededNumberDictionary> result = SeededNumberDictionary::AtNumberPut(
    871         dict, index, elm, not_a_prototype_holder);
    872     if (!result.is_identical_to(dict)) {
    873       // Dictionary needed to grow.
    874       clear_storage();
    875       set_storage(*result);
    876     }
    877     return true;
    878   }
    879 
    880   void increase_index_offset(uint32_t delta) {
    881     if (JSObject::kMaxElementCount - index_offset_ < delta) {
    882       index_offset_ = JSObject::kMaxElementCount;
    883     } else {
    884       index_offset_ += delta;
    885     }
    886     // If the initial length estimate was off (see special case in visit()),
    887     // but the array blowing the limit didn't contain elements beyond the
    888     // provided-for index range, go to dictionary mode now.
    889     if (fast_elements() &&
    890         index_offset_ >
    891             static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
    892       SetDictionaryMode();
    893     }
    894   }
    895 
    896   bool exceeds_array_limit() const {
    897     return ExceedsLimitField::decode(bit_field_);
    898   }
    899 
    900   Handle<JSArray> ToArray() {
    901     DCHECK(is_fixed_array());
    902     Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
    903     Handle<Object> length =
    904         isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
    905     Handle<Map> map = JSObject::GetElementsTransitionMap(
    906         array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
    907     array->set_map(*map);
    908     array->set_length(*length);
    909     array->set_elements(*storage_fixed_array());
    910     return array;
    911   }
    912 
    913   // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever
    914   // (otherwise)
    915   Handle<FixedArray> storage_fixed_array() {
    916     DCHECK(is_fixed_array());
    917     DCHECK(has_simple_elements());
    918     return Handle<FixedArray>::cast(storage_);
    919   }
    920   Handle<JSReceiver> storage_jsreceiver() {
    921     DCHECK(!is_fixed_array());
    922     return Handle<JSReceiver>::cast(storage_);
    923   }
    924   bool has_simple_elements() const {
    925     return HasSimpleElementsField::decode(bit_field_);
    926   }
    927 
    928  private:
    929   // Convert storage to dictionary mode.
    930   void SetDictionaryMode() {
    931     DCHECK(fast_elements() && is_fixed_array());
    932     Handle<FixedArray> current_storage = storage_fixed_array();
    933     Handle<SeededNumberDictionary> slow_storage(
    934         SeededNumberDictionary::New(isolate_, current_storage->length()));
    935     uint32_t current_length = static_cast<uint32_t>(current_storage->length());
    936     FOR_WITH_HANDLE_SCOPE(
    937         isolate_, uint32_t, i = 0, i, i < current_length, i++, {
    938           Handle<Object> element(current_storage->get(i), isolate_);
    939           if (!element->IsTheHole(isolate_)) {
    940             // The object holding this backing store has just been allocated, so
    941             // it cannot yet be used as a prototype.
    942             Handle<JSObject> not_a_prototype_holder;
    943             Handle<SeededNumberDictionary> new_storage =
    944                 SeededNumberDictionary::AtNumberPut(slow_storage, i, element,
    945                                                     not_a_prototype_holder);
    946             if (!new_storage.is_identical_to(slow_storage)) {
    947               slow_storage = loop_scope.CloseAndEscape(new_storage);
    948             }
    949           }
    950         });
    951     clear_storage();
    952     set_storage(*slow_storage);
    953     set_fast_elements(false);
    954   }
    955 
    956   inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); }
    957 
    958   inline void set_storage(FixedArray* storage) {
    959     DCHECK(is_fixed_array());
    960     DCHECK(has_simple_elements());
    961     storage_ = isolate_->global_handles()->Create(storage);
    962   }
    963 
    964   class FastElementsField : public BitField<bool, 0, 1> {};
    965   class ExceedsLimitField : public BitField<bool, 1, 1> {};
    966   class IsFixedArrayField : public BitField<bool, 2, 1> {};
    967   class HasSimpleElementsField : public BitField<bool, 3, 1> {};
    968 
    969   bool fast_elements() const { return FastElementsField::decode(bit_field_); }
    970   void set_fast_elements(bool fast) {
    971     bit_field_ = FastElementsField::update(bit_field_, fast);
    972   }
    973   void set_exceeds_array_limit(bool exceeds) {
    974     bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
    975   }
    976   bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); }
    977 
    978   Isolate* isolate_;
    979   Handle<Object> storage_;  // Always a global handle.
    980   // Index after last seen index. Always less than or equal to
    981   // JSObject::kMaxElementCount.
    982   uint32_t index_offset_;
    983   uint32_t bit_field_;
    984 };
    985 
    986 uint32_t EstimateElementCount(Handle<JSArray> array) {
    987   DisallowHeapAllocation no_gc;
    988   uint32_t length = static_cast<uint32_t>(array->length()->Number());
    989   int element_count = 0;
    990   switch (array->GetElementsKind()) {
    991     case FAST_SMI_ELEMENTS:
    992     case FAST_HOLEY_SMI_ELEMENTS:
    993     case FAST_ELEMENTS:
    994     case FAST_HOLEY_ELEMENTS: {
    995       // Fast elements can't have lengths that are not representable by
    996       // a 32-bit signed integer.
    997       DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
    998       int fast_length = static_cast<int>(length);
    999       Isolate* isolate = array->GetIsolate();
   1000       FixedArray* elements = FixedArray::cast(array->elements());
   1001       for (int i = 0; i < fast_length; i++) {
   1002         if (!elements->get(i)->IsTheHole(isolate)) element_count++;
   1003       }
   1004       break;
   1005     }
   1006     case FAST_DOUBLE_ELEMENTS:
   1007     case FAST_HOLEY_DOUBLE_ELEMENTS: {
   1008       // Fast elements can't have lengths that are not representable by
   1009       // a 32-bit signed integer.
   1010       DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
   1011       int fast_length = static_cast<int>(length);
   1012       if (array->elements()->IsFixedArray()) {
   1013         DCHECK(FixedArray::cast(array->elements())->length() == 0);
   1014         break;
   1015       }
   1016       FixedDoubleArray* elements = FixedDoubleArray::cast(array->elements());
   1017       for (int i = 0; i < fast_length; i++) {
   1018         if (!elements->is_the_hole(i)) element_count++;
   1019       }
   1020       break;
   1021     }
   1022     case DICTIONARY_ELEMENTS: {
   1023       SeededNumberDictionary* dictionary =
   1024           SeededNumberDictionary::cast(array->elements());
   1025       Isolate* isolate = dictionary->GetIsolate();
   1026       int capacity = dictionary->Capacity();
   1027       for (int i = 0; i < capacity; i++) {
   1028         Object* key = dictionary->KeyAt(i);
   1029         if (dictionary->IsKey(isolate, key)) {
   1030           element_count++;
   1031         }
   1032       }
   1033       break;
   1034     }
   1035 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
   1036 
   1037       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   1038 #undef TYPED_ARRAY_CASE
   1039       // External arrays are always dense.
   1040       return length;
   1041     case NO_ELEMENTS:
   1042       return 0;
   1043     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
   1044     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
   1045     case FAST_STRING_WRAPPER_ELEMENTS:
   1046     case SLOW_STRING_WRAPPER_ELEMENTS:
   1047       UNREACHABLE();
   1048       return 0;
   1049   }
   1050   // As an estimate, we assume that the prototype doesn't contain any
   1051   // inherited elements.
   1052   return element_count;
   1053 }
   1054 
   1055 // Used for sorting indices in a List<uint32_t>.
   1056 int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
   1057   uint32_t a = *ap;
   1058   uint32_t b = *bp;
   1059   return (a == b) ? 0 : (a < b) ? -1 : 1;
   1060 }
   1061 
   1062 void CollectElementIndices(Handle<JSObject> object, uint32_t range,
   1063                            List<uint32_t>* indices) {
   1064   Isolate* isolate = object->GetIsolate();
   1065   ElementsKind kind = object->GetElementsKind();
   1066   switch (kind) {
   1067     case FAST_SMI_ELEMENTS:
   1068     case FAST_ELEMENTS:
   1069     case FAST_HOLEY_SMI_ELEMENTS:
   1070     case FAST_HOLEY_ELEMENTS: {
   1071       DisallowHeapAllocation no_gc;
   1072       FixedArray* elements = FixedArray::cast(object->elements());
   1073       uint32_t length = static_cast<uint32_t>(elements->length());
   1074       if (range < length) length = range;
   1075       for (uint32_t i = 0; i < length; i++) {
   1076         if (!elements->get(i)->IsTheHole(isolate)) {
   1077           indices->Add(i);
   1078         }
   1079       }
   1080       break;
   1081     }
   1082     case FAST_HOLEY_DOUBLE_ELEMENTS:
   1083     case FAST_DOUBLE_ELEMENTS: {
   1084       if (object->elements()->IsFixedArray()) {
   1085         DCHECK(object->elements()->length() == 0);
   1086         break;
   1087       }
   1088       Handle<FixedDoubleArray> elements(
   1089           FixedDoubleArray::cast(object->elements()));
   1090       uint32_t length = static_cast<uint32_t>(elements->length());
   1091       if (range < length) length = range;
   1092       for (uint32_t i = 0; i < length; i++) {
   1093         if (!elements->is_the_hole(i)) {
   1094           indices->Add(i);
   1095         }
   1096       }
   1097       break;
   1098     }
   1099     case DICTIONARY_ELEMENTS: {
   1100       DisallowHeapAllocation no_gc;
   1101       SeededNumberDictionary* dict =
   1102           SeededNumberDictionary::cast(object->elements());
   1103       uint32_t capacity = dict->Capacity();
   1104       FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, j = 0, j, j < capacity, j++, {
   1105         Object* k = dict->KeyAt(j);
   1106         if (!dict->IsKey(isolate, k)) continue;
   1107         DCHECK(k->IsNumber());
   1108         uint32_t index = static_cast<uint32_t>(k->Number());
   1109         if (index < range) {
   1110           indices->Add(index);
   1111         }
   1112       });
   1113       break;
   1114     }
   1115 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
   1116 
   1117       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   1118 #undef TYPED_ARRAY_CASE
   1119       {
   1120         uint32_t length = static_cast<uint32_t>(
   1121             FixedArrayBase::cast(object->elements())->length());
   1122         if (range <= length) {
   1123           length = range;
   1124           // We will add all indices, so we might as well clear it first
   1125           // and avoid duplicates.
   1126           indices->Clear();
   1127         }
   1128         for (uint32_t i = 0; i < length; i++) {
   1129           indices->Add(i);
   1130         }
   1131         if (length == range) return;  // All indices accounted for already.
   1132         break;
   1133       }
   1134     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
   1135     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
   1136       ElementsAccessor* accessor = object->GetElementsAccessor();
   1137       for (uint32_t i = 0; i < range; i++) {
   1138         if (accessor->HasElement(object, i)) {
   1139           indices->Add(i);
   1140         }
   1141       }
   1142       break;
   1143     }
   1144     case FAST_STRING_WRAPPER_ELEMENTS:
   1145     case SLOW_STRING_WRAPPER_ELEMENTS: {
   1146       DCHECK(object->IsJSValue());
   1147       Handle<JSValue> js_value = Handle<JSValue>::cast(object);
   1148       DCHECK(js_value->value()->IsString());
   1149       Handle<String> string(String::cast(js_value->value()), isolate);
   1150       uint32_t length = static_cast<uint32_t>(string->length());
   1151       uint32_t i = 0;
   1152       uint32_t limit = Min(length, range);
   1153       for (; i < limit; i++) {
   1154         indices->Add(i);
   1155       }
   1156       ElementsAccessor* accessor = object->GetElementsAccessor();
   1157       for (; i < range; i++) {
   1158         if (accessor->HasElement(object, i)) {
   1159           indices->Add(i);
   1160         }
   1161       }
   1162       break;
   1163     }
   1164     case NO_ELEMENTS:
   1165       break;
   1166   }
   1167 
   1168   PrototypeIterator iter(isolate, object);
   1169   if (!iter.IsAtEnd()) {
   1170     // The prototype will usually have no inherited element indices,
   1171     // but we have to check.
   1172     CollectElementIndices(PrototypeIterator::GetCurrent<JSObject>(iter), range,
   1173                           indices);
   1174   }
   1175 }
   1176 
   1177 bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver,
   1178                          uint32_t length, ArrayConcatVisitor* visitor) {
   1179   FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, ++i, {
   1180     Maybe<bool> maybe = JSReceiver::HasElement(receiver, i);
   1181     if (!maybe.IsJust()) return false;
   1182     if (maybe.FromJust()) {
   1183       Handle<Object> element_value;
   1184       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1185           isolate, element_value, JSReceiver::GetElement(isolate, receiver, i),
   1186           false);
   1187       if (!visitor->visit(i, element_value)) return false;
   1188     }
   1189   });
   1190   visitor->increase_index_offset(length);
   1191   return true;
   1192 }
   1193 /**
   1194  * A helper function that visits "array" elements of a JSReceiver in numerical
   1195  * order.
   1196  *
   1197  * The visitor argument called for each existing element in the array
   1198  * with the element index and the element's value.
   1199  * Afterwards it increments the base-index of the visitor by the array
   1200  * length.
   1201  * Returns false if any access threw an exception, otherwise true.
   1202  */
   1203 bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
   1204                      ArrayConcatVisitor* visitor) {
   1205   uint32_t length = 0;
   1206 
   1207   if (receiver->IsJSArray()) {
   1208     Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   1209     length = static_cast<uint32_t>(array->length()->Number());
   1210   } else {
   1211     Handle<Object> val;
   1212     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1213         isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false);
   1214     // TODO(caitp): Support larger element indexes (up to 2^53-1).
   1215     if (!val->ToUint32(&length)) {
   1216       length = 0;
   1217     }
   1218     // TODO(cbruni): handle other element kind as well
   1219     return IterateElementsSlow(isolate, receiver, length, visitor);
   1220   }
   1221 
   1222   if (!HasOnlySimpleElements(isolate, *receiver) ||
   1223       !visitor->has_simple_elements()) {
   1224     return IterateElementsSlow(isolate, receiver, length, visitor);
   1225   }
   1226   Handle<JSObject> array = Handle<JSObject>::cast(receiver);
   1227 
   1228   switch (array->GetElementsKind()) {
   1229     case FAST_SMI_ELEMENTS:
   1230     case FAST_ELEMENTS:
   1231     case FAST_HOLEY_SMI_ELEMENTS:
   1232     case FAST_HOLEY_ELEMENTS: {
   1233       // Run through the elements FixedArray and use HasElement and GetElement
   1234       // to check the prototype for missing elements.
   1235       Handle<FixedArray> elements(FixedArray::cast(array->elements()));
   1236       int fast_length = static_cast<int>(length);
   1237       DCHECK(fast_length <= elements->length());
   1238       FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, {
   1239         Handle<Object> element_value(elements->get(j), isolate);
   1240         if (!element_value->IsTheHole(isolate)) {
   1241           if (!visitor->visit(j, element_value)) return false;
   1242         } else {
   1243           Maybe<bool> maybe = JSReceiver::HasElement(array, j);
   1244           if (!maybe.IsJust()) return false;
   1245           if (maybe.FromJust()) {
   1246             // Call GetElement on array, not its prototype, or getters won't
   1247             // have the correct receiver.
   1248             ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1249                 isolate, element_value,
   1250                 JSReceiver::GetElement(isolate, array, j), false);
   1251             if (!visitor->visit(j, element_value)) return false;
   1252           }
   1253         }
   1254       });
   1255       break;
   1256     }
   1257     case FAST_HOLEY_DOUBLE_ELEMENTS:
   1258     case FAST_DOUBLE_ELEMENTS: {
   1259       // Empty array is FixedArray but not FixedDoubleArray.
   1260       if (length == 0) break;
   1261       // Run through the elements FixedArray and use HasElement and GetElement
   1262       // to check the prototype for missing elements.
   1263       if (array->elements()->IsFixedArray()) {
   1264         DCHECK(array->elements()->length() == 0);
   1265         break;
   1266       }
   1267       Handle<FixedDoubleArray> elements(
   1268           FixedDoubleArray::cast(array->elements()));
   1269       int fast_length = static_cast<int>(length);
   1270       DCHECK(fast_length <= elements->length());
   1271       FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, {
   1272         if (!elements->is_the_hole(j)) {
   1273           double double_value = elements->get_scalar(j);
   1274           Handle<Object> element_value =
   1275               isolate->factory()->NewNumber(double_value);
   1276           if (!visitor->visit(j, element_value)) return false;
   1277         } else {
   1278           Maybe<bool> maybe = JSReceiver::HasElement(array, j);
   1279           if (!maybe.IsJust()) return false;
   1280           if (maybe.FromJust()) {
   1281             // Call GetElement on array, not its prototype, or getters won't
   1282             // have the correct receiver.
   1283             Handle<Object> element_value;
   1284             ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1285                 isolate, element_value,
   1286                 JSReceiver::GetElement(isolate, array, j), false);
   1287             if (!visitor->visit(j, element_value)) return false;
   1288           }
   1289         }
   1290       });
   1291       break;
   1292     }
   1293 
   1294     case DICTIONARY_ELEMENTS: {
   1295       Handle<SeededNumberDictionary> dict(array->element_dictionary());
   1296       List<uint32_t> indices(dict->Capacity() / 2);
   1297       // Collect all indices in the object and the prototypes less
   1298       // than length. This might introduce duplicates in the indices list.
   1299       CollectElementIndices(array, length, &indices);
   1300       indices.Sort(&compareUInt32);
   1301       int n = indices.length();
   1302       FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < n, (void)0, {
   1303         uint32_t index = indices[j];
   1304         Handle<Object> element;
   1305         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1306             isolate, element, JSReceiver::GetElement(isolate, array, index),
   1307             false);
   1308         if (!visitor->visit(index, element)) return false;
   1309         // Skip to next different index (i.e., omit duplicates).
   1310         do {
   1311           j++;
   1312         } while (j < n && indices[j] == index);
   1313       });
   1314       break;
   1315     }
   1316     case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
   1317     case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
   1318       FOR_WITH_HANDLE_SCOPE(
   1319           isolate, uint32_t, index = 0, index, index < length, index++, {
   1320             Handle<Object> element;
   1321             ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1322                 isolate, element, JSReceiver::GetElement(isolate, array, index),
   1323                 false);
   1324             if (!visitor->visit(index, element)) return false;
   1325           });
   1326       break;
   1327     }
   1328     case NO_ELEMENTS:
   1329       break;
   1330 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
   1331       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   1332 #undef TYPED_ARRAY_CASE
   1333       return IterateElementsSlow(isolate, receiver, length, visitor);
   1334     case FAST_STRING_WRAPPER_ELEMENTS:
   1335     case SLOW_STRING_WRAPPER_ELEMENTS:
   1336       // |array| is guaranteed to be an array or typed array.
   1337       UNREACHABLE();
   1338       break;
   1339   }
   1340   visitor->increase_index_offset(length);
   1341   return true;
   1342 }
   1343 
   1344 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) {
   1345   HandleScope handle_scope(isolate);
   1346   if (!obj->IsJSReceiver()) return Just(false);
   1347   if (!isolate->IsIsConcatSpreadableLookupChainIntact(JSReceiver::cast(*obj))) {
   1348     // Slow path if @@isConcatSpreadable has been used.
   1349     Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol());
   1350     Handle<Object> value;
   1351     MaybeHandle<Object> maybeValue =
   1352         i::Runtime::GetObjectProperty(isolate, obj, key);
   1353     if (!maybeValue.ToHandle(&value)) return Nothing<bool>();
   1354     if (!value->IsUndefined(isolate)) return Just(value->BooleanValue());
   1355   }
   1356   return Object::IsArray(obj);
   1357 }
   1358 
   1359 Object* Slow_ArrayConcat(BuiltinArguments* args, Handle<Object> species,
   1360                          Isolate* isolate) {
   1361   int argument_count = args->length();
   1362 
   1363   bool is_array_species = *species == isolate->context()->array_function();
   1364 
   1365   // Pass 1: estimate the length and number of elements of the result.
   1366   // The actual length can be larger if any of the arguments have getters
   1367   // that mutate other arguments (but will otherwise be precise).
   1368   // The number of elements is precise if there are no inherited elements.
   1369 
   1370   ElementsKind kind = FAST_SMI_ELEMENTS;
   1371 
   1372   uint32_t estimate_result_length = 0;
   1373   uint32_t estimate_nof_elements = 0;
   1374   FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < argument_count, i++, {
   1375     Handle<Object> obj((*args)[i], isolate);
   1376     uint32_t length_estimate;
   1377     uint32_t element_estimate;
   1378     if (obj->IsJSArray()) {
   1379       Handle<JSArray> array(Handle<JSArray>::cast(obj));
   1380       length_estimate = static_cast<uint32_t>(array->length()->Number());
   1381       if (length_estimate != 0) {
   1382         ElementsKind array_kind =
   1383             GetPackedElementsKind(array->GetElementsKind());
   1384         kind = GetMoreGeneralElementsKind(kind, array_kind);
   1385       }
   1386       element_estimate = EstimateElementCount(array);
   1387     } else {
   1388       if (obj->IsHeapObject()) {
   1389         kind = GetMoreGeneralElementsKind(
   1390             kind, obj->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS);
   1391       }
   1392       length_estimate = 1;
   1393       element_estimate = 1;
   1394     }
   1395     // Avoid overflows by capping at kMaxElementCount.
   1396     if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) {
   1397       estimate_result_length = JSObject::kMaxElementCount;
   1398     } else {
   1399       estimate_result_length += length_estimate;
   1400     }
   1401     if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) {
   1402       estimate_nof_elements = JSObject::kMaxElementCount;
   1403     } else {
   1404       estimate_nof_elements += element_estimate;
   1405     }
   1406   });
   1407 
   1408   // If estimated number of elements is more than half of length, a
   1409   // fixed array (fast case) is more time and space-efficient than a
   1410   // dictionary.
   1411   bool fast_case = is_array_species &&
   1412                    (estimate_nof_elements * 2) >= estimate_result_length &&
   1413                    isolate->IsIsConcatSpreadableLookupChainIntact();
   1414 
   1415   if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
   1416     Handle<FixedArrayBase> storage =
   1417         isolate->factory()->NewFixedDoubleArray(estimate_result_length);
   1418     int j = 0;
   1419     bool failure = false;
   1420     if (estimate_result_length > 0) {
   1421       Handle<FixedDoubleArray> double_storage =
   1422           Handle<FixedDoubleArray>::cast(storage);
   1423       for (int i = 0; i < argument_count; i++) {
   1424         Handle<Object> obj((*args)[i], isolate);
   1425         if (obj->IsSmi()) {
   1426           double_storage->set(j, Smi::cast(*obj)->value());
   1427           j++;
   1428         } else if (obj->IsNumber()) {
   1429           double_storage->set(j, obj->Number());
   1430           j++;
   1431         } else {
   1432           DisallowHeapAllocation no_gc;
   1433           JSArray* array = JSArray::cast(*obj);
   1434           uint32_t length = static_cast<uint32_t>(array->length()->Number());
   1435           switch (array->GetElementsKind()) {
   1436             case FAST_HOLEY_DOUBLE_ELEMENTS:
   1437             case FAST_DOUBLE_ELEMENTS: {
   1438               // Empty array is FixedArray but not FixedDoubleArray.
   1439               if (length == 0) break;
   1440               FixedDoubleArray* elements =
   1441                   FixedDoubleArray::cast(array->elements());
   1442               for (uint32_t i = 0; i < length; i++) {
   1443                 if (elements->is_the_hole(i)) {
   1444                   // TODO(jkummerow/verwaest): We could be a bit more clever
   1445                   // here: Check if there are no elements/getters on the
   1446                   // prototype chain, and if so, allow creation of a holey
   1447                   // result array.
   1448                   // Same thing below (holey smi case).
   1449                   failure = true;
   1450                   break;
   1451                 }
   1452                 double double_value = elements->get_scalar(i);
   1453                 double_storage->set(j, double_value);
   1454                 j++;
   1455               }
   1456               break;
   1457             }
   1458             case FAST_HOLEY_SMI_ELEMENTS:
   1459             case FAST_SMI_ELEMENTS: {
   1460               Object* the_hole = isolate->heap()->the_hole_value();
   1461               FixedArray* elements(FixedArray::cast(array->elements()));
   1462               for (uint32_t i = 0; i < length; i++) {
   1463                 Object* element = elements->get(i);
   1464                 if (element == the_hole) {
   1465                   failure = true;
   1466                   break;
   1467                 }
   1468                 int32_t int_value = Smi::cast(element)->value();
   1469                 double_storage->set(j, int_value);
   1470                 j++;
   1471               }
   1472               break;
   1473             }
   1474             case FAST_HOLEY_ELEMENTS:
   1475             case FAST_ELEMENTS:
   1476             case DICTIONARY_ELEMENTS:
   1477             case NO_ELEMENTS:
   1478               DCHECK_EQ(0u, length);
   1479               break;
   1480             default:
   1481               UNREACHABLE();
   1482           }
   1483         }
   1484         if (failure) break;
   1485       }
   1486     }
   1487     if (!failure) {
   1488       return *isolate->factory()->NewJSArrayWithElements(storage, kind, j);
   1489     }
   1490     // In case of failure, fall through.
   1491   }
   1492 
   1493   Handle<HeapObject> storage;
   1494   if (fast_case) {
   1495     // The backing storage array must have non-existing elements to preserve
   1496     // holes across concat operations.
   1497     storage =
   1498         isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
   1499   } else if (is_array_species) {
   1500     // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
   1501     uint32_t at_least_space_for =
   1502         estimate_nof_elements + (estimate_nof_elements >> 2);
   1503     storage = SeededNumberDictionary::New(isolate, at_least_space_for);
   1504   } else {
   1505     DCHECK(species->IsConstructor());
   1506     Handle<Object> length(Smi::kZero, isolate);
   1507     Handle<Object> storage_object;
   1508     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
   1509         isolate, storage_object,
   1510         Execution::New(isolate, species, species, 1, &length));
   1511     storage = Handle<HeapObject>::cast(storage_object);
   1512   }
   1513 
   1514   ArrayConcatVisitor visitor(isolate, storage, fast_case);
   1515 
   1516   for (int i = 0; i < argument_count; i++) {
   1517     Handle<Object> obj((*args)[i], isolate);
   1518     Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj);
   1519     MAYBE_RETURN(spreadable, isolate->heap()->exception());
   1520     if (spreadable.FromJust()) {
   1521       Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj);
   1522       if (!IterateElements(isolate, object, &visitor)) {
   1523         return isolate->heap()->exception();
   1524       }
   1525     } else {
   1526       if (!visitor.visit(0, obj)) return isolate->heap()->exception();
   1527       visitor.increase_index_offset(1);
   1528     }
   1529   }
   1530 
   1531   if (visitor.exceeds_array_limit()) {
   1532     THROW_NEW_ERROR_RETURN_FAILURE(
   1533         isolate, NewRangeError(MessageTemplate::kInvalidArrayLength));
   1534   }
   1535 
   1536   if (is_array_species) {
   1537     return *visitor.ToArray();
   1538   } else {
   1539     return *visitor.storage_jsreceiver();
   1540   }
   1541 }
   1542 
   1543 bool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) {
   1544   DisallowHeapAllocation no_gc;
   1545   Map* map = obj->map();
   1546   // If there is only the 'length' property we are fine.
   1547   if (map->prototype() ==
   1548           isolate->native_context()->initial_array_prototype() &&
   1549       map->NumberOfOwnDescriptors() == 1) {
   1550     return true;
   1551   }
   1552   // TODO(cbruni): slower lookup for array subclasses and support slow
   1553   // @@IsConcatSpreadable lookup.
   1554   return false;
   1555 }
   1556 
   1557 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate,
   1558                                       BuiltinArguments* args) {
   1559   if (!isolate->IsIsConcatSpreadableLookupChainIntact()) {
   1560     return MaybeHandle<JSArray>();
   1561   }
   1562   // We shouldn't overflow when adding another len.
   1563   const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
   1564   STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
   1565   STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt);
   1566   USE(kHalfOfMaxInt);
   1567 
   1568   int n_arguments = args->length();
   1569   int result_len = 0;
   1570   {
   1571     DisallowHeapAllocation no_gc;
   1572     // Iterate through all the arguments performing checks
   1573     // and calculating total length.
   1574     for (int i = 0; i < n_arguments; i++) {
   1575       Object* arg = (*args)[i];
   1576       if (!arg->IsJSArray()) return MaybeHandle<JSArray>();
   1577       if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) {
   1578         return MaybeHandle<JSArray>();
   1579       }
   1580       // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS.
   1581       if (!JSObject::cast(arg)->HasFastElements()) {
   1582         return MaybeHandle<JSArray>();
   1583       }
   1584       Handle<JSArray> array(JSArray::cast(arg), isolate);
   1585       if (!IsSimpleArray(isolate, array)) {
   1586         return MaybeHandle<JSArray>();
   1587       }
   1588       // The Array length is guaranted to be <= kHalfOfMaxInt thus we won't
   1589       // overflow.
   1590       result_len += Smi::cast(array->length())->value();
   1591       DCHECK(result_len >= 0);
   1592       // Throw an Error if we overflow the FixedArray limits
   1593       if (FixedDoubleArray::kMaxLength < result_len ||
   1594           FixedArray::kMaxLength < result_len) {
   1595         AllowHeapAllocation gc;
   1596         THROW_NEW_ERROR(isolate,
   1597                         NewRangeError(MessageTemplate::kInvalidArrayLength),
   1598                         JSArray);
   1599       }
   1600     }
   1601   }
   1602   return ElementsAccessor::Concat(isolate, args, n_arguments, result_len);
   1603 }
   1604 
   1605 }  // namespace
   1606 
   1607 // ES6 22.1.3.1 Array.prototype.concat
   1608 BUILTIN(ArrayConcat) {
   1609   HandleScope scope(isolate);
   1610 
   1611   Handle<Object> receiver = args.receiver();
   1612   // TODO(bmeurer): Do we really care about the exact exception message here?
   1613   if (receiver->IsNullOrUndefined(isolate)) {
   1614     THROW_NEW_ERROR_RETURN_FAILURE(
   1615         isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
   1616                               isolate->factory()->NewStringFromAsciiChecked(
   1617                                   "Array.prototype.concat")));
   1618   }
   1619   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
   1620       isolate, receiver, Object::ToObject(isolate, args.receiver()));
   1621   args[0] = *receiver;
   1622 
   1623   Handle<JSArray> result_array;
   1624 
   1625   // Avoid a real species read to avoid extra lookups to the array constructor
   1626   if (V8_LIKELY(receiver->IsJSArray() &&
   1627                 Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) &&
   1628                 isolate->IsArraySpeciesLookupChainIntact())) {
   1629     if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
   1630       return *result_array;
   1631     }
   1632     if (isolate->has_pending_exception()) return isolate->heap()->exception();
   1633   }
   1634   // Reading @@species happens before anything else with a side effect, so
   1635   // we can do it here to determine whether to take the fast path.
   1636   Handle<Object> species;
   1637   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
   1638       isolate, species, Object::ArraySpeciesConstructor(isolate, receiver));
   1639   if (*species == *isolate->array_function()) {
   1640     if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
   1641       return *result_array;
   1642     }
   1643     if (isolate->has_pending_exception()) return isolate->heap()->exception();
   1644   }
   1645   return Slow_ArrayConcat(&args, species, isolate);
   1646 }
   1647 
   1648 void Builtins::Generate_ArrayIsArray(compiler::CodeAssemblerState* state) {
   1649   typedef compiler::Node Node;
   1650   typedef CodeStubAssembler::Label Label;
   1651   CodeStubAssembler assembler(state);
   1652 
   1653   Node* object = assembler.Parameter(1);
   1654   Node* context = assembler.Parameter(4);
   1655 
   1656   Label call_runtime(&assembler), return_true(&assembler),
   1657       return_false(&assembler);
   1658 
   1659   assembler.GotoIf(assembler.TaggedIsSmi(object), &return_false);
   1660   Node* instance_type = assembler.LoadInstanceType(object);
   1661 
   1662   assembler.GotoIf(assembler.Word32Equal(
   1663                        instance_type, assembler.Int32Constant(JS_ARRAY_TYPE)),
   1664                    &return_true);
   1665 
   1666   // TODO(verwaest): Handle proxies in-place.
   1667   assembler.Branch(assembler.Word32Equal(
   1668                        instance_type, assembler.Int32Constant(JS_PROXY_TYPE)),
   1669                    &call_runtime, &return_false);
   1670 
   1671   assembler.Bind(&return_true);
   1672   assembler.Return(assembler.BooleanConstant(true));
   1673 
   1674   assembler.Bind(&return_false);
   1675   assembler.Return(assembler.BooleanConstant(false));
   1676 
   1677   assembler.Bind(&call_runtime);
   1678   assembler.Return(
   1679       assembler.CallRuntime(Runtime::kArrayIsArray, context, object));
   1680 }
   1681 
   1682 TF_BUILTIN(ArrayIncludes, CodeStubAssembler) {
   1683   Node* const array = Parameter(0);
   1684   Node* const search_element = Parameter(1);
   1685   Node* const start_from = Parameter(2);
   1686   Node* const context = Parameter(3 + 2);
   1687 
   1688   Variable len_var(this, MachineType::PointerRepresentation()),
   1689       index_var(this, MachineType::PointerRepresentation());
   1690 
   1691   Label init_k(this), return_true(this), return_false(this), call_runtime(this);
   1692   Label init_len(this), select_loop(this);
   1693 
   1694   index_var.Bind(IntPtrConstant(0));
   1695   len_var.Bind(IntPtrConstant(0));
   1696 
   1697   // Take slow path if not a JSArray, if retrieving elements requires
   1698   // traversing prototype, or if access checks are required.
   1699   BranchIfFastJSArray(array, context,
   1700                       CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
   1701                       &init_len, &call_runtime);
   1702 
   1703   Bind(&init_len);
   1704   {
   1705     // Handle case where JSArray length is not an Smi in the runtime
   1706     Node* len = LoadObjectField(array, JSArray::kLengthOffset);
   1707     GotoIfNot(TaggedIsSmi(len), &call_runtime);
   1708 
   1709     len_var.Bind(SmiToWord(len));
   1710 
   1711     GotoIf(IsUndefined(start_from), &select_loop);
   1712 
   1713     // Bailout to slow path if startIndex is not an Smi.
   1714     Branch(TaggedIsSmi(start_from), &init_k, &call_runtime);
   1715   }
   1716 
   1717   Bind(&init_k);
   1718   CSA_ASSERT(this, TaggedIsSmi(start_from));
   1719   Node* const untagged_start_from = SmiToWord(start_from);
   1720   index_var.Bind(Select(
   1721       IntPtrGreaterThanOrEqual(untagged_start_from, IntPtrConstant(0)),
   1722       [=]() { return untagged_start_from; },
   1723       [=]() {
   1724         Node* const index = IntPtrAdd(len_var.value(), untagged_start_from);
   1725         return SelectConstant(IntPtrLessThan(index, IntPtrConstant(0)),
   1726                               IntPtrConstant(0), index,
   1727                               MachineType::PointerRepresentation());
   1728       },
   1729       MachineType::PointerRepresentation()));
   1730 
   1731   Goto(&select_loop);
   1732   Bind(&select_loop);
   1733   static int32_t kElementsKind[] = {
   1734       FAST_SMI_ELEMENTS,   FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS,
   1735       FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS,    FAST_HOLEY_DOUBLE_ELEMENTS,
   1736   };
   1737 
   1738   Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
   1739   Label* element_kind_handlers[] = {&if_smiorobjects,   &if_smiorobjects,
   1740                                     &if_smiorobjects,   &if_smiorobjects,
   1741                                     &if_packed_doubles, &if_holey_doubles};
   1742 
   1743   Node* map = LoadMap(array);
   1744   Node* elements_kind = LoadMapElementsKind(map);
   1745   Node* elements = LoadElements(array);
   1746   Switch(elements_kind, &return_false, kElementsKind, element_kind_handlers,
   1747          arraysize(kElementsKind));
   1748 
   1749   Bind(&if_smiorobjects);
   1750   {
   1751     Variable search_num(this, MachineRepresentation::kFloat64);
   1752     Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
   1753         string_loop(this, &index_var), undef_loop(this, &index_var),
   1754         not_smi(this), not_heap_num(this);
   1755 
   1756     GotoIfNot(TaggedIsSmi(search_element), &not_smi);
   1757     search_num.Bind(SmiToFloat64(search_element));
   1758     Goto(&heap_num_loop);
   1759 
   1760     Bind(&not_smi);
   1761     GotoIf(WordEqual(search_element, UndefinedConstant()), &undef_loop);
   1762     Node* map = LoadMap(search_element);
   1763     GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
   1764     search_num.Bind(LoadHeapNumberValue(search_element));
   1765     Goto(&heap_num_loop);
   1766 
   1767     Bind(&not_heap_num);
   1768     Node* search_type = LoadMapInstanceType(map);
   1769     GotoIf(IsStringInstanceType(search_type), &string_loop);
   1770     Goto(&ident_loop);
   1771 
   1772     Bind(&ident_loop);
   1773     {
   1774       GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1775                 &return_false);
   1776       Node* element_k = LoadFixedArrayElement(elements, index_var.value());
   1777       GotoIf(WordEqual(element_k, search_element), &return_true);
   1778 
   1779       index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1780       Goto(&ident_loop);
   1781     }
   1782 
   1783     Bind(&undef_loop);
   1784     {
   1785       GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1786                 &return_false);
   1787       Node* element_k = LoadFixedArrayElement(elements, index_var.value());
   1788       GotoIf(WordEqual(element_k, UndefinedConstant()), &return_true);
   1789       GotoIf(WordEqual(element_k, TheHoleConstant()), &return_true);
   1790 
   1791       index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1792       Goto(&undef_loop);
   1793     }
   1794 
   1795     Bind(&heap_num_loop);
   1796     {
   1797       Label nan_loop(this, &index_var), not_nan_loop(this, &index_var);
   1798       BranchIfFloat64IsNaN(search_num.value(), &nan_loop, &not_nan_loop);
   1799 
   1800       Bind(&not_nan_loop);
   1801       {
   1802         Label continue_loop(this), not_smi(this);
   1803         GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1804                   &return_false);
   1805         Node* element_k = LoadFixedArrayElement(elements, index_var.value());
   1806         GotoIfNot(TaggedIsSmi(element_k), &not_smi);
   1807         Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
   1808                &return_true, &continue_loop);
   1809 
   1810         Bind(&not_smi);
   1811         GotoIfNot(IsHeapNumber(element_k), &continue_loop);
   1812         Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
   1813                &return_true, &continue_loop);
   1814 
   1815         Bind(&continue_loop);
   1816         index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1817         Goto(&not_nan_loop);
   1818       }
   1819 
   1820       Bind(&nan_loop);
   1821       {
   1822         Label continue_loop(this);
   1823         GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1824                   &return_false);
   1825         Node* element_k = LoadFixedArrayElement(elements, index_var.value());
   1826         GotoIf(TaggedIsSmi(element_k), &continue_loop);
   1827         GotoIfNot(IsHeapNumber(element_k), &continue_loop);
   1828         BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_true,
   1829                              &continue_loop);
   1830 
   1831         Bind(&continue_loop);
   1832         index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1833         Goto(&nan_loop);
   1834       }
   1835     }
   1836 
   1837     Bind(&string_loop);
   1838     {
   1839       Label continue_loop(this);
   1840       GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1841                 &return_false);
   1842       Node* element_k = LoadFixedArrayElement(elements, index_var.value());
   1843       GotoIf(TaggedIsSmi(element_k), &continue_loop);
   1844       GotoIfNot(IsStringInstanceType(LoadInstanceType(element_k)),
   1845                 &continue_loop);
   1846 
   1847       // TODO(bmeurer): Consider inlining the StringEqual logic here.
   1848       Node* result = CallStub(CodeFactory::StringEqual(isolate()), context,
   1849                               search_element, element_k);
   1850       Branch(WordEqual(BooleanConstant(true), result), &return_true,
   1851              &continue_loop);
   1852 
   1853       Bind(&continue_loop);
   1854       index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1855       Goto(&string_loop);
   1856     }
   1857   }
   1858 
   1859   Bind(&if_packed_doubles);
   1860   {
   1861     Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
   1862         hole_loop(this, &index_var), search_notnan(this);
   1863     Variable search_num(this, MachineRepresentation::kFloat64);
   1864 
   1865     GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
   1866     search_num.Bind(SmiToFloat64(search_element));
   1867     Goto(&not_nan_loop);
   1868 
   1869     Bind(&search_notnan);
   1870     GotoIfNot(IsHeapNumber(search_element), &return_false);
   1871 
   1872     search_num.Bind(LoadHeapNumberValue(search_element));
   1873 
   1874     BranchIfFloat64IsNaN(search_num.value(), &nan_loop, &not_nan_loop);
   1875 
   1876     // Search for HeapNumber
   1877     Bind(&not_nan_loop);
   1878     {
   1879       Label continue_loop(this);
   1880       GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1881                 &return_false);
   1882       Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
   1883                                                     MachineType::Float64());
   1884       Branch(Float64Equal(element_k, search_num.value()), &return_true,
   1885              &continue_loop);
   1886       Bind(&continue_loop);
   1887       index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1888       Goto(&not_nan_loop);
   1889     }
   1890 
   1891     // Search for NaN
   1892     Bind(&nan_loop);
   1893     {
   1894       Label continue_loop(this);
   1895       GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1896                 &return_false);
   1897       Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
   1898                                                     MachineType::Float64());
   1899       BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop);
   1900       Bind(&continue_loop);
   1901       index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1902       Goto(&nan_loop);
   1903     }
   1904   }
   1905 
   1906   Bind(&if_holey_doubles);
   1907   {
   1908     Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
   1909         hole_loop(this, &index_var), search_notnan(this);
   1910     Variable search_num(this, MachineRepresentation::kFloat64);
   1911 
   1912     GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
   1913     search_num.Bind(SmiToFloat64(search_element));
   1914     Goto(&not_nan_loop);
   1915 
   1916     Bind(&search_notnan);
   1917     GotoIf(WordEqual(search_element, UndefinedConstant()), &hole_loop);
   1918     GotoIfNot(IsHeapNumber(search_element), &return_false);
   1919 
   1920     search_num.Bind(LoadHeapNumberValue(search_element));
   1921 
   1922     BranchIfFloat64IsNaN(search_num.value(), &nan_loop, &not_nan_loop);
   1923 
   1924     // Search for HeapNumber
   1925     Bind(&not_nan_loop);
   1926     {
   1927       Label continue_loop(this);
   1928       GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1929                 &return_false);
   1930 
   1931       // Load double value or continue if it contains a double hole.
   1932       Node* element_k = LoadFixedDoubleArrayElement(
   1933           elements, index_var.value(), MachineType::Float64(), 0,
   1934           CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop);
   1935 
   1936       Branch(Float64Equal(element_k, search_num.value()), &return_true,
   1937              &continue_loop);
   1938       Bind(&continue_loop);
   1939       index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1940       Goto(&not_nan_loop);
   1941     }
   1942 
   1943     // Search for NaN
   1944     Bind(&nan_loop);
   1945     {
   1946       Label continue_loop(this);
   1947       GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1948                 &return_false);
   1949 
   1950       // Load double value or continue if it contains a double hole.
   1951       Node* element_k = LoadFixedDoubleArrayElement(
   1952           elements, index_var.value(), MachineType::Float64(), 0,
   1953           CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop);
   1954 
   1955       BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop);
   1956       Bind(&continue_loop);
   1957       index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1958       Goto(&nan_loop);
   1959     }
   1960 
   1961     // Search for the Hole
   1962     Bind(&hole_loop);
   1963     {
   1964       GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
   1965                 &return_false);
   1966 
   1967       // Check if the element is a double hole, but don't load it.
   1968       LoadFixedDoubleArrayElement(
   1969           elements, index_var.value(), MachineType::None(), 0,
   1970           CodeStubAssembler::INTPTR_PARAMETERS, &return_true);
   1971 
   1972       index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
   1973       Goto(&hole_loop);
   1974     }
   1975   }
   1976 
   1977   Bind(&return_true);
   1978   Return(TrueConstant());
   1979 
   1980   Bind(&return_false);
   1981   Return(FalseConstant());
   1982 
   1983   Bind(&call_runtime);
   1984   Return(CallRuntime(Runtime::kArrayIncludes_Slow, context, array,
   1985                      search_element, start_from));
   1986 }
   1987 
   1988 void Builtins::Generate_ArrayIndexOf(compiler::CodeAssemblerState* state) {
   1989   typedef compiler::Node Node;
   1990   typedef CodeStubAssembler::Label Label;
   1991   typedef CodeStubAssembler::Variable Variable;
   1992   CodeStubAssembler assembler(state);
   1993 
   1994   Node* array = assembler.Parameter(0);
   1995   Node* search_element = assembler.Parameter(1);
   1996   Node* start_from = assembler.Parameter(2);
   1997   Node* context = assembler.Parameter(3 + 2);
   1998 
   1999   Node* intptr_zero = assembler.IntPtrConstant(0);
   2000   Node* intptr_one = assembler.IntPtrConstant(1);
   2001 
   2002   Node* undefined = assembler.UndefinedConstant();
   2003 
   2004   Variable len_var(&assembler, MachineType::PointerRepresentation()),
   2005       index_var(&assembler, MachineType::PointerRepresentation()),
   2006       start_from_var(&assembler, MachineType::PointerRepresentation());
   2007 
   2008   Label init_k(&assembler), return_found(&assembler),
   2009       return_not_found(&assembler), call_runtime(&assembler);
   2010 
   2011   Label init_len(&assembler);
   2012 
   2013   index_var.Bind(intptr_zero);
   2014   len_var.Bind(intptr_zero);
   2015 
   2016   // Take slow path if not a JSArray, if retrieving elements requires
   2017   // traversing prototype, or if access checks are required.
   2018   assembler.BranchIfFastJSArray(
   2019       array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
   2020       &init_len, &call_runtime);
   2021 
   2022   assembler.Bind(&init_len);
   2023   {
   2024     // Handle case where JSArray length is not an Smi in the runtime
   2025     Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset);
   2026     assembler.GotoIfNot(assembler.TaggedIsSmi(len), &call_runtime);
   2027 
   2028     len_var.Bind(assembler.SmiToWord(len));
   2029     assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero),
   2030                      &return_not_found, &init_k);
   2031   }
   2032 
   2033   assembler.Bind(&init_k);
   2034   {
   2035     // For now only deal with undefined and Smis here; we must be really careful
   2036     // with side-effects from the ToInteger conversion as the side-effects might
   2037     // render our assumptions about the receiver being a fast JSArray and the
   2038     // length invalid.
   2039     Label done(&assembler), init_k_smi(&assembler), init_k_other(&assembler),
   2040         init_k_zero(&assembler), init_k_n(&assembler);
   2041 
   2042     assembler.Branch(assembler.TaggedIsSmi(start_from), &init_k_smi,
   2043                      &init_k_other);
   2044 
   2045     assembler.Bind(&init_k_smi);
   2046     {
   2047       start_from_var.Bind(assembler.SmiUntag(start_from));
   2048       assembler.Goto(&init_k_n);
   2049     }
   2050 
   2051     assembler.Bind(&init_k_other);
   2052     {
   2053       // The fromIndex must be undefined here, otherwise bailout and let the
   2054       // runtime deal with the full ToInteger conversion.
   2055       assembler.GotoIfNot(assembler.IsUndefined(start_from), &call_runtime);
   2056       start_from_var.Bind(intptr_zero);
   2057       assembler.Goto(&init_k_n);
   2058     }
   2059 
   2060     assembler.Bind(&init_k_n);
   2061     {
   2062       Label if_positive(&assembler), if_negative(&assembler), done(&assembler);
   2063       assembler.Branch(
   2064           assembler.IntPtrLessThan(start_from_var.value(), intptr_zero),
   2065           &if_negative, &if_positive);
   2066 
   2067       assembler.Bind(&if_positive);
   2068       {
   2069         index_var.Bind(start_from_var.value());
   2070         assembler.Goto(&done);
   2071       }
   2072 
   2073       assembler.Bind(&if_negative);
   2074       {
   2075         index_var.Bind(
   2076             assembler.IntPtrAdd(len_var.value(), start_from_var.value()));
   2077         assembler.Branch(
   2078             assembler.IntPtrLessThan(index_var.value(), intptr_zero),
   2079             &init_k_zero, &done);
   2080       }
   2081 
   2082       assembler.Bind(&init_k_zero);
   2083       {
   2084         index_var.Bind(intptr_zero);
   2085         assembler.Goto(&done);
   2086       }
   2087 
   2088       assembler.Bind(&done);
   2089     }
   2090   }
   2091 
   2092   static int32_t kElementsKind[] = {
   2093       FAST_SMI_ELEMENTS,   FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS,
   2094       FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS,    FAST_HOLEY_DOUBLE_ELEMENTS,
   2095   };
   2096 
   2097   Label if_smiorobjects(&assembler), if_packed_doubles(&assembler),
   2098       if_holey_doubles(&assembler);
   2099   Label* element_kind_handlers[] = {&if_smiorobjects,   &if_smiorobjects,
   2100                                     &if_smiorobjects,   &if_smiorobjects,
   2101                                     &if_packed_doubles, &if_holey_doubles};
   2102 
   2103   Node* map = assembler.LoadMap(array);
   2104   Node* elements_kind = assembler.LoadMapElementsKind(map);
   2105   Node* elements = assembler.LoadElements(array);
   2106   assembler.Switch(elements_kind, &return_not_found, kElementsKind,
   2107                    element_kind_handlers, arraysize(kElementsKind));
   2108 
   2109   assembler.Bind(&if_smiorobjects);
   2110   {
   2111     Variable search_num(&assembler, MachineRepresentation::kFloat64);
   2112     Label ident_loop(&assembler, &index_var),
   2113         heap_num_loop(&assembler, &search_num),
   2114         string_loop(&assembler, &index_var), undef_loop(&assembler, &index_var),
   2115         not_smi(&assembler), not_heap_num(&assembler);
   2116 
   2117     assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), &not_smi);
   2118     search_num.Bind(assembler.SmiToFloat64(search_element));
   2119     assembler.Goto(&heap_num_loop);
   2120 
   2121     assembler.Bind(&not_smi);
   2122     assembler.GotoIf(assembler.WordEqual(search_element, undefined),
   2123                      &undef_loop);
   2124     Node* map = assembler.LoadMap(search_element);
   2125     assembler.GotoIfNot(assembler.IsHeapNumberMap(map), &not_heap_num);
   2126     search_num.Bind(assembler.LoadHeapNumberValue(search_element));
   2127     assembler.Goto(&heap_num_loop);
   2128 
   2129     assembler.Bind(&not_heap_num);
   2130     Node* search_type = assembler.LoadMapInstanceType(map);
   2131     assembler.GotoIf(assembler.IsStringInstanceType(search_type), &string_loop);
   2132     assembler.Goto(&ident_loop);
   2133 
   2134     assembler.Bind(&ident_loop);
   2135     {
   2136       assembler.GotoIfNot(
   2137           assembler.UintPtrLessThan(index_var.value(), len_var.value()),
   2138           &return_not_found);
   2139       Node* element_k =
   2140           assembler.LoadFixedArrayElement(elements, index_var.value());
   2141       assembler.GotoIf(assembler.WordEqual(element_k, search_element),
   2142                        &return_found);
   2143 
   2144       index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
   2145       assembler.Goto(&ident_loop);
   2146     }
   2147 
   2148     assembler.Bind(&undef_loop);
   2149     {
   2150       assembler.GotoIfNot(
   2151           assembler.UintPtrLessThan(index_var.value(), len_var.value()),
   2152           &return_not_found);
   2153       Node* element_k =
   2154           assembler.LoadFixedArrayElement(elements, index_var.value());
   2155       assembler.GotoIf(assembler.WordEqual(element_k, undefined),
   2156                        &return_found);
   2157 
   2158       index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
   2159       assembler.Goto(&undef_loop);
   2160     }
   2161 
   2162     assembler.Bind(&heap_num_loop);
   2163     {
   2164       Label not_nan_loop(&assembler, &index_var);
   2165       assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found,
   2166                                      &not_nan_loop);
   2167 
   2168       assembler.Bind(&not_nan_loop);
   2169       {
   2170         Label continue_loop(&assembler), not_smi(&assembler);
   2171         assembler.GotoIfNot(
   2172             assembler.UintPtrLessThan(index_var.value(), len_var.value()),
   2173             &return_not_found);
   2174         Node* element_k =
   2175             assembler.LoadFixedArrayElement(elements, index_var.value());
   2176         assembler.GotoIfNot(assembler.TaggedIsSmi(element_k), &not_smi);
   2177         assembler.Branch(
   2178             assembler.Float64Equal(search_num.value(),
   2179                                    assembler.SmiToFloat64(element_k)),
   2180             &return_found, &continue_loop);
   2181 
   2182         assembler.Bind(&not_smi);
   2183         assembler.GotoIfNot(
   2184             assembler.IsHeapNumberMap(assembler.LoadMap(element_k)),
   2185             &continue_loop);
   2186         assembler.Branch(
   2187             assembler.Float64Equal(search_num.value(),
   2188                                    assembler.LoadHeapNumberValue(element_k)),
   2189             &return_found, &continue_loop);
   2190 
   2191         assembler.Bind(&continue_loop);
   2192         index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
   2193         assembler.Goto(&not_nan_loop);
   2194       }
   2195     }
   2196 
   2197     assembler.Bind(&string_loop);
   2198     {
   2199       Label continue_loop(&assembler);
   2200       assembler.GotoIfNot(
   2201           assembler.UintPtrLessThan(index_var.value(), len_var.value()),
   2202           &return_not_found);
   2203       Node* element_k =
   2204           assembler.LoadFixedArrayElement(elements, index_var.value());
   2205       assembler.GotoIf(assembler.TaggedIsSmi(element_k), &continue_loop);
   2206       assembler.GotoIfNot(
   2207           assembler.IsStringInstanceType(assembler.LoadInstanceType(element_k)),
   2208           &continue_loop);
   2209 
   2210       // TODO(bmeurer): Consider inlining the StringEqual logic here.
   2211       Callable callable = CodeFactory::StringEqual(assembler.isolate());
   2212       Node* result =
   2213           assembler.CallStub(callable, context, search_element, element_k);
   2214       assembler.Branch(
   2215           assembler.WordEqual(assembler.BooleanConstant(true), result),
   2216           &return_found, &continue_loop);
   2217 
   2218       assembler.Bind(&continue_loop);
   2219       index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
   2220       assembler.Goto(&string_loop);
   2221     }
   2222   }
   2223 
   2224   assembler.Bind(&if_packed_doubles);
   2225   {
   2226     Label not_nan_loop(&assembler, &index_var), search_notnan(&assembler);
   2227     Variable search_num(&assembler, MachineRepresentation::kFloat64);
   2228 
   2229     assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), &search_notnan);
   2230     search_num.Bind(assembler.SmiToFloat64(search_element));
   2231     assembler.Goto(&not_nan_loop);
   2232 
   2233     assembler.Bind(&search_notnan);
   2234     assembler.GotoIfNot(
   2235         assembler.IsHeapNumberMap(assembler.LoadMap(search_element)),
   2236         &return_not_found);
   2237 
   2238     search_num.Bind(assembler.LoadHeapNumberValue(search_element));
   2239 
   2240     assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found,
   2241                                    &not_nan_loop);
   2242 
   2243     // Search for HeapNumber
   2244     assembler.Bind(&not_nan_loop);
   2245     {
   2246       Label continue_loop(&assembler);
   2247       assembler.GotoIfNot(
   2248           assembler.UintPtrLessThan(index_var.value(), len_var.value()),
   2249           &return_not_found);
   2250       Node* element_k = assembler.LoadFixedDoubleArrayElement(
   2251           elements, index_var.value(), MachineType::Float64());
   2252       assembler.Branch(assembler.Float64Equal(element_k, search_num.value()),
   2253                        &return_found, &continue_loop);
   2254       assembler.Bind(&continue_loop);
   2255       index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
   2256       assembler.Goto(&not_nan_loop);
   2257     }
   2258   }
   2259 
   2260   assembler.Bind(&if_holey_doubles);
   2261   {
   2262     Label not_nan_loop(&assembler, &index_var), search_notnan(&assembler);
   2263     Variable search_num(&assembler, MachineRepresentation::kFloat64);
   2264 
   2265     assembler.GotoIfNot(assembler.TaggedIsSmi(search_element), &search_notnan);
   2266     search_num.Bind(assembler.SmiToFloat64(search_element));
   2267     assembler.Goto(&not_nan_loop);
   2268 
   2269     assembler.Bind(&search_notnan);
   2270     assembler.GotoIfNot(
   2271         assembler.IsHeapNumberMap(assembler.LoadMap(search_element)),
   2272         &return_not_found);
   2273 
   2274     search_num.Bind(assembler.LoadHeapNumberValue(search_element));
   2275 
   2276     assembler.BranchIfFloat64IsNaN(search_num.value(), &return_not_found,
   2277                                    &not_nan_loop);
   2278 
   2279     // Search for HeapNumber
   2280     assembler.Bind(&not_nan_loop);
   2281     {
   2282       Label continue_loop(&assembler);
   2283       assembler.GotoIfNot(
   2284           assembler.UintPtrLessThan(index_var.value(), len_var.value()),
   2285           &return_not_found);
   2286 
   2287       // Load double value or continue if it contains a double hole.
   2288       Node* element_k = assembler.LoadFixedDoubleArrayElement(
   2289           elements, index_var.value(), MachineType::Float64(), 0,
   2290           CodeStubAssembler::INTPTR_PARAMETERS, &continue_loop);
   2291 
   2292       assembler.Branch(assembler.Float64Equal(element_k, search_num.value()),
   2293                        &return_found, &continue_loop);
   2294       assembler.Bind(&continue_loop);
   2295       index_var.Bind(assembler.IntPtrAdd(index_var.value(), intptr_one));
   2296       assembler.Goto(&not_nan_loop);
   2297     }
   2298   }
   2299 
   2300   assembler.Bind(&return_found);
   2301   assembler.Return(assembler.SmiTag(index_var.value()));
   2302 
   2303   assembler.Bind(&return_not_found);
   2304   assembler.Return(assembler.NumberConstant(-1));
   2305 
   2306   assembler.Bind(&call_runtime);
   2307   assembler.Return(assembler.CallRuntime(Runtime::kArrayIndexOf, context, array,
   2308                                          search_element, start_from));
   2309 }
   2310 
   2311 namespace {
   2312 
   2313 template <IterationKind kIterationKind>
   2314 void Generate_ArrayPrototypeIterationMethod(
   2315     compiler::CodeAssemblerState* state) {
   2316   typedef compiler::Node Node;
   2317   typedef CodeStubAssembler::Label Label;
   2318   typedef CodeStubAssembler::Variable Variable;
   2319   CodeStubAssembler assembler(state);
   2320 
   2321   Node* receiver = assembler.Parameter(0);
   2322   Node* context = assembler.Parameter(3);
   2323 
   2324   Variable var_array(&assembler, MachineRepresentation::kTagged);
   2325   Variable var_map(&assembler, MachineRepresentation::kTagged);
   2326   Variable var_type(&assembler, MachineRepresentation::kWord32);
   2327 
   2328   Label if_isnotobject(&assembler, Label::kDeferred);
   2329   Label create_array_iterator(&assembler);
   2330 
   2331   assembler.GotoIf(assembler.TaggedIsSmi(receiver), &if_isnotobject);
   2332   var_array.Bind(receiver);
   2333   var_map.Bind(assembler.LoadMap(receiver));
   2334   var_type.Bind(assembler.LoadMapInstanceType(var_map.value()));
   2335   assembler.Branch(assembler.IsJSReceiverInstanceType(var_type.value()),
   2336                    &create_array_iterator, &if_isnotobject);
   2337 
   2338   assembler.Bind(&if_isnotobject);
   2339   {
   2340     Callable callable = CodeFactory::ToObject(assembler.isolate());
   2341     Node* result = assembler.CallStub(callable, context, receiver);
   2342     var_array.Bind(result);
   2343     var_map.Bind(assembler.LoadMap(result));
   2344     var_type.Bind(assembler.LoadMapInstanceType(var_map.value()));
   2345     assembler.Goto(&create_array_iterator);
   2346   }
   2347 
   2348   assembler.Bind(&create_array_iterator);
   2349   assembler.Return(
   2350       assembler.CreateArrayIterator(var_array.value(), var_map.value(),
   2351                                     var_type.value(), context, kIterationKind));
   2352 }
   2353 
   2354 }  // namespace
   2355 
   2356 void Builtins::Generate_ArrayPrototypeValues(
   2357     compiler::CodeAssemblerState* state) {
   2358   Generate_ArrayPrototypeIterationMethod<IterationKind::kValues>(state);
   2359 }
   2360 
   2361 void Builtins::Generate_ArrayPrototypeEntries(
   2362     compiler::CodeAssemblerState* state) {
   2363   Generate_ArrayPrototypeIterationMethod<IterationKind::kEntries>(state);
   2364 }
   2365 
   2366 void Builtins::Generate_ArrayPrototypeKeys(
   2367     compiler::CodeAssemblerState* state) {
   2368   Generate_ArrayPrototypeIterationMethod<IterationKind::kKeys>(state);
   2369 }
   2370 
   2371 void Builtins::Generate_ArrayIteratorPrototypeNext(
   2372     compiler::CodeAssemblerState* state) {
   2373   typedef compiler::Node Node;
   2374   typedef CodeStubAssembler::Label Label;
   2375   typedef CodeStubAssembler::Variable Variable;
   2376   CodeStubAssembler assembler(state);
   2377 
   2378   Handle<String> operation = assembler.factory()->NewStringFromAsciiChecked(
   2379       "Array Iterator.prototype.next", TENURED);
   2380 
   2381   Node* iterator = assembler.Parameter(0);
   2382   Node* context = assembler.Parameter(3);
   2383 
   2384   Variable var_value(&assembler, MachineRepresentation::kTagged);
   2385   Variable var_done(&assembler, MachineRepresentation::kTagged);
   2386 
   2387   // Required, or else `throw_bad_receiver` fails a DCHECK due to these
   2388   // variables not being bound along all paths, despite not being used.
   2389   var_done.Bind(assembler.TrueConstant());
   2390   var_value.Bind(assembler.UndefinedConstant());
   2391 
   2392   Label throw_bad_receiver(&assembler, Label::kDeferred);
   2393   Label set_done(&assembler);
   2394   Label allocate_key_result(&assembler);
   2395   Label allocate_entry_if_needed(&assembler);
   2396   Label allocate_iterator_result(&assembler);
   2397   Label generic_values(&assembler);
   2398 
   2399   // If O does not have all of the internal slots of an Array Iterator Instance
   2400   // (22.1.5.3), throw a TypeError exception
   2401   assembler.GotoIf(assembler.TaggedIsSmi(iterator), &throw_bad_receiver);
   2402   Node* instance_type = assembler.LoadInstanceType(iterator);
   2403   assembler.GotoIf(
   2404       assembler.Uint32LessThan(
   2405           assembler.Int32Constant(LAST_ARRAY_ITERATOR_TYPE -
   2406                                   FIRST_ARRAY_ITERATOR_TYPE),
   2407           assembler.Int32Sub(instance_type, assembler.Int32Constant(
   2408                                                 FIRST_ARRAY_ITERATOR_TYPE))),
   2409       &throw_bad_receiver);
   2410 
   2411   // Let a be O.[[IteratedObject]].
   2412   Node* array = assembler.LoadObjectField(
   2413       iterator, JSArrayIterator::kIteratedObjectOffset);
   2414 
   2415   // Let index be O.[[ArrayIteratorNextIndex]].
   2416   Node* index =
   2417       assembler.LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset);
   2418   Node* orig_map = assembler.LoadObjectField(
   2419       iterator, JSArrayIterator::kIteratedObjectMapOffset);
   2420   Node* array_map = assembler.LoadMap(array);
   2421 
   2422   Label if_isfastarray(&assembler), if_isnotfastarray(&assembler),
   2423       if_isdetached(&assembler, Label::kDeferred);
   2424 
   2425   assembler.Branch(assembler.WordEqual(orig_map, array_map), &if_isfastarray,
   2426                    &if_isnotfastarray);
   2427 
   2428   assembler.Bind(&if_isfastarray);
   2429   {
   2430     CSA_ASSERT(&assembler,
   2431                assembler.Word32Equal(assembler.LoadMapInstanceType(array_map),
   2432                                      assembler.Int32Constant(JS_ARRAY_TYPE)));
   2433 
   2434     Node* length = assembler.LoadObjectField(array, JSArray::kLengthOffset);
   2435 
   2436     CSA_ASSERT(&assembler, assembler.TaggedIsSmi(length));
   2437     CSA_ASSERT(&assembler, assembler.TaggedIsSmi(index));
   2438 
   2439     assembler.GotoIfNot(assembler.SmiBelow(index, length), &set_done);
   2440 
   2441     Node* one = assembler.SmiConstant(Smi::FromInt(1));
   2442     assembler.StoreObjectFieldNoWriteBarrier(iterator,
   2443                                              JSArrayIterator::kNextIndexOffset,
   2444                                              assembler.SmiAdd(index, one));
   2445 
   2446     var_done.Bind(assembler.FalseConstant());
   2447     Node* elements = assembler.LoadElements(array);
   2448 
   2449     static int32_t kInstanceType[] = {
   2450         JS_FAST_ARRAY_KEY_ITERATOR_TYPE,
   2451         JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2452         JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2453         JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2454         JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2455         JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2456         JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2457         JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE,
   2458         JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE,
   2459         JS_FAST_ARRAY_VALUE_ITERATOR_TYPE,
   2460         JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE,
   2461         JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE,
   2462         JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE,
   2463     };
   2464 
   2465     Label packed_object_values(&assembler), holey_object_values(&assembler),
   2466         packed_double_values(&assembler), holey_double_values(&assembler);
   2467     Label* kInstanceTypeHandlers[] = {
   2468         &allocate_key_result,  &packed_object_values, &holey_object_values,
   2469         &packed_object_values, &holey_object_values,  &packed_double_values,
   2470         &holey_double_values,  &packed_object_values, &holey_object_values,
   2471         &packed_object_values, &holey_object_values,  &packed_double_values,
   2472         &holey_double_values};
   2473 
   2474     assembler.Switch(instance_type, &throw_bad_receiver, kInstanceType,
   2475                      kInstanceTypeHandlers, arraysize(kInstanceType));
   2476 
   2477     assembler.Bind(&packed_object_values);
   2478     {
   2479       var_value.Bind(assembler.LoadFixedArrayElement(
   2480           elements, index, 0, CodeStubAssembler::SMI_PARAMETERS));
   2481       assembler.Goto(&allocate_entry_if_needed);
   2482     }
   2483 
   2484     assembler.Bind(&packed_double_values);
   2485     {
   2486       Node* value = assembler.LoadFixedDoubleArrayElement(
   2487           elements, index, MachineType::Float64(), 0,
   2488           CodeStubAssembler::SMI_PARAMETERS);
   2489       var_value.Bind(assembler.AllocateHeapNumberWithValue(value));
   2490       assembler.Goto(&allocate_entry_if_needed);
   2491     }
   2492 
   2493     assembler.Bind(&holey_object_values);
   2494     {
   2495       // Check the array_protector cell, and take the slow path if it's invalid.
   2496       Node* invalid =
   2497           assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
   2498       Node* cell = assembler.LoadRoot(Heap::kArrayProtectorRootIndex);
   2499       Node* cell_value =
   2500           assembler.LoadObjectField(cell, PropertyCell::kValueOffset);
   2501       assembler.GotoIf(assembler.WordEqual(cell_value, invalid),
   2502                        &generic_values);
   2503 
   2504       var_value.Bind(assembler.UndefinedConstant());
   2505       Node* value = assembler.LoadFixedArrayElement(
   2506           elements, index, 0, CodeStubAssembler::SMI_PARAMETERS);
   2507       assembler.GotoIf(assembler.WordEqual(value, assembler.TheHoleConstant()),
   2508                        &allocate_entry_if_needed);
   2509       var_value.Bind(value);
   2510       assembler.Goto(&allocate_entry_if_needed);
   2511     }
   2512 
   2513     assembler.Bind(&holey_double_values);
   2514     {
   2515       // Check the array_protector cell, and take the slow path if it's invalid.
   2516       Node* invalid =
   2517           assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
   2518       Node* cell = assembler.LoadRoot(Heap::kArrayProtectorRootIndex);
   2519       Node* cell_value =
   2520           assembler.LoadObjectField(cell, PropertyCell::kValueOffset);
   2521       assembler.GotoIf(assembler.WordEqual(cell_value, invalid),
   2522                        &generic_values);
   2523 
   2524       var_value.Bind(assembler.UndefinedConstant());
   2525       Node* value = assembler.LoadFixedDoubleArrayElement(
   2526           elements, index, MachineType::Float64(), 0,
   2527           CodeStubAssembler::SMI_PARAMETERS, &allocate_entry_if_needed);
   2528       var_value.Bind(assembler.AllocateHeapNumberWithValue(value));
   2529       assembler.Goto(&allocate_entry_if_needed);
   2530     }
   2531   }
   2532 
   2533   assembler.Bind(&if_isnotfastarray);
   2534   {
   2535     Label if_istypedarray(&assembler), if_isgeneric(&assembler);
   2536 
   2537     // If a is undefined, return CreateIterResultObject(undefined, true)
   2538     assembler.GotoIf(assembler.WordEqual(array, assembler.UndefinedConstant()),
   2539                      &allocate_iterator_result);
   2540 
   2541     Node* array_type = assembler.LoadInstanceType(array);
   2542     assembler.Branch(
   2543         assembler.Word32Equal(array_type,
   2544                               assembler.Int32Constant(JS_TYPED_ARRAY_TYPE)),
   2545         &if_istypedarray, &if_isgeneric);
   2546 
   2547     assembler.Bind(&if_isgeneric);
   2548     {
   2549       Label if_wasfastarray(&assembler);
   2550 
   2551       Node* length = nullptr;
   2552       {
   2553         Variable var_length(&assembler, MachineRepresentation::kTagged);
   2554         Label if_isarray(&assembler), if_isnotarray(&assembler),
   2555             done(&assembler);
   2556         assembler.Branch(
   2557             assembler.Word32Equal(array_type,
   2558                                   assembler.Int32Constant(JS_ARRAY_TYPE)),
   2559             &if_isarray, &if_isnotarray);
   2560 
   2561         assembler.Bind(&if_isarray);
   2562         {
   2563           var_length.Bind(
   2564               assembler.LoadObjectField(array, JSArray::kLengthOffset));
   2565 
   2566           // Invalidate protector cell if needed
   2567           assembler.Branch(
   2568               assembler.WordNotEqual(orig_map, assembler.UndefinedConstant()),
   2569               &if_wasfastarray, &done);
   2570 
   2571           assembler.Bind(&if_wasfastarray);
   2572           {
   2573             Label if_invalid(&assembler, Label::kDeferred);
   2574             // A fast array iterator transitioned to a slow iterator during
   2575             // iteration. Invalidate fast_array_iteration_prtoector cell to
   2576             // prevent potential deopt loops.
   2577             assembler.StoreObjectFieldNoWriteBarrier(
   2578                 iterator, JSArrayIterator::kIteratedObjectMapOffset,
   2579                 assembler.UndefinedConstant());
   2580             assembler.GotoIf(
   2581                 assembler.Uint32LessThanOrEqual(
   2582                     instance_type, assembler.Int32Constant(
   2583                                        JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
   2584                 &done);
   2585 
   2586             Node* invalid =
   2587                 assembler.SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
   2588             Node* cell =
   2589                 assembler.LoadRoot(Heap::kFastArrayIterationProtectorRootIndex);
   2590             assembler.StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset,
   2591                                                      invalid);
   2592             assembler.Goto(&done);
   2593           }
   2594         }
   2595 
   2596         assembler.Bind(&if_isnotarray);
   2597         {
   2598           Node* length_string = assembler.HeapConstant(
   2599               assembler.isolate()->factory()->length_string());
   2600           Callable get_property = CodeFactory::GetProperty(assembler.isolate());
   2601           Node* length =
   2602               assembler.CallStub(get_property, context, array, length_string);
   2603           Callable to_length = CodeFactory::ToLength(assembler.isolate());
   2604           var_length.Bind(assembler.CallStub(to_length, context, length));
   2605           assembler.Goto(&done);
   2606         }
   2607 
   2608         assembler.Bind(&done);
   2609         length = var_length.value();
   2610       }
   2611 
   2612       assembler.GotoUnlessNumberLessThan(index, length, &set_done);
   2613 
   2614       assembler.StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset,
   2615                                  assembler.NumberInc(index));
   2616       var_done.Bind(assembler.FalseConstant());
   2617 
   2618       assembler.Branch(
   2619           assembler.Uint32LessThanOrEqual(
   2620               instance_type,
   2621               assembler.Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
   2622           &allocate_key_result, &generic_values);
   2623 
   2624       assembler.Bind(&generic_values);
   2625       {
   2626         Callable get_property = CodeFactory::GetProperty(assembler.isolate());
   2627         var_value.Bind(assembler.CallStub(get_property, context, array, index));
   2628         assembler.Goto(&allocate_entry_if_needed);
   2629       }
   2630     }
   2631 
   2632     assembler.Bind(&if_istypedarray);
   2633     {
   2634       Node* buffer =
   2635           assembler.LoadObjectField(array, JSTypedArray::kBufferOffset);
   2636       assembler.GotoIf(assembler.IsDetachedBuffer(buffer), &if_isdetached);
   2637 
   2638       Node* length =
   2639           assembler.LoadObjectField(array, JSTypedArray::kLengthOffset);
   2640 
   2641       CSA_ASSERT(&assembler, assembler.TaggedIsSmi(length));
   2642       CSA_ASSERT(&assembler, assembler.TaggedIsSmi(index));
   2643 
   2644       assembler.GotoIfNot(assembler.SmiBelow(index, length), &set_done);
   2645 
   2646       Node* one = assembler.SmiConstant(1);
   2647       assembler.StoreObjectFieldNoWriteBarrier(
   2648           iterator, JSArrayIterator::kNextIndexOffset,
   2649           assembler.SmiAdd(index, one));
   2650       var_done.Bind(assembler.FalseConstant());
   2651 
   2652       Node* elements = assembler.LoadElements(array);
   2653       Node* base_ptr = assembler.LoadObjectField(
   2654           elements, FixedTypedArrayBase::kBasePointerOffset);
   2655       Node* external_ptr = assembler.LoadObjectField(
   2656           elements, FixedTypedArrayBase::kExternalPointerOffset,
   2657           MachineType::Pointer());
   2658       Node* data_ptr = assembler.IntPtrAdd(
   2659           assembler.BitcastTaggedToWord(base_ptr), external_ptr);
   2660 
   2661       static int32_t kInstanceType[] = {
   2662           JS_TYPED_ARRAY_KEY_ITERATOR_TYPE,
   2663           JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2664           JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2665           JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2666           JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2667           JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2668           JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2669           JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2670           JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2671           JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE,
   2672           JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE,
   2673           JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE,
   2674           JS_INT8_ARRAY_VALUE_ITERATOR_TYPE,
   2675           JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE,
   2676           JS_INT16_ARRAY_VALUE_ITERATOR_TYPE,
   2677           JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE,
   2678           JS_INT32_ARRAY_VALUE_ITERATOR_TYPE,
   2679           JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE,
   2680           JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE,
   2681       };
   2682 
   2683       Label uint8_values(&assembler), int8_values(&assembler),
   2684           uint16_values(&assembler), int16_values(&assembler),
   2685           uint32_values(&assembler), int32_values(&assembler),
   2686           float32_values(&assembler), float64_values(&assembler);
   2687       Label* kInstanceTypeHandlers[] = {
   2688           &allocate_key_result, &uint8_values,  &uint8_values,
   2689           &int8_values,         &uint16_values, &int16_values,
   2690           &uint32_values,       &int32_values,  &float32_values,
   2691           &float64_values,      &uint8_values,  &uint8_values,
   2692           &int8_values,         &uint16_values, &int16_values,
   2693           &uint32_values,       &int32_values,  &float32_values,
   2694           &float64_values,
   2695       };
   2696 
   2697       var_done.Bind(assembler.FalseConstant());
   2698       assembler.Switch(instance_type, &throw_bad_receiver, kInstanceType,
   2699                        kInstanceTypeHandlers, arraysize(kInstanceType));
   2700 
   2701       assembler.Bind(&uint8_values);
   2702       {
   2703         Node* value_uint8 = assembler.LoadFixedTypedArrayElement(
   2704             data_ptr, index, UINT8_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS);
   2705         var_value.Bind(assembler.SmiFromWord32(value_uint8));
   2706         assembler.Goto(&allocate_entry_if_needed);
   2707       }
   2708 
   2709       assembler.Bind(&int8_values);
   2710       {
   2711         Node* value_int8 = assembler.LoadFixedTypedArrayElement(
   2712             data_ptr, index, INT8_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS);
   2713         var_value.Bind(assembler.SmiFromWord32(value_int8));
   2714         assembler.Goto(&allocate_entry_if_needed);
   2715       }
   2716 
   2717       assembler.Bind(&uint16_values);
   2718       {
   2719         Node* value_uint16 = assembler.LoadFixedTypedArrayElement(
   2720             data_ptr, index, UINT16_ELEMENTS,
   2721             CodeStubAssembler::SMI_PARAMETERS);
   2722         var_value.Bind(assembler.SmiFromWord32(value_uint16));
   2723         assembler.Goto(&allocate_entry_if_needed);
   2724       }
   2725 
   2726       assembler.Bind(&int16_values);
   2727       {
   2728         Node* value_int16 = assembler.LoadFixedTypedArrayElement(
   2729             data_ptr, index, INT16_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS);
   2730         var_value.Bind(assembler.SmiFromWord32(value_int16));
   2731         assembler.Goto(&allocate_entry_if_needed);
   2732       }
   2733 
   2734       assembler.Bind(&uint32_values);
   2735       {
   2736         Node* value_uint32 = assembler.LoadFixedTypedArrayElement(
   2737             data_ptr, index, UINT32_ELEMENTS,
   2738             CodeStubAssembler::SMI_PARAMETERS);
   2739         var_value.Bind(assembler.ChangeUint32ToTagged(value_uint32));
   2740         assembler.Goto(&allocate_entry_if_needed);
   2741       }
   2742       assembler.Bind(&int32_values);
   2743       {
   2744         Node* value_int32 = assembler.LoadFixedTypedArrayElement(
   2745             data_ptr, index, INT32_ELEMENTS, CodeStubAssembler::SMI_PARAMETERS);
   2746         var_value.Bind(assembler.ChangeInt32ToTagged(value_int32));
   2747         assembler.Goto(&allocate_entry_if_needed);
   2748       }
   2749       assembler.Bind(&float32_values);
   2750       {
   2751         Node* value_float32 = assembler.LoadFixedTypedArrayElement(
   2752             data_ptr, index, FLOAT32_ELEMENTS,
   2753             CodeStubAssembler::SMI_PARAMETERS);
   2754         var_value.Bind(assembler.AllocateHeapNumberWithValue(
   2755             assembler.ChangeFloat32ToFloat64(value_float32)));
   2756         assembler.Goto(&allocate_entry_if_needed);
   2757       }
   2758       assembler.Bind(&float64_values);
   2759       {
   2760         Node* value_float64 = assembler.LoadFixedTypedArrayElement(
   2761             data_ptr, index, FLOAT64_ELEMENTS,
   2762             CodeStubAssembler::SMI_PARAMETERS);
   2763         var_value.Bind(assembler.AllocateHeapNumberWithValue(value_float64));
   2764         assembler.Goto(&allocate_entry_if_needed);
   2765       }
   2766     }
   2767   }
   2768 
   2769   assembler.Bind(&set_done);
   2770   {
   2771     assembler.StoreObjectFieldNoWriteBarrier(
   2772         iterator, JSArrayIterator::kIteratedObjectOffset,
   2773         assembler.UndefinedConstant());
   2774     assembler.Goto(&allocate_iterator_result);
   2775   }
   2776 
   2777   assembler.Bind(&allocate_key_result);
   2778   {
   2779     var_value.Bind(index);
   2780     var_done.Bind(assembler.FalseConstant());
   2781     assembler.Goto(&allocate_iterator_result);
   2782   }
   2783 
   2784   assembler.Bind(&allocate_entry_if_needed);
   2785   {
   2786     assembler.GotoIf(
   2787         assembler.Int32GreaterThan(
   2788             instance_type,
   2789             assembler.Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE)),
   2790         &allocate_iterator_result);
   2791 
   2792     Node* elements = assembler.AllocateFixedArray(FAST_ELEMENTS,
   2793                                                   assembler.IntPtrConstant(2));
   2794     assembler.StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER);
   2795     assembler.StoreFixedArrayElement(elements, 1, var_value.value(),
   2796                                      SKIP_WRITE_BARRIER);
   2797 
   2798     Node* entry = assembler.Allocate(JSArray::kSize);
   2799     Node* map =
   2800         assembler.LoadContextElement(assembler.LoadNativeContext(context),
   2801                                      Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX);
   2802 
   2803     assembler.StoreMapNoWriteBarrier(entry, map);
   2804     assembler.StoreObjectFieldRoot(entry, JSArray::kPropertiesOffset,
   2805                                    Heap::kEmptyFixedArrayRootIndex);
   2806     assembler.StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset,
   2807                                              elements);
   2808     assembler.StoreObjectFieldNoWriteBarrier(
   2809         entry, JSArray::kLengthOffset, assembler.SmiConstant(Smi::FromInt(2)));
   2810 
   2811     var_value.Bind(entry);
   2812     assembler.Goto(&allocate_iterator_result);
   2813   }
   2814 
   2815   assembler.Bind(&allocate_iterator_result);
   2816   {
   2817     Node* result = assembler.Allocate(JSIteratorResult::kSize);
   2818     Node* map =
   2819         assembler.LoadContextElement(assembler.LoadNativeContext(context),
   2820                                      Context::ITERATOR_RESULT_MAP_INDEX);
   2821     assembler.StoreMapNoWriteBarrier(result, map);
   2822     assembler.StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset,
   2823                                    Heap::kEmptyFixedArrayRootIndex);
   2824     assembler.StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
   2825                                    Heap::kEmptyFixedArrayRootIndex);
   2826     assembler.StoreObjectFieldNoWriteBarrier(
   2827         result, JSIteratorResult::kValueOffset, var_value.value());
   2828     assembler.StoreObjectFieldNoWriteBarrier(
   2829         result, JSIteratorResult::kDoneOffset, var_done.value());
   2830     assembler.Return(result);
   2831   }
   2832 
   2833   assembler.Bind(&throw_bad_receiver);
   2834   {
   2835     // The {receiver} is not a valid JSArrayIterator.
   2836     assembler.CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
   2837                           assembler.HeapConstant(operation), iterator);
   2838     assembler.Unreachable();
   2839   }
   2840 
   2841   assembler.Bind(&if_isdetached);
   2842   {
   2843     Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation);
   2844     assembler.CallRuntime(Runtime::kThrowTypeError, context, message,
   2845                           assembler.HeapConstant(operation));
   2846     assembler.Unreachable();
   2847   }
   2848 }
   2849 
   2850 }  // namespace internal
   2851 }  // namespace v8
   2852