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