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