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