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/messages.h"
     11 #include "src/objects-inl.h"
     12 #include "src/utils.h"
     13 
     14 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
     15 // several abstract ElementsAccessor classes are used to allow sharing
     16 // common code.
     17 //
     18 // Inheritance hierarchy:
     19 // - ElementsAccessorBase                        (abstract)
     20 //   - FastElementsAccessor                      (abstract)
     21 //     - FastSmiOrObjectElementsAccessor
     22 //       - FastPackedSmiElementsAccessor
     23 //       - FastHoleySmiElementsAccessor
     24 //       - FastPackedObjectElementsAccessor
     25 //       - FastHoleyObjectElementsAccessor
     26 //     - FastDoubleElementsAccessor
     27 //       - FastPackedDoubleElementsAccessor
     28 //       - FastHoleyDoubleElementsAccessor
     29 //   - TypedElementsAccessor: template, with instantiations:
     30 //     - FixedUint8ElementsAccessor
     31 //     - FixedInt8ElementsAccessor
     32 //     - FixedUint16ElementsAccessor
     33 //     - FixedInt16ElementsAccessor
     34 //     - FixedUint32ElementsAccessor
     35 //     - FixedInt32ElementsAccessor
     36 //     - FixedFloat32ElementsAccessor
     37 //     - FixedFloat64ElementsAccessor
     38 //     - FixedUint8ClampedElementsAccessor
     39 //   - DictionaryElementsAccessor
     40 //   - SloppyArgumentsElementsAccessor
     41 //     - FastSloppyArgumentsElementsAccessor
     42 //     - SlowSloppyArgumentsElementsAccessor
     43 
     44 
     45 namespace v8 {
     46 namespace internal {
     47 
     48 
     49 namespace {
     50 
     51 
     52 static const int kPackedSizeNotKnown = -1;
     53 
     54 enum Where { AT_START, AT_END };
     55 
     56 
     57 // First argument in list is the accessor class, the second argument is the
     58 // accessor ElementsKind, and the third is the backing store class.  Use the
     59 // fast element handler for smi-only arrays.  The implementation is currently
     60 // identical.  Note that the order must match that of the ElementsKind enum for
     61 // the |accessor_array[]| below to work.
     62 #define ELEMENTS_LIST(V)                                                      \
     63   V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray)             \
     64   V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray)        \
     65   V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray)              \
     66   V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray)         \
     67   V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
     68   V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS,              \
     69     FixedDoubleArray)                                                         \
     70   V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary)  \
     71   V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS,      \
     72     FixedArray)                                                               \
     73   V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS,      \
     74     FixedArray)                                                               \
     75   V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array)              \
     76   V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array)                 \
     77   V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array)           \
     78   V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array)              \
     79   V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array)           \
     80   V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array)              \
     81   V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array)        \
     82   V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array)        \
     83   V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS,                \
     84     FixedUint8ClampedArray)
     85 
     86 
     87 template<ElementsKind Kind> class ElementsKindTraits {
     88  public:
     89   typedef FixedArrayBase BackingStore;
     90 };
     91 
     92 #define ELEMENTS_TRAITS(Class, KindParam, Store)               \
     93 template<> class ElementsKindTraits<KindParam> {               \
     94  public:   /* NOLINT */                                        \
     95   static const ElementsKind Kind = KindParam;                  \
     96   typedef Store BackingStore;                                  \
     97 };
     98 ELEMENTS_LIST(ELEMENTS_TRAITS)
     99 #undef ELEMENTS_TRAITS
    100 
    101 
    102 MUST_USE_RESULT
    103 MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
    104   THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
    105                   Object);
    106 }
    107 
    108 
    109 void CopyObjectToObjectElements(FixedArrayBase* from_base,
    110                                 ElementsKind from_kind, uint32_t from_start,
    111                                 FixedArrayBase* to_base, ElementsKind to_kind,
    112                                 uint32_t to_start, int raw_copy_size) {
    113   DCHECK(to_base->map() !=
    114       from_base->GetIsolate()->heap()->fixed_cow_array_map());
    115   DisallowHeapAllocation no_allocation;
    116   int copy_size = raw_copy_size;
    117   if (raw_copy_size < 0) {
    118     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    119            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    120     copy_size = Min(from_base->length() - from_start,
    121                     to_base->length() - to_start);
    122     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    123       int start = to_start + copy_size;
    124       int length = to_base->length() - start;
    125       if (length > 0) {
    126         Heap* heap = from_base->GetHeap();
    127         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
    128                       heap->the_hole_value(), length);
    129       }
    130     }
    131   }
    132   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    133          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    134   if (copy_size == 0) return;
    135   FixedArray* from = FixedArray::cast(from_base);
    136   FixedArray* to = FixedArray::cast(to_base);
    137   DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
    138   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
    139 
    140   WriteBarrierMode write_barrier_mode =
    141       (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
    142           ? UPDATE_WRITE_BARRIER
    143           : SKIP_WRITE_BARRIER;
    144   for (int i = 0; i < copy_size; i++) {
    145     Object* value = from->get(from_start + i);
    146     to->set(to_start + i, value, write_barrier_mode);
    147   }
    148 }
    149 
    150 
    151 static void CopyDictionaryToObjectElements(
    152     FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
    153     ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
    154   DisallowHeapAllocation no_allocation;
    155   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
    156   int copy_size = raw_copy_size;
    157   if (raw_copy_size < 0) {
    158     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    159            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    160     copy_size = from->max_number_key() + 1 - from_start;
    161     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    162       int start = to_start + copy_size;
    163       int length = to_base->length() - start;
    164       if (length > 0) {
    165         Heap* heap = from->GetHeap();
    166         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
    167                       heap->the_hole_value(), length);
    168       }
    169     }
    170   }
    171   DCHECK(to_base != from_base);
    172   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
    173   if (copy_size == 0) return;
    174   FixedArray* to = FixedArray::cast(to_base);
    175   uint32_t to_length = to->length();
    176   if (to_start + copy_size > to_length) {
    177     copy_size = to_length - to_start;
    178   }
    179   WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
    180                                             ? UPDATE_WRITE_BARRIER
    181                                             : SKIP_WRITE_BARRIER;
    182   for (int i = 0; i < copy_size; i++) {
    183     int entry = from->FindEntry(i + from_start);
    184     if (entry != SeededNumberDictionary::kNotFound) {
    185       Object* value = from->ValueAt(entry);
    186       DCHECK(!value->IsTheHole());
    187       to->set(i + to_start, value, write_barrier_mode);
    188     } else {
    189       to->set_the_hole(i + to_start);
    190     }
    191   }
    192 }
    193 
    194 
    195 // NOTE: this method violates the handlified function signature convention:
    196 // raw pointer parameters in the function that allocates.
    197 // See ElementsAccessorBase::CopyElements() for details.
    198 static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
    199                                        uint32_t from_start,
    200                                        FixedArrayBase* to_base,
    201                                        uint32_t to_start, int raw_copy_size) {
    202   int copy_size = raw_copy_size;
    203   if (raw_copy_size < 0) {
    204     DisallowHeapAllocation no_allocation;
    205     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    206            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    207     copy_size = Min(from_base->length() - from_start,
    208                     to_base->length() - to_start);
    209     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    210       // Also initialize the area that will be copied over since HeapNumber
    211       // allocation below can cause an incremental marking step, requiring all
    212       // existing heap objects to be propertly initialized.
    213       int start = to_start;
    214       int length = to_base->length() - start;
    215       if (length > 0) {
    216         Heap* heap = from_base->GetHeap();
    217         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
    218                       heap->the_hole_value(), length);
    219       }
    220     }
    221   }
    222 
    223   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    224          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    225   if (copy_size == 0) return;
    226 
    227   // From here on, the code below could actually allocate. Therefore the raw
    228   // values are wrapped into handles.
    229   Isolate* isolate = from_base->GetIsolate();
    230   Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
    231   Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
    232 
    233   // create an outer loop to not waste too much time on creating HandleScopes
    234   // on the other hand we might overflow a single handle scope depending on
    235   // the copy_size
    236   int offset = 0;
    237   while (offset < copy_size) {
    238     HandleScope scope(isolate);
    239     offset += 100;
    240     for (int i = offset - 100; i < offset && i < copy_size; ++i) {
    241       Handle<Object> value = FixedDoubleArray::get(from, i + from_start);
    242       to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
    243     }
    244   }
    245 }
    246 
    247 
    248 static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
    249                                        uint32_t from_start,
    250                                        FixedArrayBase* to_base,
    251                                        uint32_t to_start, int raw_copy_size) {
    252   DisallowHeapAllocation no_allocation;
    253   int copy_size = raw_copy_size;
    254   if (raw_copy_size < 0) {
    255     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    256            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    257     copy_size = Min(from_base->length() - from_start,
    258                     to_base->length() - to_start);
    259     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    260       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    261         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    262       }
    263     }
    264   }
    265   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    266          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    267   if (copy_size == 0) return;
    268   FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
    269   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    270   Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
    271   Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
    272   to_address += kDoubleSize * to_start;
    273   from_address += kDoubleSize * from_start;
    274   int words_per_double = (kDoubleSize / kPointerSize);
    275   CopyWords(reinterpret_cast<Object**>(to_address),
    276             reinterpret_cast<Object**>(from_address),
    277             static_cast<size_t>(words_per_double * copy_size));
    278 }
    279 
    280 
    281 static void CopySmiToDoubleElements(FixedArrayBase* from_base,
    282                                     uint32_t from_start,
    283                                     FixedArrayBase* to_base, uint32_t to_start,
    284                                     int raw_copy_size) {
    285   DisallowHeapAllocation no_allocation;
    286   int copy_size = raw_copy_size;
    287   if (raw_copy_size < 0) {
    288     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    289            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    290     copy_size = from_base->length() - from_start;
    291     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    292       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    293         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    294       }
    295     }
    296   }
    297   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    298          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    299   if (copy_size == 0) return;
    300   FixedArray* from = FixedArray::cast(from_base);
    301   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    302   Object* the_hole = from->GetHeap()->the_hole_value();
    303   for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
    304        from_start < from_end; from_start++, to_start++) {
    305     Object* hole_or_smi = from->get(from_start);
    306     if (hole_or_smi == the_hole) {
    307       to->set_the_hole(to_start);
    308     } else {
    309       to->set(to_start, Smi::cast(hole_or_smi)->value());
    310     }
    311   }
    312 }
    313 
    314 
    315 static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
    316                                           uint32_t from_start,
    317                                           FixedArrayBase* to_base,
    318                                           uint32_t to_start, int packed_size,
    319                                           int raw_copy_size) {
    320   DisallowHeapAllocation no_allocation;
    321   int copy_size = raw_copy_size;
    322   uint32_t to_end;
    323   if (raw_copy_size < 0) {
    324     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    325            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    326     copy_size = packed_size - from_start;
    327     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    328       to_end = to_base->length();
    329       for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
    330         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    331       }
    332     } else {
    333       to_end = to_start + static_cast<uint32_t>(copy_size);
    334     }
    335   } else {
    336     to_end = to_start + static_cast<uint32_t>(copy_size);
    337   }
    338   DCHECK(static_cast<int>(to_end) <= to_base->length());
    339   DCHECK(packed_size >= 0 && packed_size <= copy_size);
    340   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    341          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    342   if (copy_size == 0) return;
    343   FixedArray* from = FixedArray::cast(from_base);
    344   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    345   for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
    346        from_start < from_end; from_start++, to_start++) {
    347     Object* smi = from->get(from_start);
    348     DCHECK(!smi->IsTheHole());
    349     to->set(to_start, Smi::cast(smi)->value());
    350   }
    351 }
    352 
    353 
    354 static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
    355                                        uint32_t from_start,
    356                                        FixedArrayBase* to_base,
    357                                        uint32_t to_start, int raw_copy_size) {
    358   DisallowHeapAllocation no_allocation;
    359   int copy_size = raw_copy_size;
    360   if (raw_copy_size < 0) {
    361     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    362            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    363     copy_size = from_base->length() - from_start;
    364     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    365       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    366         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    367       }
    368     }
    369   }
    370   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    371          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    372   if (copy_size == 0) return;
    373   FixedArray* from = FixedArray::cast(from_base);
    374   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    375   Object* the_hole = from->GetHeap()->the_hole_value();
    376   for (uint32_t from_end = from_start + copy_size;
    377        from_start < from_end; from_start++, to_start++) {
    378     Object* hole_or_object = from->get(from_start);
    379     if (hole_or_object == the_hole) {
    380       to->set_the_hole(to_start);
    381     } else {
    382       to->set(to_start, hole_or_object->Number());
    383     }
    384   }
    385 }
    386 
    387 
    388 static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
    389                                            uint32_t from_start,
    390                                            FixedArrayBase* to_base,
    391                                            uint32_t to_start,
    392                                            int raw_copy_size) {
    393   DisallowHeapAllocation no_allocation;
    394   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
    395   int copy_size = raw_copy_size;
    396   if (copy_size < 0) {
    397     DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
    398            copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    399     copy_size = from->max_number_key() + 1 - from_start;
    400     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    401       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    402         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    403       }
    404     }
    405   }
    406   if (copy_size == 0) return;
    407   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    408   uint32_t to_length = to->length();
    409   if (to_start + copy_size > to_length) {
    410     copy_size = to_length - to_start;
    411   }
    412   for (int i = 0; i < copy_size; i++) {
    413     int entry = from->FindEntry(i + from_start);
    414     if (entry != SeededNumberDictionary::kNotFound) {
    415       to->set(i + to_start, from->ValueAt(entry)->Number());
    416     } else {
    417       to->set_the_hole(i + to_start);
    418     }
    419   }
    420 }
    421 
    422 
    423 static void TraceTopFrame(Isolate* isolate) {
    424   StackFrameIterator it(isolate);
    425   if (it.done()) {
    426     PrintF("unknown location (no JavaScript frames present)");
    427     return;
    428   }
    429   StackFrame* raw_frame = it.frame();
    430   if (raw_frame->is_internal()) {
    431     Code* apply_builtin =
    432         isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
    433     if (raw_frame->unchecked_code() == apply_builtin) {
    434       PrintF("apply from ");
    435       it.Advance();
    436       raw_frame = it.frame();
    437     }
    438   }
    439   JavaScriptFrame::PrintTop(isolate, stdout, false, true);
    440 }
    441 
    442 
    443 // Base class for element handler implementations. Contains the
    444 // the common logic for objects with different ElementsKinds.
    445 // Subclasses must specialize method for which the element
    446 // implementation differs from the base class implementation.
    447 //
    448 // This class is intended to be used in the following way:
    449 //
    450 //   class SomeElementsAccessor :
    451 //       public ElementsAccessorBase<SomeElementsAccessor,
    452 //                                   BackingStoreClass> {
    453 //     ...
    454 //   }
    455 //
    456 // This is an example of the Curiously Recurring Template Pattern (see
    457 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).  We use
    458 // CRTP to guarantee aggressive compile time optimizations (i.e.  inlining and
    459 // specialization of SomeElementsAccessor methods).
    460 template <typename ElementsAccessorSubclass,
    461           typename ElementsTraitsParam>
    462 class ElementsAccessorBase : public ElementsAccessor {
    463  public:
    464   explicit ElementsAccessorBase(const char* name)
    465       : ElementsAccessor(name) { }
    466 
    467   typedef ElementsTraitsParam ElementsTraits;
    468   typedef typename ElementsTraitsParam::BackingStore BackingStore;
    469 
    470   static ElementsKind kind() { return ElementsTraits::Kind; }
    471 
    472   static void ValidateContents(Handle<JSObject> holder, int length) {
    473   }
    474 
    475   static void ValidateImpl(Handle<JSObject> holder) {
    476     Handle<FixedArrayBase> fixed_array_base(holder->elements());
    477     if (!fixed_array_base->IsHeapObject()) return;
    478     // Arrays that have been shifted in place can't be verified.
    479     if (fixed_array_base->IsFiller()) return;
    480     int length = 0;
    481     if (holder->IsJSArray()) {
    482       Object* length_obj = Handle<JSArray>::cast(holder)->length();
    483       if (length_obj->IsSmi()) {
    484         length = Smi::cast(length_obj)->value();
    485       }
    486     } else {
    487       length = fixed_array_base->length();
    488     }
    489     ElementsAccessorSubclass::ValidateContents(holder, length);
    490   }
    491 
    492   void Validate(Handle<JSObject> holder) final {
    493     DisallowHeapAllocation no_gc;
    494     ElementsAccessorSubclass::ValidateImpl(holder);
    495   }
    496 
    497   bool IsPacked(Handle<JSObject> holder, Handle<FixedArrayBase> backing_store,
    498                 uint32_t start, uint32_t end) final {
    499     return ElementsAccessorSubclass::IsPackedImpl(holder, backing_store, start,
    500                                                   end);
    501   }
    502 
    503   static bool IsPackedImpl(Handle<JSObject> holder,
    504                            Handle<FixedArrayBase> backing_store, uint32_t start,
    505                            uint32_t end) {
    506     if (IsFastPackedElementsKind(kind())) return true;
    507     for (uint32_t i = start; i < end; i++) {
    508       if (!ElementsAccessorSubclass::HasElementImpl(holder, i, backing_store,
    509                                                     ALL_PROPERTIES)) {
    510         return false;
    511       }
    512     }
    513     return true;
    514   }
    515 
    516   static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
    517     if (!IsHoleyElementsKind(kind())) return;
    518     int length = Smi::cast(array->length())->value();
    519     Handle<FixedArrayBase> backing_store(array->elements());
    520     if (!ElementsAccessorSubclass::IsPackedImpl(array, backing_store, 0,
    521                                                 length)) {
    522       return;
    523     }
    524     ElementsKind packed_kind = GetPackedElementsKind(kind());
    525     Handle<Map> new_map =
    526         JSObject::GetElementsTransitionMap(array, packed_kind);
    527     JSObject::MigrateToMap(array, new_map);
    528     if (FLAG_trace_elements_transitions) {
    529       JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
    530                                         packed_kind, backing_store);
    531     }
    532   }
    533 
    534   bool HasElement(Handle<JSObject> holder, uint32_t index,
    535                   Handle<FixedArrayBase> backing_store,
    536                   PropertyFilter filter) final {
    537     return ElementsAccessorSubclass::HasElementImpl(holder, index,
    538                                                     backing_store, filter);
    539   }
    540 
    541   static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
    542                              Handle<FixedArrayBase> backing_store,
    543                              PropertyFilter filter) {
    544     return ElementsAccessorSubclass::GetEntryForIndexImpl(
    545                *holder, *backing_store, index, filter) != kMaxUInt32;
    546   }
    547 
    548   Handle<Object> Get(Handle<FixedArrayBase> backing_store,
    549                      uint32_t entry) final {
    550     return ElementsAccessorSubclass::GetImpl(backing_store, entry);
    551   }
    552 
    553   static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
    554                                 uint32_t entry) {
    555     uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
    556     return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
    557   }
    558 
    559   void Set(FixedArrayBase* backing_store, uint32_t entry, Object* value) final {
    560     ElementsAccessorSubclass::SetImpl(backing_store, entry, value);
    561   }
    562 
    563   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
    564                              Object* value) {
    565     UNREACHABLE();
    566   }
    567 
    568 
    569   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
    570                              Object* value, WriteBarrierMode mode) {
    571     UNREACHABLE();
    572   }
    573 
    574   void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
    575                    uint32_t entry, Handle<Object> value,
    576                    PropertyAttributes attributes) final {
    577     ElementsAccessorSubclass::ReconfigureImpl(object, store, entry, value,
    578                                               attributes);
    579   }
    580 
    581   static void ReconfigureImpl(Handle<JSObject> object,
    582                               Handle<FixedArrayBase> store, uint32_t entry,
    583                               Handle<Object> value,
    584                               PropertyAttributes attributes) {
    585     UNREACHABLE();
    586   }
    587 
    588   void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
    589            PropertyAttributes attributes, uint32_t new_capacity) final {
    590     ElementsAccessorSubclass::AddImpl(object, index, value, attributes,
    591                                       new_capacity);
    592   }
    593 
    594   static void AddImpl(Handle<JSObject> object, uint32_t index,
    595                       Handle<Object> value, PropertyAttributes attributes,
    596                       uint32_t new_capacity) {
    597     UNREACHABLE();
    598   }
    599 
    600   uint32_t Push(Handle<JSArray> receiver, Handle<FixedArrayBase> backing_store,
    601                 Arguments* args, uint32_t push_size) final {
    602     return ElementsAccessorSubclass::PushImpl(receiver, backing_store, args,
    603                                               push_size);
    604   }
    605 
    606   static uint32_t PushImpl(Handle<JSArray> receiver,
    607                            Handle<FixedArrayBase> elms_obj, Arguments* args,
    608                            uint32_t push_sized) {
    609     UNREACHABLE();
    610     return 0;
    611   }
    612 
    613   uint32_t Unshift(Handle<JSArray> receiver,
    614                    Handle<FixedArrayBase> backing_store, Arguments* args,
    615                    uint32_t unshift_size) final {
    616     return ElementsAccessorSubclass::UnshiftImpl(receiver, backing_store, args,
    617                                                  unshift_size);
    618   }
    619 
    620   static uint32_t UnshiftImpl(Handle<JSArray> receiver,
    621                               Handle<FixedArrayBase> elms_obj, Arguments* args,
    622                               uint32_t unshift_size) {
    623     UNREACHABLE();
    624     return 0;
    625   }
    626 
    627   Handle<JSArray> Slice(Handle<JSObject> receiver,
    628                         Handle<FixedArrayBase> backing_store, uint32_t start,
    629                         uint32_t end) final {
    630     return ElementsAccessorSubclass::SliceImpl(receiver, backing_store, start,
    631                                                end);
    632   }
    633 
    634   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
    635                                    Handle<FixedArrayBase> backing_store,
    636                                    uint32_t start, uint32_t end) {
    637     UNREACHABLE();
    638     return Handle<JSArray>();
    639   }
    640 
    641   Handle<JSArray> Splice(Handle<JSArray> receiver,
    642                          Handle<FixedArrayBase> backing_store, uint32_t start,
    643                          uint32_t delete_count, Arguments* args,
    644                          uint32_t add_count) final {
    645     return ElementsAccessorSubclass::SpliceImpl(receiver, backing_store, start,
    646                                                 delete_count, args, add_count);
    647   }
    648 
    649   static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
    650                                     Handle<FixedArrayBase> backing_store,
    651                                     uint32_t start, uint32_t delete_count,
    652                                     Arguments* args, uint32_t add_count) {
    653     UNREACHABLE();
    654     return Handle<JSArray>();
    655   }
    656 
    657   Handle<Object> Pop(Handle<JSArray> receiver,
    658                      Handle<FixedArrayBase> backing_store) final {
    659     return ElementsAccessorSubclass::PopImpl(receiver, backing_store);
    660   }
    661 
    662   static Handle<Object> PopImpl(Handle<JSArray> receiver,
    663                                 Handle<FixedArrayBase> backing_store) {
    664     UNREACHABLE();
    665     return Handle<Object>();
    666   }
    667 
    668   Handle<Object> Shift(Handle<JSArray> receiver,
    669                        Handle<FixedArrayBase> backing_store) final {
    670     return ElementsAccessorSubclass::ShiftImpl(receiver, backing_store);
    671   }
    672 
    673   static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
    674                                   Handle<FixedArrayBase> backing_store) {
    675     UNREACHABLE();
    676     return Handle<Object>();
    677   }
    678 
    679   void SetLength(Handle<JSArray> array, uint32_t length) final {
    680     ElementsAccessorSubclass::SetLengthImpl(array->GetIsolate(), array, length,
    681                                             handle(array->elements()));
    682   }
    683 
    684   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
    685                             uint32_t length,
    686                             Handle<FixedArrayBase> backing_store) {
    687     DCHECK(!array->SetLengthWouldNormalize(length));
    688     DCHECK(IsFastElementsKind(array->GetElementsKind()));
    689     uint32_t old_length = 0;
    690     CHECK(array->length()->ToArrayIndex(&old_length));
    691 
    692     if (old_length < length) {
    693       ElementsKind kind = array->GetElementsKind();
    694       if (!IsFastHoleyElementsKind(kind)) {
    695         kind = GetHoleyElementsKind(kind);
    696         JSObject::TransitionElementsKind(array, kind);
    697       }
    698     }
    699 
    700     // Check whether the backing store should be shrunk.
    701     uint32_t capacity = backing_store->length();
    702     old_length = Min(old_length, capacity);
    703     if (length == 0) {
    704       array->initialize_elements();
    705     } else if (length <= capacity) {
    706       if (array->HasFastSmiOrObjectElements()) {
    707         backing_store = JSObject::EnsureWritableFastElements(array);
    708       }
    709       if (2 * length <= capacity) {
    710         // If more than half the elements won't be used, trim the array.
    711         isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
    712             *backing_store, capacity - length);
    713       } else {
    714         // Otherwise, fill the unused tail with holes.
    715         for (uint32_t i = length; i < old_length; i++) {
    716           BackingStore::cast(*backing_store)->set_the_hole(i);
    717         }
    718       }
    719     } else {
    720       // Check whether the backing store should be expanded.
    721       capacity = Max(length, JSObject::NewElementsCapacity(capacity));
    722       ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity);
    723     }
    724 
    725     array->set_length(Smi::FromInt(length));
    726     JSObject::ValidateElements(array);
    727   }
    728 
    729   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
    730       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
    731       ElementsKind from_kind, uint32_t capacity) {
    732     return ConvertElementsWithCapacity(
    733         object, old_elements, from_kind, capacity, 0, 0,
    734         ElementsAccessor::kCopyToEndAndInitializeToHole);
    735   }
    736 
    737   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
    738       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
    739       ElementsKind from_kind, uint32_t capacity, int copy_size) {
    740     return ConvertElementsWithCapacity(object, old_elements, from_kind,
    741                                        capacity, 0, 0, copy_size);
    742   }
    743 
    744   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
    745       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
    746       ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
    747       uint32_t dst_index, int copy_size) {
    748     Isolate* isolate = object->GetIsolate();
    749     Handle<FixedArrayBase> new_elements;
    750     if (IsFastDoubleElementsKind(kind())) {
    751       new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
    752     } else {
    753       new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
    754     }
    755 
    756     int packed_size = kPackedSizeNotKnown;
    757     if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
    758       packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
    759     }
    760 
    761     ElementsAccessorSubclass::CopyElementsImpl(
    762         *old_elements, src_index, *new_elements, from_kind, dst_index,
    763         packed_size, copy_size);
    764 
    765     return new_elements;
    766   }
    767 
    768   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
    769                                          uint32_t capacity) {
    770     ElementsKind from_kind = object->GetElementsKind();
    771     if (IsFastSmiOrObjectElementsKind(from_kind)) {
    772       // Array optimizations rely on the prototype lookups of Array objects
    773       // always returning undefined. If there is a store to the initial
    774       // prototype object, make sure all of these optimizations are invalidated.
    775       object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
    776     }
    777     Handle<FixedArrayBase> old_elements(object->elements());
    778     // This method should only be called if there's a reason to update the
    779     // elements.
    780     DCHECK(IsFastDoubleElementsKind(from_kind) !=
    781                IsFastDoubleElementsKind(kind()) ||
    782            IsDictionaryElementsKind(from_kind) ||
    783            static_cast<uint32_t>(old_elements->length()) < capacity);
    784     Handle<FixedArrayBase> elements =
    785         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
    786 
    787     ElementsKind to_kind = kind();
    788     if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
    789     Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
    790     JSObject::SetMapAndElements(object, new_map, elements);
    791 
    792     // Transition through the allocation site as well if present.
    793     JSObject::UpdateAllocationSite(object, to_kind);
    794 
    795     if (FLAG_trace_elements_transitions) {
    796       JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
    797                                         to_kind, elements);
    798     }
    799   }
    800 
    801   void GrowCapacityAndConvert(Handle<JSObject> object,
    802                               uint32_t capacity) final {
    803     ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity);
    804   }
    805 
    806   void Delete(Handle<JSObject> obj, uint32_t entry) final {
    807     ElementsAccessorSubclass::DeleteImpl(obj, entry);
    808   }
    809 
    810   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
    811                                FixedArrayBase* to, ElementsKind from_kind,
    812                                uint32_t to_start, int packed_size,
    813                                int copy_size) {
    814     UNREACHABLE();
    815   }
    816 
    817   void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start,
    818                     ElementsKind from_kind, Handle<FixedArrayBase> to,
    819                     uint32_t to_start, int copy_size) final {
    820     DCHECK(!from.is_null());
    821     // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
    822     // violate the handlified function signature convention:
    823     // raw pointer parameters in the function that allocates. This is done
    824     // intentionally to avoid ArrayConcat() builtin performance degradation.
    825     // See the comment in another ElementsAccessorBase::CopyElements() for
    826     // details.
    827     ElementsAccessorSubclass::CopyElementsImpl(*from, from_start, *to,
    828                                                from_kind, to_start,
    829                                                kPackedSizeNotKnown, copy_size);
    830   }
    831 
    832   void CopyElements(JSObject* from_holder, uint32_t from_start,
    833                     ElementsKind from_kind, Handle<FixedArrayBase> to,
    834                     uint32_t to_start, int copy_size) final {
    835     int packed_size = kPackedSizeNotKnown;
    836     bool is_packed = IsFastPackedElementsKind(from_kind) &&
    837         from_holder->IsJSArray();
    838     if (is_packed) {
    839       packed_size =
    840           Smi::cast(JSArray::cast(from_holder)->length())->value();
    841       if (copy_size >= 0 && packed_size > copy_size) {
    842         packed_size = copy_size;
    843       }
    844     }
    845     FixedArrayBase* from = from_holder->elements();
    846     // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
    847     // violate the handlified function signature convention:
    848     // raw pointer parameters in the function that allocates. This is done
    849     // intentionally to avoid ArrayConcat() builtin performance degradation.
    850     //
    851     // Details: The idea is that allocations actually happen only in case of
    852     // copying from object with fast double elements to object with object
    853     // elements. In all the other cases there are no allocations performed and
    854     // handle creation causes noticeable performance degradation of the builtin.
    855     ElementsAccessorSubclass::CopyElementsImpl(
    856         from, from_start, *to, from_kind, to_start, packed_size, copy_size);
    857   }
    858 
    859   static void CollectElementIndicesImpl(Handle<JSObject> object,
    860                                         Handle<FixedArrayBase> backing_store,
    861                                         KeyAccumulator* keys, uint32_t range,
    862                                         PropertyFilter filter,
    863                                         uint32_t offset) {
    864     if (filter & ONLY_ALL_CAN_READ) {
    865       // Non-dictionary elements can't have all-can-read accessors.
    866       return;
    867     }
    868     uint32_t length = 0;
    869     if (object->IsJSArray()) {
    870       length = Smi::cast(JSArray::cast(*object)->length())->value();
    871     } else {
    872       length =
    873           ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
    874     }
    875     if (range < length) length = range;
    876     for (uint32_t i = offset; i < length; i++) {
    877       if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
    878                                                     filter))
    879         continue;
    880       keys->AddKey(i);
    881     }
    882   }
    883 
    884   void CollectElementIndices(Handle<JSObject> object,
    885                              Handle<FixedArrayBase> backing_store,
    886                              KeyAccumulator* keys, uint32_t range,
    887                              PropertyFilter filter, uint32_t offset) final {
    888     ElementsAccessorSubclass::CollectElementIndicesImpl(
    889         object, backing_store, keys, range, filter, offset);
    890   };
    891 
    892   void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
    893                                    KeyAccumulator* accumulator,
    894                                    AddKeyConversion convert) final {
    895     Handle<FixedArrayBase> from(receiver->elements());
    896     uint32_t add_length =
    897         ElementsAccessorSubclass::GetCapacityImpl(*receiver, *from);
    898     if (add_length == 0) return;
    899 
    900     for (uint32_t i = 0; i < add_length; i++) {
    901       if (!ElementsAccessorSubclass::HasEntryImpl(*from, i)) continue;
    902       Handle<Object> value = ElementsAccessorSubclass::GetImpl(from, i);
    903       DCHECK(!value->IsTheHole());
    904       DCHECK(!value->IsAccessorPair());
    905       DCHECK(!value->IsExecutableAccessorInfo());
    906       accumulator->AddKey(value, convert);
    907     }
    908   }
    909 
    910   static uint32_t GetCapacityImpl(JSObject* holder,
    911                                   FixedArrayBase* backing_store) {
    912     return backing_store->length();
    913   }
    914 
    915   uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
    916     return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
    917   }
    918 
    919   static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
    920     return true;
    921   }
    922 
    923   static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
    924                                        uint32_t entry) {
    925     return entry;
    926   }
    927 
    928   static uint32_t GetEntryForIndexImpl(JSObject* holder,
    929                                        FixedArrayBase* backing_store,
    930                                        uint32_t index, PropertyFilter filter) {
    931     if (IsHoleyElementsKind(kind())) {
    932       return index < ElementsAccessorSubclass::GetCapacityImpl(holder,
    933                                                                backing_store) &&
    934                      !BackingStore::cast(backing_store)->is_the_hole(index)
    935                  ? index
    936                  : kMaxUInt32;
    937     } else {
    938       uint32_t length =
    939           holder->IsJSArray()
    940               ? static_cast<uint32_t>(
    941                     Smi::cast(JSArray::cast(holder)->length())->value())
    942               : ElementsAccessorSubclass::GetCapacityImpl(holder,
    943                                                           backing_store);
    944       return index < length ? index : kMaxUInt32;
    945     }
    946   }
    947 
    948   uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
    949                             uint32_t index) final {
    950     return ElementsAccessorSubclass::GetEntryForIndexImpl(
    951         holder, backing_store, index, ALL_PROPERTIES);
    952   }
    953 
    954   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
    955                                         uint32_t entry) {
    956     return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
    957   }
    958 
    959   PropertyDetails GetDetails(FixedArrayBase* backing_store,
    960                              uint32_t entry) final {
    961     return ElementsAccessorSubclass::GetDetailsImpl(backing_store, entry);
    962   }
    963 
    964  private:
    965   DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
    966 };
    967 
    968 
    969 class DictionaryElementsAccessor
    970     : public ElementsAccessorBase<DictionaryElementsAccessor,
    971                                   ElementsKindTraits<DICTIONARY_ELEMENTS> > {
    972  public:
    973   explicit DictionaryElementsAccessor(const char* name)
    974       : ElementsAccessorBase<DictionaryElementsAccessor,
    975                              ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
    976 
    977   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
    978                             uint32_t length,
    979                             Handle<FixedArrayBase> backing_store) {
    980     Handle<SeededNumberDictionary> dict =
    981         Handle<SeededNumberDictionary>::cast(backing_store);
    982     int capacity = dict->Capacity();
    983     uint32_t old_length = 0;
    984     CHECK(array->length()->ToArrayLength(&old_length));
    985     if (length < old_length) {
    986       if (dict->requires_slow_elements()) {
    987         // Find last non-deletable element in range of elements to be
    988         // deleted and adjust range accordingly.
    989         for (int entry = 0; entry < capacity; entry++) {
    990           DisallowHeapAllocation no_gc;
    991           Object* index = dict->KeyAt(entry);
    992           if (index->IsNumber()) {
    993             uint32_t number = static_cast<uint32_t>(index->Number());
    994             if (length <= number && number < old_length) {
    995               PropertyDetails details = dict->DetailsAt(entry);
    996               if (!details.IsConfigurable()) length = number + 1;
    997             }
    998           }
    999         }
   1000       }
   1001 
   1002       if (length == 0) {
   1003         // Flush the backing store.
   1004         JSObject::ResetElements(array);
   1005       } else {
   1006         DisallowHeapAllocation no_gc;
   1007         // Remove elements that should be deleted.
   1008         int removed_entries = 0;
   1009         Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
   1010         for (int entry = 0; entry < capacity; entry++) {
   1011           Object* index = dict->KeyAt(entry);
   1012           if (index->IsNumber()) {
   1013             uint32_t number = static_cast<uint32_t>(index->Number());
   1014             if (length <= number && number < old_length) {
   1015               dict->SetEntry(entry, the_hole_value, the_hole_value);
   1016               removed_entries++;
   1017             }
   1018           }
   1019         }
   1020 
   1021         // Update the number of elements.
   1022         dict->ElementsRemoved(removed_entries);
   1023       }
   1024     }
   1025 
   1026     Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
   1027     array->set_length(*length_obj);
   1028   }
   1029 
   1030   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   1031                                FixedArrayBase* to, ElementsKind from_kind,
   1032                                uint32_t to_start, int packed_size,
   1033                                int copy_size) {
   1034     UNREACHABLE();
   1035   }
   1036 
   1037 
   1038   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
   1039     // TODO(verwaest): Remove reliance on index in Shrink.
   1040     Handle<SeededNumberDictionary> dict(
   1041         SeededNumberDictionary::cast(obj->elements()));
   1042     uint32_t index = GetIndexForEntryImpl(*dict, entry);
   1043     Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
   1044     USE(result);
   1045     DCHECK(result->IsTrue());
   1046     Handle<FixedArray> new_elements =
   1047         SeededNumberDictionary::Shrink(dict, index);
   1048     obj->set_elements(*new_elements);
   1049   }
   1050 
   1051   static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
   1052     SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
   1053     return backing_store->ValueAt(entry);
   1054   }
   1055 
   1056   static Handle<Object> GetImpl(Handle<FixedArrayBase> store, uint32_t entry) {
   1057     Isolate* isolate = store->GetIsolate();
   1058     return handle(GetRaw(*store, entry), isolate);
   1059   }
   1060 
   1061   static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
   1062                              Object* value) {
   1063     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
   1064     dictionary->ValueAtPut(entry, value);
   1065   }
   1066 
   1067   static void ReconfigureImpl(Handle<JSObject> object,
   1068                               Handle<FixedArrayBase> store, uint32_t entry,
   1069                               Handle<Object> value,
   1070                               PropertyAttributes attributes) {
   1071     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
   1072     if (attributes != NONE) object->RequireSlowElements(dictionary);
   1073     dictionary->ValueAtPut(entry, *value);
   1074     PropertyDetails details = dictionary->DetailsAt(entry);
   1075     details = PropertyDetails(attributes, DATA, details.dictionary_index(),
   1076                               PropertyCellType::kNoCell);
   1077     dictionary->DetailsAtPut(entry, details);
   1078   }
   1079 
   1080   static void AddImpl(Handle<JSObject> object, uint32_t index,
   1081                       Handle<Object> value, PropertyAttributes attributes,
   1082                       uint32_t new_capacity) {
   1083     PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
   1084     Handle<SeededNumberDictionary> dictionary =
   1085         object->HasFastElements()
   1086             ? JSObject::NormalizeElements(object)
   1087             : handle(SeededNumberDictionary::cast(object->elements()));
   1088     Handle<SeededNumberDictionary> new_dictionary =
   1089         SeededNumberDictionary::AddNumberEntry(
   1090             dictionary, index, value, details,
   1091             object->map()->is_prototype_map());
   1092     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
   1093     if (dictionary.is_identical_to(new_dictionary)) return;
   1094     object->set_elements(*new_dictionary);
   1095   }
   1096 
   1097   static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
   1098     DisallowHeapAllocation no_gc;
   1099     SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
   1100     Object* index = dict->KeyAt(entry);
   1101     return !index->IsTheHole();
   1102   }
   1103 
   1104   static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
   1105     DisallowHeapAllocation no_gc;
   1106     SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
   1107     uint32_t result = 0;
   1108     CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
   1109     return result;
   1110   }
   1111 
   1112   static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
   1113                                        uint32_t index, PropertyFilter filter) {
   1114     DisallowHeapAllocation no_gc;
   1115     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
   1116     int entry = dictionary->FindEntry(index);
   1117     if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
   1118     if (filter != ALL_PROPERTIES) {
   1119       PropertyDetails details = dictionary->DetailsAt(entry);
   1120       PropertyAttributes attr = details.attributes();
   1121       if ((attr & filter) != 0) return kMaxUInt32;
   1122     }
   1123     return static_cast<uint32_t>(entry);
   1124   }
   1125 
   1126   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
   1127                                         uint32_t entry) {
   1128     return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
   1129   }
   1130 
   1131   static void CollectElementIndicesImpl(Handle<JSObject> object,
   1132                                         Handle<FixedArrayBase> backing_store,
   1133                                         KeyAccumulator* keys, uint32_t range,
   1134                                         PropertyFilter filter,
   1135                                         uint32_t offset) {
   1136     Handle<SeededNumberDictionary> dictionary =
   1137         Handle<SeededNumberDictionary>::cast(backing_store);
   1138     int capacity = dictionary->Capacity();
   1139     for (int i = 0; i < capacity; i++) {
   1140       Object* k = dictionary->KeyAt(i);
   1141       if (!dictionary->IsKey(k)) continue;
   1142       if (k->FilterKey(filter)) continue;
   1143       if (dictionary->IsDeleted(i)) continue;
   1144       DCHECK(k->IsNumber());
   1145       DCHECK_LE(k->Number(), kMaxUInt32);
   1146       uint32_t index = static_cast<uint32_t>(k->Number());
   1147       if (index < offset) continue;
   1148       PropertyDetails details = dictionary->DetailsAt(i);
   1149       if (filter & ONLY_ALL_CAN_READ) {
   1150         if (details.kind() != kAccessor) continue;
   1151         Object* accessors = dictionary->ValueAt(i);
   1152         if (!accessors->IsAccessorInfo()) continue;
   1153         if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
   1154       }
   1155       PropertyAttributes attr = details.attributes();
   1156       if ((attr & filter) != 0) continue;
   1157       keys->AddKey(index);
   1158     }
   1159 
   1160     keys->SortCurrentElementsList();
   1161   }
   1162 };
   1163 
   1164 
   1165 // Super class for all fast element arrays.
   1166 template<typename FastElementsAccessorSubclass,
   1167          typename KindTraits>
   1168 class FastElementsAccessor
   1169     : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
   1170  public:
   1171   explicit FastElementsAccessor(const char* name)
   1172       : ElementsAccessorBase<FastElementsAccessorSubclass,
   1173                              KindTraits>(name) {}
   1174 
   1175   typedef typename KindTraits::BackingStore BackingStore;
   1176 
   1177   static void DeleteAtEnd(Handle<JSObject> obj,
   1178                           Handle<BackingStore> backing_store, uint32_t entry) {
   1179     uint32_t length = static_cast<uint32_t>(backing_store->length());
   1180     Heap* heap = obj->GetHeap();
   1181     for (; entry > 0; entry--) {
   1182       if (!backing_store->is_the_hole(entry - 1)) break;
   1183     }
   1184     if (entry == 0) {
   1185       FixedArray* empty = heap->empty_fixed_array();
   1186       if (obj->HasFastArgumentsElements()) {
   1187         FixedArray::cast(obj->elements())->set(1, empty);
   1188       } else {
   1189         obj->set_elements(empty);
   1190       }
   1191       return;
   1192     }
   1193 
   1194     heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
   1195                                                            length - entry);
   1196   }
   1197 
   1198   static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
   1199                            Handle<FixedArrayBase> store) {
   1200     DCHECK(obj->HasFastSmiOrObjectElements() ||
   1201            obj->HasFastDoubleElements() ||
   1202            obj->HasFastArgumentsElements());
   1203     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
   1204     if (!obj->IsJSArray() &&
   1205         entry == static_cast<uint32_t>(store->length()) - 1) {
   1206       DeleteAtEnd(obj, backing_store, entry);
   1207       return;
   1208     }
   1209 
   1210     backing_store->set_the_hole(entry);
   1211 
   1212     // TODO(verwaest): Move this out of elements.cc.
   1213     // If an old space backing store is larger than a certain size and
   1214     // has too few used values, normalize it.
   1215     // To avoid doing the check on every delete we require at least
   1216     // one adjacent hole to the value being deleted.
   1217     const int kMinLengthForSparsenessCheck = 64;
   1218     if (backing_store->length() < kMinLengthForSparsenessCheck) return;
   1219     if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
   1220     uint32_t length = 0;
   1221     if (obj->IsJSArray()) {
   1222       JSArray::cast(*obj)->length()->ToArrayLength(&length);
   1223     } else {
   1224       length = static_cast<uint32_t>(store->length());
   1225     }
   1226     if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
   1227         (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
   1228       if (!obj->IsJSArray()) {
   1229         uint32_t i;
   1230         for (i = entry + 1; i < length; i++) {
   1231           if (!backing_store->is_the_hole(i)) break;
   1232         }
   1233         if (i == length) {
   1234           DeleteAtEnd(obj, backing_store, entry);
   1235           return;
   1236         }
   1237       }
   1238       int num_used = 0;
   1239       for (int i = 0; i < backing_store->length(); ++i) {
   1240         if (!backing_store->is_the_hole(i)) {
   1241           ++num_used;
   1242           // Bail out if a number dictionary wouldn't be able to save at least
   1243           // 75% space.
   1244           if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
   1245                   SeededNumberDictionary::kEntrySize >
   1246               backing_store->length()) {
   1247             return;
   1248           }
   1249         }
   1250       }
   1251       JSObject::NormalizeElements(obj);
   1252     }
   1253   }
   1254 
   1255   static void ReconfigureImpl(Handle<JSObject> object,
   1256                               Handle<FixedArrayBase> store, uint32_t entry,
   1257                               Handle<Object> value,
   1258                               PropertyAttributes attributes) {
   1259     Handle<SeededNumberDictionary> dictionary =
   1260         JSObject::NormalizeElements(object);
   1261     entry = dictionary->FindEntry(entry);
   1262     DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
   1263                                                 value, attributes);
   1264   }
   1265 
   1266   static void AddImpl(Handle<JSObject> object, uint32_t index,
   1267                       Handle<Object> value, PropertyAttributes attributes,
   1268                       uint32_t new_capacity) {
   1269     DCHECK_EQ(NONE, attributes);
   1270     ElementsKind from_kind = object->GetElementsKind();
   1271     ElementsKind to_kind = FastElementsAccessorSubclass::kind();
   1272     if (IsDictionaryElementsKind(from_kind) ||
   1273         IsFastDoubleElementsKind(from_kind) !=
   1274             IsFastDoubleElementsKind(to_kind) ||
   1275         FastElementsAccessorSubclass::GetCapacityImpl(
   1276             *object, object->elements()) != new_capacity) {
   1277       FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object,
   1278                                                                new_capacity);
   1279     } else {
   1280       if (from_kind != to_kind) {
   1281         JSObject::TransitionElementsKind(object, to_kind);
   1282       }
   1283       if (IsFastSmiOrObjectElementsKind(from_kind)) {
   1284         DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
   1285         JSObject::EnsureWritableFastElements(object);
   1286       }
   1287     }
   1288     FastElementsAccessorSubclass::SetImpl(object->elements(), index, *value);
   1289   }
   1290 
   1291   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
   1292     ElementsKind kind = KindTraits::Kind;
   1293     if (IsFastPackedElementsKind(kind)) {
   1294       JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
   1295     }
   1296     if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
   1297       JSObject::EnsureWritableFastElements(obj);
   1298     }
   1299     DeleteCommon(obj, entry, handle(obj->elements()));
   1300   }
   1301 
   1302   static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
   1303     return !BackingStore::cast(backing_store)->is_the_hole(entry);
   1304   }
   1305 
   1306   static void ValidateContents(Handle<JSObject> holder, int length) {
   1307 #if DEBUG
   1308     Isolate* isolate = holder->GetIsolate();
   1309     HandleScope scope(isolate);
   1310     Handle<FixedArrayBase> elements(holder->elements(), isolate);
   1311     Map* map = elements->map();
   1312     DCHECK((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
   1313             (map == isolate->heap()->fixed_array_map() ||
   1314              map == isolate->heap()->fixed_cow_array_map())) ||
   1315            (IsFastDoubleElementsKind(KindTraits::Kind) ==
   1316             ((map == isolate->heap()->fixed_array_map() && length == 0) ||
   1317              map == isolate->heap()->fixed_double_array_map())));
   1318     if (length == 0) return;  // nothing to do!
   1319     DisallowHeapAllocation no_gc;
   1320     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
   1321     if (IsFastSmiElementsKind(KindTraits::Kind)) {
   1322       for (int i = 0; i < length; i++) {
   1323         DCHECK(BackingStore::get(backing_store, i)->IsSmi() ||
   1324                (IsFastHoleyElementsKind(KindTraits::Kind) &&
   1325                 backing_store->is_the_hole(i)));
   1326       }
   1327     }
   1328 #endif
   1329   }
   1330 
   1331   static Handle<Object> PopImpl(Handle<JSArray> receiver,
   1332                                 Handle<FixedArrayBase> backing_store) {
   1333     return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
   1334                                                        AT_END);
   1335   }
   1336 
   1337   static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
   1338                                   Handle<FixedArrayBase> backing_store) {
   1339     return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
   1340                                                        AT_START);
   1341   }
   1342 
   1343   static uint32_t PushImpl(Handle<JSArray> receiver,
   1344                            Handle<FixedArrayBase> backing_store,
   1345                            Arguments* args, uint32_t push_size) {
   1346     return FastElementsAccessorSubclass::AddArguments(receiver, backing_store,
   1347                                                       args, push_size, AT_END);
   1348   }
   1349 
   1350   static uint32_t UnshiftImpl(Handle<JSArray> receiver,
   1351                               Handle<FixedArrayBase> backing_store,
   1352                               Arguments* args, uint32_t unshift_size) {
   1353     return FastElementsAccessorSubclass::AddArguments(
   1354         receiver, backing_store, args, unshift_size, AT_START);
   1355   }
   1356 
   1357   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
   1358                            Handle<FixedArrayBase> backing_store, int dst_index,
   1359                            int src_index, int len, int hole_start,
   1360                            int hole_end) {
   1361     UNREACHABLE();
   1362   }
   1363 
   1364   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
   1365                                    Handle<FixedArrayBase> backing_store,
   1366                                    uint32_t start, uint32_t end) {
   1367     DCHECK(start < end);
   1368     Isolate* isolate = receiver->GetIsolate();
   1369     int result_len = end - start;
   1370     Handle<JSArray> result_array = isolate->factory()->NewJSArray(
   1371         KindTraits::Kind, result_len, result_len);
   1372     DisallowHeapAllocation no_gc;
   1373     FastElementsAccessorSubclass::CopyElementsImpl(
   1374         *backing_store, start, result_array->elements(), KindTraits::Kind, 0,
   1375         kPackedSizeNotKnown, result_len);
   1376     FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
   1377         result_array);
   1378     return result_array;
   1379   }
   1380 
   1381   static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
   1382                                     Handle<FixedArrayBase> backing_store,
   1383                                     uint32_t start, uint32_t delete_count,
   1384                                     Arguments* args, uint32_t add_count) {
   1385     Isolate* isolate = receiver->GetIsolate();
   1386     Heap* heap = isolate->heap();
   1387     uint32_t length = Smi::cast(receiver->length())->value();
   1388     uint32_t new_length = length - delete_count + add_count;
   1389 
   1390     if (new_length == 0) {
   1391       receiver->set_elements(heap->empty_fixed_array());
   1392       receiver->set_length(Smi::FromInt(0));
   1393       return isolate->factory()->NewJSArrayWithElements(
   1394           backing_store, KindTraits::Kind, delete_count);
   1395     }
   1396 
   1397     // Construct the result array which holds the deleted elements.
   1398     Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
   1399         KindTraits::Kind, delete_count, delete_count);
   1400     if (delete_count > 0) {
   1401       DisallowHeapAllocation no_gc;
   1402       FastElementsAccessorSubclass::CopyElementsImpl(
   1403           *backing_store, start, deleted_elements->elements(), KindTraits::Kind,
   1404           0, kPackedSizeNotKnown, delete_count);
   1405     }
   1406 
   1407     // Delete and move elements to make space for add_count new elements.
   1408     if (add_count < delete_count) {
   1409       FastElementsAccessorSubclass::SpliceShrinkStep(
   1410           isolate, receiver, backing_store, start, delete_count, add_count,
   1411           length, new_length);
   1412     } else if (add_count > delete_count) {
   1413       backing_store = FastElementsAccessorSubclass::SpliceGrowStep(
   1414           isolate, receiver, backing_store, start, delete_count, add_count,
   1415           length, new_length);
   1416     }
   1417 
   1418     // Copy over the arguments.
   1419     FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count,
   1420                                                 3, start);
   1421 
   1422     receiver->set_length(Smi::FromInt(new_length));
   1423     FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
   1424         deleted_elements);
   1425     return deleted_elements;
   1426   }
   1427 
   1428  private:
   1429   // SpliceShrinkStep might modify the backing_store.
   1430   static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
   1431                                Handle<FixedArrayBase> backing_store,
   1432                                uint32_t start, uint32_t delete_count,
   1433                                uint32_t add_count, uint32_t len,
   1434                                uint32_t new_length) {
   1435     const int move_left_count = len - delete_count - start;
   1436     const int move_left_dst_index = start + add_count;
   1437     FastElementsAccessorSubclass::MoveElements(
   1438         isolate, receiver, backing_store, move_left_dst_index,
   1439         start + delete_count, move_left_count, new_length, len);
   1440   }
   1441 
   1442   // SpliceGrowStep might modify the backing_store.
   1443   static Handle<FixedArrayBase> SpliceGrowStep(
   1444       Isolate* isolate, Handle<JSArray> receiver,
   1445       Handle<FixedArrayBase> backing_store, uint32_t start,
   1446       uint32_t delete_count, uint32_t add_count, uint32_t length,
   1447       uint32_t new_length) {
   1448     // Check we do not overflow the new_length.
   1449     DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
   1450     // Check if backing_store is big enough.
   1451     if (new_length <= static_cast<uint32_t>(backing_store->length())) {
   1452       FastElementsAccessorSubclass::MoveElements(
   1453           isolate, receiver, backing_store, start + add_count,
   1454           start + delete_count, (length - delete_count - start), 0, 0);
   1455       // MoveElements updates the backing_store in-place.
   1456       return backing_store;
   1457     }
   1458     // New backing storage is needed.
   1459     int capacity = JSObject::NewElementsCapacity(new_length);
   1460     // Partially copy all elements up to start.
   1461     Handle<FixedArrayBase> new_elms =
   1462         FastElementsAccessorSubclass::ConvertElementsWithCapacity(
   1463             receiver, backing_store, KindTraits::Kind, capacity, start);
   1464     // Copy the trailing elements after start + delete_count
   1465     FastElementsAccessorSubclass::CopyElementsImpl(
   1466         *backing_store, start + delete_count, *new_elms, KindTraits::Kind,
   1467         start + add_count, kPackedSizeNotKnown,
   1468         ElementsAccessor::kCopyToEndAndInitializeToHole);
   1469     receiver->set_elements(*new_elms);
   1470     return new_elms;
   1471   }
   1472 
   1473   static Handle<Object> RemoveElement(Handle<JSArray> receiver,
   1474                                       Handle<FixedArrayBase> backing_store,
   1475                                       Where remove_position) {
   1476     Isolate* isolate = receiver->GetIsolate();
   1477     uint32_t length =
   1478         static_cast<uint32_t>(Smi::cast(receiver->length())->value());
   1479     DCHECK(length > 0);
   1480     int new_length = length - 1;
   1481     int remove_index = remove_position == AT_START ? 0 : new_length;
   1482     Handle<Object> result =
   1483         FastElementsAccessorSubclass::GetImpl(backing_store, remove_index);
   1484     if (remove_position == AT_START) {
   1485       FastElementsAccessorSubclass::MoveElements(
   1486           isolate, receiver, backing_store, 0, 1, new_length, 0, 0);
   1487     }
   1488     FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length,
   1489                                                 backing_store);
   1490 
   1491     if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
   1492       return receiver->GetIsolate()->factory()->undefined_value();
   1493     }
   1494     return result;
   1495   }
   1496 
   1497   static uint32_t AddArguments(Handle<JSArray> receiver,
   1498                                Handle<FixedArrayBase> backing_store,
   1499                                Arguments* args, uint32_t add_size,
   1500                                Where remove_position) {
   1501     uint32_t length = Smi::cast(receiver->length())->value();
   1502     DCHECK(add_size > 0);
   1503     uint32_t elms_len = backing_store->length();
   1504     // Check we do not overflow the new_length.
   1505     DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
   1506     uint32_t new_length = length + add_size;
   1507 
   1508     if (new_length > elms_len) {
   1509       // New backing storage is needed.
   1510       uint32_t capacity = JSObject::NewElementsCapacity(new_length);
   1511       // If we add arguments to the start we have to shift the existing objects.
   1512       int copy_dst_index = remove_position == AT_START ? add_size : 0;
   1513       // Copy over all objects to a new backing_store.
   1514       backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
   1515           receiver, backing_store, KindTraits::Kind, capacity, 0,
   1516           copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
   1517       receiver->set_elements(*backing_store);
   1518     } else if (remove_position == AT_START) {
   1519       // If the backing store has enough capacity and we add elements to the
   1520       // start we have to shift the existing objects.
   1521       Isolate* isolate = receiver->GetIsolate();
   1522       FastElementsAccessorSubclass::MoveElements(
   1523           isolate, receiver, backing_store, add_size, 0, length, 0, 0);
   1524     }
   1525 
   1526     int insertion_index = remove_position == AT_START ? 0 : length;
   1527     // Copy the arguments to the start.
   1528     FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_size,
   1529                                                 1, insertion_index);
   1530     // Set the length.
   1531     receiver->set_length(Smi::FromInt(new_length));
   1532     return new_length;
   1533   }
   1534 
   1535   static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
   1536                             uint32_t copy_size, uint32_t src_index,
   1537                             uint32_t dst_index) {
   1538     // Add the provided values.
   1539     DisallowHeapAllocation no_gc;
   1540     FixedArrayBase* raw_backing_store = *dst_store;
   1541     WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
   1542     for (uint32_t i = 0; i < copy_size; i++) {
   1543       Object* argument = (*args)[i + src_index];
   1544       FastElementsAccessorSubclass::SetImpl(raw_backing_store, i + dst_index,
   1545                                             argument, mode);
   1546     }
   1547   }
   1548 };
   1549 
   1550 
   1551 template<typename FastElementsAccessorSubclass,
   1552          typename KindTraits>
   1553 class FastSmiOrObjectElementsAccessor
   1554     : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
   1555  public:
   1556   explicit FastSmiOrObjectElementsAccessor(const char* name)
   1557       : FastElementsAccessor<FastElementsAccessorSubclass,
   1558                              KindTraits>(name) {}
   1559 
   1560   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   1561                              Object* value) {
   1562     FixedArray::cast(backing_store)->set(entry, value);
   1563   }
   1564 
   1565   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   1566                              Object* value, WriteBarrierMode mode) {
   1567     FixedArray::cast(backing_store)->set(entry, value, mode);
   1568   }
   1569 
   1570   static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
   1571     uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl(
   1572         backing_store, entry);
   1573     return backing_store->get(index);
   1574   }
   1575 
   1576   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
   1577                            Handle<FixedArrayBase> backing_store, int dst_index,
   1578                            int src_index, int len, int hole_start,
   1579                            int hole_end) {
   1580     Heap* heap = isolate->heap();
   1581     Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store);
   1582     if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
   1583       // Update all the copies of this backing_store handle.
   1584       *dst_elms.location() =
   1585           FixedArray::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
   1586       receiver->set_elements(*dst_elms);
   1587       // Adjust the hole offset as the array has been shrunk.
   1588       hole_end -= src_index;
   1589       DCHECK_LE(hole_start, backing_store->length());
   1590       DCHECK_LE(hole_end, backing_store->length());
   1591     } else if (len != 0) {
   1592       DisallowHeapAllocation no_gc;
   1593       heap->MoveElements(*dst_elms, dst_index, src_index, len);
   1594     }
   1595     if (hole_start != hole_end) {
   1596       dst_elms->FillWithHoles(hole_start, hole_end);
   1597     }
   1598   }
   1599 
   1600   // NOTE: this method violates the handlified function signature convention:
   1601   // raw pointer parameters in the function that allocates.
   1602   // See ElementsAccessor::CopyElements() for details.
   1603   // This method could actually allocate if copying from double elements to
   1604   // object elements.
   1605   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   1606                                FixedArrayBase* to, ElementsKind from_kind,
   1607                                uint32_t to_start, int packed_size,
   1608                                int copy_size) {
   1609     DisallowHeapAllocation no_gc;
   1610     ElementsKind to_kind = KindTraits::Kind;
   1611     switch (from_kind) {
   1612       case FAST_SMI_ELEMENTS:
   1613       case FAST_HOLEY_SMI_ELEMENTS:
   1614       case FAST_ELEMENTS:
   1615       case FAST_HOLEY_ELEMENTS:
   1616         CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
   1617                                    to_start, copy_size);
   1618         break;
   1619       case FAST_DOUBLE_ELEMENTS:
   1620       case FAST_HOLEY_DOUBLE_ELEMENTS: {
   1621         AllowHeapAllocation allow_allocation;
   1622         DCHECK(IsFastObjectElementsKind(to_kind));
   1623         CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
   1624         break;
   1625       }
   1626       case DICTIONARY_ELEMENTS:
   1627         CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
   1628                                        copy_size);
   1629         break;
   1630       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
   1631       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
   1632         UNREACHABLE();
   1633 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
   1634       case TYPE##_ELEMENTS:                                                   \
   1635         UNREACHABLE();
   1636       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   1637 #undef TYPED_ARRAY_CASE
   1638     }
   1639   }
   1640 };
   1641 
   1642 
   1643 class FastPackedSmiElementsAccessor
   1644     : public FastSmiOrObjectElementsAccessor<
   1645         FastPackedSmiElementsAccessor,
   1646         ElementsKindTraits<FAST_SMI_ELEMENTS> > {
   1647  public:
   1648   explicit FastPackedSmiElementsAccessor(const char* name)
   1649       : FastSmiOrObjectElementsAccessor<
   1650           FastPackedSmiElementsAccessor,
   1651           ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
   1652 };
   1653 
   1654 
   1655 class FastHoleySmiElementsAccessor
   1656     : public FastSmiOrObjectElementsAccessor<
   1657         FastHoleySmiElementsAccessor,
   1658         ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
   1659  public:
   1660   explicit FastHoleySmiElementsAccessor(const char* name)
   1661       : FastSmiOrObjectElementsAccessor<
   1662           FastHoleySmiElementsAccessor,
   1663           ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
   1664 };
   1665 
   1666 
   1667 class FastPackedObjectElementsAccessor
   1668     : public FastSmiOrObjectElementsAccessor<
   1669         FastPackedObjectElementsAccessor,
   1670         ElementsKindTraits<FAST_ELEMENTS> > {
   1671  public:
   1672   explicit FastPackedObjectElementsAccessor(const char* name)
   1673       : FastSmiOrObjectElementsAccessor<
   1674           FastPackedObjectElementsAccessor,
   1675           ElementsKindTraits<FAST_ELEMENTS> >(name) {}
   1676 };
   1677 
   1678 
   1679 class FastHoleyObjectElementsAccessor
   1680     : public FastSmiOrObjectElementsAccessor<
   1681         FastHoleyObjectElementsAccessor,
   1682         ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
   1683  public:
   1684   explicit FastHoleyObjectElementsAccessor(const char* name)
   1685       : FastSmiOrObjectElementsAccessor<
   1686           FastHoleyObjectElementsAccessor,
   1687           ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
   1688 };
   1689 
   1690 
   1691 template<typename FastElementsAccessorSubclass,
   1692          typename KindTraits>
   1693 class FastDoubleElementsAccessor
   1694     : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
   1695  public:
   1696   explicit FastDoubleElementsAccessor(const char* name)
   1697       : FastElementsAccessor<FastElementsAccessorSubclass,
   1698                              KindTraits>(name) {}
   1699 
   1700   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   1701                              Object* value) {
   1702     FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
   1703   }
   1704 
   1705   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   1706                              Object* value, WriteBarrierMode mode) {
   1707     FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
   1708   }
   1709 
   1710   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
   1711                            Handle<FixedArrayBase> backing_store, int dst_index,
   1712                            int src_index, int len, int hole_start,
   1713                            int hole_end) {
   1714     Heap* heap = isolate->heap();
   1715     Handle<FixedDoubleArray> dst_elms =
   1716         Handle<FixedDoubleArray>::cast(backing_store);
   1717     if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
   1718       // Update all the copies of this backing_store handle.
   1719       *dst_elms.location() = FixedDoubleArray::cast(
   1720           heap->LeftTrimFixedArray(*dst_elms, src_index));
   1721       receiver->set_elements(*dst_elms);
   1722       // Adjust the hole offset as the array has been shrunk.
   1723       hole_end -= src_index;
   1724       DCHECK_LE(hole_start, backing_store->length());
   1725       DCHECK_LE(hole_end, backing_store->length());
   1726     } else if (len != 0) {
   1727       MemMove(dst_elms->data_start() + dst_index,
   1728               dst_elms->data_start() + src_index, len * kDoubleSize);
   1729     }
   1730     if (hole_start != hole_end) {
   1731       dst_elms->FillWithHoles(hole_start, hole_end);
   1732     }
   1733   }
   1734 
   1735   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   1736                                FixedArrayBase* to, ElementsKind from_kind,
   1737                                uint32_t to_start, int packed_size,
   1738                                int copy_size) {
   1739     DisallowHeapAllocation no_allocation;
   1740     switch (from_kind) {
   1741       case FAST_SMI_ELEMENTS:
   1742         CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
   1743                                       packed_size, copy_size);
   1744         break;
   1745       case FAST_HOLEY_SMI_ELEMENTS:
   1746         CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
   1747         break;
   1748       case FAST_DOUBLE_ELEMENTS:
   1749       case FAST_HOLEY_DOUBLE_ELEMENTS:
   1750         CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
   1751         break;
   1752       case FAST_ELEMENTS:
   1753       case FAST_HOLEY_ELEMENTS:
   1754         CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
   1755         break;
   1756       case DICTIONARY_ELEMENTS:
   1757         CopyDictionaryToDoubleElements(from, from_start, to, to_start,
   1758                                        copy_size);
   1759         break;
   1760       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
   1761       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
   1762         UNREACHABLE();
   1763 
   1764 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
   1765       case TYPE##_ELEMENTS:                                                   \
   1766         UNREACHABLE();
   1767       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   1768 #undef TYPED_ARRAY_CASE
   1769     }
   1770   }
   1771 };
   1772 
   1773 
   1774 class FastPackedDoubleElementsAccessor
   1775     : public FastDoubleElementsAccessor<
   1776         FastPackedDoubleElementsAccessor,
   1777         ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
   1778  public:
   1779   explicit FastPackedDoubleElementsAccessor(const char* name)
   1780       : FastDoubleElementsAccessor<
   1781           FastPackedDoubleElementsAccessor,
   1782           ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
   1783 };
   1784 
   1785 
   1786 class FastHoleyDoubleElementsAccessor
   1787     : public FastDoubleElementsAccessor<
   1788         FastHoleyDoubleElementsAccessor,
   1789         ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
   1790  public:
   1791   explicit FastHoleyDoubleElementsAccessor(const char* name)
   1792       : FastDoubleElementsAccessor<
   1793           FastHoleyDoubleElementsAccessor,
   1794           ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
   1795 };
   1796 
   1797 
   1798 // Super class for all external element arrays.
   1799 template<ElementsKind Kind>
   1800 class TypedElementsAccessor
   1801     : public ElementsAccessorBase<TypedElementsAccessor<Kind>,
   1802                                   ElementsKindTraits<Kind> > {
   1803  public:
   1804   explicit TypedElementsAccessor(const char* name)
   1805       : ElementsAccessorBase<AccessorClass,
   1806                              ElementsKindTraits<Kind> >(name) {}
   1807 
   1808   typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
   1809   typedef TypedElementsAccessor<Kind> AccessorClass;
   1810 
   1811   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   1812                              Object* value) {
   1813     BackingStore::cast(backing_store)->SetValue(entry, value);
   1814   }
   1815 
   1816   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
   1817                              Object* value, WriteBarrierMode mode) {
   1818     BackingStore::cast(backing_store)->SetValue(entry, value);
   1819   }
   1820 
   1821   static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
   1822                                 uint32_t entry) {
   1823     uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
   1824     return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
   1825   }
   1826 
   1827   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
   1828                                         uint32_t entry) {
   1829     return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
   1830   }
   1831 
   1832   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
   1833                             uint32_t length,
   1834                             Handle<FixedArrayBase> backing_store) {
   1835     // External arrays do not support changing their length.
   1836     UNREACHABLE();
   1837   }
   1838 
   1839   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
   1840     UNREACHABLE();
   1841   }
   1842 
   1843   static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
   1844                                        uint32_t entry) {
   1845     return entry;
   1846   }
   1847 
   1848   static uint32_t GetEntryForIndexImpl(JSObject* holder,
   1849                                        FixedArrayBase* backing_store,
   1850                                        uint32_t index, PropertyFilter filter) {
   1851     return index < AccessorClass::GetCapacityImpl(holder, backing_store)
   1852                ? index
   1853                : kMaxUInt32;
   1854   }
   1855 
   1856   static uint32_t GetCapacityImpl(JSObject* holder,
   1857                                   FixedArrayBase* backing_store) {
   1858     JSArrayBufferView* view = JSArrayBufferView::cast(holder);
   1859     if (view->WasNeutered()) return 0;
   1860     return backing_store->length();
   1861   }
   1862 };
   1863 
   1864 
   1865 
   1866 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size)       \
   1867   typedef TypedElementsAccessor<TYPE##_ELEMENTS >                    \
   1868       Fixed##Type##ElementsAccessor;
   1869 
   1870 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
   1871 #undef FIXED_ELEMENTS_ACCESSOR
   1872 
   1873 
   1874 template <typename SloppyArgumentsElementsAccessorSubclass,
   1875           typename ArgumentsAccessor, typename KindTraits>
   1876 class SloppyArgumentsElementsAccessor
   1877     : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
   1878                                   KindTraits> {
   1879  public:
   1880   explicit SloppyArgumentsElementsAccessor(const char* name)
   1881       : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
   1882                              KindTraits>(name) {
   1883     USE(KindTraits::Kind);
   1884   }
   1885 
   1886   static Handle<Object> GetImpl(Handle<FixedArrayBase> parameters,
   1887                                 uint32_t entry) {
   1888     Isolate* isolate = parameters->GetIsolate();
   1889     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
   1890     uint32_t length = parameter_map->length() - 2;
   1891     if (entry < length) {
   1892       DisallowHeapAllocation no_gc;
   1893       Object* probe = parameter_map->get(entry + 2);
   1894       Context* context = Context::cast(parameter_map->get(0));
   1895       int context_entry = Smi::cast(probe)->value();
   1896       DCHECK(!context->get(context_entry)->IsTheHole());
   1897       return handle(context->get(context_entry), isolate);
   1898     } else {
   1899       // Object is not mapped, defer to the arguments.
   1900       Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)),
   1901                                    isolate);
   1902       Handle<Object> result =
   1903           ArgumentsAccessor::GetImpl(arguments, entry - length);
   1904       // Elements of the arguments object in slow mode might be slow aliases.
   1905       if (result->IsAliasedArgumentsEntry()) {
   1906         DisallowHeapAllocation no_gc;
   1907         AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
   1908         Context* context = Context::cast(parameter_map->get(0));
   1909         int context_entry = alias->aliased_context_slot();
   1910         DCHECK(!context->get(context_entry)->IsTheHole());
   1911         return handle(context->get(context_entry), isolate);
   1912       }
   1913       return result;
   1914     }
   1915   }
   1916 
   1917   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
   1918                                          uint32_t capacity) {
   1919     UNREACHABLE();
   1920   }
   1921 
   1922   static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
   1923                              Object* value) {
   1924     FixedArray* parameter_map = FixedArray::cast(store);
   1925     uint32_t length = parameter_map->length() - 2;
   1926     if (entry < length) {
   1927       Object* probe = parameter_map->get(entry + 2);
   1928       Context* context = Context::cast(parameter_map->get(0));
   1929       int context_entry = Smi::cast(probe)->value();
   1930       DCHECK(!context->get(context_entry)->IsTheHole());
   1931       context->set(context_entry, value);
   1932     } else {
   1933       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   1934       Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
   1935       if (current->IsAliasedArgumentsEntry()) {
   1936         AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
   1937         Context* context = Context::cast(parameter_map->get(0));
   1938         int context_entry = alias->aliased_context_slot();
   1939         DCHECK(!context->get(context_entry)->IsTheHole());
   1940         context->set(context_entry, value);
   1941       } else {
   1942         ArgumentsAccessor::SetImpl(arguments, entry - length, value);
   1943       }
   1944     }
   1945   }
   1946 
   1947   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
   1948                             uint32_t length,
   1949                             Handle<FixedArrayBase> parameter_map) {
   1950     // Sloppy arguments objects are not arrays.
   1951     UNREACHABLE();
   1952   }
   1953 
   1954   static uint32_t GetCapacityImpl(JSObject* holder,
   1955                                   FixedArrayBase* backing_store) {
   1956     FixedArray* parameter_map = FixedArray::cast(backing_store);
   1957     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   1958     return parameter_map->length() - 2 +
   1959            ArgumentsAccessor::GetCapacityImpl(holder, arguments);
   1960   }
   1961 
   1962   static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
   1963     FixedArray* parameter_map = FixedArray::cast(parameters);
   1964     uint32_t length = parameter_map->length() - 2;
   1965     if (entry < length) {
   1966       return !GetParameterMapArg(parameter_map, entry)->IsTheHole();
   1967     }
   1968 
   1969     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   1970     return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
   1971   }
   1972 
   1973   static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
   1974                                        uint32_t entry) {
   1975     FixedArray* parameter_map = FixedArray::cast(parameters);
   1976     uint32_t length = parameter_map->length() - 2;
   1977     if (entry < length) return entry;
   1978 
   1979     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   1980     return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
   1981   }
   1982 
   1983   static uint32_t GetEntryForIndexImpl(JSObject* holder,
   1984                                        FixedArrayBase* parameters,
   1985                                        uint32_t index, PropertyFilter filter) {
   1986     FixedArray* parameter_map = FixedArray::cast(parameters);
   1987     Object* probe = GetParameterMapArg(parameter_map, index);
   1988     if (!probe->IsTheHole()) return index;
   1989 
   1990     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   1991     uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
   1992                                                              index, filter);
   1993     if (entry == kMaxUInt32) return entry;
   1994     return (parameter_map->length() - 2) + entry;
   1995   }
   1996 
   1997   static PropertyDetails GetDetailsImpl(FixedArrayBase* parameters,
   1998                                         uint32_t entry) {
   1999     FixedArray* parameter_map = FixedArray::cast(parameters);
   2000     uint32_t length = parameter_map->length() - 2;
   2001     if (entry < length) {
   2002       return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
   2003     }
   2004     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   2005     return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
   2006   }
   2007 
   2008   static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
   2009     uint32_t length = parameter_map->length() - 2;
   2010     return index < length
   2011                ? parameter_map->get(index + 2)
   2012                : Object::cast(parameter_map->GetHeap()->the_hole_value());
   2013   }
   2014 
   2015   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
   2016     FixedArray* parameter_map = FixedArray::cast(obj->elements());
   2017     uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
   2018     if (entry < length) {
   2019       // TODO(kmillikin): We could check if this was the last aliased
   2020       // parameter, and revert to normal elements in that case.  That
   2021       // would enable GC of the context.
   2022       parameter_map->set_the_hole(entry + 2);
   2023     } else {
   2024       SloppyArgumentsElementsAccessorSubclass::DeleteFromArguments(
   2025           obj, entry - length);
   2026     }
   2027   }
   2028 };
   2029 
   2030 
   2031 class SlowSloppyArgumentsElementsAccessor
   2032     : public SloppyArgumentsElementsAccessor<
   2033           SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
   2034           ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
   2035  public:
   2036   explicit SlowSloppyArgumentsElementsAccessor(const char* name)
   2037       : SloppyArgumentsElementsAccessor<
   2038             SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
   2039             ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
   2040 
   2041   static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
   2042     Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
   2043     Handle<SeededNumberDictionary> dict(
   2044         SeededNumberDictionary::cast(parameter_map->get(1)));
   2045     // TODO(verwaest): Remove reliance on index in Shrink.
   2046     uint32_t index = GetIndexForEntryImpl(*dict, entry);
   2047     Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
   2048     USE(result);
   2049     DCHECK(result->IsTrue());
   2050     Handle<FixedArray> new_elements =
   2051         SeededNumberDictionary::Shrink(dict, index);
   2052     parameter_map->set(1, *new_elements);
   2053   }
   2054 
   2055   static void AddImpl(Handle<JSObject> object, uint32_t index,
   2056                       Handle<Object> value, PropertyAttributes attributes,
   2057                       uint32_t new_capacity) {
   2058     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
   2059     Handle<FixedArrayBase> old_elements(
   2060         FixedArrayBase::cast(parameter_map->get(1)));
   2061     Handle<SeededNumberDictionary> dictionary =
   2062         old_elements->IsSeededNumberDictionary()
   2063             ? Handle<SeededNumberDictionary>::cast(old_elements)
   2064             : JSObject::NormalizeElements(object);
   2065     PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
   2066     Handle<SeededNumberDictionary> new_dictionary =
   2067         SeededNumberDictionary::AddNumberEntry(
   2068             dictionary, index, value, details,
   2069             object->map()->is_prototype_map());
   2070     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
   2071     if (*dictionary != *new_dictionary) {
   2072       FixedArray::cast(object->elements())->set(1, *new_dictionary);
   2073     }
   2074   }
   2075 
   2076   static void ReconfigureImpl(Handle<JSObject> object,
   2077                               Handle<FixedArrayBase> store, uint32_t entry,
   2078                               Handle<Object> value,
   2079                               PropertyAttributes attributes) {
   2080     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
   2081     uint32_t length = parameter_map->length() - 2;
   2082     if (entry < length) {
   2083       Object* probe = parameter_map->get(entry + 2);
   2084       DCHECK(!probe->IsTheHole());
   2085       Context* context = Context::cast(parameter_map->get(0));
   2086       int context_entry = Smi::cast(probe)->value();
   2087       DCHECK(!context->get(context_entry)->IsTheHole());
   2088       context->set(context_entry, *value);
   2089 
   2090       // Redefining attributes of an aliased element destroys fast aliasing.
   2091       parameter_map->set_the_hole(entry + 2);
   2092       // For elements that are still writable we re-establish slow aliasing.
   2093       if ((attributes & READ_ONLY) == 0) {
   2094         Isolate* isolate = store->GetIsolate();
   2095         value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
   2096       }
   2097 
   2098       PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
   2099       Handle<SeededNumberDictionary> arguments(
   2100           SeededNumberDictionary::cast(parameter_map->get(1)));
   2101       arguments = SeededNumberDictionary::AddNumberEntry(
   2102           arguments, entry, value, details, object->map()->is_prototype_map());
   2103       // If the attributes were NONE, we would have called set rather than
   2104       // reconfigure.
   2105       DCHECK_NE(NONE, attributes);
   2106       object->RequireSlowElements(*arguments);
   2107       parameter_map->set(1, *arguments);
   2108     } else {
   2109       Handle<FixedArrayBase> arguments(
   2110           FixedArrayBase::cast(parameter_map->get(1)));
   2111       DictionaryElementsAccessor::ReconfigureImpl(
   2112           object, arguments, entry - length, value, attributes);
   2113     }
   2114   }
   2115 };
   2116 
   2117 
   2118 class FastSloppyArgumentsElementsAccessor
   2119     : public SloppyArgumentsElementsAccessor<
   2120           FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
   2121           ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
   2122  public:
   2123   explicit FastSloppyArgumentsElementsAccessor(const char* name)
   2124       : SloppyArgumentsElementsAccessor<
   2125             FastSloppyArgumentsElementsAccessor,
   2126             FastHoleyObjectElementsAccessor,
   2127             ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
   2128 
   2129   static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
   2130     FixedArray* parameter_map = FixedArray::cast(obj->elements());
   2131     Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
   2132     FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
   2133   }
   2134 
   2135   static void AddImpl(Handle<JSObject> object, uint32_t index,
   2136                       Handle<Object> value, PropertyAttributes attributes,
   2137                       uint32_t new_capacity) {
   2138     DCHECK_EQ(NONE, attributes);
   2139     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
   2140     Handle<FixedArrayBase> old_elements(
   2141         FixedArrayBase::cast(parameter_map->get(1)));
   2142     if (old_elements->IsSeededNumberDictionary() ||
   2143         static_cast<uint32_t>(old_elements->length()) < new_capacity) {
   2144       GrowCapacityAndConvertImpl(object, new_capacity);
   2145     }
   2146     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   2147     // For fast holey objects, the entry equals the index. The code above made
   2148     // sure that there's enough space to store the value. We cannot convert
   2149     // index to entry explicitly since the slot still contains the hole, so the
   2150     // current EntryForIndex would indicate that it is "absent" by returning
   2151     // kMaxUInt32.
   2152     FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
   2153   }
   2154 
   2155   static void ReconfigureImpl(Handle<JSObject> object,
   2156                               Handle<FixedArrayBase> store, uint32_t entry,
   2157                               Handle<Object> value,
   2158                               PropertyAttributes attributes) {
   2159     Handle<SeededNumberDictionary> dictionary =
   2160         JSObject::NormalizeElements(object);
   2161     FixedArray::cast(*store)->set(1, *dictionary);
   2162     uint32_t length = static_cast<uint32_t>(store->length()) - 2;
   2163     if (entry >= length) {
   2164       entry = dictionary->FindEntry(entry - length) + length;
   2165     }
   2166     SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
   2167                                                          value, attributes);
   2168   }
   2169 
   2170   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
   2171                                FixedArrayBase* to, ElementsKind from_kind,
   2172                                uint32_t to_start, int packed_size,
   2173                                int copy_size) {
   2174     DCHECK(!to->IsDictionary());
   2175     if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
   2176       CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
   2177                                      to_start, copy_size);
   2178     } else {
   2179       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
   2180       CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
   2181                                  FAST_HOLEY_ELEMENTS, to_start, copy_size);
   2182     }
   2183   }
   2184 
   2185   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
   2186                                          uint32_t capacity) {
   2187     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
   2188     Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
   2189     ElementsKind from_kind = object->GetElementsKind();
   2190     // This method should only be called if there's a reason to update the
   2191     // elements.
   2192     DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
   2193            static_cast<uint32_t>(old_elements->length()) < capacity);
   2194     Handle<FixedArrayBase> elements =
   2195         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
   2196     Handle<Map> new_map = JSObject::GetElementsTransitionMap(
   2197         object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
   2198     JSObject::MigrateToMap(object, new_map);
   2199     parameter_map->set(1, *elements);
   2200     JSObject::ValidateElements(object);
   2201   }
   2202 };
   2203 
   2204 
   2205 }  // namespace
   2206 
   2207 
   2208 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
   2209                      bool allow_appending) {
   2210   DisallowHeapAllocation no_allocation;
   2211   Object* raw_length = NULL;
   2212   const char* elements_type = "array";
   2213   if (obj->IsJSArray()) {
   2214     JSArray* array = JSArray::cast(*obj);
   2215     raw_length = array->length();
   2216   } else {
   2217     raw_length = Smi::FromInt(obj->elements()->length());
   2218     elements_type = "object";
   2219   }
   2220 
   2221   if (raw_length->IsNumber()) {
   2222     double n = raw_length->Number();
   2223     if (FastI2D(FastD2UI(n)) == n) {
   2224       int32_t int32_length = DoubleToInt32(n);
   2225       uint32_t compare_length = static_cast<uint32_t>(int32_length);
   2226       if (allow_appending) compare_length++;
   2227       if (index >= compare_length) {
   2228         PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
   2229                elements_type, op, elements_type, static_cast<int>(int32_length),
   2230                static_cast<int>(index));
   2231         TraceTopFrame(obj->GetIsolate());
   2232         PrintF("]\n");
   2233       }
   2234     } else {
   2235       PrintF("[%s elements length not integer value in ", elements_type);
   2236       TraceTopFrame(obj->GetIsolate());
   2237       PrintF("]\n");
   2238     }
   2239   } else {
   2240     PrintF("[%s elements length not a number in ", elements_type);
   2241     TraceTopFrame(obj->GetIsolate());
   2242     PrintF("]\n");
   2243   }
   2244 }
   2245 
   2246 
   2247 MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
   2248                                                      Arguments* args) {
   2249   if (args->length() == 0) {
   2250     // Optimize the case where there are no parameters passed.
   2251     JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
   2252     return array;
   2253 
   2254   } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
   2255     uint32_t length;
   2256     if (!args->at<Object>(0)->ToArrayLength(&length)) {
   2257       return ThrowArrayLengthRangeError(array->GetIsolate());
   2258     }
   2259 
   2260     // Optimize the case where there is one argument and the argument is a small
   2261     // smi.
   2262     if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
   2263       ElementsKind elements_kind = array->GetElementsKind();
   2264       JSArray::Initialize(array, length, length);
   2265 
   2266       if (!IsFastHoleyElementsKind(elements_kind)) {
   2267         elements_kind = GetHoleyElementsKind(elements_kind);
   2268         JSObject::TransitionElementsKind(array, elements_kind);
   2269       }
   2270     } else if (length == 0) {
   2271       JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
   2272     } else {
   2273       // Take the argument as the length.
   2274       JSArray::Initialize(array, 0);
   2275       JSArray::SetLength(array, length);
   2276     }
   2277     return array;
   2278   }
   2279 
   2280   Factory* factory = array->GetIsolate()->factory();
   2281 
   2282   // Set length and elements on the array.
   2283   int number_of_elements = args->length();
   2284   JSObject::EnsureCanContainElements(
   2285       array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
   2286 
   2287   // Allocate an appropriately typed elements array.
   2288   ElementsKind elements_kind = array->GetElementsKind();
   2289   Handle<FixedArrayBase> elms;
   2290   if (IsFastDoubleElementsKind(elements_kind)) {
   2291     elms = Handle<FixedArrayBase>::cast(
   2292         factory->NewFixedDoubleArray(number_of_elements));
   2293   } else {
   2294     elms = Handle<FixedArrayBase>::cast(
   2295         factory->NewFixedArrayWithHoles(number_of_elements));
   2296   }
   2297 
   2298   // Fill in the content
   2299   switch (array->GetElementsKind()) {
   2300     case FAST_HOLEY_SMI_ELEMENTS:
   2301     case FAST_SMI_ELEMENTS: {
   2302       Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
   2303       for (int entry = 0; entry < number_of_elements; entry++) {
   2304         smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
   2305       }
   2306       break;
   2307     }
   2308     case FAST_HOLEY_ELEMENTS:
   2309     case FAST_ELEMENTS: {
   2310       DisallowHeapAllocation no_gc;
   2311       WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
   2312       Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
   2313       for (int entry = 0; entry < number_of_elements; entry++) {
   2314         object_elms->set(entry, (*args)[entry], mode);
   2315       }
   2316       break;
   2317     }
   2318     case FAST_HOLEY_DOUBLE_ELEMENTS:
   2319     case FAST_DOUBLE_ELEMENTS: {
   2320       Handle<FixedDoubleArray> double_elms =
   2321           Handle<FixedDoubleArray>::cast(elms);
   2322       for (int entry = 0; entry < number_of_elements; entry++) {
   2323         double_elms->set(entry, (*args)[entry]->Number());
   2324       }
   2325       break;
   2326     }
   2327     default:
   2328       UNREACHABLE();
   2329       break;
   2330   }
   2331 
   2332   array->set_elements(*elms);
   2333   array->set_length(Smi::FromInt(number_of_elements));
   2334   return array;
   2335 }
   2336 
   2337 
   2338 void ElementsAccessor::InitializeOncePerProcess() {
   2339   static ElementsAccessor* accessor_array[] = {
   2340 #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
   2341       ELEMENTS_LIST(ACCESSOR_ARRAY)
   2342 #undef ACCESSOR_ARRAY
   2343   };
   2344 
   2345   STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
   2346                 kElementsKindCount);
   2347 
   2348   elements_accessors_ = accessor_array;
   2349 }
   2350 
   2351 
   2352 void ElementsAccessor::TearDown() {
   2353   if (elements_accessors_ == NULL) return;
   2354 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
   2355   ELEMENTS_LIST(ACCESSOR_DELETE)
   2356 #undef ACCESSOR_DELETE
   2357   elements_accessors_ = NULL;
   2358 }
   2359 
   2360 
   2361 Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
   2362                                          uint32_t concat_size) {
   2363   int result_len = 0;
   2364   ElementsKind elements_kind = GetInitialFastElementsKind();
   2365   bool has_double = false;
   2366   {
   2367     DisallowHeapAllocation no_gc;
   2368     // Iterate through all the arguments performing checks
   2369     // and calculating total length.
   2370     bool is_holey = false;
   2371     for (uint32_t i = 0; i < concat_size; i++) {
   2372       Object* arg = (*args)[i];
   2373       int len = Smi::cast(JSArray::cast(arg)->length())->value();
   2374 
   2375       // We shouldn't overflow when adding another len.
   2376       const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
   2377       STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
   2378       USE(kHalfOfMaxInt);
   2379       result_len += len;
   2380       DCHECK(0 <= result_len);
   2381       DCHECK(result_len <= FixedDoubleArray::kMaxLength);
   2382 
   2383       ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
   2384       has_double = has_double || IsFastDoubleElementsKind(arg_kind);
   2385       is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
   2386       elements_kind = GetMoreGeneralElementsKind(elements_kind, arg_kind);
   2387     }
   2388     if (is_holey) {
   2389       elements_kind = GetHoleyElementsKind(elements_kind);
   2390     }
   2391   }
   2392 
   2393   // If a double array is concatted into a fast elements array, the fast
   2394   // elements array needs to be initialized to contain proper holes, since
   2395   // boxing doubles may cause incremental marking.
   2396   ArrayStorageAllocationMode mode =
   2397       has_double && IsFastObjectElementsKind(elements_kind)
   2398           ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
   2399           : DONT_INITIALIZE_ARRAY_ELEMENTS;
   2400   Handle<JSArray> result_array = isolate->factory()->NewJSArray(
   2401       elements_kind, result_len, result_len, Strength::WEAK, mode);
   2402   if (result_len == 0) return result_array;
   2403   int j = 0;
   2404   Handle<FixedArrayBase> storage(result_array->elements(), isolate);
   2405   ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
   2406   for (uint32_t i = 0; i < concat_size; i++) {
   2407     // It is crucial to keep |array| in a raw pointer form to avoid
   2408     // performance degradation.
   2409     JSArray* array = JSArray::cast((*args)[i]);
   2410     int len = Smi::cast(array->length())->value();
   2411     if (len > 0) {
   2412       ElementsKind from_kind = array->GetElementsKind();
   2413       accessor->CopyElements(array, 0, from_kind, storage, j, len);
   2414       j += len;
   2415     }
   2416   }
   2417 
   2418   DCHECK(j == result_len);
   2419   return result_array;
   2420 }
   2421 
   2422 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
   2423 }  // namespace internal
   2424 }  // namespace v8
   2425