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/v8.h"
      6 
      7 #include "src/arguments.h"
      8 #include "src/conversions.h"
      9 #include "src/elements.h"
     10 #include "src/objects.h"
     11 #include "src/utils.h"
     12 
     13 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
     14 // several abstract ElementsAccessor classes are used to allow sharing
     15 // common code.
     16 //
     17 // Inheritance hierarchy:
     18 // - ElementsAccessorBase                        (abstract)
     19 //   - FastElementsAccessor                      (abstract)
     20 //     - FastSmiOrObjectElementsAccessor
     21 //       - FastPackedSmiElementsAccessor
     22 //       - FastHoleySmiElementsAccessor
     23 //       - FastPackedObjectElementsAccessor
     24 //       - FastHoleyObjectElementsAccessor
     25 //     - FastDoubleElementsAccessor
     26 //       - FastPackedDoubleElementsAccessor
     27 //       - FastHoleyDoubleElementsAccessor
     28 //   - TypedElementsAccessor: template, with instantiations:
     29 //     - ExternalInt8ElementsAccessor
     30 //     - ExternalUint8ElementsAccessor
     31 //     - ExternalInt16ElementsAccessor
     32 //     - ExternalUint16ElementsAccessor
     33 //     - ExternalInt32ElementsAccessor
     34 //     - ExternalUint32ElementsAccessor
     35 //     - ExternalFloat32ElementsAccessor
     36 //     - ExternalFloat64ElementsAccessor
     37 //     - ExternalUint8ClampedElementsAccessor
     38 //     - FixedUint8ElementsAccessor
     39 //     - FixedInt8ElementsAccessor
     40 //     - FixedUint16ElementsAccessor
     41 //     - FixedInt16ElementsAccessor
     42 //     - FixedUint32ElementsAccessor
     43 //     - FixedInt32ElementsAccessor
     44 //     - FixedFloat32ElementsAccessor
     45 //     - FixedFloat64ElementsAccessor
     46 //     - FixedUint8ClampedElementsAccessor
     47 //   - DictionaryElementsAccessor
     48 //   - SloppyArgumentsElementsAccessor
     49 
     50 
     51 namespace v8 {
     52 namespace internal {
     53 
     54 
     55 static const int kPackedSizeNotKnown = -1;
     56 
     57 
     58 // First argument in list is the accessor class, the second argument is the
     59 // accessor ElementsKind, and the third is the backing store class.  Use the
     60 // fast element handler for smi-only arrays.  The implementation is currently
     61 // identical.  Note that the order must match that of the ElementsKind enum for
     62 // the |accessor_array[]| below to work.
     63 #define ELEMENTS_LIST(V)                                                \
     64   V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray)       \
     65   V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS,              \
     66     FixedArray)                                                         \
     67   V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray)        \
     68   V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray)   \
     69   V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS,             \
     70     FixedDoubleArray)                                                   \
     71   V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS,        \
     72     FixedDoubleArray)                                                   \
     73   V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS,                    \
     74     SeededNumberDictionary)                                             \
     75   V(SloppyArgumentsElementsAccessor, SLOPPY_ARGUMENTS_ELEMENTS,         \
     76     FixedArray)                                                         \
     77   V(ExternalInt8ElementsAccessor, EXTERNAL_INT8_ELEMENTS,               \
     78     ExternalInt8Array)                                                  \
     79   V(ExternalUint8ElementsAccessor,                                      \
     80     EXTERNAL_UINT8_ELEMENTS, ExternalUint8Array)                        \
     81   V(ExternalInt16ElementsAccessor, EXTERNAL_INT16_ELEMENTS,             \
     82     ExternalInt16Array)                                                 \
     83   V(ExternalUint16ElementsAccessor,                                     \
     84     EXTERNAL_UINT16_ELEMENTS, ExternalUint16Array)                      \
     85   V(ExternalInt32ElementsAccessor, EXTERNAL_INT32_ELEMENTS,             \
     86     ExternalInt32Array)                                                 \
     87   V(ExternalUint32ElementsAccessor,                                     \
     88     EXTERNAL_UINT32_ELEMENTS, ExternalUint32Array)                      \
     89   V(ExternalFloat32ElementsAccessor,                                    \
     90     EXTERNAL_FLOAT32_ELEMENTS, ExternalFloat32Array)                    \
     91   V(ExternalFloat64ElementsAccessor,                                    \
     92     EXTERNAL_FLOAT64_ELEMENTS, ExternalFloat64Array)                    \
     93   V(ExternalUint8ClampedElementsAccessor,                               \
     94     EXTERNAL_UINT8_CLAMPED_ELEMENTS,                                    \
     95     ExternalUint8ClampedArray)                                          \
     96   V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array)        \
     97   V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array)           \
     98   V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array)     \
     99   V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array)        \
    100   V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array)     \
    101   V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array)        \
    102   V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array)  \
    103   V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array)  \
    104   V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS,          \
    105     FixedUint8ClampedArray)
    106 
    107 
    108 template<ElementsKind Kind> class ElementsKindTraits {
    109  public:
    110   typedef FixedArrayBase BackingStore;
    111 };
    112 
    113 #define ELEMENTS_TRAITS(Class, KindParam, Store)               \
    114 template<> class ElementsKindTraits<KindParam> {               \
    115  public:   /* NOLINT */                                        \
    116   static const ElementsKind Kind = KindParam;                  \
    117   typedef Store BackingStore;                                  \
    118 };
    119 ELEMENTS_LIST(ELEMENTS_TRAITS)
    120 #undef ELEMENTS_TRAITS
    121 
    122 
    123 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
    124 
    125 
    126 static bool HasKey(Handle<FixedArray> array, Handle<Object> key_handle) {
    127   DisallowHeapAllocation no_gc;
    128   Object* key = *key_handle;
    129   int len0 = array->length();
    130   for (int i = 0; i < len0; i++) {
    131     Object* element = array->get(i);
    132     if (element->IsSmi() && element == key) return true;
    133     if (element->IsString() &&
    134         key->IsString() && String::cast(element)->Equals(String::cast(key))) {
    135       return true;
    136     }
    137   }
    138   return false;
    139 }
    140 
    141 
    142 MUST_USE_RESULT
    143 static MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
    144   THROW_NEW_ERROR(isolate, NewRangeError("invalid_array_length",
    145                                          HandleVector<Object>(NULL, 0)),
    146                   Object);
    147 }
    148 
    149 
    150 static void CopyObjectToObjectElements(FixedArrayBase* from_base,
    151                                        ElementsKind from_kind,
    152                                        uint32_t from_start,
    153                                        FixedArrayBase* to_base,
    154                                        ElementsKind to_kind, uint32_t to_start,
    155                                        int raw_copy_size) {
    156   DCHECK(to_base->map() !=
    157       from_base->GetIsolate()->heap()->fixed_cow_array_map());
    158   DisallowHeapAllocation no_allocation;
    159   int copy_size = raw_copy_size;
    160   if (raw_copy_size < 0) {
    161     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    162            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    163     copy_size = Min(from_base->length() - from_start,
    164                     to_base->length() - to_start);
    165     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    166       int start = to_start + copy_size;
    167       int length = to_base->length() - start;
    168       if (length > 0) {
    169         Heap* heap = from_base->GetHeap();
    170         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
    171                       heap->the_hole_value(), length);
    172       }
    173     }
    174   }
    175   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    176          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    177   if (copy_size == 0) return;
    178   FixedArray* from = FixedArray::cast(from_base);
    179   FixedArray* to = FixedArray::cast(to_base);
    180   DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
    181   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
    182   Address to_address = to->address() + FixedArray::kHeaderSize;
    183   Address from_address = from->address() + FixedArray::kHeaderSize;
    184   CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
    185             reinterpret_cast<Object**>(from_address) + from_start,
    186             static_cast<size_t>(copy_size));
    187   if (IsFastObjectElementsKind(from_kind) &&
    188       IsFastObjectElementsKind(to_kind)) {
    189     Heap* heap = from->GetHeap();
    190     if (!heap->InNewSpace(to)) {
    191       heap->RecordWrites(to->address(),
    192                          to->OffsetOfElementAt(to_start),
    193                          copy_size);
    194     }
    195     heap->incremental_marking()->RecordWrites(to);
    196   }
    197 }
    198 
    199 
    200 static void CopyDictionaryToObjectElements(
    201     FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
    202     ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
    203   DisallowHeapAllocation no_allocation;
    204   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
    205   int copy_size = raw_copy_size;
    206   Heap* heap = from->GetHeap();
    207   if (raw_copy_size < 0) {
    208     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    209            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    210     copy_size = from->max_number_key() + 1 - from_start;
    211     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    212       int start = to_start + copy_size;
    213       int length = to_base->length() - start;
    214       if (length > 0) {
    215         Heap* heap = from->GetHeap();
    216         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
    217                       heap->the_hole_value(), length);
    218       }
    219     }
    220   }
    221   DCHECK(to_base != from_base);
    222   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
    223   if (copy_size == 0) return;
    224   FixedArray* to = FixedArray::cast(to_base);
    225   uint32_t to_length = to->length();
    226   if (to_start + copy_size > to_length) {
    227     copy_size = to_length - to_start;
    228   }
    229   for (int i = 0; i < copy_size; i++) {
    230     int entry = from->FindEntry(i + from_start);
    231     if (entry != SeededNumberDictionary::kNotFound) {
    232       Object* value = from->ValueAt(entry);
    233       DCHECK(!value->IsTheHole());
    234       to->set(i + to_start, value, SKIP_WRITE_BARRIER);
    235     } else {
    236       to->set_the_hole(i + to_start);
    237     }
    238   }
    239   if (IsFastObjectElementsKind(to_kind)) {
    240     if (!heap->InNewSpace(to)) {
    241       heap->RecordWrites(to->address(),
    242                          to->OffsetOfElementAt(to_start),
    243                          copy_size);
    244     }
    245     heap->incremental_marking()->RecordWrites(to);
    246   }
    247 }
    248 
    249 
    250 static void CopyDoubleToObjectElements(Handle<FixedArrayBase> from_base,
    251                                        uint32_t from_start,
    252                                        Handle<FixedArrayBase> to_base,
    253                                        ElementsKind to_kind,
    254                                        uint32_t to_start,
    255                                        int raw_copy_size) {
    256   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
    257   int copy_size = raw_copy_size;
    258   if (raw_copy_size < 0) {
    259     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    260            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    261     copy_size = Min(from_base->length() - from_start,
    262                     to_base->length() - to_start);
    263     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    264       // Also initialize the area that will be copied over since HeapNumber
    265       // allocation below can cause an incremental marking step, requiring all
    266       // existing heap objects to be propertly initialized.
    267       int start = to_start;
    268       int length = to_base->length() - start;
    269       if (length > 0) {
    270         Heap* heap = from_base->GetHeap();
    271         MemsetPointer(FixedArray::cast(*to_base)->data_start() + start,
    272                       heap->the_hole_value(), length);
    273       }
    274     }
    275   }
    276   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    277          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    278   if (copy_size == 0) return;
    279   Isolate* isolate = from_base->GetIsolate();
    280   Handle<FixedDoubleArray> from = Handle<FixedDoubleArray>::cast(from_base);
    281   Handle<FixedArray> to = Handle<FixedArray>::cast(to_base);
    282   for (int i = 0; i < copy_size; ++i) {
    283     HandleScope scope(isolate);
    284     if (IsFastSmiElementsKind(to_kind)) {
    285       UNIMPLEMENTED();
    286     } else {
    287       DCHECK(IsFastObjectElementsKind(to_kind));
    288       Handle<Object> value = FixedDoubleArray::get(from, i + from_start);
    289       to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
    290     }
    291   }
    292 }
    293 
    294 
    295 static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
    296                                        uint32_t from_start,
    297                                        FixedArrayBase* to_base,
    298                                        uint32_t to_start, int raw_copy_size) {
    299   DisallowHeapAllocation no_allocation;
    300   int copy_size = raw_copy_size;
    301   if (raw_copy_size < 0) {
    302     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    303            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    304     copy_size = Min(from_base->length() - from_start,
    305                     to_base->length() - to_start);
    306     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    307       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    308         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    309       }
    310     }
    311   }
    312   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    313          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    314   if (copy_size == 0) return;
    315   FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
    316   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    317   Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
    318   Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
    319   to_address += kDoubleSize * to_start;
    320   from_address += kDoubleSize * from_start;
    321   int words_per_double = (kDoubleSize / kPointerSize);
    322   CopyWords(reinterpret_cast<Object**>(to_address),
    323             reinterpret_cast<Object**>(from_address),
    324             static_cast<size_t>(words_per_double * copy_size));
    325 }
    326 
    327 
    328 static void CopySmiToDoubleElements(FixedArrayBase* from_base,
    329                                     uint32_t from_start,
    330                                     FixedArrayBase* to_base, uint32_t to_start,
    331                                     int raw_copy_size) {
    332   DisallowHeapAllocation no_allocation;
    333   int copy_size = raw_copy_size;
    334   if (raw_copy_size < 0) {
    335     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    336            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    337     copy_size = from_base->length() - from_start;
    338     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    339       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    340         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    341       }
    342     }
    343   }
    344   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    345          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    346   if (copy_size == 0) return;
    347   FixedArray* from = FixedArray::cast(from_base);
    348   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    349   Object* the_hole = from->GetHeap()->the_hole_value();
    350   for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
    351        from_start < from_end; from_start++, to_start++) {
    352     Object* hole_or_smi = from->get(from_start);
    353     if (hole_or_smi == the_hole) {
    354       to->set_the_hole(to_start);
    355     } else {
    356       to->set(to_start, Smi::cast(hole_or_smi)->value());
    357     }
    358   }
    359 }
    360 
    361 
    362 static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
    363                                           uint32_t from_start,
    364                                           FixedArrayBase* to_base,
    365                                           uint32_t to_start, int packed_size,
    366                                           int raw_copy_size) {
    367   DisallowHeapAllocation no_allocation;
    368   int copy_size = raw_copy_size;
    369   uint32_t to_end;
    370   if (raw_copy_size < 0) {
    371     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    372            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    373     copy_size = packed_size - from_start;
    374     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    375       to_end = to_base->length();
    376       for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
    377         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    378       }
    379     } else {
    380       to_end = to_start + static_cast<uint32_t>(copy_size);
    381     }
    382   } else {
    383     to_end = to_start + static_cast<uint32_t>(copy_size);
    384   }
    385   DCHECK(static_cast<int>(to_end) <= to_base->length());
    386   DCHECK(packed_size >= 0 && packed_size <= copy_size);
    387   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    388          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    389   if (copy_size == 0) return;
    390   FixedArray* from = FixedArray::cast(from_base);
    391   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    392   for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
    393        from_start < from_end; from_start++, to_start++) {
    394     Object* smi = from->get(from_start);
    395     DCHECK(!smi->IsTheHole());
    396     to->set(to_start, Smi::cast(smi)->value());
    397   }
    398 }
    399 
    400 
    401 static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
    402                                        uint32_t from_start,
    403                                        FixedArrayBase* to_base,
    404                                        uint32_t to_start, int raw_copy_size) {
    405   DisallowHeapAllocation no_allocation;
    406   int copy_size = raw_copy_size;
    407   if (raw_copy_size < 0) {
    408     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    409            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    410     copy_size = from_base->length() - from_start;
    411     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    412       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    413         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    414       }
    415     }
    416   }
    417   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
    418          (copy_size + static_cast<int>(from_start)) <= from_base->length());
    419   if (copy_size == 0) return;
    420   FixedArray* from = FixedArray::cast(from_base);
    421   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    422   Object* the_hole = from->GetHeap()->the_hole_value();
    423   for (uint32_t from_end = from_start + copy_size;
    424        from_start < from_end; from_start++, to_start++) {
    425     Object* hole_or_object = from->get(from_start);
    426     if (hole_or_object == the_hole) {
    427       to->set_the_hole(to_start);
    428     } else {
    429       to->set(to_start, hole_or_object->Number());
    430     }
    431   }
    432 }
    433 
    434 
    435 static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
    436                                            uint32_t from_start,
    437                                            FixedArrayBase* to_base,
    438                                            uint32_t to_start,
    439                                            int raw_copy_size) {
    440   DisallowHeapAllocation no_allocation;
    441   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
    442   int copy_size = raw_copy_size;
    443   if (copy_size < 0) {
    444     DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
    445            copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    446     copy_size = from->max_number_key() + 1 - from_start;
    447     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    448       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
    449         FixedDoubleArray::cast(to_base)->set_the_hole(i);
    450       }
    451     }
    452   }
    453   if (copy_size == 0) return;
    454   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
    455   uint32_t to_length = to->length();
    456   if (to_start + copy_size > to_length) {
    457     copy_size = to_length - to_start;
    458   }
    459   for (int i = 0; i < copy_size; i++) {
    460     int entry = from->FindEntry(i + from_start);
    461     if (entry != SeededNumberDictionary::kNotFound) {
    462       to->set(i + to_start, from->ValueAt(entry)->Number());
    463     } else {
    464       to->set_the_hole(i + to_start);
    465     }
    466   }
    467 }
    468 
    469 
    470 static void TraceTopFrame(Isolate* isolate) {
    471   StackFrameIterator it(isolate);
    472   if (it.done()) {
    473     PrintF("unknown location (no JavaScript frames present)");
    474     return;
    475   }
    476   StackFrame* raw_frame = it.frame();
    477   if (raw_frame->is_internal()) {
    478     Code* apply_builtin = isolate->builtins()->builtin(
    479         Builtins::kFunctionApply);
    480     if (raw_frame->unchecked_code() == apply_builtin) {
    481       PrintF("apply from ");
    482       it.Advance();
    483       raw_frame = it.frame();
    484     }
    485   }
    486   JavaScriptFrame::PrintTop(isolate, stdout, false, true);
    487 }
    488 
    489 
    490 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t key,
    491                      bool allow_appending) {
    492   DisallowHeapAllocation no_allocation;
    493   Object* raw_length = NULL;
    494   const char* elements_type = "array";
    495   if (obj->IsJSArray()) {
    496     JSArray* array = JSArray::cast(*obj);
    497     raw_length = array->length();
    498   } else {
    499     raw_length = Smi::FromInt(obj->elements()->length());
    500     elements_type = "object";
    501   }
    502 
    503   if (raw_length->IsNumber()) {
    504     double n = raw_length->Number();
    505     if (FastI2D(FastD2UI(n)) == n) {
    506       int32_t int32_length = DoubleToInt32(n);
    507       uint32_t compare_length = static_cast<uint32_t>(int32_length);
    508       if (allow_appending) compare_length++;
    509       if (key >= compare_length) {
    510         PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
    511                elements_type, op, elements_type,
    512                static_cast<int>(int32_length),
    513                static_cast<int>(key));
    514         TraceTopFrame(obj->GetIsolate());
    515         PrintF("]\n");
    516       }
    517     } else {
    518       PrintF("[%s elements length not integer value in ", elements_type);
    519       TraceTopFrame(obj->GetIsolate());
    520       PrintF("]\n");
    521     }
    522   } else {
    523     PrintF("[%s elements length not a number in ", elements_type);
    524     TraceTopFrame(obj->GetIsolate());
    525     PrintF("]\n");
    526   }
    527 }
    528 
    529 
    530 // Base class for element handler implementations. Contains the
    531 // the common logic for objects with different ElementsKinds.
    532 // Subclasses must specialize method for which the element
    533 // implementation differs from the base class implementation.
    534 //
    535 // This class is intended to be used in the following way:
    536 //
    537 //   class SomeElementsAccessor :
    538 //       public ElementsAccessorBase<SomeElementsAccessor,
    539 //                                   BackingStoreClass> {
    540 //     ...
    541 //   }
    542 //
    543 // This is an example of the Curiously Recurring Template Pattern (see
    544 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).  We use
    545 // CRTP to guarantee aggressive compile time optimizations (i.e.  inlining and
    546 // specialization of SomeElementsAccessor methods).
    547 template <typename ElementsAccessorSubclass,
    548           typename ElementsTraitsParam>
    549 class ElementsAccessorBase : public ElementsAccessor {
    550  protected:
    551   explicit ElementsAccessorBase(const char* name)
    552       : ElementsAccessor(name) { }
    553 
    554   typedef ElementsTraitsParam ElementsTraits;
    555   typedef typename ElementsTraitsParam::BackingStore BackingStore;
    556 
    557   virtual ElementsKind kind() const FINAL OVERRIDE {
    558     return ElementsTraits::Kind;
    559   }
    560 
    561   static void ValidateContents(Handle<JSObject> holder, int length) {
    562   }
    563 
    564   static void ValidateImpl(Handle<JSObject> holder) {
    565     Handle<FixedArrayBase> fixed_array_base(holder->elements());
    566     if (!fixed_array_base->IsHeapObject()) return;
    567     // Arrays that have been shifted in place can't be verified.
    568     if (fixed_array_base->IsFiller()) return;
    569     int length = 0;
    570     if (holder->IsJSArray()) {
    571       Object* length_obj = Handle<JSArray>::cast(holder)->length();
    572       if (length_obj->IsSmi()) {
    573         length = Smi::cast(length_obj)->value();
    574       }
    575     } else {
    576       length = fixed_array_base->length();
    577     }
    578     ElementsAccessorSubclass::ValidateContents(holder, length);
    579   }
    580 
    581   virtual void Validate(Handle<JSObject> holder) FINAL OVERRIDE {
    582     DisallowHeapAllocation no_gc;
    583     ElementsAccessorSubclass::ValidateImpl(holder);
    584   }
    585 
    586   static bool HasElementImpl(Handle<Object> receiver,
    587                              Handle<JSObject> holder,
    588                              uint32_t key,
    589                              Handle<FixedArrayBase> backing_store) {
    590     return ElementsAccessorSubclass::GetAttributesImpl(
    591         receiver, holder, key, backing_store) != ABSENT;
    592   }
    593 
    594   virtual bool HasElement(
    595       Handle<Object> receiver,
    596       Handle<JSObject> holder,
    597       uint32_t key,
    598       Handle<FixedArrayBase> backing_store) FINAL OVERRIDE {
    599     return ElementsAccessorSubclass::HasElementImpl(
    600         receiver, holder, key, backing_store);
    601   }
    602 
    603   MUST_USE_RESULT virtual MaybeHandle<Object> Get(
    604       Handle<Object> receiver,
    605       Handle<JSObject> holder,
    606       uint32_t key,
    607       Handle<FixedArrayBase> backing_store) FINAL OVERRIDE {
    608     if (!IsExternalArrayElementsKind(ElementsTraits::Kind) &&
    609         FLAG_trace_js_array_abuse) {
    610       CheckArrayAbuse(holder, "elements read", key);
    611     }
    612 
    613     if (IsExternalArrayElementsKind(ElementsTraits::Kind) &&
    614         FLAG_trace_external_array_abuse) {
    615       CheckArrayAbuse(holder, "external elements read", key);
    616     }
    617 
    618     return ElementsAccessorSubclass::GetImpl(
    619         receiver, holder, key, backing_store);
    620   }
    621 
    622   MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
    623       Handle<Object> receiver,
    624       Handle<JSObject> obj,
    625       uint32_t key,
    626       Handle<FixedArrayBase> backing_store) {
    627     if (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
    628       return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
    629     } else {
    630       return backing_store->GetIsolate()->factory()->the_hole_value();
    631     }
    632   }
    633 
    634   MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
    635       Handle<Object> receiver,
    636       Handle<JSObject> holder,
    637       uint32_t key,
    638       Handle<FixedArrayBase> backing_store) FINAL OVERRIDE {
    639     return ElementsAccessorSubclass::GetAttributesImpl(
    640         receiver, holder, key, backing_store);
    641   }
    642 
    643   MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
    644         Handle<Object> receiver,
    645         Handle<JSObject> obj,
    646         uint32_t key,
    647         Handle<FixedArrayBase> backing_store) {
    648     if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
    649       return ABSENT;
    650     }
    651     return
    652         Handle<BackingStore>::cast(backing_store)->is_the_hole(key)
    653           ? ABSENT : NONE;
    654   }
    655 
    656   MUST_USE_RESULT virtual MaybeHandle<AccessorPair> GetAccessorPair(
    657       Handle<Object> receiver,
    658       Handle<JSObject> holder,
    659       uint32_t key,
    660       Handle<FixedArrayBase> backing_store) FINAL OVERRIDE {
    661     return ElementsAccessorSubclass::GetAccessorPairImpl(
    662         receiver, holder, key, backing_store);
    663   }
    664 
    665   MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
    666       Handle<Object> receiver,
    667       Handle<JSObject> obj,
    668       uint32_t key,
    669       Handle<FixedArrayBase> backing_store) {
    670     return MaybeHandle<AccessorPair>();
    671   }
    672 
    673   MUST_USE_RESULT virtual MaybeHandle<Object> SetLength(
    674       Handle<JSArray> array,
    675       Handle<Object> length) FINAL OVERRIDE {
    676     return ElementsAccessorSubclass::SetLengthImpl(
    677         array, length, handle(array->elements()));
    678   }
    679 
    680   MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
    681       Handle<JSObject> obj,
    682       Handle<Object> length,
    683       Handle<FixedArrayBase> backing_store);
    684 
    685   virtual void SetCapacityAndLength(
    686       Handle<JSArray> array,
    687       int capacity,
    688       int length) FINAL OVERRIDE {
    689     ElementsAccessorSubclass::
    690         SetFastElementsCapacityAndLength(array, capacity, length);
    691   }
    692 
    693   static void SetFastElementsCapacityAndLength(
    694       Handle<JSObject> obj,
    695       int capacity,
    696       int length) {
    697     UNIMPLEMENTED();
    698   }
    699 
    700   MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
    701       Handle<JSObject> obj,
    702       uint32_t key,
    703       JSReceiver::DeleteMode mode) OVERRIDE = 0;
    704 
    705   static void CopyElementsImpl(Handle<FixedArrayBase> from,
    706                                uint32_t from_start,
    707                                Handle<FixedArrayBase> to,
    708                                ElementsKind from_kind,
    709                                uint32_t to_start,
    710                                int packed_size,
    711                                int copy_size) {
    712     UNREACHABLE();
    713   }
    714 
    715   virtual void CopyElements(
    716       Handle<FixedArrayBase> from,
    717       uint32_t from_start,
    718       ElementsKind from_kind,
    719       Handle<FixedArrayBase> to,
    720       uint32_t to_start,
    721       int copy_size) FINAL OVERRIDE {
    722     DCHECK(!from.is_null());
    723     ElementsAccessorSubclass::CopyElementsImpl(
    724         from, from_start, to, from_kind, to_start, kPackedSizeNotKnown,
    725         copy_size);
    726   }
    727 
    728   virtual void CopyElements(
    729       JSObject* from_holder,
    730       uint32_t from_start,
    731       ElementsKind from_kind,
    732       Handle<FixedArrayBase> to,
    733       uint32_t to_start,
    734       int copy_size) FINAL OVERRIDE {
    735     int packed_size = kPackedSizeNotKnown;
    736     bool is_packed = IsFastPackedElementsKind(from_kind) &&
    737         from_holder->IsJSArray();
    738     if (is_packed) {
    739       packed_size =
    740           Smi::cast(JSArray::cast(from_holder)->length())->value();
    741       if (copy_size >= 0 && packed_size > copy_size) {
    742         packed_size = copy_size;
    743       }
    744     }
    745     Handle<FixedArrayBase> from(from_holder->elements());
    746     ElementsAccessorSubclass::CopyElementsImpl(
    747         from, from_start, to, from_kind, to_start, packed_size, copy_size);
    748   }
    749 
    750   virtual MaybeHandle<FixedArray> AddElementsToFixedArray(
    751       Handle<Object> receiver,
    752       Handle<JSObject> holder,
    753       Handle<FixedArray> to,
    754       Handle<FixedArrayBase> from) FINAL OVERRIDE {
    755     int len0 = to->length();
    756 #ifdef ENABLE_SLOW_DCHECKS
    757     if (FLAG_enable_slow_asserts) {
    758       for (int i = 0; i < len0; i++) {
    759         DCHECK(!to->get(i)->IsTheHole());
    760       }
    761     }
    762 #endif
    763 
    764     // Optimize if 'other' is empty.
    765     // We cannot optimize if 'this' is empty, as other may have holes.
    766     uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from);
    767     if (len1 == 0) return to;
    768 
    769     Isolate* isolate = from->GetIsolate();
    770 
    771     // Compute how many elements are not in other.
    772     uint32_t extra = 0;
    773     for (uint32_t y = 0; y < len1; y++) {
    774       uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
    775       if (ElementsAccessorSubclass::HasElementImpl(
    776               receiver, holder, key, from)) {
    777         Handle<Object> value;
    778         ASSIGN_RETURN_ON_EXCEPTION(
    779             isolate, value,
    780             ElementsAccessorSubclass::GetImpl(receiver, holder, key, from),
    781             FixedArray);
    782 
    783         DCHECK(!value->IsTheHole());
    784         if (!HasKey(to, value)) {
    785           extra++;
    786         }
    787       }
    788     }
    789 
    790     if (extra == 0) return to;
    791 
    792     // Allocate the result
    793     Handle<FixedArray> result = isolate->factory()->NewFixedArray(len0 + extra);
    794 
    795     // Fill in the content
    796     {
    797       DisallowHeapAllocation no_gc;
    798       WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
    799       for (int i = 0; i < len0; i++) {
    800         Object* e = to->get(i);
    801         DCHECK(e->IsString() || e->IsNumber());
    802         result->set(i, e, mode);
    803       }
    804     }
    805     // Fill in the extra values.
    806     uint32_t index = 0;
    807     for (uint32_t y = 0; y < len1; y++) {
    808       uint32_t key =
    809           ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
    810       if (ElementsAccessorSubclass::HasElementImpl(
    811               receiver, holder, key, from)) {
    812         Handle<Object> value;
    813         ASSIGN_RETURN_ON_EXCEPTION(
    814             isolate, value,
    815             ElementsAccessorSubclass::GetImpl(receiver, holder, key, from),
    816             FixedArray);
    817         if (!value->IsTheHole() && !HasKey(to, value)) {
    818           result->set(len0 + index, *value);
    819           index++;
    820         }
    821       }
    822     }
    823     DCHECK(extra == index);
    824     return result;
    825   }
    826 
    827  protected:
    828   static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
    829     return backing_store->length();
    830   }
    831 
    832   virtual uint32_t GetCapacity(Handle<FixedArrayBase> backing_store)
    833       FINAL OVERRIDE {
    834     return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
    835   }
    836 
    837   static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> backing_store,
    838                                      uint32_t index) {
    839     return index;
    840   }
    841 
    842   virtual uint32_t GetKeyForIndex(Handle<FixedArrayBase> backing_store,
    843                                   uint32_t index) FINAL OVERRIDE {
    844     return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
    845   }
    846 
    847  private:
    848   DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
    849 };
    850 
    851 
    852 // Super class for all fast element arrays.
    853 template<typename FastElementsAccessorSubclass,
    854          typename KindTraits>
    855 class FastElementsAccessor
    856     : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
    857  public:
    858   explicit FastElementsAccessor(const char* name)
    859       : ElementsAccessorBase<FastElementsAccessorSubclass,
    860                              KindTraits>(name) {}
    861  protected:
    862   friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
    863   friend class SloppyArgumentsElementsAccessor;
    864 
    865   typedef typename KindTraits::BackingStore BackingStore;
    866 
    867   // Adjusts the length of the fast backing store.
    868   static Handle<Object> SetLengthWithoutNormalize(
    869       Handle<FixedArrayBase> backing_store,
    870       Handle<JSArray> array,
    871       Handle<Object> length_object,
    872       uint32_t length) {
    873     Isolate* isolate = array->GetIsolate();
    874     uint32_t old_capacity = backing_store->length();
    875     Handle<Object> old_length(array->length(), isolate);
    876     bool same_or_smaller_size = old_length->IsSmi() &&
    877         static_cast<uint32_t>(Handle<Smi>::cast(old_length)->value()) >= length;
    878     ElementsKind kind = array->GetElementsKind();
    879 
    880     if (!same_or_smaller_size && IsFastElementsKind(kind) &&
    881         !IsFastHoleyElementsKind(kind)) {
    882       kind = GetHoleyElementsKind(kind);
    883       JSObject::TransitionElementsKind(array, kind);
    884     }
    885 
    886     // Check whether the backing store should be shrunk.
    887     if (length <= old_capacity) {
    888       if (array->HasFastSmiOrObjectElements()) {
    889         backing_store = JSObject::EnsureWritableFastElements(array);
    890       }
    891       if (2 * length <= old_capacity) {
    892         // If more than half the elements won't be used, trim the array.
    893         if (length == 0) {
    894           array->initialize_elements();
    895         } else {
    896           isolate->heap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(
    897               *backing_store, old_capacity - length);
    898         }
    899       } else {
    900         // Otherwise, fill the unused tail with holes.
    901         int old_length = FastD2IChecked(array->length()->Number());
    902         for (int i = length; i < old_length; i++) {
    903           Handle<BackingStore>::cast(backing_store)->set_the_hole(i);
    904         }
    905       }
    906       return length_object;
    907     }
    908 
    909     // Check whether the backing store should be expanded.
    910     uint32_t min = JSObject::NewElementsCapacity(old_capacity);
    911     uint32_t new_capacity = length > min ? length : min;
    912     FastElementsAccessorSubclass::SetFastElementsCapacityAndLength(
    913         array, new_capacity, length);
    914     JSObject::ValidateElements(array);
    915     return length_object;
    916   }
    917 
    918   static Handle<Object> DeleteCommon(Handle<JSObject> obj,
    919                                      uint32_t key,
    920                                      JSReceiver::DeleteMode mode) {
    921     DCHECK(obj->HasFastSmiOrObjectElements() ||
    922            obj->HasFastDoubleElements() ||
    923            obj->HasFastArgumentsElements());
    924     Isolate* isolate = obj->GetIsolate();
    925     Heap* heap = obj->GetHeap();
    926     Handle<FixedArrayBase> elements(obj->elements());
    927     if (*elements == heap->empty_fixed_array()) {
    928       return isolate->factory()->true_value();
    929     }
    930     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
    931     bool is_sloppy_arguments_elements_map =
    932         backing_store->map() == heap->sloppy_arguments_elements_map();
    933     if (is_sloppy_arguments_elements_map) {
    934       backing_store = handle(
    935           BackingStore::cast(Handle<FixedArray>::cast(backing_store)->get(1)),
    936           isolate);
    937     }
    938     uint32_t length = static_cast<uint32_t>(
    939         obj->IsJSArray()
    940         ? Smi::cast(Handle<JSArray>::cast(obj)->length())->value()
    941         : backing_store->length());
    942     if (key < length) {
    943       if (!is_sloppy_arguments_elements_map) {
    944         ElementsKind kind = KindTraits::Kind;
    945         if (IsFastPackedElementsKind(kind)) {
    946           JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
    947         }
    948         if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
    949           Handle<Object> writable = JSObject::EnsureWritableFastElements(obj);
    950           backing_store = Handle<BackingStore>::cast(writable);
    951         }
    952       }
    953       backing_store->set_the_hole(key);
    954       // If an old space backing store is larger than a certain size and
    955       // has too few used values, normalize it.
    956       // To avoid doing the check on every delete we require at least
    957       // one adjacent hole to the value being deleted.
    958       const int kMinLengthForSparsenessCheck = 64;
    959       if (backing_store->length() >= kMinLengthForSparsenessCheck &&
    960           !heap->InNewSpace(*backing_store) &&
    961           ((key > 0 && backing_store->is_the_hole(key - 1)) ||
    962            (key + 1 < length && backing_store->is_the_hole(key + 1)))) {
    963         int num_used = 0;
    964         for (int i = 0; i < backing_store->length(); ++i) {
    965           if (!backing_store->is_the_hole(i)) ++num_used;
    966           // Bail out early if more than 1/4 is used.
    967           if (4 * num_used > backing_store->length()) break;
    968         }
    969         if (4 * num_used <= backing_store->length()) {
    970           JSObject::NormalizeElements(obj);
    971         }
    972       }
    973     }
    974     return isolate->factory()->true_value();
    975   }
    976 
    977   virtual MaybeHandle<Object> Delete(
    978       Handle<JSObject> obj,
    979       uint32_t key,
    980       JSReceiver::DeleteMode mode) FINAL OVERRIDE {
    981     return DeleteCommon(obj, key, mode);
    982   }
    983 
    984   static bool HasElementImpl(
    985       Handle<Object> receiver,
    986       Handle<JSObject> holder,
    987       uint32_t key,
    988       Handle<FixedArrayBase> backing_store) {
    989     if (key >= static_cast<uint32_t>(backing_store->length())) {
    990       return false;
    991     }
    992     return !Handle<BackingStore>::cast(backing_store)->is_the_hole(key);
    993   }
    994 
    995   static void ValidateContents(Handle<JSObject> holder, int length) {
    996 #if DEBUG
    997     Isolate* isolate = holder->GetIsolate();
    998     HandleScope scope(isolate);
    999     Handle<FixedArrayBase> elements(holder->elements(), isolate);
   1000     Map* map = elements->map();
   1001     DCHECK((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
   1002             (map == isolate->heap()->fixed_array_map() ||
   1003              map == isolate->heap()->fixed_cow_array_map())) ||
   1004            (IsFastDoubleElementsKind(KindTraits::Kind) ==
   1005             ((map == isolate->heap()->fixed_array_map() && length == 0) ||
   1006              map == isolate->heap()->fixed_double_array_map())));
   1007     DisallowHeapAllocation no_gc;
   1008     for (int i = 0; i < length; i++) {
   1009       HandleScope scope(isolate);
   1010       Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
   1011       DCHECK((!IsFastSmiElementsKind(KindTraits::Kind) ||
   1012               BackingStore::get(backing_store, i)->IsSmi()) ||
   1013              (IsFastHoleyElementsKind(KindTraits::Kind) ==
   1014               backing_store->is_the_hole(i)));
   1015     }
   1016 #endif
   1017   }
   1018 };
   1019 
   1020 
   1021 static inline ElementsKind ElementsKindForArray(Handle<FixedArrayBase> array) {
   1022   switch (array->map()->instance_type()) {
   1023     case FIXED_ARRAY_TYPE:
   1024       if (array->IsDictionary()) {
   1025         return DICTIONARY_ELEMENTS;
   1026       } else {
   1027         return FAST_HOLEY_ELEMENTS;
   1028       }
   1029     case FIXED_DOUBLE_ARRAY_TYPE:
   1030       return FAST_HOLEY_DOUBLE_ELEMENTS;
   1031 
   1032 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
   1033     case EXTERNAL_##TYPE##_ARRAY_TYPE:                                        \
   1034       return EXTERNAL_##TYPE##_ELEMENTS;                                      \
   1035     case FIXED_##TYPE##_ARRAY_TYPE:                                           \
   1036       return TYPE##_ELEMENTS;
   1037 
   1038     TYPED_ARRAYS(TYPED_ARRAY_CASE)
   1039 #undef TYPED_ARRAY_CASE
   1040 
   1041     default:
   1042       UNREACHABLE();
   1043   }
   1044   return FAST_HOLEY_ELEMENTS;
   1045 }
   1046 
   1047 
   1048 template<typename FastElementsAccessorSubclass,
   1049          typename KindTraits>
   1050 class FastSmiOrObjectElementsAccessor
   1051     : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
   1052  public:
   1053   explicit FastSmiOrObjectElementsAccessor(const char* name)
   1054       : FastElementsAccessor<FastElementsAccessorSubclass,
   1055                              KindTraits>(name) {}
   1056 
   1057   static void CopyElementsImpl(Handle<FixedArrayBase> from,
   1058                                uint32_t from_start,
   1059                                Handle<FixedArrayBase> to,
   1060                                ElementsKind from_kind,
   1061                                uint32_t to_start,
   1062                                int packed_size,
   1063                                int copy_size) {
   1064     ElementsKind to_kind = KindTraits::Kind;
   1065     switch (from_kind) {
   1066       case FAST_SMI_ELEMENTS:
   1067       case FAST_HOLEY_SMI_ELEMENTS:
   1068       case FAST_ELEMENTS:
   1069       case FAST_HOLEY_ELEMENTS:
   1070         CopyObjectToObjectElements(*from, from_kind, from_start, *to, to_kind,
   1071                                    to_start, copy_size);
   1072         break;
   1073       case FAST_DOUBLE_ELEMENTS:
   1074       case FAST_HOLEY_DOUBLE_ELEMENTS:
   1075         CopyDoubleToObjectElements(
   1076             from, from_start, to, to_kind, to_start, copy_size);
   1077         break;
   1078       case DICTIONARY_ELEMENTS:
   1079         CopyDictionaryToObjectElements(*from, from_start, *to, to_kind,
   1080                                        to_start, copy_size);
   1081         break;
   1082       case SLOPPY_ARGUMENTS_ELEMENTS: {
   1083         // TODO(verwaest): This is a temporary hack to support extending
   1084         // SLOPPY_ARGUMENTS_ELEMENTS in SetFastElementsCapacityAndLength.
   1085         // This case should be UNREACHABLE().
   1086         Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(from);
   1087         Handle<FixedArrayBase> arguments(
   1088             FixedArrayBase::cast(parameter_map->get(1)));
   1089         ElementsKind from_kind = ElementsKindForArray(arguments);
   1090         CopyElementsImpl(arguments, from_start, to, from_kind,
   1091                          to_start, packed_size, copy_size);
   1092         break;
   1093       }
   1094 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
   1095       case EXTERNAL_##TYPE##_ELEMENTS:                                        \
   1096       case TYPE##_ELEMENTS:                                                   \
   1097         UNREACHABLE();
   1098       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   1099 #undef TYPED_ARRAY_CASE
   1100     }
   1101   }
   1102 
   1103 
   1104   static void SetFastElementsCapacityAndLength(
   1105       Handle<JSObject> obj,
   1106       uint32_t capacity,
   1107       uint32_t length) {
   1108     JSObject::SetFastElementsCapacitySmiMode set_capacity_mode =
   1109         obj->HasFastSmiElements()
   1110             ? JSObject::kAllowSmiElements
   1111             : JSObject::kDontAllowSmiElements;
   1112     JSObject::SetFastElementsCapacityAndLength(
   1113         obj, capacity, length, set_capacity_mode);
   1114   }
   1115 };
   1116 
   1117 
   1118 class FastPackedSmiElementsAccessor
   1119     : public FastSmiOrObjectElementsAccessor<
   1120         FastPackedSmiElementsAccessor,
   1121         ElementsKindTraits<FAST_SMI_ELEMENTS> > {
   1122  public:
   1123   explicit FastPackedSmiElementsAccessor(const char* name)
   1124       : FastSmiOrObjectElementsAccessor<
   1125           FastPackedSmiElementsAccessor,
   1126           ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
   1127 };
   1128 
   1129 
   1130 class FastHoleySmiElementsAccessor
   1131     : public FastSmiOrObjectElementsAccessor<
   1132         FastHoleySmiElementsAccessor,
   1133         ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
   1134  public:
   1135   explicit FastHoleySmiElementsAccessor(const char* name)
   1136       : FastSmiOrObjectElementsAccessor<
   1137           FastHoleySmiElementsAccessor,
   1138           ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
   1139 };
   1140 
   1141 
   1142 class FastPackedObjectElementsAccessor
   1143     : public FastSmiOrObjectElementsAccessor<
   1144         FastPackedObjectElementsAccessor,
   1145         ElementsKindTraits<FAST_ELEMENTS> > {
   1146  public:
   1147   explicit FastPackedObjectElementsAccessor(const char* name)
   1148       : FastSmiOrObjectElementsAccessor<
   1149           FastPackedObjectElementsAccessor,
   1150           ElementsKindTraits<FAST_ELEMENTS> >(name) {}
   1151 };
   1152 
   1153 
   1154 class FastHoleyObjectElementsAccessor
   1155     : public FastSmiOrObjectElementsAccessor<
   1156         FastHoleyObjectElementsAccessor,
   1157         ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
   1158  public:
   1159   explicit FastHoleyObjectElementsAccessor(const char* name)
   1160       : FastSmiOrObjectElementsAccessor<
   1161           FastHoleyObjectElementsAccessor,
   1162           ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
   1163 };
   1164 
   1165 
   1166 template<typename FastElementsAccessorSubclass,
   1167          typename KindTraits>
   1168 class FastDoubleElementsAccessor
   1169     : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
   1170  public:
   1171   explicit FastDoubleElementsAccessor(const char* name)
   1172       : FastElementsAccessor<FastElementsAccessorSubclass,
   1173                              KindTraits>(name) {}
   1174 
   1175   static void SetFastElementsCapacityAndLength(Handle<JSObject> obj,
   1176                                                uint32_t capacity,
   1177                                                uint32_t length) {
   1178     JSObject::SetFastDoubleElementsCapacityAndLength(obj, capacity, length);
   1179   }
   1180 
   1181  protected:
   1182   static void CopyElementsImpl(Handle<FixedArrayBase> from,
   1183                                uint32_t from_start,
   1184                                Handle<FixedArrayBase> to,
   1185                                ElementsKind from_kind,
   1186                                uint32_t to_start,
   1187                                int packed_size,
   1188                                int copy_size) {
   1189     switch (from_kind) {
   1190       case FAST_SMI_ELEMENTS:
   1191         CopyPackedSmiToDoubleElements(*from, from_start, *to, to_start,
   1192                                       packed_size, copy_size);
   1193         break;
   1194       case FAST_HOLEY_SMI_ELEMENTS:
   1195         CopySmiToDoubleElements(*from, from_start, *to, to_start, copy_size);
   1196         break;
   1197       case FAST_DOUBLE_ELEMENTS:
   1198       case FAST_HOLEY_DOUBLE_ELEMENTS:
   1199         CopyDoubleToDoubleElements(*from, from_start, *to, to_start, copy_size);
   1200         break;
   1201       case FAST_ELEMENTS:
   1202       case FAST_HOLEY_ELEMENTS:
   1203         CopyObjectToDoubleElements(*from, from_start, *to, to_start, copy_size);
   1204         break;
   1205       case DICTIONARY_ELEMENTS:
   1206         CopyDictionaryToDoubleElements(*from, from_start, *to, to_start,
   1207                                        copy_size);
   1208         break;
   1209       case SLOPPY_ARGUMENTS_ELEMENTS:
   1210         UNREACHABLE();
   1211 
   1212 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
   1213       case EXTERNAL_##TYPE##_ELEMENTS:                                        \
   1214       case TYPE##_ELEMENTS:                                                   \
   1215         UNREACHABLE();
   1216       TYPED_ARRAYS(TYPED_ARRAY_CASE)
   1217 #undef TYPED_ARRAY_CASE
   1218     }
   1219   }
   1220 };
   1221 
   1222 
   1223 class FastPackedDoubleElementsAccessor
   1224     : public FastDoubleElementsAccessor<
   1225         FastPackedDoubleElementsAccessor,
   1226         ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
   1227  public:
   1228   friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor,
   1229                                     ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
   1230   explicit FastPackedDoubleElementsAccessor(const char* name)
   1231       : FastDoubleElementsAccessor<
   1232           FastPackedDoubleElementsAccessor,
   1233           ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
   1234 };
   1235 
   1236 
   1237 class FastHoleyDoubleElementsAccessor
   1238     : public FastDoubleElementsAccessor<
   1239         FastHoleyDoubleElementsAccessor,
   1240         ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
   1241  public:
   1242   friend class ElementsAccessorBase<
   1243     FastHoleyDoubleElementsAccessor,
   1244     ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >;
   1245   explicit FastHoleyDoubleElementsAccessor(const char* name)
   1246       : FastDoubleElementsAccessor<
   1247           FastHoleyDoubleElementsAccessor,
   1248           ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
   1249 };
   1250 
   1251 
   1252 // Super class for all external element arrays.
   1253 template<ElementsKind Kind>
   1254 class TypedElementsAccessor
   1255     : public ElementsAccessorBase<TypedElementsAccessor<Kind>,
   1256                                   ElementsKindTraits<Kind> > {
   1257  public:
   1258   explicit TypedElementsAccessor(const char* name)
   1259       : ElementsAccessorBase<AccessorClass,
   1260                              ElementsKindTraits<Kind> >(name) {}
   1261 
   1262  protected:
   1263   typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
   1264   typedef TypedElementsAccessor<Kind> AccessorClass;
   1265 
   1266   friend class ElementsAccessorBase<AccessorClass,
   1267                                     ElementsKindTraits<Kind> >;
   1268 
   1269   MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
   1270       Handle<Object> receiver,
   1271       Handle<JSObject> obj,
   1272       uint32_t key,
   1273       Handle<FixedArrayBase> backing_store) {
   1274     if (key < AccessorClass::GetCapacityImpl(backing_store)) {
   1275       return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
   1276     } else {
   1277       return backing_store->GetIsolate()->factory()->undefined_value();
   1278     }
   1279   }
   1280 
   1281   MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
   1282       Handle<Object> receiver,
   1283       Handle<JSObject> obj,
   1284       uint32_t key,
   1285       Handle<FixedArrayBase> backing_store) {
   1286     return
   1287         key < AccessorClass::GetCapacityImpl(backing_store)
   1288           ? NONE : ABSENT;
   1289   }
   1290 
   1291   MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
   1292       Handle<JSObject> obj,
   1293       Handle<Object> length,
   1294       Handle<FixedArrayBase> backing_store) {
   1295     // External arrays do not support changing their length.
   1296     UNREACHABLE();
   1297     return obj;
   1298   }
   1299 
   1300   MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
   1301       Handle<JSObject> obj,
   1302       uint32_t key,
   1303       JSReceiver::DeleteMode mode) FINAL OVERRIDE {
   1304     // External arrays always ignore deletes.
   1305     return obj->GetIsolate()->factory()->true_value();
   1306   }
   1307 
   1308   static bool HasElementImpl(Handle<Object> receiver,
   1309                              Handle<JSObject> holder,
   1310                              uint32_t key,
   1311                              Handle<FixedArrayBase> backing_store) {
   1312     uint32_t capacity =
   1313         AccessorClass::GetCapacityImpl(backing_store);
   1314     return key < capacity;
   1315   }
   1316 };
   1317 
   1318 
   1319 
   1320 #define EXTERNAL_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size)    \
   1321   typedef TypedElementsAccessor<EXTERNAL_##TYPE##_ELEMENTS>          \
   1322       External##Type##ElementsAccessor;
   1323 
   1324 TYPED_ARRAYS(EXTERNAL_ELEMENTS_ACCESSOR)
   1325 #undef EXTERNAL_ELEMENTS_ACCESSOR
   1326 
   1327 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size)       \
   1328   typedef TypedElementsAccessor<TYPE##_ELEMENTS >                    \
   1329       Fixed##Type##ElementsAccessor;
   1330 
   1331 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
   1332 #undef FIXED_ELEMENTS_ACCESSOR
   1333 
   1334 
   1335 
   1336 class DictionaryElementsAccessor
   1337     : public ElementsAccessorBase<DictionaryElementsAccessor,
   1338                                   ElementsKindTraits<DICTIONARY_ELEMENTS> > {
   1339  public:
   1340   explicit DictionaryElementsAccessor(const char* name)
   1341       : ElementsAccessorBase<DictionaryElementsAccessor,
   1342                              ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
   1343 
   1344   // Adjusts the length of the dictionary backing store and returns the new
   1345   // length according to ES5 section 15.4.5.2 behavior.
   1346   static Handle<Object> SetLengthWithoutNormalize(
   1347       Handle<FixedArrayBase> store,
   1348       Handle<JSArray> array,
   1349       Handle<Object> length_object,
   1350       uint32_t length) {
   1351     Handle<SeededNumberDictionary> dict =
   1352         Handle<SeededNumberDictionary>::cast(store);
   1353     Isolate* isolate = array->GetIsolate();
   1354     int capacity = dict->Capacity();
   1355     uint32_t new_length = length;
   1356     uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
   1357     if (new_length < old_length) {
   1358       // Find last non-deletable element in range of elements to be
   1359       // deleted and adjust range accordingly.
   1360       for (int i = 0; i < capacity; i++) {
   1361         DisallowHeapAllocation no_gc;
   1362         Object* key = dict->KeyAt(i);
   1363         if (key->IsNumber()) {
   1364           uint32_t number = static_cast<uint32_t>(key->Number());
   1365           if (new_length <= number && number < old_length) {
   1366             PropertyDetails details = dict->DetailsAt(i);
   1367             if (!details.IsConfigurable()) new_length = number + 1;
   1368           }
   1369         }
   1370       }
   1371       if (new_length != length) {
   1372         length_object = isolate->factory()->NewNumberFromUint(new_length);
   1373       }
   1374     }
   1375 
   1376     if (new_length == 0) {
   1377       // Flush the backing store.
   1378       JSObject::ResetElements(array);
   1379     } else {
   1380       DisallowHeapAllocation no_gc;
   1381       // Remove elements that should be deleted.
   1382       int removed_entries = 0;
   1383       Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
   1384       for (int i = 0; i < capacity; i++) {
   1385         Object* key = dict->KeyAt(i);
   1386         if (key->IsNumber()) {
   1387           uint32_t number = static_cast<uint32_t>(key->Number());
   1388           if (new_length <= number && number < old_length) {
   1389             dict->SetEntry(i, the_hole_value, the_hole_value);
   1390             removed_entries++;
   1391           }
   1392         }
   1393       }
   1394 
   1395       // Update the number of elements.
   1396       dict->ElementsRemoved(removed_entries);
   1397     }
   1398     return length_object;
   1399   }
   1400 
   1401   MUST_USE_RESULT static MaybeHandle<Object> DeleteCommon(
   1402       Handle<JSObject> obj,
   1403       uint32_t key,
   1404       JSReceiver::DeleteMode mode) {
   1405     Isolate* isolate = obj->GetIsolate();
   1406     Handle<FixedArray> backing_store(FixedArray::cast(obj->elements()),
   1407                                      isolate);
   1408     bool is_arguments =
   1409         (obj->GetElementsKind() == SLOPPY_ARGUMENTS_ELEMENTS);
   1410     if (is_arguments) {
   1411       backing_store = handle(FixedArray::cast(backing_store->get(1)), isolate);
   1412     }
   1413     Handle<SeededNumberDictionary> dictionary =
   1414         Handle<SeededNumberDictionary>::cast(backing_store);
   1415     int entry = dictionary->FindEntry(key);
   1416     if (entry != SeededNumberDictionary::kNotFound) {
   1417       Handle<Object> result =
   1418           SeededNumberDictionary::DeleteProperty(dictionary, entry, mode);
   1419       if (*result == *isolate->factory()->false_value()) {
   1420         if (mode == JSObject::STRICT_DELETION) {
   1421           // Deleting a non-configurable property in strict mode.
   1422           Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
   1423           Handle<Object> args[2] = { name, obj };
   1424           THROW_NEW_ERROR(isolate, NewTypeError("strict_delete_property",
   1425                                                 HandleVector(args, 2)),
   1426                           Object);
   1427         }
   1428         return isolate->factory()->false_value();
   1429       }
   1430       Handle<FixedArray> new_elements =
   1431           SeededNumberDictionary::Shrink(dictionary, key);
   1432 
   1433       if (is_arguments) {
   1434         FixedArray::cast(obj->elements())->set(1, *new_elements);
   1435       } else {
   1436         obj->set_elements(*new_elements);
   1437       }
   1438     }
   1439     return isolate->factory()->true_value();
   1440   }
   1441 
   1442   static void CopyElementsImpl(Handle<FixedArrayBase> from,
   1443                                uint32_t from_start,
   1444                                Handle<FixedArrayBase> to,
   1445                                ElementsKind from_kind,
   1446                                uint32_t to_start,
   1447                                int packed_size,
   1448                                int copy_size) {
   1449     UNREACHABLE();
   1450   }
   1451 
   1452 
   1453  protected:
   1454   friend class ElementsAccessorBase<DictionaryElementsAccessor,
   1455                                     ElementsKindTraits<DICTIONARY_ELEMENTS> >;
   1456 
   1457   MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
   1458       Handle<JSObject> obj,
   1459       uint32_t key,
   1460       JSReceiver::DeleteMode mode) FINAL OVERRIDE {
   1461     return DeleteCommon(obj, key, mode);
   1462   }
   1463 
   1464   MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
   1465       Handle<Object> receiver,
   1466       Handle<JSObject> obj,
   1467       uint32_t key,
   1468       Handle<FixedArrayBase> store) {
   1469     Handle<SeededNumberDictionary> backing_store =
   1470         Handle<SeededNumberDictionary>::cast(store);
   1471     Isolate* isolate = backing_store->GetIsolate();
   1472     int entry = backing_store->FindEntry(key);
   1473     if (entry != SeededNumberDictionary::kNotFound) {
   1474       Handle<Object> element(backing_store->ValueAt(entry), isolate);
   1475       PropertyDetails details = backing_store->DetailsAt(entry);
   1476       if (details.type() == CALLBACKS) {
   1477         return JSObject::GetElementWithCallback(
   1478             obj, receiver, element, key, obj);
   1479       } else {
   1480         return element;
   1481       }
   1482     }
   1483     return isolate->factory()->the_hole_value();
   1484   }
   1485 
   1486   MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
   1487       Handle<Object> receiver,
   1488       Handle<JSObject> obj,
   1489       uint32_t key,
   1490       Handle<FixedArrayBase> backing_store) {
   1491     Handle<SeededNumberDictionary> dictionary =
   1492         Handle<SeededNumberDictionary>::cast(backing_store);
   1493     int entry = dictionary->FindEntry(key);
   1494     if (entry != SeededNumberDictionary::kNotFound) {
   1495       return dictionary->DetailsAt(entry).attributes();
   1496     }
   1497     return ABSENT;
   1498   }
   1499 
   1500   MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
   1501       Handle<Object> receiver,
   1502       Handle<JSObject> obj,
   1503       uint32_t key,
   1504       Handle<FixedArrayBase> store) {
   1505     Handle<SeededNumberDictionary> backing_store =
   1506         Handle<SeededNumberDictionary>::cast(store);
   1507     int entry = backing_store->FindEntry(key);
   1508     if (entry != SeededNumberDictionary::kNotFound &&
   1509         backing_store->DetailsAt(entry).type() == CALLBACKS &&
   1510         backing_store->ValueAt(entry)->IsAccessorPair()) {
   1511       return handle(AccessorPair::cast(backing_store->ValueAt(entry)));
   1512     }
   1513     return MaybeHandle<AccessorPair>();
   1514   }
   1515 
   1516   static bool HasElementImpl(Handle<Object> receiver,
   1517                              Handle<JSObject> holder,
   1518                              uint32_t key,
   1519                              Handle<FixedArrayBase> store) {
   1520     Handle<SeededNumberDictionary> backing_store =
   1521         Handle<SeededNumberDictionary>::cast(store);
   1522     return backing_store->FindEntry(key) != SeededNumberDictionary::kNotFound;
   1523   }
   1524 
   1525   static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> store,
   1526                                      uint32_t index) {
   1527     DisallowHeapAllocation no_gc;
   1528     Handle<SeededNumberDictionary> dict =
   1529         Handle<SeededNumberDictionary>::cast(store);
   1530     Object* key = dict->KeyAt(index);
   1531     return Smi::cast(key)->value();
   1532   }
   1533 };
   1534 
   1535 
   1536 class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
   1537     SloppyArgumentsElementsAccessor,
   1538     ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> > {
   1539  public:
   1540   explicit SloppyArgumentsElementsAccessor(const char* name)
   1541       : ElementsAccessorBase<
   1542           SloppyArgumentsElementsAccessor,
   1543           ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
   1544  protected:
   1545   friend class ElementsAccessorBase<
   1546       SloppyArgumentsElementsAccessor,
   1547       ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> >;
   1548 
   1549   MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
   1550       Handle<Object> receiver,
   1551       Handle<JSObject> obj,
   1552       uint32_t key,
   1553       Handle<FixedArrayBase> parameters) {
   1554     Isolate* isolate = obj->GetIsolate();
   1555     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
   1556     Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
   1557     if (!probe->IsTheHole()) {
   1558       DisallowHeapAllocation no_gc;
   1559       Context* context = Context::cast(parameter_map->get(0));
   1560       int context_index = Handle<Smi>::cast(probe)->value();
   1561       DCHECK(!context->get(context_index)->IsTheHole());
   1562       return handle(context->get(context_index), isolate);
   1563     } else {
   1564       // Object is not mapped, defer to the arguments.
   1565       Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)),
   1566                                    isolate);
   1567       Handle<Object> result;
   1568       ASSIGN_RETURN_ON_EXCEPTION(
   1569           isolate, result,
   1570           ElementsAccessor::ForArray(arguments)->Get(
   1571               receiver, obj, key, arguments),
   1572           Object);
   1573       // Elements of the arguments object in slow mode might be slow aliases.
   1574       if (result->IsAliasedArgumentsEntry()) {
   1575         DisallowHeapAllocation no_gc;
   1576         AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(*result);
   1577         Context* context = Context::cast(parameter_map->get(0));
   1578         int context_index = entry->aliased_context_slot();
   1579         DCHECK(!context->get(context_index)->IsTheHole());
   1580         return handle(context->get(context_index), isolate);
   1581       } else {
   1582         return result;
   1583       }
   1584     }
   1585   }
   1586 
   1587   MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
   1588       Handle<Object> receiver,
   1589       Handle<JSObject> obj,
   1590       uint32_t key,
   1591       Handle<FixedArrayBase> backing_store) {
   1592     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(backing_store);
   1593     Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
   1594     if (!probe->IsTheHole()) {
   1595       return NONE;
   1596     } else {
   1597       // If not aliased, check the arguments.
   1598       Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
   1599       return ElementsAccessor::ForArray(arguments)->GetAttributes(
   1600           receiver, obj, key, arguments);
   1601     }
   1602   }
   1603 
   1604   MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
   1605       Handle<Object> receiver,
   1606       Handle<JSObject> obj,
   1607       uint32_t key,
   1608       Handle<FixedArrayBase> parameters) {
   1609     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
   1610     Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
   1611     if (!probe->IsTheHole()) {
   1612       return MaybeHandle<AccessorPair>();
   1613     } else {
   1614       // If not aliased, check the arguments.
   1615       Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
   1616       return ElementsAccessor::ForArray(arguments)->GetAccessorPair(
   1617           receiver, obj, key, arguments);
   1618     }
   1619   }
   1620 
   1621   MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
   1622       Handle<JSObject> obj,
   1623       Handle<Object> length,
   1624       Handle<FixedArrayBase> parameter_map) {
   1625     // TODO(mstarzinger): This was never implemented but will be used once we
   1626     // correctly implement [[DefineOwnProperty]] on arrays.
   1627     UNIMPLEMENTED();
   1628     return obj;
   1629   }
   1630 
   1631   MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
   1632       Handle<JSObject> obj,
   1633       uint32_t key,
   1634       JSReceiver::DeleteMode mode) FINAL OVERRIDE {
   1635     Isolate* isolate = obj->GetIsolate();
   1636     Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
   1637     Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
   1638     if (!probe->IsTheHole()) {
   1639       // TODO(kmillikin): We could check if this was the last aliased
   1640       // parameter, and revert to normal elements in that case.  That
   1641       // would enable GC of the context.
   1642       parameter_map->set_the_hole(key + 2);
   1643     } else {
   1644       Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
   1645       if (arguments->IsDictionary()) {
   1646         return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
   1647       } else {
   1648         // It's difficult to access the version of DeleteCommon that is declared
   1649         // in the templatized super class, call the concrete implementation in
   1650         // the class for the most generalized ElementsKind subclass.
   1651         return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode);
   1652       }
   1653     }
   1654     return isolate->factory()->true_value();
   1655   }
   1656 
   1657   static void CopyElementsImpl(Handle<FixedArrayBase> from,
   1658                                uint32_t from_start,
   1659                                Handle<FixedArrayBase> to,
   1660                                ElementsKind from_kind,
   1661                                uint32_t to_start,
   1662                                int packed_size,
   1663                                int copy_size) {
   1664     UNREACHABLE();
   1665   }
   1666 
   1667   static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
   1668     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(backing_store);
   1669     Handle<FixedArrayBase> arguments(
   1670         FixedArrayBase::cast(parameter_map->get(1)));
   1671     return Max(static_cast<uint32_t>(parameter_map->length() - 2),
   1672                ForArray(arguments)->GetCapacity(arguments));
   1673   }
   1674 
   1675   static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> dict,
   1676                                      uint32_t index) {
   1677     return index;
   1678   }
   1679 
   1680   static bool HasElementImpl(Handle<Object> receiver,
   1681                              Handle<JSObject> holder,
   1682                              uint32_t key,
   1683                              Handle<FixedArrayBase> parameters) {
   1684     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
   1685     Handle<Object> probe = GetParameterMapArg(holder, parameter_map, key);
   1686     if (!probe->IsTheHole()) {
   1687       return true;
   1688     } else {
   1689       Isolate* isolate = holder->GetIsolate();
   1690       Handle<FixedArrayBase> arguments(FixedArrayBase::cast(
   1691           Handle<FixedArray>::cast(parameter_map)->get(1)), isolate);
   1692       ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
   1693       Handle<Object> value;
   1694       ASSIGN_RETURN_ON_EXCEPTION_VALUE(
   1695           isolate, value,
   1696           accessor->Get(receiver, holder, key, arguments),
   1697           false);
   1698       return !value->IsTheHole();
   1699     }
   1700   }
   1701 
   1702  private:
   1703   static Handle<Object> GetParameterMapArg(Handle<JSObject> holder,
   1704                                            Handle<FixedArray> parameter_map,
   1705                                            uint32_t key) {
   1706     Isolate* isolate = holder->GetIsolate();
   1707     uint32_t length = holder->IsJSArray()
   1708         ? Smi::cast(Handle<JSArray>::cast(holder)->length())->value()
   1709         : parameter_map->length();
   1710     return key < (length - 2)
   1711         ? handle(parameter_map->get(key + 2), isolate)
   1712         : Handle<Object>::cast(isolate->factory()->the_hole_value());
   1713   }
   1714 };
   1715 
   1716 
   1717 ElementsAccessor* ElementsAccessor::ForArray(Handle<FixedArrayBase> array) {
   1718   return elements_accessors_[ElementsKindForArray(array)];
   1719 }
   1720 
   1721 
   1722 void ElementsAccessor::InitializeOncePerProcess() {
   1723   static ElementsAccessor* accessor_array[] = {
   1724 #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
   1725     ELEMENTS_LIST(ACCESSOR_ARRAY)
   1726 #undef ACCESSOR_ARRAY
   1727   };
   1728 
   1729   STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
   1730                 kElementsKindCount);
   1731 
   1732   elements_accessors_ = accessor_array;
   1733 }
   1734 
   1735 
   1736 void ElementsAccessor::TearDown() {
   1737   if (elements_accessors_ == NULL) return;
   1738 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
   1739   ELEMENTS_LIST(ACCESSOR_DELETE)
   1740 #undef ACCESSOR_DELETE
   1741   elements_accessors_ = NULL;
   1742 }
   1743 
   1744 
   1745 template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
   1746 MUST_USE_RESULT
   1747 MaybeHandle<Object> ElementsAccessorBase<ElementsAccessorSubclass,
   1748                                          ElementsKindTraits>::
   1749     SetLengthImpl(Handle<JSObject> obj,
   1750                   Handle<Object> length,
   1751                   Handle<FixedArrayBase> backing_store) {
   1752   Isolate* isolate = obj->GetIsolate();
   1753   Handle<JSArray> array = Handle<JSArray>::cast(obj);
   1754 
   1755   // Fast case: The new length fits into a Smi.
   1756   Handle<Object> smi_length;
   1757 
   1758   if (Object::ToSmi(isolate, length).ToHandle(&smi_length) &&
   1759       smi_length->IsSmi()) {
   1760     const int value = Handle<Smi>::cast(smi_length)->value();
   1761     if (value >= 0) {
   1762       Handle<Object> new_length = ElementsAccessorSubclass::
   1763           SetLengthWithoutNormalize(backing_store, array, smi_length, value);
   1764       DCHECK(!new_length.is_null());
   1765 
   1766       // even though the proposed length was a smi, new_length could
   1767       // still be a heap number because SetLengthWithoutNormalize doesn't
   1768       // allow the array length property to drop below the index of
   1769       // non-deletable elements.
   1770       DCHECK(new_length->IsSmi() || new_length->IsHeapNumber() ||
   1771              new_length->IsUndefined());
   1772       if (new_length->IsSmi()) {
   1773         array->set_length(*Handle<Smi>::cast(new_length));
   1774         return array;
   1775       } else if (new_length->IsHeapNumber()) {
   1776         array->set_length(*new_length);
   1777         return array;
   1778       }
   1779     } else {
   1780       return ThrowArrayLengthRangeError(isolate);
   1781     }
   1782   }
   1783 
   1784   // Slow case: The new length does not fit into a Smi or conversion
   1785   // to slow elements is needed for other reasons.
   1786   if (length->IsNumber()) {
   1787     uint32_t value;
   1788     if (length->ToArrayIndex(&value)) {
   1789       Handle<SeededNumberDictionary> dictionary =
   1790           JSObject::NormalizeElements(array);
   1791       DCHECK(!dictionary.is_null());
   1792 
   1793       Handle<Object> new_length = DictionaryElementsAccessor::
   1794           SetLengthWithoutNormalize(dictionary, array, length, value);
   1795       DCHECK(!new_length.is_null());
   1796 
   1797       DCHECK(new_length->IsNumber());
   1798       array->set_length(*new_length);
   1799       return array;
   1800     } else {
   1801       return ThrowArrayLengthRangeError(isolate);
   1802     }
   1803   }
   1804 
   1805   // Fall-back case: The new length is not a number so make the array
   1806   // size one and set only element to length.
   1807   Handle<FixedArray> new_backing_store = isolate->factory()->NewFixedArray(1);
   1808   new_backing_store->set(0, *length);
   1809   JSArray::SetContent(array, new_backing_store);
   1810   return array;
   1811 }
   1812 
   1813 
   1814 MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
   1815                                                      Arguments* args) {
   1816   // Optimize the case where there is one argument and the argument is a
   1817   // small smi.
   1818   if (args->length() == 1) {
   1819     Handle<Object> obj = args->at<Object>(0);
   1820     if (obj->IsSmi()) {
   1821       int len = Handle<Smi>::cast(obj)->value();
   1822       if (len > 0 && len < JSObject::kInitialMaxFastElementArray) {
   1823         ElementsKind elements_kind = array->GetElementsKind();
   1824         JSArray::Initialize(array, len, len);
   1825 
   1826         if (!IsFastHoleyElementsKind(elements_kind)) {
   1827           elements_kind = GetHoleyElementsKind(elements_kind);
   1828           JSObject::TransitionElementsKind(array, elements_kind);
   1829         }
   1830         return array;
   1831       } else if (len == 0) {
   1832         JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
   1833         return array;
   1834       }
   1835     }
   1836 
   1837     // Take the argument as the length.
   1838     JSArray::Initialize(array, 0);
   1839 
   1840     return JSArray::SetElementsLength(array, obj);
   1841   }
   1842 
   1843   // Optimize the case where there are no parameters passed.
   1844   if (args->length() == 0) {
   1845     JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
   1846     return array;
   1847   }
   1848 
   1849   Factory* factory = array->GetIsolate()->factory();
   1850 
   1851   // Set length and elements on the array.
   1852   int number_of_elements = args->length();
   1853   JSObject::EnsureCanContainElements(
   1854       array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
   1855 
   1856   // Allocate an appropriately typed elements array.
   1857   ElementsKind elements_kind = array->GetElementsKind();
   1858   Handle<FixedArrayBase> elms;
   1859   if (IsFastDoubleElementsKind(elements_kind)) {
   1860     elms = Handle<FixedArrayBase>::cast(
   1861         factory->NewFixedDoubleArray(number_of_elements));
   1862   } else {
   1863     elms = Handle<FixedArrayBase>::cast(
   1864         factory->NewFixedArrayWithHoles(number_of_elements));
   1865   }
   1866 
   1867   // Fill in the content
   1868   switch (array->GetElementsKind()) {
   1869     case FAST_HOLEY_SMI_ELEMENTS:
   1870     case FAST_SMI_ELEMENTS: {
   1871       Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
   1872       for (int index = 0; index < number_of_elements; index++) {
   1873         smi_elms->set(index, (*args)[index], SKIP_WRITE_BARRIER);
   1874       }
   1875       break;
   1876     }
   1877     case FAST_HOLEY_ELEMENTS:
   1878     case FAST_ELEMENTS: {
   1879       DisallowHeapAllocation no_gc;
   1880       WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
   1881       Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
   1882       for (int index = 0; index < number_of_elements; index++) {
   1883         object_elms->set(index, (*args)[index], mode);
   1884       }
   1885       break;
   1886     }
   1887     case FAST_HOLEY_DOUBLE_ELEMENTS:
   1888     case FAST_DOUBLE_ELEMENTS: {
   1889       Handle<FixedDoubleArray> double_elms =
   1890           Handle<FixedDoubleArray>::cast(elms);
   1891       for (int index = 0; index < number_of_elements; index++) {
   1892         double_elms->set(index, (*args)[index]->Number());
   1893       }
   1894       break;
   1895     }
   1896     default:
   1897       UNREACHABLE();
   1898       break;
   1899   }
   1900 
   1901   array->set_elements(*elms);
   1902   array->set_length(Smi::FromInt(number_of_elements));
   1903   return array;
   1904 }
   1905 
   1906 } }  // namespace v8::internal
   1907