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
58namespace v8 {
59namespace 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
94template<ElementsKind Kind> class ElementsKindTraits {
95 public:
96  typedef FixedArrayBase BackingStore;
97};
98
99#define ELEMENTS_TRAITS(Class, KindParam, Store)               \
100template<> class ElementsKindTraits<KindParam> {               \
101  public:                                                      \
102  static const ElementsKind Kind = KindParam;                  \
103  typedef Store BackingStore;                                  \
104};
105ELEMENTS_LIST(ELEMENTS_TRAITS)
106#undef ELEMENTS_TRAITS
107
108
109ElementsAccessor** ElementsAccessor::elements_accessors_;
110
111
112static 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
126static 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
134void 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
180static 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
230MUST_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
285static 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
316static 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
346static 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).
395template <typename ElementsAccessorSubclass,
396          typename ElementsTraitsParam>
397class 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.
612template<typename FastElementsAccessorSubclass,
613         typename KindTraits,
614         int ElementSize>
615class 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
677class 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
784class 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.
853template<typename ExternalElementsAccessorSubclass,
854         ElementsKind Kind>
855class 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
905class 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
915class 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
925class 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
935class 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
945class 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
955class 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
965class 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
975class 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
985class 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
995class 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
1176class 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
1301ElementsAccessor* 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
1334void 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
1358template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
1359MaybeObject* 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