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