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