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 "objects.h"
     31 #include "elements.h"
     32 #include "utils.h"
     33 
     34 
     35 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
     36 // several abstract ElementsAccessor classes are used to allow sharing
     37 // common code.
     38 //
     39 // Inheritance hierarchy:
     40 // - ElementsAccessorBase                        (abstract)
     41 //   - FastElementsAccessor                      (abstract)
     42 //     - FastObjectElementsAccessor
     43 //     - FastDoubleElementsAccessor
     44 //   - ExternalElementsAccessor                  (abstract)
     45 //     - ExternalByteElementsAccessor
     46 //     - ExternalUnsignedByteElementsAccessor
     47 //     - ExternalShortElementsAccessor
     48 //     - ExternalUnsignedShortElementsAccessor
     49 //     - ExternalIntElementsAccessor
     50 //     - ExternalUnsignedIntElementsAccessor
     51 //     - ExternalFloatElementsAccessor
     52 //     - ExternalDoubleElementsAccessor
     53 //     - PixelElementsAccessor
     54 //   - DictionaryElementsAccessor
     55 //   - NonStrictArgumentsElementsAccessor
     56 
     57 
     58 namespace v8 {
     59 namespace internal {
     60 
     61 
     62 // First argument in list is the accessor class, the second argument is the
     63 // accessor ElementsKind, and the third is the backing store class.  Use the
     64 // fast element handler for smi-only arrays.  The implementation is currently
     65 // identical.  Note that the order must match that of the ElementsKind enum for
     66 // the |accessor_array[]| below to work.
     67 #define ELEMENTS_LIST(V)                                                \
     68   V(FastObjectElementsAccessor, FAST_SMI_ONLY_ELEMENTS, FixedArray)     \
     69   V(FastObjectElementsAccessor, FAST_ELEMENTS, FixedArray)              \
     70   V(FastDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
     71   V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS,                    \
     72     SeededNumberDictionary)                                             \
     73   V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS,  \
     74     FixedArray)                                                         \
     75   V(ExternalByteElementsAccessor, EXTERNAL_BYTE_ELEMENTS,               \
     76     ExternalByteArray)                                                  \
     77   V(ExternalUnsignedByteElementsAccessor,                               \
     78     EXTERNAL_UNSIGNED_BYTE_ELEMENTS, ExternalUnsignedByteArray)         \
     79   V(ExternalShortElementsAccessor, EXTERNAL_SHORT_ELEMENTS,             \
     80     ExternalShortArray)                                                 \
     81   V(ExternalUnsignedShortElementsAccessor,                              \
     82     EXTERNAL_UNSIGNED_SHORT_ELEMENTS, ExternalUnsignedShortArray)       \
     83   V(ExternalIntElementsAccessor, EXTERNAL_INT_ELEMENTS,                 \
     84     ExternalIntArray)                                                   \
     85   V(ExternalUnsignedIntElementsAccessor,                                \
     86     EXTERNAL_UNSIGNED_INT_ELEMENTS, ExternalUnsignedIntArray)           \
     87   V(ExternalFloatElementsAccessor,                                      \
     88     EXTERNAL_FLOAT_ELEMENTS, ExternalFloatArray)                        \
     89   V(ExternalDoubleElementsAccessor,                                     \
     90     EXTERNAL_DOUBLE_ELEMENTS, ExternalDoubleArray)                      \
     91   V(PixelElementsAccessor, EXTERNAL_PIXEL_ELEMENTS, ExternalPixelArray)
     92 
     93 
     94 template<ElementsKind Kind> class ElementsKindTraits {
     95  public:
     96   typedef FixedArrayBase BackingStore;
     97 };
     98 
     99 #define ELEMENTS_TRAITS(Class, KindParam, Store)               \
    100 template<> class ElementsKindTraits<KindParam> {               \
    101   public:                                                      \
    102   static const ElementsKind Kind = KindParam;                  \
    103   typedef Store BackingStore;                                  \
    104 };
    105 ELEMENTS_LIST(ELEMENTS_TRAITS)
    106 #undef ELEMENTS_TRAITS
    107 
    108 
    109 ElementsAccessor** ElementsAccessor::elements_accessors_;
    110 
    111 
    112 static bool HasKey(FixedArray* array, Object* key) {
    113   int len0 = array->length();
    114   for (int i = 0; i < len0; i++) {
    115     Object* element = array->get(i);
    116     if (element->IsSmi() && element == key) return true;
    117     if (element->IsString() &&
    118         key->IsString() && String::cast(element)->Equals(String::cast(key))) {
    119       return true;
    120     }
    121   }
    122   return false;
    123 }
    124 
    125 
    126 static Failure* ThrowArrayLengthRangeError(Heap* heap) {
    127   HandleScope scope(heap->isolate());
    128   return heap->isolate()->Throw(
    129       *heap->isolate()->factory()->NewRangeError("invalid_array_length",
    130           HandleVector<Object>(NULL, 0)));
    131 }
    132 
    133 
    134 void CopyObjectToObjectElements(FixedArray* from,
    135                                 ElementsKind from_kind,
    136                                 uint32_t from_start,
    137                                 FixedArray* to,
    138                                 ElementsKind to_kind,
    139                                 uint32_t to_start,
    140                                 int raw_copy_size) {
    141   ASSERT(to->map() != HEAP->fixed_cow_array_map());
    142   ASSERT(from_kind == FAST_ELEMENTS || from_kind == FAST_SMI_ONLY_ELEMENTS);
    143   ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
    144   int copy_size = raw_copy_size;
    145   if (raw_copy_size < 0) {
    146     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    147            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    148     copy_size = Min(from->length() - from_start,
    149                     to->length() - to_start);
    150 #ifdef DEBUG
    151     // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
    152     // marked with the hole.
    153     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    154       for (int i = to_start + copy_size; i < to->length(); ++i) {
    155         ASSERT(to->get(i)->IsTheHole());
    156       }
    157     }
    158 #endif
    159   }
    160   ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
    161          (copy_size + static_cast<int>(from_start)) <= from->length());
    162   if (copy_size == 0) return;
    163   Address to_address = to->address() + FixedArray::kHeaderSize;
    164   Address from_address = from->address() + FixedArray::kHeaderSize;
    165   CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
    166             reinterpret_cast<Object**>(from_address) + from_start,
    167             copy_size);
    168   if (from_kind == FAST_ELEMENTS && to_kind == FAST_ELEMENTS) {
    169     Heap* heap = from->GetHeap();
    170     if (!heap->InNewSpace(to)) {
    171       heap->RecordWrites(to->address(),
    172                          to->OffsetOfElementAt(to_start),
    173                          copy_size);
    174     }
    175     heap->incremental_marking()->RecordWrites(to);
    176   }
    177 }
    178 
    179 
    180 static void CopyDictionaryToObjectElements(SeededNumberDictionary* from,
    181                                            uint32_t from_start,
    182                                            FixedArray* to,
    183                                            ElementsKind to_kind,
    184                                            uint32_t to_start,
    185                                            int raw_copy_size) {
    186   int copy_size = raw_copy_size;
    187   Heap* heap = from->GetHeap();
    188   if (raw_copy_size < 0) {
    189     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    190            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    191     copy_size = from->max_number_key() + 1 - from_start;
    192 #ifdef DEBUG
    193     // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
    194     // marked with the hole.
    195     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    196       for (int i = to_start + copy_size; i < to->length(); ++i) {
    197         ASSERT(to->get(i)->IsTheHole());
    198       }
    199     }
    200 #endif
    201   }
    202   ASSERT(to != from);
    203   ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
    204   if (copy_size == 0) return;
    205   uint32_t to_length = to->length();
    206   if (to_start + copy_size > to_length) {
    207     copy_size = to_length - to_start;
    208   }
    209   for (int i = 0; i < copy_size; i++) {
    210     int entry = from->FindEntry(i + from_start);
    211     if (entry != SeededNumberDictionary::kNotFound) {
    212       Object* value = from->ValueAt(entry);
    213       ASSERT(!value->IsTheHole());
    214       to->set(i + to_start, value, SKIP_WRITE_BARRIER);
    215     } else {
    216       to->set_the_hole(i + to_start);
    217     }
    218   }
    219   if (to_kind == FAST_ELEMENTS) {
    220     if (!heap->InNewSpace(to)) {
    221       heap->RecordWrites(to->address(),
    222                          to->OffsetOfElementAt(to_start),
    223                          copy_size);
    224     }
    225     heap->incremental_marking()->RecordWrites(to);
    226   }
    227 }
    228 
    229 
    230 MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
    231     FixedDoubleArray* from,
    232     uint32_t from_start,
    233     FixedArray* to,
    234     ElementsKind to_kind,
    235     uint32_t to_start,
    236     int raw_copy_size) {
    237   ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS);
    238   int copy_size = raw_copy_size;
    239   if (raw_copy_size < 0) {
    240     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    241            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    242     copy_size = Min(from->length() - from_start,
    243                     to->length() - to_start);
    244 #ifdef DEBUG
    245     // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already
    246     // marked with the hole.
    247     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    248       for (int i = to_start + copy_size; i < to->length(); ++i) {
    249         ASSERT(to->get(i)->IsTheHole());
    250       }
    251     }
    252 #endif
    253   }
    254   ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
    255          (copy_size + static_cast<int>(from_start)) <= from->length());
    256   if (copy_size == 0) return from;
    257   for (int i = 0; i < copy_size; ++i) {
    258     if (to_kind == FAST_SMI_ONLY_ELEMENTS) {
    259       UNIMPLEMENTED();
    260       return Failure::Exception();
    261     } else {
    262       MaybeObject* maybe_value = from->get(i + from_start);
    263       Object* value;
    264       ASSERT(to_kind == FAST_ELEMENTS);
    265       // Because FAST_DOUBLE_ELEMENTS -> FAST_ELEMENT allocate HeapObjects
    266       // iteratively, the allocate must succeed within a single GC cycle,
    267       // otherwise the retry after the GC will also fail. In order to ensure
    268       // that no GC is triggered, allocate HeapNumbers from old space if they
    269       // can't be taken from new space.
    270       if (!maybe_value->ToObject(&value)) {
    271         ASSERT(maybe_value->IsRetryAfterGC() || maybe_value->IsOutOfMemory());
    272         Heap* heap = from->GetHeap();
    273         MaybeObject* maybe_value_object =
    274             heap->AllocateHeapNumber(from->get_scalar(i + from_start),
    275                                      TENURED);
    276         if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
    277       }
    278       to->set(i + to_start, value, UPDATE_WRITE_BARRIER);
    279     }
    280   }
    281   return to;
    282 }
    283 
    284 
    285 static void CopyDoubleToDoubleElements(FixedDoubleArray* from,
    286                                        uint32_t from_start,
    287                                        FixedDoubleArray* to,
    288                                        uint32_t to_start,
    289                                        int raw_copy_size) {
    290   int copy_size = raw_copy_size;
    291   if (raw_copy_size < 0) {
    292     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    293            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    294     copy_size = Min(from->length() - from_start,
    295                     to->length() - to_start);
    296     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    297       for (int i = to_start + copy_size; i < to->length(); ++i) {
    298         to->set_the_hole(i);
    299       }
    300     }
    301   }
    302   ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
    303          (copy_size + static_cast<int>(from_start)) <= from->length());
    304   if (copy_size == 0) return;
    305   Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
    306   Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
    307   to_address += kDoubleSize * to_start;
    308   from_address += kDoubleSize * from_start;
    309   int words_per_double = (kDoubleSize / kPointerSize);
    310   CopyWords(reinterpret_cast<Object**>(to_address),
    311             reinterpret_cast<Object**>(from_address),
    312             words_per_double * copy_size);
    313 }
    314 
    315 
    316 static void CopyObjectToDoubleElements(FixedArray* from,
    317                                        uint32_t from_start,
    318                                        FixedDoubleArray* to,
    319                                        uint32_t to_start,
    320                                        int raw_copy_size) {
    321   int copy_size = raw_copy_size;
    322   if (raw_copy_size < 0) {
    323     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
    324            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    325     copy_size = from->length() - from_start;
    326     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    327       for (int i = to_start + copy_size; i < to->length(); ++i) {
    328         to->set_the_hole(i);
    329       }
    330     }
    331   }
    332   ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
    333          (copy_size + static_cast<int>(from_start)) <= from->length());
    334   if (copy_size == 0) return;
    335   for (int i = 0; i < copy_size; i++) {
    336     Object* hole_or_object = from->get(i + from_start);
    337     if (hole_or_object->IsTheHole()) {
    338       to->set_the_hole(i + to_start);
    339     } else {
    340       to->set(i + to_start, hole_or_object->Number());
    341     }
    342   }
    343 }
    344 
    345 
    346 static void CopyDictionaryToDoubleElements(SeededNumberDictionary* from,
    347                                            uint32_t from_start,
    348                                            FixedDoubleArray* to,
    349                                            uint32_t to_start,
    350                                            int raw_copy_size) {
    351   int copy_size = raw_copy_size;
    352   if (copy_size < 0) {
    353     ASSERT(copy_size == ElementsAccessor::kCopyToEnd ||
    354            copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
    355     copy_size = from->max_number_key() + 1 - from_start;
    356     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
    357       for (int i = to_start + copy_size; i < to->length(); ++i) {
    358         to->set_the_hole(i);
    359       }
    360     }
    361   }
    362   if (copy_size == 0) return;
    363   uint32_t to_length = to->length();
    364   if (to_start + copy_size > to_length) {
    365     copy_size = to_length - to_start;
    366   }
    367   for (int i = 0; i < copy_size; i++) {
    368     int entry = from->FindEntry(i + from_start);
    369     if (entry != SeededNumberDictionary::kNotFound) {
    370       to->set(i + to_start, from->ValueAt(entry)->Number());
    371     } else {
    372       to->set_the_hole(i + to_start);
    373     }
    374   }
    375 }
    376 
    377 
    378 // Base class for element handler implementations. Contains the
    379 // the common logic for objects with different ElementsKinds.
    380 // Subclasses must specialize method for which the element
    381 // implementation differs from the base class implementation.
    382 //
    383 // This class is intended to be used in the following way:
    384 //
    385 //   class SomeElementsAccessor :
    386 //       public ElementsAccessorBase<SomeElementsAccessor,
    387 //                                   BackingStoreClass> {
    388 //     ...
    389 //   }
    390 //
    391 // This is an example of the Curiously Recurring Template Pattern (see
    392 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).  We use
    393 // CRTP to guarantee aggressive compile time optimizations (i.e.  inlining and
    394 // specialization of SomeElementsAccessor methods).
    395 template <typename ElementsAccessorSubclass,
    396           typename ElementsTraitsParam>
    397 class ElementsAccessorBase : public ElementsAccessor {
    398  protected:
    399   explicit ElementsAccessorBase(const char* name)
    400       : ElementsAccessor(name) { }
    401 
    402   typedef ElementsTraitsParam ElementsTraits;
    403   typedef typename ElementsTraitsParam::BackingStore BackingStore;
    404 
    405   virtual ElementsKind kind() const { return ElementsTraits::Kind; }
    406 
    407   static bool HasElementImpl(Object* receiver,
    408                              JSObject* holder,
    409                              uint32_t key,
    410                              BackingStore* backing_store) {
    411     MaybeObject* element =
    412         ElementsAccessorSubclass::GetImpl(receiver, holder, key, backing_store);
    413     return !element->IsTheHole();
    414   }
    415 
    416   virtual bool HasElement(Object* receiver,
    417                           JSObject* holder,
    418                           uint32_t key,
    419                           FixedArrayBase* backing_store) {
    420     if (backing_store == NULL) {
    421       backing_store = holder->elements();
    422     }
    423     return ElementsAccessorSubclass::HasElementImpl(
    424         receiver, holder, key, BackingStore::cast(backing_store));
    425   }
    426 
    427   virtual MaybeObject* Get(Object* receiver,
    428                            JSObject* holder,
    429                            uint32_t key,
    430                            FixedArrayBase* backing_store) {
    431     if (backing_store == NULL) {
    432       backing_store = holder->elements();
    433     }
    434     return ElementsAccessorSubclass::GetImpl(
    435         receiver, holder, key, BackingStore::cast(backing_store));
    436   }
    437 
    438   static MaybeObject* GetImpl(Object* receiver,
    439                               JSObject* obj,
    440                               uint32_t key,
    441                               BackingStore* backing_store) {
    442     return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
    443            ? backing_store->get(key)
    444            : backing_store->GetHeap()->the_hole_value();
    445   }
    446 
    447   virtual MaybeObject* SetLength(JSArray* array,
    448                                  Object* length) {
    449     return ElementsAccessorSubclass::SetLengthImpl(
    450         array, length, BackingStore::cast(array->elements()));
    451   }
    452 
    453   static MaybeObject* SetLengthImpl(JSObject* obj,
    454                                     Object* length,
    455                                     BackingStore* backing_store);
    456 
    457   virtual MaybeObject* SetCapacityAndLength(JSArray* array,
    458                                             int capacity,
    459                                             int length) {
    460     return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
    461         array,
    462         capacity,
    463         length);
    464   }
    465 
    466   static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
    467                                                        int capacity,
    468                                                        int length) {
    469     UNIMPLEMENTED();
    470     return obj;
    471   }
    472 
    473   virtual MaybeObject* Delete(JSObject* obj,
    474                               uint32_t key,
    475                               JSReceiver::DeleteMode mode) = 0;
    476 
    477   static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
    478                                        uint32_t from_start,
    479                                        FixedArrayBase* to,
    480                                        ElementsKind to_kind,
    481                                        uint32_t to_start,
    482                                        int copy_size) {
    483     UNREACHABLE();
    484     return NULL;
    485   }
    486 
    487   virtual MaybeObject* CopyElements(JSObject* from_holder,
    488                                     uint32_t from_start,
    489                                     FixedArrayBase* to,
    490                                     ElementsKind to_kind,
    491                                     uint32_t to_start,
    492                                     int copy_size,
    493                                     FixedArrayBase* from) {
    494     if (from == NULL) {
    495       from = from_holder->elements();
    496     }
    497     if (from->length() == 0) {
    498       return from;
    499     }
    500     return ElementsAccessorSubclass::CopyElementsImpl(
    501         from, from_start, to, to_kind, to_start, copy_size);
    502   }
    503 
    504   virtual MaybeObject* AddElementsToFixedArray(Object* receiver,
    505                                                JSObject* holder,
    506                                                FixedArray* to,
    507                                                FixedArrayBase* from) {
    508     int len0 = to->length();
    509 #ifdef DEBUG
    510     if (FLAG_enable_slow_asserts) {
    511       for (int i = 0; i < len0; i++) {
    512         ASSERT(!to->get(i)->IsTheHole());
    513       }
    514     }
    515 #endif
    516     if (from == NULL) {
    517       from = holder->elements();
    518     }
    519     BackingStore* backing_store = BackingStore::cast(from);
    520     uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store);
    521 
    522     // Optimize if 'other' is empty.
    523     // We cannot optimize if 'this' is empty, as other may have holes.
    524     if (len1 == 0) return to;
    525 
    526     // Compute how many elements are not in other.
    527     uint32_t extra = 0;
    528     for (uint32_t y = 0; y < len1; y++) {
    529       uint32_t key =
    530           ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
    531       if (ElementsAccessorSubclass::HasElementImpl(
    532               receiver, holder, key, backing_store)) {
    533         MaybeObject* maybe_value =
    534             ElementsAccessorSubclass::GetImpl(receiver, holder,
    535                                               key, backing_store);
    536         Object* value;
    537         if (!maybe_value->ToObject(&value)) return maybe_value;
    538         ASSERT(!value->IsTheHole());
    539         if (!HasKey(to, value)) {
    540           extra++;
    541         }
    542       }
    543     }
    544 
    545     if (extra == 0) return to;
    546 
    547     // Allocate the result
    548     FixedArray* result;
    549     MaybeObject* maybe_obj =
    550         backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
    551     if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
    552 
    553     // Fill in the content
    554     {
    555       AssertNoAllocation no_gc;
    556       WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
    557       for (int i = 0; i < len0; i++) {
    558         Object* e = to->get(i);
    559         ASSERT(e->IsString() || e->IsNumber());
    560         result->set(i, e, mode);
    561       }
    562     }
    563     // Fill in the extra values.
    564     uint32_t index = 0;
    565     for (uint32_t y = 0; y < len1; y++) {
    566       uint32_t key =
    567           ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
    568       if (ElementsAccessorSubclass::HasElementImpl(
    569               receiver, holder, key, backing_store)) {
    570         MaybeObject* maybe_value =
    571             ElementsAccessorSubclass::GetImpl(receiver, holder,
    572                                               key, backing_store);
    573         Object* value;
    574         if (!maybe_value->ToObject(&value)) return maybe_value;
    575         if (!value->IsTheHole() && !HasKey(to, value)) {
    576           result->set(len0 + index, value);
    577           index++;
    578         }
    579       }
    580     }
    581     ASSERT(extra == index);
    582     return result;
    583   }
    584 
    585  protected:
    586   static uint32_t GetCapacityImpl(BackingStore* backing_store) {
    587     return backing_store->length();
    588   }
    589 
    590   virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
    591     return ElementsAccessorSubclass::GetCapacityImpl(
    592         BackingStore::cast(backing_store));
    593   }
    594 
    595   static uint32_t GetKeyForIndexImpl(BackingStore* backing_store,
    596                                      uint32_t index) {
    597     return index;
    598   }
    599 
    600   virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
    601                                   uint32_t index) {
    602     return ElementsAccessorSubclass::GetKeyForIndexImpl(
    603         BackingStore::cast(backing_store), index);
    604   }
    605 
    606  private:
    607   DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
    608 };
    609 
    610 
    611 // Super class for all fast element arrays.
    612 template<typename FastElementsAccessorSubclass,
    613          typename KindTraits,
    614          int ElementSize>
    615 class FastElementsAccessor
    616     : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
    617  public:
    618   explicit FastElementsAccessor(const char* name)
    619       : ElementsAccessorBase<FastElementsAccessorSubclass,
    620                              KindTraits>(name) {}
    621  protected:
    622   friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
    623 
    624   typedef typename KindTraits::BackingStore BackingStore;
    625 
    626   // Adjusts the length of the fast backing store or returns the new length or
    627   // undefined in case conversion to a slow backing store should be performed.
    628   static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
    629                                                 JSArray* array,
    630                                                 Object* length_object,
    631                                                 uint32_t length) {
    632     uint32_t old_capacity = backing_store->length();
    633 
    634     // Check whether the backing store should be shrunk.
    635     if (length <= old_capacity) {
    636       if (array->HasFastTypeElements()) {
    637         MaybeObject* maybe_obj = array->EnsureWritableFastElements();
    638         if (!maybe_obj->To(&backing_store)) return maybe_obj;
    639       }
    640       if (2 * length <= old_capacity) {
    641         // If more than half the elements won't be used, trim the array.
    642         if (length == 0) {
    643           array->initialize_elements();
    644         } else {
    645           backing_store->set_length(length);
    646           Address filler_start = backing_store->address() +
    647               BackingStore::OffsetOfElementAt(length);
    648           int filler_size = (old_capacity - length) * ElementSize;
    649           array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
    650         }
    651       } else {
    652         // Otherwise, fill the unused tail with holes.
    653         int old_length = FastD2I(array->length()->Number());
    654         for (int i = length; i < old_length; i++) {
    655           backing_store->set_the_hole(i);
    656         }
    657       }
    658       return length_object;
    659     }
    660 
    661     // Check whether the backing store should be expanded.
    662     uint32_t min = JSObject::NewElementsCapacity(old_capacity);
    663     uint32_t new_capacity = length > min ? length : min;
    664     if (!array->ShouldConvertToSlowElements(new_capacity)) {
    665       MaybeObject* result = FastElementsAccessorSubclass::
    666           SetFastElementsCapacityAndLength(array, new_capacity, length);
    667       if (result->IsFailure()) return result;
    668       return length_object;
    669     }
    670 
    671     // Request conversion to slow elements.
    672     return array->GetHeap()->undefined_value();
    673   }
    674 };
    675 
    676 
    677 class FastObjectElementsAccessor
    678     : public FastElementsAccessor<FastObjectElementsAccessor,
    679                                   ElementsKindTraits<FAST_ELEMENTS>,
    680                                   kPointerSize> {
    681  public:
    682   explicit FastObjectElementsAccessor(const char* name)
    683       : FastElementsAccessor<FastObjectElementsAccessor,
    684                              ElementsKindTraits<FAST_ELEMENTS>,
    685                              kPointerSize>(name) {}
    686 
    687   static MaybeObject* DeleteCommon(JSObject* obj,
    688                                    uint32_t key) {
    689     ASSERT(obj->HasFastElements() ||
    690            obj->HasFastSmiOnlyElements() ||
    691            obj->HasFastArgumentsElements());
    692     Heap* heap = obj->GetHeap();
    693     FixedArray* backing_store = FixedArray::cast(obj->elements());
    694     if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
    695       backing_store = FixedArray::cast(backing_store->get(1));
    696     } else {
    697       Object* writable;
    698       MaybeObject* maybe = obj->EnsureWritableFastElements();
    699       if (!maybe->ToObject(&writable)) return maybe;
    700       backing_store = FixedArray::cast(writable);
    701     }
    702     uint32_t length = static_cast<uint32_t>(
    703         obj->IsJSArray()
    704         ? Smi::cast(JSArray::cast(obj)->length())->value()
    705         : backing_store->length());
    706     if (key < length) {
    707       backing_store->set_the_hole(key);
    708       // If an old space backing store is larger than a certain size and
    709       // has too few used values, normalize it.
    710       // To avoid doing the check on every delete we require at least
    711       // one adjacent hole to the value being deleted.
    712       Object* hole = heap->the_hole_value();
    713       const int kMinLengthForSparsenessCheck = 64;
    714       if (backing_store->length() >= kMinLengthForSparsenessCheck &&
    715           !heap->InNewSpace(backing_store) &&
    716           ((key > 0 && backing_store->get(key - 1) == hole) ||
    717            (key + 1 < length && backing_store->get(key + 1) == hole))) {
    718         int num_used = 0;
    719         for (int i = 0; i < backing_store->length(); ++i) {
    720           if (backing_store->get(i) != hole) ++num_used;
    721           // Bail out early if more than 1/4 is used.
    722           if (4 * num_used > backing_store->length()) break;
    723         }
    724         if (4 * num_used <= backing_store->length()) {
    725           MaybeObject* result = obj->NormalizeElements();
    726           if (result->IsFailure()) return result;
    727         }
    728       }
    729     }
    730     return heap->true_value();
    731   }
    732 
    733   static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
    734                                        uint32_t from_start,
    735                                        FixedArrayBase* to,
    736                                        ElementsKind to_kind,
    737                                        uint32_t to_start,
    738                                        int copy_size) {
    739     switch (to_kind) {
    740       case FAST_SMI_ONLY_ELEMENTS:
    741       case FAST_ELEMENTS: {
    742         CopyObjectToObjectElements(
    743             FixedArray::cast(from), ElementsTraits::Kind, from_start,
    744             FixedArray::cast(to), to_kind, to_start, copy_size);
    745         return from;
    746       }
    747       case FAST_DOUBLE_ELEMENTS:
    748         CopyObjectToDoubleElements(
    749             FixedArray::cast(from), from_start,
    750             FixedDoubleArray::cast(to), to_start, copy_size);
    751         return from;
    752       default:
    753         UNREACHABLE();
    754     }
    755     return to->GetHeap()->undefined_value();
    756   }
    757 
    758 
    759   static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
    760                                                        uint32_t capacity,
    761                                                        uint32_t length) {
    762     JSObject::SetFastElementsCapacityMode set_capacity_mode =
    763         obj->HasFastSmiOnlyElements()
    764             ? JSObject::kAllowSmiOnlyElements
    765             : JSObject::kDontAllowSmiOnlyElements;
    766     return obj->SetFastElementsCapacityAndLength(capacity,
    767                                                  length,
    768                                                  set_capacity_mode);
    769   }
    770 
    771  protected:
    772   friend class FastElementsAccessor<FastObjectElementsAccessor,
    773                                     ElementsKindTraits<FAST_ELEMENTS>,
    774                                     kPointerSize>;
    775 
    776   virtual MaybeObject* Delete(JSObject* obj,
    777                               uint32_t key,
    778                               JSReceiver::DeleteMode mode) {
    779     return DeleteCommon(obj, key);
    780   }
    781 };
    782 
    783 
    784 class FastDoubleElementsAccessor
    785     : public FastElementsAccessor<FastDoubleElementsAccessor,
    786                                   ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
    787                                   kDoubleSize> {
    788  public:
    789   explicit FastDoubleElementsAccessor(const char* name)
    790       : FastElementsAccessor<FastDoubleElementsAccessor,
    791                              ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
    792                              kDoubleSize>(name) {}
    793 
    794   static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
    795                                                        uint32_t capacity,
    796                                                        uint32_t length) {
    797     return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
    798   }
    799 
    800  protected:
    801   friend class ElementsAccessorBase<FastDoubleElementsAccessor,
    802                                     ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
    803   friend class FastElementsAccessor<FastDoubleElementsAccessor,
    804                                     ElementsKindTraits<FAST_DOUBLE_ELEMENTS>,
    805                                     kDoubleSize>;
    806 
    807   static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
    808                                        uint32_t from_start,
    809                                        FixedArrayBase* to,
    810                                        ElementsKind to_kind,
    811                                        uint32_t to_start,
    812                                        int copy_size) {
    813     switch (to_kind) {
    814       case FAST_SMI_ONLY_ELEMENTS:
    815       case FAST_ELEMENTS:
    816         return CopyDoubleToObjectElements(
    817             FixedDoubleArray::cast(from), from_start, FixedArray::cast(to),
    818             to_kind, to_start, copy_size);
    819       case FAST_DOUBLE_ELEMENTS:
    820         CopyDoubleToDoubleElements(FixedDoubleArray::cast(from), from_start,
    821                                    FixedDoubleArray::cast(to),
    822                                    to_start, copy_size);
    823         return from;
    824       default:
    825         UNREACHABLE();
    826     }
    827     return to->GetHeap()->undefined_value();
    828   }
    829 
    830   virtual MaybeObject* Delete(JSObject* obj,
    831                               uint32_t key,
    832                               JSReceiver::DeleteMode mode) {
    833     int length = obj->IsJSArray()
    834         ? Smi::cast(JSArray::cast(obj)->length())->value()
    835         : FixedDoubleArray::cast(obj->elements())->length();
    836     if (key < static_cast<uint32_t>(length)) {
    837       FixedDoubleArray::cast(obj->elements())->set_the_hole(key);
    838     }
    839     return obj->GetHeap()->true_value();
    840   }
    841 
    842   static bool HasElementImpl(Object* receiver,
    843                              JSObject* holder,
    844                              uint32_t key,
    845                              FixedDoubleArray* backing_store) {
    846     return key < static_cast<uint32_t>(backing_store->length()) &&
    847         !backing_store->is_the_hole(key);
    848   }
    849 };
    850 
    851 
    852 // Super class for all external element arrays.
    853 template<typename ExternalElementsAccessorSubclass,
    854          ElementsKind Kind>
    855 class ExternalElementsAccessor
    856     : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
    857                                   ElementsKindTraits<Kind> > {
    858  public:
    859   explicit ExternalElementsAccessor(const char* name)
    860       : ElementsAccessorBase<ExternalElementsAccessorSubclass,
    861                              ElementsKindTraits<Kind> >(name) {}
    862 
    863  protected:
    864   typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
    865 
    866   friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
    867                                     ElementsKindTraits<Kind> >;
    868 
    869   static MaybeObject* GetImpl(Object* receiver,
    870                               JSObject* obj,
    871                               uint32_t key,
    872                               BackingStore* backing_store) {
    873     return
    874         key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
    875         ? backing_store->get(key)
    876         : backing_store->GetHeap()->undefined_value();
    877   }
    878 
    879   static MaybeObject* SetLengthImpl(JSObject* obj,
    880                                     Object* length,
    881                                     BackingStore* backing_store) {
    882     // External arrays do not support changing their length.
    883     UNREACHABLE();
    884     return obj;
    885   }
    886 
    887   virtual MaybeObject* Delete(JSObject* obj,
    888                               uint32_t key,
    889                               JSReceiver::DeleteMode mode) {
    890     // External arrays always ignore deletes.
    891     return obj->GetHeap()->true_value();
    892   }
    893 
    894   static bool HasElementImpl(Object* receiver,
    895                              JSObject* holder,
    896                              uint32_t key,
    897                              BackingStore* backing_store) {
    898     uint32_t capacity =
    899         ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
    900     return key < capacity;
    901   }
    902 };
    903 
    904 
    905 class ExternalByteElementsAccessor
    906     : public ExternalElementsAccessor<ExternalByteElementsAccessor,
    907                                       EXTERNAL_BYTE_ELEMENTS> {
    908  public:
    909   explicit ExternalByteElementsAccessor(const char* name)
    910       : ExternalElementsAccessor<ExternalByteElementsAccessor,
    911                                  EXTERNAL_BYTE_ELEMENTS>(name) {}
    912 };
    913 
    914 
    915 class ExternalUnsignedByteElementsAccessor
    916     : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
    917                                       EXTERNAL_UNSIGNED_BYTE_ELEMENTS> {
    918  public:
    919   explicit ExternalUnsignedByteElementsAccessor(const char* name)
    920       : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
    921                                  EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {}
    922 };
    923 
    924 
    925 class ExternalShortElementsAccessor
    926     : public ExternalElementsAccessor<ExternalShortElementsAccessor,
    927                                       EXTERNAL_SHORT_ELEMENTS> {
    928  public:
    929   explicit ExternalShortElementsAccessor(const char* name)
    930       : ExternalElementsAccessor<ExternalShortElementsAccessor,
    931                                  EXTERNAL_SHORT_ELEMENTS>(name) {}
    932 };
    933 
    934 
    935 class ExternalUnsignedShortElementsAccessor
    936     : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
    937                                       EXTERNAL_UNSIGNED_SHORT_ELEMENTS> {
    938  public:
    939   explicit ExternalUnsignedShortElementsAccessor(const char* name)
    940       : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
    941                                  EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {}
    942 };
    943 
    944 
    945 class ExternalIntElementsAccessor
    946     : public ExternalElementsAccessor<ExternalIntElementsAccessor,
    947                                       EXTERNAL_INT_ELEMENTS> {
    948  public:
    949   explicit ExternalIntElementsAccessor(const char* name)
    950       : ExternalElementsAccessor<ExternalIntElementsAccessor,
    951                                  EXTERNAL_INT_ELEMENTS>(name) {}
    952 };
    953 
    954 
    955 class ExternalUnsignedIntElementsAccessor
    956     : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
    957                                       EXTERNAL_UNSIGNED_INT_ELEMENTS> {
    958  public:
    959   explicit ExternalUnsignedIntElementsAccessor(const char* name)
    960       : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
    961                                  EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {}
    962 };
    963 
    964 
    965 class ExternalFloatElementsAccessor
    966     : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
    967                                       EXTERNAL_FLOAT_ELEMENTS> {
    968  public:
    969   explicit ExternalFloatElementsAccessor(const char* name)
    970       : ExternalElementsAccessor<ExternalFloatElementsAccessor,
    971                                  EXTERNAL_FLOAT_ELEMENTS>(name) {}
    972 };
    973 
    974 
    975 class ExternalDoubleElementsAccessor
    976     : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
    977                                       EXTERNAL_DOUBLE_ELEMENTS> {
    978  public:
    979   explicit ExternalDoubleElementsAccessor(const char* name)
    980       : ExternalElementsAccessor<ExternalDoubleElementsAccessor,
    981                                  EXTERNAL_DOUBLE_ELEMENTS>(name) {}
    982 };
    983 
    984 
    985 class PixelElementsAccessor
    986     : public ExternalElementsAccessor<PixelElementsAccessor,
    987                                       EXTERNAL_PIXEL_ELEMENTS> {
    988  public:
    989   explicit PixelElementsAccessor(const char* name)
    990       : ExternalElementsAccessor<PixelElementsAccessor,
    991                                  EXTERNAL_PIXEL_ELEMENTS>(name) {}
    992 };
    993 
    994 
    995 class DictionaryElementsAccessor
    996     : public ElementsAccessorBase<DictionaryElementsAccessor,
    997                                   ElementsKindTraits<DICTIONARY_ELEMENTS> > {
    998  public:
    999   explicit DictionaryElementsAccessor(const char* name)
   1000       : ElementsAccessorBase<DictionaryElementsAccessor,
   1001                              ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
   1002 
   1003   // Adjusts the length of the dictionary backing store and returns the new
   1004   // length according to ES5 section 15.4.5.2 behavior.
   1005   static MaybeObject* SetLengthWithoutNormalize(SeededNumberDictionary* dict,
   1006                                                 JSArray* array,
   1007                                                 Object* length_object,
   1008                                                 uint32_t length) {
   1009     if (length == 0) {
   1010       // If the length of a slow array is reset to zero, we clear
   1011       // the array and flush backing storage. This has the added
   1012       // benefit that the array returns to fast mode.
   1013       Object* obj;
   1014       MaybeObject* maybe_obj = array->ResetElements();
   1015       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
   1016     } else {
   1017       uint32_t new_length = length;
   1018       uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
   1019       if (new_length < old_length) {
   1020         // Find last non-deletable element in range of elements to be
   1021         // deleted and adjust range accordingly.
   1022         Heap* heap = array->GetHeap();
   1023         int capacity = dict->Capacity();
   1024         for (int i = 0; i < capacity; i++) {
   1025           Object* key = dict->KeyAt(i);
   1026           if (key->IsNumber()) {
   1027             uint32_t number = static_cast<uint32_t>(key->Number());
   1028             if (new_length <= number && number < old_length) {
   1029               PropertyDetails details = dict->DetailsAt(i);
   1030               if (details.IsDontDelete()) new_length = number + 1;
   1031             }
   1032           }
   1033         }
   1034         if (new_length != length) {
   1035           MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
   1036           if (!maybe_object->To(&length_object)) return maybe_object;
   1037         }
   1038 
   1039         // Remove elements that should be deleted.
   1040         int removed_entries = 0;
   1041         Object* the_hole_value = heap->the_hole_value();
   1042         for (int i = 0; i < capacity; i++) {
   1043           Object* key = dict->KeyAt(i);
   1044           if (key->IsNumber()) {
   1045             uint32_t number = static_cast<uint32_t>(key->Number());
   1046             if (new_length <= number && number < old_length) {
   1047               dict->SetEntry(i, the_hole_value, the_hole_value);
   1048               removed_entries++;
   1049             }
   1050           }
   1051         }
   1052 
   1053         // Update the number of elements.
   1054         dict->ElementsRemoved(removed_entries);
   1055       }
   1056     }
   1057     return length_object;
   1058   }
   1059 
   1060   static MaybeObject* DeleteCommon(JSObject* obj,
   1061                                    uint32_t key,
   1062                                    JSReceiver::DeleteMode mode) {
   1063     Isolate* isolate = obj->GetIsolate();
   1064     Heap* heap = isolate->heap();
   1065     FixedArray* backing_store = FixedArray::cast(obj->elements());
   1066     bool is_arguments =
   1067         (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
   1068     if (is_arguments) {
   1069       backing_store = FixedArray::cast(backing_store->get(1));
   1070     }
   1071     SeededNumberDictionary* dictionary =
   1072         SeededNumberDictionary::cast(backing_store);
   1073     int entry = dictionary->FindEntry(key);
   1074     if (entry != SeededNumberDictionary::kNotFound) {
   1075       Object* result = dictionary->DeleteProperty(entry, mode);
   1076       if (result == heap->true_value()) {
   1077         MaybeObject* maybe_elements = dictionary->Shrink(key);
   1078         FixedArray* new_elements = NULL;
   1079         if (!maybe_elements->To(&new_elements)) {
   1080           return maybe_elements;
   1081         }
   1082         if (is_arguments) {
   1083           FixedArray::cast(obj->elements())->set(1, new_elements);
   1084         } else {
   1085           obj->set_elements(new_elements);
   1086         }
   1087       }
   1088       if (mode == JSObject::STRICT_DELETION &&
   1089           result == heap->false_value()) {
   1090         // In strict mode, attempting to delete a non-configurable property
   1091         // throws an exception.
   1092         HandleScope scope(isolate);
   1093         Handle<Object> holder(obj);
   1094         Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
   1095         Handle<Object> args[2] = { name, holder };
   1096         Handle<Object> error =
   1097             isolate->factory()->NewTypeError("strict_delete_property",
   1098                                              HandleVector(args, 2));
   1099         return isolate->Throw(*error);
   1100       }
   1101     }
   1102     return heap->true_value();
   1103   }
   1104 
   1105   static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
   1106                                        uint32_t from_start,
   1107                                        FixedArrayBase* to,
   1108                                        ElementsKind to_kind,
   1109                                        uint32_t to_start,
   1110                                        int copy_size) {
   1111     switch (to_kind) {
   1112       case FAST_SMI_ONLY_ELEMENTS:
   1113       case FAST_ELEMENTS:
   1114         CopyDictionaryToObjectElements(
   1115             SeededNumberDictionary::cast(from), from_start,
   1116             FixedArray::cast(to), to_kind, to_start, copy_size);
   1117         return from;
   1118       case FAST_DOUBLE_ELEMENTS:
   1119         CopyDictionaryToDoubleElements(
   1120             SeededNumberDictionary::cast(from), from_start,
   1121             FixedDoubleArray::cast(to), to_start, copy_size);
   1122         return from;
   1123       default:
   1124         UNREACHABLE();
   1125     }
   1126     return to->GetHeap()->undefined_value();
   1127   }
   1128 
   1129 
   1130  protected:
   1131   friend class ElementsAccessorBase<DictionaryElementsAccessor,
   1132                                     ElementsKindTraits<DICTIONARY_ELEMENTS> >;
   1133 
   1134   virtual MaybeObject* Delete(JSObject* obj,
   1135                               uint32_t key,
   1136                               JSReceiver::DeleteMode mode) {
   1137     return DeleteCommon(obj, key, mode);
   1138   }
   1139 
   1140   static MaybeObject* GetImpl(Object* receiver,
   1141                               JSObject* obj,
   1142                               uint32_t key,
   1143                               SeededNumberDictionary* backing_store) {
   1144     int entry = backing_store->FindEntry(key);
   1145     if (entry != SeededNumberDictionary::kNotFound) {
   1146       Object* element = backing_store->ValueAt(entry);
   1147       PropertyDetails details = backing_store->DetailsAt(entry);
   1148       if (details.type() == CALLBACKS) {
   1149         return obj->GetElementWithCallback(receiver,
   1150                                            element,
   1151                                            key,
   1152                                            obj);
   1153       } else {
   1154         return element;
   1155       }
   1156     }
   1157     return obj->GetHeap()->the_hole_value();
   1158   }
   1159 
   1160   static bool HasElementImpl(Object* receiver,
   1161                              JSObject* holder,
   1162                              uint32_t key,
   1163                              SeededNumberDictionary* backing_store) {
   1164     return backing_store->FindEntry(key) !=
   1165         SeededNumberDictionary::kNotFound;
   1166   }
   1167 
   1168   static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
   1169                                      uint32_t index) {
   1170     Object* key = dict->KeyAt(index);
   1171     return Smi::cast(key)->value();
   1172   }
   1173 };
   1174 
   1175 
   1176 class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
   1177     NonStrictArgumentsElementsAccessor,
   1178     ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > {
   1179  public:
   1180   explicit NonStrictArgumentsElementsAccessor(const char* name)
   1181       : ElementsAccessorBase<
   1182           NonStrictArgumentsElementsAccessor,
   1183           ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {}
   1184  protected:
   1185   friend class ElementsAccessorBase<
   1186       NonStrictArgumentsElementsAccessor,
   1187       ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >;
   1188 
   1189   static MaybeObject* GetImpl(Object* receiver,
   1190                               JSObject* obj,
   1191                               uint32_t key,
   1192                               FixedArray* parameter_map) {
   1193     Object* probe = GetParameterMapArg(obj, parameter_map, key);
   1194     if (!probe->IsTheHole()) {
   1195       Context* context = Context::cast(parameter_map->get(0));
   1196       int context_index = Smi::cast(probe)->value();
   1197       ASSERT(!context->get(context_index)->IsTheHole());
   1198       return context->get(context_index);
   1199     } else {
   1200       // Object is not mapped, defer to the arguments.
   1201       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   1202       MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get(
   1203           receiver, obj, key, arguments);
   1204       Object* result;
   1205       if (!maybe_result->ToObject(&result)) return maybe_result;
   1206       // Elements of the arguments object in slow mode might be slow aliases.
   1207       if (result->IsAliasedArgumentsEntry()) {
   1208         AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result);
   1209         Context* context = Context::cast(parameter_map->get(0));
   1210         int context_index = entry->aliased_context_slot();
   1211         ASSERT(!context->get(context_index)->IsTheHole());
   1212         return context->get(context_index);
   1213       } else {
   1214         return result;
   1215       }
   1216     }
   1217   }
   1218 
   1219   static MaybeObject* SetLengthImpl(JSObject* obj,
   1220                                     Object* length,
   1221                                     FixedArray* parameter_map) {
   1222     // TODO(mstarzinger): This was never implemented but will be used once we
   1223     // correctly implement [[DefineOwnProperty]] on arrays.
   1224     UNIMPLEMENTED();
   1225     return obj;
   1226   }
   1227 
   1228   virtual MaybeObject* Delete(JSObject* obj,
   1229                               uint32_t key,
   1230                               JSReceiver::DeleteMode mode) {
   1231     FixedArray* parameter_map = FixedArray::cast(obj->elements());
   1232     Object* probe = GetParameterMapArg(obj, parameter_map, key);
   1233     if (!probe->IsTheHole()) {
   1234       // TODO(kmillikin): We could check if this was the last aliased
   1235       // parameter, and revert to normal elements in that case.  That
   1236       // would enable GC of the context.
   1237       parameter_map->set_the_hole(key + 2);
   1238     } else {
   1239       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   1240       if (arguments->IsDictionary()) {
   1241         return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
   1242       } else {
   1243         return FastObjectElementsAccessor::DeleteCommon(obj, key);
   1244       }
   1245     }
   1246     return obj->GetHeap()->true_value();
   1247   }
   1248 
   1249   static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
   1250                                        uint32_t from_start,
   1251                                        FixedArrayBase* to,
   1252                                        ElementsKind to_kind,
   1253                                        uint32_t to_start,
   1254                                        int copy_size) {
   1255     FixedArray* parameter_map = FixedArray::cast(from);
   1256     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
   1257     ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
   1258     return accessor->CopyElements(NULL, from_start, to, to_kind,
   1259                                   to_start, copy_size, arguments);
   1260   }
   1261 
   1262   static uint32_t GetCapacityImpl(FixedArray* parameter_map) {
   1263     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   1264     return Max(static_cast<uint32_t>(parameter_map->length() - 2),
   1265                ForArray(arguments)->GetCapacity(arguments));
   1266   }
   1267 
   1268   static uint32_t GetKeyForIndexImpl(FixedArray* dict,
   1269                                      uint32_t index) {
   1270     return index;
   1271   }
   1272 
   1273   static bool HasElementImpl(Object* receiver,
   1274                              JSObject* holder,
   1275                              uint32_t key,
   1276                              FixedArray* parameter_map) {
   1277     Object* probe = GetParameterMapArg(holder, parameter_map, key);
   1278     if (!probe->IsTheHole()) {
   1279       return true;
   1280     } else {
   1281       FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
   1282       ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
   1283       return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
   1284     }
   1285   }
   1286 
   1287  private:
   1288   static Object* GetParameterMapArg(JSObject* holder,
   1289                                     FixedArray* parameter_map,
   1290                                     uint32_t key) {
   1291     uint32_t length = holder->IsJSArray()
   1292         ? Smi::cast(JSArray::cast(holder)->length())->value()
   1293         : parameter_map->length();
   1294     return key < (length - 2 )
   1295         ? parameter_map->get(key + 2)
   1296         : parameter_map->GetHeap()->the_hole_value();
   1297   }
   1298 };
   1299 
   1300 
   1301 ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
   1302   switch (array->map()->instance_type()) {
   1303     case FIXED_ARRAY_TYPE:
   1304       if (array->IsDictionary()) {
   1305         return elements_accessors_[DICTIONARY_ELEMENTS];
   1306       } else {
   1307         return elements_accessors_[FAST_ELEMENTS];
   1308       }
   1309     case EXTERNAL_BYTE_ARRAY_TYPE:
   1310       return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
   1311     case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
   1312       return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
   1313     case EXTERNAL_SHORT_ARRAY_TYPE:
   1314       return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
   1315     case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
   1316       return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
   1317     case EXTERNAL_INT_ARRAY_TYPE:
   1318       return elements_accessors_[EXTERNAL_INT_ELEMENTS];
   1319     case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
   1320       return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
   1321     case EXTERNAL_FLOAT_ARRAY_TYPE:
   1322       return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
   1323     case EXTERNAL_DOUBLE_ARRAY_TYPE:
   1324       return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
   1325     case EXTERNAL_PIXEL_ARRAY_TYPE:
   1326       return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
   1327     default:
   1328       UNREACHABLE();
   1329       return NULL;
   1330   }
   1331 }
   1332 
   1333 
   1334 void ElementsAccessor::InitializeOncePerProcess() {
   1335   static struct ConcreteElementsAccessors {
   1336 #define ACCESSOR_STRUCT(Class, Kind, Store) Class* Kind##_handler;
   1337     ELEMENTS_LIST(ACCESSOR_STRUCT)
   1338 #undef ACCESSOR_STRUCT
   1339   } element_accessors = {
   1340 #define ACCESSOR_INIT(Class, Kind, Store) new Class(#Kind),
   1341     ELEMENTS_LIST(ACCESSOR_INIT)
   1342 #undef ACCESSOR_INIT
   1343   };
   1344 
   1345   static ElementsAccessor* accessor_array[] = {
   1346 #define ACCESSOR_ARRAY(Class, Kind, Store) element_accessors.Kind##_handler,
   1347     ELEMENTS_LIST(ACCESSOR_ARRAY)
   1348 #undef ACCESSOR_ARRAY
   1349   };
   1350 
   1351   STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
   1352                 kElementsKindCount);
   1353 
   1354   elements_accessors_ = accessor_array;
   1355 }
   1356 
   1357 
   1358 template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
   1359 MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
   1360                                   ElementsKindTraits>::
   1361     SetLengthImpl(JSObject* obj,
   1362                   Object* length,
   1363                   typename ElementsKindTraits::BackingStore* backing_store) {
   1364   JSArray* array = JSArray::cast(obj);
   1365 
   1366   // Fast case: The new length fits into a Smi.
   1367   MaybeObject* maybe_smi_length = length->ToSmi();
   1368   Object* smi_length = Smi::FromInt(0);
   1369   if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
   1370     const int value = Smi::cast(smi_length)->value();
   1371     if (value >= 0) {
   1372       Object* new_length;
   1373       MaybeObject* result = ElementsAccessorSubclass::
   1374           SetLengthWithoutNormalize(backing_store, array, smi_length, value);
   1375       if (!result->ToObject(&new_length)) return result;
   1376       ASSERT(new_length->IsSmi() || new_length->IsUndefined());
   1377       if (new_length->IsSmi()) {
   1378         array->set_length(Smi::cast(new_length));
   1379         return array;
   1380       }
   1381     } else {
   1382       return ThrowArrayLengthRangeError(array->GetHeap());
   1383     }
   1384   }
   1385 
   1386   // Slow case: The new length does not fit into a Smi or conversion
   1387   // to slow elements is needed for other reasons.
   1388   if (length->IsNumber()) {
   1389     uint32_t value;
   1390     if (length->ToArrayIndex(&value)) {
   1391       SeededNumberDictionary* dictionary;
   1392       MaybeObject* maybe_object = array->NormalizeElements();
   1393       if (!maybe_object->To(&dictionary)) return maybe_object;
   1394       Object* new_length;
   1395       MaybeObject* result = DictionaryElementsAccessor::
   1396           SetLengthWithoutNormalize(dictionary, array, length, value);
   1397       if (!result->ToObject(&new_length)) return result;
   1398       ASSERT(new_length->IsNumber());
   1399       array->set_length(new_length);
   1400       return array;
   1401     } else {
   1402       return ThrowArrayLengthRangeError(array->GetHeap());
   1403     }
   1404   }
   1405 
   1406   // Fall-back case: The new length is not a number so make the array
   1407   // size one and set only element to length.
   1408   FixedArray* new_backing_store;
   1409   MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
   1410   if (!maybe_obj->To(&new_backing_store)) return maybe_obj;
   1411   new_backing_store->set(0, length);
   1412   { MaybeObject* result = array->SetContent(new_backing_store);
   1413     if (result->IsFailure()) return result;
   1414   }
   1415   return array;
   1416 }
   1417 
   1418 
   1419 } }  // namespace v8::internal
   1420