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 
IncludesValueSlowPath(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)471 static Maybe<bool> IncludesValueSlowPath(Isolate* isolate,
472                                          Handle<JSObject> receiver,
473                                          Handle<Object> value,
474                                          uint32_t start_from, uint32_t length) {
475   bool search_for_hole = value->IsUndefined(isolate);
476   for (uint32_t k = start_from; k < length; ++k) {
477     LookupIterator it(isolate, receiver, k);
478     if (!it.IsFound()) {
479       if (search_for_hole) return Just(true);
480       continue;
481     }
482     Handle<Object> element_k;
483     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
484                                      Object::GetProperty(&it), Nothing<bool>());
485 
486     if (value->SameValueZero(*element_k)) return Just(true);
487   }
488 
489   return Just(false);
490 }
491 
IndexOfValueSlowPath(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)492 static Maybe<int64_t> IndexOfValueSlowPath(Isolate* isolate,
493                                            Handle<JSObject> receiver,
494                                            Handle<Object> value,
495                                            uint32_t start_from,
496                                            uint32_t length) {
497   for (uint32_t k = start_from; k < length; ++k) {
498     LookupIterator it(isolate, receiver, k);
499     if (!it.IsFound()) {
500       continue;
501     }
502     Handle<Object> element_k;
503     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
504         isolate, element_k, Object::GetProperty(&it), Nothing<int64_t>());
505 
506     if (value->StrictEquals(*element_k)) return Just<int64_t>(k);
507   }
508 
509   return Just<int64_t>(-1);
510 }
511 
512 // Base class for element handler implementations. Contains the
513 // the common logic for objects with different ElementsKinds.
514 // Subclasses must specialize method for which the element
515 // implementation differs from the base class implementation.
516 //
517 // This class is intended to be used in the following way:
518 //
519 //   class SomeElementsAccessor :
520 //       public ElementsAccessorBase<SomeElementsAccessor,
521 //                                   BackingStoreClass> {
522 //     ...
523 //   }
524 //
525 // This is an example of the Curiously Recurring Template Pattern (see
526 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).  We use
527 // CRTP to guarantee aggressive compile time optimizations (i.e.  inlining and
528 // specialization of SomeElementsAccessor methods).
529 template <typename Subclass, typename ElementsTraitsParam>
530 class ElementsAccessorBase : public ElementsAccessor {
531  public:
ElementsAccessorBase(const char * name)532   explicit ElementsAccessorBase(const char* name)
533       : ElementsAccessor(name) { }
534 
535   typedef ElementsTraitsParam ElementsTraits;
536   typedef typename ElementsTraitsParam::BackingStore BackingStore;
537 
kind()538   static ElementsKind kind() { return ElementsTraits::Kind; }
539 
ValidateContents(Handle<JSObject> holder,int length)540   static void ValidateContents(Handle<JSObject> holder, int length) {
541   }
542 
ValidateImpl(Handle<JSObject> holder)543   static void ValidateImpl(Handle<JSObject> holder) {
544     Handle<FixedArrayBase> fixed_array_base(holder->elements());
545     if (!fixed_array_base->IsHeapObject()) return;
546     // Arrays that have been shifted in place can't be verified.
547     if (fixed_array_base->IsFiller()) return;
548     int length = 0;
549     if (holder->IsJSArray()) {
550       Object* length_obj = Handle<JSArray>::cast(holder)->length();
551       if (length_obj->IsSmi()) {
552         length = Smi::cast(length_obj)->value();
553       }
554     } else {
555       length = fixed_array_base->length();
556     }
557     Subclass::ValidateContents(holder, length);
558   }
559 
Validate(Handle<JSObject> holder)560   void Validate(Handle<JSObject> holder) final {
561     DisallowHeapAllocation no_gc;
562     Subclass::ValidateImpl(holder);
563   }
564 
IsPackedImpl(Handle<JSObject> holder,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)565   static bool IsPackedImpl(Handle<JSObject> holder,
566                            Handle<FixedArrayBase> backing_store, uint32_t start,
567                            uint32_t end) {
568     if (IsFastPackedElementsKind(kind())) return true;
569     Isolate* isolate = backing_store->GetIsolate();
570     for (uint32_t i = start; i < end; i++) {
571       if (!Subclass::HasElementImpl(isolate, holder, i, backing_store,
572                                     ALL_PROPERTIES)) {
573         return false;
574       }
575     }
576     return true;
577   }
578 
TryTransitionResultArrayToPacked(Handle<JSArray> array)579   static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
580     if (!IsHoleyElementsKind(kind())) return;
581     int length = Smi::cast(array->length())->value();
582     Handle<FixedArrayBase> backing_store(array->elements());
583     if (!Subclass::IsPackedImpl(array, backing_store, 0, length)) {
584       return;
585     }
586     ElementsKind packed_kind = GetPackedElementsKind(kind());
587     Handle<Map> new_map =
588         JSObject::GetElementsTransitionMap(array, packed_kind);
589     JSObject::MigrateToMap(array, new_map);
590     if (FLAG_trace_elements_transitions) {
591       JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
592                                         packed_kind, backing_store);
593     }
594   }
595 
HasElement(Handle<JSObject> holder,uint32_t index,Handle<FixedArrayBase> backing_store,PropertyFilter filter)596   bool HasElement(Handle<JSObject> holder, uint32_t index,
597                   Handle<FixedArrayBase> backing_store,
598                   PropertyFilter filter) final {
599     return Subclass::HasElementImpl(holder->GetIsolate(), holder, index,
600                                     backing_store, filter);
601   }
602 
HasElementImpl(Isolate * isolate,Handle<JSObject> holder,uint32_t index,Handle<FixedArrayBase> backing_store,PropertyFilter filter)603   static bool HasElementImpl(Isolate* isolate, Handle<JSObject> holder,
604                              uint32_t index,
605                              Handle<FixedArrayBase> backing_store,
606                              PropertyFilter filter) {
607     return Subclass::GetEntryForIndexImpl(isolate, *holder, *backing_store,
608                                           index, filter) != kMaxUInt32;
609   }
610 
HasAccessors(JSObject * holder)611   bool HasAccessors(JSObject* holder) final {
612     return Subclass::HasAccessorsImpl(holder, holder->elements());
613   }
614 
HasAccessorsImpl(JSObject * holder,FixedArrayBase * backing_store)615   static bool HasAccessorsImpl(JSObject* holder,
616                                FixedArrayBase* backing_store) {
617     return false;
618   }
619 
Get(Handle<JSObject> holder,uint32_t entry)620   Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final {
621     return Subclass::GetImpl(holder, entry);
622   }
623 
GetImpl(Handle<JSObject> holder,uint32_t entry)624   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
625     return Subclass::GetImpl(holder->elements(), entry);
626   }
627 
GetImpl(FixedArrayBase * backing_store,uint32_t entry)628   static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
629     Isolate* isolate = backing_store->GetIsolate();
630     uint32_t index = GetIndexForEntryImpl(backing_store, entry);
631     return handle(BackingStore::cast(backing_store)->get(index), isolate);
632   }
633 
Set(Handle<JSObject> holder,uint32_t entry,Object * value)634   void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final {
635     Subclass::SetImpl(holder, entry, value);
636   }
637 
Reconfigure(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)638   void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
639                    uint32_t entry, Handle<Object> value,
640                    PropertyAttributes attributes) final {
641     Subclass::ReconfigureImpl(object, store, entry, value, attributes);
642   }
643 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)644   static void ReconfigureImpl(Handle<JSObject> object,
645                               Handle<FixedArrayBase> store, uint32_t entry,
646                               Handle<Object> value,
647                               PropertyAttributes attributes) {
648     UNREACHABLE();
649   }
650 
Add(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)651   void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
652            PropertyAttributes attributes, uint32_t new_capacity) final {
653     Subclass::AddImpl(object, index, value, attributes, new_capacity);
654   }
655 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)656   static void AddImpl(Handle<JSObject> object, uint32_t index,
657                       Handle<Object> value, PropertyAttributes attributes,
658                       uint32_t new_capacity) {
659     UNREACHABLE();
660   }
661 
Push(Handle<JSArray> receiver,Arguments * args,uint32_t push_size)662   uint32_t Push(Handle<JSArray> receiver, Arguments* args,
663                 uint32_t push_size) final {
664     return Subclass::PushImpl(receiver, args, push_size);
665   }
666 
PushImpl(Handle<JSArray> receiver,Arguments * args,uint32_t push_sized)667   static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args,
668                            uint32_t push_sized) {
669     UNREACHABLE();
670     return 0;
671   }
672 
Unshift(Handle<JSArray> receiver,Arguments * args,uint32_t unshift_size)673   uint32_t Unshift(Handle<JSArray> receiver, Arguments* args,
674                    uint32_t unshift_size) final {
675     return Subclass::UnshiftImpl(receiver, args, unshift_size);
676   }
677 
UnshiftImpl(Handle<JSArray> receiver,Arguments * args,uint32_t unshift_size)678   static uint32_t UnshiftImpl(Handle<JSArray> receiver, Arguments* args,
679                               uint32_t unshift_size) {
680     UNREACHABLE();
681     return 0;
682   }
683 
Slice(Handle<JSObject> receiver,uint32_t start,uint32_t end)684   Handle<JSArray> Slice(Handle<JSObject> receiver, uint32_t start,
685                         uint32_t end) final {
686     return Subclass::SliceImpl(receiver, start, end);
687   }
688 
SliceImpl(Handle<JSObject> receiver,uint32_t start,uint32_t end)689   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
690                                    uint32_t start, uint32_t end) {
691     UNREACHABLE();
692     return Handle<JSArray>();
693   }
694 
Splice(Handle<JSArray> receiver,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)695   Handle<JSArray> Splice(Handle<JSArray> receiver, uint32_t start,
696                          uint32_t delete_count, Arguments* args,
697                          uint32_t add_count) final {
698     return Subclass::SpliceImpl(receiver, start, delete_count, args, add_count);
699   }
700 
SpliceImpl(Handle<JSArray> receiver,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)701   static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
702                                     uint32_t start, uint32_t delete_count,
703                                     Arguments* args, uint32_t add_count) {
704     UNREACHABLE();
705     return Handle<JSArray>();
706   }
707 
Pop(Handle<JSArray> receiver)708   Handle<Object> Pop(Handle<JSArray> receiver) final {
709     return Subclass::PopImpl(receiver);
710   }
711 
PopImpl(Handle<JSArray> receiver)712   static Handle<Object> PopImpl(Handle<JSArray> receiver) {
713     UNREACHABLE();
714     return Handle<Object>();
715   }
716 
Shift(Handle<JSArray> receiver)717   Handle<Object> Shift(Handle<JSArray> receiver) final {
718     return Subclass::ShiftImpl(receiver);
719   }
720 
ShiftImpl(Handle<JSArray> receiver)721   static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
722     UNREACHABLE();
723     return Handle<Object>();
724   }
725 
SetLength(Handle<JSArray> array,uint32_t length)726   void SetLength(Handle<JSArray> array, uint32_t length) final {
727     Subclass::SetLengthImpl(array->GetIsolate(), array, length,
728                             handle(array->elements()));
729   }
730 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)731   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
732                             uint32_t length,
733                             Handle<FixedArrayBase> backing_store) {
734     DCHECK(!array->SetLengthWouldNormalize(length));
735     DCHECK(IsFastElementsKind(array->GetElementsKind()));
736     uint32_t old_length = 0;
737     CHECK(array->length()->ToArrayIndex(&old_length));
738 
739     if (old_length < length) {
740       ElementsKind kind = array->GetElementsKind();
741       if (!IsFastHoleyElementsKind(kind)) {
742         kind = GetHoleyElementsKind(kind);
743         JSObject::TransitionElementsKind(array, kind);
744       }
745     }
746 
747     // Check whether the backing store should be shrunk.
748     uint32_t capacity = backing_store->length();
749     old_length = Min(old_length, capacity);
750     if (length == 0) {
751       array->initialize_elements();
752     } else if (length <= capacity) {
753       if (IsFastSmiOrObjectElementsKind(kind())) {
754         JSObject::EnsureWritableFastElements(array);
755         if (array->elements() != *backing_store) {
756           backing_store = handle(array->elements(), isolate);
757         }
758       }
759       if (2 * length <= capacity) {
760         // If more than half the elements won't be used, trim the array.
761         isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
762             *backing_store, capacity - length);
763       } else {
764         // Otherwise, fill the unused tail with holes.
765         for (uint32_t i = length; i < old_length; i++) {
766           BackingStore::cast(*backing_store)->set_the_hole(i);
767         }
768       }
769     } else {
770       // Check whether the backing store should be expanded.
771       capacity = Max(length, JSObject::NewElementsCapacity(capacity));
772       Subclass::GrowCapacityAndConvertImpl(array, capacity);
773     }
774 
775     array->set_length(Smi::FromInt(length));
776     JSObject::ValidateElements(array);
777   }
778 
NumberOfElements(JSObject * receiver)779   uint32_t NumberOfElements(JSObject* receiver) final {
780     return Subclass::NumberOfElementsImpl(receiver, receiver->elements());
781   }
782 
NumberOfElementsImpl(JSObject * receiver,FixedArrayBase * backing_store)783   static uint32_t NumberOfElementsImpl(JSObject* receiver,
784                                        FixedArrayBase* backing_store) {
785     UNREACHABLE();
786   }
787 
GetMaxIndex(JSObject * receiver,FixedArrayBase * elements)788   static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase* elements) {
789     if (receiver->IsJSArray()) {
790       DCHECK(JSArray::cast(receiver)->length()->IsSmi());
791       return static_cast<uint32_t>(
792           Smi::cast(JSArray::cast(receiver)->length())->value());
793     }
794     return Subclass::GetCapacityImpl(receiver, elements);
795   }
796 
GetMaxNumberOfEntries(JSObject * receiver,FixedArrayBase * elements)797   static uint32_t GetMaxNumberOfEntries(JSObject* receiver,
798                                         FixedArrayBase* elements) {
799     return Subclass::GetMaxIndex(receiver, elements);
800   }
801 
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity)802   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
803       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
804       ElementsKind from_kind, uint32_t capacity) {
805     return ConvertElementsWithCapacity(
806         object, old_elements, from_kind, capacity, 0, 0,
807         ElementsAccessor::kCopyToEndAndInitializeToHole);
808   }
809 
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity,int copy_size)810   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
811       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
812       ElementsKind from_kind, uint32_t capacity, int copy_size) {
813     return ConvertElementsWithCapacity(object, old_elements, from_kind,
814                                        capacity, 0, 0, copy_size);
815   }
816 
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)817   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
818       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
819       ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
820       uint32_t dst_index, int copy_size) {
821     Isolate* isolate = object->GetIsolate();
822     Handle<FixedArrayBase> new_elements;
823     if (IsFastDoubleElementsKind(kind())) {
824       new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
825     } else {
826       new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
827     }
828 
829     int packed_size = kPackedSizeNotKnown;
830     if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
831       packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
832     }
833 
834     Subclass::CopyElementsImpl(*old_elements, src_index, *new_elements,
835                                from_kind, dst_index, packed_size, copy_size);
836 
837     return new_elements;
838   }
839 
TransitionElementsKindImpl(Handle<JSObject> object,Handle<Map> to_map)840   static void TransitionElementsKindImpl(Handle<JSObject> object,
841                                          Handle<Map> to_map) {
842     Handle<Map> from_map = handle(object->map());
843     ElementsKind from_kind = from_map->elements_kind();
844     ElementsKind to_kind = to_map->elements_kind();
845     if (IsFastHoleyElementsKind(from_kind)) {
846       to_kind = GetHoleyElementsKind(to_kind);
847     }
848     if (from_kind != to_kind) {
849       // This method should never be called for any other case.
850       DCHECK(IsFastElementsKind(from_kind));
851       DCHECK(IsFastElementsKind(to_kind));
852       DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
853 
854       Handle<FixedArrayBase> from_elements(object->elements());
855       if (object->elements() == object->GetHeap()->empty_fixed_array() ||
856           IsFastDoubleElementsKind(from_kind) ==
857               IsFastDoubleElementsKind(to_kind)) {
858         // No change is needed to the elements() buffer, the transition
859         // only requires a map change.
860         JSObject::MigrateToMap(object, to_map);
861       } else {
862         DCHECK((IsFastSmiElementsKind(from_kind) &&
863                 IsFastDoubleElementsKind(to_kind)) ||
864                (IsFastDoubleElementsKind(from_kind) &&
865                 IsFastObjectElementsKind(to_kind)));
866         uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
867         Handle<FixedArrayBase> elements = ConvertElementsWithCapacity(
868             object, from_elements, from_kind, capacity);
869         JSObject::SetMapAndElements(object, to_map, elements);
870       }
871       if (FLAG_trace_elements_transitions) {
872         JSObject::PrintElementsTransition(stdout, object, from_kind,
873                                           from_elements, to_kind,
874                                           handle(object->elements()));
875       }
876     }
877   }
878 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)879   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
880                                          uint32_t capacity) {
881     ElementsKind from_kind = object->GetElementsKind();
882     if (IsFastSmiOrObjectElementsKind(from_kind)) {
883       // Array optimizations rely on the prototype lookups of Array objects
884       // always returning undefined. If there is a store to the initial
885       // prototype object, make sure all of these optimizations are invalidated.
886       object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
887     }
888     Handle<FixedArrayBase> old_elements(object->elements());
889     // This method should only be called if there's a reason to update the
890     // elements.
891     DCHECK(IsFastDoubleElementsKind(from_kind) !=
892                IsFastDoubleElementsKind(kind()) ||
893            IsDictionaryElementsKind(from_kind) ||
894            static_cast<uint32_t>(old_elements->length()) < capacity);
895     Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
896                                               kind(), capacity);
897   }
898 
BasicGrowCapacityAndConvertImpl(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,ElementsKind to_kind,uint32_t capacity)899   static void BasicGrowCapacityAndConvertImpl(
900       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
901       ElementsKind from_kind, ElementsKind to_kind, uint32_t capacity) {
902     Handle<FixedArrayBase> elements =
903         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
904 
905     if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
906     Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
907     JSObject::SetMapAndElements(object, new_map, elements);
908 
909     // Transition through the allocation site as well if present.
910     JSObject::UpdateAllocationSite(object, to_kind);
911 
912     if (FLAG_trace_elements_transitions) {
913       JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
914                                         to_kind, elements);
915     }
916   }
917 
TransitionElementsKind(Handle<JSObject> object,Handle<Map> map)918   void TransitionElementsKind(Handle<JSObject> object, Handle<Map> map) final {
919     Subclass::TransitionElementsKindImpl(object, map);
920   }
921 
GrowCapacityAndConvert(Handle<JSObject> object,uint32_t capacity)922   void GrowCapacityAndConvert(Handle<JSObject> object,
923                               uint32_t capacity) final {
924     Subclass::GrowCapacityAndConvertImpl(object, capacity);
925   }
926 
GrowCapacity(Handle<JSObject> object,uint32_t index)927   bool GrowCapacity(Handle<JSObject> object, uint32_t index) final {
928     // This function is intended to be called from optimized code. We don't
929     // want to trigger lazy deopts there, so refuse to handle cases that would.
930     if (object->map()->is_prototype_map() ||
931         object->WouldConvertToSlowElements(index)) {
932       return false;
933     }
934     Handle<FixedArrayBase> old_elements(object->elements());
935     uint32_t new_capacity = JSObject::NewElementsCapacity(index + 1);
936     DCHECK(static_cast<uint32_t>(old_elements->length()) < new_capacity);
937     Handle<FixedArrayBase> elements =
938         ConvertElementsWithCapacity(object, old_elements, kind(), new_capacity);
939 
940     DCHECK_EQ(object->GetElementsKind(), kind());
941     // Transition through the allocation site as well if present.
942     if (JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
943             object, kind())) {
944       return false;
945     }
946 
947     object->set_elements(*elements);
948     return true;
949   }
950 
Delete(Handle<JSObject> obj,uint32_t entry)951   void Delete(Handle<JSObject> obj, uint32_t entry) final {
952     Subclass::DeleteImpl(obj, entry);
953   }
954 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)955   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
956                                FixedArrayBase* to, ElementsKind from_kind,
957                                uint32_t to_start, int packed_size,
958                                int copy_size) {
959     UNREACHABLE();
960   }
961 
CopyElements(JSObject * from_holder,uint32_t from_start,ElementsKind from_kind,Handle<FixedArrayBase> to,uint32_t to_start,int copy_size)962   void CopyElements(JSObject* from_holder, uint32_t from_start,
963                     ElementsKind from_kind, Handle<FixedArrayBase> to,
964                     uint32_t to_start, int copy_size) final {
965     int packed_size = kPackedSizeNotKnown;
966     bool is_packed = IsFastPackedElementsKind(from_kind) &&
967         from_holder->IsJSArray();
968     if (is_packed) {
969       packed_size =
970           Smi::cast(JSArray::cast(from_holder)->length())->value();
971       if (copy_size >= 0 && packed_size > copy_size) {
972         packed_size = copy_size;
973       }
974     }
975     FixedArrayBase* from = from_holder->elements();
976     // NOTE: the Subclass::CopyElementsImpl() methods
977     // violate the handlified function signature convention:
978     // raw pointer parameters in the function that allocates. This is done
979     // intentionally to avoid ArrayConcat() builtin performance degradation.
980     //
981     // Details: The idea is that allocations actually happen only in case of
982     // copying from object with fast double elements to object with object
983     // elements. In all the other cases there are no allocations performed and
984     // handle creation causes noticeable performance degradation of the builtin.
985     Subclass::CopyElementsImpl(from, from_start, *to, from_kind, to_start,
986                                packed_size, copy_size);
987   }
988 
CopyElements(Handle<FixedArrayBase> source,ElementsKind source_kind,Handle<FixedArrayBase> destination,int size)989   void CopyElements(Handle<FixedArrayBase> source, ElementsKind source_kind,
990                     Handle<FixedArrayBase> destination, int size) {
991     Subclass::CopyElementsImpl(*source, 0, *destination, source_kind, 0,
992                                kPackedSizeNotKnown, size);
993   }
994 
Normalize(Handle<JSObject> object)995   Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final {
996     return Subclass::NormalizeImpl(object, handle(object->elements()));
997   }
998 
NormalizeImpl(Handle<JSObject> object,Handle<FixedArrayBase> elements)999   static Handle<SeededNumberDictionary> NormalizeImpl(
1000       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
1001     UNREACHABLE();
1002     return Handle<SeededNumberDictionary>();
1003   }
1004 
CollectValuesOrEntries(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)1005   Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject> object,
1006                                      Handle<FixedArray> values_or_entries,
1007                                      bool get_entries, int* nof_items,
1008                                      PropertyFilter filter) {
1009     return Subclass::CollectValuesOrEntriesImpl(
1010         isolate, object, values_or_entries, get_entries, nof_items, filter);
1011   }
1012 
CollectValuesOrEntriesImpl(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)1013   static Maybe<bool> CollectValuesOrEntriesImpl(
1014       Isolate* isolate, Handle<JSObject> object,
1015       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
1016       PropertyFilter filter) {
1017     int count = 0;
1018     KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
1019                                ALL_PROPERTIES);
1020     Subclass::CollectElementIndicesImpl(
1021         object, handle(object->elements(), isolate), &accumulator);
1022     Handle<FixedArray> keys = accumulator.GetKeys();
1023 
1024     for (int i = 0; i < keys->length(); ++i) {
1025       Handle<Object> key(keys->get(i), isolate);
1026       Handle<Object> value;
1027       uint32_t index;
1028       if (!key->ToUint32(&index)) continue;
1029 
1030       uint32_t entry = Subclass::GetEntryForIndexImpl(
1031           isolate, *object, object->elements(), index, filter);
1032       if (entry == kMaxUInt32) continue;
1033 
1034       PropertyDetails details = Subclass::GetDetailsImpl(*object, entry);
1035 
1036       if (details.kind() == kData) {
1037         value = Subclass::GetImpl(object, entry);
1038       } else {
1039         LookupIterator it(isolate, object, index, LookupIterator::OWN);
1040         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1041             isolate, value, Object::GetProperty(&it), Nothing<bool>());
1042       }
1043       if (get_entries) {
1044         value = MakeEntryPair(isolate, index, value);
1045       }
1046       values_or_entries->set(count++, *value);
1047     }
1048 
1049     *nof_items = count;
1050     return Just(true);
1051   }
1052 
CollectElementIndices(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)1053   void CollectElementIndices(Handle<JSObject> object,
1054                              Handle<FixedArrayBase> backing_store,
1055                              KeyAccumulator* keys) final {
1056     if (keys->filter() & ONLY_ALL_CAN_READ) return;
1057     Subclass::CollectElementIndicesImpl(object, backing_store, keys);
1058   }
1059 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)1060   static void CollectElementIndicesImpl(Handle<JSObject> object,
1061                                         Handle<FixedArrayBase> backing_store,
1062                                         KeyAccumulator* keys) {
1063     DCHECK_NE(DICTIONARY_ELEMENTS, kind());
1064     // Non-dictionary elements can't have all-can-read accessors.
1065     uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
1066     PropertyFilter filter = keys->filter();
1067     Isolate* isolate = keys->isolate();
1068     Factory* factory = isolate->factory();
1069     for (uint32_t i = 0; i < length; i++) {
1070       if (Subclass::HasElementImpl(isolate, object, i, backing_store, filter)) {
1071         keys->AddKey(factory->NewNumberFromUint(i));
1072       }
1073     }
1074   }
1075 
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)1076   static Handle<FixedArray> DirectCollectElementIndicesImpl(
1077       Isolate* isolate, Handle<JSObject> object,
1078       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1079       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
1080       uint32_t insertion_index = 0) {
1081     uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
1082     for (uint32_t i = 0; i < length; i++) {
1083       if (Subclass::HasElementImpl(isolate, object, i, backing_store, filter)) {
1084         if (convert == GetKeysConversion::kConvertToString) {
1085           Handle<String> index_string = isolate->factory()->Uint32ToString(i);
1086           list->set(insertion_index, *index_string);
1087         } else {
1088           list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
1089         }
1090         insertion_index++;
1091       }
1092     }
1093     *nof_indices = insertion_index;
1094     return list;
1095   }
1096 
PrependElementIndices(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,Handle<FixedArray> keys,GetKeysConversion convert,PropertyFilter filter)1097   MaybeHandle<FixedArray> PrependElementIndices(
1098       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
1099       Handle<FixedArray> keys, GetKeysConversion convert,
1100       PropertyFilter filter) final {
1101     return Subclass::PrependElementIndicesImpl(object, backing_store, keys,
1102                                                convert, filter);
1103   }
1104 
PrependElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,Handle<FixedArray> keys,GetKeysConversion convert,PropertyFilter filter)1105   static MaybeHandle<FixedArray> PrependElementIndicesImpl(
1106       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
1107       Handle<FixedArray> keys, GetKeysConversion convert,
1108       PropertyFilter filter) {
1109     Isolate* isolate = object->GetIsolate();
1110     uint32_t nof_property_keys = keys->length();
1111     uint32_t initial_list_length =
1112         Subclass::GetMaxNumberOfEntries(*object, *backing_store);
1113 
1114     initial_list_length += nof_property_keys;
1115     if (initial_list_length > FixedArray::kMaxLength ||
1116         initial_list_length < nof_property_keys) {
1117       return isolate->Throw<FixedArray>(isolate->factory()->NewRangeError(
1118           MessageTemplate::kInvalidArrayLength));
1119     }
1120 
1121     // Collect the element indices into a new list.
1122     MaybeHandle<FixedArray> raw_array =
1123         isolate->factory()->TryNewFixedArray(initial_list_length);
1124     Handle<FixedArray> combined_keys;
1125 
1126     // If we have a holey backing store try to precisely estimate the backing
1127     // store size as a last emergency measure if we cannot allocate the big
1128     // array.
1129     if (!raw_array.ToHandle(&combined_keys)) {
1130       if (IsHoleyElementsKind(kind())) {
1131         // If we overestimate the result list size we might end up in the
1132         // large-object space which doesn't free memory on shrinking the list.
1133         // Hence we try to estimate the final size for holey backing stores more
1134         // precisely here.
1135         initial_list_length =
1136             Subclass::NumberOfElementsImpl(*object, *backing_store);
1137         initial_list_length += nof_property_keys;
1138       }
1139       combined_keys = isolate->factory()->NewFixedArray(initial_list_length);
1140     }
1141 
1142     uint32_t nof_indices = 0;
1143     bool needs_sorting =
1144         IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind());
1145     combined_keys = Subclass::DirectCollectElementIndicesImpl(
1146         isolate, object, backing_store,
1147         needs_sorting ? GetKeysConversion::kKeepNumbers : convert, filter,
1148         combined_keys, &nof_indices);
1149 
1150     if (needs_sorting) {
1151       SortIndices(combined_keys, nof_indices);
1152       // Indices from dictionary elements should only be converted after
1153       // sorting.
1154       if (convert == GetKeysConversion::kConvertToString) {
1155         for (uint32_t i = 0; i < nof_indices; i++) {
1156           Handle<Object> index_string = isolate->factory()->Uint32ToString(
1157               combined_keys->get(i)->Number());
1158           combined_keys->set(i, *index_string);
1159         }
1160       }
1161     }
1162 
1163     // Copy over the passed-in property keys.
1164     CopyObjectToObjectElements(*keys, FAST_ELEMENTS, 0, *combined_keys,
1165                                FAST_ELEMENTS, nof_indices, nof_property_keys);
1166 
1167     // For holey elements and arguments we might have to shrink the collected
1168     // keys since the estimates might be off.
1169     if (IsHoleyElementsKind(kind()) || IsSloppyArgumentsElements(kind())) {
1170       // Shrink combined_keys to the final size.
1171       int final_size = nof_indices + nof_property_keys;
1172       DCHECK_LE(final_size, combined_keys->length());
1173       combined_keys->Shrink(final_size);
1174     }
1175 
1176     return combined_keys;
1177   }
1178 
AddElementsToKeyAccumulator(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)1179   void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
1180                                    KeyAccumulator* accumulator,
1181                                    AddKeyConversion convert) final {
1182     Subclass::AddElementsToKeyAccumulatorImpl(receiver, accumulator, convert);
1183   }
1184 
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)1185   static uint32_t GetCapacityImpl(JSObject* holder,
1186                                   FixedArrayBase* backing_store) {
1187     return backing_store->length();
1188   }
1189 
GetCapacity(JSObject * holder,FixedArrayBase * backing_store)1190   uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
1191     return Subclass::GetCapacityImpl(holder, backing_store);
1192   }
1193 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)1194   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1195                                        Handle<JSObject> receiver,
1196                                        Handle<Object> value,
1197                                        uint32_t start_from, uint32_t length) {
1198     return IncludesValueSlowPath(isolate, receiver, value, start_from, length);
1199   }
1200 
IncludesValue(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)1201   Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
1202                             Handle<Object> value, uint32_t start_from,
1203                             uint32_t length) final {
1204     return Subclass::IncludesValueImpl(isolate, receiver, value, start_from,
1205                                        length);
1206   }
1207 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)1208   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
1209                                          Handle<JSObject> receiver,
1210                                          Handle<Object> value,
1211                                          uint32_t start_from, uint32_t length) {
1212     return IndexOfValueSlowPath(isolate, receiver, value, start_from, length);
1213   }
1214 
IndexOfValue(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)1215   Maybe<int64_t> IndexOfValue(Isolate* isolate, Handle<JSObject> receiver,
1216                               Handle<Object> value, uint32_t start_from,
1217                               uint32_t length) final {
1218     return Subclass::IndexOfValueImpl(isolate, receiver, value, start_from,
1219                                       length);
1220   }
1221 
GetIndexForEntryImpl(FixedArrayBase * backing_store,uint32_t entry)1222   static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1223                                        uint32_t entry) {
1224     return entry;
1225   }
1226 
GetEntryForIndexImpl(Isolate * isolate,JSObject * holder,FixedArrayBase * backing_store,uint32_t index,PropertyFilter filter)1227   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
1228                                        FixedArrayBase* backing_store,
1229                                        uint32_t index, PropertyFilter filter) {
1230     uint32_t length = Subclass::GetMaxIndex(holder, backing_store);
1231     if (IsHoleyElementsKind(kind())) {
1232       return index < length &&
1233                      !BackingStore::cast(backing_store)
1234                           ->is_the_hole(isolate, index)
1235                  ? index
1236                  : kMaxUInt32;
1237     } else {
1238       return index < length ? index : kMaxUInt32;
1239     }
1240   }
1241 
GetEntryForIndex(Isolate * isolate,JSObject * holder,FixedArrayBase * backing_store,uint32_t index)1242   uint32_t GetEntryForIndex(Isolate* isolate, JSObject* holder,
1243                             FixedArrayBase* backing_store,
1244                             uint32_t index) final {
1245     return Subclass::GetEntryForIndexImpl(isolate, holder, backing_store, index,
1246                                           ALL_PROPERTIES);
1247   }
1248 
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)1249   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1250                                         uint32_t entry) {
1251     return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
1252   }
1253 
GetDetailsImpl(JSObject * holder,uint32_t entry)1254   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1255     return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
1256   }
1257 
GetDetails(JSObject * holder,uint32_t entry)1258   PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final {
1259     return Subclass::GetDetailsImpl(holder, entry);
1260   }
1261 
1262  private:
1263   DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
1264 };
1265 
1266 
1267 class DictionaryElementsAccessor
1268     : public ElementsAccessorBase<DictionaryElementsAccessor,
1269                                   ElementsKindTraits<DICTIONARY_ELEMENTS> > {
1270  public:
DictionaryElementsAccessor(const char * name)1271   explicit DictionaryElementsAccessor(const char* name)
1272       : ElementsAccessorBase<DictionaryElementsAccessor,
1273                              ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
1274 
GetMaxIndex(JSObject * receiver,FixedArrayBase * elements)1275   static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase* elements) {
1276     // We cannot properly estimate this for dictionaries.
1277     UNREACHABLE();
1278   }
1279 
GetMaxNumberOfEntries(JSObject * receiver,FixedArrayBase * backing_store)1280   static uint32_t GetMaxNumberOfEntries(JSObject* receiver,
1281                                         FixedArrayBase* backing_store) {
1282     return NumberOfElementsImpl(receiver, backing_store);
1283   }
1284 
NumberOfElementsImpl(JSObject * receiver,FixedArrayBase * backing_store)1285   static uint32_t NumberOfElementsImpl(JSObject* receiver,
1286                                        FixedArrayBase* backing_store) {
1287     SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
1288     return dict->NumberOfElements();
1289   }
1290 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)1291   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1292                             uint32_t length,
1293                             Handle<FixedArrayBase> backing_store) {
1294     Handle<SeededNumberDictionary> dict =
1295         Handle<SeededNumberDictionary>::cast(backing_store);
1296     int capacity = dict->Capacity();
1297     uint32_t old_length = 0;
1298     CHECK(array->length()->ToArrayLength(&old_length));
1299     if (length < old_length) {
1300       if (dict->requires_slow_elements()) {
1301         // Find last non-deletable element in range of elements to be
1302         // deleted and adjust range accordingly.
1303         for (int entry = 0; entry < capacity; entry++) {
1304           DisallowHeapAllocation no_gc;
1305           Object* index = dict->KeyAt(entry);
1306           if (index->IsNumber()) {
1307             uint32_t number = static_cast<uint32_t>(index->Number());
1308             if (length <= number && number < old_length) {
1309               PropertyDetails details = dict->DetailsAt(entry);
1310               if (!details.IsConfigurable()) length = number + 1;
1311             }
1312           }
1313         }
1314       }
1315 
1316       if (length == 0) {
1317         // Flush the backing store.
1318         JSObject::ResetElements(array);
1319       } else {
1320         DisallowHeapAllocation no_gc;
1321         // Remove elements that should be deleted.
1322         int removed_entries = 0;
1323         Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
1324         for (int entry = 0; entry < capacity; entry++) {
1325           Object* index = dict->KeyAt(entry);
1326           if (index->IsNumber()) {
1327             uint32_t number = static_cast<uint32_t>(index->Number());
1328             if (length <= number && number < old_length) {
1329               dict->SetEntry(entry, the_hole_value, the_hole_value);
1330               removed_entries++;
1331             }
1332           }
1333         }
1334 
1335         // Update the number of elements.
1336         dict->ElementsRemoved(removed_entries);
1337       }
1338     }
1339 
1340     Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1341     array->set_length(*length_obj);
1342   }
1343 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)1344   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1345                                FixedArrayBase* to, ElementsKind from_kind,
1346                                uint32_t to_start, int packed_size,
1347                                int copy_size) {
1348     UNREACHABLE();
1349   }
1350 
1351 
DeleteImpl(Handle<JSObject> obj,uint32_t entry)1352   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1353     // TODO(verwaest): Remove reliance on index in Shrink.
1354     Handle<SeededNumberDictionary> dict(
1355         SeededNumberDictionary::cast(obj->elements()));
1356     uint32_t index = GetIndexForEntryImpl(*dict, entry);
1357     Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
1358     USE(result);
1359     DCHECK(result->IsTrue(dict->GetIsolate()));
1360     Handle<FixedArray> new_elements =
1361         SeededNumberDictionary::Shrink(dict, index);
1362     obj->set_elements(*new_elements);
1363   }
1364 
HasAccessorsImpl(JSObject * holder,FixedArrayBase * backing_store)1365   static bool HasAccessorsImpl(JSObject* holder,
1366                                FixedArrayBase* backing_store) {
1367     DisallowHeapAllocation no_gc;
1368     SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
1369     if (!dict->requires_slow_elements()) return false;
1370     int capacity = dict->Capacity();
1371     Isolate* isolate = dict->GetIsolate();
1372     for (int i = 0; i < capacity; i++) {
1373       Object* key = dict->KeyAt(i);
1374       if (!dict->IsKey(isolate, key)) continue;
1375       DCHECK(!dict->IsDeleted(i));
1376       PropertyDetails details = dict->DetailsAt(i);
1377       if (details.type() == ACCESSOR_CONSTANT) return true;
1378     }
1379     return false;
1380   }
1381 
GetRaw(FixedArrayBase * store,uint32_t entry)1382   static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
1383     SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
1384     return backing_store->ValueAt(entry);
1385   }
1386 
GetImpl(Handle<JSObject> holder,uint32_t entry)1387   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
1388     return GetImpl(holder->elements(), entry);
1389   }
1390 
GetImpl(FixedArrayBase * backing_store,uint32_t entry)1391   static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
1392     return handle(GetRaw(backing_store, entry), backing_store->GetIsolate());
1393   }
1394 
SetImpl(Handle<JSObject> holder,uint32_t entry,Object * value)1395   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
1396                              Object* value) {
1397     SetImpl(holder->elements(), entry, value);
1398   }
1399 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)1400   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1401                              Object* value) {
1402     SeededNumberDictionary::cast(backing_store)->ValueAtPut(entry, value);
1403   }
1404 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)1405   static void ReconfigureImpl(Handle<JSObject> object,
1406                               Handle<FixedArrayBase> store, uint32_t entry,
1407                               Handle<Object> value,
1408                               PropertyAttributes attributes) {
1409     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
1410     if (attributes != NONE) object->RequireSlowElements(dictionary);
1411     dictionary->ValueAtPut(entry, *value);
1412     PropertyDetails details = dictionary->DetailsAt(entry);
1413     details = PropertyDetails(attributes, DATA, details.dictionary_index(),
1414                               PropertyCellType::kNoCell);
1415     dictionary->DetailsAtPut(entry, details);
1416   }
1417 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)1418   static void AddImpl(Handle<JSObject> object, uint32_t index,
1419                       Handle<Object> value, PropertyAttributes attributes,
1420                       uint32_t new_capacity) {
1421     PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
1422     Handle<SeededNumberDictionary> dictionary =
1423         object->HasFastElements() || object->HasFastStringWrapperElements()
1424             ? JSObject::NormalizeElements(object)
1425             : handle(SeededNumberDictionary::cast(object->elements()));
1426     Handle<SeededNumberDictionary> new_dictionary =
1427         SeededNumberDictionary::AddNumberEntry(
1428             dictionary, index, value, details,
1429             object->map()->is_prototype_map());
1430     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1431     if (dictionary.is_identical_to(new_dictionary)) return;
1432     object->set_elements(*new_dictionary);
1433   }
1434 
HasEntryImpl(Isolate * isolate,FixedArrayBase * store,uint32_t entry)1435   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* store,
1436                            uint32_t entry) {
1437     DisallowHeapAllocation no_gc;
1438     SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1439     Object* index = dict->KeyAt(entry);
1440     return !index->IsTheHole(isolate);
1441   }
1442 
GetIndexForEntryImpl(FixedArrayBase * store,uint32_t entry)1443   static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
1444     DisallowHeapAllocation no_gc;
1445     SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1446     uint32_t result = 0;
1447     CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
1448     return result;
1449   }
1450 
GetEntryForIndexImpl(Isolate * isolate,JSObject * holder,FixedArrayBase * store,uint32_t index,PropertyFilter filter)1451   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
1452                                        FixedArrayBase* store, uint32_t index,
1453                                        PropertyFilter filter) {
1454     DisallowHeapAllocation no_gc;
1455     SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1456     int entry = dictionary->FindEntry(isolate, index);
1457     if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
1458     if (filter != ALL_PROPERTIES) {
1459       PropertyDetails details = dictionary->DetailsAt(entry);
1460       PropertyAttributes attr = details.attributes();
1461       if ((attr & filter) != 0) return kMaxUInt32;
1462     }
1463     return static_cast<uint32_t>(entry);
1464   }
1465 
GetDetailsImpl(JSObject * holder,uint32_t entry)1466   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
1467     return GetDetailsImpl(holder->elements(), entry);
1468   }
1469 
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)1470   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1471                                         uint32_t entry) {
1472     return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
1473   }
1474 
FilterKey(Handle<SeededNumberDictionary> dictionary,int entry,Object * raw_key,PropertyFilter filter)1475   static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary,
1476                             int entry, Object* raw_key, PropertyFilter filter) {
1477     DCHECK(!dictionary->IsDeleted(entry));
1478     DCHECK(raw_key->IsNumber());
1479     DCHECK_LE(raw_key->Number(), kMaxUInt32);
1480     PropertyDetails details = dictionary->DetailsAt(entry);
1481     PropertyAttributes attr = details.attributes();
1482     if ((attr & filter) != 0) return kMaxUInt32;
1483     return static_cast<uint32_t>(raw_key->Number());
1484   }
1485 
GetKeyForEntryImpl(Isolate * isolate,Handle<SeededNumberDictionary> dictionary,int entry,PropertyFilter filter)1486   static uint32_t GetKeyForEntryImpl(Isolate* isolate,
1487                                      Handle<SeededNumberDictionary> dictionary,
1488                                      int entry, PropertyFilter filter) {
1489     DisallowHeapAllocation no_gc;
1490     Object* raw_key = dictionary->KeyAt(entry);
1491     if (!dictionary->IsKey(isolate, raw_key)) return kMaxUInt32;
1492     return FilterKey(dictionary, entry, raw_key, filter);
1493   }
1494 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)1495   static void CollectElementIndicesImpl(Handle<JSObject> object,
1496                                         Handle<FixedArrayBase> backing_store,
1497                                         KeyAccumulator* keys) {
1498     if (keys->filter() & SKIP_STRINGS) return;
1499     Isolate* isolate = keys->isolate();
1500     Handle<SeededNumberDictionary> dictionary =
1501         Handle<SeededNumberDictionary>::cast(backing_store);
1502     int capacity = dictionary->Capacity();
1503     Handle<FixedArray> elements = isolate->factory()->NewFixedArray(
1504         GetMaxNumberOfEntries(*object, *backing_store));
1505     int insertion_index = 0;
1506     PropertyFilter filter = keys->filter();
1507     for (int i = 0; i < capacity; i++) {
1508       Object* raw_key = dictionary->KeyAt(i);
1509       if (!dictionary->IsKey(isolate, raw_key)) continue;
1510       uint32_t key = FilterKey(dictionary, i, raw_key, filter);
1511       if (key == kMaxUInt32) {
1512         keys->AddShadowingKey(raw_key);
1513         continue;
1514       }
1515       elements->set(insertion_index, raw_key);
1516       insertion_index++;
1517     }
1518     SortIndices(elements, insertion_index);
1519     for (int i = 0; i < insertion_index; i++) {
1520       keys->AddKey(elements->get(i));
1521     }
1522   }
1523 
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)1524   static Handle<FixedArray> DirectCollectElementIndicesImpl(
1525       Isolate* isolate, Handle<JSObject> object,
1526       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1527       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
1528       uint32_t insertion_index = 0) {
1529     if (filter & SKIP_STRINGS) return list;
1530     if (filter & ONLY_ALL_CAN_READ) return list;
1531 
1532     Handle<SeededNumberDictionary> dictionary =
1533         Handle<SeededNumberDictionary>::cast(backing_store);
1534     uint32_t capacity = dictionary->Capacity();
1535     for (uint32_t i = 0; i < capacity; i++) {
1536       uint32_t key = GetKeyForEntryImpl(isolate, dictionary, i, filter);
1537       if (key == kMaxUInt32) continue;
1538       Handle<Object> index = isolate->factory()->NewNumberFromUint(key);
1539       list->set(insertion_index, *index);
1540       insertion_index++;
1541     }
1542     *nof_indices = insertion_index;
1543     return list;
1544   }
1545 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)1546   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1547                                               KeyAccumulator* accumulator,
1548                                               AddKeyConversion convert) {
1549     Isolate* isolate = accumulator->isolate();
1550     Handle<Object> undefined = isolate->factory()->undefined_value();
1551     Handle<Object> the_hole = isolate->factory()->the_hole_value();
1552     Handle<SeededNumberDictionary> dictionary(
1553         SeededNumberDictionary::cast(receiver->elements()), isolate);
1554     int capacity = dictionary->Capacity();
1555     for (int i = 0; i < capacity; i++) {
1556       Object* k = dictionary->KeyAt(i);
1557       if (k == *undefined) continue;
1558       if (k == *the_hole) continue;
1559       if (dictionary->IsDeleted(i)) continue;
1560       Object* value = dictionary->ValueAt(i);
1561       DCHECK(!value->IsTheHole(isolate));
1562       DCHECK(!value->IsAccessorPair());
1563       DCHECK(!value->IsAccessorInfo());
1564       accumulator->AddKey(value, convert);
1565     }
1566   }
1567 
IncludesValueFastPath(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length,Maybe<bool> * result)1568   static bool IncludesValueFastPath(Isolate* isolate, Handle<JSObject> receiver,
1569                                     Handle<Object> value, uint32_t start_from,
1570                                     uint32_t length, Maybe<bool>* result) {
1571     DisallowHeapAllocation no_gc;
1572     SeededNumberDictionary* dictionary =
1573         SeededNumberDictionary::cast(receiver->elements());
1574     int capacity = dictionary->Capacity();
1575     Object* the_hole = isolate->heap()->the_hole_value();
1576     Object* undefined = isolate->heap()->undefined_value();
1577 
1578     // Scan for accessor properties. If accessors are present, then elements
1579     // must be accessed in order via the slow path.
1580     bool found = false;
1581     for (int i = 0; i < capacity; ++i) {
1582       Object* k = dictionary->KeyAt(i);
1583       if (k == the_hole) continue;
1584       if (k == undefined) continue;
1585 
1586       uint32_t index;
1587       if (!k->ToArrayIndex(&index) || index < start_from || index >= length) {
1588         continue;
1589       }
1590 
1591       if (dictionary->DetailsAt(i).type() == ACCESSOR_CONSTANT) {
1592         // Restart from beginning in slow path, otherwise we may observably
1593         // access getters out of order
1594         return false;
1595       } else if (!found) {
1596         Object* element_k = dictionary->ValueAt(i);
1597         if (value->SameValueZero(element_k)) found = true;
1598       }
1599     }
1600 
1601     *result = Just(found);
1602     return true;
1603   }
1604 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)1605   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1606                                        Handle<JSObject> receiver,
1607                                        Handle<Object> value,
1608                                        uint32_t start_from, uint32_t length) {
1609     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
1610     bool search_for_hole = value->IsUndefined(isolate);
1611 
1612     if (!search_for_hole) {
1613       Maybe<bool> result = Nothing<bool>();
1614       if (DictionaryElementsAccessor::IncludesValueFastPath(
1615               isolate, receiver, value, start_from, length, &result)) {
1616         return result;
1617       }
1618     }
1619 
1620     Handle<SeededNumberDictionary> dictionary(
1621         SeededNumberDictionary::cast(receiver->elements()), isolate);
1622     // Iterate through entire range, as accessing elements out of order is
1623     // observable
1624     for (uint32_t k = start_from; k < length; ++k) {
1625       int entry = dictionary->FindEntry(k);
1626       if (entry == SeededNumberDictionary::kNotFound) {
1627         if (search_for_hole) return Just(true);
1628         continue;
1629       }
1630 
1631       PropertyDetails details = GetDetailsImpl(*dictionary, entry);
1632       switch (details.kind()) {
1633         case kData: {
1634           Object* element_k = dictionary->ValueAt(entry);
1635           if (value->SameValueZero(element_k)) return Just(true);
1636           break;
1637         }
1638         case kAccessor: {
1639           LookupIterator it(isolate, receiver, k,
1640                             LookupIterator::OWN_SKIP_INTERCEPTOR);
1641           DCHECK(it.IsFound());
1642           DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
1643           Handle<Object> element_k;
1644 
1645           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1646               isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
1647               Nothing<bool>());
1648 
1649           if (value->SameValueZero(*element_k)) return Just(true);
1650 
1651           // Bailout to slow path if elements on prototype changed
1652           if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
1653             return IncludesValueSlowPath(isolate, receiver, value, k + 1,
1654                                          length);
1655           }
1656 
1657           // Continue if elements unchanged
1658           if (*dictionary == receiver->elements()) continue;
1659 
1660           // Otherwise, bailout or update elements
1661           if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
1662             if (receiver->map()->GetInitialElements() == receiver->elements()) {
1663               // If switched to initial elements, return true if searching for
1664               // undefined, and false otherwise.
1665               return Just(search_for_hole);
1666             }
1667             // Otherwise, switch to slow path.
1668             return IncludesValueSlowPath(isolate, receiver, value, k + 1,
1669                                          length);
1670           }
1671           dictionary = handle(
1672               SeededNumberDictionary::cast(receiver->elements()), isolate);
1673           break;
1674         }
1675       }
1676     }
1677     return Just(false);
1678   }
1679 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)1680   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
1681                                          Handle<JSObject> receiver,
1682                                          Handle<Object> value,
1683                                          uint32_t start_from, uint32_t length) {
1684     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
1685 
1686     Handle<SeededNumberDictionary> dictionary(
1687         SeededNumberDictionary::cast(receiver->elements()), isolate);
1688     // Iterate through entire range, as accessing elements out of order is
1689     // observable.
1690     for (uint32_t k = start_from; k < length; ++k) {
1691       int entry = dictionary->FindEntry(k);
1692       if (entry == SeededNumberDictionary::kNotFound) {
1693         continue;
1694       }
1695 
1696       PropertyDetails details = GetDetailsImpl(*dictionary, entry);
1697       switch (details.kind()) {
1698         case kData: {
1699           Object* element_k = dictionary->ValueAt(entry);
1700           if (value->StrictEquals(element_k)) {
1701             return Just<int64_t>(k);
1702           }
1703           break;
1704         }
1705         case kAccessor: {
1706           LookupIterator it(isolate, receiver, k,
1707                             LookupIterator::OWN_SKIP_INTERCEPTOR);
1708           DCHECK(it.IsFound());
1709           DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
1710           Handle<Object> element_k;
1711 
1712           ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1713               isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
1714               Nothing<int64_t>());
1715 
1716           if (value->StrictEquals(*element_k)) return Just<int64_t>(k);
1717 
1718           // Bailout to slow path if elements on prototype changed.
1719           if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
1720             return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
1721                                         length);
1722           }
1723 
1724           // Continue if elements unchanged.
1725           if (*dictionary == receiver->elements()) continue;
1726 
1727           // Otherwise, bailout or update elements.
1728           if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
1729             // Otherwise, switch to slow path.
1730             return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
1731                                         length);
1732           }
1733           dictionary = handle(
1734               SeededNumberDictionary::cast(receiver->elements()), isolate);
1735           break;
1736         }
1737       }
1738     }
1739     return Just<int64_t>(-1);
1740   }
1741 };
1742 
1743 
1744 // Super class for all fast element arrays.
1745 template <typename Subclass, typename KindTraits>
1746 class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
1747  public:
FastElementsAccessor(const char * name)1748   explicit FastElementsAccessor(const char* name)
1749       : ElementsAccessorBase<Subclass, KindTraits>(name) {}
1750 
1751   typedef typename KindTraits::BackingStore BackingStore;
1752 
NormalizeImpl(Handle<JSObject> object,Handle<FixedArrayBase> store)1753   static Handle<SeededNumberDictionary> NormalizeImpl(
1754       Handle<JSObject> object, Handle<FixedArrayBase> store) {
1755     Isolate* isolate = store->GetIsolate();
1756     ElementsKind kind = Subclass::kind();
1757 
1758     // Ensure that notifications fire if the array or object prototypes are
1759     // normalizing.
1760     if (IsFastSmiOrObjectElementsKind(kind)) {
1761       isolate->UpdateArrayProtectorOnNormalizeElements(object);
1762     }
1763 
1764     int capacity = object->GetFastElementsUsage();
1765     Handle<SeededNumberDictionary> dictionary =
1766         SeededNumberDictionary::New(isolate, capacity);
1767 
1768     PropertyDetails details = PropertyDetails::Empty();
1769     bool used_as_prototype = object->map()->is_prototype_map();
1770     int j = 0;
1771     for (int i = 0; j < capacity; i++) {
1772       if (IsHoleyElementsKind(kind)) {
1773         if (BackingStore::cast(*store)->is_the_hole(isolate, i)) continue;
1774       }
1775       Handle<Object> value = Subclass::GetImpl(*store, i);
1776       dictionary = SeededNumberDictionary::AddNumberEntry(
1777           dictionary, i, value, details, used_as_prototype);
1778       j++;
1779     }
1780     return dictionary;
1781   }
1782 
DeleteAtEnd(Handle<JSObject> obj,Handle<BackingStore> backing_store,uint32_t entry)1783   static void DeleteAtEnd(Handle<JSObject> obj,
1784                           Handle<BackingStore> backing_store, uint32_t entry) {
1785     uint32_t length = static_cast<uint32_t>(backing_store->length());
1786     Isolate* isolate = obj->GetIsolate();
1787     for (; entry > 0; entry--) {
1788       if (!backing_store->is_the_hole(isolate, entry - 1)) break;
1789     }
1790     if (entry == 0) {
1791       FixedArray* empty = isolate->heap()->empty_fixed_array();
1792       // Dynamically ask for the elements kind here since we manually redirect
1793       // the operations for argument backing stores.
1794       if (obj->GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
1795         FixedArray::cast(obj->elements())->set(1, empty);
1796       } else {
1797         obj->set_elements(empty);
1798       }
1799       return;
1800     }
1801 
1802     isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
1803         *backing_store, length - entry);
1804   }
1805 
DeleteCommon(Handle<JSObject> obj,uint32_t entry,Handle<FixedArrayBase> store)1806   static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1807                            Handle<FixedArrayBase> store) {
1808     DCHECK(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() ||
1809            obj->HasFastArgumentsElements() ||
1810            obj->HasFastStringWrapperElements());
1811     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
1812     if (!obj->IsJSArray() &&
1813         entry == static_cast<uint32_t>(store->length()) - 1) {
1814       DeleteAtEnd(obj, backing_store, entry);
1815       return;
1816     }
1817 
1818     Isolate* isolate = obj->GetIsolate();
1819     backing_store->set_the_hole(entry);
1820 
1821     // TODO(verwaest): Move this out of elements.cc.
1822     // If an old space backing store is larger than a certain size and
1823     // has too few used values, normalize it.
1824     // To avoid doing the check on every delete we require at least
1825     // one adjacent hole to the value being deleted.
1826     const int kMinLengthForSparsenessCheck = 64;
1827     if (backing_store->length() < kMinLengthForSparsenessCheck) return;
1828     if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
1829     uint32_t length = 0;
1830     if (obj->IsJSArray()) {
1831       JSArray::cast(*obj)->length()->ToArrayLength(&length);
1832     } else {
1833       length = static_cast<uint32_t>(store->length());
1834     }
1835     if ((entry > 0 && backing_store->is_the_hole(isolate, entry - 1)) ||
1836         (entry + 1 < length &&
1837          backing_store->is_the_hole(isolate, entry + 1))) {
1838       if (!obj->IsJSArray()) {
1839         uint32_t i;
1840         for (i = entry + 1; i < length; i++) {
1841           if (!backing_store->is_the_hole(isolate, i)) break;
1842         }
1843         if (i == length) {
1844           DeleteAtEnd(obj, backing_store, entry);
1845           return;
1846         }
1847       }
1848       int num_used = 0;
1849       for (int i = 0; i < backing_store->length(); ++i) {
1850         if (!backing_store->is_the_hole(isolate, i)) {
1851           ++num_used;
1852           // Bail out if a number dictionary wouldn't be able to save at least
1853           // 75% space.
1854           if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
1855                   SeededNumberDictionary::kEntrySize >
1856               backing_store->length()) {
1857             return;
1858           }
1859         }
1860       }
1861       JSObject::NormalizeElements(obj);
1862     }
1863   }
1864 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)1865   static void ReconfigureImpl(Handle<JSObject> object,
1866                               Handle<FixedArrayBase> store, uint32_t entry,
1867                               Handle<Object> value,
1868                               PropertyAttributes attributes) {
1869     Handle<SeededNumberDictionary> dictionary =
1870         JSObject::NormalizeElements(object);
1871     entry = dictionary->FindEntry(entry);
1872     DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
1873                                                 value, attributes);
1874   }
1875 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)1876   static void AddImpl(Handle<JSObject> object, uint32_t index,
1877                       Handle<Object> value, PropertyAttributes attributes,
1878                       uint32_t new_capacity) {
1879     DCHECK_EQ(NONE, attributes);
1880     ElementsKind from_kind = object->GetElementsKind();
1881     ElementsKind to_kind = Subclass::kind();
1882     if (IsDictionaryElementsKind(from_kind) ||
1883         IsFastDoubleElementsKind(from_kind) !=
1884             IsFastDoubleElementsKind(to_kind) ||
1885         Subclass::GetCapacityImpl(*object, object->elements()) !=
1886             new_capacity) {
1887       Subclass::GrowCapacityAndConvertImpl(object, new_capacity);
1888     } else {
1889       if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
1890         JSObject::TransitionElementsKind(object, to_kind);
1891       }
1892       if (IsFastSmiOrObjectElementsKind(from_kind)) {
1893         DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
1894         JSObject::EnsureWritableFastElements(object);
1895       }
1896     }
1897     Subclass::SetImpl(object, index, *value);
1898   }
1899 
DeleteImpl(Handle<JSObject> obj,uint32_t entry)1900   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1901     ElementsKind kind = KindTraits::Kind;
1902     if (IsFastPackedElementsKind(kind)) {
1903       JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
1904     }
1905     if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1906       JSObject::EnsureWritableFastElements(obj);
1907     }
1908     DeleteCommon(obj, entry, handle(obj->elements()));
1909   }
1910 
HasEntryImpl(Isolate * isolate,FixedArrayBase * backing_store,uint32_t entry)1911   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* backing_store,
1912                            uint32_t entry) {
1913     return !BackingStore::cast(backing_store)->is_the_hole(isolate, entry);
1914   }
1915 
NumberOfElementsImpl(JSObject * receiver,FixedArrayBase * backing_store)1916   static uint32_t NumberOfElementsImpl(JSObject* receiver,
1917                                        FixedArrayBase* backing_store) {
1918     uint32_t max_index = Subclass::GetMaxIndex(receiver, backing_store);
1919     if (IsFastPackedElementsKind(Subclass::kind())) return max_index;
1920     Isolate* isolate = receiver->GetIsolate();
1921     uint32_t count = 0;
1922     for (uint32_t i = 0; i < max_index; i++) {
1923       if (Subclass::HasEntryImpl(isolate, backing_store, i)) count++;
1924     }
1925     return count;
1926   }
1927 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)1928   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
1929                                               KeyAccumulator* accumulator,
1930                                               AddKeyConversion convert) {
1931     Isolate* isolate = accumulator->isolate();
1932     Handle<FixedArrayBase> elements(receiver->elements(), isolate);
1933     uint32_t length = Subclass::GetMaxNumberOfEntries(*receiver, *elements);
1934     for (uint32_t i = 0; i < length; i++) {
1935       if (IsFastPackedElementsKind(KindTraits::Kind) ||
1936           HasEntryImpl(isolate, *elements, i)) {
1937         accumulator->AddKey(Subclass::GetImpl(*elements, i), convert);
1938       }
1939     }
1940   }
1941 
ValidateContents(Handle<JSObject> holder,int length)1942   static void ValidateContents(Handle<JSObject> holder, int length) {
1943 #if DEBUG
1944     Isolate* isolate = holder->GetIsolate();
1945     Heap* heap = isolate->heap();
1946     HandleScope scope(isolate);
1947     Handle<FixedArrayBase> elements(holder->elements(), isolate);
1948     Map* map = elements->map();
1949     if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1950       DCHECK_NE(map, heap->fixed_double_array_map());
1951     } else if (IsFastDoubleElementsKind(KindTraits::Kind)) {
1952       DCHECK_NE(map, heap->fixed_cow_array_map());
1953       if (map == heap->fixed_array_map()) DCHECK_EQ(0, length);
1954     } else {
1955       UNREACHABLE();
1956     }
1957     if (length == 0) return;  // nothing to do!
1958 #if ENABLE_SLOW_DCHECKS
1959     DisallowHeapAllocation no_gc;
1960     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
1961     if (IsFastSmiElementsKind(KindTraits::Kind)) {
1962       for (int i = 0; i < length; i++) {
1963         DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() ||
1964                (IsFastHoleyElementsKind(KindTraits::Kind) &&
1965                 backing_store->is_the_hole(isolate, i)));
1966       }
1967     } else if (KindTraits::Kind == FAST_ELEMENTS ||
1968                KindTraits::Kind == FAST_DOUBLE_ELEMENTS) {
1969       for (int i = 0; i < length; i++) {
1970         DCHECK(!backing_store->is_the_hole(isolate, i));
1971       }
1972     } else {
1973       DCHECK(IsFastHoleyElementsKind(KindTraits::Kind));
1974     }
1975 #endif
1976 #endif
1977   }
1978 
PopImpl(Handle<JSArray> receiver)1979   static Handle<Object> PopImpl(Handle<JSArray> receiver) {
1980     return Subclass::RemoveElement(receiver, AT_END);
1981   }
1982 
ShiftImpl(Handle<JSArray> receiver)1983   static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
1984     return Subclass::RemoveElement(receiver, AT_START);
1985   }
1986 
PushImpl(Handle<JSArray> receiver,Arguments * args,uint32_t push_size)1987   static uint32_t PushImpl(Handle<JSArray> receiver,
1988                            Arguments* args, uint32_t push_size) {
1989     Handle<FixedArrayBase> backing_store(receiver->elements());
1990     return Subclass::AddArguments(receiver, backing_store, args, push_size,
1991                                   AT_END);
1992   }
1993 
UnshiftImpl(Handle<JSArray> receiver,Arguments * args,uint32_t unshift_size)1994   static uint32_t UnshiftImpl(Handle<JSArray> receiver,
1995                               Arguments* args, uint32_t unshift_size) {
1996     Handle<FixedArrayBase> backing_store(receiver->elements());
1997     return Subclass::AddArguments(receiver, backing_store, args, unshift_size,
1998                                   AT_START);
1999   }
2000 
SliceImpl(Handle<JSObject> receiver,uint32_t start,uint32_t end)2001   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
2002                                    uint32_t start, uint32_t end) {
2003     Isolate* isolate = receiver->GetIsolate();
2004     Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
2005     int result_len = end < start ? 0u : end - start;
2006     Handle<JSArray> result_array = isolate->factory()->NewJSArray(
2007         KindTraits::Kind, result_len, result_len);
2008     DisallowHeapAllocation no_gc;
2009     Subclass::CopyElementsImpl(*backing_store, start, result_array->elements(),
2010                                KindTraits::Kind, 0, kPackedSizeNotKnown,
2011                                result_len);
2012     Subclass::TryTransitionResultArrayToPacked(result_array);
2013     return result_array;
2014   }
2015 
SpliceImpl(Handle<JSArray> receiver,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)2016   static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
2017                                     uint32_t start, uint32_t delete_count,
2018                                     Arguments* args, uint32_t add_count) {
2019     Isolate* isolate = receiver->GetIsolate();
2020     Heap* heap = isolate->heap();
2021     uint32_t length = Smi::cast(receiver->length())->value();
2022     uint32_t new_length = length - delete_count + add_count;
2023 
2024     ElementsKind kind = KindTraits::Kind;
2025     if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) &&
2026         IsFastSmiOrObjectElementsKind(kind)) {
2027       HandleScope scope(isolate);
2028       JSObject::EnsureWritableFastElements(receiver);
2029     }
2030 
2031     Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
2032 
2033     if (new_length == 0) {
2034       receiver->set_elements(heap->empty_fixed_array());
2035       receiver->set_length(Smi::kZero);
2036       return isolate->factory()->NewJSArrayWithElements(
2037           backing_store, KindTraits::Kind, delete_count);
2038     }
2039 
2040     // Construct the result array which holds the deleted elements.
2041     Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
2042         KindTraits::Kind, delete_count, delete_count);
2043     if (delete_count > 0) {
2044       DisallowHeapAllocation no_gc;
2045       Subclass::CopyElementsImpl(*backing_store, start,
2046                                  deleted_elements->elements(), KindTraits::Kind,
2047                                  0, kPackedSizeNotKnown, delete_count);
2048     }
2049 
2050     // Delete and move elements to make space for add_count new elements.
2051     if (add_count < delete_count) {
2052       Subclass::SpliceShrinkStep(isolate, receiver, backing_store, start,
2053                                  delete_count, add_count, length, new_length);
2054     } else if (add_count > delete_count) {
2055       backing_store =
2056           Subclass::SpliceGrowStep(isolate, receiver, backing_store, start,
2057                                    delete_count, add_count, length, new_length);
2058     }
2059 
2060     // Copy over the arguments.
2061     Subclass::CopyArguments(args, backing_store, add_count, 3, start);
2062 
2063     receiver->set_length(Smi::FromInt(new_length));
2064     Subclass::TryTransitionResultArrayToPacked(deleted_elements);
2065     return deleted_elements;
2066   }
2067 
CollectValuesOrEntriesImpl(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)2068   static Maybe<bool> CollectValuesOrEntriesImpl(
2069       Isolate* isolate, Handle<JSObject> object,
2070       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
2071       PropertyFilter filter) {
2072     Handle<BackingStore> elements(BackingStore::cast(object->elements()),
2073                                   isolate);
2074     int count = 0;
2075     uint32_t length = elements->length();
2076     for (uint32_t index = 0; index < length; ++index) {
2077       if (!HasEntryImpl(isolate, *elements, index)) continue;
2078       Handle<Object> value = Subclass::GetImpl(*elements, index);
2079       if (get_entries) {
2080         value = MakeEntryPair(isolate, index, value);
2081       }
2082       values_or_entries->set(count++, *value);
2083     }
2084     *nof_items = count;
2085     return Just(true);
2086   }
2087 
MoveElements(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,int dst_index,int src_index,int len,int hole_start,int hole_end)2088   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
2089                            Handle<FixedArrayBase> backing_store, int dst_index,
2090                            int src_index, int len, int hole_start,
2091                            int hole_end) {
2092     Heap* heap = isolate->heap();
2093     Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store);
2094     if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
2095       // Update all the copies of this backing_store handle.
2096       *dst_elms.location() =
2097           BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
2098       receiver->set_elements(*dst_elms);
2099       // Adjust the hole offset as the array has been shrunk.
2100       hole_end -= src_index;
2101       DCHECK_LE(hole_start, backing_store->length());
2102       DCHECK_LE(hole_end, backing_store->length());
2103     } else if (len != 0) {
2104       if (IsFastDoubleElementsKind(KindTraits::Kind)) {
2105         MemMove(dst_elms->data_start() + dst_index,
2106                 dst_elms->data_start() + src_index, len * kDoubleSize);
2107       } else {
2108         DisallowHeapAllocation no_gc;
2109         heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index,
2110                            len);
2111       }
2112     }
2113     if (hole_start != hole_end) {
2114       dst_elms->FillWithHoles(hole_start, hole_end);
2115     }
2116   }
2117 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> search_value,uint32_t start_from,uint32_t length)2118   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
2119                                        Handle<JSObject> receiver,
2120                                        Handle<Object> search_value,
2121                                        uint32_t start_from, uint32_t length) {
2122     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2123     DisallowHeapAllocation no_gc;
2124     FixedArrayBase* elements_base = receiver->elements();
2125     Object* the_hole = isolate->heap()->the_hole_value();
2126     Object* undefined = isolate->heap()->undefined_value();
2127     Object* value = *search_value;
2128 
2129     // Elements beyond the capacity of the backing store treated as undefined.
2130     if (value == undefined &&
2131         static_cast<uint32_t>(elements_base->length()) < length) {
2132       return Just(true);
2133     }
2134 
2135     if (start_from >= length) return Just(false);
2136 
2137     length = std::min(static_cast<uint32_t>(elements_base->length()), length);
2138 
2139     if (!value->IsNumber()) {
2140       if (value == undefined) {
2141         // Only FAST_ELEMENTS, FAST_HOLEY_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, and
2142         // FAST_HOLEY_DOUBLE_ELEMENTS can have `undefined` as a value.
2143         if (!IsFastObjectElementsKind(Subclass::kind()) &&
2144             !IsFastHoleyElementsKind(Subclass::kind())) {
2145           return Just(false);
2146         }
2147 
2148         // Search for `undefined` or The Hole in FAST_ELEMENTS,
2149         // FAST_HOLEY_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS
2150         if (IsFastSmiOrObjectElementsKind(Subclass::kind())) {
2151           auto elements = FixedArray::cast(receiver->elements());
2152 
2153           for (uint32_t k = start_from; k < length; ++k) {
2154             Object* element_k = elements->get(k);
2155 
2156             if (IsFastHoleyElementsKind(Subclass::kind()) &&
2157                 element_k == the_hole) {
2158               return Just(true);
2159             }
2160             if (IsFastObjectElementsKind(Subclass::kind()) &&
2161                 element_k == undefined) {
2162               return Just(true);
2163             }
2164           }
2165           return Just(false);
2166         } else {
2167           // Seach for The Hole in FAST_HOLEY_DOUBLE_ELEMENTS
2168           DCHECK_EQ(Subclass::kind(), FAST_HOLEY_DOUBLE_ELEMENTS);
2169           auto elements = FixedDoubleArray::cast(receiver->elements());
2170 
2171           for (uint32_t k = start_from; k < length; ++k) {
2172             if (IsFastHoleyElementsKind(Subclass::kind()) &&
2173                 elements->is_the_hole(k)) {
2174               return Just(true);
2175             }
2176           }
2177           return Just(false);
2178         }
2179       } else if (!IsFastObjectElementsKind(Subclass::kind())) {
2180         // Search for non-number, non-Undefined value, with either
2181         // FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS or
2182         // FAST_HOLEY_DOUBLE_ELEMENTS. Guaranteed to return false, since these
2183         // elements kinds can only contain Number values or undefined.
2184         return Just(false);
2185       } else {
2186         // Search for non-number, non-Undefined value with either
2187         // FAST_ELEMENTS or FAST_HOLEY_ELEMENTS.
2188         DCHECK(IsFastObjectElementsKind(Subclass::kind()));
2189         auto elements = FixedArray::cast(receiver->elements());
2190 
2191         for (uint32_t k = start_from; k < length; ++k) {
2192           Object* element_k = elements->get(k);
2193           if (IsFastHoleyElementsKind(Subclass::kind()) &&
2194               element_k == the_hole) {
2195             continue;
2196           }
2197 
2198           if (value->SameValueZero(element_k)) return Just(true);
2199         }
2200         return Just(false);
2201       }
2202     } else {
2203       if (!value->IsNaN()) {
2204         double search_value = value->Number();
2205         if (IsFastDoubleElementsKind(Subclass::kind())) {
2206           // Search for non-NaN Number in FAST_DOUBLE_ELEMENTS or
2207           // FAST_HOLEY_DOUBLE_ELEMENTS --- Skip TheHole, and trust UCOMISD or
2208           // similar operation for result.
2209           auto elements = FixedDoubleArray::cast(receiver->elements());
2210 
2211           for (uint32_t k = start_from; k < length; ++k) {
2212             if (IsFastHoleyElementsKind(Subclass::kind()) &&
2213                 elements->is_the_hole(k)) {
2214               continue;
2215             }
2216             if (elements->get_scalar(k) == search_value) return Just(true);
2217           }
2218           return Just(false);
2219         } else {
2220           // Search for non-NaN Number in FAST_ELEMENTS, FAST_HOLEY_ELEMENTS,
2221           // FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS --- Skip non-Numbers,
2222           // and trust UCOMISD or similar operation for result
2223           auto elements = FixedArray::cast(receiver->elements());
2224 
2225           for (uint32_t k = start_from; k < length; ++k) {
2226             Object* element_k = elements->get(k);
2227             if (element_k->IsNumber() && element_k->Number() == search_value) {
2228               return Just(true);
2229             }
2230           }
2231           return Just(false);
2232         }
2233       } else {
2234         // Search for NaN --- NaN cannot be represented with Smi elements, so
2235         // abort if ElementsKind is FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS
2236         if (IsFastSmiElementsKind(Subclass::kind())) return Just(false);
2237 
2238         if (IsFastDoubleElementsKind(Subclass::kind())) {
2239           // Search for NaN in FAST_DOUBLE_ELEMENTS or
2240           // FAST_HOLEY_DOUBLE_ELEMENTS --- Skip The Hole and trust
2241           // std::isnan(elementK) for result
2242           auto elements = FixedDoubleArray::cast(receiver->elements());
2243 
2244           for (uint32_t k = start_from; k < length; ++k) {
2245             if (IsFastHoleyElementsKind(Subclass::kind()) &&
2246                 elements->is_the_hole(k)) {
2247               continue;
2248             }
2249             if (std::isnan(elements->get_scalar(k))) return Just(true);
2250           }
2251           return Just(false);
2252         } else {
2253           // Search for NaN in FAST_ELEMENTS, FAST_HOLEY_ELEMENTS,
2254           // FAST_SMI_ELEMENTS or FAST_HOLEY_SMI_ELEMENTS. Return true if
2255           // elementK->IsHeapNumber() && std::isnan(elementK->Number())
2256           DCHECK(IsFastSmiOrObjectElementsKind(Subclass::kind()));
2257           auto elements = FixedArray::cast(receiver->elements());
2258 
2259           for (uint32_t k = start_from; k < length; ++k) {
2260             if (elements->get(k)->IsNaN()) return Just(true);
2261           }
2262           return Just(false);
2263         }
2264       }
2265     }
2266   }
2267 
2268  private:
2269   // 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)2270   static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
2271                                Handle<FixedArrayBase> backing_store,
2272                                uint32_t start, uint32_t delete_count,
2273                                uint32_t add_count, uint32_t len,
2274                                uint32_t new_length) {
2275     const int move_left_count = len - delete_count - start;
2276     const int move_left_dst_index = start + add_count;
2277     Subclass::MoveElements(isolate, receiver, backing_store,
2278                            move_left_dst_index, start + delete_count,
2279                            move_left_count, new_length, len);
2280   }
2281 
2282   // 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)2283   static Handle<FixedArrayBase> SpliceGrowStep(
2284       Isolate* isolate, Handle<JSArray> receiver,
2285       Handle<FixedArrayBase> backing_store, uint32_t start,
2286       uint32_t delete_count, uint32_t add_count, uint32_t length,
2287       uint32_t new_length) {
2288     // Check we do not overflow the new_length.
2289     DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
2290     // Check if backing_store is big enough.
2291     if (new_length <= static_cast<uint32_t>(backing_store->length())) {
2292       Subclass::MoveElements(isolate, receiver, backing_store,
2293                              start + add_count, start + delete_count,
2294                              (length - delete_count - start), 0, 0);
2295       // MoveElements updates the backing_store in-place.
2296       return backing_store;
2297     }
2298     // New backing storage is needed.
2299     int capacity = JSObject::NewElementsCapacity(new_length);
2300     // Partially copy all elements up to start.
2301     Handle<FixedArrayBase> new_elms = Subclass::ConvertElementsWithCapacity(
2302         receiver, backing_store, KindTraits::Kind, capacity, start);
2303     // Copy the trailing elements after start + delete_count
2304     Subclass::CopyElementsImpl(*backing_store, start + delete_count, *new_elms,
2305                                KindTraits::Kind, start + add_count,
2306                                kPackedSizeNotKnown,
2307                                ElementsAccessor::kCopyToEndAndInitializeToHole);
2308     receiver->set_elements(*new_elms);
2309     return new_elms;
2310   }
2311 
RemoveElement(Handle<JSArray> receiver,Where remove_position)2312   static Handle<Object> RemoveElement(Handle<JSArray> receiver,
2313                                       Where remove_position) {
2314     Isolate* isolate = receiver->GetIsolate();
2315     ElementsKind kind = KindTraits::Kind;
2316     if (IsFastSmiOrObjectElementsKind(kind)) {
2317       HandleScope scope(isolate);
2318       JSObject::EnsureWritableFastElements(receiver);
2319     }
2320     Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
2321     uint32_t length =
2322         static_cast<uint32_t>(Smi::cast(receiver->length())->value());
2323     DCHECK(length > 0);
2324     int new_length = length - 1;
2325     int remove_index = remove_position == AT_START ? 0 : new_length;
2326     Handle<Object> result = Subclass::GetImpl(*backing_store, remove_index);
2327     if (remove_position == AT_START) {
2328       Subclass::MoveElements(isolate, receiver, backing_store, 0, 1, new_length,
2329                              0, 0);
2330     }
2331     Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store);
2332 
2333     if (IsHoleyElementsKind(kind) && result->IsTheHole(isolate)) {
2334       return isolate->factory()->undefined_value();
2335     }
2336     return result;
2337   }
2338 
AddArguments(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t add_size,Where add_position)2339   static uint32_t AddArguments(Handle<JSArray> receiver,
2340                                Handle<FixedArrayBase> backing_store,
2341                                Arguments* args, uint32_t add_size,
2342                                Where add_position) {
2343     uint32_t length = Smi::cast(receiver->length())->value();
2344     DCHECK(0 < add_size);
2345     uint32_t elms_len = backing_store->length();
2346     // Check we do not overflow the new_length.
2347     DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
2348     uint32_t new_length = length + add_size;
2349 
2350     if (new_length > elms_len) {
2351       // New backing storage is needed.
2352       uint32_t capacity = JSObject::NewElementsCapacity(new_length);
2353       // If we add arguments to the start we have to shift the existing objects.
2354       int copy_dst_index = add_position == AT_START ? add_size : 0;
2355       // Copy over all objects to a new backing_store.
2356       backing_store = Subclass::ConvertElementsWithCapacity(
2357           receiver, backing_store, KindTraits::Kind, capacity, 0,
2358           copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
2359       receiver->set_elements(*backing_store);
2360     } else if (add_position == AT_START) {
2361       // If the backing store has enough capacity and we add elements to the
2362       // start we have to shift the existing objects.
2363       Isolate* isolate = receiver->GetIsolate();
2364       Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0,
2365                              length, 0, 0);
2366     }
2367 
2368     int insertion_index = add_position == AT_START ? 0 : length;
2369     // Copy the arguments to the start.
2370     Subclass::CopyArguments(args, backing_store, add_size, 1, insertion_index);
2371     // Set the length.
2372     receiver->set_length(Smi::FromInt(new_length));
2373     return new_length;
2374   }
2375 
CopyArguments(Arguments * args,Handle<FixedArrayBase> dst_store,uint32_t copy_size,uint32_t src_index,uint32_t dst_index)2376   static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
2377                             uint32_t copy_size, uint32_t src_index,
2378                             uint32_t dst_index) {
2379     // Add the provided values.
2380     DisallowHeapAllocation no_gc;
2381     FixedArrayBase* raw_backing_store = *dst_store;
2382     WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
2383     for (uint32_t i = 0; i < copy_size; i++) {
2384       Object* argument = (*args)[src_index + i];
2385       DCHECK(!argument->IsTheHole(raw_backing_store->GetIsolate()));
2386       Subclass::SetImpl(raw_backing_store, dst_index + i, argument, mode);
2387     }
2388   }
2389 };
2390 
2391 template <typename Subclass, typename KindTraits>
2392 class FastSmiOrObjectElementsAccessor
2393     : public FastElementsAccessor<Subclass, KindTraits> {
2394  public:
FastSmiOrObjectElementsAccessor(const char * name)2395   explicit FastSmiOrObjectElementsAccessor(const char* name)
2396       : FastElementsAccessor<Subclass, KindTraits>(name) {}
2397 
SetImpl(Handle<JSObject> holder,uint32_t entry,Object * value)2398   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2399                              Object* value) {
2400     SetImpl(holder->elements(), entry, value);
2401   }
2402 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)2403   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2404                              Object* value) {
2405     FixedArray::cast(backing_store)->set(entry, value);
2406   }
2407 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)2408   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2409                              Object* value, WriteBarrierMode mode) {
2410     FixedArray::cast(backing_store)->set(entry, value, mode);
2411   }
2412 
GetRaw(FixedArray * backing_store,uint32_t entry)2413   static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
2414     uint32_t index = Subclass::GetIndexForEntryImpl(backing_store, entry);
2415     return backing_store->get(index);
2416   }
2417 
2418   // NOTE: this method violates the handlified function signature convention:
2419   // raw pointer parameters in the function that allocates.
2420   // See ElementsAccessor::CopyElements() for details.
2421   // This method could actually allocate if copying from double elements to
2422   // object elements.
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)2423   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2424                                FixedArrayBase* to, ElementsKind from_kind,
2425                                uint32_t to_start, int packed_size,
2426                                int copy_size) {
2427     DisallowHeapAllocation no_gc;
2428     ElementsKind to_kind = KindTraits::Kind;
2429     switch (from_kind) {
2430       case FAST_SMI_ELEMENTS:
2431       case FAST_HOLEY_SMI_ELEMENTS:
2432       case FAST_ELEMENTS:
2433       case FAST_HOLEY_ELEMENTS:
2434         CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
2435                                    to_start, copy_size);
2436         break;
2437       case FAST_DOUBLE_ELEMENTS:
2438       case FAST_HOLEY_DOUBLE_ELEMENTS: {
2439         AllowHeapAllocation allow_allocation;
2440         DCHECK(IsFastObjectElementsKind(to_kind));
2441         CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
2442         break;
2443       }
2444       case DICTIONARY_ELEMENTS:
2445         CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
2446                                        copy_size);
2447         break;
2448       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
2449       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
2450       case FAST_STRING_WRAPPER_ELEMENTS:
2451       case SLOW_STRING_WRAPPER_ELEMENTS:
2452 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
2453       TYPED_ARRAYS(TYPED_ARRAY_CASE)
2454 #undef TYPED_ARRAY_CASE
2455       // This function is currently only used for JSArrays with non-zero
2456       // length.
2457       UNREACHABLE();
2458       break;
2459       case NO_ELEMENTS:
2460         break;  // Nothing to do.
2461     }
2462   }
2463 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> search_value,uint32_t start_from,uint32_t length)2464   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2465                                          Handle<JSObject> receiver,
2466                                          Handle<Object> search_value,
2467                                          uint32_t start_from, uint32_t length) {
2468     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2469     DisallowHeapAllocation no_gc;
2470     FixedArrayBase* elements_base = receiver->elements();
2471     Object* value = *search_value;
2472 
2473     if (start_from >= length) return Just<int64_t>(-1);
2474 
2475     length = std::min(static_cast<uint32_t>(elements_base->length()), length);
2476 
2477     // Only FAST_{,HOLEY_}ELEMENTS can store non-numbers.
2478     if (!value->IsNumber() && !IsFastObjectElementsKind(Subclass::kind())) {
2479       return Just<int64_t>(-1);
2480     }
2481     // NaN can never be found by strict equality.
2482     if (value->IsNaN()) return Just<int64_t>(-1);
2483 
2484     FixedArray* elements = FixedArray::cast(receiver->elements());
2485     for (uint32_t k = start_from; k < length; ++k) {
2486       if (value->StrictEquals(elements->get(k))) return Just<int64_t>(k);
2487     }
2488     return Just<int64_t>(-1);
2489   }
2490 };
2491 
2492 
2493 class FastPackedSmiElementsAccessor
2494     : public FastSmiOrObjectElementsAccessor<
2495         FastPackedSmiElementsAccessor,
2496         ElementsKindTraits<FAST_SMI_ELEMENTS> > {
2497  public:
FastPackedSmiElementsAccessor(const char * name)2498   explicit FastPackedSmiElementsAccessor(const char* name)
2499       : FastSmiOrObjectElementsAccessor<
2500           FastPackedSmiElementsAccessor,
2501           ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
2502 };
2503 
2504 
2505 class FastHoleySmiElementsAccessor
2506     : public FastSmiOrObjectElementsAccessor<
2507         FastHoleySmiElementsAccessor,
2508         ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
2509  public:
FastHoleySmiElementsAccessor(const char * name)2510   explicit FastHoleySmiElementsAccessor(const char* name)
2511       : FastSmiOrObjectElementsAccessor<
2512           FastHoleySmiElementsAccessor,
2513           ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
2514 };
2515 
2516 
2517 class FastPackedObjectElementsAccessor
2518     : public FastSmiOrObjectElementsAccessor<
2519         FastPackedObjectElementsAccessor,
2520         ElementsKindTraits<FAST_ELEMENTS> > {
2521  public:
FastPackedObjectElementsAccessor(const char * name)2522   explicit FastPackedObjectElementsAccessor(const char* name)
2523       : FastSmiOrObjectElementsAccessor<
2524           FastPackedObjectElementsAccessor,
2525           ElementsKindTraits<FAST_ELEMENTS> >(name) {}
2526 };
2527 
2528 
2529 class FastHoleyObjectElementsAccessor
2530     : public FastSmiOrObjectElementsAccessor<
2531         FastHoleyObjectElementsAccessor,
2532         ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
2533  public:
FastHoleyObjectElementsAccessor(const char * name)2534   explicit FastHoleyObjectElementsAccessor(const char* name)
2535       : FastSmiOrObjectElementsAccessor<
2536           FastHoleyObjectElementsAccessor,
2537           ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
2538 };
2539 
2540 template <typename Subclass, typename KindTraits>
2541 class FastDoubleElementsAccessor
2542     : public FastElementsAccessor<Subclass, KindTraits> {
2543  public:
FastDoubleElementsAccessor(const char * name)2544   explicit FastDoubleElementsAccessor(const char* name)
2545       : FastElementsAccessor<Subclass, KindTraits>(name) {}
2546 
GetImpl(Handle<JSObject> holder,uint32_t entry)2547   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2548     return GetImpl(holder->elements(), entry);
2549   }
2550 
GetImpl(FixedArrayBase * backing_store,uint32_t entry)2551   static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
2552     Isolate* isolate = backing_store->GetIsolate();
2553     return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry,
2554                                  isolate);
2555   }
2556 
SetImpl(Handle<JSObject> holder,uint32_t entry,Object * value)2557   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2558                              Object* value) {
2559     SetImpl(holder->elements(), entry, value);
2560   }
2561 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)2562   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2563                              Object* value) {
2564     FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
2565   }
2566 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)2567   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2568                              Object* value, WriteBarrierMode mode) {
2569     FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
2570   }
2571 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)2572   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2573                                FixedArrayBase* to, ElementsKind from_kind,
2574                                uint32_t to_start, int packed_size,
2575                                int copy_size) {
2576     DisallowHeapAllocation no_allocation;
2577     switch (from_kind) {
2578       case FAST_SMI_ELEMENTS:
2579         CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
2580                                       packed_size, copy_size);
2581         break;
2582       case FAST_HOLEY_SMI_ELEMENTS:
2583         CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
2584         break;
2585       case FAST_DOUBLE_ELEMENTS:
2586       case FAST_HOLEY_DOUBLE_ELEMENTS:
2587         CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
2588         break;
2589       case FAST_ELEMENTS:
2590       case FAST_HOLEY_ELEMENTS:
2591         CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
2592         break;
2593       case DICTIONARY_ELEMENTS:
2594         CopyDictionaryToDoubleElements(from, from_start, to, to_start,
2595                                        copy_size);
2596         break;
2597       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
2598       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
2599       case FAST_STRING_WRAPPER_ELEMENTS:
2600       case SLOW_STRING_WRAPPER_ELEMENTS:
2601       case NO_ELEMENTS:
2602 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
2603       TYPED_ARRAYS(TYPED_ARRAY_CASE)
2604 #undef TYPED_ARRAY_CASE
2605       // This function is currently only used for JSArrays with non-zero
2606       // length.
2607       UNREACHABLE();
2608       break;
2609     }
2610   }
2611 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> search_value,uint32_t start_from,uint32_t length)2612   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2613                                          Handle<JSObject> receiver,
2614                                          Handle<Object> search_value,
2615                                          uint32_t start_from, uint32_t length) {
2616     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2617     DisallowHeapAllocation no_gc;
2618     FixedArrayBase* elements_base = receiver->elements();
2619     Object* value = *search_value;
2620 
2621     if (start_from >= length) return Just<int64_t>(-1);
2622 
2623     length = std::min(static_cast<uint32_t>(elements_base->length()), length);
2624 
2625     if (!value->IsNumber()) {
2626       return Just<int64_t>(-1);
2627     }
2628     if (value->IsNaN()) {
2629       return Just<int64_t>(-1);
2630     }
2631     double numeric_search_value = value->Number();
2632     FixedDoubleArray* elements = FixedDoubleArray::cast(receiver->elements());
2633 
2634     for (uint32_t k = start_from; k < length; ++k) {
2635       if (elements->is_the_hole(k)) {
2636         continue;
2637       }
2638       if (elements->get_scalar(k) == numeric_search_value) {
2639         return Just<int64_t>(k);
2640       }
2641     }
2642     return Just<int64_t>(-1);
2643   }
2644 };
2645 
2646 
2647 class FastPackedDoubleElementsAccessor
2648     : public FastDoubleElementsAccessor<
2649         FastPackedDoubleElementsAccessor,
2650         ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
2651  public:
FastPackedDoubleElementsAccessor(const char * name)2652   explicit FastPackedDoubleElementsAccessor(const char* name)
2653       : FastDoubleElementsAccessor<
2654           FastPackedDoubleElementsAccessor,
2655           ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
2656 };
2657 
2658 
2659 class FastHoleyDoubleElementsAccessor
2660     : public FastDoubleElementsAccessor<
2661         FastHoleyDoubleElementsAccessor,
2662         ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
2663  public:
FastHoleyDoubleElementsAccessor(const char * name)2664   explicit FastHoleyDoubleElementsAccessor(const char* name)
2665       : FastDoubleElementsAccessor<
2666           FastHoleyDoubleElementsAccessor,
2667           ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
2668 };
2669 
2670 
2671 // Super class for all external element arrays.
2672 template <ElementsKind Kind, typename ctype>
2673 class TypedElementsAccessor
2674     : public ElementsAccessorBase<TypedElementsAccessor<Kind, ctype>,
2675                                   ElementsKindTraits<Kind>> {
2676  public:
TypedElementsAccessor(const char * name)2677   explicit TypedElementsAccessor(const char* name)
2678       : ElementsAccessorBase<AccessorClass,
2679                              ElementsKindTraits<Kind> >(name) {}
2680 
2681   typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
2682   typedef TypedElementsAccessor<Kind, ctype> AccessorClass;
2683 
SetImpl(Handle<JSObject> holder,uint32_t entry,Object * value)2684   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2685                              Object* value) {
2686     SetImpl(holder->elements(), entry, value);
2687   }
2688 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)2689   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2690                              Object* value) {
2691     BackingStore::cast(backing_store)->SetValue(entry, value);
2692   }
2693 
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)2694   static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2695                              Object* value, WriteBarrierMode mode) {
2696     BackingStore::cast(backing_store)->SetValue(entry, value);
2697   }
2698 
GetImpl(Handle<JSObject> holder,uint32_t entry)2699   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2700     return GetImpl(holder->elements(), entry);
2701   }
2702 
GetImpl(FixedArrayBase * backing_store,uint32_t entry)2703   static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) {
2704     return BackingStore::get(BackingStore::cast(backing_store), entry);
2705   }
2706 
GetDetailsImpl(JSObject * holder,uint32_t entry)2707   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
2708     return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
2709   }
2710 
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)2711   static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
2712                                         uint32_t entry) {
2713     return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
2714   }
2715 
HasElementImpl(Isolate * isolate,Handle<JSObject> holder,uint32_t index,Handle<FixedArrayBase> backing_store,PropertyFilter filter)2716   static bool HasElementImpl(Isolate* isolate, Handle<JSObject> holder,
2717                              uint32_t index,
2718                              Handle<FixedArrayBase> backing_store,
2719                              PropertyFilter filter) {
2720     return index < AccessorClass::GetCapacityImpl(*holder, *backing_store);
2721   }
2722 
HasAccessorsImpl(JSObject * holder,FixedArrayBase * backing_store)2723   static bool HasAccessorsImpl(JSObject* holder,
2724                                FixedArrayBase* backing_store) {
2725     return false;
2726   }
2727 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)2728   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2729                             uint32_t length,
2730                             Handle<FixedArrayBase> backing_store) {
2731     // External arrays do not support changing their length.
2732     UNREACHABLE();
2733   }
2734 
DeleteImpl(Handle<JSObject> obj,uint32_t entry)2735   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2736     UNREACHABLE();
2737   }
2738 
GetIndexForEntryImpl(FixedArrayBase * backing_store,uint32_t entry)2739   static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
2740                                        uint32_t entry) {
2741     return entry;
2742   }
2743 
GetEntryForIndexImpl(Isolate * isolate,JSObject * holder,FixedArrayBase * backing_store,uint32_t index,PropertyFilter filter)2744   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
2745                                        FixedArrayBase* backing_store,
2746                                        uint32_t index, PropertyFilter filter) {
2747     return index < AccessorClass::GetCapacityImpl(holder, backing_store)
2748                ? index
2749                : kMaxUInt32;
2750   }
2751 
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)2752   static uint32_t GetCapacityImpl(JSObject* holder,
2753                                   FixedArrayBase* backing_store) {
2754     JSArrayBufferView* view = JSArrayBufferView::cast(holder);
2755     if (view->WasNeutered()) return 0;
2756     return backing_store->length();
2757   }
2758 
NumberOfElementsImpl(JSObject * receiver,FixedArrayBase * backing_store)2759   static uint32_t NumberOfElementsImpl(JSObject* receiver,
2760                                        FixedArrayBase* backing_store) {
2761     return AccessorClass::GetCapacityImpl(receiver, backing_store);
2762   }
2763 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)2764   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
2765                                               KeyAccumulator* accumulator,
2766                                               AddKeyConversion convert) {
2767     Handle<FixedArrayBase> elements(receiver->elements());
2768     uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements);
2769     for (uint32_t i = 0; i < length; i++) {
2770       Handle<Object> value = AccessorClass::GetImpl(*elements, i);
2771       accumulator->AddKey(value, convert);
2772     }
2773   }
2774 
CollectValuesOrEntriesImpl(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)2775   static Maybe<bool> CollectValuesOrEntriesImpl(
2776       Isolate* isolate, Handle<JSObject> object,
2777       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
2778       PropertyFilter filter) {
2779     int count = 0;
2780     if ((filter & ONLY_CONFIGURABLE) == 0) {
2781       Handle<FixedArrayBase> elements(object->elements());
2782       uint32_t length = AccessorClass::GetCapacityImpl(*object, *elements);
2783       for (uint32_t index = 0; index < length; ++index) {
2784         Handle<Object> value = AccessorClass::GetImpl(*elements, index);
2785         if (get_entries) {
2786           value = MakeEntryPair(isolate, index, value);
2787         }
2788         values_or_entries->set(count++, *value);
2789       }
2790     }
2791     *nof_items = count;
2792     return Just(true);
2793   }
2794 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)2795   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
2796                                        Handle<JSObject> receiver,
2797                                        Handle<Object> value,
2798                                        uint32_t start_from, uint32_t length) {
2799     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2800     DisallowHeapAllocation no_gc;
2801 
2802     BackingStore* elements = BackingStore::cast(receiver->elements());
2803     if (value->IsUndefined(isolate) &&
2804         length > static_cast<uint32_t>(elements->length())) {
2805       return Just(true);
2806     }
2807     if (!value->IsNumber()) return Just(false);
2808 
2809     double search_value = value->Number();
2810 
2811     if (!std::isfinite(search_value)) {
2812       // Integral types cannot represent +Inf or NaN
2813       if (AccessorClass::kind() < FLOAT32_ELEMENTS ||
2814           AccessorClass::kind() > FLOAT64_ELEMENTS) {
2815         return Just(false);
2816       }
2817     } else if (search_value < std::numeric_limits<ctype>::lowest() ||
2818                search_value > std::numeric_limits<ctype>::max()) {
2819       // Return false if value can't be represented in this space
2820       return Just(false);
2821     }
2822 
2823     // Prototype has no elements, and not searching for the hole --- limit
2824     // search to backing store length.
2825     if (static_cast<uint32_t>(elements->length()) < length) {
2826       length = elements->length();
2827     }
2828 
2829     if (!std::isnan(search_value)) {
2830       for (uint32_t k = start_from; k < length; ++k) {
2831         double element_k = elements->get_scalar(k);
2832         if (element_k == search_value) return Just(true);
2833       }
2834       return Just(false);
2835     } else {
2836       for (uint32_t k = start_from; k < length; ++k) {
2837         double element_k = elements->get_scalar(k);
2838         if (std::isnan(element_k)) return Just(true);
2839       }
2840       return Just(false);
2841     }
2842   }
2843 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,uint32_t start_from,uint32_t length)2844   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2845                                          Handle<JSObject> receiver,
2846                                          Handle<Object> value,
2847                                          uint32_t start_from, uint32_t length) {
2848     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2849     DisallowHeapAllocation no_gc;
2850 
2851     BackingStore* elements = BackingStore::cast(receiver->elements());
2852     if (!value->IsNumber()) return Just<int64_t>(-1);
2853 
2854     double search_value = value->Number();
2855 
2856     if (!std::isfinite(search_value)) {
2857       // Integral types cannot represent +Inf or NaN.
2858       if (AccessorClass::kind() < FLOAT32_ELEMENTS ||
2859           AccessorClass::kind() > FLOAT64_ELEMENTS) {
2860         return Just<int64_t>(-1);
2861       }
2862     } else if (search_value < std::numeric_limits<ctype>::lowest() ||
2863                search_value > std::numeric_limits<ctype>::max()) {
2864       // Return false if value can't be represented in this ElementsKind.
2865       return Just<int64_t>(-1);
2866     }
2867 
2868     // Prototype has no elements, and not searching for the hole --- limit
2869     // search to backing store length.
2870     if (static_cast<uint32_t>(elements->length()) < length) {
2871       length = elements->length();
2872     }
2873 
2874     if (std::isnan(search_value)) {
2875       return Just<int64_t>(-1);
2876     }
2877 
2878     ctype typed_search_value = static_cast<ctype>(search_value);
2879     if (static_cast<double>(typed_search_value) != search_value) {
2880       return Just<int64_t>(-1);  // Loss of precision.
2881     }
2882 
2883     for (uint32_t k = start_from; k < length; ++k) {
2884       ctype element_k = elements->get_scalar(k);
2885       if (element_k == typed_search_value) return Just<int64_t>(k);
2886     }
2887     return Just<int64_t>(-1);
2888   }
2889 };
2890 
2891 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
2892   typedef TypedElementsAccessor<TYPE##_ELEMENTS, ctype>        \
2893       Fixed##Type##ElementsAccessor;
2894 
2895 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
2896 #undef FIXED_ELEMENTS_ACCESSOR
2897 
2898 template <typename Subclass, typename ArgumentsAccessor, typename KindTraits>
2899 class SloppyArgumentsElementsAccessor
2900     : public ElementsAccessorBase<Subclass, KindTraits> {
2901  public:
SloppyArgumentsElementsAccessor(const char * name)2902   explicit SloppyArgumentsElementsAccessor(const char* name)
2903       : ElementsAccessorBase<Subclass, KindTraits>(name) {
2904     USE(KindTraits::Kind);
2905   }
2906 
GetImpl(Handle<JSObject> holder,uint32_t entry)2907   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
2908     return GetImpl(holder->elements(), entry);
2909   }
2910 
GetImpl(FixedArrayBase * parameters,uint32_t entry)2911   static Handle<Object> GetImpl(FixedArrayBase* parameters, uint32_t entry) {
2912     Isolate* isolate = parameters->GetIsolate();
2913     Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate);
2914     uint32_t length = parameter_map->length() - 2;
2915     if (entry < length) {
2916       DisallowHeapAllocation no_gc;
2917       Object* probe = parameter_map->get(entry + 2);
2918       Context* context = Context::cast(parameter_map->get(0));
2919       int context_entry = Smi::cast(probe)->value();
2920       DCHECK(!context->get(context_entry)->IsTheHole(isolate));
2921       return handle(context->get(context_entry), isolate);
2922     } else {
2923       // Object is not mapped, defer to the arguments.
2924       Handle<Object> result = ArgumentsAccessor::GetImpl(
2925           FixedArray::cast(parameter_map->get(1)), entry - length);
2926       // Elements of the arguments object in slow mode might be slow aliases.
2927       if (result->IsAliasedArgumentsEntry()) {
2928         DisallowHeapAllocation no_gc;
2929         AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
2930         Context* context = Context::cast(parameter_map->get(0));
2931         int context_entry = alias->aliased_context_slot();
2932         DCHECK(!context->get(context_entry)->IsTheHole(isolate));
2933         return handle(context->get(context_entry), isolate);
2934       }
2935       return result;
2936     }
2937   }
2938 
TransitionElementsKindImpl(Handle<JSObject> object,Handle<Map> map)2939   static void TransitionElementsKindImpl(Handle<JSObject> object,
2940                                          Handle<Map> map) {
2941     UNREACHABLE();
2942   }
2943 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)2944   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2945                                          uint32_t capacity) {
2946     UNREACHABLE();
2947   }
2948 
SetImpl(Handle<JSObject> holder,uint32_t entry,Object * value)2949   static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2950                              Object* value) {
2951     SetImpl(holder->elements(), entry, value);
2952   }
2953 
SetImpl(FixedArrayBase * store,uint32_t entry,Object * value)2954   static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
2955                              Object* value) {
2956     FixedArray* parameter_map = FixedArray::cast(store);
2957     uint32_t length = parameter_map->length() - 2;
2958     if (entry < length) {
2959       Object* probe = parameter_map->get(entry + 2);
2960       Context* context = Context::cast(parameter_map->get(0));
2961       int context_entry = Smi::cast(probe)->value();
2962       DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
2963       context->set(context_entry, value);
2964     } else {
2965       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2966       Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
2967       if (current->IsAliasedArgumentsEntry()) {
2968         AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
2969         Context* context = Context::cast(parameter_map->get(0));
2970         int context_entry = alias->aliased_context_slot();
2971         DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
2972         context->set(context_entry, value);
2973       } else {
2974         ArgumentsAccessor::SetImpl(arguments, entry - length, value);
2975       }
2976     }
2977   }
2978 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> parameter_map)2979   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2980                             uint32_t length,
2981                             Handle<FixedArrayBase> parameter_map) {
2982     // Sloppy arguments objects are not arrays.
2983     UNREACHABLE();
2984   }
2985 
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)2986   static uint32_t GetCapacityImpl(JSObject* holder,
2987                                   FixedArrayBase* backing_store) {
2988     FixedArray* parameter_map = FixedArray::cast(backing_store);
2989     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2990     return parameter_map->length() - 2 +
2991            ArgumentsAccessor::GetCapacityImpl(holder, arguments);
2992   }
2993 
GetMaxNumberOfEntries(JSObject * holder,FixedArrayBase * backing_store)2994   static uint32_t GetMaxNumberOfEntries(JSObject* holder,
2995                                         FixedArrayBase* backing_store) {
2996     FixedArray* parameter_map = FixedArray::cast(backing_store);
2997     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
2998     return parameter_map->length() - 2 +
2999            ArgumentsAccessor::GetMaxNumberOfEntries(holder, arguments);
3000   }
3001 
NumberOfElementsImpl(JSObject * receiver,FixedArrayBase * backing_store)3002   static uint32_t NumberOfElementsImpl(JSObject* receiver,
3003                                        FixedArrayBase* backing_store) {
3004     FixedArray* parameter_map = FixedArray::cast(backing_store);
3005     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
3006     uint32_t nof_elements = 0;
3007     uint32_t length = parameter_map->length() - 2;
3008     for (uint32_t entry = 0; entry < length; entry++) {
3009       if (HasParameterMapArg(parameter_map, entry)) nof_elements++;
3010     }
3011     return nof_elements +
3012            ArgumentsAccessor::NumberOfElementsImpl(receiver, arguments);
3013   }
3014 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)3015   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
3016                                               KeyAccumulator* accumulator,
3017                                               AddKeyConversion convert) {
3018     Isolate* isolate = accumulator->isolate();
3019     Handle<FixedArrayBase> elements(receiver->elements(), isolate);
3020     uint32_t length = GetCapacityImpl(*receiver, *elements);
3021     for (uint32_t entry = 0; entry < length; entry++) {
3022       if (!HasEntryImpl(isolate, *elements, entry)) continue;
3023       Handle<Object> value = GetImpl(*elements, entry);
3024       accumulator->AddKey(value, convert);
3025     }
3026   }
3027 
HasEntryImpl(Isolate * isolate,FixedArrayBase * parameters,uint32_t entry)3028   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* parameters,
3029                            uint32_t entry) {
3030     FixedArray* parameter_map = FixedArray::cast(parameters);
3031     uint32_t length = parameter_map->length() - 2;
3032     if (entry < length) {
3033       return HasParameterMapArg(parameter_map, entry);
3034     }
3035 
3036     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
3037     return ArgumentsAccessor::HasEntryImpl(isolate, arguments, entry - length);
3038   }
3039 
HasAccessorsImpl(JSObject * holder,FixedArrayBase * backing_store)3040   static bool HasAccessorsImpl(JSObject* holder,
3041                                FixedArrayBase* backing_store) {
3042     FixedArray* parameter_map = FixedArray::cast(backing_store);
3043     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
3044     return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
3045   }
3046 
GetIndexForEntryImpl(FixedArrayBase * parameters,uint32_t entry)3047   static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
3048                                        uint32_t entry) {
3049     FixedArray* parameter_map = FixedArray::cast(parameters);
3050     uint32_t length = parameter_map->length() - 2;
3051     if (entry < length) return entry;
3052 
3053     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3054     return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
3055   }
3056 
GetEntryForIndexImpl(Isolate * isolate,JSObject * holder,FixedArrayBase * parameters,uint32_t index,PropertyFilter filter)3057   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
3058                                        FixedArrayBase* parameters,
3059                                        uint32_t index, PropertyFilter filter) {
3060     FixedArray* parameter_map = FixedArray::cast(parameters);
3061     if (HasParameterMapArg(parameter_map, index)) return index;
3062 
3063     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3064     uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(
3065         isolate, holder, arguments, index, filter);
3066     if (entry == kMaxUInt32) return kMaxUInt32;
3067     return (parameter_map->length() - 2) + entry;
3068   }
3069 
GetDetailsImpl(JSObject * holder,uint32_t entry)3070   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
3071     FixedArray* parameter_map = FixedArray::cast(holder->elements());
3072     uint32_t length = parameter_map->length() - 2;
3073     if (entry < length) {
3074       return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
3075     }
3076     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3077     return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
3078   }
3079 
HasParameterMapArg(FixedArray * parameter_map,uint32_t index)3080   static bool HasParameterMapArg(FixedArray* parameter_map, uint32_t index) {
3081     uint32_t length = parameter_map->length() - 2;
3082     if (index >= length) return false;
3083     return !parameter_map->get(index + 2)->IsTheHole(
3084         parameter_map->GetIsolate());
3085   }
3086 
DeleteImpl(Handle<JSObject> obj,uint32_t entry)3087   static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
3088     FixedArray* parameter_map = FixedArray::cast(obj->elements());
3089     uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
3090     if (entry < length) {
3091       // TODO(kmillikin): We could check if this was the last aliased
3092       // parameter, and revert to normal elements in that case.  That
3093       // would enable GC of the context.
3094       parameter_map->set_the_hole(entry + 2);
3095     } else {
3096       Subclass::DeleteFromArguments(obj, entry - length);
3097     }
3098   }
3099 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)3100   static void CollectElementIndicesImpl(Handle<JSObject> object,
3101                                         Handle<FixedArrayBase> backing_store,
3102                                         KeyAccumulator* keys) {
3103     Isolate* isolate = keys->isolate();
3104     uint32_t nof_indices = 0;
3105     Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
3106         GetCapacityImpl(*object, *backing_store));
3107     DirectCollectElementIndicesImpl(isolate, object, backing_store,
3108                                     GetKeysConversion::kKeepNumbers,
3109                                     ENUMERABLE_STRINGS, indices, &nof_indices);
3110     SortIndices(indices, nof_indices);
3111     for (uint32_t i = 0; i < nof_indices; i++) {
3112       keys->AddKey(indices->get(i));
3113     }
3114   }
3115 
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)3116   static Handle<FixedArray> DirectCollectElementIndicesImpl(
3117       Isolate* isolate, Handle<JSObject> object,
3118       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
3119       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
3120       uint32_t insertion_index = 0) {
3121     Handle<FixedArray> parameter_map(FixedArray::cast(*backing_store), isolate);
3122     uint32_t length = parameter_map->length() - 2;
3123 
3124     for (uint32_t i = 0; i < length; ++i) {
3125       if (parameter_map->get(i + 2)->IsTheHole(isolate)) continue;
3126       if (convert == GetKeysConversion::kConvertToString) {
3127         Handle<String> index_string = isolate->factory()->Uint32ToString(i);
3128         list->set(insertion_index, *index_string);
3129       } else {
3130         list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
3131       }
3132       insertion_index++;
3133     }
3134 
3135     Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1)));
3136     return ArgumentsAccessor::DirectCollectElementIndicesImpl(
3137         isolate, object, store, convert, filter, list, nof_indices,
3138         insertion_index);
3139   }
3140 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> object,Handle<Object> value,uint32_t start_from,uint32_t length)3141   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
3142                                        Handle<JSObject> object,
3143                                        Handle<Object> value,
3144                                        uint32_t start_from, uint32_t length) {
3145     DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
3146     Handle<Map> original_map = handle(object->map(), isolate);
3147     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()),
3148                                      isolate);
3149     bool search_for_hole = value->IsUndefined(isolate);
3150 
3151     for (uint32_t k = start_from; k < length; ++k) {
3152       uint32_t entry = GetEntryForIndexImpl(isolate, *object, *parameter_map, k,
3153                                             ALL_PROPERTIES);
3154       if (entry == kMaxUInt32) {
3155         if (search_for_hole) return Just(true);
3156         continue;
3157       }
3158 
3159       Handle<Object> element_k = GetImpl(*parameter_map, entry);
3160 
3161       if (element_k->IsAccessorPair()) {
3162         LookupIterator it(isolate, object, k, LookupIterator::OWN);
3163         DCHECK(it.IsFound());
3164         DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
3165         ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
3166                                          Object::GetPropertyWithAccessor(&it),
3167                                          Nothing<bool>());
3168 
3169         if (value->SameValueZero(*element_k)) return Just(true);
3170 
3171         if (object->map() != *original_map) {
3172           // Some mutation occurred in accessor. Abort "fast" path
3173           return IncludesValueSlowPath(isolate, object, value, k + 1, length);
3174         }
3175       } else if (value->SameValueZero(*element_k)) {
3176         return Just(true);
3177       }
3178     }
3179     return Just(false);
3180   }
3181 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> object,Handle<Object> value,uint32_t start_from,uint32_t length)3182   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
3183                                          Handle<JSObject> object,
3184                                          Handle<Object> value,
3185                                          uint32_t start_from, uint32_t length) {
3186     DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
3187     Handle<Map> original_map = handle(object->map(), isolate);
3188     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()),
3189                                      isolate);
3190 
3191     for (uint32_t k = start_from; k < length; ++k) {
3192       uint32_t entry = GetEntryForIndexImpl(isolate, *object, *parameter_map, k,
3193                                             ALL_PROPERTIES);
3194       if (entry == kMaxUInt32) {
3195         continue;
3196       }
3197 
3198       Handle<Object> element_k = GetImpl(*parameter_map, entry);
3199 
3200       if (element_k->IsAccessorPair()) {
3201         LookupIterator it(isolate, object, k, LookupIterator::OWN);
3202         DCHECK(it.IsFound());
3203         DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
3204         ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
3205                                          Object::GetPropertyWithAccessor(&it),
3206                                          Nothing<int64_t>());
3207 
3208         if (value->StrictEquals(*element_k)) {
3209           return Just<int64_t>(k);
3210         }
3211 
3212         if (object->map() != *original_map) {
3213           // Some mutation occurred in accessor. Abort "fast" path.
3214           return IndexOfValueSlowPath(isolate, object, value, k + 1, length);
3215         }
3216       } else if (value->StrictEquals(*element_k)) {
3217         return Just<int64_t>(k);
3218       }
3219     }
3220     return Just<int64_t>(-1);
3221   }
3222 };
3223 
3224 
3225 class SlowSloppyArgumentsElementsAccessor
3226     : public SloppyArgumentsElementsAccessor<
3227           SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
3228           ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
3229  public:
SlowSloppyArgumentsElementsAccessor(const char * name)3230   explicit SlowSloppyArgumentsElementsAccessor(const char* name)
3231       : SloppyArgumentsElementsAccessor<
3232             SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
3233             ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
3234 
DeleteFromArguments(Handle<JSObject> obj,uint32_t entry)3235   static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
3236     Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
3237     Handle<SeededNumberDictionary> dict(
3238         SeededNumberDictionary::cast(parameter_map->get(1)));
3239     // TODO(verwaest): Remove reliance on index in Shrink.
3240     uint32_t index = GetIndexForEntryImpl(*dict, entry);
3241     Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
3242     USE(result);
3243     DCHECK(result->IsTrue(dict->GetIsolate()));
3244     Handle<FixedArray> new_elements =
3245         SeededNumberDictionary::Shrink(dict, index);
3246     parameter_map->set(1, *new_elements);
3247   }
3248 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)3249   static void AddImpl(Handle<JSObject> object, uint32_t index,
3250                       Handle<Object> value, PropertyAttributes attributes,
3251                       uint32_t new_capacity) {
3252     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
3253     Handle<FixedArrayBase> old_elements(
3254         FixedArrayBase::cast(parameter_map->get(1)));
3255     Handle<SeededNumberDictionary> dictionary =
3256         old_elements->IsSeededNumberDictionary()
3257             ? Handle<SeededNumberDictionary>::cast(old_elements)
3258             : JSObject::NormalizeElements(object);
3259     PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
3260     Handle<SeededNumberDictionary> new_dictionary =
3261         SeededNumberDictionary::AddNumberEntry(
3262             dictionary, index, value, details,
3263             object->map()->is_prototype_map());
3264     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
3265     if (*dictionary != *new_dictionary) {
3266       FixedArray::cast(object->elements())->set(1, *new_dictionary);
3267     }
3268   }
3269 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)3270   static void ReconfigureImpl(Handle<JSObject> object,
3271                               Handle<FixedArrayBase> store, uint32_t entry,
3272                               Handle<Object> value,
3273                               PropertyAttributes attributes) {
3274     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
3275     uint32_t length = parameter_map->length() - 2;
3276     Isolate* isolate = store->GetIsolate();
3277     if (entry < length) {
3278       Object* probe = parameter_map->get(entry + 2);
3279       DCHECK(!probe->IsTheHole(isolate));
3280       Context* context = Context::cast(parameter_map->get(0));
3281       int context_entry = Smi::cast(probe)->value();
3282       DCHECK(!context->get(context_entry)->IsTheHole(isolate));
3283       context->set(context_entry, *value);
3284 
3285       // Redefining attributes of an aliased element destroys fast aliasing.
3286       parameter_map->set_the_hole(entry + 2);
3287       // For elements that are still writable we re-establish slow aliasing.
3288       if ((attributes & READ_ONLY) == 0) {
3289         value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
3290       }
3291 
3292       PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
3293       Handle<SeededNumberDictionary> arguments(
3294           SeededNumberDictionary::cast(parameter_map->get(1)), isolate);
3295       arguments = SeededNumberDictionary::AddNumberEntry(
3296           arguments, entry, value, details, object->map()->is_prototype_map());
3297       // If the attributes were NONE, we would have called set rather than
3298       // reconfigure.
3299       DCHECK_NE(NONE, attributes);
3300       object->RequireSlowElements(*arguments);
3301       parameter_map->set(1, *arguments);
3302     } else {
3303       Handle<FixedArrayBase> arguments(
3304           FixedArrayBase::cast(parameter_map->get(1)), isolate);
3305       DictionaryElementsAccessor::ReconfigureImpl(
3306           object, arguments, entry - length, value, attributes);
3307     }
3308   }
3309 };
3310 
3311 
3312 class FastSloppyArgumentsElementsAccessor
3313     : public SloppyArgumentsElementsAccessor<
3314           FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
3315           ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
3316  public:
FastSloppyArgumentsElementsAccessor(const char * name)3317   explicit FastSloppyArgumentsElementsAccessor(const char* name)
3318       : SloppyArgumentsElementsAccessor<
3319             FastSloppyArgumentsElementsAccessor,
3320             FastHoleyObjectElementsAccessor,
3321             ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
3322 
GetArguments(Isolate * isolate,FixedArrayBase * backing_store)3323   static Handle<FixedArray> GetArguments(Isolate* isolate,
3324                                          FixedArrayBase* backing_store) {
3325     FixedArray* parameter_map = FixedArray::cast(backing_store);
3326     return Handle<FixedArray>(FixedArray::cast(parameter_map->get(1)), isolate);
3327   }
3328 
SliceImpl(Handle<JSObject> receiver,uint32_t start,uint32_t end)3329   static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, uint32_t start,
3330                                    uint32_t end) {
3331     Isolate* isolate = receiver->GetIsolate();
3332     uint32_t result_len = end < start ? 0u : end - start;
3333     Handle<JSArray> result_array = isolate->factory()->NewJSArray(
3334         FAST_HOLEY_ELEMENTS, result_len, result_len);
3335     DisallowHeapAllocation no_gc;
3336     FixedArray* elements = FixedArray::cast(result_array->elements());
3337     FixedArray* parameters = FixedArray::cast(receiver->elements());
3338     uint32_t insertion_index = 0;
3339     for (uint32_t i = start; i < end; i++) {
3340       uint32_t entry = GetEntryForIndexImpl(isolate, *receiver, parameters, i,
3341                                             ALL_PROPERTIES);
3342       if (entry != kMaxUInt32 && HasEntryImpl(isolate, parameters, entry)) {
3343         elements->set(insertion_index, *GetImpl(parameters, entry));
3344       } else {
3345         elements->set_the_hole(insertion_index);
3346       }
3347       insertion_index++;
3348     }
3349     return result_array;
3350   }
3351 
NormalizeImpl(Handle<JSObject> object,Handle<FixedArrayBase> elements)3352   static Handle<SeededNumberDictionary> NormalizeImpl(
3353       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
3354     Handle<FixedArray> arguments =
3355         GetArguments(elements->GetIsolate(), *elements);
3356     return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments);
3357   }
3358 
DeleteFromArguments(Handle<JSObject> obj,uint32_t entry)3359   static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
3360     Handle<FixedArray> arguments =
3361         GetArguments(obj->GetIsolate(), obj->elements());
3362     FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
3363   }
3364 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)3365   static void AddImpl(Handle<JSObject> object, uint32_t index,
3366                       Handle<Object> value, PropertyAttributes attributes,
3367                       uint32_t new_capacity) {
3368     DCHECK_EQ(NONE, attributes);
3369     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
3370     Handle<FixedArrayBase> old_elements(
3371         FixedArrayBase::cast(parameter_map->get(1)));
3372     if (old_elements->IsSeededNumberDictionary() ||
3373         static_cast<uint32_t>(old_elements->length()) < new_capacity) {
3374       GrowCapacityAndConvertImpl(object, new_capacity);
3375     }
3376     FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3377     // For fast holey objects, the entry equals the index. The code above made
3378     // sure that there's enough space to store the value. We cannot convert
3379     // index to entry explicitly since the slot still contains the hole, so the
3380     // current EntryForIndex would indicate that it is "absent" by returning
3381     // kMaxUInt32.
3382     FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
3383   }
3384 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)3385   static void ReconfigureImpl(Handle<JSObject> object,
3386                               Handle<FixedArrayBase> store, uint32_t entry,
3387                               Handle<Object> value,
3388                               PropertyAttributes attributes) {
3389     Handle<SeededNumberDictionary> dictionary =
3390         JSObject::NormalizeElements(object);
3391     FixedArray::cast(*store)->set(1, *dictionary);
3392     uint32_t length = static_cast<uint32_t>(store->length()) - 2;
3393     if (entry >= length) {
3394       entry = dictionary->FindEntry(entry - length) + length;
3395     }
3396     SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
3397                                                          value, attributes);
3398   }
3399 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)3400   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
3401                                FixedArrayBase* to, ElementsKind from_kind,
3402                                uint32_t to_start, int packed_size,
3403                                int copy_size) {
3404     DCHECK(!to->IsDictionary());
3405     if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
3406       CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
3407                                      to_start, copy_size);
3408     } else {
3409       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
3410       CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
3411                                  FAST_HOLEY_ELEMENTS, to_start, copy_size);
3412     }
3413   }
3414 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)3415   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
3416                                          uint32_t capacity) {
3417     Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
3418     Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
3419     ElementsKind from_kind = object->GetElementsKind();
3420     // This method should only be called if there's a reason to update the
3421     // elements.
3422     DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
3423            static_cast<uint32_t>(old_elements->length()) < capacity);
3424     Handle<FixedArrayBase> elements =
3425         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
3426     Handle<Map> new_map = JSObject::GetElementsTransitionMap(
3427         object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
3428     JSObject::MigrateToMap(object, new_map);
3429     parameter_map->set(1, *elements);
3430     JSObject::ValidateElements(object);
3431   }
3432 };
3433 
3434 template <typename Subclass, typename BackingStoreAccessor, typename KindTraits>
3435 class StringWrapperElementsAccessor
3436     : public ElementsAccessorBase<Subclass, KindTraits> {
3437  public:
StringWrapperElementsAccessor(const char * name)3438   explicit StringWrapperElementsAccessor(const char* name)
3439       : ElementsAccessorBase<Subclass, KindTraits>(name) {
3440     USE(KindTraits::Kind);
3441   }
3442 
GetImpl(Handle<JSObject> holder,uint32_t entry)3443   static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
3444     Isolate* isolate = holder->GetIsolate();
3445     Handle<String> string(GetString(*holder), isolate);
3446     uint32_t length = static_cast<uint32_t>(string->length());
3447     if (entry < length) {
3448       return isolate->factory()->LookupSingleCharacterStringFromCode(
3449           String::Flatten(string)->Get(entry));
3450     }
3451     return BackingStoreAccessor::GetImpl(holder, entry - length);
3452   }
3453 
GetDetailsImpl(JSObject * holder,uint32_t entry)3454   static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
3455     uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
3456     if (entry < length) {
3457       PropertyAttributes attributes =
3458           static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
3459       return PropertyDetails(attributes, v8::internal::DATA, 0,
3460                              PropertyCellType::kNoCell);
3461     }
3462     return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
3463   }
3464 
GetEntryForIndexImpl(Isolate * isolate,JSObject * holder,FixedArrayBase * backing_store,uint32_t index,PropertyFilter filter)3465   static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
3466                                        FixedArrayBase* backing_store,
3467                                        uint32_t index, PropertyFilter filter) {
3468     uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
3469     if (index < length) return index;
3470     uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl(
3471         isolate, holder, backing_store, index, filter);
3472     if (backing_store_entry == kMaxUInt32) return kMaxUInt32;
3473     DCHECK(backing_store_entry < kMaxUInt32 - length);
3474     return backing_store_entry + length;
3475   }
3476 
DeleteImpl(Handle<JSObject> holder,uint32_t entry)3477   static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) {
3478     uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
3479     if (entry < length) {
3480       return;  // String contents can't be deleted.
3481     }
3482     BackingStoreAccessor::DeleteImpl(holder, entry - length);
3483   }
3484 
SetImpl(Handle<JSObject> holder,uint32_t entry,Object * value)3485   static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) {
3486     uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
3487     if (entry < length) {
3488       return;  // String contents are read-only.
3489     }
3490     BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value);
3491   }
3492 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)3493   static void AddImpl(Handle<JSObject> object, uint32_t index,
3494                       Handle<Object> value, PropertyAttributes attributes,
3495                       uint32_t new_capacity) {
3496     DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length()));
3497     // Explicitly grow fast backing stores if needed. Dictionaries know how to
3498     // extend their capacity themselves.
3499     if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
3500         (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
3501          BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
3502              new_capacity)) {
3503       GrowCapacityAndConvertImpl(object, new_capacity);
3504     }
3505     BackingStoreAccessor::AddImpl(object, index, value, attributes,
3506                                   new_capacity);
3507   }
3508 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)3509   static void ReconfigureImpl(Handle<JSObject> object,
3510                               Handle<FixedArrayBase> store, uint32_t entry,
3511                               Handle<Object> value,
3512                               PropertyAttributes attributes) {
3513     uint32_t length = static_cast<uint32_t>(GetString(*object)->length());
3514     if (entry < length) {
3515       return;  // String contents can't be reconfigured.
3516     }
3517     BackingStoreAccessor::ReconfigureImpl(object, store, entry - length, value,
3518                                           attributes);
3519   }
3520 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)3521   static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
3522                                               KeyAccumulator* accumulator,
3523                                               AddKeyConversion convert) {
3524     Isolate* isolate = receiver->GetIsolate();
3525     Handle<String> string(GetString(*receiver), isolate);
3526     string = String::Flatten(string);
3527     uint32_t length = static_cast<uint32_t>(string->length());
3528     for (uint32_t i = 0; i < length; i++) {
3529       accumulator->AddKey(
3530           isolate->factory()->LookupSingleCharacterStringFromCode(
3531               string->Get(i)),
3532           convert);
3533     }
3534     BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
3535                                                           convert);
3536   }
3537 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)3538   static void CollectElementIndicesImpl(Handle<JSObject> object,
3539                                         Handle<FixedArrayBase> backing_store,
3540                                         KeyAccumulator* keys) {
3541     uint32_t length = GetString(*object)->length();
3542     Factory* factory = keys->isolate()->factory();
3543     for (uint32_t i = 0; i < length; i++) {
3544       keys->AddKey(factory->NewNumberFromUint(i));
3545     }
3546     BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store,
3547                                                     keys);
3548   }
3549 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)3550   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
3551                                          uint32_t capacity) {
3552     Handle<FixedArrayBase> old_elements(object->elements());
3553     ElementsKind from_kind = object->GetElementsKind();
3554     // This method should only be called if there's a reason to update the
3555     // elements.
3556     DCHECK(from_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
3557            static_cast<uint32_t>(old_elements->length()) < capacity);
3558     Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
3559                                               FAST_STRING_WRAPPER_ELEMENTS,
3560                                               capacity);
3561   }
3562 
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)3563   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
3564                                FixedArrayBase* to, ElementsKind from_kind,
3565                                uint32_t to_start, int packed_size,
3566                                int copy_size) {
3567     DCHECK(!to->IsDictionary());
3568     if (from_kind == SLOW_STRING_WRAPPER_ELEMENTS) {
3569       CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
3570                                      to_start, copy_size);
3571     } else {
3572       DCHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, from_kind);
3573       CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
3574                                  FAST_HOLEY_ELEMENTS, to_start, copy_size);
3575     }
3576   }
3577 
NumberOfElementsImpl(JSObject * object,FixedArrayBase * backing_store)3578   static uint32_t NumberOfElementsImpl(JSObject* object,
3579                                        FixedArrayBase* backing_store) {
3580     uint32_t length = GetString(object)->length();
3581     return length +
3582            BackingStoreAccessor::NumberOfElementsImpl(object, backing_store);
3583   }
3584 
3585  private:
GetString(JSObject * holder)3586   static String* GetString(JSObject* holder) {
3587     DCHECK(holder->IsJSValue());
3588     JSValue* js_value = JSValue::cast(holder);
3589     DCHECK(js_value->value()->IsString());
3590     return String::cast(js_value->value());
3591   }
3592 };
3593 
3594 class FastStringWrapperElementsAccessor
3595     : public StringWrapperElementsAccessor<
3596           FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
3597           ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
3598  public:
FastStringWrapperElementsAccessor(const char * name)3599   explicit FastStringWrapperElementsAccessor(const char* name)
3600       : StringWrapperElementsAccessor<
3601             FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
3602             ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
3603 
NormalizeImpl(Handle<JSObject> object,Handle<FixedArrayBase> elements)3604   static Handle<SeededNumberDictionary> NormalizeImpl(
3605       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
3606     return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
3607   }
3608 };
3609 
3610 class SlowStringWrapperElementsAccessor
3611     : public StringWrapperElementsAccessor<
3612           SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
3613           ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
3614  public:
SlowStringWrapperElementsAccessor(const char * name)3615   explicit SlowStringWrapperElementsAccessor(const char* name)
3616       : StringWrapperElementsAccessor<
3617             SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
3618             ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {}
3619 
HasAccessorsImpl(JSObject * holder,FixedArrayBase * backing_store)3620   static bool HasAccessorsImpl(JSObject* holder,
3621                                FixedArrayBase* backing_store) {
3622     return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
3623   }
3624 };
3625 
3626 }  // namespace
3627 
3628 
CheckArrayAbuse(Handle<JSObject> obj,const char * op,uint32_t index,bool allow_appending)3629 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
3630                      bool allow_appending) {
3631   DisallowHeapAllocation no_allocation;
3632   Object* raw_length = NULL;
3633   const char* elements_type = "array";
3634   if (obj->IsJSArray()) {
3635     JSArray* array = JSArray::cast(*obj);
3636     raw_length = array->length();
3637   } else {
3638     raw_length = Smi::FromInt(obj->elements()->length());
3639     elements_type = "object";
3640   }
3641 
3642   if (raw_length->IsNumber()) {
3643     double n = raw_length->Number();
3644     if (FastI2D(FastD2UI(n)) == n) {
3645       int32_t int32_length = DoubleToInt32(n);
3646       uint32_t compare_length = static_cast<uint32_t>(int32_length);
3647       if (allow_appending) compare_length++;
3648       if (index >= compare_length) {
3649         PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
3650                elements_type, op, elements_type, static_cast<int>(int32_length),
3651                static_cast<int>(index));
3652         TraceTopFrame(obj->GetIsolate());
3653         PrintF("]\n");
3654       }
3655     } else {
3656       PrintF("[%s elements length not integer value in ", elements_type);
3657       TraceTopFrame(obj->GetIsolate());
3658       PrintF("]\n");
3659     }
3660   } else {
3661     PrintF("[%s elements length not a number in ", elements_type);
3662     TraceTopFrame(obj->GetIsolate());
3663     PrintF("]\n");
3664   }
3665 }
3666 
3667 
ArrayConstructInitializeElements(Handle<JSArray> array,Arguments * args)3668 MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
3669                                                      Arguments* args) {
3670   if (args->length() == 0) {
3671     // Optimize the case where there are no parameters passed.
3672     JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
3673     return array;
3674 
3675   } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
3676     uint32_t length;
3677     if (!args->at<Object>(0)->ToArrayLength(&length)) {
3678       return ThrowArrayLengthRangeError(array->GetIsolate());
3679     }
3680 
3681     // Optimize the case where there is one argument and the argument is a small
3682     // smi.
3683     if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
3684       ElementsKind elements_kind = array->GetElementsKind();
3685       JSArray::Initialize(array, length, length);
3686 
3687       if (!IsFastHoleyElementsKind(elements_kind)) {
3688         elements_kind = GetHoleyElementsKind(elements_kind);
3689         JSObject::TransitionElementsKind(array, elements_kind);
3690       }
3691     } else if (length == 0) {
3692       JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
3693     } else {
3694       // Take the argument as the length.
3695       JSArray::Initialize(array, 0);
3696       JSArray::SetLength(array, length);
3697     }
3698     return array;
3699   }
3700 
3701   Factory* factory = array->GetIsolate()->factory();
3702 
3703   // Set length and elements on the array.
3704   int number_of_elements = args->length();
3705   JSObject::EnsureCanContainElements(
3706       array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
3707 
3708   // Allocate an appropriately typed elements array.
3709   ElementsKind elements_kind = array->GetElementsKind();
3710   Handle<FixedArrayBase> elms;
3711   if (IsFastDoubleElementsKind(elements_kind)) {
3712     elms = Handle<FixedArrayBase>::cast(
3713         factory->NewFixedDoubleArray(number_of_elements));
3714   } else {
3715     elms = Handle<FixedArrayBase>::cast(
3716         factory->NewFixedArrayWithHoles(number_of_elements));
3717   }
3718 
3719   // Fill in the content
3720   switch (elements_kind) {
3721     case FAST_HOLEY_SMI_ELEMENTS:
3722     case FAST_SMI_ELEMENTS: {
3723       Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
3724       for (int entry = 0; entry < number_of_elements; entry++) {
3725         smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
3726       }
3727       break;
3728     }
3729     case FAST_HOLEY_ELEMENTS:
3730     case FAST_ELEMENTS: {
3731       DisallowHeapAllocation no_gc;
3732       WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
3733       Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
3734       for (int entry = 0; entry < number_of_elements; entry++) {
3735         object_elms->set(entry, (*args)[entry], mode);
3736       }
3737       break;
3738     }
3739     case FAST_HOLEY_DOUBLE_ELEMENTS:
3740     case FAST_DOUBLE_ELEMENTS: {
3741       Handle<FixedDoubleArray> double_elms =
3742           Handle<FixedDoubleArray>::cast(elms);
3743       for (int entry = 0; entry < number_of_elements; entry++) {
3744         double_elms->set(entry, (*args)[entry]->Number());
3745       }
3746       break;
3747     }
3748     default:
3749       UNREACHABLE();
3750       break;
3751   }
3752 
3753   array->set_elements(*elms);
3754   array->set_length(Smi::FromInt(number_of_elements));
3755   return array;
3756 }
3757 
3758 
InitializeOncePerProcess()3759 void ElementsAccessor::InitializeOncePerProcess() {
3760   static ElementsAccessor* accessor_array[] = {
3761 #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
3762       ELEMENTS_LIST(ACCESSOR_ARRAY)
3763 #undef ACCESSOR_ARRAY
3764   };
3765 
3766   STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
3767                 kElementsKindCount);
3768 
3769   elements_accessors_ = accessor_array;
3770 }
3771 
3772 
TearDown()3773 void ElementsAccessor::TearDown() {
3774   if (elements_accessors_ == NULL) return;
3775 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
3776   ELEMENTS_LIST(ACCESSOR_DELETE)
3777 #undef ACCESSOR_DELETE
3778   elements_accessors_ = NULL;
3779 }
3780 
Concat(Isolate * isolate,Arguments * args,uint32_t concat_size,uint32_t result_len)3781 Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
3782                                          uint32_t concat_size,
3783                                          uint32_t result_len) {
3784   ElementsKind result_elements_kind = GetInitialFastElementsKind();
3785   bool has_raw_doubles = false;
3786   {
3787     DisallowHeapAllocation no_gc;
3788     bool is_holey = false;
3789     for (uint32_t i = 0; i < concat_size; i++) {
3790       Object* arg = (*args)[i];
3791       ElementsKind arg_kind = JSArray::cast(arg)->GetElementsKind();
3792       has_raw_doubles = has_raw_doubles || IsFastDoubleElementsKind(arg_kind);
3793       is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
3794       result_elements_kind =
3795           GetMoreGeneralElementsKind(result_elements_kind, arg_kind);
3796     }
3797     if (is_holey) {
3798       result_elements_kind = GetHoleyElementsKind(result_elements_kind);
3799     }
3800   }
3801 
3802   // If a double array is concatted into a fast elements array, the fast
3803   // elements array needs to be initialized to contain proper holes, since
3804   // boxing doubles may cause incremental marking.
3805   bool requires_double_boxing =
3806       has_raw_doubles && !IsFastDoubleElementsKind(result_elements_kind);
3807   ArrayStorageAllocationMode mode = requires_double_boxing
3808                                         ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
3809                                         : DONT_INITIALIZE_ARRAY_ELEMENTS;
3810   Handle<JSArray> result_array = isolate->factory()->NewJSArray(
3811       result_elements_kind, result_len, result_len, mode);
3812   if (result_len == 0) return result_array;
3813 
3814   uint32_t insertion_index = 0;
3815   Handle<FixedArrayBase> storage(result_array->elements(), isolate);
3816   ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind);
3817   for (uint32_t i = 0; i < concat_size; i++) {
3818     // It is crucial to keep |array| in a raw pointer form to avoid
3819     // performance degradation.
3820     JSArray* array = JSArray::cast((*args)[i]);
3821     uint32_t len = 0;
3822     array->length()->ToArrayLength(&len);
3823     if (len == 0) continue;
3824     ElementsKind from_kind = array->GetElementsKind();
3825     accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len);
3826     insertion_index += len;
3827   }
3828 
3829   DCHECK_EQ(insertion_index, result_len);
3830   return result_array;
3831 }
3832 
3833 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
3834 }  // namespace internal
3835 }  // namespace v8
3836