• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/elements.h"
6 
7 #include "src/arguments.h"
8 #include "src/conversions.h"
9 #include "src/factory.h"
10 #include "src/messages.h"
11 #include "src/objects-inl.h"
12 #include "src/utils.h"
13 
14 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
15 // several abstract ElementsAccessor classes are used to allow sharing
16 // common code.
17 //
18 // Inheritance hierarchy:
19 // - ElementsAccessorBase                        (abstract)
20 //   - FastElementsAccessor                      (abstract)
21 //     - FastSmiOrObjectElementsAccessor
22 //       - FastPackedSmiElementsAccessor
23 //       - FastHoleySmiElementsAccessor
24 //       - FastPackedObjectElementsAccessor
25 //       - FastHoleyObjectElementsAccessor
26 //     - FastDoubleElementsAccessor
27 //       - FastPackedDoubleElementsAccessor
28 //       - FastHoleyDoubleElementsAccessor
29 //   - TypedElementsAccessor: template, with instantiations:
30 //     - FixedUint8ElementsAccessor
31 //     - FixedInt8ElementsAccessor
32 //     - FixedUint16ElementsAccessor
33 //     - FixedInt16ElementsAccessor
34 //     - FixedUint32ElementsAccessor
35 //     - FixedInt32ElementsAccessor
36 //     - FixedFloat32ElementsAccessor
37 //     - FixedFloat64ElementsAccessor
38 //     - FixedUint8ClampedElementsAccessor
39 //   - DictionaryElementsAccessor
40 //   - SloppyArgumentsElementsAccessor
41 //     - FastSloppyArgumentsElementsAccessor
42 //     - SlowSloppyArgumentsElementsAccessor
43 
44 
45 namespace v8 {
46 namespace internal {
47 
48 
49 namespace {
50 
51 
52 static const int kPackedSizeNotKnown = -1;
53 
54 enum Where { AT_START, AT_END };
55 
56 
57 // First argument in list is the accessor class, the second argument is the
58 // accessor ElementsKind, and the third is the backing store class.  Use the
59 // fast element handler for smi-only arrays.  The implementation is currently
60 // identical.  Note that the order must match that of the ElementsKind enum for
61 // the |accessor_array[]| below to work.
62 #define ELEMENTS_LIST(V)                                                      \
63   V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray)             \
64   V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray)        \
65   V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray)              \
66   V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray)         \
67   V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
68   V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS,              \
69     FixedDoubleArray)                                                         \
70   V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary)  \
71   V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS,      \
72     FixedArray)                                                               \
73   V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS,      \
74     FixedArray)                                                               \
75   V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array)              \
76   V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array)                 \
77   V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array)           \
78   V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array)              \
79   V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array)           \
80   V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array)              \
81   V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array)        \
82   V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array)        \
83   V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS,                \
84     FixedUint8ClampedArray)
85 
86 
87 template<ElementsKind Kind> class ElementsKindTraits {
88  public:
89   typedef FixedArrayBase BackingStore;
90 };
91 
92 #define ELEMENTS_TRAITS(Class, KindParam, Store)               \
93 template<> class ElementsKindTraits<KindParam> {               \
94  public:   /* NOLINT */                                        \
95   static const ElementsKind Kind = KindParam;                  \
96   typedef Store BackingStore;                                  \
97 };
ELEMENTS_LIST(ELEMENTS_TRAITS)98 ELEMENTS_LIST(ELEMENTS_TRAITS)
99 #undef ELEMENTS_TRAITS
100 
101 
102 MUST_USE_RESULT
103 MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
104   THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
105                   Object);
106 }
107 
108 
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)109 void CopyObjectToObjectElements(FixedArrayBase* from_base,
110                                 ElementsKind from_kind, uint32_t from_start,
111                                 FixedArrayBase* to_base, ElementsKind to_kind,
112                                 uint32_t to_start, int raw_copy_size) {
113   DCHECK(to_base->map() !=
114       from_base->GetIsolate()->heap()->fixed_cow_array_map());
115   DisallowHeapAllocation no_allocation;
116   int copy_size = raw_copy_size;
117   if (raw_copy_size < 0) {
118     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
119            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
120     copy_size = Min(from_base->length() - from_start,
121                     to_base->length() - to_start);
122     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
123       int start = to_start + copy_size;
124       int length = to_base->length() - start;
125       if (length > 0) {
126         Heap* heap = from_base->GetHeap();
127         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
128                       heap->the_hole_value(), length);
129       }
130     }
131   }
132   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
133          (copy_size + static_cast<int>(from_start)) <= from_base->length());
134   if (copy_size == 0) return;
135   FixedArray* from = FixedArray::cast(from_base);
136   FixedArray* to = FixedArray::cast(to_base);
137   DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
138   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
139 
140   WriteBarrierMode write_barrier_mode =
141       (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
142           ? UPDATE_WRITE_BARRIER
143           : SKIP_WRITE_BARRIER;
144   for (int i = 0; i < copy_size; i++) {
145     Object* value = from->get(from_start + i);
146     to->set(to_start + i, value, write_barrier_mode);
147   }
148 }
149 
150 
CopyDictionaryToObjectElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)151 static void CopyDictionaryToObjectElements(
152     FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
153     ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
154   DisallowHeapAllocation no_allocation;
155   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
156   int copy_size = raw_copy_size;
157   if (raw_copy_size < 0) {
158     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
159            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
160     copy_size = from->max_number_key() + 1 - from_start;
161     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
162       int start = to_start + copy_size;
163       int length = to_base->length() - start;
164       if (length > 0) {
165         Heap* heap = from->GetHeap();
166         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
167                       heap->the_hole_value(), length);
168       }
169     }
170   }
171   DCHECK(to_base != from_base);
172   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
173   if (copy_size == 0) return;
174   FixedArray* to = FixedArray::cast(to_base);
175   uint32_t to_length = to->length();
176   if (to_start + copy_size > to_length) {
177     copy_size = to_length - to_start;
178   }
179   WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
180                                             ? UPDATE_WRITE_BARRIER
181                                             : SKIP_WRITE_BARRIER;
182   for (int i = 0; i < copy_size; i++) {
183     int entry = from->FindEntry(i + from_start);
184     if (entry != SeededNumberDictionary::kNotFound) {
185       Object* value = from->ValueAt(entry);
186       DCHECK(!value->IsTheHole());
187       to->set(i + to_start, value, write_barrier_mode);
188     } else {
189       to->set_the_hole(i + to_start);
190     }
191   }
192 }
193 
194 
195 // NOTE: this method violates the handlified function signature convention:
196 // raw pointer parameters in the function that allocates.
197 // See ElementsAccessorBase::CopyElements() for details.
CopyDoubleToObjectElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)198 static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
199                                        uint32_t from_start,
200                                        FixedArrayBase* to_base,
201                                        uint32_t to_start, int raw_copy_size) {
202   int copy_size = raw_copy_size;
203   if (raw_copy_size < 0) {
204     DisallowHeapAllocation no_allocation;
205     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
206            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
207     copy_size = Min(from_base->length() - from_start,
208                     to_base->length() - to_start);
209     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
210       // Also initialize the area that will be copied over since HeapNumber
211       // allocation below can cause an incremental marking step, requiring all
212       // existing heap objects to be propertly initialized.
213       int start = to_start;
214       int length = to_base->length() - start;
215       if (length > 0) {
216         Heap* heap = from_base->GetHeap();
217         MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
218                       heap->the_hole_value(), length);
219       }
220     }
221   }
222 
223   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
224          (copy_size + static_cast<int>(from_start)) <= from_base->length());
225   if (copy_size == 0) return;
226 
227   // From here on, the code below could actually allocate. Therefore the raw
228   // values are wrapped into handles.
229   Isolate* isolate = from_base->GetIsolate();
230   Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
231   Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
232 
233   // create an outer loop to not waste too much time on creating HandleScopes
234   // on the other hand we might overflow a single handle scope depending on
235   // the copy_size
236   int offset = 0;
237   while (offset < copy_size) {
238     HandleScope scope(isolate);
239     offset += 100;
240     for (int i = offset - 100; i < offset && i < copy_size; ++i) {
241       Handle<Object> value = FixedDoubleArray::get(from, i + from_start);
242       to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
243     }
244   }
245 }
246 
247 
CopyDoubleToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)248 static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
249                                        uint32_t from_start,
250                                        FixedArrayBase* to_base,
251                                        uint32_t to_start, int raw_copy_size) {
252   DisallowHeapAllocation no_allocation;
253   int copy_size = raw_copy_size;
254   if (raw_copy_size < 0) {
255     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
256            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
257     copy_size = Min(from_base->length() - from_start,
258                     to_base->length() - to_start);
259     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
260       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
261         FixedDoubleArray::cast(to_base)->set_the_hole(i);
262       }
263     }
264   }
265   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
266          (copy_size + static_cast<int>(from_start)) <= from_base->length());
267   if (copy_size == 0) return;
268   FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
269   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
270   Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
271   Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
272   to_address += kDoubleSize * to_start;
273   from_address += kDoubleSize * from_start;
274   int words_per_double = (kDoubleSize / kPointerSize);
275   CopyWords(reinterpret_cast<Object**>(to_address),
276             reinterpret_cast<Object**>(from_address),
277             static_cast<size_t>(words_per_double * copy_size));
278 }
279 
280 
CopySmiToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)281 static void CopySmiToDoubleElements(FixedArrayBase* from_base,
282                                     uint32_t from_start,
283                                     FixedArrayBase* to_base, uint32_t to_start,
284                                     int raw_copy_size) {
285   DisallowHeapAllocation no_allocation;
286   int copy_size = raw_copy_size;
287   if (raw_copy_size < 0) {
288     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
289            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
290     copy_size = from_base->length() - from_start;
291     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
292       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
293         FixedDoubleArray::cast(to_base)->set_the_hole(i);
294       }
295     }
296   }
297   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
298          (copy_size + static_cast<int>(from_start)) <= from_base->length());
299   if (copy_size == 0) return;
300   FixedArray* from = FixedArray::cast(from_base);
301   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
302   Object* the_hole = from->GetHeap()->the_hole_value();
303   for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
304        from_start < from_end; from_start++, to_start++) {
305     Object* hole_or_smi = from->get(from_start);
306     if (hole_or_smi == the_hole) {
307       to->set_the_hole(to_start);
308     } else {
309       to->set(to_start, Smi::cast(hole_or_smi)->value());
310     }
311   }
312 }
313 
314 
CopyPackedSmiToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int packed_size,int raw_copy_size)315 static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
316                                           uint32_t from_start,
317                                           FixedArrayBase* to_base,
318                                           uint32_t to_start, int packed_size,
319                                           int raw_copy_size) {
320   DisallowHeapAllocation no_allocation;
321   int copy_size = raw_copy_size;
322   uint32_t to_end;
323   if (raw_copy_size < 0) {
324     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
325            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
326     copy_size = packed_size - from_start;
327     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
328       to_end = to_base->length();
329       for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
330         FixedDoubleArray::cast(to_base)->set_the_hole(i);
331       }
332     } else {
333       to_end = to_start + static_cast<uint32_t>(copy_size);
334     }
335   } else {
336     to_end = to_start + static_cast<uint32_t>(copy_size);
337   }
338   DCHECK(static_cast<int>(to_end) <= to_base->length());
339   DCHECK(packed_size >= 0 && packed_size <= copy_size);
340   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
341          (copy_size + static_cast<int>(from_start)) <= from_base->length());
342   if (copy_size == 0) return;
343   FixedArray* from = FixedArray::cast(from_base);
344   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
345   for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
346        from_start < from_end; from_start++, to_start++) {
347     Object* smi = from->get(from_start);
348     DCHECK(!smi->IsTheHole());
349     to->set(to_start, Smi::cast(smi)->value());
350   }
351 }
352 
353 
CopyObjectToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)354 static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
355                                        uint32_t from_start,
356                                        FixedArrayBase* to_base,
357                                        uint32_t to_start, int raw_copy_size) {
358   DisallowHeapAllocation no_allocation;
359   int copy_size = raw_copy_size;
360   if (raw_copy_size < 0) {
361     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
362            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
363     copy_size = from_base->length() - from_start;
364     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
365       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
366         FixedDoubleArray::cast(to_base)->set_the_hole(i);
367       }
368     }
369   }
370   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
371          (copy_size + static_cast<int>(from_start)) <= from_base->length());
372   if (copy_size == 0) return;
373   FixedArray* from = FixedArray::cast(from_base);
374   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
375   Object* the_hole = from->GetHeap()->the_hole_value();
376   for (uint32_t from_end = from_start + copy_size;
377        from_start < from_end; from_start++, to_start++) {
378     Object* hole_or_object = from->get(from_start);
379     if (hole_or_object == the_hole) {
380       to->set_the_hole(to_start);
381     } else {
382       to->set(to_start, hole_or_object->Number());
383     }
384   }
385 }
386 
387 
CopyDictionaryToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)388 static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
389                                            uint32_t from_start,
390                                            FixedArrayBase* to_base,
391                                            uint32_t to_start,
392                                            int raw_copy_size) {
393   DisallowHeapAllocation no_allocation;
394   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
395   int copy_size = raw_copy_size;
396   if (copy_size < 0) {
397     DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
398            copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
399     copy_size = from->max_number_key() + 1 - from_start;
400     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
401       for (int i = to_start + copy_size; i < to_base->length(); ++i) {
402         FixedDoubleArray::cast(to_base)->set_the_hole(i);
403       }
404     }
405   }
406   if (copy_size == 0) return;
407   FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
408   uint32_t to_length = to->length();
409   if (to_start + copy_size > to_length) {
410     copy_size = to_length - to_start;
411   }
412   for (int i = 0; i < copy_size; i++) {
413     int entry = from->FindEntry(i + from_start);
414     if (entry != SeededNumberDictionary::kNotFound) {
415       to->set(i + to_start, from->ValueAt(entry)->Number());
416     } else {
417       to->set_the_hole(i + to_start);
418     }
419   }
420 }
421 
422 
TraceTopFrame(Isolate * isolate)423 static void TraceTopFrame(Isolate* isolate) {
424   StackFrameIterator it(isolate);
425   if (it.done()) {
426     PrintF("unknown location (no JavaScript frames present)");
427     return;
428   }
429   StackFrame* raw_frame = it.frame();
430   if (raw_frame->is_internal()) {
431     Code* apply_builtin =
432         isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
433     if (raw_frame->unchecked_code() == apply_builtin) {
434       PrintF("apply from ");
435       it.Advance();
436       raw_frame = it.frame();
437     }
438   }
439   JavaScriptFrame::PrintTop(isolate, stdout, false, true);
440 }
441 
442 
443 // Base class for element handler implementations. Contains the
444 // the common logic for objects with different ElementsKinds.
445 // Subclasses must specialize method for which the element
446 // implementation differs from the base class implementation.
447 //
448 // This class is intended to be used in the following way:
449 //
450 //   class SomeElementsAccessor :
451 //       public ElementsAccessorBase<SomeElementsAccessor,
452 //                                   BackingStoreClass> {
453 //     ...
454 //   }
455 //
456 // This is an example of the Curiously Recurring Template Pattern (see
457 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).  We use
458 // CRTP to guarantee aggressive compile time optimizations (i.e.  inlining and
459 // specialization of SomeElementsAccessor methods).
460 template <typename ElementsAccessorSubclass,
461           typename ElementsTraitsParam>
462 class ElementsAccessorBase : public ElementsAccessor {
463  public:
ElementsAccessorBase(const char * name)464   explicit ElementsAccessorBase(const char* name)
465       : ElementsAccessor(name) { }
466 
467   typedef ElementsTraitsParam ElementsTraits;
468   typedef typename ElementsTraitsParam::BackingStore BackingStore;
469 
kind()470   static ElementsKind kind() { return ElementsTraits::Kind; }
471 
ValidateContents(Handle<JSObject> holder,int length)472   static void ValidateContents(Handle<JSObject> holder, int length) {
473   }
474 
ValidateImpl(Handle<JSObject> holder)475   static void ValidateImpl(Handle<JSObject> holder) {
476     Handle<FixedArrayBase> fixed_array_base(holder->elements());
477     if (!fixed_array_base->IsHeapObject()) return;
478     // Arrays that have been shifted in place can't be verified.
479     if (fixed_array_base->IsFiller()) return;
480     int length = 0;
481     if (holder->IsJSArray()) {
482       Object* length_obj = Handle<JSArray>::cast(holder)->length();
483       if (length_obj->IsSmi()) {
484         length = Smi::cast(length_obj)->value();
485       }
486     } else {
487       length = fixed_array_base->length();
488     }
489     ElementsAccessorSubclass::ValidateContents(holder, length);
490   }
491 
Validate(Handle<JSObject> holder)492   void Validate(Handle<JSObject> holder) final {
493     DisallowHeapAllocation no_gc;
494     ElementsAccessorSubclass::ValidateImpl(holder);
495   }
496 
IsPacked(Handle<JSObject> holder,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)497   bool IsPacked(Handle<JSObject> holder, Handle<FixedArrayBase> backing_store,
498                 uint32_t start, uint32_t end) final {
499     return ElementsAccessorSubclass::IsPackedImpl(holder, backing_store, start,
500                                                   end);
501   }
502 
IsPackedImpl(Handle<JSObject> holder,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)503   static bool IsPackedImpl(Handle<JSObject> holder,
504                            Handle<FixedArrayBase> backing_store, uint32_t start,
505                            uint32_t end) {
506     if (IsFastPackedElementsKind(kind())) return true;
507     for (uint32_t i = start; i < end; i++) {
508       if (!ElementsAccessorSubclass::HasElementImpl(holder, i, backing_store,
509                                                     ALL_PROPERTIES)) {
510         return false;
511       }
512     }
513     return true;
514   }
515 
TryTransitionResultArrayToPacked(Handle<JSArray> array)516   static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
517     if (!IsHoleyElementsKind(kind())) return;
518     int length = Smi::cast(array->length())->value();
519     Handle<FixedArrayBase> backing_store(array->elements());
520     if (!ElementsAccessorSubclass::IsPackedImpl(array, backing_store, 0,
521                                                 length)) {
522       return;
523     }
524     ElementsKind packed_kind = GetPackedElementsKind(kind());
525     Handle<Map> new_map =
526         JSObject::GetElementsTransitionMap(array, packed_kind);
527     JSObject::MigrateToMap(array, new_map);
528     if (FLAG_trace_elements_transitions) {
529       JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
530                                         packed_kind, backing_store);
531     }
532   }
533 
HasElement(Handle<JSObject> holder,uint32_t index,Handle<FixedArrayBase> backing_store,PropertyFilter filter)534   bool HasElement(Handle<JSObject> holder, uint32_t index,
535                   Handle<FixedArrayBase> backing_store,
536                   PropertyFilter filter) final {
537     return ElementsAccessorSubclass::HasElementImpl(holder, index,
538                                                     backing_store, filter);
539   }
540 
HasElementImpl(Handle<JSObject> holder,uint32_t index,Handle<FixedArrayBase> backing_store,PropertyFilter filter)541   static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
542                              Handle<FixedArrayBase> backing_store,
543                              PropertyFilter filter) {
544     return ElementsAccessorSubclass::GetEntryForIndexImpl(
545                *holder, *backing_store, index, filter) != kMaxUInt32;
546   }
547 
Get(Handle<FixedArrayBase> backing_store,uint32_t entry)548   Handle<Object> Get(Handle<FixedArrayBase> backing_store,
549                      uint32_t entry) final {
550     return ElementsAccessorSubclass::GetImpl(backing_store, entry);
551   }
552 
GetImpl(Handle<FixedArrayBase> backing_store,uint32_t entry)553   static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
554                                 uint32_t entry) {
555     uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
556     return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
557   }
558 
Set(FixedArrayBase * backing_store,uint32_t entry,Object * value)559   void Set(FixedArrayBase* backing_store, uint32_t entry, Object* value) final {
560     ElementsAccessorSubclass::SetImpl(backing_store, entry, value);
561   }
562 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)563   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
564                              Object* value) {
565     UNREACHABLE();
566   }
567 
568 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)569   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
570                              Object* value, WriteBarrierMode mode) {
571     UNREACHABLE();
572   }
573 
Reconfigure(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)574   void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
575                    uint32_t entry, Handle<Object> value,
576                    PropertyAttributes attributes) final {
577     ElementsAccessorSubclass::ReconfigureImpl(object, store, entry, value,
578                                               attributes);
579   }
580 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)581   static void ReconfigureImpl(Handle<JSObject> object,
582                               Handle<FixedArrayBase> store, uint32_t entry,
583                               Handle<Object> value,
584                               PropertyAttributes attributes) {
585     UNREACHABLE();
586   }
587 
Add(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)588   void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
589            PropertyAttributes attributes, uint32_t new_capacity) final {
590     ElementsAccessorSubclass::AddImpl(object, index, value, attributes,
591                                       new_capacity);
592   }
593 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)594   static void AddImpl(Handle<JSObject> object, uint32_t index,
595                       Handle<Object> value, PropertyAttributes attributes,
596                       uint32_t new_capacity) {
597     UNREACHABLE();
598   }
599 
Push(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t push_size)600   uint32_t Push(Handle<JSArray> receiver, Handle<FixedArrayBase> backing_store,
601                 Arguments* args, uint32_t push_size) final {
602     return ElementsAccessorSubclass::PushImpl(receiver, backing_store, args,
603                                               push_size);
604   }
605 
PushImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> elms_obj,Arguments * args,uint32_t push_sized)606   static uint32_t PushImpl(Handle<JSArray> receiver,
607                            Handle<FixedArrayBase> elms_obj, Arguments* args,
608                            uint32_t push_sized) {
609     UNREACHABLE();
610     return 0;
611   }
612 
Unshift(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t unshift_size)613   uint32_t Unshift(Handle<JSArray> receiver,
614                    Handle<FixedArrayBase> backing_store, Arguments* args,
615                    uint32_t unshift_size) final {
616     return ElementsAccessorSubclass::UnshiftImpl(receiver, backing_store, args,
617                                                  unshift_size);
618   }
619 
UnshiftImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> elms_obj,Arguments * args,uint32_t unshift_size)620   static uint32_t UnshiftImpl(Handle<JSArray> receiver,
621                               Handle<FixedArrayBase> elms_obj, Arguments* args,
622                               uint32_t unshift_size) {
623     UNREACHABLE();
624     return 0;
625   }
626 
Slice(Handle<JSObject> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)627   Handle<JSArray> Slice(Handle<JSObject> receiver,
628                         Handle<FixedArrayBase> backing_store, uint32_t start,
629                         uint32_t end) final {
630     return ElementsAccessorSubclass::SliceImpl(receiver, backing_store, start,
631                                                end);
632   }
633 
SliceImpl(Handle<JSObject> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)634   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
635                                    Handle<FixedArrayBase> backing_store,
636                                    uint32_t start, uint32_t end) {
637     UNREACHABLE();
638     return Handle<JSArray>();
639   }
640 
Splice(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)641   Handle<JSArray> Splice(Handle<JSArray> receiver,
642                          Handle<FixedArrayBase> backing_store, uint32_t start,
643                          uint32_t delete_count, Arguments* args,
644                          uint32_t add_count) final {
645     return ElementsAccessorSubclass::SpliceImpl(receiver, backing_store, start,
646                                                 delete_count, args, add_count);
647   }
648 
SpliceImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)649   static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
650                                     Handle<FixedArrayBase> backing_store,
651                                     uint32_t start, uint32_t delete_count,
652                                     Arguments* args, uint32_t add_count) {
653     UNREACHABLE();
654     return Handle<JSArray>();
655   }
656 
Pop(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)657   Handle<Object> Pop(Handle<JSArray> receiver,
658                      Handle<FixedArrayBase> backing_store) final {
659     return ElementsAccessorSubclass::PopImpl(receiver, backing_store);
660   }
661 
PopImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)662   static Handle<Object> PopImpl(Handle<JSArray> receiver,
663                                 Handle<FixedArrayBase> backing_store) {
664     UNREACHABLE();
665     return Handle<Object>();
666   }
667 
Shift(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)668   Handle<Object> Shift(Handle<JSArray> receiver,
669                        Handle<FixedArrayBase> backing_store) final {
670     return ElementsAccessorSubclass::ShiftImpl(receiver, backing_store);
671   }
672 
ShiftImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)673   static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
674                                   Handle<FixedArrayBase> backing_store) {
675     UNREACHABLE();
676     return Handle<Object>();
677   }
678 
SetLength(Handle<JSArray> array,uint32_t length)679   void SetLength(Handle<JSArray> array, uint32_t length) final {
680     ElementsAccessorSubclass::SetLengthImpl(array->GetIsolate(), array, length,
681                                             handle(array->elements()));
682   }
683 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)684   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
685                             uint32_t length,
686                             Handle<FixedArrayBase> backing_store) {
687     DCHECK(!array->SetLengthWouldNormalize(length));
688     DCHECK(IsFastElementsKind(array->GetElementsKind()));
689     uint32_t old_length = 0;
690     CHECK(array->length()->ToArrayIndex(&old_length));
691 
692     if (old_length < length) {
693       ElementsKind kind = array->GetElementsKind();
694       if (!IsFastHoleyElementsKind(kind)) {
695         kind = GetHoleyElementsKind(kind);
696         JSObject::TransitionElementsKind(array, kind);
697       }
698     }
699 
700     // Check whether the backing store should be shrunk.
701     uint32_t capacity = backing_store->length();
702     old_length = Min(old_length, capacity);
703     if (length == 0) {
704       array->initialize_elements();
705     } else if (length <= capacity) {
706       if (array->HasFastSmiOrObjectElements()) {
707         backing_store = JSObject::EnsureWritableFastElements(array);
708       }
709       if (2 * length <= capacity) {
710         // If more than half the elements won't be used, trim the array.
711         isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
712             *backing_store, capacity - length);
713       } else {
714         // Otherwise, fill the unused tail with holes.
715         for (uint32_t i = length; i < old_length; i++) {
716           BackingStore::cast(*backing_store)->set_the_hole(i);
717         }
718       }
719     } else {
720       // Check whether the backing store should be expanded.
721       capacity = Max(length, JSObject::NewElementsCapacity(capacity));
722       ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity);
723     }
724 
725     array->set_length(Smi::FromInt(length));
726     JSObject::ValidateElements(array);
727   }
728 
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity)729   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
730       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
731       ElementsKind from_kind, uint32_t capacity) {
732     return ConvertElementsWithCapacity(
733         object, old_elements, from_kind, capacity, 0, 0,
734         ElementsAccessor::kCopyToEndAndInitializeToHole);
735   }
736 
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity,int copy_size)737   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
738       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
739       ElementsKind from_kind, uint32_t capacity, int copy_size) {
740     return ConvertElementsWithCapacity(object, old_elements, from_kind,
741                                        capacity, 0, 0, copy_size);
742   }
743 
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity,uint32_t src_index,uint32_t dst_index,int copy_size)744   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
745       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
746       ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
747       uint32_t dst_index, int copy_size) {
748     Isolate* isolate = object->GetIsolate();
749     Handle<FixedArrayBase> new_elements;
750     if (IsFastDoubleElementsKind(kind())) {
751       new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
752     } else {
753       new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
754     }
755 
756     int packed_size = kPackedSizeNotKnown;
757     if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
758       packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
759     }
760 
761     ElementsAccessorSubclass::CopyElementsImpl(
762         *old_elements, src_index, *new_elements, from_kind, dst_index,
763         packed_size, copy_size);
764 
765     return new_elements;
766   }
767 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)768   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
769                                          uint32_t capacity) {
770     ElementsKind from_kind = object->GetElementsKind();
771     if (IsFastSmiOrObjectElementsKind(from_kind)) {
772       // Array optimizations rely on the prototype lookups of Array objects
773       // always returning undefined. If there is a store to the initial
774       // prototype object, make sure all of these optimizations are invalidated.
775       object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
776     }
777     Handle<FixedArrayBase> old_elements(object->elements());
778     // This method should only be called if there's a reason to update the
779     // elements.
780     DCHECK(IsFastDoubleElementsKind(from_kind) !=
781                IsFastDoubleElementsKind(kind()) ||
782            IsDictionaryElementsKind(from_kind) ||
783            static_cast<uint32_t>(old_elements->length()) < capacity);
784     Handle<FixedArrayBase> elements =
785         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
786 
787     ElementsKind to_kind = kind();
788     if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
789     Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
790     JSObject::SetMapAndElements(object, new_map, elements);
791 
792     // Transition through the allocation site as well if present.
793     JSObject::UpdateAllocationSite(object, to_kind);
794 
795     if (FLAG_trace_elements_transitions) {
796       JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
797                                         to_kind, elements);
798     }
799   }
800 
GrowCapacityAndConvert(Handle<JSObject> object,uint32_t capacity)801   void GrowCapacityAndConvert(Handle<JSObject> object,
802                               uint32_t capacity) final {
803     ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity);
804   }
805 
Delete(Handle<JSObject> obj,uint32_t entry)806   void Delete(Handle<JSObject> obj, uint32_t entry) final {
807     ElementsAccessorSubclass::DeleteImpl(obj, entry);
808   }
809 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)810   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
811                                FixedArrayBase* to, ElementsKind from_kind,
812                                uint32_t to_start, int packed_size,
813                                int copy_size) {
814     UNREACHABLE();
815   }
816 
CopyElements(Handle<FixedArrayBase> from,uint32_t from_start,ElementsKind from_kind,Handle<FixedArrayBase> to,uint32_t to_start,int copy_size)817   void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start,
818                     ElementsKind from_kind, Handle<FixedArrayBase> to,
819                     uint32_t to_start, int copy_size) final {
820     DCHECK(!from.is_null());
821     // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
822     // violate the handlified function signature convention:
823     // raw pointer parameters in the function that allocates. This is done
824     // intentionally to avoid ArrayConcat() builtin performance degradation.
825     // See the comment in another ElementsAccessorBase::CopyElements() for
826     // details.
827     ElementsAccessorSubclass::CopyElementsImpl(*from, from_start, *to,
828                                                from_kind, to_start,
829                                                kPackedSizeNotKnown, copy_size);
830   }
831 
CopyElements(JSObject * from_holder,uint32_t from_start,ElementsKind from_kind,Handle<FixedArrayBase> to,uint32_t to_start,int copy_size)832   void CopyElements(JSObject* from_holder, uint32_t from_start,
833                     ElementsKind from_kind, Handle<FixedArrayBase> to,
834                     uint32_t to_start, int copy_size) final {
835     int packed_size = kPackedSizeNotKnown;
836     bool is_packed = IsFastPackedElementsKind(from_kind) &&
837         from_holder->IsJSArray();
838     if (is_packed) {
839       packed_size =
840           Smi::cast(JSArray::cast(from_holder)->length())->value();
841       if (copy_size >= 0 && packed_size > copy_size) {
842         packed_size = copy_size;
843       }
844     }
845     FixedArrayBase* from = from_holder->elements();
846     // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
847     // violate the handlified function signature convention:
848     // raw pointer parameters in the function that allocates. This is done
849     // intentionally to avoid ArrayConcat() builtin performance degradation.
850     //
851     // Details: The idea is that allocations actually happen only in case of
852     // copying from object with fast double elements to object with object
853     // elements. In all the other cases there are no allocations performed and
854     // handle creation causes noticeable performance degradation of the builtin.
855     ElementsAccessorSubclass::CopyElementsImpl(
856         from, from_start, *to, from_kind, to_start, packed_size, copy_size);
857   }
858 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys,uint32_t range,PropertyFilter filter,uint32_t offset)859   static void CollectElementIndicesImpl(Handle<JSObject> object,
860                                         Handle<FixedArrayBase> backing_store,
861                                         KeyAccumulator* keys, uint32_t range,
862                                         PropertyFilter filter,
863                                         uint32_t offset) {
864     if (filter & ONLY_ALL_CAN_READ) {
865       // Non-dictionary elements can't have all-can-read accessors.
866       return;
867     }
868     uint32_t length = 0;
869     if (object->IsJSArray()) {
870       length = Smi::cast(JSArray::cast(*object)->length())->value();
871     } else {
872       length =
873           ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
874     }
875     if (range < length) length = range;
876     for (uint32_t i = offset; i < length; i++) {
877       if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
878                                                     filter))
879         continue;
880       keys->AddKey(i);
881     }
882   }
883 
CollectElementIndices(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys,uint32_t range,PropertyFilter filter,uint32_t offset)884   void CollectElementIndices(Handle<JSObject> object,
885                              Handle<FixedArrayBase> backing_store,
886                              KeyAccumulator* keys, uint32_t range,
887                              PropertyFilter filter, uint32_t offset) final {
888     ElementsAccessorSubclass::CollectElementIndicesImpl(
889         object, backing_store, keys, range, filter, offset);
890   };
891 
AddElementsToKeyAccumulator(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)892   void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
893                                    KeyAccumulator* accumulator,
894                                    AddKeyConversion convert) final {
895     Handle<FixedArrayBase> from(receiver->elements());
896     uint32_t add_length =
897         ElementsAccessorSubclass::GetCapacityImpl(*receiver, *from);
898     if (add_length == 0) return;
899 
900     for (uint32_t i = 0; i < add_length; i++) {
901       if (!ElementsAccessorSubclass::HasEntryImpl(*from, i)) continue;
902       Handle<Object> value = ElementsAccessorSubclass::GetImpl(from, i);
903       DCHECK(!value->IsTheHole());
904       DCHECK(!value->IsAccessorPair());
905       DCHECK(!value->IsExecutableAccessorInfo());
906       accumulator->AddKey(value, convert);
907     }
908   }
909 
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)910   static uint32_t GetCapacityImpl(JSObject* holder,
911                                   FixedArrayBase* backing_store) {
912     return backing_store->length();
913   }
914 
GetCapacity(JSObject * holder,FixedArrayBase * backing_store)915   uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
916     return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
917   }
918 
HasEntryImpl(FixedArrayBase * backing_store,uint32_t entry)919   static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
920     return true;
921   }
922 
GetIndexForEntryImpl(FixedArrayBase * backing_store,uint32_t entry)923   static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
924                                        uint32_t entry) {
925     return entry;
926   }
927 
GetEntryForIndexImpl(JSObject * holder,FixedArrayBase * backing_store,uint32_t index,PropertyFilter filter)928   static uint32_t GetEntryForIndexImpl(JSObject* holder,
929                                        FixedArrayBase* backing_store,
930                                        uint32_t index, PropertyFilter filter) {
931     if (IsHoleyElementsKind(kind())) {
932       return index < ElementsAccessorSubclass::GetCapacityImpl(holder,
933                                                                backing_store) &&
934                      !BackingStore::cast(backing_store)->is_the_hole(index)
935                  ? index
936                  : kMaxUInt32;
937     } else {
938       uint32_t length =
939           holder->IsJSArray()
940               ? static_cast<uint32_t>(
941                     Smi::cast(JSArray::cast(holder)->length())->value())
942               : ElementsAccessorSubclass::GetCapacityImpl(holder,
943                                                           backing_store);
944       return index < length ? index : kMaxUInt32;
945     }
946   }
947 
GetEntryForIndex(JSObject * holder,FixedArrayBase * backing_store,uint32_t index)948   uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
949                             uint32_t index) final {
950     return ElementsAccessorSubclass::GetEntryForIndexImpl(
951         holder, backing_store, index, ALL_PROPERTIES);
952   }
953 
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)954   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
955                                         uint32_t entry) {
956     return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
957   }
958 
GetDetails(FixedArrayBase * backing_store,uint32_t entry)959   PropertyDetails GetDetails(FixedArrayBase* backing_store,
960                              uint32_t entry) final {
961     return ElementsAccessorSubclass::GetDetailsImpl(backing_store, entry);
962   }
963 
964  private:
965   DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
966 };
967 
968 
969 class DictionaryElementsAccessor
970     : public ElementsAccessorBase<DictionaryElementsAccessor,
971                                   ElementsKindTraits<DICTIONARY_ELEMENTS> > {
972  public:
DictionaryElementsAccessor(const char * name)973   explicit DictionaryElementsAccessor(const char* name)
974       : ElementsAccessorBase<DictionaryElementsAccessor,
975                              ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
976 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)977   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
978                             uint32_t length,
979                             Handle<FixedArrayBase> backing_store) {
980     Handle<SeededNumberDictionary> dict =
981         Handle<SeededNumberDictionary>::cast(backing_store);
982     int capacity = dict->Capacity();
983     uint32_t old_length = 0;
984     CHECK(array->length()->ToArrayLength(&old_length));
985     if (length < old_length) {
986       if (dict->requires_slow_elements()) {
987         // Find last non-deletable element in range of elements to be
988         // deleted and adjust range accordingly.
989         for (int entry = 0; entry < capacity; entry++) {
990           DisallowHeapAllocation no_gc;
991           Object* index = dict->KeyAt(entry);
992           if (index->IsNumber()) {
993             uint32_t number = static_cast<uint32_t>(index->Number());
994             if (length <= number && number < old_length) {
995               PropertyDetails details = dict->DetailsAt(entry);
996               if (!details.IsConfigurable()) length = number + 1;
997             }
998           }
999         }
1000       }
1001 
1002       if (length == 0) {
1003         // Flush the backing store.
1004         JSObject::ResetElements(array);
1005       } else {
1006         DisallowHeapAllocation no_gc;
1007         // Remove elements that should be deleted.
1008         int removed_entries = 0;
1009         Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
1010         for (int entry = 0; entry < capacity; entry++) {
1011           Object* index = dict->KeyAt(entry);
1012           if (index->IsNumber()) {
1013             uint32_t number = static_cast<uint32_t>(index->Number());
1014             if (length <= number && number < old_length) {
1015               dict->SetEntry(entry, the_hole_value, the_hole_value);
1016               removed_entries++;
1017             }
1018           }
1019         }
1020 
1021         // Update the number of elements.
1022         dict->ElementsRemoved(removed_entries);
1023       }
1024     }
1025 
1026     Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1027     array->set_length(*length_obj);
1028   }
1029 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)1030   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1031                                FixedArrayBase* to, ElementsKind from_kind,
1032                                uint32_t to_start, int packed_size,
1033                                int copy_size) {
1034     UNREACHABLE();
1035   }
1036 
1037 
DeleteImpl(Handle<JSObject> obj,uint32_t entry)1038   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1039     // TODO(verwaest): Remove reliance on index in Shrink.
1040     Handle<SeededNumberDictionary> dict(
1041         SeededNumberDictionary::cast(obj->elements()));
1042     uint32_t index = GetIndexForEntryImpl(*dict, entry);
1043     Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
1044     USE(result);
1045     DCHECK(result->IsTrue());
1046     Handle<FixedArray> new_elements =
1047         SeededNumberDictionary::Shrink(dict, index);
1048     obj->set_elements(*new_elements);
1049   }
1050 
GetRaw(FixedArrayBase * store,uint32_t entry)1051   static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
1052     SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
1053     return backing_store->ValueAt(entry);
1054   }
1055 
GetImpl(Handle<FixedArrayBase> store,uint32_t entry)1056   static Handle<Object> GetImpl(Handle<FixedArrayBase> store, uint32_t entry) {
1057     Isolate* isolate = store->GetIsolate();
1058     return handle(GetRaw(*store, entry), isolate);
1059   }
1060 
SetImpl(FixedArrayBase * store,uint32_t entry,Object * value)1061   static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
1062                              Object* value) {
1063     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1064     dictionary->ValueAtPut(entry, value);
1065   }
1066 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)1067   static void ReconfigureImpl(Handle<JSObject> object,
1068                               Handle<FixedArrayBase> store, uint32_t entry,
1069                               Handle<Object> value,
1070                               PropertyAttributes attributes) {
1071     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
1072     if (attributes != NONE) object->RequireSlowElements(dictionary);
1073     dictionary->ValueAtPut(entry, *value);
1074     PropertyDetails details = dictionary->DetailsAt(entry);
1075     details = PropertyDetails(attributes, DATA, details.dictionary_index(),
1076                               PropertyCellType::kNoCell);
1077     dictionary->DetailsAtPut(entry, details);
1078   }
1079 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)1080   static void AddImpl(Handle<JSObject> object, uint32_t index,
1081                       Handle<Object> value, PropertyAttributes attributes,
1082                       uint32_t new_capacity) {
1083     PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
1084     Handle<SeededNumberDictionary> dictionary =
1085         object->HasFastElements()
1086             ? JSObject::NormalizeElements(object)
1087             : handle(SeededNumberDictionary::cast(object->elements()));
1088     Handle<SeededNumberDictionary> new_dictionary =
1089         SeededNumberDictionary::AddNumberEntry(
1090             dictionary, index, value, details,
1091             object->map()->is_prototype_map());
1092     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1093     if (dictionary.is_identical_to(new_dictionary)) return;
1094     object->set_elements(*new_dictionary);
1095   }
1096 
HasEntryImpl(FixedArrayBase * store,uint32_t entry)1097   static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
1098     DisallowHeapAllocation no_gc;
1099     SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1100     Object* index = dict->KeyAt(entry);
1101     return !index->IsTheHole();
1102   }
1103 
GetIndexForEntryImpl(FixedArrayBase * store,uint32_t entry)1104   static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
1105     DisallowHeapAllocation no_gc;
1106     SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1107     uint32_t result = 0;
1108     CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
1109     return result;
1110   }
1111 
GetEntryForIndexImpl(JSObject * holder,FixedArrayBase * store,uint32_t index,PropertyFilter filter)1112   static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
1113                                        uint32_t index, PropertyFilter filter) {
1114     DisallowHeapAllocation no_gc;
1115     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1116     int entry = dictionary->FindEntry(index);
1117     if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
1118     if (filter != ALL_PROPERTIES) {
1119       PropertyDetails details = dictionary->DetailsAt(entry);
1120       PropertyAttributes attr = details.attributes();
1121       if ((attr & filter) != 0) return kMaxUInt32;
1122     }
1123     return static_cast<uint32_t>(entry);
1124   }
1125 
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)1126   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1127                                         uint32_t entry) {
1128     return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
1129   }
1130 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys,uint32_t range,PropertyFilter filter,uint32_t offset)1131   static void CollectElementIndicesImpl(Handle<JSObject> object,
1132                                         Handle<FixedArrayBase> backing_store,
1133                                         KeyAccumulator* keys, uint32_t range,
1134                                         PropertyFilter filter,
1135                                         uint32_t offset) {
1136     Handle<SeededNumberDictionary> dictionary =
1137         Handle<SeededNumberDictionary>::cast(backing_store);
1138     int capacity = dictionary->Capacity();
1139     for (int i = 0; i < capacity; i++) {
1140       Object* k = dictionary->KeyAt(i);
1141       if (!dictionary->IsKey(k)) continue;
1142       if (k->FilterKey(filter)) continue;
1143       if (dictionary->IsDeleted(i)) continue;
1144       DCHECK(k->IsNumber());
1145       DCHECK_LE(k->Number(), kMaxUInt32);
1146       uint32_t index = static_cast<uint32_t>(k->Number());
1147       if (index < offset) continue;
1148       PropertyDetails details = dictionary->DetailsAt(i);
1149       if (filter & ONLY_ALL_CAN_READ) {
1150         if (details.kind() != kAccessor) continue;
1151         Object* accessors = dictionary->ValueAt(i);
1152         if (!accessors->IsAccessorInfo()) continue;
1153         if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
1154       }
1155       PropertyAttributes attr = details.attributes();
1156       if ((attr & filter) != 0) continue;
1157       keys->AddKey(index);
1158     }
1159 
1160     keys->SortCurrentElementsList();
1161   }
1162 };
1163 
1164 
1165 // Super class for all fast element arrays.
1166 template<typename FastElementsAccessorSubclass,
1167          typename KindTraits>
1168 class FastElementsAccessor
1169     : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
1170  public:
FastElementsAccessor(const char * name)1171   explicit FastElementsAccessor(const char* name)
1172       : ElementsAccessorBase<FastElementsAccessorSubclass,
1173                              KindTraits>(name) {}
1174 
1175   typedef typename KindTraits::BackingStore BackingStore;
1176 
DeleteAtEnd(Handle<JSObject> obj,Handle<BackingStore> backing_store,uint32_t entry)1177   static void DeleteAtEnd(Handle<JSObject> obj,
1178                           Handle<BackingStore> backing_store, uint32_t entry) {
1179     uint32_t length = static_cast<uint32_t>(backing_store->length());
1180     Heap* heap = obj->GetHeap();
1181     for (; entry > 0; entry--) {
1182       if (!backing_store->is_the_hole(entry - 1)) break;
1183     }
1184     if (entry == 0) {
1185       FixedArray* empty = heap->empty_fixed_array();
1186       if (obj->HasFastArgumentsElements()) {
1187         FixedArray::cast(obj->elements())->set(1, empty);
1188       } else {
1189         obj->set_elements(empty);
1190       }
1191       return;
1192     }
1193 
1194     heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
1195                                                            length - entry);
1196   }
1197 
DeleteCommon(Handle<JSObject> obj,uint32_t entry,Handle<FixedArrayBase> store)1198   static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1199                            Handle<FixedArrayBase> store) {
1200     DCHECK(obj->HasFastSmiOrObjectElements() ||
1201            obj->HasFastDoubleElements() ||
1202            obj->HasFastArgumentsElements());
1203     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
1204     if (!obj->IsJSArray() &&
1205         entry == static_cast<uint32_t>(store->length()) - 1) {
1206       DeleteAtEnd(obj, backing_store, entry);
1207       return;
1208     }
1209 
1210     backing_store->set_the_hole(entry);
1211 
1212     // TODO(verwaest): Move this out of elements.cc.
1213     // If an old space backing store is larger than a certain size and
1214     // has too few used values, normalize it.
1215     // To avoid doing the check on every delete we require at least
1216     // one adjacent hole to the value being deleted.
1217     const int kMinLengthForSparsenessCheck = 64;
1218     if (backing_store->length() < kMinLengthForSparsenessCheck) return;
1219     if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
1220     uint32_t length = 0;
1221     if (obj->IsJSArray()) {
1222       JSArray::cast(*obj)->length()->ToArrayLength(&length);
1223     } else {
1224       length = static_cast<uint32_t>(store->length());
1225     }
1226     if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
1227         (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
1228       if (!obj->IsJSArray()) {
1229         uint32_t i;
1230         for (i = entry + 1; i < length; i++) {
1231           if (!backing_store->is_the_hole(i)) break;
1232         }
1233         if (i == length) {
1234           DeleteAtEnd(obj, backing_store, entry);
1235           return;
1236         }
1237       }
1238       int num_used = 0;
1239       for (int i = 0; i < backing_store->length(); ++i) {
1240         if (!backing_store->is_the_hole(i)) {
1241           ++num_used;
1242           // Bail out if a number dictionary wouldn't be able to save at least
1243           // 75% space.
1244           if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
1245                   SeededNumberDictionary::kEntrySize >
1246               backing_store->length()) {
1247             return;
1248           }
1249         }
1250       }
1251       JSObject::NormalizeElements(obj);
1252     }
1253   }
1254 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)1255   static void ReconfigureImpl(Handle<JSObject> object,
1256                               Handle<FixedArrayBase> store, uint32_t entry,
1257                               Handle<Object> value,
1258                               PropertyAttributes attributes) {
1259     Handle<SeededNumberDictionary> dictionary =
1260         JSObject::NormalizeElements(object);
1261     entry = dictionary->FindEntry(entry);
1262     DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
1263                                                 value, attributes);
1264   }
1265 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)1266   static void AddImpl(Handle<JSObject> object, uint32_t index,
1267                       Handle<Object> value, PropertyAttributes attributes,
1268                       uint32_t new_capacity) {
1269     DCHECK_EQ(NONE, attributes);
1270     ElementsKind from_kind = object->GetElementsKind();
1271     ElementsKind to_kind = FastElementsAccessorSubclass::kind();
1272     if (IsDictionaryElementsKind(from_kind) ||
1273         IsFastDoubleElementsKind(from_kind) !=
1274             IsFastDoubleElementsKind(to_kind) ||
1275         FastElementsAccessorSubclass::GetCapacityImpl(
1276             *object, object->elements()) != new_capacity) {
1277       FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object,
1278                                                                new_capacity);
1279     } else {
1280       if (from_kind != to_kind) {
1281         JSObject::TransitionElementsKind(object, to_kind);
1282       }
1283       if (IsFastSmiOrObjectElementsKind(from_kind)) {
1284         DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
1285         JSObject::EnsureWritableFastElements(object);
1286       }
1287     }
1288     FastElementsAccessorSubclass::SetImpl(object->elements(), index, *value);
1289   }
1290 
DeleteImpl(Handle<JSObject> obj,uint32_t entry)1291   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1292     ElementsKind kind = KindTraits::Kind;
1293     if (IsFastPackedElementsKind(kind)) {
1294       JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
1295     }
1296     if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1297       JSObject::EnsureWritableFastElements(obj);
1298     }
1299     DeleteCommon(obj, entry, handle(obj->elements()));
1300   }
1301 
HasEntryImpl(FixedArrayBase * backing_store,uint32_t entry)1302   static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
1303     return !BackingStore::cast(backing_store)->is_the_hole(entry);
1304   }
1305 
ValidateContents(Handle<JSObject> holder,int length)1306   static void ValidateContents(Handle<JSObject> holder, int length) {
1307 #if DEBUG
1308     Isolate* isolate = holder->GetIsolate();
1309     HandleScope scope(isolate);
1310     Handle<FixedArrayBase> elements(holder->elements(), isolate);
1311     Map* map = elements->map();
1312     DCHECK((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
1313             (map == isolate->heap()->fixed_array_map() ||
1314              map == isolate->heap()->fixed_cow_array_map())) ||
1315            (IsFastDoubleElementsKind(KindTraits::Kind) ==
1316             ((map == isolate->heap()->fixed_array_map() && length == 0) ||
1317              map == isolate->heap()->fixed_double_array_map())));
1318     if (length == 0) return;  // nothing to do!
1319     DisallowHeapAllocation no_gc;
1320     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
1321     if (IsFastSmiElementsKind(KindTraits::Kind)) {
1322       for (int i = 0; i < length; i++) {
1323         DCHECK(BackingStore::get(backing_store, i)->IsSmi() ||
1324                (IsFastHoleyElementsKind(KindTraits::Kind) &&
1325                 backing_store->is_the_hole(i)));
1326       }
1327     }
1328 #endif
1329   }
1330 
PopImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)1331   static Handle<Object> PopImpl(Handle<JSArray> receiver,
1332                                 Handle<FixedArrayBase> backing_store) {
1333     return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
1334                                                        AT_END);
1335   }
1336 
ShiftImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)1337   static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
1338                                   Handle<FixedArrayBase> backing_store) {
1339     return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
1340                                                        AT_START);
1341   }
1342 
PushImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t push_size)1343   static uint32_t PushImpl(Handle<JSArray> receiver,
1344                            Handle<FixedArrayBase> backing_store,
1345                            Arguments* args, uint32_t push_size) {
1346     return FastElementsAccessorSubclass::AddArguments(receiver, backing_store,
1347                                                       args, push_size, AT_END);
1348   }
1349 
UnshiftImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t unshift_size)1350   static uint32_t UnshiftImpl(Handle<JSArray> receiver,
1351                               Handle<FixedArrayBase> backing_store,
1352                               Arguments* args, uint32_t unshift_size) {
1353     return FastElementsAccessorSubclass::AddArguments(
1354         receiver, backing_store, args, unshift_size, AT_START);
1355   }
1356 
MoveElements(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,int dst_index,int src_index,int len,int hole_start,int hole_end)1357   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1358                            Handle<FixedArrayBase> backing_store, int dst_index,
1359                            int src_index, int len, int hole_start,
1360                            int hole_end) {
1361     UNREACHABLE();
1362   }
1363 
SliceImpl(Handle<JSObject> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)1364   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
1365                                    Handle<FixedArrayBase> backing_store,
1366                                    uint32_t start, uint32_t end) {
1367     DCHECK(start < end);
1368     Isolate* isolate = receiver->GetIsolate();
1369     int result_len = end - start;
1370     Handle<JSArray> result_array = isolate->factory()->NewJSArray(
1371         KindTraits::Kind, result_len, result_len);
1372     DisallowHeapAllocation no_gc;
1373     FastElementsAccessorSubclass::CopyElementsImpl(
1374         *backing_store, start, result_array->elements(), KindTraits::Kind, 0,
1375         kPackedSizeNotKnown, result_len);
1376     FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
1377         result_array);
1378     return result_array;
1379   }
1380 
SpliceImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)1381   static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
1382                                     Handle<FixedArrayBase> backing_store,
1383                                     uint32_t start, uint32_t delete_count,
1384                                     Arguments* args, uint32_t add_count) {
1385     Isolate* isolate = receiver->GetIsolate();
1386     Heap* heap = isolate->heap();
1387     uint32_t length = Smi::cast(receiver->length())->value();
1388     uint32_t new_length = length - delete_count + add_count;
1389 
1390     if (new_length == 0) {
1391       receiver->set_elements(heap->empty_fixed_array());
1392       receiver->set_length(Smi::FromInt(0));
1393       return isolate->factory()->NewJSArrayWithElements(
1394           backing_store, KindTraits::Kind, delete_count);
1395     }
1396 
1397     // Construct the result array which holds the deleted elements.
1398     Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
1399         KindTraits::Kind, delete_count, delete_count);
1400     if (delete_count > 0) {
1401       DisallowHeapAllocation no_gc;
1402       FastElementsAccessorSubclass::CopyElementsImpl(
1403           *backing_store, start, deleted_elements->elements(), KindTraits::Kind,
1404           0, kPackedSizeNotKnown, delete_count);
1405     }
1406 
1407     // Delete and move elements to make space for add_count new elements.
1408     if (add_count < delete_count) {
1409       FastElementsAccessorSubclass::SpliceShrinkStep(
1410           isolate, receiver, backing_store, start, delete_count, add_count,
1411           length, new_length);
1412     } else if (add_count > delete_count) {
1413       backing_store = FastElementsAccessorSubclass::SpliceGrowStep(
1414           isolate, receiver, backing_store, start, delete_count, add_count,
1415           length, new_length);
1416     }
1417 
1418     // Copy over the arguments.
1419     FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count,
1420                                                 3, start);
1421 
1422     receiver->set_length(Smi::FromInt(new_length));
1423     FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
1424         deleted_elements);
1425     return deleted_elements;
1426   }
1427 
1428  private:
1429   // SpliceShrinkStep might modify the backing_store.
SpliceShrinkStep(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t delete_count,uint32_t add_count,uint32_t len,uint32_t new_length)1430   static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
1431                                Handle<FixedArrayBase> backing_store,
1432                                uint32_t start, uint32_t delete_count,
1433                                uint32_t add_count, uint32_t len,
1434                                uint32_t new_length) {
1435     const int move_left_count = len - delete_count - start;
1436     const int move_left_dst_index = start + add_count;
1437     FastElementsAccessorSubclass::MoveElements(
1438         isolate, receiver, backing_store, move_left_dst_index,
1439         start + delete_count, move_left_count, new_length, len);
1440   }
1441 
1442   // SpliceGrowStep might modify the backing_store.
SpliceGrowStep(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t delete_count,uint32_t add_count,uint32_t length,uint32_t new_length)1443   static Handle<FixedArrayBase> SpliceGrowStep(
1444       Isolate* isolate, Handle<JSArray> receiver,
1445       Handle<FixedArrayBase> backing_store, uint32_t start,
1446       uint32_t delete_count, uint32_t add_count, uint32_t length,
1447       uint32_t new_length) {
1448     // Check we do not overflow the new_length.
1449     DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
1450     // Check if backing_store is big enough.
1451     if (new_length <= static_cast<uint32_t>(backing_store->length())) {
1452       FastElementsAccessorSubclass::MoveElements(
1453           isolate, receiver, backing_store, start + add_count,
1454           start + delete_count, (length - delete_count - start), 0, 0);
1455       // MoveElements updates the backing_store in-place.
1456       return backing_store;
1457     }
1458     // New backing storage is needed.
1459     int capacity = JSObject::NewElementsCapacity(new_length);
1460     // Partially copy all elements up to start.
1461     Handle<FixedArrayBase> new_elms =
1462         FastElementsAccessorSubclass::ConvertElementsWithCapacity(
1463             receiver, backing_store, KindTraits::Kind, capacity, start);
1464     // Copy the trailing elements after start + delete_count
1465     FastElementsAccessorSubclass::CopyElementsImpl(
1466         *backing_store, start + delete_count, *new_elms, KindTraits::Kind,
1467         start + add_count, kPackedSizeNotKnown,
1468         ElementsAccessor::kCopyToEndAndInitializeToHole);
1469     receiver->set_elements(*new_elms);
1470     return new_elms;
1471   }
1472 
RemoveElement(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Where remove_position)1473   static Handle<Object> RemoveElement(Handle<JSArray> receiver,
1474                                       Handle<FixedArrayBase> backing_store,
1475                                       Where remove_position) {
1476     Isolate* isolate = receiver->GetIsolate();
1477     uint32_t length =
1478         static_cast<uint32_t>(Smi::cast(receiver->length())->value());
1479     DCHECK(length > 0);
1480     int new_length = length - 1;
1481     int remove_index = remove_position == AT_START ? 0 : new_length;
1482     Handle<Object> result =
1483         FastElementsAccessorSubclass::GetImpl(backing_store, remove_index);
1484     if (remove_position == AT_START) {
1485       FastElementsAccessorSubclass::MoveElements(
1486           isolate, receiver, backing_store, 0, 1, new_length, 0, 0);
1487     }
1488     FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length,
1489                                                 backing_store);
1490 
1491     if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
1492       return receiver->GetIsolate()->factory()->undefined_value();
1493     }
1494     return result;
1495   }
1496 
AddArguments(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t add_size,Where remove_position)1497   static uint32_t AddArguments(Handle<JSArray> receiver,
1498                                Handle<FixedArrayBase> backing_store,
1499                                Arguments* args, uint32_t add_size,
1500                                Where remove_position) {
1501     uint32_t length = Smi::cast(receiver->length())->value();
1502     DCHECK(add_size > 0);
1503     uint32_t elms_len = backing_store->length();
1504     // Check we do not overflow the new_length.
1505     DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
1506     uint32_t new_length = length + add_size;
1507 
1508     if (new_length > elms_len) {
1509       // New backing storage is needed.
1510       uint32_t capacity = JSObject::NewElementsCapacity(new_length);
1511       // If we add arguments to the start we have to shift the existing objects.
1512       int copy_dst_index = remove_position == AT_START ? add_size : 0;
1513       // Copy over all objects to a new backing_store.
1514       backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
1515           receiver, backing_store, KindTraits::Kind, capacity, 0,
1516           copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
1517       receiver->set_elements(*backing_store);
1518     } else if (remove_position == AT_START) {
1519       // If the backing store has enough capacity and we add elements to the
1520       // start we have to shift the existing objects.
1521       Isolate* isolate = receiver->GetIsolate();
1522       FastElementsAccessorSubclass::MoveElements(
1523           isolate, receiver, backing_store, add_size, 0, length, 0, 0);
1524     }
1525 
1526     int insertion_index = remove_position == AT_START ? 0 : length;
1527     // Copy the arguments to the start.
1528     FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_size,
1529                                                 1, insertion_index);
1530     // Set the length.
1531     receiver->set_length(Smi::FromInt(new_length));
1532     return new_length;
1533   }
1534 
CopyArguments(Arguments * args,Handle<FixedArrayBase> dst_store,uint32_t copy_size,uint32_t src_index,uint32_t dst_index)1535   static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
1536                             uint32_t copy_size, uint32_t src_index,
1537                             uint32_t dst_index) {
1538     // Add the provided values.
1539     DisallowHeapAllocation no_gc;
1540     FixedArrayBase* raw_backing_store = *dst_store;
1541     WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
1542     for (uint32_t i = 0; i < copy_size; i++) {
1543       Object* argument = (*args)[i + src_index];
1544       FastElementsAccessorSubclass::SetImpl(raw_backing_store, i + dst_index,
1545                                             argument, mode);
1546     }
1547   }
1548 };
1549 
1550 
1551 template<typename FastElementsAccessorSubclass,
1552          typename KindTraits>
1553 class FastSmiOrObjectElementsAccessor
1554     : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
1555  public:
FastSmiOrObjectElementsAccessor(const char * name)1556   explicit FastSmiOrObjectElementsAccessor(const char* name)
1557       : FastElementsAccessor<FastElementsAccessorSubclass,
1558                              KindTraits>(name) {}
1559 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)1560   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1561                              Object* value) {
1562     FixedArray::cast(backing_store)->set(entry, value);
1563   }
1564 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)1565   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1566                              Object* value, WriteBarrierMode mode) {
1567     FixedArray::cast(backing_store)->set(entry, value, mode);
1568   }
1569 
GetRaw(FixedArray * backing_store,uint32_t entry)1570   static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
1571     uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl(
1572         backing_store, entry);
1573     return backing_store->get(index);
1574   }
1575 
MoveElements(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,int dst_index,int src_index,int len,int hole_start,int hole_end)1576   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1577                            Handle<FixedArrayBase> backing_store, int dst_index,
1578                            int src_index, int len, int hole_start,
1579                            int hole_end) {
1580     Heap* heap = isolate->heap();
1581     Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store);
1582     if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1583       // Update all the copies of this backing_store handle.
1584       *dst_elms.location() =
1585           FixedArray::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
1586       receiver->set_elements(*dst_elms);
1587       // Adjust the hole offset as the array has been shrunk.
1588       hole_end -= src_index;
1589       DCHECK_LE(hole_start, backing_store->length());
1590       DCHECK_LE(hole_end, backing_store->length());
1591     } else if (len != 0) {
1592       DisallowHeapAllocation no_gc;
1593       heap->MoveElements(*dst_elms, dst_index, src_index, len);
1594     }
1595     if (hole_start != hole_end) {
1596       dst_elms->FillWithHoles(hole_start, hole_end);
1597     }
1598   }
1599 
1600   // NOTE: this method violates the handlified function signature convention:
1601   // raw pointer parameters in the function that allocates.
1602   // See ElementsAccessor::CopyElements() for details.
1603   // This method could actually allocate if copying from double elements to
1604   // object elements.
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)1605   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1606                                FixedArrayBase* to, ElementsKind from_kind,
1607                                uint32_t to_start, int packed_size,
1608                                int copy_size) {
1609     DisallowHeapAllocation no_gc;
1610     ElementsKind to_kind = KindTraits::Kind;
1611     switch (from_kind) {
1612       case FAST_SMI_ELEMENTS:
1613       case FAST_HOLEY_SMI_ELEMENTS:
1614       case FAST_ELEMENTS:
1615       case FAST_HOLEY_ELEMENTS:
1616         CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
1617                                    to_start, copy_size);
1618         break;
1619       case FAST_DOUBLE_ELEMENTS:
1620       case FAST_HOLEY_DOUBLE_ELEMENTS: {
1621         AllowHeapAllocation allow_allocation;
1622         DCHECK(IsFastObjectElementsKind(to_kind));
1623         CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
1624         break;
1625       }
1626       case DICTIONARY_ELEMENTS:
1627         CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
1628                                        copy_size);
1629         break;
1630       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1631       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
1632         UNREACHABLE();
1633 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
1634       case TYPE##_ELEMENTS:                                                   \
1635         UNREACHABLE();
1636       TYPED_ARRAYS(TYPED_ARRAY_CASE)
1637 #undef TYPED_ARRAY_CASE
1638     }
1639   }
1640 };
1641 
1642 
1643 class FastPackedSmiElementsAccessor
1644     : public FastSmiOrObjectElementsAccessor<
1645         FastPackedSmiElementsAccessor,
1646         ElementsKindTraits<FAST_SMI_ELEMENTS> > {
1647  public:
FastPackedSmiElementsAccessor(const char * name)1648   explicit FastPackedSmiElementsAccessor(const char* name)
1649       : FastSmiOrObjectElementsAccessor<
1650           FastPackedSmiElementsAccessor,
1651           ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
1652 };
1653 
1654 
1655 class FastHoleySmiElementsAccessor
1656     : public FastSmiOrObjectElementsAccessor<
1657         FastHoleySmiElementsAccessor,
1658         ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
1659  public:
FastHoleySmiElementsAccessor(const char * name)1660   explicit FastHoleySmiElementsAccessor(const char* name)
1661       : FastSmiOrObjectElementsAccessor<
1662           FastHoleySmiElementsAccessor,
1663           ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
1664 };
1665 
1666 
1667 class FastPackedObjectElementsAccessor
1668     : public FastSmiOrObjectElementsAccessor<
1669         FastPackedObjectElementsAccessor,
1670         ElementsKindTraits<FAST_ELEMENTS> > {
1671  public:
FastPackedObjectElementsAccessor(const char * name)1672   explicit FastPackedObjectElementsAccessor(const char* name)
1673       : FastSmiOrObjectElementsAccessor<
1674           FastPackedObjectElementsAccessor,
1675           ElementsKindTraits<FAST_ELEMENTS> >(name) {}
1676 };
1677 
1678 
1679 class FastHoleyObjectElementsAccessor
1680     : public FastSmiOrObjectElementsAccessor<
1681         FastHoleyObjectElementsAccessor,
1682         ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
1683  public:
FastHoleyObjectElementsAccessor(const char * name)1684   explicit FastHoleyObjectElementsAccessor(const char* name)
1685       : FastSmiOrObjectElementsAccessor<
1686           FastHoleyObjectElementsAccessor,
1687           ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
1688 };
1689 
1690 
1691 template<typename FastElementsAccessorSubclass,
1692          typename KindTraits>
1693 class FastDoubleElementsAccessor
1694     : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
1695  public:
FastDoubleElementsAccessor(const char * name)1696   explicit FastDoubleElementsAccessor(const char* name)
1697       : FastElementsAccessor<FastElementsAccessorSubclass,
1698                              KindTraits>(name) {}
1699 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)1700   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1701                              Object* value) {
1702     FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
1703   }
1704 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)1705   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1706                              Object* value, WriteBarrierMode mode) {
1707     FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
1708   }
1709 
MoveElements(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,int dst_index,int src_index,int len,int hole_start,int hole_end)1710   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1711                            Handle<FixedArrayBase> backing_store, int dst_index,
1712                            int src_index, int len, int hole_start,
1713                            int hole_end) {
1714     Heap* heap = isolate->heap();
1715     Handle<FixedDoubleArray> dst_elms =
1716         Handle<FixedDoubleArray>::cast(backing_store);
1717     if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1718       // Update all the copies of this backing_store handle.
1719       *dst_elms.location() = FixedDoubleArray::cast(
1720           heap->LeftTrimFixedArray(*dst_elms, src_index));
1721       receiver->set_elements(*dst_elms);
1722       // Adjust the hole offset as the array has been shrunk.
1723       hole_end -= src_index;
1724       DCHECK_LE(hole_start, backing_store->length());
1725       DCHECK_LE(hole_end, backing_store->length());
1726     } else if (len != 0) {
1727       MemMove(dst_elms->data_start() + dst_index,
1728               dst_elms->data_start() + src_index, len * kDoubleSize);
1729     }
1730     if (hole_start != hole_end) {
1731       dst_elms->FillWithHoles(hole_start, hole_end);
1732     }
1733   }
1734 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)1735   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1736                                FixedArrayBase* to, ElementsKind from_kind,
1737                                uint32_t to_start, int packed_size,
1738                                int copy_size) {
1739     DisallowHeapAllocation no_allocation;
1740     switch (from_kind) {
1741       case FAST_SMI_ELEMENTS:
1742         CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
1743                                       packed_size, copy_size);
1744         break;
1745       case FAST_HOLEY_SMI_ELEMENTS:
1746         CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
1747         break;
1748       case FAST_DOUBLE_ELEMENTS:
1749       case FAST_HOLEY_DOUBLE_ELEMENTS:
1750         CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
1751         break;
1752       case FAST_ELEMENTS:
1753       case FAST_HOLEY_ELEMENTS:
1754         CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
1755         break;
1756       case DICTIONARY_ELEMENTS:
1757         CopyDictionaryToDoubleElements(from, from_start, to, to_start,
1758                                        copy_size);
1759         break;
1760       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1761       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
1762         UNREACHABLE();
1763 
1764 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
1765       case TYPE##_ELEMENTS:                                                   \
1766         UNREACHABLE();
1767       TYPED_ARRAYS(TYPED_ARRAY_CASE)
1768 #undef TYPED_ARRAY_CASE
1769     }
1770   }
1771 };
1772 
1773 
1774 class FastPackedDoubleElementsAccessor
1775     : public FastDoubleElementsAccessor<
1776         FastPackedDoubleElementsAccessor,
1777         ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
1778  public:
FastPackedDoubleElementsAccessor(const char * name)1779   explicit FastPackedDoubleElementsAccessor(const char* name)
1780       : FastDoubleElementsAccessor<
1781           FastPackedDoubleElementsAccessor,
1782           ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
1783 };
1784 
1785 
1786 class FastHoleyDoubleElementsAccessor
1787     : public FastDoubleElementsAccessor<
1788         FastHoleyDoubleElementsAccessor,
1789         ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
1790  public:
FastHoleyDoubleElementsAccessor(const char * name)1791   explicit FastHoleyDoubleElementsAccessor(const char* name)
1792       : FastDoubleElementsAccessor<
1793           FastHoleyDoubleElementsAccessor,
1794           ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
1795 };
1796 
1797 
1798 // Super class for all external element arrays.
1799 template<ElementsKind Kind>
1800 class TypedElementsAccessor
1801     : public ElementsAccessorBase<TypedElementsAccessor<Kind>,
1802                                   ElementsKindTraits<Kind> > {
1803  public:
TypedElementsAccessor(const char * name)1804   explicit TypedElementsAccessor(const char* name)
1805       : ElementsAccessorBase<AccessorClass,
1806                              ElementsKindTraits<Kind> >(name) {}
1807 
1808   typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
1809   typedef TypedElementsAccessor<Kind> AccessorClass;
1810 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)1811   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1812                              Object* value) {
1813     BackingStore::cast(backing_store)->SetValue(entry, value);
1814   }
1815 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)1816   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1817                              Object* value, WriteBarrierMode mode) {
1818     BackingStore::cast(backing_store)->SetValue(entry, value);
1819   }
1820 
GetImpl(Handle<FixedArrayBase> backing_store,uint32_t entry)1821   static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
1822                                 uint32_t entry) {
1823     uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
1824     return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
1825   }
1826 
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)1827   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1828                                         uint32_t entry) {
1829     return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
1830   }
1831 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)1832   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1833                             uint32_t length,
1834                             Handle<FixedArrayBase> backing_store) {
1835     // External arrays do not support changing their length.
1836     UNREACHABLE();
1837   }
1838 
DeleteImpl(Handle<JSObject> obj,uint32_t entry)1839   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1840     UNREACHABLE();
1841   }
1842 
GetIndexForEntryImpl(FixedArrayBase * backing_store,uint32_t entry)1843   static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1844                                        uint32_t entry) {
1845     return entry;
1846   }
1847 
GetEntryForIndexImpl(JSObject * holder,FixedArrayBase * backing_store,uint32_t index,PropertyFilter filter)1848   static uint32_t GetEntryForIndexImpl(JSObject* holder,
1849                                        FixedArrayBase* backing_store,
1850                                        uint32_t index, PropertyFilter filter) {
1851     return index < AccessorClass::GetCapacityImpl(holder, backing_store)
1852                ? index
1853                : kMaxUInt32;
1854   }
1855 
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)1856   static uint32_t GetCapacityImpl(JSObject* holder,
1857                                   FixedArrayBase* backing_store) {
1858     JSArrayBufferView* view = JSArrayBufferView::cast(holder);
1859     if (view->WasNeutered()) return 0;
1860     return backing_store->length();
1861   }
1862 };
1863 
1864 
1865 
1866 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size)       \
1867   typedef TypedElementsAccessor<TYPE##_ELEMENTS >                    \
1868       Fixed##Type##ElementsAccessor;
1869 
1870 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
1871 #undef FIXED_ELEMENTS_ACCESSOR
1872 
1873 
1874 template <typename SloppyArgumentsElementsAccessorSubclass,
1875           typename ArgumentsAccessor, typename KindTraits>
1876 class SloppyArgumentsElementsAccessor
1877     : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
1878                                   KindTraits> {
1879  public:
SloppyArgumentsElementsAccessor(const char * name)1880   explicit SloppyArgumentsElementsAccessor(const char* name)
1881       : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
1882                              KindTraits>(name) {
1883     USE(KindTraits::Kind);
1884   }
1885 
GetImpl(Handle<FixedArrayBase> parameters,uint32_t entry)1886   static Handle<Object> GetImpl(Handle<FixedArrayBase> parameters,
1887                                 uint32_t entry) {
1888     Isolate* isolate = parameters->GetIsolate();
1889     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
1890     uint32_t length = parameter_map->length() - 2;
1891     if (entry < length) {
1892       DisallowHeapAllocation no_gc;
1893       Object* probe = parameter_map->get(entry + 2);
1894       Context* context = Context::cast(parameter_map->get(0));
1895       int context_entry = Smi::cast(probe)->value();
1896       DCHECK(!context->get(context_entry)->IsTheHole());
1897       return handle(context->get(context_entry), isolate);
1898     } else {
1899       // Object is not mapped, defer to the arguments.
1900       Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)),
1901                                    isolate);
1902       Handle<Object> result =
1903           ArgumentsAccessor::GetImpl(arguments, entry - length);
1904       // Elements of the arguments object in slow mode might be slow aliases.
1905       if (result->IsAliasedArgumentsEntry()) {
1906         DisallowHeapAllocation no_gc;
1907         AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
1908         Context* context = Context::cast(parameter_map->get(0));
1909         int context_entry = alias->aliased_context_slot();
1910         DCHECK(!context->get(context_entry)->IsTheHole());
1911         return handle(context->get(context_entry), isolate);
1912       }
1913       return result;
1914     }
1915   }
1916 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)1917   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
1918                                          uint32_t capacity) {
1919     UNREACHABLE();
1920   }
1921 
SetImpl(FixedArrayBase * store,uint32_t entry,Object * value)1922   static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
1923                              Object* value) {
1924     FixedArray* parameter_map = FixedArray::cast(store);
1925     uint32_t length = parameter_map->length() - 2;
1926     if (entry < length) {
1927       Object* probe = parameter_map->get(entry + 2);
1928       Context* context = Context::cast(parameter_map->get(0));
1929       int context_entry = Smi::cast(probe)->value();
1930       DCHECK(!context->get(context_entry)->IsTheHole());
1931       context->set(context_entry, value);
1932     } else {
1933       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1934       Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
1935       if (current->IsAliasedArgumentsEntry()) {
1936         AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
1937         Context* context = Context::cast(parameter_map->get(0));
1938         int context_entry = alias->aliased_context_slot();
1939         DCHECK(!context->get(context_entry)->IsTheHole());
1940         context->set(context_entry, value);
1941       } else {
1942         ArgumentsAccessor::SetImpl(arguments, entry - length, value);
1943       }
1944     }
1945   }
1946 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> parameter_map)1947   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1948                             uint32_t length,
1949                             Handle<FixedArrayBase> parameter_map) {
1950     // Sloppy arguments objects are not arrays.
1951     UNREACHABLE();
1952   }
1953 
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)1954   static uint32_t GetCapacityImpl(JSObject* holder,
1955                                   FixedArrayBase* backing_store) {
1956     FixedArray* parameter_map = FixedArray::cast(backing_store);
1957     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1958     return parameter_map->length() - 2 +
1959            ArgumentsAccessor::GetCapacityImpl(holder, arguments);
1960   }
1961 
HasEntryImpl(FixedArrayBase * parameters,uint32_t entry)1962   static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
1963     FixedArray* parameter_map = FixedArray::cast(parameters);
1964     uint32_t length = parameter_map->length() - 2;
1965     if (entry < length) {
1966       return !GetParameterMapArg(parameter_map, entry)->IsTheHole();
1967     }
1968 
1969     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1970     return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
1971   }
1972 
GetIndexForEntryImpl(FixedArrayBase * parameters,uint32_t entry)1973   static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
1974                                        uint32_t entry) {
1975     FixedArray* parameter_map = FixedArray::cast(parameters);
1976     uint32_t length = parameter_map->length() - 2;
1977     if (entry < length) return entry;
1978 
1979     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1980     return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
1981   }
1982 
GetEntryForIndexImpl(JSObject * holder,FixedArrayBase * parameters,uint32_t index,PropertyFilter filter)1983   static uint32_t GetEntryForIndexImpl(JSObject* holder,
1984                                        FixedArrayBase* parameters,
1985                                        uint32_t index, PropertyFilter filter) {
1986     FixedArray* parameter_map = FixedArray::cast(parameters);
1987     Object* probe = GetParameterMapArg(parameter_map, index);
1988     if (!probe->IsTheHole()) return index;
1989 
1990     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1991     uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
1992                                                              index, filter);
1993     if (entry == kMaxUInt32) return entry;
1994     return (parameter_map->length() - 2) + entry;
1995   }
1996 
GetDetailsImpl(FixedArrayBase * parameters,uint32_t entry)1997   static PropertyDetails GetDetailsImpl(FixedArrayBase* parameters,
1998                                         uint32_t entry) {
1999     FixedArray* parameter_map = FixedArray::cast(parameters);
2000     uint32_t length = parameter_map->length() - 2;
2001     if (entry < length) {
2002       return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
2003     }
2004     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2005     return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
2006   }
2007 
GetParameterMapArg(FixedArray * parameter_map,uint32_t index)2008   static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
2009     uint32_t length = parameter_map->length() - 2;
2010     return index < length
2011                ? parameter_map->get(index + 2)
2012                : Object::cast(parameter_map->GetHeap()->the_hole_value());
2013   }
2014 
DeleteImpl(Handle<JSObject> obj,uint32_t entry)2015   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2016     FixedArray* parameter_map = FixedArray::cast(obj->elements());
2017     uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
2018     if (entry < length) {
2019       // TODO(kmillikin): We could check if this was the last aliased
2020       // parameter, and revert to normal elements in that case.  That
2021       // would enable GC of the context.
2022       parameter_map->set_the_hole(entry + 2);
2023     } else {
2024       SloppyArgumentsElementsAccessorSubclass::DeleteFromArguments(
2025           obj, entry - length);
2026     }
2027   }
2028 };
2029 
2030 
2031 class SlowSloppyArgumentsElementsAccessor
2032     : public SloppyArgumentsElementsAccessor<
2033           SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2034           ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
2035  public:
SlowSloppyArgumentsElementsAccessor(const char * name)2036   explicit SlowSloppyArgumentsElementsAccessor(const char* name)
2037       : SloppyArgumentsElementsAccessor<
2038             SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2039             ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2040 
DeleteFromArguments(Handle<JSObject> obj,uint32_t entry)2041   static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2042     Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
2043     Handle<SeededNumberDictionary> dict(
2044         SeededNumberDictionary::cast(parameter_map->get(1)));
2045     // TODO(verwaest): Remove reliance on index in Shrink.
2046     uint32_t index = GetIndexForEntryImpl(*dict, entry);
2047     Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
2048     USE(result);
2049     DCHECK(result->IsTrue());
2050     Handle<FixedArray> new_elements =
2051         SeededNumberDictionary::Shrink(dict, index);
2052     parameter_map->set(1, *new_elements);
2053   }
2054 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)2055   static void AddImpl(Handle<JSObject> object, uint32_t index,
2056                       Handle<Object> value, PropertyAttributes attributes,
2057                       uint32_t new_capacity) {
2058     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2059     Handle<FixedArrayBase> old_elements(
2060         FixedArrayBase::cast(parameter_map->get(1)));
2061     Handle<SeededNumberDictionary> dictionary =
2062         old_elements->IsSeededNumberDictionary()
2063             ? Handle<SeededNumberDictionary>::cast(old_elements)
2064             : JSObject::NormalizeElements(object);
2065     PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2066     Handle<SeededNumberDictionary> new_dictionary =
2067         SeededNumberDictionary::AddNumberEntry(
2068             dictionary, index, value, details,
2069             object->map()->is_prototype_map());
2070     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
2071     if (*dictionary != *new_dictionary) {
2072       FixedArray::cast(object->elements())->set(1, *new_dictionary);
2073     }
2074   }
2075 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)2076   static void ReconfigureImpl(Handle<JSObject> object,
2077                               Handle<FixedArrayBase> store, uint32_t entry,
2078                               Handle<Object> value,
2079                               PropertyAttributes attributes) {
2080     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
2081     uint32_t length = parameter_map->length() - 2;
2082     if (entry < length) {
2083       Object* probe = parameter_map->get(entry + 2);
2084       DCHECK(!probe->IsTheHole());
2085       Context* context = Context::cast(parameter_map->get(0));
2086       int context_entry = Smi::cast(probe)->value();
2087       DCHECK(!context->get(context_entry)->IsTheHole());
2088       context->set(context_entry, *value);
2089 
2090       // Redefining attributes of an aliased element destroys fast aliasing.
2091       parameter_map->set_the_hole(entry + 2);
2092       // For elements that are still writable we re-establish slow aliasing.
2093       if ((attributes & READ_ONLY) == 0) {
2094         Isolate* isolate = store->GetIsolate();
2095         value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
2096       }
2097 
2098       PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2099       Handle<SeededNumberDictionary> arguments(
2100           SeededNumberDictionary::cast(parameter_map->get(1)));
2101       arguments = SeededNumberDictionary::AddNumberEntry(
2102           arguments, entry, value, details, object->map()->is_prototype_map());
2103       // If the attributes were NONE, we would have called set rather than
2104       // reconfigure.
2105       DCHECK_NE(NONE, attributes);
2106       object->RequireSlowElements(*arguments);
2107       parameter_map->set(1, *arguments);
2108     } else {
2109       Handle<FixedArrayBase> arguments(
2110           FixedArrayBase::cast(parameter_map->get(1)));
2111       DictionaryElementsAccessor::ReconfigureImpl(
2112           object, arguments, entry - length, value, attributes);
2113     }
2114   }
2115 };
2116 
2117 
2118 class FastSloppyArgumentsElementsAccessor
2119     : public SloppyArgumentsElementsAccessor<
2120           FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
2121           ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
2122  public:
FastSloppyArgumentsElementsAccessor(const char * name)2123   explicit FastSloppyArgumentsElementsAccessor(const char* name)
2124       : SloppyArgumentsElementsAccessor<
2125             FastSloppyArgumentsElementsAccessor,
2126             FastHoleyObjectElementsAccessor,
2127             ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2128 
DeleteFromArguments(Handle<JSObject> obj,uint32_t entry)2129   static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2130     FixedArray* parameter_map = FixedArray::cast(obj->elements());
2131     Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
2132     FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
2133   }
2134 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)2135   static void AddImpl(Handle<JSObject> object, uint32_t index,
2136                       Handle<Object> value, PropertyAttributes attributes,
2137                       uint32_t new_capacity) {
2138     DCHECK_EQ(NONE, attributes);
2139     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2140     Handle<FixedArrayBase> old_elements(
2141         FixedArrayBase::cast(parameter_map->get(1)));
2142     if (old_elements->IsSeededNumberDictionary() ||
2143         static_cast<uint32_t>(old_elements->length()) < new_capacity) {
2144       GrowCapacityAndConvertImpl(object, new_capacity);
2145     }
2146     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2147     // For fast holey objects, the entry equals the index. The code above made
2148     // sure that there's enough space to store the value. We cannot convert
2149     // index to entry explicitly since the slot still contains the hole, so the
2150     // current EntryForIndex would indicate that it is "absent" by returning
2151     // kMaxUInt32.
2152     FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
2153   }
2154 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)2155   static void ReconfigureImpl(Handle<JSObject> object,
2156                               Handle<FixedArrayBase> store, uint32_t entry,
2157                               Handle<Object> value,
2158                               PropertyAttributes attributes) {
2159     Handle<SeededNumberDictionary> dictionary =
2160         JSObject::NormalizeElements(object);
2161     FixedArray::cast(*store)->set(1, *dictionary);
2162     uint32_t length = static_cast<uint32_t>(store->length()) - 2;
2163     if (entry >= length) {
2164       entry = dictionary->FindEntry(entry - length) + length;
2165     }
2166     SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
2167                                                          value, attributes);
2168   }
2169 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)2170   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2171                                FixedArrayBase* to, ElementsKind from_kind,
2172                                uint32_t to_start, int packed_size,
2173                                int copy_size) {
2174     DCHECK(!to->IsDictionary());
2175     if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
2176       CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
2177                                      to_start, copy_size);
2178     } else {
2179       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
2180       CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
2181                                  FAST_HOLEY_ELEMENTS, to_start, copy_size);
2182     }
2183   }
2184 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)2185   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2186                                          uint32_t capacity) {
2187     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2188     Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
2189     ElementsKind from_kind = object->GetElementsKind();
2190     // This method should only be called if there's a reason to update the
2191     // elements.
2192     DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
2193            static_cast<uint32_t>(old_elements->length()) < capacity);
2194     Handle<FixedArrayBase> elements =
2195         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
2196     Handle<Map> new_map = JSObject::GetElementsTransitionMap(
2197         object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
2198     JSObject::MigrateToMap(object, new_map);
2199     parameter_map->set(1, *elements);
2200     JSObject::ValidateElements(object);
2201   }
2202 };
2203 
2204 
2205 }  // namespace
2206 
2207 
CheckArrayAbuse(Handle<JSObject> obj,const char * op,uint32_t index,bool allow_appending)2208 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
2209                      bool allow_appending) {
2210   DisallowHeapAllocation no_allocation;
2211   Object* raw_length = NULL;
2212   const char* elements_type = "array";
2213   if (obj->IsJSArray()) {
2214     JSArray* array = JSArray::cast(*obj);
2215     raw_length = array->length();
2216   } else {
2217     raw_length = Smi::FromInt(obj->elements()->length());
2218     elements_type = "object";
2219   }
2220 
2221   if (raw_length->IsNumber()) {
2222     double n = raw_length->Number();
2223     if (FastI2D(FastD2UI(n)) == n) {
2224       int32_t int32_length = DoubleToInt32(n);
2225       uint32_t compare_length = static_cast<uint32_t>(int32_length);
2226       if (allow_appending) compare_length++;
2227       if (index >= compare_length) {
2228         PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
2229                elements_type, op, elements_type, static_cast<int>(int32_length),
2230                static_cast<int>(index));
2231         TraceTopFrame(obj->GetIsolate());
2232         PrintF("]\n");
2233       }
2234     } else {
2235       PrintF("[%s elements length not integer value in ", elements_type);
2236       TraceTopFrame(obj->GetIsolate());
2237       PrintF("]\n");
2238     }
2239   } else {
2240     PrintF("[%s elements length not a number in ", elements_type);
2241     TraceTopFrame(obj->GetIsolate());
2242     PrintF("]\n");
2243   }
2244 }
2245 
2246 
ArrayConstructInitializeElements(Handle<JSArray> array,Arguments * args)2247 MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
2248                                                      Arguments* args) {
2249   if (args->length() == 0) {
2250     // Optimize the case where there are no parameters passed.
2251     JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2252     return array;
2253 
2254   } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
2255     uint32_t length;
2256     if (!args->at<Object>(0)->ToArrayLength(&length)) {
2257       return ThrowArrayLengthRangeError(array->GetIsolate());
2258     }
2259 
2260     // Optimize the case where there is one argument and the argument is a small
2261     // smi.
2262     if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
2263       ElementsKind elements_kind = array->GetElementsKind();
2264       JSArray::Initialize(array, length, length);
2265 
2266       if (!IsFastHoleyElementsKind(elements_kind)) {
2267         elements_kind = GetHoleyElementsKind(elements_kind);
2268         JSObject::TransitionElementsKind(array, elements_kind);
2269       }
2270     } else if (length == 0) {
2271       JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2272     } else {
2273       // Take the argument as the length.
2274       JSArray::Initialize(array, 0);
2275       JSArray::SetLength(array, length);
2276     }
2277     return array;
2278   }
2279 
2280   Factory* factory = array->GetIsolate()->factory();
2281 
2282   // Set length and elements on the array.
2283   int number_of_elements = args->length();
2284   JSObject::EnsureCanContainElements(
2285       array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
2286 
2287   // Allocate an appropriately typed elements array.
2288   ElementsKind elements_kind = array->GetElementsKind();
2289   Handle<FixedArrayBase> elms;
2290   if (IsFastDoubleElementsKind(elements_kind)) {
2291     elms = Handle<FixedArrayBase>::cast(
2292         factory->NewFixedDoubleArray(number_of_elements));
2293   } else {
2294     elms = Handle<FixedArrayBase>::cast(
2295         factory->NewFixedArrayWithHoles(number_of_elements));
2296   }
2297 
2298   // Fill in the content
2299   switch (array->GetElementsKind()) {
2300     case FAST_HOLEY_SMI_ELEMENTS:
2301     case FAST_SMI_ELEMENTS: {
2302       Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
2303       for (int entry = 0; entry < number_of_elements; entry++) {
2304         smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
2305       }
2306       break;
2307     }
2308     case FAST_HOLEY_ELEMENTS:
2309     case FAST_ELEMENTS: {
2310       DisallowHeapAllocation no_gc;
2311       WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
2312       Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
2313       for (int entry = 0; entry < number_of_elements; entry++) {
2314         object_elms->set(entry, (*args)[entry], mode);
2315       }
2316       break;
2317     }
2318     case FAST_HOLEY_DOUBLE_ELEMENTS:
2319     case FAST_DOUBLE_ELEMENTS: {
2320       Handle<FixedDoubleArray> double_elms =
2321           Handle<FixedDoubleArray>::cast(elms);
2322       for (int entry = 0; entry < number_of_elements; entry++) {
2323         double_elms->set(entry, (*args)[entry]->Number());
2324       }
2325       break;
2326     }
2327     default:
2328       UNREACHABLE();
2329       break;
2330   }
2331 
2332   array->set_elements(*elms);
2333   array->set_length(Smi::FromInt(number_of_elements));
2334   return array;
2335 }
2336 
2337 
InitializeOncePerProcess()2338 void ElementsAccessor::InitializeOncePerProcess() {
2339   static ElementsAccessor* accessor_array[] = {
2340 #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
2341       ELEMENTS_LIST(ACCESSOR_ARRAY)
2342 #undef ACCESSOR_ARRAY
2343   };
2344 
2345   STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
2346                 kElementsKindCount);
2347 
2348   elements_accessors_ = accessor_array;
2349 }
2350 
2351 
TearDown()2352 void ElementsAccessor::TearDown() {
2353   if (elements_accessors_ == NULL) return;
2354 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
2355   ELEMENTS_LIST(ACCESSOR_DELETE)
2356 #undef ACCESSOR_DELETE
2357   elements_accessors_ = NULL;
2358 }
2359 
2360 
Concat(Isolate * isolate,Arguments * args,uint32_t concat_size)2361 Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
2362                                          uint32_t concat_size) {
2363   int result_len = 0;
2364   ElementsKind elements_kind = GetInitialFastElementsKind();
2365   bool has_double = false;
2366   {
2367     DisallowHeapAllocation no_gc;
2368     // Iterate through all the arguments performing checks
2369     // and calculating total length.
2370     bool is_holey = false;
2371     for (uint32_t i = 0; i < concat_size; i++) {
2372       Object* arg = (*args)[i];
2373       int len = Smi::cast(JSArray::cast(arg)->length())->value();
2374 
2375       // We shouldn't overflow when adding another len.
2376       const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
2377       STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
2378       USE(kHalfOfMaxInt);
2379       result_len += len;
2380       DCHECK(0 <= result_len);
2381       DCHECK(result_len <= FixedDoubleArray::kMaxLength);
2382 
2383       ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
2384       has_double = has_double || IsFastDoubleElementsKind(arg_kind);
2385       is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
2386       elements_kind = GetMoreGeneralElementsKind(elements_kind, arg_kind);
2387     }
2388     if (is_holey) {
2389       elements_kind = GetHoleyElementsKind(elements_kind);
2390     }
2391   }
2392 
2393   // If a double array is concatted into a fast elements array, the fast
2394   // elements array needs to be initialized to contain proper holes, since
2395   // boxing doubles may cause incremental marking.
2396   ArrayStorageAllocationMode mode =
2397       has_double && IsFastObjectElementsKind(elements_kind)
2398           ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
2399           : DONT_INITIALIZE_ARRAY_ELEMENTS;
2400   Handle<JSArray> result_array = isolate->factory()->NewJSArray(
2401       elements_kind, result_len, result_len, Strength::WEAK, mode);
2402   if (result_len == 0) return result_array;
2403   int j = 0;
2404   Handle<FixedArrayBase> storage(result_array->elements(), isolate);
2405   ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
2406   for (uint32_t i = 0; i < concat_size; i++) {
2407     // It is crucial to keep |array| in a raw pointer form to avoid
2408     // performance degradation.
2409     JSArray* array = JSArray::cast((*args)[i]);
2410     int len = Smi::cast(array->length())->value();
2411     if (len > 0) {
2412       ElementsKind from_kind = array->GetElementsKind();
2413       accessor->CopyElements(array, 0, from_kind, storage, j, len);
2414       j += len;
2415     }
2416   }
2417 
2418   DCHECK(j == result_len);
2419   return result_array;
2420 }
2421 
2422 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
2423 }  // namespace internal
2424 }  // namespace v8
2425