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