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