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