Home | History | Annotate | Download | only in src
      1 // Copyright 2012 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/elements.h"
      6 
      7 #include "src/arguments.h"
      8 #include "src/conversions.h"
      9 #include "src/factory.h"
     10 #include "src/isolate-inl.h"
     11 #include "src/messages.h"
     12 #include "src/objects-inl.h"
     13 #include "src/utils.h"
     14 
     15 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
     16 // several abstract ElementsAccessor classes are used to allow sharing
     17 // common code.
     18 //
     19 // Inheritance hierarchy:
     20 // - ElementsAccessorBase                        (abstract)
     21 //   - FastElementsAccessor                      (abstract)
     22 //     - FastSmiOrObjectElementsAccessor
     23 //       - FastPackedSmiElementsAccessor
     24 //       - FastHoleySmiElementsAccessor
     25 //       - FastPackedObjectElementsAccessor
     26 //       - FastHoleyObjectElementsAccessor
     27 //     - FastDoubleElementsAccessor
     28 //       - FastPackedDoubleElementsAccessor
     29 //       - FastHoleyDoubleElementsAccessor
     30 //   - TypedElementsAccessor: template, with instantiations:
     31 //     - FixedUint8ElementsAccessor
     32 //     - FixedInt8ElementsAccessor
     33 //     - FixedUint16ElementsAccessor
     34 //     - FixedInt16ElementsAccessor
     35 //     - FixedUint32ElementsAccessor
     36 //     - FixedInt32ElementsAccessor
     37 //     - FixedFloat32ElementsAccessor
     38 //     - FixedFloat64ElementsAccessor
     39 //     - FixedUint8ClampedElementsAccessor
     40 //   - DictionaryElementsAccessor
     41 //   - SloppyArgumentsElementsAccessor
     42 //     - FastSloppyArgumentsElementsAccessor
     43 //     - SlowSloppyArgumentsElementsAccessor
     44 //   - StringWrapperElementsAccessor
     45 //     - FastStringWrapperElementsAccessor
     46 //     - SlowStringWrapperElementsAccessor
     47 
     48 namespace v8 {
     49 namespace internal {
     50 
     51 
     52 namespace {
     53 
     54 
     55 static const int kPackedSizeNotKnown = -1;
     56 
     57 enum Where { AT_START, AT_END };
     58 
     59 
     60 // First argument in list is the accessor class, the second argument is the
     61 // accessor ElementsKind, and the third is the backing store class.  Use the
     62 // fast element handler for smi-only arrays.  The implementation is currently
     63 // identical.  Note that the order must match that of the ElementsKind enum for
     64 // the |accessor_array[]| below to work.
     65 #define ELEMENTS_LIST(V)                                                      \
     66   V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray)             \
     67   V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray)        \
     68   V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray)              \
     69   V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray)         \
     70   V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
     71   V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS,              \
     72     FixedDoubleArray)                                                         \
     73   V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary)  \
     74   V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS,      \
     75     FixedArray)                                                               \
     76   V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS,      \
     77     FixedArray)                                                               \
     78   V(FastStringWrapperElementsAccessor, FAST_STRING_WRAPPER_ELEMENTS,          \
     79     FixedArray)                                                               \
     80   V(SlowStringWrapperElementsAccessor, SLOW_STRING_WRAPPER_ELEMENTS,          \
     81     FixedArray)                                                               \
     82   V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array)              \
     83   V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array)                 \
     84   V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array)           \
     85   V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array)              \
     86   V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array)           \
     87   V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array)              \
     88   V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array)        \
     89   V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array)        \
     90   V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS,                \
     91     FixedUint8ClampedArray)
     92 
     93 template<ElementsKind Kind> class ElementsKindTraits {
     94  public:
     95   typedef FixedArrayBase BackingStore;
     96 };
     97 
     98 #define ELEMENTS_TRAITS(Class, KindParam, Store)               \
     99 template<> class ElementsKindTraits<KindParam> {               \
    100  public:   /* NOLINT */                                        \
    101   static const ElementsKind Kind = KindParam;                  \
    102   typedef Store BackingStore;                                  \
    103 };
    104 ELEMENTS_LIST(ELEMENTS_TRAITS)
    105 #undef ELEMENTS_TRAITS
    106 
    107 
    108 MUST_USE_RESULT
    109 MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
    110   THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
    111                   Object);
    112 }
    113 
    114 
    115 void CopyObjectToObjectElements(FixedArrayBase* from_base,
    116                                 ElementsKind from_kind, uint32_t from_start,
    117                                 FixedArrayBase* to_base, ElementsKind to_kind,
    118                                 uint32_t to_start, int raw_copy_size) {
    119   DCHECK(to_base->map() !=
    120       from_base->GetIsolate()->heap()->fixed_cow_array_map());
    121   DisallowHeapAllocation no_allocation;
    122   int copy_size = raw_copy_size;
    123   if (raw_copy_size < 0) {
    124     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    125            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    126     copy_size = Min(from_base->length() - from_start,
    127                     to_base->length() - to_start);
    128     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    129       int start = to_start + copy_size;
    130       int length = to_base->length() - start;
    131       if (length > 0) {
    132         Heap* heap = from_base->GetHeap();
    133         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
    134                       heap->the_hole_value(), length);
    135       }
    136     }
    137   }
    138   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    139          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    140   if (copy_size == 0) return;
    141   FixedArray* from = FixedArray::cast(from_base);
    142   FixedArray* to = FixedArray::cast(to_base);
    143   DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
    144   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
    145 
    146   WriteBarrierMode write_barrier_mode =
    147       (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
    148           ? UPDATE_WRITE_BARRIER
    149           : SKIP_WRITE_BARRIER;
    150   for (int i = 0; i < copy_size; i++) {
    151     Object* value = from->get(from_start + i);
    152     to->set(to_start + i, value, write_barrier_mode);
    153   }
    154 }
    155 
    156 
    157 static void CopyDictionaryToObjectElements(
    158     FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
    159     ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
    160   DisallowHeapAllocation no_allocation;
    161   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
    162   int copy_size = raw_copy_size;
    163   if (raw_copy_size < 0) {
    164     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    165            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    166     copy_size = from->max_number_key() + 1 - from_start;
    167     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    168       int start = to_start + copy_size;
    169       int length = to_base->length() - start;
    170       if (length > 0) {
    171         Heap* heap = from->GetHeap();
    172         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
    173                       heap->the_hole_value(), length);
    174       }
    175     }
    176   }
    177   DCHECK(to_base != from_base);
    178   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
    179   if (copy_size == 0) return;
    180   FixedArray* to = FixedArray::cast(to_base);
    181   uint32_t to_length = to->length();
    182   if (to_start + copy_size > to_length) {
    183     copy_size = to_length - to_start;
    184   }
    185   WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
    186                                             ? UPDATE_WRITE_BARRIER
    187                                             : SKIP_WRITE_BARRIER;
    188   for (int i = 0; i < copy_size; i++) {
    189     int entry = from->FindEntry(i + from_start);
    190     if (entry != SeededNumberDictionary::kNotFound) {
    191       Object* value = from->ValueAt(entry);
    192       DCHECK(!value->IsTheHole(from->GetIsolate()));
    193       to->set(i + to_start, value, write_barrier_mode);
    194     } else {
    195       to->set_the_hole(i + to_start);
    196     }
    197   }
    198 }
    199 
    200 
    201 // NOTE: this method violates the handlified function signature convention:
    202 // raw pointer parameters in the function that allocates.
    203 // See ElementsAccessorBase::CopyElements() for details.
    204 static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
    205                                        uint32_t from_start,
    206                                        FixedArrayBase* to_base,
    207                                        uint32_t to_start, int raw_copy_size) {
    208   int copy_size = raw_copy_size;
    209   if (raw_copy_size < 0) {
    210     DisallowHeapAllocation no_allocation;
    211     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    212            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    213     copy_size = Min(from_base->length() - from_start,
    214                     to_base->length() - to_start);
    215     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    216       // Also initialize the area that will be copied over since HeapNumber
    217       // allocation below can cause an incremental marking step, requiring all
    218       // existing heap objects to be propertly initialized.
    219       int start = to_start;
    220       int length = to_base->length() - start;
    221       if (length > 0) {
    222         Heap* heap = from_base->GetHeap();
    223         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
    224                       heap->the_hole_value(), length);
    225       }
    226     }
    227   }
    228 
    229   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    230          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    231   if (copy_size == 0) return;
    232 
    233   // From here on, the code below could actually allocate. Therefore the raw
    234   // values are wrapped into handles.
    235   Isolate* isolate = from_base->GetIsolate();
    236   Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
    237   Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
    238 
    239   // Use an outer loop to not waste too much time on creating HandleScopes.
    240   // On the other hand we might overflow a single handle scope depending on
    241   // the copy_size.
    242   int offset = 0;
    243   while (offset < copy_size) {
    244     HandleScope scope(isolate);
    245     offset += 100;
    246     for (int i = offset - 100; i < offset && i < copy_size; ++i) {
    247       Handle<Object> value =
    248           FixedDoubleArray::get(*from, i + from_start, isolate);
    249       to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
    250     }
    251   }
    252 }
    253 
    254 
    255 static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
    256                                        uint32_t from_start,
    257                                        FixedArrayBase* to_base,
    258                                        uint32_t to_start, int raw_copy_size) {
    259   DisallowHeapAllocation no_allocation;
    260   int copy_size = raw_copy_size;
    261   if (raw_copy_size < 0) {
    262     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    263            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    264     copy_size = Min(from_base->length() - from_start,
    265                     to_base->length() - to_start);
    266     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    267       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    268         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    269       }
    270     }
    271   }
    272   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    273          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    274   if (copy_size == 0) return;
    275   FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
    276   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    277   Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
    278   Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
    279   to_address += kDoubleSize * to_start;
    280   from_address += kDoubleSize * from_start;
    281   int words_per_double = (kDoubleSize / kPointerSize);
    282   CopyWords(reinterpret_cast<Object**>(to_address),
    283             reinterpret_cast<Object**>(from_address),
    284             static_cast<size_t>(words_per_double * copy_size));
    285 }
    286 
    287 
    288 static void CopySmiToDoubleElements(FixedArrayBase* from_base,
    289                                     uint32_t from_start,
    290                                     FixedArrayBase* to_base, uint32_t to_start,
    291                                     int raw_copy_size) {
    292   DisallowHeapAllocation no_allocation;
    293   int copy_size = raw_copy_size;
    294   if (raw_copy_size < 0) {
    295     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    296            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    297     copy_size = from_base->length() - from_start;
    298     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    299       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    300         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    301       }
    302     }
    303   }
    304   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    305          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    306   if (copy_size == 0) return;
    307   FixedArray* from = FixedArray::cast(from_base);
    308   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    309   Object* the_hole = from->GetHeap()->the_hole_value();
    310   for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
    311        from_start < from_end; from_start++, to_start++) {
    312     Object* hole_or_smi = from->get(from_start);
    313     if (hole_or_smi == the_hole) {
    314       to->set_the_hole(to_start);
    315     } else {
    316       to->set(to_start, Smi::cast(hole_or_smi)->value());
    317     }
    318   }
    319 }
    320 
    321 
    322 static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
    323                                           uint32_t from_start,
    324                                           FixedArrayBase* to_base,
    325                                           uint32_t to_start, int packed_size,
    326                                           int raw_copy_size) {
    327   DisallowHeapAllocation no_allocation;
    328   int copy_size = raw_copy_size;
    329   uint32_t to_end;
    330   if (raw_copy_size < 0) {
    331     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    332            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    333     copy_size = packed_size - from_start;
    334     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    335       to_end = to_base->length();
    336       for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
    337         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    338       }
    339     } else {
    340       to_end = to_start + static_cast<uint32_t>(copy_size);
    341     }
    342   } else {
    343     to_end = to_start + static_cast<uint32_t>(copy_size);
    344   }
    345   DCHECK(static_cast<int>(to_end) <= to_base->length());
    346   DCHECK(packed_size >= 0 && packed_size <= copy_size);
    347   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    348          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    349   if (copy_size == 0) return;
    350   FixedArray* from = FixedArray::cast(from_base);
    351   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    352   for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
    353        from_start < from_end; from_start++, to_start++) {
    354     Object* smi = from->get(from_start);
    355     DCHECK(!smi->IsTheHole(from->GetIsolate()));
    356     to->set(to_start, Smi::cast(smi)->value());
    357   }
    358 }
    359 
    360 
    361 static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
    362                                        uint32_t from_start,
    363                                        FixedArrayBase* to_base,
    364                                        uint32_t to_start, int raw_copy_size) {
    365   DisallowHeapAllocation no_allocation;
    366   int copy_size = raw_copy_size;
    367   if (raw_copy_size < 0) {
    368     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    369            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    370     copy_size = from_base->length() - from_start;
    371     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    372       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    373         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    374       }
    375     }
    376   }
    377   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    378          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    379   if (copy_size == 0) return;
    380   FixedArray* from = FixedArray::cast(from_base);
    381   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    382   Object* the_hole = from->GetHeap()->the_hole_value();
    383   for (uint32_t from_end = from_start + copy_size;
    384        from_start < from_end; from_start++, to_start++) {
    385     Object* hole_or_object = from->get(from_start);
    386     if (hole_or_object == the_hole) {
    387       to->set_the_hole(to_start);
    388     } else {
    389       to->set(to_start, hole_or_object->Number());
    390     }
    391   }
    392 }
    393 
    394 
    395 static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
    396                                            uint32_t from_start,
    397                                            FixedArrayBase* to_base,
    398                                            uint32_t to_start,
    399                                            int raw_copy_size) {
    400   DisallowHeapAllocation no_allocation;
    401   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
    402   int copy_size = raw_copy_size;
    403   if (copy_size < 0) {
    404     DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
    405            copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    406     copy_size = from->max_number_key() + 1 - from_start;
    407     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    408       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    409         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    410       }
    411     }
    412   }
    413   if (copy_size == 0) return;
    414   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    415   uint32_t to_length = to->length();
    416   if (to_start + copy_size > to_length) {
    417     copy_size = to_length - to_start;
    418   }
    419   for (int i = 0; i < copy_size; i++) {
    420     int entry = from->FindEntry(i + from_start);
    421     if (entry != SeededNumberDictionary::kNotFound) {
    422       to->set(i + to_start, from->ValueAt(entry)->Number());
    423     } else {
    424       to->set_the_hole(i + to_start);
    425     }
    426   }
    427 }
    428 
    429 static void TraceTopFrame(Isolate* isolate) {
    430   StackFrameIterator it(isolate);
    431   if (it.done()) {
    432     PrintF("unknown location (no JavaScript frames present)");
    433     return;
    434   }
    435   StackFrame* raw_frame = it.frame();
    436   if (raw_frame->is_internal()) {
    437     Code* apply_builtin =
    438         isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
    439     if (raw_frame->unchecked_code() == apply_builtin) {
    440       PrintF("apply from ");
    441       it.Advance();
    442       raw_frame = it.frame();
    443     }
    444   }
    445   JavaScriptFrame::PrintTop(isolate, stdout, false, true);
    446 }
    447 
    448 static void SortIndices(
    449     Handle<FixedArray> indices, uint32_t sort_size,
    450     WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER) {
    451   struct {
    452     bool operator()(Object* a, Object* b) {
    453       if (a->IsSmi() || !a->IsUndefined(HeapObject::cast(a)->GetIsolate())) {
    454         if (!b->IsSmi() && b->IsUndefined(HeapObject::cast(b)->GetIsolate())) {
    455           return true;
    456         }
    457         return a->Number() < b->Number();
    458       }
    459       return !b->IsSmi() && b->IsUndefined(HeapObject::cast(b)->GetIsolate());
    460     }
    461   } cmp;
    462   Object** start =
    463       reinterpret_cast<Object**>(indices->GetFirstElementAddress());
    464   std::sort(start, start + sort_size, cmp);
    465   if (write_barrier_mode != SKIP_WRITE_BARRIER) {
    466     FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(indices->GetIsolate()->heap(), *indices,
    467                                        0, sort_size);
    468   }
    469 }
    470 
    471 static Maybe<bool> IncludesValueSlowPath(Isolate* isolate,
    472                                          Handle<JSObject> receiver,
    473                                          Handle<Object> value,
    474                                          uint32_t start_from, uint32_t length) {
    475   bool search_for_hole = value->IsUndefined(isolate);
    476   for (uint32_t k = start_from; k < length; ++k) {
    477     LookupIterator it(isolate, receiver, k);
    478     if (!it.IsFound()) {
    479       if (search_for_hole) return Just(true);
    480       continue;
    481     }
    482     Handle<Object> element_k;
    483     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
    484                                      Object::GetProperty(&it), Nothing<bool>());
    485 
    486     if (value->SameValueZero(*element_k)) return Just(true);
    487   }
    488 
    489   return Just(false);
    490 }
    491 
    492 static Maybe<int64_t> IndexOfValueSlowPath(Isolate* isolate,
    493                                            Handle<JSObject> receiver,
    494                                            Handle<Object> value,
    495                                            uint32_t start_from,
    496                                            uint32_t length) {
    497   for (uint32_t k = start_from; k < length; ++k) {
    498     LookupIterator it(isolate, receiver, k);
    499     if (!it.IsFound()) {
    500       continue;
    501     }
    502     Handle<Object> element_k;
    503     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
    504         isolate, element_k, Object::GetProperty(&it), Nothing<int64_t>());
    505 
    506     if (value->StrictEquals(*element_k)) return Just<int64_t>(k);
    507   }
    508 
    509   return Just<int64_t>(-1);
    510 }
    511 
    512 // Base class for element handler implementations. Contains the
    513 // the common logic for objects with different ElementsKinds.
    514 // Subclasses must specialize method for which the element
    515 // implementation differs from the base class implementation.
    516 //
    517 // This class is intended to be used in the following way:
    518 //
    519 //   class SomeElementsAccessor :
    520 //       public ElementsAccessorBase<SomeElementsAccessor,
    521 //                                   BackingStoreClass> {
    522 //     ...
    523 //   }
    524 //
    525 // This is an example of the Curiously Recurring Template Pattern (see
    526 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).  We use
    527 // CRTP to guarantee aggressive compile time optimizations (i.e.  inlining and
    528 // specialization of SomeElementsAccessor methods).
    529 template <typename Subclass, typename ElementsTraitsParam>
    530 class ElementsAccessorBase : public ElementsAccessor {
    531  public:
    532   explicit ElementsAccessorBase(const char* name)
    533       : ElementsAccessor(name) { }
    534 
    535   typedef ElementsTraitsParam ElementsTraits;
    536   typedef typename ElementsTraitsParam::BackingStore BackingStore;
    537 
    538   static ElementsKind kind() { return ElementsTraits::Kind; }
    539 
    540   static void ValidateContents(Handle<JSObject> holder, int length) {
    541   }
    542 
    543   static void ValidateImpl(Handle<JSObject> holder) {
    544     Handle<FixedArrayBase> fixed_array_base(holder->elements());
    545     if (!fixed_array_base->IsHeapObject()) return;
    546     // Arrays that have been shifted in place can't be verified.
    547     if (fixed_array_base->IsFiller()) return;
    548     int length = 0;
    549     if (holder->IsJSArray()) {
    550       Object* length_obj = Handle<JSArray>::cast(holder)->length();
    551       if (length_obj->IsSmi()) {
    552         length = Smi::cast(length_obj)->value();
    553       }
    554     } else {
    555       length = fixed_array_base->length();
    556     }
    557     Subclass::ValidateContents(holder, length);
    558   }
    559 
    560   void Validate(Handle<JSObject> holder) final {
    561     DisallowHeapAllocation no_gc;
    562     Subclass::ValidateImpl(holder);
    563   }
    564 
    565   static bool IsPackedImpl(Handle<JSObject> holder,
    566                            Handle<FixedArrayBase> backing_store, uint32_t start,
    567                            uint32_t end) {
    568     if (IsFastPackedElementsKind(kind())) return true;
    569     Isolate* isolate = backing_store->GetIsolate();
    570     for (uint32_t i = start; i < end; i++) {
    571       if (!Subclass::HasElementImpl(isolate, holder, i, backing_store,
    572                                     ALL_PROPERTIES)) {
    573         return false;
    574       }
    575     }
    576     return true;
    577   }
    578 
    579   static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
    580     if (!IsHoleyElementsKind(kind())) return;
    581     int length = Smi::cast(array->length())->value();
    582     Handle<FixedArrayBase> backing_store(array->elements());
    583     if (!Subclass::IsPackedImpl(array, backing_store, 0, length)) {
    584       return;
    585     }
    586     ElementsKind packed_kind = GetPackedElementsKind(kind());
    587     Handle<Map> new_map =
    588         JSObject::GetElementsTransitionMap(array, packed_kind);
    589     JSObject::MigrateToMap(array, new_map);
    590     if (FLAG_trace_elements_transitions) {
    591       JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
    592                                         packed_kind, backing_store);
    593     }
    594   }
    595 
    596   bool HasElement(Handle<JSObject> holder, uint32_t index,
    597                   Handle<FixedArrayBase> backing_store,
    598                   PropertyFilter filter) final {
    599     return Subclass::HasElementImpl(holder->GetIsolate(), holder, index,
    600                                     backing_store, filter);
    601   }
    602 
    603   static bool HasElementImpl(Isolate* isolate, Handle<JSObject> holder,
    604                              uint32_t index,
    605                              Handle<FixedArrayBase> backing_store,
    606                              PropertyFilter filter) {
    607     return Subclass::GetEntryForIndexImpl(isolate, *holder, *backing_store,
    608                                           index, filter) != kMaxUInt32;
    609   }
    610 
    611   bool HasAccessors(JSObject* holder) final {
    612     return Subclass::HasAccessorsImpl(holder, holder->elements());
    613   }
    614 
    615   static bool HasAccessorsImpl(JSObject* holder,
    616                                FixedArrayBase* backing_store) {
    617     return false;
    618   }
    619 
    620   Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final {
    621     return Subclass::GetImpl(holder, entry);
    622   }
    623 
    624   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
    625     return Subclass::GetImpl(holder->elements(), entry);
    626   }
    627 
    628   static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
    629     Isolate* isolate = backing_store->GetIsolate();
    630     uint32_t index = GetIndexForEntryImpl(backing_store, entry);
    631     return handle(BackingStore::cast(backing_store)->get(index), isolate);
    632   }
    633 
    634   void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final {
    635     Subclass::SetImpl(holder, entry, value);
    636   }
    637 
    638   void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
    639                    uint32_t entry, Handle<Object> value,
    640                    PropertyAttributes attributes) final {
    641     Subclass::ReconfigureImpl(object, store, entry, value, attributes);
    642   }
    643 
    644   static void ReconfigureImpl(Handle<JSObject> object,
    645                               Handle<FixedArrayBase> store, uint32_t entry,
    646                               Handle<Object> value,
    647                               PropertyAttributes attributes) {
    648     UNREACHABLE();
    649   }
    650 
    651   void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
    652            PropertyAttributes attributes, uint32_t new_capacity) final {
    653     Subclass::AddImpl(object, index, value, attributes, new_capacity);
    654   }
    655 
    656   static void AddImpl(Handle<JSObject> object, uint32_t index,
    657                       Handle<Object> value, PropertyAttributes attributes,
    658                       uint32_t new_capacity) {
    659     UNREACHABLE();
    660   }
    661 
    662   uint32_t Push(Handle<JSArray> receiver, Arguments* args,
    663                 uint32_t push_size) final {
    664     return Subclass::PushImpl(receiver, args, push_size);
    665   }
    666 
    667   static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args,
    668                            uint32_t push_sized) {
    669     UNREACHABLE();
    670     return 0;
    671   }
    672 
    673   uint32_t Unshift(Handle<JSArray> receiver, Arguments* args,
    674                    uint32_t unshift_size) final {
    675     return Subclass::UnshiftImpl(receiver, args, unshift_size);
    676   }
    677 
    678   static uint32_t UnshiftImpl(Handle<JSArray> receiver, Arguments* args,
    679                               uint32_t unshift_size) {
    680     UNREACHABLE();
    681     return 0;
    682   }
    683 
    684   Handle<JSArray> Slice(Handle<JSObject> receiver, uint32_t start,
    685                         uint32_t end) final {
    686     return Subclass::SliceImpl(receiver, start, end);
    687   }
    688 
    689   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
    690                                    uint32_t start, uint32_t end) {
    691     UNREACHABLE();
    692     return Handle<JSArray>();
    693   }
    694 
    695   Handle<JSArray> Splice(Handle<JSArray> receiver, uint32_t start,
    696                          uint32_t delete_count, Arguments* args,
    697                          uint32_t add_count) final {
    698     return Subclass::SpliceImpl(receiver, start, delete_count, args, add_count);
    699   }
    700 
    701   static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
    702                                     uint32_t start, uint32_t delete_count,
    703                                     Arguments* args, uint32_t add_count) {
    704     UNREACHABLE();
    705     return Handle<JSArray>();
    706   }
    707 
    708   Handle<Object> Pop(Handle<JSArray> receiver) final {
    709     return Subclass::PopImpl(receiver);
    710   }
    711 
    712   static Handle<Object> PopImpl(Handle<JSArray> receiver) {
    713     UNREACHABLE();
    714     return Handle<Object>();
    715   }
    716 
    717   Handle<Object> Shift(Handle<JSArray> receiver) final {
    718     return Subclass::ShiftImpl(receiver);
    719   }
    720 
    721   static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
    722     UNREACHABLE();
    723     return Handle<Object>();
    724   }
    725 
    726   void SetLength(Handle<JSArray> array, uint32_t length) final {
    727     Subclass::SetLengthImpl(array->GetIsolate(), array, length,
    728                             handle(array->elements()));
    729   }
    730 
    731   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
    732                             uint32_t length,
    733                             Handle<FixedArrayBase> backing_store) {
    734     DCHECK(!array->SetLengthWouldNormalize(length));
    735     DCHECK(IsFastElementsKind(array->GetElementsKind()));
    736     uint32_t old_length = 0;
    737     CHECK(array->length()->ToArrayIndex(&old_length));
    738 
    739     if (old_length < length) {
    740       ElementsKind kind = array->GetElementsKind();
    741       if (!IsFastHoleyElementsKind(kind)) {
    742         kind = GetHoleyElementsKind(kind);
    743         JSObject::TransitionElementsKind(array, kind);
    744       }
    745     }
    746 
    747     // Check whether the backing store should be shrunk.
    748     uint32_t capacity = backing_store->length();
    749     old_length = Min(old_length, capacity);
    750     if (length == 0) {
    751       array->initialize_elements();
    752     } else if (length <= capacity) {
    753       if (IsFastSmiOrObjectElementsKind(kind())) {
    754         JSObject::EnsureWritableFastElements(array);
    755         if (array->elements() != *backing_store) {
    756           backing_store = handle(array->elements(), isolate);
    757         }
    758       }
    759       if (2 * length <= capacity) {
    760         // If more than half the elements won't be used, trim the array.
    761         isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
    762             *backing_store, capacity - length);
    763       } else {
    764         // Otherwise, fill the unused tail with holes.
    765         for (uint32_t i = length; i < old_length; i++) {
    766           BackingStore::cast(*backing_store)->set_the_hole(i);
    767         }
    768       }
    769     } else {
    770       // Check whether the backing store should be expanded.
    771       capacity = Max(length, JSObject::NewElementsCapacity(capacity));
    772       Subclass::GrowCapacityAndConvertImpl(array, capacity);
    773     }
    774 
    775     array->set_length(Smi::FromInt(length));
    776     JSObject::ValidateElements(array);
    777   }
    778 
    779   uint32_t NumberOfElements(JSObject* receiver) final {
    780     return Subclass::NumberOfElementsImpl(receiver, receiver->elements());
    781   }
    782 
    783   static uint32_t NumberOfElementsImpl(JSObject* receiver,
    784                                        FixedArrayBase* backing_store) {
    785     UNREACHABLE();
    786   }
    787 
    788   static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase* elements) {
    789     if (receiver->IsJSArray()) {
    790       DCHECK(JSArray::cast(receiver)->length()->IsSmi());
    791       return static_cast<uint32_t>(
    792           Smi::cast(JSArray::cast(receiver)->length())->value());
    793     }
    794     return Subclass::GetCapacityImpl(receiver, elements);
    795   }
    796 
    797   static uint32_t GetMaxNumberOfEntries(JSObject* receiver,
    798                                         FixedArrayBase* elements) {
    799     return Subclass::GetMaxIndex(receiver, elements);
    800   }
    801 
    802   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
    803       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
    804       ElementsKind from_kind, uint32_t capacity) {
    805     return ConvertElementsWithCapacity(
    806         object, old_elements, from_kind, capacity, 0, 0,
    807         ElementsAccessor::kCopyToEndAndInitializeToHole);
    808   }
    809 
    810   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
    811       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
    812       ElementsKind from_kind, uint32_t capacity, int copy_size) {
    813     return ConvertElementsWithCapacity(object, old_elements, from_kind,
    814                                        capacity, 0, 0, copy_size);
    815   }
    816 
    817   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
    818       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
    819       ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
    820       uint32_t dst_index, int copy_size) {
    821     Isolate* isolate = object->GetIsolate();
    822     Handle<FixedArrayBase> new_elements;
    823     if (IsFastDoubleElementsKind(kind())) {
    824       new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
    825     } else {
    826       new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
    827     }
    828 
    829     int packed_size = kPackedSizeNotKnown;
    830     if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
    831       packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
    832     }
    833 
    834     Subclass::CopyElementsImpl(*old_elements, src_index, *new_elements,
    835                                from_kind, dst_index, packed_size, copy_size);
    836 
    837     return new_elements;
    838   }
    839 
    840   static void TransitionElementsKindImpl(Handle<JSObject> object,
    841                                          Handle<Map> to_map) {
    842     Handle<Map> from_map = handle(object->map());
    843     ElementsKind from_kind = from_map->elements_kind();
    844     ElementsKind to_kind = to_map->elements_kind();
    845     if (IsFastHoleyElementsKind(from_kind)) {
    846       to_kind = GetHoleyElementsKind(to_kind);
    847     }
    848     if (from_kind != to_kind) {
    849       // This method should never be called for any other case.
    850       DCHECK(IsFastElementsKind(from_kind));
    851       DCHECK(IsFastElementsKind(to_kind));
    852       DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
    853 
    854       Handle<FixedArrayBase> from_elements(object->elements());
    855       if (object->elements() == object->GetHeap()->empty_fixed_array() ||
    856           IsFastDoubleElementsKind(from_kind) ==
    857               IsFastDoubleElementsKind(to_kind)) {
    858         // No change is needed to the elements() buffer, the transition
    859         // only requires a map change.
    860         JSObject::MigrateToMap(object, to_map);
    861       } else {
    862         DCHECK((IsFastSmiElementsKind(from_kind) &&
    863                 IsFastDoubleElementsKind(to_kind)) ||
    864                (IsFastDoubleElementsKind(from_kind) &&
    865                 IsFastObjectElementsKind(to_kind)));
    866         uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
    867         Handle<FixedArrayBase> elements = ConvertElementsWithCapacity(
    868             object, from_elements, from_kind, capacity);
    869         JSObject::SetMapAndElements(object, to_map, elements);
    870       }
    871       if (FLAG_trace_elements_transitions) {
    872         JSObject::PrintElementsTransition(stdout, object, from_kind,
    873                                           from_elements, to_kind,
    874                                           handle(object->elements()));
    875       }
    876     }
    877   }
    878 
    879   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
    880                                          uint32_t capacity) {
    881     ElementsKind from_kind = object->GetElementsKind();
    882     if (IsFastSmiOrObjectElementsKind(from_kind)) {
    883       // Array optimizations rely on the prototype lookups of Array objects
    884       // always returning undefined. If there is a store to the initial
    885       // prototype object, make sure all of these optimizations are invalidated.
    886       object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
    887     }
    888     Handle<FixedArrayBase> old_elements(object->elements());
    889     // This method should only be called if there's a reason to update the
    890     // elements.
    891     DCHECK(IsFastDoubleElementsKind(from_kind) !=
    892                IsFastDoubleElementsKind(kind()) ||
    893            IsDictionaryElementsKind(from_kind) ||
    894            static_cast<uint32_t>(old_elements->length()) < capacity);
    895     Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
    896                                               kind(), capacity);
    897   }
    898 
    899   static void BasicGrowCapacityAndConvertImpl(
    900       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
    901       ElementsKind from_kind, ElementsKind to_kind, uint32_t capacity) {
    902     Handle<FixedArrayBase> elements =
    903         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
    904 
    905     if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
    906     Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
    907     JSObject::SetMapAndElements(object, new_map, elements);
    908 
    909     // Transition through the allocation site as well if present.
    910     JSObject::UpdateAllocationSite(object, to_kind);
    911 
    912     if (FLAG_trace_elements_transitions) {
    913       JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
    914                                         to_kind, elements);
    915     }
    916   }
    917 
    918   void TransitionElementsKind(Handle<JSObject> object, Handle<Map> map) final {
    919     Subclass::TransitionElementsKindImpl(object, map);
    920   }
    921 
    922   void GrowCapacityAndConvert(Handle<JSObject> object,
    923                               uint32_t capacity) final {
    924     Subclass::GrowCapacityAndConvertImpl(object, capacity);
    925   }
    926 
    927   bool GrowCapacity(Handle<JSObject> object, uint32_t index) final {
    928     // This function is intended to be called from optimized code. We don't
    929     // want to trigger lazy deopts there, so refuse to handle cases that would.
    930     if (object->map()->is_prototype_map() ||
    931         object->WouldConvertToSlowElements(index)) {
    932       return false;
    933     }
    934     Handle<FixedArrayBase> old_elements(object->elements());
    935     uint32_t new_capacity = JSObject::NewElementsCapacity(index + 1);
    936     DCHECK(static_cast<uint32_t>(old_elements->length()) < new_capacity);
    937     Handle<FixedArrayBase> elements =
    938         ConvertElementsWithCapacity(object, old_elements, kind(), new_capacity);
    939 
    940     DCHECK_EQ(object->GetElementsKind(), kind());
    941     // Transition through the allocation site as well if present.
    942     if (JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
    943             object, kind())) {
    944       return false;
    945     }
    946 
    947     object->set_elements(*elements);
    948     return true;
    949   }
    950 
    951   void Delete(Handle<JSObject> obj, uint32_t entry) final {
    952     Subclass::DeleteImpl(obj, entry);
    953   }
    954 
    955   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
    956                                FixedArrayBase* to, ElementsKind from_kind,
    957                                uint32_t to_start, int packed_size,
    958                                int copy_size) {
    959     UNREACHABLE();
    960   }
    961 
    962   void CopyElements(JSObject* from_holder, uint32_t from_start,
    963                     ElementsKind from_kind, Handle<FixedArrayBase> to,
    964                     uint32_t to_start, int copy_size) final {
    965     int packed_size = kPackedSizeNotKnown;
    966     bool is_packed = IsFastPackedElementsKind(from_kind) &&
    967         from_holder->IsJSArray();
    968     if (is_packed) {
    969       packed_size =
    970           Smi::cast(JSArray::cast(from_holder)->length())->value();
    971       if (copy_size >= 0 && packed_size > copy_size) {
    972         packed_size = copy_size;
    973       }
    974     }
    975     FixedArrayBase* from = from_holder->elements();
    976     // NOTE: the Subclass::CopyElementsImpl() methods
    977     // violate the handlified function signature convention:
    978     // raw pointer parameters in the function that allocates. This is done
    979     // intentionally to avoid ArrayConcat() builtin performance degradation.
    980     //
    981     // Details: The idea is that allocations actually happen only in case of
    982     // copying from object with fast double elements to object with object
    983     // elements. In all the other cases there are no allocations performed and
    984     // handle creation causes noticeable performance degradation of the builtin.
    985     Subclass::CopyElementsImpl(from, from_start, *to, from_kind, to_start,
    986                                packed_size, copy_size);
    987   }
    988 
    989   void CopyElements(Handle<FixedArrayBase> source, ElementsKind source_kind,
    990                     Handle<FixedArrayBase> destination, int size) {
    991     Subclass::CopyElementsImpl(*source, 0, *destination, source_kind, 0,
    992                                kPackedSizeNotKnown, size);
    993   }
    994 
    995   Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final {
    996     return Subclass::NormalizeImpl(object, handle(object->elements()));
    997   }
    998 
    999   static Handle<SeededNumberDictionary> NormalizeImpl(
   1000       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
   1001     UNREACHABLE();
   1002     return Handle<SeededNumberDictionary>();
   1003   }
   1004 
   1005   Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject> object,
   1006                                      Handle<FixedArray> values_or_entries,
   1007                                      bool get_entries, int* nof_items,
   1008                                      PropertyFilter filter) {
   1009     return Subclass::CollectValuesOrEntriesImpl(
   1010         isolate, object, values_or_entries, get_entries, nof_items, filter);
   1011   }
   1012 
   1013   static Maybe<bool> CollectValuesOrEntriesImpl(
   1014       Isolate* isolate, Handle<JSObject> object,
   1015       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
   1016       PropertyFilter filter) {
   1017     int count = 0;
   1018     KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
   1019                                ALL_PROPERTIES);
   1020     Subclass::CollectElementIndicesImpl(
   1021         object, handle(object->elements(), isolate), &accumulator);
   1022     Handle<FixedArray> keys = accumulator.GetKeys();
   1023 
   1024     for (int i = 0; i < keys->length(); ++i) {
   1025       Handle<Object> key(keys->get(i), isolate);
   1026       Handle<Object> value;
   1027       uint32_t index;
   1028       if (!key->ToUint32(&index)) continue;
   1029 
   1030       uint32_t entry = Subclass::GetEntryForIndexImpl(
   1031           isolate, *object, object->elements(), index, filter);
   1032       if (entry == kMaxUInt32) continue;
   1033 
   1034       PropertyDetails details = Subclass::GetDetailsImpl(*object, entry);
   1035 
   1036       if (details.kind() == kData) {
   1037         value = Subclass::GetImpl(object, entry);
   1038       } else {
   1039         LookupIterator it(isolate, object, index, LookupIterator::OWN);
   1040         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1041             isolate, value, Object::GetProperty(&it), Nothing<bool>());
   1042       }
   1043       if (get_entries) {
   1044         value = MakeEntryPair(isolate, index, value);
   1045       }
   1046       values_or_entries->set(count++, *value);
   1047     }
   1048 
   1049     *nof_items = count;
   1050     return Just(true);
   1051   }
   1052 
   1053   void CollectElementIndices(Handle<JSObject> object,
   1054                              Handle<FixedArrayBase> backing_store,
   1055                              KeyAccumulator* keys) final {
   1056     if (keys->filter() & ONLY_ALL_CAN_READ) return;
   1057     Subclass::CollectElementIndicesImpl(object, backing_store, keys);
   1058   }
   1059 
   1060   static void CollectElementIndicesImpl(Handle<JSObject> object,
   1061                                         Handle<FixedArrayBase> backing_store,
   1062                                         KeyAccumulator* keys) {
   1063     DCHECK_NE(DICTIONARY_ELEMENTS, kind());
   1064     // Non-dictionary elements can't have all-can-read accessors.
   1065     uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
   1066     PropertyFilter filter = keys->filter();
   1067     Isolate* isolate = keys->isolate();
   1068     Factory* factory = isolate->factory();
   1069     for (uint32_t i = 0; i < length; i++) {
   1070       if (Subclass::HasElementImpl(isolate, object, i, backing_store, filter)) {
   1071         keys->AddKey(factory->NewNumberFromUint(i));
   1072       }
   1073     }
   1074   }
   1075 
   1076   static Handle<FixedArray> DirectCollectElementIndicesImpl(
   1077       Isolate* isolate, Handle<JSObject> object,
   1078       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
   1079       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
   1080       uint32_t insertion_index = 0) {
   1081     uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
   1082     for (uint32_t i = 0; i < length; i++) {
   1083       if (Subclass::HasElementImpl(isolate, object, i, backing_store, filter)) {
   1084         if (convert == GetKeysConversion::kConvertToString) {
   1085           Handle<String> index_string = isolate->factory()->Uint32ToString(i);
   1086           list->set(insertion_index, *index_string);
   1087         } else {
   1088           list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
   1089         }
   1090         insertion_index++;
   1091       }
   1092     }
   1093     *nof_indices = insertion_index;
   1094     return list;
   1095   }
   1096 
   1097   MaybeHandle<FixedArray> PrependElementIndices(
   1098       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
   1099       Handle<FixedArray> keys, GetKeysConversion convert,
   1100       PropertyFilter filter) final {
   1101     return Subclass::PrependElementIndicesImpl(object, backing_store, keys,
   1102                                                convert, filter);
   1103   }
   1104 
   1105   static MaybeHandle<FixedArray> PrependElementIndicesImpl(
   1106       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
   1107       Handle<FixedArray> keys, GetKeysConversion convert,
   1108       PropertyFilter filter) {
   1109     Isolate* isolate = object->GetIsolate();
   1110     uint32_t nof_property_keys = keys->length();
   1111     uint32_t initial_list_length =
   1112         Subclass::GetMaxNumberOfEntries(*object, *backing_store);
   1113 
   1114     initial_list_length += nof_property_keys;
   1115     if (initial_list_length > FixedArray::kMaxLength ||
   1116         initial_list_length < nof_property_keys) {
   1117       return isolate->Throw<FixedArray>(isolate->factory()->NewRangeError(
   1118           MessageTemplate::kInvalidArrayLength));
   1119     }
   1120 
   1121     // Collect the element indices into a new list.
   1122     MaybeHandle<FixedArray> raw_array =
   1123         isolate->factory()->TryNewFixedArray(initial_list_length);
   1124     Handle<FixedArray> combined_keys;
   1125 
   1126     // If we have a holey backing store try to precisely estimate the backing
   1127     // store size as a last emergency measure if we cannot allocate the big
   1128     // array.
   1129     if (!raw_array.ToHandle(&combined_keys)) {
   1130       if (IsHoleyElementsKind(kind())) {
   1131         // If we overestimate the result list size we might end up in the
   1132         // large-object space which doesn't free memory on shrinking the list.
   1133         // Hence we try to estimate the final size for holey backing stores more
   1134         // precisely here.
   1135         initial_list_length =
   1136             Subclass::NumberOfElementsImpl(*object, *backing_store);
   1137         initial_list_length += nof_property_keys;
   1138       }
   1139       combined_keys = isolate->factory()->NewFixedArray(initial_list_length);
   1140     }
   1141 
   1142     uint32_t nof_indices = 0;
   1143     bool needs_sorting =
   1144         IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind());
   1145     combined_keys = Subclass::DirectCollectElementIndicesImpl(
   1146         isolate, object, backing_store,
   1147         needs_sorting ? GetKeysConversion::kKeepNumbers : convert, filter,
   1148         combined_keys, &nof_indices);
   1149 
   1150     if (needs_sorting) {
   1151       SortIndices(combined_keys, nof_indices);
   1152       // Indices from dictionary elements should only be converted after
   1153       // sorting.
   1154       if (convert == GetKeysConversion::kConvertToString) {
   1155         for (uint32_t i = 0; i < nof_indices; i++) {
   1156           Handle<Object> index_string = isolate->factory()->Uint32ToString(
   1157               combined_keys->get(i)->Number());
   1158           combined_keys->set(i, *index_string);
   1159         }
   1160       }
   1161     }
   1162 
   1163     // Copy over the passed-in property keys.
   1164     CopyObjectToObjectElements(*keys, FAST_ELEMENTS, 0, *combined_keys,
   1165                                FAST_ELEMENTS, nof_indices, nof_property_keys);
   1166 
   1167     // For holey elements and arguments we might have to shrink the collected
   1168     // keys since the estimates might be off.
   1169     if (IsHoleyElementsKind(kind()) || IsSloppyArgumentsElements(kind())) {
   1170       // Shrink combined_keys to the final size.
   1171       int final_size = nof_indices + nof_property_keys;
   1172       DCHECK_LE(final_size, combined_keys->length());
   1173       combined_keys->Shrink(final_size);
   1174     }
   1175 
   1176     return combined_keys;
   1177   }
   1178 
   1179   void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
   1180                                    KeyAccumulator* accumulator,
   1181                                    AddKeyConversion convert) final {
   1182     Subclass::AddElementsToKeyAccumulatorImpl(receiver, accumulator, convert);
   1183   }
   1184 
   1185   static uint32_t GetCapacityImpl(JSObject* holder,
   1186                                   FixedArrayBase* backing_store) {
   1187     return backing_store->length();
   1188   }
   1189 
   1190   uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
   1191     return Subclass::GetCapacityImpl(holder, backing_store);
   1192   }
   1193 
   1194   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
   1195                                        Handle<JSObject> receiver,
   1196                                        Handle<Object> value,
   1197                                        uint32_t start_from, uint32_t length) {
   1198     return IncludesValueSlowPath(isolate, receiver, value, start_from, length);
   1199   }
   1200 
   1201   Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
   1202                             Handle<Object> value, uint32_t start_from,
   1203                             uint32_t length) final {
   1204     return Subclass::IncludesValueImpl(isolate, receiver, value, start_from,
   1205                                        length);
   1206   }
   1207 
   1208   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
   1209                                          Handle<JSObject> receiver,
   1210                                          Handle<Object> value,
   1211                                          uint32_t start_from, uint32_t length) {
   1212     return IndexOfValueSlowPath(isolate, receiver, value, start_from, length);
   1213   }
   1214 
   1215   Maybe<int64_t> IndexOfValue(Isolate* isolate, Handle<JSObject> receiver,
   1216                               Handle<Object> value, uint32_t start_from,
   1217                               uint32_t length) final {
   1218     return Subclass::IndexOfValueImpl(isolate, receiver, value, start_from,
   1219                                       length);
   1220   }
   1221 
   1222   static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
   1223                                        uint32_t entry) {
   1224     return entry;
   1225   }
   1226 
   1227   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
   1228                                        FixedArrayBase* backing_store,
   1229                                        uint32_t index, PropertyFilter filter) {
   1230     uint32_t length = Subclass::GetMaxIndex(holder, backing_store);
   1231     if (IsHoleyElementsKind(kind())) {
   1232       return index < length &&
   1233                      !BackingStore::cast(backing_store)
   1234                           ->is_the_hole(isolate, index)
   1235                  ? index
   1236                  : kMaxUInt32;
   1237     } else {
   1238       return index < length ? index : kMaxUInt32;
   1239     }
   1240   }
   1241 
   1242   uint32_t GetEntryForIndex(Isolate* isolate, JSObject* holder,
   1243                             FixedArrayBase* backing_store,
   1244                             uint32_t index) final {
   1245     return Subclass::GetEntryForIndexImpl(isolate, holder, backing_store, index,
   1246                                           ALL_PROPERTIES);
   1247   }
   1248 
   1249   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
   1250                                         uint32_t entry) {
   1251     return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
   1252   }
   1253 
   1254   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
   1255     return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
   1256   }
   1257 
   1258   PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final {
   1259     return Subclass::GetDetailsImpl(holder, entry);
   1260   }
   1261 
   1262  private:
   1263   DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
   1264 };
   1265 
   1266 
   1267 class DictionaryElementsAccessor
   1268     : public ElementsAccessorBase<DictionaryElementsAccessor,
   1269                                   ElementsKindTraits<DICTIONARY_ELEMENTS> > {
   1270  public:
   1271   explicit DictionaryElementsAccessor(const char* name)
   1272       : ElementsAccessorBase<DictionaryElementsAccessor,
   1273                              ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
   1274 
   1275   static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase* elements) {
   1276     // We cannot properly estimate this for dictionaries.
   1277     UNREACHABLE();
   1278   }
   1279 
   1280   static uint32_t GetMaxNumberOfEntries(JSObject* receiver,
   1281                                         FixedArrayBase* backing_store) {
   1282     return NumberOfElementsImpl(receiver, backing_store);
   1283   }
   1284 
   1285   static uint32_t NumberOfElementsImpl(JSObject* receiver,
   1286                                        FixedArrayBase* backing_store) {
   1287     SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
   1288     return dict->NumberOfElements();
   1289   }
   1290 
   1291   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
   1292                             uint32_t length,
   1293                             Handle<FixedArrayBase> backing_store) {
   1294     Handle<SeededNumberDictionary> dict =
   1295         Handle<SeededNumberDictionary>::cast(backing_store);
   1296     int capacity = dict->Capacity();
   1297     uint32_t old_length = 0;
   1298     CHECK(array->length()->ToArrayLength(&old_length));
   1299     if (length < old_length) {
   1300       if (dict->requires_slow_elements()) {
   1301         // Find last non-deletable element in range of elements to be
   1302         // deleted and adjust range accordingly.
   1303         for (int entry = 0; entry < capacity; entry++) {
   1304           DisallowHeapAllocation no_gc;
   1305           Object* index = dict->KeyAt(entry);
   1306           if (index->IsNumber()) {
   1307             uint32_t number = static_cast<uint32_t>(index->Number());
   1308             if (length <= number && number < old_length) {
   1309               PropertyDetails details = dict->DetailsAt(entry);
   1310               if (!details.IsConfigurable()) length = number + 1;
   1311             }
   1312           }
   1313         }
   1314       }
   1315 
   1316       if (length == 0) {
   1317         // Flush the backing store.
   1318         JSObject::ResetElements(array);
   1319       } else {
   1320         DisallowHeapAllocation no_gc;
   1321         // Remove elements that should be deleted.
   1322         int removed_entries = 0;
   1323         Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
   1324         for (int entry = 0; entry < capacity; entry++) {
   1325           Object* index = dict->KeyAt(entry);
   1326           if (index->IsNumber()) {
   1327             uint32_t number = static_cast<uint32_t>(index->Number());
   1328             if (length <= number && number < old_length) {
   1329               dict->SetEntry(entry, the_hole_value, the_hole_value);
   1330               removed_entries++;
   1331             }
   1332           }
   1333         }
   1334 
   1335         // Update the number of elements.
   1336         dict->ElementsRemoved(removed_entries);
   1337       }
   1338     }
   1339 
   1340     Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
   1341     array->set_length(*length_obj);
   1342   }
   1343 
   1344   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   1345                                FixedArrayBase* to, ElementsKind from_kind,
   1346                                uint32_t to_start, int packed_size,
   1347                                int copy_size) {
   1348     UNREACHABLE();
   1349   }
   1350 
   1351 
   1352   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
   1353     // TODO(verwaest): Remove reliance on index in Shrink.
   1354     Handle<SeededNumberDictionary> dict(
   1355         SeededNumberDictionary::cast(obj->elements()));
   1356     uint32_t index = GetIndexForEntryImpl(*dict, entry);
   1357     Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
   1358     USE(result);
   1359     DCHECK(result->IsTrue(dict->GetIsolate()));
   1360     Handle<FixedArray> new_elements =
   1361         SeededNumberDictionary::Shrink(dict, index);
   1362     obj->set_elements(*new_elements);
   1363   }
   1364 
   1365   static bool HasAccessorsImpl(JSObject* holder,
   1366                                FixedArrayBase* backing_store) {
   1367     DisallowHeapAllocation no_gc;
   1368     SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
   1369     if (!dict->requires_slow_elements()) return false;
   1370     int capacity = dict->Capacity();
   1371     Isolate* isolate = dict->GetIsolate();
   1372     for (int i = 0; i < capacity; i++) {
   1373       Object* key = dict->KeyAt(i);
   1374       if (!dict->IsKey(isolate, key)) continue;
   1375       DCHECK(!dict->IsDeleted(i));
   1376       PropertyDetails details = dict->DetailsAt(i);
   1377       if (details.type() == ACCESSOR_CONSTANT) return true;
   1378     }
   1379     return false;
   1380   }
   1381 
   1382   static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
   1383     SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
   1384     return backing_store->ValueAt(entry);
   1385   }
   1386 
   1387   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
   1388     return GetImpl(holder->elements(), entry);
   1389   }
   1390 
   1391   static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
   1392     return handle(GetRaw(backing_store, entry), backing_store->GetIsolate());
   1393   }
   1394 
   1395   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
   1396                              Object* value) {
   1397     SetImpl(holder->elements(), entry, value);
   1398   }
   1399 
   1400   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   1401                              Object* value) {
   1402     SeededNumberDictionary::cast(backing_store)->ValueAtPut(entry, value);
   1403   }
   1404 
   1405   static void ReconfigureImpl(Handle<JSObject> object,
   1406                               Handle<FixedArrayBase> store, uint32_t entry,
   1407                               Handle<Object> value,
   1408                               PropertyAttributes attributes) {
   1409     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
   1410     if (attributes != NONE) object->RequireSlowElements(dictionary);
   1411     dictionary->ValueAtPut(entry, *value);
   1412     PropertyDetails details = dictionary->DetailsAt(entry);
   1413     details = PropertyDetails(attributes, DATA, details.dictionary_index(),
   1414                               PropertyCellType::kNoCell);
   1415     dictionary->DetailsAtPut(entry, details);
   1416   }
   1417 
   1418   static void AddImpl(Handle<JSObject> object, uint32_t index,
   1419                       Handle<Object> value, PropertyAttributes attributes,
   1420                       uint32_t new_capacity) {
   1421     PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
   1422     Handle<SeededNumberDictionary> dictionary =
   1423         object->HasFastElements() || object->HasFastStringWrapperElements()
   1424             ? JSObject::NormalizeElements(object)
   1425             : handle(SeededNumberDictionary::cast(object->elements()));
   1426     Handle<SeededNumberDictionary> new_dictionary =
   1427         SeededNumberDictionary::AddNumberEntry(
   1428             dictionary, index, value, details,
   1429             object->map()->is_prototype_map());
   1430     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
   1431     if (dictionary.is_identical_to(new_dictionary)) return;
   1432     object->set_elements(*new_dictionary);
   1433   }
   1434 
   1435   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* store,
   1436                            uint32_t entry) {
   1437     DisallowHeapAllocation no_gc;
   1438     SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
   1439     Object* index = dict->KeyAt(entry);
   1440     return !index->IsTheHole(isolate);
   1441   }
   1442 
   1443   static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
   1444     DisallowHeapAllocation no_gc;
   1445     SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
   1446     uint32_t result = 0;
   1447     CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
   1448     return result;
   1449   }
   1450 
   1451   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
   1452                                        FixedArrayBase* store, uint32_t index,
   1453                                        PropertyFilter filter) {
   1454     DisallowHeapAllocation no_gc;
   1455     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
   1456     int entry = dictionary->FindEntry(isolate, index);
   1457     if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
   1458     if (filter != ALL_PROPERTIES) {
   1459       PropertyDetails details = dictionary->DetailsAt(entry);
   1460       PropertyAttributes attr = details.attributes();
   1461       if ((attr & filter) != 0) return kMaxUInt32;
   1462     }
   1463     return static_cast<uint32_t>(entry);
   1464   }
   1465 
   1466   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
   1467     return GetDetailsImpl(holder->elements(), entry);
   1468   }
   1469 
   1470   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
   1471                                         uint32_t entry) {
   1472     return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
   1473   }
   1474 
   1475   static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary,
   1476                             int entry, Object* raw_key, PropertyFilter filter) {
   1477     DCHECK(!dictionary->IsDeleted(entry));
   1478     DCHECK(raw_key->IsNumber());
   1479     DCHECK_LE(raw_key->Number(), kMaxUInt32);
   1480     PropertyDetails details = dictionary->DetailsAt(entry);
   1481     PropertyAttributes attr = details.attributes();
   1482     if ((attr & filter) != 0) return kMaxUInt32;
   1483     return static_cast<uint32_t>(raw_key->Number());
   1484   }
   1485 
   1486   static uint32_t GetKeyForEntryImpl(Isolate* isolate,
   1487                                      Handle<SeededNumberDictionary> dictionary,
   1488                                      int entry, PropertyFilter filter) {
   1489     DisallowHeapAllocation no_gc;
   1490     Object* raw_key = dictionary->KeyAt(entry);
   1491     if (!dictionary->IsKey(isolate, raw_key)) return kMaxUInt32;
   1492     return FilterKey(dictionary, entry, raw_key, filter);
   1493   }
   1494 
   1495   static void CollectElementIndicesImpl(Handle<JSObject> object,
   1496                                         Handle<FixedArrayBase> backing_store,
   1497                                         KeyAccumulator* keys) {
   1498     if (keys->filter() & SKIP_STRINGS) return;
   1499     Isolate* isolate = keys->isolate();
   1500     Handle<SeededNumberDictionary> dictionary =
   1501         Handle<SeededNumberDictionary>::cast(backing_store);
   1502     int capacity = dictionary->Capacity();
   1503     Handle<FixedArray> elements = isolate->factory()->NewFixedArray(
   1504         GetMaxNumberOfEntries(*object, *backing_store));
   1505     int insertion_index = 0;
   1506     PropertyFilter filter = keys->filter();
   1507     for (int i = 0; i < capacity; i++) {
   1508       Object* raw_key = dictionary->KeyAt(i);
   1509       if (!dictionary->IsKey(isolate, raw_key)) continue;
   1510       uint32_t key = FilterKey(dictionary, i, raw_key, filter);
   1511       if (key == kMaxUInt32) {
   1512         keys->AddShadowingKey(raw_key);
   1513         continue;
   1514       }
   1515       elements->set(insertion_index, raw_key);
   1516       insertion_index++;
   1517     }
   1518     SortIndices(elements, insertion_index);
   1519     for (int i = 0; i < insertion_index; i++) {
   1520       keys->AddKey(elements->get(i));
   1521     }
   1522   }
   1523 
   1524   static Handle<FixedArray> DirectCollectElementIndicesImpl(
   1525       Isolate* isolate, Handle<JSObject> object,
   1526       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
   1527       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
   1528       uint32_t insertion_index = 0) {
   1529     if (filter & SKIP_STRINGS) return list;
   1530     if (filter & ONLY_ALL_CAN_READ) return list;
   1531 
   1532     Handle<SeededNumberDictionary> dictionary =
   1533         Handle<SeededNumberDictionary>::cast(backing_store);
   1534     uint32_t capacity = dictionary->Capacity();
   1535     for (uint32_t i = 0; i < capacity; i++) {
   1536       uint32_t key = GetKeyForEntryImpl(isolate, dictionary, i, filter);
   1537       if (key == kMaxUInt32) continue;
   1538       Handle<Object> index = isolate->factory()->NewNumberFromUint(key);
   1539       list->set(insertion_index, *index);
   1540       insertion_index++;
   1541     }
   1542     *nof_indices = insertion_index;
   1543     return list;
   1544   }
   1545 
   1546   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
   1547                                               KeyAccumulator* accumulator,
   1548                                               AddKeyConversion convert) {
   1549     Isolate* isolate = accumulator->isolate();
   1550     Handle<Object> undefined = isolate->factory()->undefined_value();
   1551     Handle<Object> the_hole = isolate->factory()->the_hole_value();
   1552     Handle<SeededNumberDictionary> dictionary(
   1553         SeededNumberDictionary::cast(receiver->elements()), isolate);
   1554     int capacity = dictionary->Capacity();
   1555     for (int i = 0; i < capacity; i++) {
   1556       Object* k = dictionary->KeyAt(i);
   1557       if (k == *undefined) continue;
   1558       if (k == *the_hole) continue;
   1559       if (dictionary->IsDeleted(i)) continue;
   1560       Object* value = dictionary->ValueAt(i);
   1561       DCHECK(!value->IsTheHole(isolate));
   1562       DCHECK(!value->IsAccessorPair());
   1563       DCHECK(!value->IsAccessorInfo());
   1564       accumulator->AddKey(value, convert);
   1565     }
   1566   }
   1567 
   1568   static bool IncludesValueFastPath(Isolate* isolate, Handle<JSObject> receiver,
   1569                                     Handle<Object> value, uint32_t start_from,
   1570                                     uint32_t length, Maybe<bool>* result) {
   1571     DisallowHeapAllocation no_gc;
   1572     SeededNumberDictionary* dictionary =
   1573         SeededNumberDictionary::cast(receiver->elements());
   1574     int capacity = dictionary->Capacity();
   1575     Object* the_hole = isolate->heap()->the_hole_value();
   1576     Object* undefined = isolate->heap()->undefined_value();
   1577 
   1578     // Scan for accessor properties. If accessors are present, then elements
   1579     // must be accessed in order via the slow path.
   1580     bool found = false;
   1581     for (int i = 0; i < capacity; ++i) {
   1582       Object* k = dictionary->KeyAt(i);
   1583       if (k == the_hole) continue;
   1584       if (k == undefined) continue;
   1585 
   1586       uint32_t index;
   1587       if (!k->ToArrayIndex(&index) || index < start_from || index >= length) {
   1588         continue;
   1589       }
   1590 
   1591       if (dictionary->DetailsAt(i).type() == ACCESSOR_CONSTANT) {
   1592         // Restart from beginning in slow path, otherwise we may observably
   1593         // access getters out of order
   1594         return false;
   1595       } else if (!found) {
   1596         Object* element_k = dictionary->ValueAt(i);
   1597         if (value->SameValueZero(element_k)) found = true;
   1598       }
   1599     }
   1600 
   1601     *result = Just(found);
   1602     return true;
   1603   }
   1604 
   1605   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
   1606                                        Handle<JSObject> receiver,
   1607                                        Handle<Object> value,
   1608                                        uint32_t start_from, uint32_t length) {
   1609     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
   1610     bool search_for_hole = value->IsUndefined(isolate);
   1611 
   1612     if (!search_for_hole) {
   1613       Maybe<bool> result = Nothing<bool>();
   1614       if (DictionaryElementsAccessor::IncludesValueFastPath(
   1615               isolate, receiver, value, start_from, length, &result)) {
   1616         return result;
   1617       }
   1618     }
   1619 
   1620     Handle<SeededNumberDictionary> dictionary(
   1621         SeededNumberDictionary::cast(receiver->elements()), isolate);
   1622     // Iterate through entire range, as accessing elements out of order is
   1623     // observable
   1624     for (uint32_t k = start_from; k < length; ++k) {
   1625       int entry = dictionary->FindEntry(k);
   1626       if (entry == SeededNumberDictionary::kNotFound) {
   1627         if (search_for_hole) return Just(true);
   1628         continue;
   1629       }
   1630 
   1631       PropertyDetails details = GetDetailsImpl(*dictionary, entry);
   1632       switch (details.kind()) {
   1633         case kData: {
   1634           Object* element_k = dictionary->ValueAt(entry);
   1635           if (value->SameValueZero(element_k)) return Just(true);
   1636           break;
   1637         }
   1638         case kAccessor: {
   1639           LookupIterator it(isolate, receiver, k,
   1640                             LookupIterator::OWN_SKIP_INTERCEPTOR);
   1641           DCHECK(it.IsFound());
   1642           DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
   1643           Handle<Object> element_k;
   1644 
   1645           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1646               isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
   1647               Nothing<bool>());
   1648 
   1649           if (value->SameValueZero(*element_k)) return Just(true);
   1650 
   1651           // Bailout to slow path if elements on prototype changed
   1652           if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
   1653             return IncludesValueSlowPath(isolate, receiver, value, k + 1,
   1654                                          length);
   1655           }
   1656 
   1657           // Continue if elements unchanged
   1658           if (*dictionary == receiver->elements()) continue;
   1659 
   1660           // Otherwise, bailout or update elements
   1661           if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
   1662             if (receiver->map()->GetInitialElements() == receiver->elements()) {
   1663               // If switched to initial elements, return true if searching for
   1664               // undefined, and false otherwise.
   1665               return Just(search_for_hole);
   1666             }
   1667             // Otherwise, switch to slow path.
   1668             return IncludesValueSlowPath(isolate, receiver, value, k + 1,
   1669                                          length);
   1670           }
   1671           dictionary = handle(
   1672               SeededNumberDictionary::cast(receiver->elements()), isolate);
   1673           break;
   1674         }
   1675       }
   1676     }
   1677     return Just(false);
   1678   }
   1679 
   1680   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
   1681                                          Handle<JSObject> receiver,
   1682                                          Handle<Object> value,
   1683                                          uint32_t start_from, uint32_t length) {
   1684     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
   1685 
   1686     Handle<SeededNumberDictionary> dictionary(
   1687         SeededNumberDictionary::cast(receiver->elements()), isolate);
   1688     // Iterate through entire range, as accessing elements out of order is
   1689     // observable.
   1690     for (uint32_t k = start_from; k < length; ++k) {
   1691       int entry = dictionary->FindEntry(k);
   1692       if (entry == SeededNumberDictionary::kNotFound) {
   1693         continue;
   1694       }
   1695 
   1696       PropertyDetails details = GetDetailsImpl(*dictionary, entry);
   1697       switch (details.kind()) {
   1698         case kData: {
   1699           Object* element_k = dictionary->ValueAt(entry);
   1700           if (value->StrictEquals(element_k)) {
   1701             return Just<int64_t>(k);
   1702           }
   1703           break;
   1704         }
   1705         case kAccessor: {
   1706           LookupIterator it(isolate, receiver, k,
   1707                             LookupIterator::OWN_SKIP_INTERCEPTOR);
   1708           DCHECK(it.IsFound());
   1709           DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
   1710           Handle<Object> element_k;
   1711 
   1712           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1713               isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
   1714               Nothing<int64_t>());
   1715 
   1716           if (value->StrictEquals(*element_k)) return Just<int64_t>(k);
   1717 
   1718           // Bailout to slow path if elements on prototype changed.
   1719           if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
   1720             return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
   1721                                         length);
   1722           }
   1723 
   1724           // Continue if elements unchanged.
   1725           if (*dictionary == receiver->elements()) continue;
   1726 
   1727           // Otherwise, bailout or update elements.
   1728           if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
   1729             // Otherwise, switch to slow path.
   1730             return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
   1731                                         length);
   1732           }
   1733           dictionary = handle(
   1734               SeededNumberDictionary::cast(receiver->elements()), isolate);
   1735           break;
   1736         }
   1737       }
   1738     }
   1739     return Just<int64_t>(-1);
   1740   }
   1741 };
   1742 
   1743 
   1744 // Super class for all fast element arrays.
   1745 template <typename Subclass, typename KindTraits>
   1746 class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
   1747  public:
   1748   explicit FastElementsAccessor(const char* name)
   1749       : ElementsAccessorBase<Subclass, KindTraits>(name) {}
   1750 
   1751   typedef typename KindTraits::BackingStore BackingStore;
   1752 
   1753   static Handle<SeededNumberDictionary> NormalizeImpl(
   1754       Handle<JSObject> object, Handle<FixedArrayBase> store) {
   1755     Isolate* isolate = store->GetIsolate();
   1756     ElementsKind kind = Subclass::kind();
   1757 
   1758     // Ensure that notifications fire if the array or object prototypes are
   1759     // normalizing.
   1760     if (IsFastSmiOrObjectElementsKind(kind)) {
   1761       isolate->UpdateArrayProtectorOnNormalizeElements(object);
   1762     }
   1763 
   1764     int capacity = object->GetFastElementsUsage();
   1765     Handle<SeededNumberDictionary> dictionary =
   1766         SeededNumberDictionary::New(isolate, capacity);
   1767 
   1768     PropertyDetails details = PropertyDetails::Empty();
   1769     bool used_as_prototype = object->map()->is_prototype_map();
   1770     int j = 0;
   1771     for (int i = 0; j < capacity; i++) {
   1772       if (IsHoleyElementsKind(kind)) {
   1773         if (BackingStore::cast(*store)->is_the_hole(isolate, i)) continue;
   1774       }
   1775       Handle<Object> value = Subclass::GetImpl(*store, i);
   1776       dictionary = SeededNumberDictionary::AddNumberEntry(
   1777           dictionary, i, value, details, used_as_prototype);
   1778       j++;
   1779     }
   1780     return dictionary;
   1781   }
   1782 
   1783   static void DeleteAtEnd(Handle<JSObject> obj,
   1784                           Handle<BackingStore> backing_store, uint32_t entry) {
   1785     uint32_t length = static_cast<uint32_t>(backing_store->length());
   1786     Isolate* isolate = obj->GetIsolate();
   1787     for (; entry > 0; entry--) {
   1788       if (!backing_store->is_the_hole(isolate, entry - 1)) break;
   1789     }
   1790     if (entry == 0) {
   1791       FixedArray* empty = isolate->heap()->empty_fixed_array();
   1792       // Dynamically ask for the elements kind here since we manually redirect
   1793       // the operations for argument backing stores.
   1794       if (obj->GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
   1795         FixedArray::cast(obj->elements())->set(1, empty);
   1796       } else {
   1797         obj->set_elements(empty);
   1798       }
   1799       return;
   1800     }
   1801 
   1802     isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
   1803         *backing_store, length - entry);
   1804   }
   1805 
   1806   static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
   1807                            Handle<FixedArrayBase> store) {
   1808     DCHECK(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() ||
   1809            obj->HasFastArgumentsElements() ||
   1810            obj->HasFastStringWrapperElements());
   1811     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
   1812     if (!obj->IsJSArray() &&
   1813         entry == static_cast<uint32_t>(store->length()) - 1) {
   1814       DeleteAtEnd(obj, backing_store, entry);
   1815       return;
   1816     }
   1817 
   1818     Isolate* isolate = obj->GetIsolate();
   1819     backing_store->set_the_hole(entry);
   1820 
   1821     // TODO(verwaest): Move this out of elements.cc.
   1822     // If an old space backing store is larger than a certain size and
   1823     // has too few used values, normalize it.
   1824     // To avoid doing the check on every delete we require at least
   1825     // one adjacent hole to the value being deleted.
   1826     const int kMinLengthForSparsenessCheck = 64;
   1827     if (backing_store->length() < kMinLengthForSparsenessCheck) return;
   1828     if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
   1829     uint32_t length = 0;
   1830     if (obj->IsJSArray()) {
   1831       JSArray::cast(*obj)->length()->ToArrayLength(&length);
   1832     } else {
   1833       length = static_cast<uint32_t>(store->length());
   1834     }
   1835     if ((entry > 0 && backing_store->is_the_hole(isolate, entry - 1)) ||
   1836         (entry + 1 < length &&
   1837          backing_store->is_the_hole(isolate, entry + 1))) {
   1838       if (!obj->IsJSArray()) {
   1839         uint32_t i;
   1840         for (i = entry + 1; i < length; i++) {
   1841           if (!backing_store->is_the_hole(isolate, i)) break;
   1842         }
   1843         if (i == length) {
   1844           DeleteAtEnd(obj, backing_store, entry);
   1845           return;
   1846         }
   1847       }
   1848       int num_used = 0;
   1849       for (int i = 0; i < backing_store->length(); ++i) {
   1850         if (!backing_store->is_the_hole(isolate, i)) {
   1851           ++num_used;
   1852           // Bail out if a number dictionary wouldn't be able to save at least
   1853           // 75% space.
   1854           if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
   1855                   SeededNumberDictionary::kEntrySize >
   1856               backing_store->length()) {
   1857             return;
   1858           }
   1859         }
   1860       }
   1861       JSObject::NormalizeElements(obj);
   1862     }
   1863   }
   1864 
   1865   static void ReconfigureImpl(Handle<JSObject> object,
   1866                               Handle<FixedArrayBase> store, uint32_t entry,
   1867                               Handle<Object> value,
   1868                               PropertyAttributes attributes) {
   1869     Handle<SeededNumberDictionary> dictionary =
   1870         JSObject::NormalizeElements(object);
   1871     entry = dictionary->FindEntry(entry);
   1872     DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
   1873                                                 value, attributes);
   1874   }
   1875 
   1876   static void AddImpl(Handle<JSObject> object, uint32_t index,
   1877                       Handle<Object> value, PropertyAttributes attributes,
   1878                       uint32_t new_capacity) {
   1879     DCHECK_EQ(NONE, attributes);
   1880     ElementsKind from_kind = object->GetElementsKind();
   1881     ElementsKind to_kind = Subclass::kind();
   1882     if (IsDictionaryElementsKind(from_kind) ||
   1883         IsFastDoubleElementsKind(from_kind) !=
   1884             IsFastDoubleElementsKind(to_kind) ||
   1885         Subclass::GetCapacityImpl(*object, object->elements()) !=
   1886             new_capacity) {
   1887       Subclass::GrowCapacityAndConvertImpl(object, new_capacity);
   1888     } else {
   1889       if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
   1890         JSObject::TransitionElementsKind(object, to_kind);
   1891       }
   1892       if (IsFastSmiOrObjectElementsKind(from_kind)) {
   1893         DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
   1894         JSObject::EnsureWritableFastElements(object);
   1895       }
   1896     }
   1897     Subclass::SetImpl(object, index, *value);
   1898   }
   1899 
   1900   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
   1901     ElementsKind kind = KindTraits::Kind;
   1902     if (IsFastPackedElementsKind(kind)) {
   1903       JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
   1904     }
   1905     if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
   1906       JSObject::EnsureWritableFastElements(obj);
   1907     }
   1908     DeleteCommon(obj, entry, handle(obj->elements()));
   1909   }
   1910 
   1911   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* backing_store,
   1912                            uint32_t entry) {
   1913     return !BackingStore::cast(backing_store)->is_the_hole(isolate, entry);
   1914   }
   1915 
   1916   static uint32_t NumberOfElementsImpl(JSObject* receiver,
   1917                                        FixedArrayBase* backing_store) {
   1918     uint32_t max_index = Subclass::GetMaxIndex(receiver, backing_store);
   1919     if (IsFastPackedElementsKind(Subclass::kind())) return max_index;
   1920     Isolate* isolate = receiver->GetIsolate();
   1921     uint32_t count = 0;
   1922     for (uint32_t i = 0; i < max_index; i++) {
   1923       if (Subclass::HasEntryImpl(isolate, backing_store, i)) count++;
   1924     }
   1925     return count;
   1926   }
   1927 
   1928   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
   1929                                               KeyAccumulator* accumulator,
   1930                                               AddKeyConversion convert) {
   1931     Isolate* isolate = accumulator->isolate();
   1932     Handle<FixedArrayBase> elements(receiver->elements(), isolate);
   1933     uint32_t length = Subclass::GetMaxNumberOfEntries(*receiver, *elements);
   1934     for (uint32_t i = 0; i < length; i++) {
   1935       if (IsFastPackedElementsKind(KindTraits::Kind) ||
   1936           HasEntryImpl(isolate, *elements, i)) {
   1937         accumulator->AddKey(Subclass::GetImpl(*elements, i), convert);
   1938       }
   1939     }
   1940   }
   1941 
   1942   static void ValidateContents(Handle<JSObject> holder, int length) {
   1943 #if DEBUG
   1944     Isolate* isolate = holder->GetIsolate();
   1945     Heap* heap = isolate->heap();
   1946     HandleScope scope(isolate);
   1947     Handle<FixedArrayBase> elements(holder->elements(), isolate);
   1948     Map* map = elements->map();
   1949     if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
   1950       DCHECK_NE(map, heap->fixed_double_array_map());
   1951     } else if (IsFastDoubleElementsKind(KindTraits::Kind)) {
   1952       DCHECK_NE(map, heap->fixed_cow_array_map());
   1953       if (map == heap->fixed_array_map()) DCHECK_EQ(0, length);
   1954     } else {
   1955       UNREACHABLE();
   1956     }
   1957     if (length == 0) return;  // nothing to do!
   1958 #if ENABLE_SLOW_DCHECKS
   1959     DisallowHeapAllocation no_gc;
   1960     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
   1961     if (IsFastSmiElementsKind(KindTraits::Kind)) {
   1962       for (int i = 0; i < length; i++) {
   1963         DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() ||
   1964                (IsFastHoleyElementsKind(KindTraits::Kind) &&
   1965                 backing_store->is_the_hole(isolate, i)));
   1966       }
   1967     } else if (KindTraits::Kind == FAST_ELEMENTS ||
   1968                KindTraits::Kind == FAST_DOUBLE_ELEMENTS) {
   1969       for (int i = 0; i < length; i++) {
   1970         DCHECK(!backing_store->is_the_hole(isolate, i));
   1971       }
   1972     } else {
   1973       DCHECK(IsFastHoleyElementsKind(KindTraits::Kind));
   1974     }
   1975 #endif
   1976 #endif
   1977   }
   1978 
   1979   static Handle<Object> PopImpl(Handle<JSArray> receiver) {
   1980     return Subclass::RemoveElement(receiver, AT_END);
   1981   }
   1982 
   1983   static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
   1984     return Subclass::RemoveElement(receiver, AT_START);
   1985   }
   1986 
   1987   static uint32_t PushImpl(Handle<JSArray> receiver,
   1988                            Arguments* args, uint32_t push_size) {
   1989     Handle<FixedArrayBase> backing_store(receiver->elements());
   1990     return Subclass::AddArguments(receiver, backing_store, args, push_size,
   1991                                   AT_END);
   1992   }
   1993 
   1994   static uint32_t UnshiftImpl(Handle<JSArray> receiver,
   1995                               Arguments* args, uint32_t unshift_size) {
   1996     Handle<FixedArrayBase> backing_store(receiver->elements());
   1997     return Subclass::AddArguments(receiver, backing_store, args, unshift_size,
   1998                                   AT_START);
   1999   }
   2000 
   2001   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
   2002                                    uint32_t start, uint32_t end) {
   2003     Isolate* isolate = receiver->GetIsolate();
   2004     Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
   2005     int result_len = end < start ? 0u : end - start;
   2006     Handle<JSArray> result_array = isolate->factory()->NewJSArray(
   2007         KindTraits::Kind, result_len, result_len);
   2008     DisallowHeapAllocation no_gc;
   2009     Subclass::CopyElementsImpl(*backing_store, start, result_array->elements(),
   2010                                KindTraits::Kind, 0, kPackedSizeNotKnown,
   2011                                result_len);
   2012     Subclass::TryTransitionResultArrayToPacked(result_array);
   2013     return result_array;
   2014   }
   2015 
   2016   static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
   2017                                     uint32_t start, uint32_t delete_count,
   2018                                     Arguments* args, uint32_t add_count) {
   2019     Isolate* isolate = receiver->GetIsolate();
   2020     Heap* heap = isolate->heap();
   2021     uint32_t length = Smi::cast(receiver->length())->value();
   2022     uint32_t new_length = length - delete_count + add_count;
   2023 
   2024     ElementsKind kind = KindTraits::Kind;
   2025     if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) &&
   2026         IsFastSmiOrObjectElementsKind(kind)) {
   2027       HandleScope scope(isolate);
   2028       JSObject::EnsureWritableFastElements(receiver);
   2029     }
   2030 
   2031     Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
   2032 
   2033     if (new_length == 0) {
   2034       receiver->set_elements(heap->empty_fixed_array());
   2035       receiver->set_length(Smi::kZero);
   2036       return isolate->factory()->NewJSArrayWithElements(
   2037           backing_store, KindTraits::Kind, delete_count);
   2038     }
   2039 
   2040     // Construct the result array which holds the deleted elements.
   2041     Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
   2042         KindTraits::Kind, delete_count, delete_count);
   2043     if (delete_count > 0) {
   2044       DisallowHeapAllocation no_gc;
   2045       Subclass::CopyElementsImpl(*backing_store, start,
   2046                                  deleted_elements->elements(), KindTraits::Kind,
   2047                                  0, kPackedSizeNotKnown, delete_count);
   2048     }
   2049 
   2050     // Delete and move elements to make space for add_count new elements.
   2051     if (add_count < delete_count) {
   2052       Subclass::SpliceShrinkStep(isolate, receiver, backing_store, start,
   2053                                  delete_count, add_count, length, new_length);
   2054     } else if (add_count > delete_count) {
   2055       backing_store =
   2056           Subclass::SpliceGrowStep(isolate, receiver, backing_store, start,
   2057                                    delete_count, add_count, length, new_length);
   2058     }
   2059 
   2060     // Copy over the arguments.
   2061     Subclass::CopyArguments(args, backing_store, add_count, 3, start);
   2062 
   2063     receiver->set_length(Smi::FromInt(new_length));
   2064     Subclass::TryTransitionResultArrayToPacked(deleted_elements);
   2065     return deleted_elements;
   2066   }
   2067 
   2068   static Maybe<bool> CollectValuesOrEntriesImpl(
   2069       Isolate* isolate, Handle<JSObject> object,
   2070       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
   2071       PropertyFilter filter) {
   2072     Handle<BackingStore> elements(BackingStore::cast(object->elements()),
   2073                                   isolate);
   2074     int count = 0;
   2075     uint32_t length = elements->length();
   2076     for (uint32_t index = 0; index < length; ++index) {
   2077       if (!HasEntryImpl(isolate, *elements, index)) continue;
   2078       Handle<Object> value = Subclass::GetImpl(*elements, index);
   2079       if (get_entries) {
   2080         value = MakeEntryPair(isolate, index, value);
   2081       }
   2082       values_or_entries->set(count++, *value);
   2083     }
   2084     *nof_items = count;
   2085     return Just(true);
   2086   }
   2087 
   2088   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
   2089                            Handle<FixedArrayBase> backing_store, int dst_index,
   2090                            int src_index, int len, int hole_start,
   2091                            int hole_end) {
   2092     Heap* heap = isolate->heap();
   2093     Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store);
   2094     if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
   2095       // Update all the copies of this backing_store handle.
   2096       *dst_elms.location() =
   2097           BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
   2098       receiver->set_elements(*dst_elms);
   2099       // Adjust the hole offset as the array has been shrunk.
   2100       hole_end -= src_index;
   2101       DCHECK_LE(hole_start, backing_store->length());
   2102       DCHECK_LE(hole_end, backing_store->length());
   2103     } else if (len != 0) {
   2104       if (IsFastDoubleElementsKind(KindTraits::Kind)) {
   2105         MemMove(dst_elms->data_start() + dst_index,
   2106                 dst_elms->data_start() + src_index, len * kDoubleSize);
   2107       } else {
   2108         DisallowHeapAllocation no_gc;
   2109         heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index,
   2110                            len);
   2111       }
   2112     }
   2113     if (hole_start != hole_end) {
   2114       dst_elms->FillWithHoles(hole_start, hole_end);
   2115     }
   2116   }
   2117 
   2118   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
   2119                                        Handle<JSObject> receiver,
   2120                                        Handle<Object> search_value,
   2121                                        uint32_t start_from, uint32_t length) {
   2122     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
   2123     DisallowHeapAllocation no_gc;
   2124     FixedArrayBase* elements_base = receiver->elements();
   2125     Object* the_hole = isolate->heap()->the_hole_value();
   2126     Object* undefined = isolate->heap()->undefined_value();
   2127     Object* value = *search_value;
   2128 
   2129     // Elements beyond the capacity of the backing store treated as undefined.
   2130     if (value == undefined &&
   2131         static_cast<uint32_t>(elements_base->length()) < length) {
   2132       return Just(true);
   2133     }
   2134 
   2135     if (start_from >= length) return Just(false);
   2136 
   2137     length = std::min(static_cast<uint32_t>(elements_base->length()), length);
   2138 
   2139     if (!value->IsNumber()) {
   2140       if (value == undefined) {
   2141         // Only FAST_ELEMENTS, FAST_HOLEY_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, and
   2142         // FAST_HOLEY_DOUBLE_ELEMENTS can have `undefined` as a value.
   2143         if (!IsFastObjectElementsKind(Subclass::kind()) &&
   2144             !IsFastHoleyElementsKind(Subclass::kind())) {
   2145           return Just(false);
   2146         }
   2147 
   2148         // Search for `undefined` or The Hole in FAST_ELEMENTS,
   2149         // FAST_HOLEY_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS
   2150         if (IsFastSmiOrObjectElementsKind(Subclass::kind())) {
   2151           auto elements = FixedArray::cast(receiver->elements());
   2152 
   2153           for (uint32_t k = start_from; k < length; ++k) {
   2154             Object* element_k = elements->get(k);
   2155 
   2156             if (IsFastHoleyElementsKind(Subclass::kind()) &&
   2157                 element_k == the_hole) {
   2158               return Just(true);
   2159             }
   2160             if (IsFastObjectElementsKind(Subclass::kind()) &&
   2161                 element_k == undefined) {
   2162               return Just(true);
   2163             }
   2164           }
   2165           return Just(false);
   2166         } else {
   2167           // Seach for The Hole in FAST_HOLEY_DOUBLE_ELEMENTS
   2168           DCHECK_EQ(Subclass::kind(), FAST_HOLEY_DOUBLE_ELEMENTS);
   2169           auto elements = FixedDoubleArray::cast(receiver->elements());
   2170 
   2171           for (uint32_t k = start_from; k < length; ++k) {
   2172             if (IsFastHoleyElementsKind(Subclass::kind()) &&
   2173                 elements->is_the_hole(k)) {
   2174               return Just(true);
   2175             }
   2176           }
   2177           return Just(false);
   2178         }
   2179       } else if (!IsFastObjectElementsKind(Subclass::kind())) {
   2180         // Search for non-number, non-Undefined value, with either
   2181         // FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS or
   2182         // FAST_HOLEY_DOUBLE_ELEMENTS. Guaranteed to return false, since these
   2183         // elements kinds can only contain Number values or undefined.
   2184         return Just(false);
   2185       } else {
   2186         // Search for non-number, non-Undefined value with either
   2187         // FAST_ELEMENTS or FAST_HOLEY_ELEMENTS.
   2188         DCHECK(IsFastObjectElementsKind(Subclass::kind()));
   2189         auto elements = FixedArray::cast(receiver->elements());
   2190 
   2191         for (uint32_t k = start_from; k < length; ++k) {
   2192           Object* element_k = elements->get(k);
   2193           if (IsFastHoleyElementsKind(Subclass::kind()) &&
   2194               element_k == the_hole) {
   2195             continue;
   2196           }
   2197 
   2198           if (value->SameValueZero(element_k)) return Just(true);
   2199         }
   2200         return Just(false);
   2201       }
   2202     } else {
   2203       if (!value->IsNaN()) {
   2204         double search_value = value->Number();
   2205         if (IsFastDoubleElementsKind(Subclass::kind())) {
   2206           // Search for non-NaN Number in FAST_DOUBLE_ELEMENTS or
   2207           // FAST_HOLEY_DOUBLE_ELEMENTS --- Skip TheHole, and trust UCOMISD or
   2208           // similar operation for result.
   2209           auto elements = FixedDoubleArray::cast(receiver->elements());
   2210 
   2211           for (uint32_t k = start_from; k < length; ++k) {
   2212             if (IsFastHoleyElementsKind(Subclass::kind()) &&
   2213                 elements->is_the_hole(k)) {
   2214               continue;
   2215             }
   2216             if (elements->get_scalar(k) == search_value) return Just(true);
   2217           }
   2218           return Just(false);
   2219         } else {
   2220           // Search for non-NaN Number in FAST_ELEMENTS, FAST_HOLEY_ELEMENTS,
   2221           // FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS --- Skip non-Numbers,
   2222           // and trust UCOMISD or similar operation for result
   2223           auto elements = FixedArray::cast(receiver->elements());
   2224 
   2225           for (uint32_t k = start_from; k < length; ++k) {
   2226             Object* element_k = elements->get(k);
   2227             if (element_k->IsNumber() && element_k->Number() == search_value) {
   2228               return Just(true);
   2229             }
   2230           }
   2231           return Just(false);
   2232         }
   2233       } else {
   2234         // Search for NaN --- NaN cannot be represented with Smi elements, so
   2235         // abort if ElementsKind is FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS
   2236         if (IsFastSmiElementsKind(Subclass::kind())) return Just(false);
   2237 
   2238         if (IsFastDoubleElementsKind(Subclass::kind())) {
   2239           // Search for NaN in FAST_DOUBLE_ELEMENTS or
   2240           // FAST_HOLEY_DOUBLE_ELEMENTS --- Skip The Hole and trust
   2241           // std::isnan(elementK) for result
   2242           auto elements = FixedDoubleArray::cast(receiver->elements());
   2243 
   2244           for (uint32_t k = start_from; k < length; ++k) {
   2245             if (IsFastHoleyElementsKind(Subclass::kind()) &&
   2246                 elements->is_the_hole(k)) {
   2247               continue;
   2248             }
   2249             if (std::isnan(elements->get_scalar(k))) return Just(true);
   2250           }
   2251           return Just(false);
   2252         } else {
   2253           // Search for NaN in FAST_ELEMENTS, FAST_HOLEY_ELEMENTS,
   2254           // FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS. Return true if
   2255           // elementK->IsHeapNumber() && std::isnan(elementK->Number())
   2256           DCHECK(IsFastSmiOrObjectElementsKind(Subclass::kind()));
   2257           auto elements = FixedArray::cast(receiver->elements());
   2258 
   2259           for (uint32_t k = start_from; k < length; ++k) {
   2260             if (elements->get(k)->IsNaN()) return Just(true);
   2261           }
   2262           return Just(false);
   2263         }
   2264       }
   2265     }
   2266   }
   2267 
   2268  private:
   2269   // SpliceShrinkStep might modify the backing_store.
   2270   static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
   2271                                Handle<FixedArrayBase> backing_store,
   2272                                uint32_t start, uint32_t delete_count,
   2273                                uint32_t add_count, uint32_t len,
   2274                                uint32_t new_length) {
   2275     const int move_left_count = len - delete_count - start;
   2276     const int move_left_dst_index = start + add_count;
   2277     Subclass::MoveElements(isolate, receiver, backing_store,
   2278                            move_left_dst_index, start + delete_count,
   2279                            move_left_count, new_length, len);
   2280   }
   2281 
   2282   // SpliceGrowStep might modify the backing_store.
   2283   static Handle<FixedArrayBase> SpliceGrowStep(
   2284       Isolate* isolate, Handle<JSArray> receiver,
   2285       Handle<FixedArrayBase> backing_store, uint32_t start,
   2286       uint32_t delete_count, uint32_t add_count, uint32_t length,
   2287       uint32_t new_length) {
   2288     // Check we do not overflow the new_length.
   2289     DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
   2290     // Check if backing_store is big enough.
   2291     if (new_length <= static_cast<uint32_t>(backing_store->length())) {
   2292       Subclass::MoveElements(isolate, receiver, backing_store,
   2293                              start + add_count, start + delete_count,
   2294                              (length - delete_count - start), 0, 0);
   2295       // MoveElements updates the backing_store in-place.
   2296       return backing_store;
   2297     }
   2298     // New backing storage is needed.
   2299     int capacity = JSObject::NewElementsCapacity(new_length);
   2300     // Partially copy all elements up to start.
   2301     Handle<FixedArrayBase> new_elms = Subclass::ConvertElementsWithCapacity(
   2302         receiver, backing_store, KindTraits::Kind, capacity, start);
   2303     // Copy the trailing elements after start + delete_count
   2304     Subclass::CopyElementsImpl(*backing_store, start + delete_count, *new_elms,
   2305                                KindTraits::Kind, start + add_count,
   2306                                kPackedSizeNotKnown,
   2307                                ElementsAccessor::kCopyToEndAndInitializeToHole);
   2308     receiver->set_elements(*new_elms);
   2309     return new_elms;
   2310   }
   2311 
   2312   static Handle<Object> RemoveElement(Handle<JSArray> receiver,
   2313                                       Where remove_position) {
   2314     Isolate* isolate = receiver->GetIsolate();
   2315     ElementsKind kind = KindTraits::Kind;
   2316     if (IsFastSmiOrObjectElementsKind(kind)) {
   2317       HandleScope scope(isolate);
   2318       JSObject::EnsureWritableFastElements(receiver);
   2319     }
   2320     Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
   2321     uint32_t length =
   2322         static_cast<uint32_t>(Smi::cast(receiver->length())->value());
   2323     DCHECK(length > 0);
   2324     int new_length = length - 1;
   2325     int remove_index = remove_position == AT_START ? 0 : new_length;
   2326     Handle<Object> result = Subclass::GetImpl(*backing_store, remove_index);
   2327     if (remove_position == AT_START) {
   2328       Subclass::MoveElements(isolate, receiver, backing_store, 0, 1, new_length,
   2329                              0, 0);
   2330     }
   2331     Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store);
   2332 
   2333     if (IsHoleyElementsKind(kind) && result->IsTheHole(isolate)) {
   2334       return isolate->factory()->undefined_value();
   2335     }
   2336     return result;
   2337   }
   2338 
   2339   static uint32_t AddArguments(Handle<JSArray> receiver,
   2340                                Handle<FixedArrayBase> backing_store,
   2341                                Arguments* args, uint32_t add_size,
   2342                                Where add_position) {
   2343     uint32_t length = Smi::cast(receiver->length())->value();
   2344     DCHECK(0 < add_size);
   2345     uint32_t elms_len = backing_store->length();
   2346     // Check we do not overflow the new_length.
   2347     DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
   2348     uint32_t new_length = length + add_size;
   2349 
   2350     if (new_length > elms_len) {
   2351       // New backing storage is needed.
   2352       uint32_t capacity = JSObject::NewElementsCapacity(new_length);
   2353       // If we add arguments to the start we have to shift the existing objects.
   2354       int copy_dst_index = add_position == AT_START ? add_size : 0;
   2355       // Copy over all objects to a new backing_store.
   2356       backing_store = Subclass::ConvertElementsWithCapacity(
   2357           receiver, backing_store, KindTraits::Kind, capacity, 0,
   2358           copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
   2359       receiver->set_elements(*backing_store);
   2360     } else if (add_position == AT_START) {
   2361       // If the backing store has enough capacity and we add elements to the
   2362       // start we have to shift the existing objects.
   2363       Isolate* isolate = receiver->GetIsolate();
   2364       Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0,
   2365                              length, 0, 0);
   2366     }
   2367 
   2368     int insertion_index = add_position == AT_START ? 0 : length;
   2369     // Copy the arguments to the start.
   2370     Subclass::CopyArguments(args, backing_store, add_size, 1, insertion_index);
   2371     // Set the length.
   2372     receiver->set_length(Smi::FromInt(new_length));
   2373     return new_length;
   2374   }
   2375 
   2376   static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
   2377                             uint32_t copy_size, uint32_t src_index,
   2378                             uint32_t dst_index) {
   2379     // Add the provided values.
   2380     DisallowHeapAllocation no_gc;
   2381     FixedArrayBase* raw_backing_store = *dst_store;
   2382     WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
   2383     for (uint32_t i = 0; i < copy_size; i++) {
   2384       Object* argument = (*args)[src_index + i];
   2385       DCHECK(!argument->IsTheHole(raw_backing_store->GetIsolate()));
   2386       Subclass::SetImpl(raw_backing_store, dst_index + i, argument, mode);
   2387     }
   2388   }
   2389 };
   2390 
   2391 template <typename Subclass, typename KindTraits>
   2392 class FastSmiOrObjectElementsAccessor
   2393     : public FastElementsAccessor<Subclass, KindTraits> {
   2394  public:
   2395   explicit FastSmiOrObjectElementsAccessor(const char* name)
   2396       : FastElementsAccessor<Subclass, KindTraits>(name) {}
   2397 
   2398   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
   2399                              Object* value) {
   2400     SetImpl(holder->elements(), entry, value);
   2401   }
   2402 
   2403   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   2404                              Object* value) {
   2405     FixedArray::cast(backing_store)->set(entry, value);
   2406   }
   2407 
   2408   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   2409                              Object* value, WriteBarrierMode mode) {
   2410     FixedArray::cast(backing_store)->set(entry, value, mode);
   2411   }
   2412 
   2413   static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
   2414     uint32_t index = Subclass::GetIndexForEntryImpl(backing_store, entry);
   2415     return backing_store->get(index);
   2416   }
   2417 
   2418   // NOTE: this method violates the handlified function signature convention:
   2419   // raw pointer parameters in the function that allocates.
   2420   // See ElementsAccessor::CopyElements() for details.
   2421   // This method could actually allocate if copying from double elements to
   2422   // object elements.
   2423   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   2424                                FixedArrayBase* to, ElementsKind from_kind,
   2425                                uint32_t to_start, int packed_size,
   2426                                int copy_size) {
   2427     DisallowHeapAllocation no_gc;
   2428     ElementsKind to_kind = KindTraits::Kind;
   2429     switch (from_kind) {
   2430       case FAST_SMI_ELEMENTS:
   2431       case FAST_HOLEY_SMI_ELEMENTS:
   2432       case FAST_ELEMENTS:
   2433       case FAST_HOLEY_ELEMENTS:
   2434         CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
   2435                                    to_start, copy_size);
   2436         break;
   2437       case FAST_DOUBLE_ELEMENTS:
   2438       case FAST_HOLEY_DOUBLE_ELEMENTS: {
   2439         AllowHeapAllocation allow_allocation;
   2440         DCHECK(IsFastObjectElementsKind(to_kind));
   2441         CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
   2442         break;
   2443       }
   2444       case DICTIONARY_ELEMENTS:
   2445         CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
   2446                                        copy_size);
   2447         break;
   2448       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
   2449       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
   2450       case FAST_STRING_WRAPPER_ELEMENTS:
   2451       case SLOW_STRING_WRAPPER_ELEMENTS:
   2452 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
   2453       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   2454 #undef TYPED_ARRAY_CASE
   2455       // This function is currently only used for JSArrays with non-zero
   2456       // length.
   2457       UNREACHABLE();
   2458       break;
   2459       case NO_ELEMENTS:
   2460         break;  // Nothing to do.
   2461     }
   2462   }
   2463 
   2464   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
   2465                                          Handle<JSObject> receiver,
   2466                                          Handle<Object> search_value,
   2467                                          uint32_t start_from, uint32_t length) {
   2468     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
   2469     DisallowHeapAllocation no_gc;
   2470     FixedArrayBase* elements_base = receiver->elements();
   2471     Object* value = *search_value;
   2472 
   2473     if (start_from >= length) return Just<int64_t>(-1);
   2474 
   2475     length = std::min(static_cast<uint32_t>(elements_base->length()), length);
   2476 
   2477     // Only FAST_{,HOLEY_}ELEMENTS can store non-numbers.
   2478     if (!value->IsNumber() && !IsFastObjectElementsKind(Subclass::kind())) {
   2479       return Just<int64_t>(-1);
   2480     }
   2481     // NaN can never be found by strict equality.
   2482     if (value->IsNaN()) return Just<int64_t>(-1);
   2483 
   2484     FixedArray* elements = FixedArray::cast(receiver->elements());
   2485     for (uint32_t k = start_from; k < length; ++k) {
   2486       if (value->StrictEquals(elements->get(k))) return Just<int64_t>(k);
   2487     }
   2488     return Just<int64_t>(-1);
   2489   }
   2490 };
   2491 
   2492 
   2493 class FastPackedSmiElementsAccessor
   2494     : public FastSmiOrObjectElementsAccessor<
   2495         FastPackedSmiElementsAccessor,
   2496         ElementsKindTraits<FAST_SMI_ELEMENTS> > {
   2497  public:
   2498   explicit FastPackedSmiElementsAccessor(const char* name)
   2499       : FastSmiOrObjectElementsAccessor<
   2500           FastPackedSmiElementsAccessor,
   2501           ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
   2502 };
   2503 
   2504 
   2505 class FastHoleySmiElementsAccessor
   2506     : public FastSmiOrObjectElementsAccessor<
   2507         FastHoleySmiElementsAccessor,
   2508         ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
   2509  public:
   2510   explicit FastHoleySmiElementsAccessor(const char* name)
   2511       : FastSmiOrObjectElementsAccessor<
   2512           FastHoleySmiElementsAccessor,
   2513           ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
   2514 };
   2515 
   2516 
   2517 class FastPackedObjectElementsAccessor
   2518     : public FastSmiOrObjectElementsAccessor<
   2519         FastPackedObjectElementsAccessor,
   2520         ElementsKindTraits<FAST_ELEMENTS> > {
   2521  public:
   2522   explicit FastPackedObjectElementsAccessor(const char* name)
   2523       : FastSmiOrObjectElementsAccessor<
   2524           FastPackedObjectElementsAccessor,
   2525           ElementsKindTraits<FAST_ELEMENTS> >(name) {}
   2526 };
   2527 
   2528 
   2529 class FastHoleyObjectElementsAccessor
   2530     : public FastSmiOrObjectElementsAccessor<
   2531         FastHoleyObjectElementsAccessor,
   2532         ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
   2533  public:
   2534   explicit FastHoleyObjectElementsAccessor(const char* name)
   2535       : FastSmiOrObjectElementsAccessor<
   2536           FastHoleyObjectElementsAccessor,
   2537           ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
   2538 };
   2539 
   2540 template <typename Subclass, typename KindTraits>
   2541 class FastDoubleElementsAccessor
   2542     : public FastElementsAccessor<Subclass, KindTraits> {
   2543  public:
   2544   explicit FastDoubleElementsAccessor(const char* name)
   2545       : FastElementsAccessor<Subclass, KindTraits>(name) {}
   2546 
   2547   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
   2548     return GetImpl(holder->elements(), entry);
   2549   }
   2550 
   2551   static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
   2552     Isolate* isolate = backing_store->GetIsolate();
   2553     return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry,
   2554                                  isolate);
   2555   }
   2556 
   2557   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
   2558                              Object* value) {
   2559     SetImpl(holder->elements(), entry, value);
   2560   }
   2561 
   2562   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   2563                              Object* value) {
   2564     FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
   2565   }
   2566 
   2567   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   2568                              Object* value, WriteBarrierMode mode) {
   2569     FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
   2570   }
   2571 
   2572   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   2573                                FixedArrayBase* to, ElementsKind from_kind,
   2574                                uint32_t to_start, int packed_size,
   2575                                int copy_size) {
   2576     DisallowHeapAllocation no_allocation;
   2577     switch (from_kind) {
   2578       case FAST_SMI_ELEMENTS:
   2579         CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
   2580                                       packed_size, copy_size);
   2581         break;
   2582       case FAST_HOLEY_SMI_ELEMENTS:
   2583         CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
   2584         break;
   2585       case FAST_DOUBLE_ELEMENTS:
   2586       case FAST_HOLEY_DOUBLE_ELEMENTS:
   2587         CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
   2588         break;
   2589       case FAST_ELEMENTS:
   2590       case FAST_HOLEY_ELEMENTS:
   2591         CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
   2592         break;
   2593       case DICTIONARY_ELEMENTS:
   2594         CopyDictionaryToDoubleElements(from, from_start, to, to_start,
   2595                                        copy_size);
   2596         break;
   2597       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
   2598       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
   2599       case FAST_STRING_WRAPPER_ELEMENTS:
   2600       case SLOW_STRING_WRAPPER_ELEMENTS:
   2601       case NO_ELEMENTS:
   2602 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
   2603       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   2604 #undef TYPED_ARRAY_CASE
   2605       // This function is currently only used for JSArrays with non-zero
   2606       // length.
   2607       UNREACHABLE();
   2608       break;
   2609     }
   2610   }
   2611 
   2612   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
   2613                                          Handle<JSObject> receiver,
   2614                                          Handle<Object> search_value,
   2615                                          uint32_t start_from, uint32_t length) {
   2616     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
   2617     DisallowHeapAllocation no_gc;
   2618     FixedArrayBase* elements_base = receiver->elements();
   2619     Object* value = *search_value;
   2620 
   2621     if (start_from >= length) return Just<int64_t>(-1);
   2622 
   2623     length = std::min(static_cast<uint32_t>(elements_base->length()), length);
   2624 
   2625     if (!value->IsNumber()) {
   2626       return Just<int64_t>(-1);
   2627     }
   2628     if (value->IsNaN()) {
   2629       return Just<int64_t>(-1);
   2630     }
   2631     double numeric_search_value = value->Number();
   2632     FixedDoubleArray* elements = FixedDoubleArray::cast(receiver->elements());
   2633 
   2634     for (uint32_t k = start_from; k < length; ++k) {
   2635       if (elements->is_the_hole(k)) {
   2636         continue;
   2637       }
   2638       if (elements->get_scalar(k) == numeric_search_value) {
   2639         return Just<int64_t>(k);
   2640       }
   2641     }
   2642     return Just<int64_t>(-1);
   2643   }
   2644 };
   2645 
   2646 
   2647 class FastPackedDoubleElementsAccessor
   2648     : public FastDoubleElementsAccessor<
   2649         FastPackedDoubleElementsAccessor,
   2650         ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
   2651  public:
   2652   explicit FastPackedDoubleElementsAccessor(const char* name)
   2653       : FastDoubleElementsAccessor<
   2654           FastPackedDoubleElementsAccessor,
   2655           ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
   2656 };
   2657 
   2658 
   2659 class FastHoleyDoubleElementsAccessor
   2660     : public FastDoubleElementsAccessor<
   2661         FastHoleyDoubleElementsAccessor,
   2662         ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
   2663  public:
   2664   explicit FastHoleyDoubleElementsAccessor(const char* name)
   2665       : FastDoubleElementsAccessor<
   2666           FastHoleyDoubleElementsAccessor,
   2667           ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
   2668 };
   2669 
   2670 
   2671 // Super class for all external element arrays.
   2672 template <ElementsKind Kind, typename ctype>
   2673 class TypedElementsAccessor
   2674     : public ElementsAccessorBase<TypedElementsAccessor<Kind, ctype>,
   2675                                   ElementsKindTraits<Kind>> {
   2676  public:
   2677   explicit TypedElementsAccessor(const char* name)
   2678       : ElementsAccessorBase<AccessorClass,
   2679                              ElementsKindTraits<Kind> >(name) {}
   2680 
   2681   typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
   2682   typedef TypedElementsAccessor<Kind, ctype> AccessorClass;
   2683 
   2684   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
   2685                              Object* value) {
   2686     SetImpl(holder->elements(), entry, value);
   2687   }
   2688 
   2689   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   2690                              Object* value) {
   2691     BackingStore::cast(backing_store)->SetValue(entry, value);
   2692   }
   2693 
   2694   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   2695                              Object* value, WriteBarrierMode mode) {
   2696     BackingStore::cast(backing_store)->SetValue(entry, value);
   2697   }
   2698 
   2699   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
   2700     return GetImpl(holder->elements(), entry);
   2701   }
   2702 
   2703   static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
   2704     return BackingStore::get(BackingStore::cast(backing_store), entry);
   2705   }
   2706 
   2707   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
   2708     return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
   2709   }
   2710 
   2711   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
   2712                                         uint32_t entry) {
   2713     return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
   2714   }
   2715 
   2716   static bool HasElementImpl(Isolate* isolate, Handle<JSObject> holder,
   2717                              uint32_t index,
   2718                              Handle<FixedArrayBase> backing_store,
   2719                              PropertyFilter filter) {
   2720     return index < AccessorClass::GetCapacityImpl(*holder, *backing_store);
   2721   }
   2722 
   2723   static bool HasAccessorsImpl(JSObject* holder,
   2724                                FixedArrayBase* backing_store) {
   2725     return false;
   2726   }
   2727 
   2728   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
   2729                             uint32_t length,
   2730                             Handle<FixedArrayBase> backing_store) {
   2731     // External arrays do not support changing their length.
   2732     UNREACHABLE();
   2733   }
   2734 
   2735   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
   2736     UNREACHABLE();
   2737   }
   2738 
   2739   static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
   2740                                        uint32_t entry) {
   2741     return entry;
   2742   }
   2743 
   2744   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
   2745                                        FixedArrayBase* backing_store,
   2746                                        uint32_t index, PropertyFilter filter) {
   2747     return index < AccessorClass::GetCapacityImpl(holder, backing_store)
   2748                ? index
   2749                : kMaxUInt32;
   2750   }
   2751 
   2752   static uint32_t GetCapacityImpl(JSObject* holder,
   2753                                   FixedArrayBase* backing_store) {
   2754     JSArrayBufferView* view = JSArrayBufferView::cast(holder);
   2755     if (view->WasNeutered()) return 0;
   2756     return backing_store->length();
   2757   }
   2758 
   2759   static uint32_t NumberOfElementsImpl(JSObject* receiver,
   2760                                        FixedArrayBase* backing_store) {
   2761     return AccessorClass::GetCapacityImpl(receiver, backing_store);
   2762   }
   2763 
   2764   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
   2765                                               KeyAccumulator* accumulator,
   2766                                               AddKeyConversion convert) {
   2767     Handle<FixedArrayBase> elements(receiver->elements());
   2768     uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements);
   2769     for (uint32_t i = 0; i < length; i++) {
   2770       Handle<Object> value = AccessorClass::GetImpl(*elements, i);
   2771       accumulator->AddKey(value, convert);
   2772     }
   2773   }
   2774 
   2775   static Maybe<bool> CollectValuesOrEntriesImpl(
   2776       Isolate* isolate, Handle<JSObject> object,
   2777       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
   2778       PropertyFilter filter) {
   2779     int count = 0;
   2780     if ((filter & ONLY_CONFIGURABLE) == 0) {
   2781       Handle<FixedArrayBase> elements(object->elements());
   2782       uint32_t length = AccessorClass::GetCapacityImpl(*object, *elements);
   2783       for (uint32_t index = 0; index < length; ++index) {
   2784         Handle<Object> value = AccessorClass::GetImpl(*elements, index);
   2785         if (get_entries) {
   2786           value = MakeEntryPair(isolate, index, value);
   2787         }
   2788         values_or_entries->set(count++, *value);
   2789       }
   2790     }
   2791     *nof_items = count;
   2792     return Just(true);
   2793   }
   2794 
   2795   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
   2796                                        Handle<JSObject> receiver,
   2797                                        Handle<Object> value,
   2798                                        uint32_t start_from, uint32_t length) {
   2799     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
   2800     DisallowHeapAllocation no_gc;
   2801 
   2802     BackingStore* elements = BackingStore::cast(receiver->elements());
   2803     if (value->IsUndefined(isolate) &&
   2804         length > static_cast<uint32_t>(elements->length())) {
   2805       return Just(true);
   2806     }
   2807     if (!value->IsNumber()) return Just(false);
   2808 
   2809     double search_value = value->Number();
   2810 
   2811     if (!std::isfinite(search_value)) {
   2812       // Integral types cannot represent +Inf or NaN
   2813       if (AccessorClass::kind() < FLOAT32_ELEMENTS ||
   2814           AccessorClass::kind() > FLOAT64_ELEMENTS) {
   2815         return Just(false);
   2816       }
   2817     } else if (search_value < std::numeric_limits<ctype>::lowest() ||
   2818                search_value > std::numeric_limits<ctype>::max()) {
   2819       // Return false if value can't be represented in this space
   2820       return Just(false);
   2821     }
   2822 
   2823     // Prototype has no elements, and not searching for the hole --- limit
   2824     // search to backing store length.
   2825     if (static_cast<uint32_t>(elements->length()) < length) {
   2826       length = elements->length();
   2827     }
   2828 
   2829     if (!std::isnan(search_value)) {
   2830       for (uint32_t k = start_from; k < length; ++k) {
   2831         double element_k = elements->get_scalar(k);
   2832         if (element_k == search_value) return Just(true);
   2833       }
   2834       return Just(false);
   2835     } else {
   2836       for (uint32_t k = start_from; k < length; ++k) {
   2837         double element_k = elements->get_scalar(k);
   2838         if (std::isnan(element_k)) return Just(true);
   2839       }
   2840       return Just(false);
   2841     }
   2842   }
   2843 
   2844   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
   2845                                          Handle<JSObject> receiver,
   2846                                          Handle<Object> value,
   2847                                          uint32_t start_from, uint32_t length) {
   2848     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
   2849     DisallowHeapAllocation no_gc;
   2850 
   2851     BackingStore* elements = BackingStore::cast(receiver->elements());
   2852     if (!value->IsNumber()) return Just<int64_t>(-1);
   2853 
   2854     double search_value = value->Number();
   2855 
   2856     if (!std::isfinite(search_value)) {
   2857       // Integral types cannot represent +Inf or NaN.
   2858       if (AccessorClass::kind() < FLOAT32_ELEMENTS ||
   2859           AccessorClass::kind() > FLOAT64_ELEMENTS) {
   2860         return Just<int64_t>(-1);
   2861       }
   2862     } else if (search_value < std::numeric_limits<ctype>::lowest() ||
   2863                search_value > std::numeric_limits<ctype>::max()) {
   2864       // Return false if value can't be represented in this ElementsKind.
   2865       return Just<int64_t>(-1);
   2866     }
   2867 
   2868     // Prototype has no elements, and not searching for the hole --- limit
   2869     // search to backing store length.
   2870     if (static_cast<uint32_t>(elements->length()) < length) {
   2871       length = elements->length();
   2872     }
   2873 
   2874     if (std::isnan(search_value)) {
   2875       return Just<int64_t>(-1);
   2876     }
   2877 
   2878     ctype typed_search_value = static_cast<ctype>(search_value);
   2879     if (static_cast<double>(typed_search_value) != search_value) {
   2880       return Just<int64_t>(-1);  // Loss of precision.
   2881     }
   2882 
   2883     for (uint32_t k = start_from; k < length; ++k) {
   2884       ctype element_k = elements->get_scalar(k);
   2885       if (element_k == typed_search_value) return Just<int64_t>(k);
   2886     }
   2887     return Just<int64_t>(-1);
   2888   }
   2889 };
   2890 
   2891 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
   2892   typedef TypedElementsAccessor<TYPE##_ELEMENTS, ctype>        \
   2893       Fixed##Type##ElementsAccessor;
   2894 
   2895 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
   2896 #undef FIXED_ELEMENTS_ACCESSOR
   2897 
   2898 template <typename Subclass, typename ArgumentsAccessor, typename KindTraits>
   2899 class SloppyArgumentsElementsAccessor
   2900     : public ElementsAccessorBase<Subclass, KindTraits> {
   2901  public:
   2902   explicit SloppyArgumentsElementsAccessor(const char* name)
   2903       : ElementsAccessorBase<Subclass, KindTraits>(name) {
   2904     USE(KindTraits::Kind);
   2905   }
   2906 
   2907   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
   2908     return GetImpl(holder->elements(), entry);
   2909   }
   2910 
   2911   static Handle<Object> GetImpl(FixedArrayBase* parameters, uint32_t entry) {
   2912     Isolate* isolate = parameters->GetIsolate();
   2913     Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate);
   2914     uint32_t length = parameter_map->length() - 2;
   2915     if (entry < length) {
   2916       DisallowHeapAllocation no_gc;
   2917       Object* probe = parameter_map->get(entry + 2);
   2918       Context* context = Context::cast(parameter_map->get(0));
   2919       int context_entry = Smi::cast(probe)->value();
   2920       DCHECK(!context->get(context_entry)->IsTheHole(isolate));
   2921       return handle(context->get(context_entry), isolate);
   2922     } else {
   2923       // Object is not mapped, defer to the arguments.
   2924       Handle<Object> result = ArgumentsAccessor::GetImpl(
   2925           FixedArray::cast(parameter_map->get(1)), entry - length);
   2926       // Elements of the arguments object in slow mode might be slow aliases.
   2927       if (result->IsAliasedArgumentsEntry()) {
   2928         DisallowHeapAllocation no_gc;
   2929         AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
   2930         Context* context = Context::cast(parameter_map->get(0));
   2931         int context_entry = alias->aliased_context_slot();
   2932         DCHECK(!context->get(context_entry)->IsTheHole(isolate));
   2933         return handle(context->get(context_entry), isolate);
   2934       }
   2935       return result;
   2936     }
   2937   }
   2938 
   2939   static void TransitionElementsKindImpl(Handle<JSObject> object,
   2940                                          Handle<Map> map) {
   2941     UNREACHABLE();
   2942   }
   2943 
   2944   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
   2945                                          uint32_t capacity) {
   2946     UNREACHABLE();
   2947   }
   2948 
   2949   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
   2950                              Object* value) {
   2951     SetImpl(holder->elements(), entry, value);
   2952   }
   2953 
   2954   static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
   2955                              Object* value) {
   2956     FixedArray* parameter_map = FixedArray::cast(store);
   2957     uint32_t length = parameter_map->length() - 2;
   2958     if (entry < length) {
   2959       Object* probe = parameter_map->get(entry + 2);
   2960       Context* context = Context::cast(parameter_map->get(0));
   2961       int context_entry = Smi::cast(probe)->value();
   2962       DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
   2963       context->set(context_entry, value);
   2964     } else {
   2965       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   2966       Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
   2967       if (current->IsAliasedArgumentsEntry()) {
   2968         AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
   2969         Context* context = Context::cast(parameter_map->get(0));
   2970         int context_entry = alias->aliased_context_slot();
   2971         DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
   2972         context->set(context_entry, value);
   2973       } else {
   2974         ArgumentsAccessor::SetImpl(arguments, entry - length, value);
   2975       }
   2976     }
   2977   }
   2978 
   2979   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
   2980                             uint32_t length,
   2981                             Handle<FixedArrayBase> parameter_map) {
   2982     // Sloppy arguments objects are not arrays.
   2983     UNREACHABLE();
   2984   }
   2985 
   2986   static uint32_t GetCapacityImpl(JSObject* holder,
   2987                                   FixedArrayBase* backing_store) {
   2988     FixedArray* parameter_map = FixedArray::cast(backing_store);
   2989     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   2990     return parameter_map->length() - 2 +
   2991            ArgumentsAccessor::GetCapacityImpl(holder, arguments);
   2992   }
   2993 
   2994   static uint32_t GetMaxNumberOfEntries(JSObject* holder,
   2995                                         FixedArrayBase* backing_store) {
   2996     FixedArray* parameter_map = FixedArray::cast(backing_store);
   2997     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   2998     return parameter_map->length() - 2 +
   2999            ArgumentsAccessor::GetMaxNumberOfEntries(holder, arguments);
   3000   }
   3001 
   3002   static uint32_t NumberOfElementsImpl(JSObject* receiver,
   3003                                        FixedArrayBase* backing_store) {
   3004     FixedArray* parameter_map = FixedArray::cast(backing_store);
   3005     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   3006     uint32_t nof_elements = 0;
   3007     uint32_t length = parameter_map->length() - 2;
   3008     for (uint32_t entry = 0; entry < length; entry++) {
   3009       if (HasParameterMapArg(parameter_map, entry)) nof_elements++;
   3010     }
   3011     return nof_elements +
   3012            ArgumentsAccessor::NumberOfElementsImpl(receiver, arguments);
   3013   }
   3014 
   3015   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
   3016                                               KeyAccumulator* accumulator,
   3017                                               AddKeyConversion convert) {
   3018     Isolate* isolate = accumulator->isolate();
   3019     Handle<FixedArrayBase> elements(receiver->elements(), isolate);
   3020     uint32_t length = GetCapacityImpl(*receiver, *elements);
   3021     for (uint32_t entry = 0; entry < length; entry++) {
   3022       if (!HasEntryImpl(isolate, *elements, entry)) continue;
   3023       Handle<Object> value = GetImpl(*elements, entry);
   3024       accumulator->AddKey(value, convert);
   3025     }
   3026   }
   3027 
   3028   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* parameters,
   3029                            uint32_t entry) {
   3030     FixedArray* parameter_map = FixedArray::cast(parameters);
   3031     uint32_t length = parameter_map->length() - 2;
   3032     if (entry < length) {
   3033       return HasParameterMapArg(parameter_map, entry);
   3034     }
   3035 
   3036     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   3037     return ArgumentsAccessor::HasEntryImpl(isolate, arguments, entry - length);
   3038   }
   3039 
   3040   static bool HasAccessorsImpl(JSObject* holder,
   3041                                FixedArrayBase* backing_store) {
   3042     FixedArray* parameter_map = FixedArray::cast(backing_store);
   3043     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   3044     return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
   3045   }
   3046 
   3047   static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
   3048                                        uint32_t entry) {
   3049     FixedArray* parameter_map = FixedArray::cast(parameters);
   3050     uint32_t length = parameter_map->length() - 2;
   3051     if (entry < length) return entry;
   3052 
   3053     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   3054     return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
   3055   }
   3056 
   3057   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
   3058                                        FixedArrayBase* parameters,
   3059                                        uint32_t index, PropertyFilter filter) {
   3060     FixedArray* parameter_map = FixedArray::cast(parameters);
   3061     if (HasParameterMapArg(parameter_map, index)) return index;
   3062 
   3063     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   3064     uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(
   3065         isolate, holder, arguments, index, filter);
   3066     if (entry == kMaxUInt32) return kMaxUInt32;
   3067     return (parameter_map->length() - 2) + entry;
   3068   }
   3069 
   3070   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
   3071     FixedArray* parameter_map = FixedArray::cast(holder->elements());
   3072     uint32_t length = parameter_map->length() - 2;
   3073     if (entry < length) {
   3074       return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
   3075     }
   3076     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   3077     return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
   3078   }
   3079 
   3080   static bool HasParameterMapArg(FixedArray* parameter_map, uint32_t index) {
   3081     uint32_t length = parameter_map->length() - 2;
   3082     if (index >= length) return false;
   3083     return !parameter_map->get(index + 2)->IsTheHole(
   3084         parameter_map->GetIsolate());
   3085   }
   3086 
   3087   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
   3088     FixedArray* parameter_map = FixedArray::cast(obj->elements());
   3089     uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
   3090     if (entry < length) {
   3091       // TODO(kmillikin): We could check if this was the last aliased
   3092       // parameter, and revert to normal elements in that case.  That
   3093       // would enable GC of the context.
   3094       parameter_map->set_the_hole(entry + 2);
   3095     } else {
   3096       Subclass::DeleteFromArguments(obj, entry - length);
   3097     }
   3098   }
   3099 
   3100   static void CollectElementIndicesImpl(Handle<JSObject> object,
   3101                                         Handle<FixedArrayBase> backing_store,
   3102                                         KeyAccumulator* keys) {
   3103     Isolate* isolate = keys->isolate();
   3104     uint32_t nof_indices = 0;
   3105     Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
   3106         GetCapacityImpl(*object, *backing_store));
   3107     DirectCollectElementIndicesImpl(isolate, object, backing_store,
   3108                                     GetKeysConversion::kKeepNumbers,
   3109                                     ENUMERABLE_STRINGS, indices, &nof_indices);
   3110     SortIndices(indices, nof_indices);
   3111     for (uint32_t i = 0; i < nof_indices; i++) {
   3112       keys->AddKey(indices->get(i));
   3113     }
   3114   }
   3115 
   3116   static Handle<FixedArray> DirectCollectElementIndicesImpl(
   3117       Isolate* isolate, Handle<JSObject> object,
   3118       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
   3119       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
   3120       uint32_t insertion_index = 0) {
   3121     Handle<FixedArray> parameter_map(FixedArray::cast(*backing_store), isolate);
   3122     uint32_t length = parameter_map->length() - 2;
   3123 
   3124     for (uint32_t i = 0; i < length; ++i) {
   3125       if (parameter_map->get(i + 2)->IsTheHole(isolate)) continue;
   3126       if (convert == GetKeysConversion::kConvertToString) {
   3127         Handle<String> index_string = isolate->factory()->Uint32ToString(i);
   3128         list->set(insertion_index, *index_string);
   3129       } else {
   3130         list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
   3131       }
   3132       insertion_index++;
   3133     }
   3134 
   3135     Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
   3136     return ArgumentsAccessor::DirectCollectElementIndicesImpl(
   3137         isolate, object, store, convert, filter, list, nof_indices,
   3138         insertion_index);
   3139   }
   3140 
   3141   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
   3142                                        Handle<JSObject> object,
   3143                                        Handle<Object> value,
   3144                                        uint32_t start_from, uint32_t length) {
   3145     DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
   3146     Handle<Map> original_map = handle(object->map(), isolate);
   3147     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()),
   3148                                      isolate);
   3149     bool search_for_hole = value->IsUndefined(isolate);
   3150 
   3151     for (uint32_t k = start_from; k < length; ++k) {
   3152       uint32_t entry = GetEntryForIndexImpl(isolate, *object, *parameter_map, k,
   3153                                             ALL_PROPERTIES);
   3154       if (entry == kMaxUInt32) {
   3155         if (search_for_hole) return Just(true);
   3156         continue;
   3157       }
   3158 
   3159       Handle<Object> element_k = GetImpl(*parameter_map, entry);
   3160 
   3161       if (element_k->IsAccessorPair()) {
   3162         LookupIterator it(isolate, object, k, LookupIterator::OWN);
   3163         DCHECK(it.IsFound());
   3164         DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
   3165         ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
   3166                                          Object::GetPropertyWithAccessor(&it),
   3167                                          Nothing<bool>());
   3168 
   3169         if (value->SameValueZero(*element_k)) return Just(true);
   3170 
   3171         if (object->map() != *original_map) {
   3172           // Some mutation occurred in accessor. Abort "fast" path
   3173           return IncludesValueSlowPath(isolate, object, value, k + 1, length);
   3174         }
   3175       } else if (value->SameValueZero(*element_k)) {
   3176         return Just(true);
   3177       }
   3178     }
   3179     return Just(false);
   3180   }
   3181 
   3182   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
   3183                                          Handle<JSObject> object,
   3184                                          Handle<Object> value,
   3185                                          uint32_t start_from, uint32_t length) {
   3186     DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
   3187     Handle<Map> original_map = handle(object->map(), isolate);
   3188     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()),
   3189                                      isolate);
   3190 
   3191     for (uint32_t k = start_from; k < length; ++k) {
   3192       uint32_t entry = GetEntryForIndexImpl(isolate, *object, *parameter_map, k,
   3193                                             ALL_PROPERTIES);
   3194       if (entry == kMaxUInt32) {
   3195         continue;
   3196       }
   3197 
   3198       Handle<Object> element_k = GetImpl(*parameter_map, entry);
   3199 
   3200       if (element_k->IsAccessorPair()) {
   3201         LookupIterator it(isolate, object, k, LookupIterator::OWN);
   3202         DCHECK(it.IsFound());
   3203         DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
   3204         ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
   3205                                          Object::GetPropertyWithAccessor(&it),
   3206                                          Nothing<int64_t>());
   3207 
   3208         if (value->StrictEquals(*element_k)) {
   3209           return Just<int64_t>(k);
   3210         }
   3211 
   3212         if (object->map() != *original_map) {
   3213           // Some mutation occurred in accessor. Abort "fast" path.
   3214           return IndexOfValueSlowPath(isolate, object, value, k + 1, length);
   3215         }
   3216       } else if (value->StrictEquals(*element_k)) {
   3217         return Just<int64_t>(k);
   3218       }
   3219     }
   3220     return Just<int64_t>(-1);
   3221   }
   3222 };
   3223 
   3224 
   3225 class SlowSloppyArgumentsElementsAccessor
   3226     : public SloppyArgumentsElementsAccessor<
   3227           SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
   3228           ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
   3229  public:
   3230   explicit SlowSloppyArgumentsElementsAccessor(const char* name)
   3231       : SloppyArgumentsElementsAccessor<
   3232             SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
   3233             ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
   3234 
   3235   static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
   3236     Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
   3237     Handle<SeededNumberDictionary> dict(
   3238         SeededNumberDictionary::cast(parameter_map->get(1)));
   3239     // TODO(verwaest): Remove reliance on index in Shrink.
   3240     uint32_t index = GetIndexForEntryImpl(*dict, entry);
   3241     Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
   3242     USE(result);
   3243     DCHECK(result->IsTrue(dict->GetIsolate()));
   3244     Handle<FixedArray> new_elements =
   3245         SeededNumberDictionary::Shrink(dict, index);
   3246     parameter_map->set(1, *new_elements);
   3247   }
   3248 
   3249   static void AddImpl(Handle<JSObject> object, uint32_t index,
   3250                       Handle<Object> value, PropertyAttributes attributes,
   3251                       uint32_t new_capacity) {
   3252     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
   3253     Handle<FixedArrayBase> old_elements(
   3254         FixedArrayBase::cast(parameter_map->get(1)));
   3255     Handle<SeededNumberDictionary> dictionary =
   3256         old_elements->IsSeededNumberDictionary()
   3257             ? Handle<SeededNumberDictionary>::cast(old_elements)
   3258             : JSObject::NormalizeElements(object);
   3259     PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
   3260     Handle<SeededNumberDictionary> new_dictionary =
   3261         SeededNumberDictionary::AddNumberEntry(
   3262             dictionary, index, value, details,
   3263             object->map()->is_prototype_map());
   3264     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
   3265     if (*dictionary != *new_dictionary) {
   3266       FixedArray::cast(object->elements())->set(1, *new_dictionary);
   3267     }
   3268   }
   3269 
   3270   static void ReconfigureImpl(Handle<JSObject> object,
   3271                               Handle<FixedArrayBase> store, uint32_t entry,
   3272                               Handle<Object> value,
   3273                               PropertyAttributes attributes) {
   3274     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
   3275     uint32_t length = parameter_map->length() - 2;
   3276     Isolate* isolate = store->GetIsolate();
   3277     if (entry < length) {
   3278       Object* probe = parameter_map->get(entry + 2);
   3279       DCHECK(!probe->IsTheHole(isolate));
   3280       Context* context = Context::cast(parameter_map->get(0));
   3281       int context_entry = Smi::cast(probe)->value();
   3282       DCHECK(!context->get(context_entry)->IsTheHole(isolate));
   3283       context->set(context_entry, *value);
   3284 
   3285       // Redefining attributes of an aliased element destroys fast aliasing.
   3286       parameter_map->set_the_hole(entry + 2);
   3287       // For elements that are still writable we re-establish slow aliasing.
   3288       if ((attributes & READ_ONLY) == 0) {
   3289         value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
   3290       }
   3291 
   3292       PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
   3293       Handle<SeededNumberDictionary> arguments(
   3294           SeededNumberDictionary::cast(parameter_map->get(1)), isolate);
   3295       arguments = SeededNumberDictionary::AddNumberEntry(
   3296           arguments, entry, value, details, object->map()->is_prototype_map());
   3297       // If the attributes were NONE, we would have called set rather than
   3298       // reconfigure.
   3299       DCHECK_NE(NONE, attributes);
   3300       object->RequireSlowElements(*arguments);
   3301       parameter_map->set(1, *arguments);
   3302     } else {
   3303       Handle<FixedArrayBase> arguments(
   3304           FixedArrayBase::cast(parameter_map->get(1)), isolate);
   3305       DictionaryElementsAccessor::ReconfigureImpl(
   3306           object, arguments, entry - length, value, attributes);
   3307     }
   3308   }
   3309 };
   3310 
   3311 
   3312 class FastSloppyArgumentsElementsAccessor
   3313     : public SloppyArgumentsElementsAccessor<
   3314           FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
   3315           ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
   3316  public:
   3317   explicit FastSloppyArgumentsElementsAccessor(const char* name)
   3318       : SloppyArgumentsElementsAccessor<
   3319             FastSloppyArgumentsElementsAccessor,
   3320             FastHoleyObjectElementsAccessor,
   3321             ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
   3322 
   3323   static Handle<FixedArray> GetArguments(Isolate* isolate,
   3324                                          FixedArrayBase* backing_store) {
   3325     FixedArray* parameter_map = FixedArray::cast(backing_store);
   3326     return Handle<FixedArray>(FixedArray::cast(parameter_map->get(1)), isolate);
   3327   }
   3328 
   3329   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, uint32_t start,
   3330                                    uint32_t end) {
   3331     Isolate* isolate = receiver->GetIsolate();
   3332     uint32_t result_len = end < start ? 0u : end - start;
   3333     Handle<JSArray> result_array = isolate->factory()->NewJSArray(
   3334         FAST_HOLEY_ELEMENTS, result_len, result_len);
   3335     DisallowHeapAllocation no_gc;
   3336     FixedArray* elements = FixedArray::cast(result_array->elements());
   3337     FixedArray* parameters = FixedArray::cast(receiver->elements());
   3338     uint32_t insertion_index = 0;
   3339     for (uint32_t i = start; i < end; i++) {
   3340       uint32_t entry = GetEntryForIndexImpl(isolate, *receiver, parameters, i,
   3341                                             ALL_PROPERTIES);
   3342       if (entry != kMaxUInt32 && HasEntryImpl(isolate, parameters, entry)) {
   3343         elements->set(insertion_index, *GetImpl(parameters, entry));
   3344       } else {
   3345         elements->set_the_hole(insertion_index);
   3346       }
   3347       insertion_index++;
   3348     }
   3349     return result_array;
   3350   }
   3351 
   3352   static Handle<SeededNumberDictionary> NormalizeImpl(
   3353       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
   3354     Handle<FixedArray> arguments =
   3355         GetArguments(elements->GetIsolate(), *elements);
   3356     return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments);
   3357   }
   3358 
   3359   static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
   3360     Handle<FixedArray> arguments =
   3361         GetArguments(obj->GetIsolate(), obj->elements());
   3362     FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
   3363   }
   3364 
   3365   static void AddImpl(Handle<JSObject> object, uint32_t index,
   3366                       Handle<Object> value, PropertyAttributes attributes,
   3367                       uint32_t new_capacity) {
   3368     DCHECK_EQ(NONE, attributes);
   3369     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
   3370     Handle<FixedArrayBase> old_elements(
   3371         FixedArrayBase::cast(parameter_map->get(1)));
   3372     if (old_elements->IsSeededNumberDictionary() ||
   3373         static_cast<uint32_t>(old_elements->length()) < new_capacity) {
   3374       GrowCapacityAndConvertImpl(object, new_capacity);
   3375     }
   3376     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   3377     // For fast holey objects, the entry equals the index. The code above made
   3378     // sure that there's enough space to store the value. We cannot convert
   3379     // index to entry explicitly since the slot still contains the hole, so the
   3380     // current EntryForIndex would indicate that it is "absent" by returning
   3381     // kMaxUInt32.
   3382     FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
   3383   }
   3384 
   3385   static void ReconfigureImpl(Handle<JSObject> object,
   3386                               Handle<FixedArrayBase> store, uint32_t entry,
   3387                               Handle<Object> value,
   3388                               PropertyAttributes attributes) {
   3389     Handle<SeededNumberDictionary> dictionary =
   3390         JSObject::NormalizeElements(object);
   3391     FixedArray::cast(*store)->set(1, *dictionary);
   3392     uint32_t length = static_cast<uint32_t>(store->length()) - 2;
   3393     if (entry >= length) {
   3394       entry = dictionary->FindEntry(entry - length) + length;
   3395     }
   3396     SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
   3397                                                          value, attributes);
   3398   }
   3399 
   3400   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   3401                                FixedArrayBase* to, ElementsKind from_kind,
   3402                                uint32_t to_start, int packed_size,
   3403                                int copy_size) {
   3404     DCHECK(!to->IsDictionary());
   3405     if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
   3406       CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
   3407                                      to_start, copy_size);
   3408     } else {
   3409       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
   3410       CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
   3411                                  FAST_HOLEY_ELEMENTS, to_start, copy_size);
   3412     }
   3413   }
   3414 
   3415   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
   3416                                          uint32_t capacity) {
   3417     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
   3418     Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
   3419     ElementsKind from_kind = object->GetElementsKind();
   3420     // This method should only be called if there's a reason to update the
   3421     // elements.
   3422     DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
   3423            static_cast<uint32_t>(old_elements->length()) < capacity);
   3424     Handle<FixedArrayBase> elements =
   3425         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
   3426     Handle<Map> new_map = JSObject::GetElementsTransitionMap(
   3427         object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
   3428     JSObject::MigrateToMap(object, new_map);
   3429     parameter_map->set(1, *elements);
   3430     JSObject::ValidateElements(object);
   3431   }
   3432 };
   3433 
   3434 template <typename Subclass, typename BackingStoreAccessor, typename KindTraits>
   3435 class StringWrapperElementsAccessor
   3436     : public ElementsAccessorBase<Subclass, KindTraits> {
   3437  public:
   3438   explicit StringWrapperElementsAccessor(const char* name)
   3439       : ElementsAccessorBase<Subclass, KindTraits>(name) {
   3440     USE(KindTraits::Kind);
   3441   }
   3442 
   3443   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
   3444     Isolate* isolate = holder->GetIsolate();
   3445     Handle<String> string(GetString(*holder), isolate);
   3446     uint32_t length = static_cast<uint32_t>(string->length());
   3447     if (entry < length) {
   3448       return isolate->factory()->LookupSingleCharacterStringFromCode(
   3449           String::Flatten(string)->Get(entry));
   3450     }
   3451     return BackingStoreAccessor::GetImpl(holder, entry - length);
   3452   }
   3453 
   3454   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
   3455     uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
   3456     if (entry < length) {
   3457       PropertyAttributes attributes =
   3458           static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
   3459       return PropertyDetails(attributes, v8::internal::DATA, 0,
   3460                              PropertyCellType::kNoCell);
   3461     }
   3462     return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
   3463   }
   3464 
   3465   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
   3466                                        FixedArrayBase* backing_store,
   3467                                        uint32_t index, PropertyFilter filter) {
   3468     uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
   3469     if (index < length) return index;
   3470     uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl(
   3471         isolate, holder, backing_store, index, filter);
   3472     if (backing_store_entry == kMaxUInt32) return kMaxUInt32;
   3473     DCHECK(backing_store_entry < kMaxUInt32 - length);
   3474     return backing_store_entry + length;
   3475   }
   3476 
   3477   static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) {
   3478     uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
   3479     if (entry < length) {
   3480       return;  // String contents can't be deleted.
   3481     }
   3482     BackingStoreAccessor::DeleteImpl(holder, entry - length);
   3483   }
   3484 
   3485   static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) {
   3486     uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
   3487     if (entry < length) {
   3488       return;  // String contents are read-only.
   3489     }
   3490     BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value);
   3491   }
   3492 
   3493   static void AddImpl(Handle<JSObject> object, uint32_t index,
   3494                       Handle<Object> value, PropertyAttributes attributes,
   3495                       uint32_t new_capacity) {
   3496     DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length()));
   3497     // Explicitly grow fast backing stores if needed. Dictionaries know how to
   3498     // extend their capacity themselves.
   3499     if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
   3500         (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
   3501          BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
   3502              new_capacity)) {
   3503       GrowCapacityAndConvertImpl(object, new_capacity);
   3504     }
   3505     BackingStoreAccessor::AddImpl(object, index, value, attributes,
   3506                                   new_capacity);
   3507   }
   3508 
   3509   static void ReconfigureImpl(Handle<JSObject> object,
   3510                               Handle<FixedArrayBase> store, uint32_t entry,
   3511                               Handle<Object> value,
   3512                               PropertyAttributes attributes) {
   3513     uint32_t length = static_cast<uint32_t>(GetString(*object)->length());
   3514     if (entry < length) {
   3515       return;  // String contents can't be reconfigured.
   3516     }
   3517     BackingStoreAccessor::ReconfigureImpl(object, store, entry - length, value,
   3518                                           attributes);
   3519   }
   3520 
   3521   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
   3522                                               KeyAccumulator* accumulator,
   3523                                               AddKeyConversion convert) {
   3524     Isolate* isolate = receiver->GetIsolate();
   3525     Handle<String> string(GetString(*receiver), isolate);
   3526     string = String::Flatten(string);
   3527     uint32_t length = static_cast<uint32_t>(string->length());
   3528     for (uint32_t i = 0; i < length; i++) {
   3529       accumulator->AddKey(
   3530           isolate->factory()->LookupSingleCharacterStringFromCode(
   3531               string->Get(i)),
   3532           convert);
   3533     }
   3534     BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
   3535                                                           convert);
   3536   }
   3537 
   3538   static void CollectElementIndicesImpl(Handle<JSObject> object,
   3539                                         Handle<FixedArrayBase> backing_store,
   3540                                         KeyAccumulator* keys) {
   3541     uint32_t length = GetString(*object)->length();
   3542     Factory* factory = keys->isolate()->factory();
   3543     for (uint32_t i = 0; i < length; i++) {
   3544       keys->AddKey(factory->NewNumberFromUint(i));
   3545     }
   3546     BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store,
   3547                                                     keys);
   3548   }
   3549 
   3550   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
   3551                                          uint32_t capacity) {
   3552     Handle<FixedArrayBase> old_elements(object->elements());
   3553     ElementsKind from_kind = object->GetElementsKind();
   3554     // This method should only be called if there's a reason to update the
   3555     // elements.
   3556     DCHECK(from_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
   3557            static_cast<uint32_t>(old_elements->length()) < capacity);
   3558     Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
   3559                                               FAST_STRING_WRAPPER_ELEMENTS,
   3560                                               capacity);
   3561   }
   3562 
   3563   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   3564                                FixedArrayBase* to, ElementsKind from_kind,
   3565                                uint32_t to_start, int packed_size,
   3566                                int copy_size) {
   3567     DCHECK(!to->IsDictionary());
   3568     if (from_kind == SLOW_STRING_WRAPPER_ELEMENTS) {
   3569       CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
   3570                                      to_start, copy_size);
   3571     } else {
   3572       DCHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, from_kind);
   3573       CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
   3574                                  FAST_HOLEY_ELEMENTS, to_start, copy_size);
   3575     }
   3576   }
   3577 
   3578   static uint32_t NumberOfElementsImpl(JSObject* object,
   3579                                        FixedArrayBase* backing_store) {
   3580     uint32_t length = GetString(object)->length();
   3581     return length +
   3582            BackingStoreAccessor::NumberOfElementsImpl(object, backing_store);
   3583   }
   3584 
   3585  private:
   3586   static String* GetString(JSObject* holder) {
   3587     DCHECK(holder->IsJSValue());
   3588     JSValue* js_value = JSValue::cast(holder);
   3589     DCHECK(js_value->value()->IsString());
   3590     return String::cast(js_value->value());
   3591   }
   3592 };
   3593 
   3594 class FastStringWrapperElementsAccessor
   3595     : public StringWrapperElementsAccessor<
   3596           FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
   3597           ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
   3598  public:
   3599   explicit FastStringWrapperElementsAccessor(const char* name)
   3600       : StringWrapperElementsAccessor<
   3601             FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
   3602             ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
   3603 
   3604   static Handle<SeededNumberDictionary> NormalizeImpl(
   3605       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
   3606     return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
   3607   }
   3608 };
   3609 
   3610 class SlowStringWrapperElementsAccessor
   3611     : public StringWrapperElementsAccessor<
   3612           SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
   3613           ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
   3614  public:
   3615   explicit SlowStringWrapperElementsAccessor(const char* name)
   3616       : StringWrapperElementsAccessor<
   3617             SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
   3618             ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {}
   3619 
   3620   static bool HasAccessorsImpl(JSObject* holder,
   3621                                FixedArrayBase* backing_store) {
   3622     return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
   3623   }
   3624 };
   3625 
   3626 }  // namespace
   3627 
   3628 
   3629 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
   3630                      bool allow_appending) {
   3631   DisallowHeapAllocation no_allocation;
   3632   Object* raw_length = NULL;
   3633   const char* elements_type = "array";
   3634   if (obj->IsJSArray()) {
   3635     JSArray* array = JSArray::cast(*obj);
   3636     raw_length = array->length();
   3637   } else {
   3638     raw_length = Smi::FromInt(obj->elements()->length());
   3639     elements_type = "object";
   3640   }
   3641 
   3642   if (raw_length->IsNumber()) {
   3643     double n = raw_length->Number();
   3644     if (FastI2D(FastD2UI(n)) == n) {
   3645       int32_t int32_length = DoubleToInt32(n);
   3646       uint32_t compare_length = static_cast<uint32_t>(int32_length);
   3647       if (allow_appending) compare_length++;
   3648       if (index >= compare_length) {
   3649         PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
   3650                elements_type, op, elements_type, static_cast<int>(int32_length),
   3651                static_cast<int>(index));
   3652         TraceTopFrame(obj->GetIsolate());
   3653         PrintF("]\n");
   3654       }
   3655     } else {
   3656       PrintF("[%s elements length not integer value in ", elements_type);
   3657       TraceTopFrame(obj->GetIsolate());
   3658       PrintF("]\n");
   3659     }
   3660   } else {
   3661     PrintF("[%s elements length not a number in ", elements_type);
   3662     TraceTopFrame(obj->GetIsolate());
   3663     PrintF("]\n");
   3664   }
   3665 }
   3666 
   3667 
   3668 MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
   3669                                                      Arguments* args) {
   3670   if (args->length() == 0) {
   3671     // Optimize the case where there are no parameters passed.
   3672     JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
   3673     return array;
   3674 
   3675   } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
   3676     uint32_t length;
   3677     if (!args->at<Object>(0)->ToArrayLength(&length)) {
   3678       return ThrowArrayLengthRangeError(array->GetIsolate());
   3679     }
   3680 
   3681     // Optimize the case where there is one argument and the argument is a small
   3682     // smi.
   3683     if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
   3684       ElementsKind elements_kind = array->GetElementsKind();
   3685       JSArray::Initialize(array, length, length);
   3686 
   3687       if (!IsFastHoleyElementsKind(elements_kind)) {
   3688         elements_kind = GetHoleyElementsKind(elements_kind);
   3689         JSObject::TransitionElementsKind(array, elements_kind);
   3690       }
   3691     } else if (length == 0) {
   3692       JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
   3693     } else {
   3694       // Take the argument as the length.
   3695       JSArray::Initialize(array, 0);
   3696       JSArray::SetLength(array, length);
   3697     }
   3698     return array;
   3699   }
   3700 
   3701   Factory* factory = array->GetIsolate()->factory();
   3702 
   3703   // Set length and elements on the array.
   3704   int number_of_elements = args->length();
   3705   JSObject::EnsureCanContainElements(
   3706       array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
   3707 
   3708   // Allocate an appropriately typed elements array.
   3709   ElementsKind elements_kind = array->GetElementsKind();
   3710   Handle<FixedArrayBase> elms;
   3711   if (IsFastDoubleElementsKind(elements_kind)) {
   3712     elms = Handle<FixedArrayBase>::cast(
   3713         factory->NewFixedDoubleArray(number_of_elements));
   3714   } else {
   3715     elms = Handle<FixedArrayBase>::cast(
   3716         factory->NewFixedArrayWithHoles(number_of_elements));
   3717   }
   3718 
   3719   // Fill in the content
   3720   switch (elements_kind) {
   3721     case FAST_HOLEY_SMI_ELEMENTS:
   3722     case FAST_SMI_ELEMENTS: {
   3723       Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
   3724       for (int entry = 0; entry < number_of_elements; entry++) {
   3725         smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
   3726       }
   3727       break;
   3728     }
   3729     case FAST_HOLEY_ELEMENTS:
   3730     case FAST_ELEMENTS: {
   3731       DisallowHeapAllocation no_gc;
   3732       WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
   3733       Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
   3734       for (int entry = 0; entry < number_of_elements; entry++) {
   3735         object_elms->set(entry, (*args)[entry], mode);
   3736       }
   3737       break;
   3738     }
   3739     case FAST_HOLEY_DOUBLE_ELEMENTS:
   3740     case FAST_DOUBLE_ELEMENTS: {
   3741       Handle<FixedDoubleArray> double_elms =
   3742           Handle<FixedDoubleArray>::cast(elms);
   3743       for (int entry = 0; entry < number_of_elements; entry++) {
   3744         double_elms->set(entry, (*args)[entry]->Number());
   3745       }
   3746       break;
   3747     }
   3748     default:
   3749       UNREACHABLE();
   3750       break;
   3751   }
   3752 
   3753   array->set_elements(*elms);
   3754   array->set_length(Smi::FromInt(number_of_elements));
   3755   return array;
   3756 }
   3757 
   3758 
   3759 void ElementsAccessor::InitializeOncePerProcess() {
   3760   static ElementsAccessor* accessor_array[] = {
   3761 #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
   3762       ELEMENTS_LIST(ACCESSOR_ARRAY)
   3763 #undef ACCESSOR_ARRAY
   3764   };
   3765 
   3766   STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
   3767                 kElementsKindCount);
   3768 
   3769   elements_accessors_ = accessor_array;
   3770 }
   3771 
   3772 
   3773 void ElementsAccessor::TearDown() {
   3774   if (elements_accessors_ == NULL) return;
   3775 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
   3776   ELEMENTS_LIST(ACCESSOR_DELETE)
   3777 #undef ACCESSOR_DELETE
   3778   elements_accessors_ = NULL;
   3779 }
   3780 
   3781 Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
   3782                                          uint32_t concat_size,
   3783                                          uint32_t result_len) {
   3784   ElementsKind result_elements_kind = GetInitialFastElementsKind();
   3785   bool has_raw_doubles = false;
   3786   {
   3787     DisallowHeapAllocation no_gc;
   3788     bool is_holey = false;
   3789     for (uint32_t i = 0; i < concat_size; i++) {
   3790       Object* arg = (*args)[i];
   3791       ElementsKind arg_kind = JSArray::cast(arg)->GetElementsKind();
   3792       has_raw_doubles = has_raw_doubles || IsFastDoubleElementsKind(arg_kind);
   3793       is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
   3794       result_elements_kind =
   3795           GetMoreGeneralElementsKind(result_elements_kind, arg_kind);
   3796     }
   3797     if (is_holey) {
   3798       result_elements_kind = GetHoleyElementsKind(result_elements_kind);
   3799     }
   3800   }
   3801 
   3802   // If a double array is concatted into a fast elements array, the fast
   3803   // elements array needs to be initialized to contain proper holes, since
   3804   // boxing doubles may cause incremental marking.
   3805   bool requires_double_boxing =
   3806       has_raw_doubles && !IsFastDoubleElementsKind(result_elements_kind);
   3807   ArrayStorageAllocationMode mode = requires_double_boxing
   3808                                         ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
   3809                                         : DONT_INITIALIZE_ARRAY_ELEMENTS;
   3810   Handle<JSArray> result_array = isolate->factory()->NewJSArray(
   3811       result_elements_kind, result_len, result_len, mode);
   3812   if (result_len == 0) return result_array;
   3813 
   3814   uint32_t insertion_index = 0;
   3815   Handle<FixedArrayBase> storage(result_array->elements(), isolate);
   3816   ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind);
   3817   for (uint32_t i = 0; i < concat_size; i++) {
   3818     // It is crucial to keep |array| in a raw pointer form to avoid
   3819     // performance degradation.
   3820     JSArray* array = JSArray::cast((*args)[i]);
   3821     uint32_t len = 0;
   3822     array->length()->ToArrayLength(&len);
   3823     if (len == 0) continue;
   3824     ElementsKind from_kind = array->GetElementsKind();
   3825     accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len);
   3826     insertion_index += len;
   3827   }
   3828 
   3829   DCHECK_EQ(insertion_index, result_len);
   3830   return result_array;
   3831 }
   3832 
   3833 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
   3834 }  // namespace internal
   3835 }  // namespace v8
   3836