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/objects/elements.h"
6 
7 #include "src/common/message-template.h"
8 #include "src/execution/arguments.h"
9 #include "src/execution/frames.h"
10 #include "src/execution/isolate-inl.h"
11 #include "src/execution/protectors-inl.h"
12 #include "src/heap/factory.h"
13 #include "src/heap/heap-inl.h"  // For MaxNumberToStringCacheSize.
14 #include "src/heap/heap-write-barrier-inl.h"
15 #include "src/numbers/conversions.h"
16 #include "src/objects/arguments-inl.h"
17 #include "src/objects/hash-table-inl.h"
18 #include "src/objects/js-array-buffer-inl.h"
19 #include "src/objects/js-array-inl.h"
20 #include "src/objects/keys.h"
21 #include "src/objects/objects-inl.h"
22 #include "src/objects/slots-atomic-inl.h"
23 #include "src/objects/slots.h"
24 #include "src/utils/utils.h"
25 
26 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
27 // several abstract ElementsAccessor classes are used to allow sharing
28 // common code.
29 //
30 // Inheritance hierarchy:
31 // - ElementsAccessorBase                        (abstract)
32 //   - FastElementsAccessor                      (abstract)
33 //     - FastSmiOrObjectElementsAccessor
34 //       - FastPackedSmiElementsAccessor
35 //       - FastHoleySmiElementsAccessor
36 //       - FastPackedObjectElementsAccessor
37 //       - FastNonextensibleObjectElementsAccessor: template
38 //         - FastPackedNonextensibleObjectElementsAccessor
39 //         - FastHoleyNonextensibleObjectElementsAccessor
40 //       - FastSealedObjectElementsAccessor: template
41 //         - FastPackedSealedObjectElementsAccessor
42 //         - FastHoleySealedObjectElementsAccessor
43 //       - FastFrozenObjectElementsAccessor: template
44 //         - FastPackedFrozenObjectElementsAccessor
45 //         - FastHoleyFrozenObjectElementsAccessor
46 //       - FastHoleyObjectElementsAccessor
47 //     - FastDoubleElementsAccessor
48 //       - FastPackedDoubleElementsAccessor
49 //       - FastHoleyDoubleElementsAccessor
50 //   - TypedElementsAccessor: template, with instantiations:
51 //     - Uint8ElementsAccessor
52 //     - Int8ElementsAccessor
53 //     - Uint16ElementsAccessor
54 //     - Int16ElementsAccessor
55 //     - Uint32ElementsAccessor
56 //     - Int32ElementsAccessor
57 //     - Float32ElementsAccessor
58 //     - Float64ElementsAccessor
59 //     - Uint8ClampedElementsAccessor
60 //     - BigUint64ElementsAccessor
61 //     - BigInt64ElementsAccessor
62 //   - DictionaryElementsAccessor
63 //   - SloppyArgumentsElementsAccessor
64 //     - FastSloppyArgumentsElementsAccessor
65 //     - SlowSloppyArgumentsElementsAccessor
66 //   - StringWrapperElementsAccessor
67 //     - FastStringWrapperElementsAccessor
68 //     - SlowStringWrapperElementsAccessor
69 
70 namespace v8 {
71 namespace internal {
72 
73 namespace {
74 
75 #define RETURN_NOTHING_IF_NOT_SUCCESSFUL(call) \
76   do {                                         \
77     if (!(call)) return Nothing<bool>();       \
78   } while (false)
79 
80 #define RETURN_FAILURE_IF_NOT_SUCCESSFUL(call)          \
81   do {                                                  \
82     ExceptionStatus status_enum_result = (call);        \
83     if (!status_enum_result) return status_enum_result; \
84   } while (false)
85 
86 static const int kPackedSizeNotKnown = -1;
87 
88 enum Where { AT_START, AT_END };
89 
90 // First argument in list is the accessor class, the second argument is the
91 // accessor ElementsKind, and the third is the backing store class.  Use the
92 // fast element handler for smi-only arrays.  The implementation is currently
93 // identical.  Note that the order must match that of the ElementsKind enum for
94 // the |accessor_array[]| below to work.
95 #define ELEMENTS_LIST(V)                                                      \
96   V(FastPackedSmiElementsAccessor, PACKED_SMI_ELEMENTS, FixedArray)           \
97   V(FastHoleySmiElementsAccessor, HOLEY_SMI_ELEMENTS, FixedArray)             \
98   V(FastPackedObjectElementsAccessor, PACKED_ELEMENTS, FixedArray)            \
99   V(FastHoleyObjectElementsAccessor, HOLEY_ELEMENTS, FixedArray)              \
100   V(FastPackedDoubleElementsAccessor, PACKED_DOUBLE_ELEMENTS,                 \
101     FixedDoubleArray)                                                         \
102   V(FastHoleyDoubleElementsAccessor, HOLEY_DOUBLE_ELEMENTS, FixedDoubleArray) \
103   V(FastPackedNonextensibleObjectElementsAccessor,                            \
104     PACKED_NONEXTENSIBLE_ELEMENTS, FixedArray)                                \
105   V(FastHoleyNonextensibleObjectElementsAccessor,                             \
106     HOLEY_NONEXTENSIBLE_ELEMENTS, FixedArray)                                 \
107   V(FastPackedSealedObjectElementsAccessor, PACKED_SEALED_ELEMENTS,           \
108     FixedArray)                                                               \
109   V(FastHoleySealedObjectElementsAccessor, HOLEY_SEALED_ELEMENTS, FixedArray) \
110   V(FastPackedFrozenObjectElementsAccessor, PACKED_FROZEN_ELEMENTS,           \
111     FixedArray)                                                               \
112   V(FastHoleyFrozenObjectElementsAccessor, HOLEY_FROZEN_ELEMENTS, FixedArray) \
113   V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, NumberDictionary)        \
114   V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS,      \
115     FixedArray)                                                               \
116   V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS,      \
117     FixedArray)                                                               \
118   V(FastStringWrapperElementsAccessor, FAST_STRING_WRAPPER_ELEMENTS,          \
119     FixedArray)                                                               \
120   V(SlowStringWrapperElementsAccessor, SLOW_STRING_WRAPPER_ELEMENTS,          \
121     FixedArray)                                                               \
122   V(Uint8ElementsAccessor, UINT8_ELEMENTS, ByteArray)                         \
123   V(Int8ElementsAccessor, INT8_ELEMENTS, ByteArray)                           \
124   V(Uint16ElementsAccessor, UINT16_ELEMENTS, ByteArray)                       \
125   V(Int16ElementsAccessor, INT16_ELEMENTS, ByteArray)                         \
126   V(Uint32ElementsAccessor, UINT32_ELEMENTS, ByteArray)                       \
127   V(Int32ElementsAccessor, INT32_ELEMENTS, ByteArray)                         \
128   V(Float32ElementsAccessor, FLOAT32_ELEMENTS, ByteArray)                     \
129   V(Float64ElementsAccessor, FLOAT64_ELEMENTS, ByteArray)                     \
130   V(Uint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, ByteArray)          \
131   V(BigUint64ElementsAccessor, BIGUINT64_ELEMENTS, ByteArray)                 \
132   V(BigInt64ElementsAccessor, BIGINT64_ELEMENTS, ByteArray)
133 
134 template <ElementsKind Kind>
135 class ElementsKindTraits {
136  public:
137   using BackingStore = FixedArrayBase;
138 };
139 
140 #define ELEMENTS_TRAITS(Class, KindParam, Store)    \
141   template <>                                       \
142   class ElementsKindTraits<KindParam> {             \
143    public: /* NOLINT */                             \
144     static constexpr ElementsKind Kind = KindParam; \
145     using BackingStore = Store;                     \
146   };                                                \
147   constexpr ElementsKind ElementsKindTraits<KindParam>::Kind;
ELEMENTS_LIST(ELEMENTS_TRAITS)148 ELEMENTS_LIST(ELEMENTS_TRAITS)
149 #undef ELEMENTS_TRAITS
150 
151 V8_WARN_UNUSED_RESULT
152 MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
153   THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
154                   Object);
155 }
156 
GetWriteBarrierMode(ElementsKind kind)157 WriteBarrierMode GetWriteBarrierMode(ElementsKind kind) {
158   if (IsSmiElementsKind(kind)) return SKIP_WRITE_BARRIER;
159   if (IsDoubleElementsKind(kind)) return SKIP_WRITE_BARRIER;
160   return UPDATE_WRITE_BARRIER;
161 }
162 
163 // If kCopyToEndAndInitializeToHole is specified as the copy_size to
164 // CopyElements, it copies all of elements from source after source_start to
165 // destination array, padding any remaining uninitialized elements in the
166 // destination array with the hole.
167 constexpr int kCopyToEndAndInitializeToHole = -1;
168 
CopyObjectToObjectElements(Isolate * isolate,FixedArrayBase from_base,ElementsKind from_kind,uint32_t from_start,FixedArrayBase to_base,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)169 void CopyObjectToObjectElements(Isolate* isolate, FixedArrayBase from_base,
170                                 ElementsKind from_kind, uint32_t from_start,
171                                 FixedArrayBase to_base, ElementsKind to_kind,
172                                 uint32_t to_start, int raw_copy_size) {
173   ReadOnlyRoots roots(isolate);
174   DCHECK(to_base.map() != roots.fixed_cow_array_map());
175   DisallowHeapAllocation no_allocation;
176   int copy_size = raw_copy_size;
177   if (raw_copy_size < 0) {
178     DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size);
179     copy_size =
180         Min(from_base.length() - from_start, to_base.length() - to_start);
181     int start = to_start + copy_size;
182     int length = to_base.length() - start;
183     if (length > 0) {
184       MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start),
185                    roots.the_hole_value(), length);
186     }
187   }
188   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() &&
189          (copy_size + static_cast<int>(from_start)) <= from_base.length());
190   if (copy_size == 0) return;
191   FixedArray from = FixedArray::cast(from_base);
192   FixedArray to = FixedArray::cast(to_base);
193   DCHECK(IsSmiOrObjectElementsKind(from_kind));
194   DCHECK(IsSmiOrObjectElementsKind(to_kind));
195 
196   WriteBarrierMode write_barrier_mode =
197       (IsObjectElementsKind(from_kind) && IsObjectElementsKind(to_kind))
198           ? UPDATE_WRITE_BARRIER
199           : SKIP_WRITE_BARRIER;
200   to.CopyElements(isolate, to_start, from, from_start, copy_size,
201                   write_barrier_mode);
202 }
203 
CopyDictionaryToObjectElements(Isolate * isolate,FixedArrayBase from_base,uint32_t from_start,FixedArrayBase to_base,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)204 void CopyDictionaryToObjectElements(Isolate* isolate, FixedArrayBase from_base,
205                                     uint32_t from_start, FixedArrayBase to_base,
206                                     ElementsKind to_kind, uint32_t to_start,
207                                     int raw_copy_size) {
208   DisallowHeapAllocation no_allocation;
209   NumberDictionary from = NumberDictionary::cast(from_base);
210   int copy_size = raw_copy_size;
211   if (raw_copy_size < 0) {
212     DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size);
213     copy_size = from.max_number_key() + 1 - from_start;
214     int start = to_start + copy_size;
215     int length = to_base.length() - start;
216     if (length > 0) {
217       MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start),
218                    ReadOnlyRoots(isolate).the_hole_value(), length);
219     }
220   }
221   DCHECK(to_base != from_base);
222   DCHECK(IsSmiOrObjectElementsKind(to_kind));
223   if (copy_size == 0) return;
224   FixedArray to = FixedArray::cast(to_base);
225   uint32_t to_length = to.length();
226   if (to_start + copy_size > to_length) {
227     copy_size = to_length - to_start;
228   }
229   WriteBarrierMode write_barrier_mode = GetWriteBarrierMode(to_kind);
230   for (int i = 0; i < copy_size; i++) {
231     InternalIndex entry = from.FindEntry(isolate, i + from_start);
232     if (entry.is_found()) {
233       Object value = from.ValueAt(entry);
234       DCHECK(!value.IsTheHole(isolate));
235       to.set(i + to_start, value, write_barrier_mode);
236     } else {
237       to.set_the_hole(isolate, i + to_start);
238     }
239   }
240 }
241 
242 // NOTE: this method violates the handlified function signature convention:
243 // raw pointer parameters in the function that allocates.
244 // See ElementsAccessorBase::CopyElements() for details.
CopyDoubleToObjectElements(Isolate * isolate,FixedArrayBase from_base,uint32_t from_start,FixedArrayBase to_base,uint32_t to_start,int raw_copy_size)245 void CopyDoubleToObjectElements(Isolate* isolate, FixedArrayBase from_base,
246                                 uint32_t from_start, FixedArrayBase to_base,
247                                 uint32_t to_start, int raw_copy_size) {
248   int copy_size = raw_copy_size;
249   if (raw_copy_size < 0) {
250     DisallowHeapAllocation no_allocation;
251     DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size);
252     copy_size =
253         Min(from_base.length() - from_start, to_base.length() - to_start);
254     // Also initialize the area that will be copied over since HeapNumber
255     // allocation below can cause an incremental marking step, requiring all
256     // existing heap objects to be propertly initialized.
257     int start = to_start;
258     int length = to_base.length() - start;
259     if (length > 0) {
260       MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start),
261                    ReadOnlyRoots(isolate).the_hole_value(), length);
262     }
263   }
264 
265   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() &&
266          (copy_size + static_cast<int>(from_start)) <= from_base.length());
267   if (copy_size == 0) return;
268 
269   // From here on, the code below could actually allocate. Therefore the raw
270   // values are wrapped into handles.
271   Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
272   Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
273 
274   // Use an outer loop to not waste too much time on creating HandleScopes.
275   // On the other hand we might overflow a single handle scope depending on
276   // the copy_size.
277   int offset = 0;
278   while (offset < copy_size) {
279     HandleScope scope(isolate);
280     offset += 100;
281     for (int i = offset - 100; i < offset && i < copy_size; ++i) {
282       Handle<Object> value =
283           FixedDoubleArray::get(*from, i + from_start, isolate);
284       to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
285     }
286   }
287 }
288 
CopyDoubleToDoubleElements(FixedArrayBase from_base,uint32_t from_start,FixedArrayBase to_base,uint32_t to_start,int raw_copy_size)289 void CopyDoubleToDoubleElements(FixedArrayBase from_base, 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_EQ(kCopyToEndAndInitializeToHole, raw_copy_size);
296     copy_size =
297         Min(from_base.length() - from_start, to_base.length() - to_start);
298     for (int i = to_start + copy_size; i < to_base.length(); ++i) {
299       FixedDoubleArray::cast(to_base).set_the_hole(i);
300     }
301   }
302   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() &&
303          (copy_size + static_cast<int>(from_start)) <= from_base.length());
304   if (copy_size == 0) return;
305   FixedDoubleArray from = FixedDoubleArray::cast(from_base);
306   FixedDoubleArray to = FixedDoubleArray::cast(to_base);
307   Address to_address = to.address() + FixedDoubleArray::kHeaderSize;
308   Address from_address = from.address() + FixedDoubleArray::kHeaderSize;
309   to_address += kDoubleSize * to_start;
310   from_address += kDoubleSize * from_start;
311 #ifdef V8_COMPRESS_POINTERS
312   // TODO(ishell, v8:8875): we use CopyTagged() in order to avoid unaligned
313   // access to double values in the arrays. This will no longed be necessary
314   // once the allocations alignment issue is fixed.
315   int words_per_double = (kDoubleSize / kTaggedSize);
316   CopyTagged(to_address, from_address,
317              static_cast<size_t>(words_per_double * copy_size));
318 #else
319   int words_per_double = (kDoubleSize / kSystemPointerSize);
320   CopyWords(to_address, from_address,
321             static_cast<size_t>(words_per_double * copy_size));
322 #endif
323 }
324 
CopySmiToDoubleElements(FixedArrayBase from_base,uint32_t from_start,FixedArrayBase to_base,uint32_t to_start,int raw_copy_size)325 void CopySmiToDoubleElements(FixedArrayBase from_base, uint32_t from_start,
326                              FixedArrayBase to_base, uint32_t to_start,
327                              int raw_copy_size) {
328   DisallowHeapAllocation no_allocation;
329   int copy_size = raw_copy_size;
330   if (raw_copy_size < 0) {
331     DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size);
332     copy_size = from_base.length() - from_start;
333     for (int i = to_start + copy_size; i < to_base.length(); ++i) {
334       FixedDoubleArray::cast(to_base).set_the_hole(i);
335     }
336   }
337   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() &&
338          (copy_size + static_cast<int>(from_start)) <= from_base.length());
339   if (copy_size == 0) return;
340   FixedArray from = FixedArray::cast(from_base);
341   FixedDoubleArray to = FixedDoubleArray::cast(to_base);
342   Object the_hole = from.GetReadOnlyRoots().the_hole_value();
343   for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
344        from_start < from_end; from_start++, to_start++) {
345     Object hole_or_smi = from.get(from_start);
346     if (hole_or_smi == the_hole) {
347       to.set_the_hole(to_start);
348     } else {
349       to.set(to_start, Smi::ToInt(hole_or_smi));
350     }
351   }
352 }
353 
CopyPackedSmiToDoubleElements(FixedArrayBase from_base,uint32_t from_start,FixedArrayBase to_base,uint32_t to_start,int packed_size,int raw_copy_size)354 void CopyPackedSmiToDoubleElements(FixedArrayBase from_base,
355                                    uint32_t from_start, FixedArrayBase to_base,
356                                    uint32_t to_start, int packed_size,
357                                    int raw_copy_size) {
358   DisallowHeapAllocation no_allocation;
359   int copy_size = raw_copy_size;
360   uint32_t to_end;
361   if (raw_copy_size < 0) {
362     DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size);
363     copy_size = packed_size - from_start;
364     to_end = to_base.length();
365     for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
366       FixedDoubleArray::cast(to_base).set_the_hole(i);
367     }
368   } else {
369     to_end = to_start + static_cast<uint32_t>(copy_size);
370   }
371   DCHECK(static_cast<int>(to_end) <= to_base.length());
372   DCHECK(packed_size >= 0 && packed_size <= copy_size);
373   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() &&
374          (copy_size + static_cast<int>(from_start)) <= from_base.length());
375   if (copy_size == 0) return;
376   FixedArray from = FixedArray::cast(from_base);
377   FixedDoubleArray to = FixedDoubleArray::cast(to_base);
378   for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
379        from_start < from_end; from_start++, to_start++) {
380     Object smi = from.get(from_start);
381     DCHECK(!smi.IsTheHole());
382     to.set(to_start, Smi::ToInt(smi));
383   }
384 }
385 
CopyObjectToDoubleElements(FixedArrayBase from_base,uint32_t from_start,FixedArrayBase to_base,uint32_t to_start,int raw_copy_size)386 void CopyObjectToDoubleElements(FixedArrayBase from_base, uint32_t from_start,
387                                 FixedArrayBase to_base, uint32_t to_start,
388                                 int raw_copy_size) {
389   DisallowHeapAllocation no_allocation;
390   int copy_size = raw_copy_size;
391   if (raw_copy_size < 0) {
392     DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size);
393     copy_size = from_base.length() - from_start;
394     for (int i = to_start + copy_size; i < to_base.length(); ++i) {
395       FixedDoubleArray::cast(to_base).set_the_hole(i);
396     }
397   }
398   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() &&
399          (copy_size + static_cast<int>(from_start)) <= from_base.length());
400   if (copy_size == 0) return;
401   FixedArray from = FixedArray::cast(from_base);
402   FixedDoubleArray to = FixedDoubleArray::cast(to_base);
403   Object the_hole = from.GetReadOnlyRoots().the_hole_value();
404   for (uint32_t from_end = from_start + copy_size; from_start < from_end;
405        from_start++, to_start++) {
406     Object hole_or_object = from.get(from_start);
407     if (hole_or_object == the_hole) {
408       to.set_the_hole(to_start);
409     } else {
410       to.set(to_start, hole_or_object.Number());
411     }
412   }
413 }
414 
CopyDictionaryToDoubleElements(Isolate * isolate,FixedArrayBase from_base,uint32_t from_start,FixedArrayBase to_base,uint32_t to_start,int raw_copy_size)415 void CopyDictionaryToDoubleElements(Isolate* isolate, FixedArrayBase from_base,
416                                     uint32_t from_start, FixedArrayBase to_base,
417                                     uint32_t to_start, int raw_copy_size) {
418   DisallowHeapAllocation no_allocation;
419   NumberDictionary from = NumberDictionary::cast(from_base);
420   int copy_size = raw_copy_size;
421   if (copy_size < 0) {
422     DCHECK_EQ(kCopyToEndAndInitializeToHole, copy_size);
423     copy_size = from.max_number_key() + 1 - from_start;
424     for (int i = to_start + copy_size; i < to_base.length(); ++i) {
425       FixedDoubleArray::cast(to_base).set_the_hole(i);
426     }
427   }
428   if (copy_size == 0) return;
429   FixedDoubleArray to = FixedDoubleArray::cast(to_base);
430   uint32_t to_length = to.length();
431   if (to_start + copy_size > to_length) {
432     copy_size = to_length - to_start;
433   }
434   for (int i = 0; i < copy_size; i++) {
435     InternalIndex entry = from.FindEntry(isolate, i + from_start);
436     if (entry.is_found()) {
437       to.set(i + to_start, from.ValueAt(entry).Number());
438     } else {
439       to.set_the_hole(i + to_start);
440     }
441   }
442 }
443 
SortIndices(Isolate * isolate,Handle<FixedArray> indices,uint32_t sort_size)444 void SortIndices(Isolate* isolate, Handle<FixedArray> indices,
445                  uint32_t sort_size) {
446   // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and
447   // store operations that are safe for concurrent marking.
448   AtomicSlot start(indices->GetFirstElementAddress());
449   AtomicSlot end(start + sort_size);
450   std::sort(start, end, [isolate](Tagged_t elementA, Tagged_t elementB) {
451 #ifdef V8_COMPRESS_POINTERS
452     Object a(DecompressTaggedAny(isolate, elementA));
453     Object b(DecompressTaggedAny(isolate, elementB));
454 #else
455     Object a(elementA);
456     Object b(elementB);
457 #endif
458     if (a.IsSmi() || !a.IsUndefined(isolate)) {
459       if (!b.IsSmi() && b.IsUndefined(isolate)) {
460         return true;
461       }
462       return a.Number() < b.Number();
463     }
464     return !b.IsSmi() && b.IsUndefined(isolate);
465   });
466   isolate->heap()->WriteBarrierForRange(*indices, ObjectSlot(start),
467                                         ObjectSlot(end));
468 }
469 
IncludesValueSlowPath(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)470 Maybe<bool> IncludesValueSlowPath(Isolate* isolate, Handle<JSObject> receiver,
471                                   Handle<Object> value, size_t start_from,
472                                   size_t length) {
473   bool search_for_hole = value->IsUndefined(isolate);
474   for (size_t k = start_from; k < length; ++k) {
475     LookupIterator it(isolate, receiver, k);
476     if (!it.IsFound()) {
477       if (search_for_hole) return Just(true);
478       continue;
479     }
480     Handle<Object> element_k;
481     ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
482                                      Object::GetProperty(&it), Nothing<bool>());
483 
484     if (value->SameValueZero(*element_k)) return Just(true);
485   }
486 
487   return Just(false);
488 }
489 
IndexOfValueSlowPath(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)490 Maybe<int64_t> IndexOfValueSlowPath(Isolate* isolate, Handle<JSObject> receiver,
491                                     Handle<Object> value, size_t start_from,
492                                     size_t length) {
493   for (size_t k = start_from; k < length; ++k) {
494     LookupIterator it(isolate, receiver, k);
495     if (!it.IsFound()) {
496       continue;
497     }
498     Handle<Object> element_k;
499     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
500         isolate, element_k, Object::GetProperty(&it), Nothing<int64_t>());
501 
502     if (value->StrictEquals(*element_k)) return Just<int64_t>(k);
503   }
504 
505   return Just<int64_t>(-1);
506 }
507 
508 // The InternalElementsAccessor is a helper class to expose otherwise protected
509 // methods to its subclasses. Namely, we don't want to publicly expose methods
510 // that take an entry (instead of an index) as an argument.
511 class InternalElementsAccessor : public ElementsAccessor {
512  public:
513   InternalIndex GetEntryForIndex(Isolate* isolate, JSObject holder,
514                                  FixedArrayBase backing_store,
515                                  size_t index) override = 0;
516 
517   PropertyDetails GetDetails(JSObject holder, InternalIndex entry) override = 0;
518 };
519 
520 // Base class for element handler implementations. Contains the
521 // the common logic for objects with different ElementsKinds.
522 // Subclasses must specialize method for which the element
523 // implementation differs from the base class implementation.
524 //
525 // This class is intended to be used in the following way:
526 //
527 //   class SomeElementsAccessor :
528 //       public ElementsAccessorBase<SomeElementsAccessor,
529 //                                   BackingStoreClass> {
530 //     ...
531 //   }
532 //
533 // This is an example of the Curiously Recurring Template Pattern (see
534 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).  We use
535 // CRTP to guarantee aggressive compile time optimizations (i.e.  inlining and
536 // specialization of SomeElementsAccessor methods).
537 template <typename Subclass, typename ElementsTraitsParam>
538 class ElementsAccessorBase : public InternalElementsAccessor {
539  public:
540   ElementsAccessorBase() = default;
541 
542   using ElementsTraits = ElementsTraitsParam;
543   using BackingStore = typename ElementsTraitsParam::BackingStore;
544 
kind()545   static ElementsKind kind() { return ElementsTraits::Kind; }
546 
ValidateContents(JSObject holder,size_t length)547   static void ValidateContents(JSObject holder, size_t length) {}
548 
ValidateImpl(JSObject holder)549   static void ValidateImpl(JSObject holder) {
550     FixedArrayBase fixed_array_base = holder.elements();
551     if (!fixed_array_base.IsHeapObject()) return;
552     // Arrays that have been shifted in place can't be verified.
553     if (fixed_array_base.IsFreeSpaceOrFiller()) return;
554     size_t length = 0;
555     if (holder.IsJSArray()) {
556       Object length_obj = JSArray::cast(holder).length();
557       if (length_obj.IsSmi()) {
558         length = Smi::ToInt(length_obj);
559       }
560     } else if (holder.IsJSTypedArray()) {
561       length = JSTypedArray::cast(holder).length();
562     } else {
563       length = fixed_array_base.length();
564     }
565     Subclass::ValidateContents(holder, length);
566   }
567 
Validate(JSObject holder)568   void Validate(JSObject holder) final {
569     DisallowHeapAllocation no_gc;
570     Subclass::ValidateImpl(holder);
571   }
572 
HasElement(JSObject holder,uint32_t index,FixedArrayBase backing_store,PropertyFilter filter)573   bool HasElement(JSObject holder, uint32_t index, FixedArrayBase backing_store,
574                   PropertyFilter filter) final {
575     return Subclass::HasElementImpl(holder.GetIsolate(), holder, index,
576                                     backing_store, filter);
577   }
578 
HasElementImpl(Isolate * isolate,JSObject holder,size_t index,FixedArrayBase backing_store,PropertyFilter filter=ALL_PROPERTIES)579   static bool HasElementImpl(Isolate* isolate, JSObject holder, size_t index,
580                              FixedArrayBase backing_store,
581                              PropertyFilter filter = ALL_PROPERTIES) {
582     return Subclass::GetEntryForIndexImpl(isolate, holder, backing_store, index,
583                                           filter)
584         .is_found();
585   }
586 
HasEntry(JSObject holder,InternalIndex entry)587   bool HasEntry(JSObject holder, InternalIndex entry) final {
588     return Subclass::HasEntryImpl(holder.GetIsolate(), holder.elements(),
589                                   entry);
590   }
591 
HasEntryImpl(Isolate * isolate,FixedArrayBase backing_store,InternalIndex entry)592   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase backing_store,
593                            InternalIndex entry) {
594     UNIMPLEMENTED();
595   }
596 
HasAccessors(JSObject holder)597   bool HasAccessors(JSObject holder) final {
598     return Subclass::HasAccessorsImpl(holder, holder.elements());
599   }
600 
HasAccessorsImpl(JSObject holder,FixedArrayBase backing_store)601   static bool HasAccessorsImpl(JSObject holder, FixedArrayBase backing_store) {
602     return false;
603   }
604 
Get(Handle<JSObject> holder,InternalIndex entry)605   Handle<Object> Get(Handle<JSObject> holder, InternalIndex entry) final {
606     return Subclass::GetInternalImpl(holder, entry);
607   }
608 
GetInternalImpl(Handle<JSObject> holder,InternalIndex entry)609   static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
610                                         InternalIndex entry) {
611     return Subclass::GetImpl(holder->GetIsolate(), holder->elements(), entry);
612   }
613 
GetImpl(Isolate * isolate,FixedArrayBase backing_store,InternalIndex entry)614   static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
615                                 InternalIndex entry) {
616     return handle(BackingStore::cast(backing_store).get(entry.as_int()),
617                   isolate);
618   }
619 
Set(Handle<JSObject> holder,InternalIndex entry,Object value)620   void Set(Handle<JSObject> holder, InternalIndex entry, Object value) final {
621     Subclass::SetImpl(holder, entry, value);
622   }
623 
Reconfigure(Handle<JSObject> object,Handle<FixedArrayBase> store,InternalIndex entry,Handle<Object> value,PropertyAttributes attributes)624   void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
625                    InternalIndex entry, Handle<Object> value,
626                    PropertyAttributes attributes) final {
627     Subclass::ReconfigureImpl(object, store, entry, value, attributes);
628   }
629 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,InternalIndex entry,Handle<Object> value,PropertyAttributes attributes)630   static void ReconfigureImpl(Handle<JSObject> object,
631                               Handle<FixedArrayBase> store, InternalIndex entry,
632                               Handle<Object> value,
633                               PropertyAttributes attributes) {
634     UNREACHABLE();
635   }
636 
Add(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)637   void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
638            PropertyAttributes attributes, uint32_t new_capacity) final {
639     Subclass::AddImpl(object, index, value, attributes, new_capacity);
640   }
641 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)642   static void AddImpl(Handle<JSObject> object, uint32_t index,
643                       Handle<Object> value, PropertyAttributes attributes,
644                       uint32_t new_capacity) {
645     UNREACHABLE();
646   }
647 
Push(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t push_size)648   uint32_t Push(Handle<JSArray> receiver, BuiltinArguments* args,
649                 uint32_t push_size) final {
650     return Subclass::PushImpl(receiver, args, push_size);
651   }
652 
PushImpl(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t push_sized)653   static uint32_t PushImpl(Handle<JSArray> receiver, BuiltinArguments* args,
654                            uint32_t push_sized) {
655     UNREACHABLE();
656   }
657 
Unshift(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t unshift_size)658   uint32_t Unshift(Handle<JSArray> receiver, BuiltinArguments* args,
659                    uint32_t unshift_size) final {
660     return Subclass::UnshiftImpl(receiver, args, unshift_size);
661   }
662 
UnshiftImpl(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t unshift_size)663   static uint32_t UnshiftImpl(Handle<JSArray> receiver, BuiltinArguments* args,
664                               uint32_t unshift_size) {
665     UNREACHABLE();
666   }
667 
Pop(Handle<JSArray> receiver)668   Handle<Object> Pop(Handle<JSArray> receiver) final {
669     return Subclass::PopImpl(receiver);
670   }
671 
PopImpl(Handle<JSArray> receiver)672   static Handle<Object> PopImpl(Handle<JSArray> receiver) { UNREACHABLE(); }
673 
Shift(Handle<JSArray> receiver)674   Handle<Object> Shift(Handle<JSArray> receiver) final {
675     return Subclass::ShiftImpl(receiver);
676   }
677 
ShiftImpl(Handle<JSArray> receiver)678   static Handle<Object> ShiftImpl(Handle<JSArray> receiver) { UNREACHABLE(); }
679 
SetLength(Handle<JSArray> array,uint32_t length)680   void SetLength(Handle<JSArray> array, uint32_t length) final {
681     Subclass::SetLengthImpl(array->GetIsolate(), array, length,
682                             handle(array->elements(), array->GetIsolate()));
683   }
684 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)685   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
686                             uint32_t length,
687                             Handle<FixedArrayBase> backing_store) {
688     DCHECK(!array->SetLengthWouldNormalize(length));
689     DCHECK(IsFastElementsKind(array->GetElementsKind()));
690     uint32_t old_length = 0;
691     CHECK(array->length().ToArrayIndex(&old_length));
692 
693     if (old_length < length) {
694       ElementsKind kind = array->GetElementsKind();
695       if (!IsHoleyElementsKind(kind)) {
696         kind = GetHoleyElementsKind(kind);
697         JSObject::TransitionElementsKind(array, kind);
698       }
699     }
700 
701     // Check whether the backing store should be shrunk.
702     uint32_t capacity = backing_store->length();
703     old_length = Min(old_length, capacity);
704     if (length == 0) {
705       array->initialize_elements();
706     } else if (length <= capacity) {
707       if (IsSmiOrObjectElementsKind(kind())) {
708         JSObject::EnsureWritableFastElements(array);
709         if (array->elements() != *backing_store) {
710           backing_store = handle(array->elements(), isolate);
711         }
712       }
713       if (2 * length + JSObject::kMinAddedElementsCapacity <= capacity) {
714         // If more than half the elements won't be used, trim the array.
715         // Do not trim from short arrays to prevent frequent trimming on
716         // repeated pop operations.
717         // Leave some space to allow for subsequent push operations.
718         int elements_to_trim = length + 1 == old_length
719                                    ? (capacity - length) / 2
720                                    : capacity - length;
721         isolate->heap()->RightTrimFixedArray(*backing_store, elements_to_trim);
722         // Fill the non-trimmed elements with holes.
723         BackingStore::cast(*backing_store)
724             .FillWithHoles(length,
725                            std::min(old_length, capacity - elements_to_trim));
726       } else {
727         // Otherwise, fill the unused tail with holes.
728         BackingStore::cast(*backing_store).FillWithHoles(length, old_length);
729       }
730     } else {
731       // Check whether the backing store should be expanded.
732       capacity = Max(length, JSObject::NewElementsCapacity(capacity));
733       Subclass::GrowCapacityAndConvertImpl(array, capacity);
734     }
735 
736     array->set_length(Smi::FromInt(length));
737     JSObject::ValidateElements(*array);
738   }
739 
NumberOfElements(JSObject receiver)740   size_t NumberOfElements(JSObject receiver) final {
741     return Subclass::NumberOfElementsImpl(receiver, receiver.elements());
742   }
743 
NumberOfElementsImpl(JSObject receiver,FixedArrayBase backing_store)744   static uint32_t NumberOfElementsImpl(JSObject receiver,
745                                        FixedArrayBase backing_store) {
746     UNREACHABLE();
747   }
748 
GetMaxIndex(JSObject receiver,FixedArrayBase elements)749   static size_t GetMaxIndex(JSObject receiver, FixedArrayBase elements) {
750     if (receiver.IsJSArray()) {
751       DCHECK(JSArray::cast(receiver).length().IsSmi());
752       return static_cast<uint32_t>(
753           Smi::ToInt(JSArray::cast(receiver).length()));
754     }
755     return Subclass::GetCapacityImpl(receiver, elements);
756   }
757 
GetMaxNumberOfEntries(JSObject receiver,FixedArrayBase elements)758   static size_t GetMaxNumberOfEntries(JSObject receiver,
759                                       FixedArrayBase elements) {
760     return Subclass::GetMaxIndex(receiver, elements);
761   }
762 
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity)763   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
764       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
765       ElementsKind from_kind, uint32_t capacity) {
766     return ConvertElementsWithCapacity(object, old_elements, from_kind,
767                                        capacity, 0, 0);
768   }
769 
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity,uint32_t src_index,uint32_t dst_index)770   static Handle<FixedArrayBase> ConvertElementsWithCapacity(
771       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
772       ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
773       uint32_t dst_index) {
774     Isolate* isolate = object->GetIsolate();
775     Handle<FixedArrayBase> new_elements;
776     if (IsDoubleElementsKind(kind())) {
777       new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
778     } else {
779       new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
780     }
781 
782     int packed_size = kPackedSizeNotKnown;
783     if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
784       packed_size = Smi::ToInt(JSArray::cast(*object).length());
785     }
786 
787     Subclass::CopyElementsImpl(isolate, *old_elements, src_index, *new_elements,
788                                from_kind, dst_index, packed_size,
789                                kCopyToEndAndInitializeToHole);
790 
791     return new_elements;
792   }
793 
TransitionElementsKindImpl(Handle<JSObject> object,Handle<Map> to_map)794   static void TransitionElementsKindImpl(Handle<JSObject> object,
795                                          Handle<Map> to_map) {
796     Isolate* isolate = object->GetIsolate();
797     Handle<Map> from_map = handle(object->map(), isolate);
798     ElementsKind from_kind = from_map->elements_kind();
799     ElementsKind to_kind = to_map->elements_kind();
800     if (IsHoleyElementsKind(from_kind)) {
801       to_kind = GetHoleyElementsKind(to_kind);
802     }
803     if (from_kind != to_kind) {
804       // This method should never be called for any other case.
805       DCHECK(IsFastElementsKind(from_kind));
806       DCHECK(IsFastElementsKind(to_kind));
807       DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
808 
809       Handle<FixedArrayBase> from_elements(object->elements(), isolate);
810       if (object->elements() == ReadOnlyRoots(isolate).empty_fixed_array() ||
811           IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) {
812         // No change is needed to the elements() buffer, the transition
813         // only requires a map change.
814         JSObject::MigrateToMap(isolate, object, to_map);
815       } else {
816         DCHECK(
817             (IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
818             (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
819         uint32_t capacity = static_cast<uint32_t>(object->elements().length());
820         Handle<FixedArrayBase> elements = ConvertElementsWithCapacity(
821             object, from_elements, from_kind, capacity);
822         JSObject::SetMapAndElements(object, to_map, elements);
823       }
824       if (FLAG_trace_elements_transitions) {
825         JSObject::PrintElementsTransition(stdout, object, from_kind,
826                                           from_elements, to_kind,
827                                           handle(object->elements(), isolate));
828       }
829     }
830   }
831 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)832   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
833                                          uint32_t capacity) {
834     ElementsKind from_kind = object->GetElementsKind();
835     if (IsSmiOrObjectElementsKind(from_kind)) {
836       // Array optimizations rely on the prototype lookups of Array objects
837       // always returning undefined. If there is a store to the initial
838       // prototype object, make sure all of these optimizations are invalidated.
839       object->GetIsolate()->UpdateNoElementsProtectorOnSetLength(object);
840     }
841     Handle<FixedArrayBase> old_elements(object->elements(),
842                                         object->GetIsolate());
843     // This method should only be called if there's a reason to update the
844     // elements.
845     DCHECK(IsDoubleElementsKind(from_kind) != IsDoubleElementsKind(kind()) ||
846            IsDictionaryElementsKind(from_kind) ||
847            static_cast<uint32_t>(old_elements->length()) < capacity);
848     Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
849                                               kind(), capacity);
850   }
851 
BasicGrowCapacityAndConvertImpl(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,ElementsKind to_kind,uint32_t capacity)852   static void BasicGrowCapacityAndConvertImpl(
853       Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
854       ElementsKind from_kind, ElementsKind to_kind, uint32_t capacity) {
855     Handle<FixedArrayBase> elements =
856         ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
857 
858     if (IsHoleyElementsKind(from_kind)) {
859       to_kind = GetHoleyElementsKind(to_kind);
860     }
861     Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
862     JSObject::SetMapAndElements(object, new_map, elements);
863 
864     // Transition through the allocation site as well if present.
865     JSObject::UpdateAllocationSite(object, to_kind);
866 
867     if (FLAG_trace_elements_transitions) {
868       JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
869                                         to_kind, elements);
870     }
871   }
872 
TransitionElementsKind(Handle<JSObject> object,Handle<Map> map)873   void TransitionElementsKind(Handle<JSObject> object, Handle<Map> map) final {
874     Subclass::TransitionElementsKindImpl(object, map);
875   }
876 
GrowCapacityAndConvert(Handle<JSObject> object,uint32_t capacity)877   void GrowCapacityAndConvert(Handle<JSObject> object,
878                               uint32_t capacity) final {
879     Subclass::GrowCapacityAndConvertImpl(object, capacity);
880   }
881 
GrowCapacity(Handle<JSObject> object,uint32_t index)882   bool GrowCapacity(Handle<JSObject> object, uint32_t index) final {
883     // This function is intended to be called from optimized code. We don't
884     // want to trigger lazy deopts there, so refuse to handle cases that would.
885     if (object->map().is_prototype_map() ||
886         object->WouldConvertToSlowElements(index)) {
887       return false;
888     }
889     Handle<FixedArrayBase> old_elements(object->elements(),
890                                         object->GetIsolate());
891     uint32_t new_capacity = JSObject::NewElementsCapacity(index + 1);
892     DCHECK(static_cast<uint32_t>(old_elements->length()) < new_capacity);
893     Handle<FixedArrayBase> elements =
894         ConvertElementsWithCapacity(object, old_elements, kind(), new_capacity);
895 
896     DCHECK_EQ(object->GetElementsKind(), kind());
897     // Transition through the allocation site as well if present.
898     if (JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
899             object, kind())) {
900       return false;
901     }
902 
903     object->set_elements(*elements);
904     return true;
905   }
906 
Delete(Handle<JSObject> obj,InternalIndex entry)907   void Delete(Handle<JSObject> obj, InternalIndex entry) final {
908     Subclass::DeleteImpl(obj, entry);
909   }
910 
CopyElementsImpl(Isolate * isolate,FixedArrayBase from,uint32_t from_start,FixedArrayBase to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)911   static void CopyElementsImpl(Isolate* isolate, FixedArrayBase from,
912                                uint32_t from_start, FixedArrayBase to,
913                                ElementsKind from_kind, uint32_t to_start,
914                                int packed_size, int copy_size) {
915     UNREACHABLE();
916   }
917 
CopyElements(JSObject from_holder,uint32_t from_start,ElementsKind from_kind,Handle<FixedArrayBase> to,uint32_t to_start,int copy_size)918   void CopyElements(JSObject from_holder, uint32_t from_start,
919                     ElementsKind from_kind, Handle<FixedArrayBase> to,
920                     uint32_t to_start, int copy_size) final {
921     int packed_size = kPackedSizeNotKnown;
922     bool is_packed =
923         IsFastPackedElementsKind(from_kind) && from_holder.IsJSArray();
924     if (is_packed) {
925       packed_size = Smi::ToInt(JSArray::cast(from_holder).length());
926       if (copy_size >= 0 && packed_size > copy_size) {
927         packed_size = copy_size;
928       }
929     }
930     FixedArrayBase from = from_holder.elements();
931     // NOTE: the Subclass::CopyElementsImpl() methods
932     // violate the handlified function signature convention:
933     // raw pointer parameters in the function that allocates. This is done
934     // intentionally to avoid ArrayConcat() builtin performance degradation.
935     //
936     // Details: The idea is that allocations actually happen only in case of
937     // copying from object with fast double elements to object with object
938     // elements. In all the other cases there are no allocations performed and
939     // handle creation causes noticeable performance degradation of the builtin.
940     Subclass::CopyElementsImpl(from_holder.GetIsolate(), from, from_start, *to,
941                                from_kind, to_start, packed_size, copy_size);
942   }
943 
CopyElements(Isolate * isolate,Handle<FixedArrayBase> source,ElementsKind source_kind,Handle<FixedArrayBase> destination,int size)944   void CopyElements(Isolate* isolate, Handle<FixedArrayBase> source,
945                     ElementsKind source_kind,
946                     Handle<FixedArrayBase> destination, int size) override {
947     Subclass::CopyElementsImpl(isolate, *source, 0, *destination, source_kind,
948                                0, kPackedSizeNotKnown, size);
949   }
950 
CopyTypedArrayElementsSlice(JSTypedArray source,JSTypedArray destination,size_t start,size_t end)951   void CopyTypedArrayElementsSlice(JSTypedArray source,
952                                    JSTypedArray destination, size_t start,
953                                    size_t end) override {
954     Subclass::CopyTypedArrayElementsSliceImpl(source, destination, start, end);
955   }
956 
CopyTypedArrayElementsSliceImpl(JSTypedArray source,JSTypedArray destination,size_t start,size_t end)957   static void CopyTypedArrayElementsSliceImpl(JSTypedArray source,
958                                               JSTypedArray destination,
959                                               size_t start, size_t end) {
960     UNREACHABLE();
961   }
962 
CopyElements(Handle<Object> source,Handle<JSObject> destination,size_t length,size_t offset)963   Object CopyElements(Handle<Object> source, Handle<JSObject> destination,
964                       size_t length, size_t offset) final {
965     return Subclass::CopyElementsHandleImpl(source, destination, length,
966                                             offset);
967   }
968 
CopyElementsHandleImpl(Handle<Object> source,Handle<JSObject> destination,size_t length,size_t offset)969   static Object CopyElementsHandleImpl(Handle<Object> source,
970                                        Handle<JSObject> destination,
971                                        size_t length, size_t offset) {
972     UNREACHABLE();
973   }
974 
Normalize(Handle<JSObject> object)975   Handle<NumberDictionary> Normalize(Handle<JSObject> object) final {
976     return Subclass::NormalizeImpl(
977         object, handle(object->elements(), object->GetIsolate()));
978   }
979 
NormalizeImpl(Handle<JSObject> object,Handle<FixedArrayBase> elements)980   static Handle<NumberDictionary> NormalizeImpl(
981       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
982     UNREACHABLE();
983   }
984 
CollectValuesOrEntries(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)985   Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject> object,
986                                      Handle<FixedArray> values_or_entries,
987                                      bool get_entries, int* nof_items,
988                                      PropertyFilter filter) override {
989     return Subclass::CollectValuesOrEntriesImpl(
990         isolate, object, values_or_entries, get_entries, nof_items, filter);
991   }
992 
CollectValuesOrEntriesImpl(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)993   static Maybe<bool> CollectValuesOrEntriesImpl(
994       Isolate* isolate, Handle<JSObject> object,
995       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
996       PropertyFilter filter) {
997     DCHECK_EQ(*nof_items, 0);
998     KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
999                                ALL_PROPERTIES);
1000     RETURN_NOTHING_IF_NOT_SUCCESSFUL(Subclass::CollectElementIndicesImpl(
1001         object, handle(object->elements(), isolate), &accumulator));
1002     Handle<FixedArray> keys = accumulator.GetKeys();
1003 
1004     int count = 0;
1005     int i = 0;
1006     ElementsKind original_elements_kind = object->GetElementsKind();
1007 
1008     for (; i < keys->length(); ++i) {
1009       Handle<Object> key(keys->get(i), isolate);
1010       uint32_t index;
1011       if (!key->ToUint32(&index)) continue;
1012 
1013       DCHECK_EQ(object->GetElementsKind(), original_elements_kind);
1014       InternalIndex entry = Subclass::GetEntryForIndexImpl(
1015           isolate, *object, object->elements(), index, filter);
1016       if (entry.is_not_found()) continue;
1017       PropertyDetails details = Subclass::GetDetailsImpl(*object, entry);
1018 
1019       Handle<Object> value;
1020       if (details.kind() == kData) {
1021         value = Subclass::GetInternalImpl(object, entry);
1022       } else {
1023         // This might modify the elements and/or change the elements kind.
1024         LookupIterator it(isolate, object, index, LookupIterator::OWN);
1025         ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1026             isolate, value, Object::GetProperty(&it), Nothing<bool>());
1027       }
1028       if (get_entries) value = MakeEntryPair(isolate, index, value);
1029       values_or_entries->set(count++, *value);
1030       if (object->GetElementsKind() != original_elements_kind) break;
1031     }
1032 
1033     // Slow path caused by changes in elements kind during iteration.
1034     for (; i < keys->length(); i++) {
1035       Handle<Object> key(keys->get(i), isolate);
1036       uint32_t index;
1037       if (!key->ToUint32(&index)) continue;
1038 
1039       if (filter & ONLY_ENUMERABLE) {
1040         InternalElementsAccessor* accessor =
1041             reinterpret_cast<InternalElementsAccessor*>(
1042                 object->GetElementsAccessor());
1043         InternalIndex entry = accessor->GetEntryForIndex(
1044             isolate, *object, object->elements(), index);
1045         if (entry.is_not_found()) continue;
1046         PropertyDetails details = accessor->GetDetails(*object, entry);
1047         if (!details.IsEnumerable()) continue;
1048       }
1049 
1050       Handle<Object> value;
1051       LookupIterator it(isolate, object, index, LookupIterator::OWN);
1052       ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::GetProperty(&it),
1053                                        Nothing<bool>());
1054 
1055       if (get_entries) value = MakeEntryPair(isolate, index, value);
1056       values_or_entries->set(count++, *value);
1057     }
1058 
1059     *nof_items = count;
1060     return Just(true);
1061   }
1062 
CollectElementIndices(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)1063   V8_WARN_UNUSED_RESULT ExceptionStatus CollectElementIndices(
1064       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
1065       KeyAccumulator* keys) final {
1066     if (keys->filter() & ONLY_ALL_CAN_READ) return ExceptionStatus::kSuccess;
1067     return Subclass::CollectElementIndicesImpl(object, backing_store, keys);
1068   }
1069 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)1070   V8_WARN_UNUSED_RESULT static ExceptionStatus CollectElementIndicesImpl(
1071       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
1072       KeyAccumulator* keys) {
1073     DCHECK_NE(DICTIONARY_ELEMENTS, kind());
1074     // Non-dictionary elements can't have all-can-read accessors.
1075     size_t length = Subclass::GetMaxIndex(*object, *backing_store);
1076     PropertyFilter filter = keys->filter();
1077     Isolate* isolate = keys->isolate();
1078     Factory* factory = isolate->factory();
1079     for (size_t i = 0; i < length; i++) {
1080       if (Subclass::HasElementImpl(isolate, *object, i, *backing_store,
1081                                    filter)) {
1082         RETURN_FAILURE_IF_NOT_SUCCESSFUL(
1083             keys->AddKey(factory->NewNumberFromSize(i)));
1084       }
1085     }
1086     return ExceptionStatus::kSuccess;
1087   }
1088 
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)1089   static Handle<FixedArray> DirectCollectElementIndicesImpl(
1090       Isolate* isolate, Handle<JSObject> object,
1091       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1092       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
1093       uint32_t insertion_index = 0) {
1094     size_t length = Subclass::GetMaxIndex(*object, *backing_store);
1095     uint32_t const kMaxStringTableEntries =
1096         isolate->heap()->MaxNumberToStringCacheSize();
1097     for (size_t i = 0; i < length; i++) {
1098       if (Subclass::HasElementImpl(isolate, *object, i, *backing_store,
1099                                    filter)) {
1100         if (convert == GetKeysConversion::kConvertToString) {
1101           bool use_cache = i < kMaxStringTableEntries;
1102           Handle<String> index_string =
1103               isolate->factory()->SizeToString(i, use_cache);
1104           list->set(insertion_index, *index_string);
1105         } else {
1106           Handle<Object> number = isolate->factory()->NewNumberFromSize(i);
1107           list->set(insertion_index, *number);
1108         }
1109         insertion_index++;
1110       }
1111     }
1112     *nof_indices = insertion_index;
1113     return list;
1114   }
1115 
PrependElementIndices(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,Handle<FixedArray> keys,GetKeysConversion convert,PropertyFilter filter)1116   MaybeHandle<FixedArray> PrependElementIndices(
1117       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
1118       Handle<FixedArray> keys, GetKeysConversion convert,
1119       PropertyFilter filter) final {
1120     return Subclass::PrependElementIndicesImpl(object, backing_store, keys,
1121                                                convert, filter);
1122   }
1123 
PrependElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,Handle<FixedArray> keys,GetKeysConversion convert,PropertyFilter filter)1124   static MaybeHandle<FixedArray> PrependElementIndicesImpl(
1125       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
1126       Handle<FixedArray> keys, GetKeysConversion convert,
1127       PropertyFilter filter) {
1128     Isolate* isolate = object->GetIsolate();
1129     uint32_t nof_property_keys = keys->length();
1130     size_t initial_list_length =
1131         Subclass::GetMaxNumberOfEntries(*object, *backing_store);
1132 
1133     if (initial_list_length > FixedArray::kMaxLength - nof_property_keys) {
1134       return isolate->Throw<FixedArray>(isolate->factory()->NewRangeError(
1135           MessageTemplate::kInvalidArrayLength));
1136     }
1137     initial_list_length += nof_property_keys;
1138 
1139     // Collect the element indices into a new list.
1140     DCHECK_LE(initial_list_length, std::numeric_limits<int>::max());
1141     MaybeHandle<FixedArray> raw_array = isolate->factory()->TryNewFixedArray(
1142         static_cast<int>(initial_list_length));
1143     Handle<FixedArray> combined_keys;
1144 
1145     // If we have a holey backing store try to precisely estimate the backing
1146     // store size as a last emergency measure if we cannot allocate the big
1147     // array.
1148     if (!raw_array.ToHandle(&combined_keys)) {
1149       if (IsHoleyOrDictionaryElementsKind(kind())) {
1150         // If we overestimate the result list size we might end up in the
1151         // large-object space which doesn't free memory on shrinking the list.
1152         // Hence we try to estimate the final size for holey backing stores more
1153         // precisely here.
1154         initial_list_length =
1155             Subclass::NumberOfElementsImpl(*object, *backing_store);
1156         initial_list_length += nof_property_keys;
1157       }
1158       DCHECK_LE(initial_list_length, std::numeric_limits<int>::max());
1159       combined_keys = isolate->factory()->NewFixedArray(
1160           static_cast<int>(initial_list_length));
1161     }
1162 
1163     uint32_t nof_indices = 0;
1164     bool needs_sorting = IsDictionaryElementsKind(kind()) ||
1165                          IsSloppyArgumentsElementsKind(kind());
1166     combined_keys = Subclass::DirectCollectElementIndicesImpl(
1167         isolate, object, backing_store,
1168         needs_sorting ? GetKeysConversion::kKeepNumbers : convert, filter,
1169         combined_keys, &nof_indices);
1170 
1171     if (needs_sorting) {
1172       SortIndices(isolate, combined_keys, nof_indices);
1173       // Indices from dictionary elements should only be converted after
1174       // sorting.
1175       if (convert == GetKeysConversion::kConvertToString) {
1176         for (uint32_t i = 0; i < nof_indices; i++) {
1177           Handle<Object> index_string = isolate->factory()->Uint32ToString(
1178               combined_keys->get(i).Number());
1179           combined_keys->set(i, *index_string);
1180         }
1181       }
1182     }
1183 
1184     // Copy over the passed-in property keys.
1185     CopyObjectToObjectElements(isolate, *keys, PACKED_ELEMENTS, 0,
1186                                *combined_keys, PACKED_ELEMENTS, nof_indices,
1187                                nof_property_keys);
1188 
1189     // For holey elements and arguments we might have to shrink the collected
1190     // keys since the estimates might be off.
1191     if (IsHoleyOrDictionaryElementsKind(kind()) ||
1192         IsSloppyArgumentsElementsKind(kind())) {
1193       // Shrink combined_keys to the final size.
1194       int final_size = nof_indices + nof_property_keys;
1195       DCHECK_LE(final_size, combined_keys->length());
1196       return FixedArray::ShrinkOrEmpty(isolate, combined_keys, final_size);
1197     }
1198 
1199     return combined_keys;
1200   }
1201 
AddElementsToKeyAccumulator(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)1202   V8_WARN_UNUSED_RESULT ExceptionStatus AddElementsToKeyAccumulator(
1203       Handle<JSObject> receiver, KeyAccumulator* accumulator,
1204       AddKeyConversion convert) final {
1205     return Subclass::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
1206                                                      convert);
1207   }
1208 
GetCapacityImpl(JSObject holder,FixedArrayBase backing_store)1209   static uint32_t GetCapacityImpl(JSObject holder,
1210                                   FixedArrayBase backing_store) {
1211     return backing_store.length();
1212   }
1213 
GetCapacity(JSObject holder,FixedArrayBase backing_store)1214   size_t GetCapacity(JSObject holder, FixedArrayBase backing_store) final {
1215     return Subclass::GetCapacityImpl(holder, backing_store);
1216   }
1217 
FillImpl(Handle<JSObject> receiver,Handle<Object> obj_value,size_t start,size_t end)1218   static Object FillImpl(Handle<JSObject> receiver, Handle<Object> obj_value,
1219                          size_t start, size_t end) {
1220     UNREACHABLE();
1221   }
1222 
Fill(Handle<JSObject> receiver,Handle<Object> obj_value,size_t start,size_t end)1223   Object Fill(Handle<JSObject> receiver, Handle<Object> obj_value, size_t start,
1224               size_t end) override {
1225     return Subclass::FillImpl(receiver, obj_value, start, end);
1226   }
1227 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)1228   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1229                                        Handle<JSObject> receiver,
1230                                        Handle<Object> value, size_t start_from,
1231                                        size_t length) {
1232     return IncludesValueSlowPath(isolate, receiver, value, start_from, length);
1233   }
1234 
IncludesValue(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)1235   Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
1236                             Handle<Object> value, size_t start_from,
1237                             size_t length) final {
1238     return Subclass::IncludesValueImpl(isolate, receiver, value, start_from,
1239                                        length);
1240   }
1241 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)1242   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
1243                                          Handle<JSObject> receiver,
1244                                          Handle<Object> value,
1245                                          size_t start_from, size_t length) {
1246     return IndexOfValueSlowPath(isolate, receiver, value, start_from, length);
1247   }
1248 
IndexOfValue(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)1249   Maybe<int64_t> IndexOfValue(Isolate* isolate, Handle<JSObject> receiver,
1250                               Handle<Object> value, size_t start_from,
1251                               size_t length) final {
1252     return Subclass::IndexOfValueImpl(isolate, receiver, value, start_from,
1253                                       length);
1254   }
1255 
LastIndexOfValueImpl(Handle<JSObject> receiver,Handle<Object> value,size_t start_from)1256   static Maybe<int64_t> LastIndexOfValueImpl(Handle<JSObject> receiver,
1257                                              Handle<Object> value,
1258                                              size_t start_from) {
1259     UNREACHABLE();
1260   }
1261 
LastIndexOfValue(Handle<JSObject> receiver,Handle<Object> value,size_t start_from)1262   Maybe<int64_t> LastIndexOfValue(Handle<JSObject> receiver,
1263                                   Handle<Object> value,
1264                                   size_t start_from) final {
1265     return Subclass::LastIndexOfValueImpl(receiver, value, start_from);
1266   }
1267 
ReverseImpl(JSObject receiver)1268   static void ReverseImpl(JSObject receiver) { UNREACHABLE(); }
1269 
Reverse(JSObject receiver)1270   void Reverse(JSObject receiver) final { Subclass::ReverseImpl(receiver); }
1271 
GetEntryForIndexImpl(Isolate * isolate,JSObject holder,FixedArrayBase backing_store,size_t index,PropertyFilter filter)1272   static InternalIndex GetEntryForIndexImpl(Isolate* isolate, JSObject holder,
1273                                             FixedArrayBase backing_store,
1274                                             size_t index,
1275                                             PropertyFilter filter) {
1276     DCHECK(IsFastElementsKind(kind()) ||
1277            IsAnyNonextensibleElementsKind(kind()));
1278     size_t length = Subclass::GetMaxIndex(holder, backing_store);
1279     if (IsHoleyElementsKindForRead(kind())) {
1280       DCHECK_IMPLIES(
1281           index < length,
1282           index <= static_cast<size_t>(std::numeric_limits<int>::max()));
1283       return index < length &&
1284                      !BackingStore::cast(backing_store)
1285                           .is_the_hole(isolate, static_cast<int>(index))
1286                  ? InternalIndex(index)
1287                  : InternalIndex::NotFound();
1288     } else {
1289       return index < length ? InternalIndex(index) : InternalIndex::NotFound();
1290     }
1291   }
1292 
GetEntryForIndex(Isolate * isolate,JSObject holder,FixedArrayBase backing_store,size_t index)1293   InternalIndex GetEntryForIndex(Isolate* isolate, JSObject holder,
1294                                  FixedArrayBase backing_store,
1295                                  size_t index) final {
1296     return Subclass::GetEntryForIndexImpl(isolate, holder, backing_store, index,
1297                                           ALL_PROPERTIES);
1298   }
1299 
GetDetailsImpl(FixedArrayBase backing_store,InternalIndex entry)1300   static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
1301                                         InternalIndex entry) {
1302     return PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
1303   }
1304 
GetDetailsImpl(JSObject holder,InternalIndex entry)1305   static PropertyDetails GetDetailsImpl(JSObject holder, InternalIndex entry) {
1306     return PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
1307   }
1308 
GetDetails(JSObject holder,InternalIndex entry)1309   PropertyDetails GetDetails(JSObject holder, InternalIndex entry) final {
1310     return Subclass::GetDetailsImpl(holder, entry);
1311   }
1312 
CreateListFromArrayLike(Isolate * isolate,Handle<JSObject> object,uint32_t length)1313   Handle<FixedArray> CreateListFromArrayLike(Isolate* isolate,
1314                                              Handle<JSObject> object,
1315                                              uint32_t length) final {
1316     return Subclass::CreateListFromArrayLikeImpl(isolate, object, length);
1317   }
1318 
CreateListFromArrayLikeImpl(Isolate * isolate,Handle<JSObject> object,uint32_t length)1319   static Handle<FixedArray> CreateListFromArrayLikeImpl(Isolate* isolate,
1320                                                         Handle<JSObject> object,
1321                                                         uint32_t length) {
1322     UNREACHABLE();
1323   }
1324 
1325  private:
1326   DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
1327 };
1328 
1329 class DictionaryElementsAccessor
1330     : public ElementsAccessorBase<DictionaryElementsAccessor,
1331                                   ElementsKindTraits<DICTIONARY_ELEMENTS>> {
1332  public:
GetMaxIndex(JSObject receiver,FixedArrayBase elements)1333   static uint32_t GetMaxIndex(JSObject receiver, FixedArrayBase elements) {
1334     // We cannot properly estimate this for dictionaries.
1335     UNREACHABLE();
1336   }
1337 
GetMaxNumberOfEntries(JSObject receiver,FixedArrayBase backing_store)1338   static uint32_t GetMaxNumberOfEntries(JSObject receiver,
1339                                         FixedArrayBase backing_store) {
1340     return NumberOfElementsImpl(receiver, backing_store);
1341   }
1342 
NumberOfElementsImpl(JSObject receiver,FixedArrayBase backing_store)1343   static uint32_t NumberOfElementsImpl(JSObject receiver,
1344                                        FixedArrayBase backing_store) {
1345     NumberDictionary dict = NumberDictionary::cast(backing_store);
1346     return dict.NumberOfElements();
1347   }
1348 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)1349   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1350                             uint32_t length,
1351                             Handle<FixedArrayBase> backing_store) {
1352     Handle<NumberDictionary> dict =
1353         Handle<NumberDictionary>::cast(backing_store);
1354     uint32_t old_length = 0;
1355     CHECK(array->length().ToArrayLength(&old_length));
1356     {
1357       DisallowHeapAllocation no_gc;
1358       ReadOnlyRoots roots(isolate);
1359       if (length < old_length) {
1360         if (dict->requires_slow_elements()) {
1361           // Find last non-deletable element in range of elements to be
1362           // deleted and adjust range accordingly.
1363           for (InternalIndex entry : dict->IterateEntries()) {
1364             Object index = dict->KeyAt(entry);
1365             if (dict->IsKey(roots, index)) {
1366               uint32_t number = static_cast<uint32_t>(index.Number());
1367               if (length <= number && number < old_length) {
1368                 PropertyDetails details = dict->DetailsAt(entry);
1369                 if (!details.IsConfigurable()) length = number + 1;
1370               }
1371             }
1372           }
1373         }
1374 
1375         if (length == 0) {
1376           // Flush the backing store.
1377           array->initialize_elements();
1378         } else {
1379           // Remove elements that should be deleted.
1380           int removed_entries = 0;
1381           for (InternalIndex entry : dict->IterateEntries()) {
1382             Object index = dict->KeyAt(entry);
1383             if (dict->IsKey(roots, index)) {
1384               uint32_t number = static_cast<uint32_t>(index.Number());
1385               if (length <= number && number < old_length) {
1386                 dict->ClearEntry(entry);
1387                 removed_entries++;
1388               }
1389             }
1390           }
1391 
1392           if (removed_entries > 0) {
1393             // Update the number of elements.
1394             dict->ElementsRemoved(removed_entries);
1395           }
1396         }
1397       }
1398     }
1399 
1400     Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1401     array->set_length(*length_obj);
1402   }
1403 
CopyElementsImpl(Isolate * isolate,FixedArrayBase from,uint32_t from_start,FixedArrayBase to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)1404   static void CopyElementsImpl(Isolate* isolate, FixedArrayBase from,
1405                                uint32_t from_start, FixedArrayBase to,
1406                                ElementsKind from_kind, uint32_t to_start,
1407                                int packed_size, int copy_size) {
1408     UNREACHABLE();
1409   }
1410 
DeleteImpl(Handle<JSObject> obj,InternalIndex entry)1411   static void DeleteImpl(Handle<JSObject> obj, InternalIndex entry) {
1412     Handle<NumberDictionary> dict(NumberDictionary::cast(obj->elements()),
1413                                   obj->GetIsolate());
1414     dict = NumberDictionary::DeleteEntry(obj->GetIsolate(), dict, entry);
1415     obj->set_elements(*dict);
1416   }
1417 
HasAccessorsImpl(JSObject holder,FixedArrayBase backing_store)1418   static bool HasAccessorsImpl(JSObject holder, FixedArrayBase backing_store) {
1419     DisallowHeapAllocation no_gc;
1420     NumberDictionary dict = NumberDictionary::cast(backing_store);
1421     if (!dict.requires_slow_elements()) return false;
1422     ReadOnlyRoots roots = holder.GetReadOnlyRoots();
1423     for (InternalIndex i : dict.IterateEntries()) {
1424       Object key = dict.KeyAt(i);
1425       if (!dict.IsKey(roots, key)) continue;
1426       PropertyDetails details = dict.DetailsAt(i);
1427       if (details.kind() == kAccessor) return true;
1428     }
1429     return false;
1430   }
1431 
GetRaw(FixedArrayBase store,InternalIndex entry)1432   static Object GetRaw(FixedArrayBase store, InternalIndex entry) {
1433     NumberDictionary backing_store = NumberDictionary::cast(store);
1434     return backing_store.ValueAt(entry);
1435   }
1436 
GetImpl(Isolate * isolate,FixedArrayBase backing_store,InternalIndex entry)1437   static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
1438                                 InternalIndex entry) {
1439     return handle(GetRaw(backing_store, entry), isolate);
1440   }
1441 
SetImpl(Handle<JSObject> holder,InternalIndex entry,Object value)1442   static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
1443                              Object value) {
1444     SetImpl(holder->elements(), entry, value);
1445   }
1446 
SetImpl(FixedArrayBase backing_store,InternalIndex entry,Object value)1447   static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
1448                              Object value) {
1449     NumberDictionary::cast(backing_store).ValueAtPut(entry, value);
1450   }
1451 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,InternalIndex entry,Handle<Object> value,PropertyAttributes attributes)1452   static void ReconfigureImpl(Handle<JSObject> object,
1453                               Handle<FixedArrayBase> store, InternalIndex entry,
1454                               Handle<Object> value,
1455                               PropertyAttributes attributes) {
1456     NumberDictionary dictionary = NumberDictionary::cast(*store);
1457     if (attributes != NONE) object->RequireSlowElements(dictionary);
1458     dictionary.ValueAtPut(entry, *value);
1459     PropertyDetails details = dictionary.DetailsAt(entry);
1460     details = PropertyDetails(kData, attributes, PropertyCellType::kNoCell,
1461                               details.dictionary_index());
1462 
1463     dictionary.DetailsAtPut(entry, details);
1464   }
1465 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)1466   static void AddImpl(Handle<JSObject> object, uint32_t index,
1467                       Handle<Object> value, PropertyAttributes attributes,
1468                       uint32_t new_capacity) {
1469     PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
1470     Handle<NumberDictionary> dictionary =
1471         object->HasFastElements() || object->HasFastStringWrapperElements()
1472             ? JSObject::NormalizeElements(object)
1473             : handle(NumberDictionary::cast(object->elements()),
1474                      object->GetIsolate());
1475     Handle<NumberDictionary> new_dictionary = NumberDictionary::Add(
1476         object->GetIsolate(), dictionary, index, value, details);
1477     new_dictionary->UpdateMaxNumberKey(index, object);
1478     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1479     if (dictionary.is_identical_to(new_dictionary)) return;
1480     object->set_elements(*new_dictionary);
1481   }
1482 
HasEntryImpl(Isolate * isolate,FixedArrayBase store,InternalIndex entry)1483   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase store,
1484                            InternalIndex entry) {
1485     DisallowHeapAllocation no_gc;
1486     NumberDictionary dict = NumberDictionary::cast(store);
1487     Object index = dict.KeyAt(entry);
1488     return !index.IsTheHole(isolate);
1489   }
1490 
GetEntryForIndexImpl(Isolate * isolate,JSObject holder,FixedArrayBase store,size_t index,PropertyFilter filter)1491   static InternalIndex GetEntryForIndexImpl(Isolate* isolate, JSObject holder,
1492                                             FixedArrayBase store, size_t index,
1493                                             PropertyFilter filter) {
1494     DisallowHeapAllocation no_gc;
1495     NumberDictionary dictionary = NumberDictionary::cast(store);
1496     DCHECK_LE(index, std::numeric_limits<uint32_t>::max());
1497     InternalIndex entry =
1498         dictionary.FindEntry(isolate, static_cast<uint32_t>(index));
1499     if (entry.is_not_found()) return entry;
1500 
1501     if (filter != ALL_PROPERTIES) {
1502       PropertyDetails details = dictionary.DetailsAt(entry);
1503       PropertyAttributes attr = details.attributes();
1504       if ((attr & filter) != 0) return InternalIndex::NotFound();
1505     }
1506     return entry;
1507   }
1508 
GetDetailsImpl(JSObject holder,InternalIndex entry)1509   static PropertyDetails GetDetailsImpl(JSObject holder, InternalIndex entry) {
1510     return GetDetailsImpl(holder.elements(), entry);
1511   }
1512 
GetDetailsImpl(FixedArrayBase backing_store,InternalIndex entry)1513   static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
1514                                         InternalIndex entry) {
1515     return NumberDictionary::cast(backing_store).DetailsAt(entry);
1516   }
1517 
FilterKey(Handle<NumberDictionary> dictionary,InternalIndex entry,Object raw_key,PropertyFilter filter)1518   static uint32_t FilterKey(Handle<NumberDictionary> dictionary,
1519                             InternalIndex entry, Object raw_key,
1520                             PropertyFilter filter) {
1521     DCHECK(raw_key.IsNumber());
1522     DCHECK_LE(raw_key.Number(), kMaxUInt32);
1523     PropertyDetails details = dictionary->DetailsAt(entry);
1524     PropertyAttributes attr = details.attributes();
1525     if ((attr & filter) != 0) return kMaxUInt32;
1526     return static_cast<uint32_t>(raw_key.Number());
1527   }
1528 
GetKeyForEntryImpl(Isolate * isolate,Handle<NumberDictionary> dictionary,InternalIndex entry,PropertyFilter filter)1529   static uint32_t GetKeyForEntryImpl(Isolate* isolate,
1530                                      Handle<NumberDictionary> dictionary,
1531                                      InternalIndex entry,
1532                                      PropertyFilter filter) {
1533     DisallowHeapAllocation no_gc;
1534     Object raw_key = dictionary->KeyAt(entry);
1535     if (!dictionary->IsKey(ReadOnlyRoots(isolate), raw_key)) return kMaxUInt32;
1536     return FilterKey(dictionary, entry, raw_key, filter);
1537   }
1538 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)1539   V8_WARN_UNUSED_RESULT static ExceptionStatus CollectElementIndicesImpl(
1540       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
1541       KeyAccumulator* keys) {
1542     if (keys->filter() & SKIP_STRINGS) return ExceptionStatus::kSuccess;
1543     Isolate* isolate = keys->isolate();
1544     Handle<NumberDictionary> dictionary =
1545         Handle<NumberDictionary>::cast(backing_store);
1546     Handle<FixedArray> elements = isolate->factory()->NewFixedArray(
1547         GetMaxNumberOfEntries(*object, *backing_store));
1548     int insertion_index = 0;
1549     PropertyFilter filter = keys->filter();
1550     ReadOnlyRoots roots(isolate);
1551     for (InternalIndex i : dictionary->IterateEntries()) {
1552       AllowHeapAllocation allow_gc;
1553       Object raw_key = dictionary->KeyAt(i);
1554       if (!dictionary->IsKey(roots, raw_key)) continue;
1555       uint32_t key = FilterKey(dictionary, i, raw_key, filter);
1556       if (key == kMaxUInt32) {
1557         // This might allocate, but {raw_key} is not used afterwards.
1558         keys->AddShadowingKey(raw_key, &allow_gc);
1559         continue;
1560       }
1561       elements->set(insertion_index, raw_key);
1562       insertion_index++;
1563     }
1564     SortIndices(isolate, elements, insertion_index);
1565     for (int i = 0; i < insertion_index; i++) {
1566       RETURN_FAILURE_IF_NOT_SUCCESSFUL(keys->AddKey(elements->get(i)));
1567     }
1568     return ExceptionStatus::kSuccess;
1569   }
1570 
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)1571   static Handle<FixedArray> DirectCollectElementIndicesImpl(
1572       Isolate* isolate, Handle<JSObject> object,
1573       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1574       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
1575       uint32_t insertion_index = 0) {
1576     if (filter & SKIP_STRINGS) return list;
1577     if (filter & ONLY_ALL_CAN_READ) return list;
1578 
1579     Handle<NumberDictionary> dictionary =
1580         Handle<NumberDictionary>::cast(backing_store);
1581     for (InternalIndex i : dictionary->IterateEntries()) {
1582       uint32_t key = GetKeyForEntryImpl(isolate, dictionary, i, filter);
1583       if (key == kMaxUInt32) continue;
1584       Handle<Object> index = isolate->factory()->NewNumberFromUint(key);
1585       list->set(insertion_index, *index);
1586       insertion_index++;
1587     }
1588     *nof_indices = insertion_index;
1589     return list;
1590   }
1591 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)1592   V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
1593       Handle<JSObject> receiver, KeyAccumulator* accumulator,
1594       AddKeyConversion convert) {
1595     Isolate* isolate = accumulator->isolate();
1596     Handle<NumberDictionary> dictionary(
1597         NumberDictionary::cast(receiver->elements()), isolate);
1598     ReadOnlyRoots roots(isolate);
1599     for (InternalIndex i : dictionary->IterateEntries()) {
1600       Object k = dictionary->KeyAt(i);
1601       if (!dictionary->IsKey(roots, k)) continue;
1602       Object value = dictionary->ValueAt(i);
1603       DCHECK(!value.IsTheHole(isolate));
1604       DCHECK(!value.IsAccessorPair());
1605       DCHECK(!value.IsAccessorInfo());
1606       RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(value, convert));
1607     }
1608     return ExceptionStatus::kSuccess;
1609   }
1610 
IncludesValueFastPath(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length,Maybe<bool> * result)1611   static bool IncludesValueFastPath(Isolate* isolate, Handle<JSObject> receiver,
1612                                     Handle<Object> value, size_t start_from,
1613                                     size_t length, Maybe<bool>* result) {
1614     DisallowHeapAllocation no_gc;
1615     NumberDictionary dictionary = NumberDictionary::cast(receiver->elements());
1616     Object the_hole = ReadOnlyRoots(isolate).the_hole_value();
1617     Object undefined = ReadOnlyRoots(isolate).undefined_value();
1618 
1619     // Scan for accessor properties. If accessors are present, then elements
1620     // must be accessed in order via the slow path.
1621     bool found = false;
1622     for (InternalIndex i : dictionary.IterateEntries()) {
1623       Object k = dictionary.KeyAt(i);
1624       if (k == the_hole) continue;
1625       if (k == undefined) continue;
1626 
1627       uint32_t index;
1628       if (!k.ToArrayIndex(&index) || index < start_from || index >= length) {
1629         continue;
1630       }
1631 
1632       if (dictionary.DetailsAt(i).kind() == kAccessor) {
1633         // Restart from beginning in slow path, otherwise we may observably
1634         // access getters out of order
1635         return false;
1636       } else if (!found) {
1637         Object element_k = dictionary.ValueAt(i);
1638         if (value->SameValueZero(element_k)) found = true;
1639       }
1640     }
1641 
1642     *result = Just(found);
1643     return true;
1644   }
1645 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)1646   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1647                                        Handle<JSObject> receiver,
1648                                        Handle<Object> value, size_t start_from,
1649                                        size_t length) {
1650     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
1651     bool search_for_hole = value->IsUndefined(isolate);
1652 
1653     if (!search_for_hole) {
1654       Maybe<bool> result = Nothing<bool>();
1655       if (DictionaryElementsAccessor::IncludesValueFastPath(
1656               isolate, receiver, value, start_from, length, &result)) {
1657         return result;
1658       }
1659     }
1660     ElementsKind original_elements_kind = receiver->GetElementsKind();
1661     USE(original_elements_kind);
1662     Handle<NumberDictionary> dictionary(
1663         NumberDictionary::cast(receiver->elements()), isolate);
1664     // Iterate through the entire range, as accessing elements out of order is
1665     // observable.
1666     for (size_t k = start_from; k < length; ++k) {
1667       DCHECK_EQ(receiver->GetElementsKind(), original_elements_kind);
1668       InternalIndex entry =
1669           dictionary->FindEntry(isolate, static_cast<uint32_t>(k));
1670       if (entry.is_not_found()) {
1671         if (search_for_hole) return Just(true);
1672         continue;
1673       }
1674 
1675       PropertyDetails details = GetDetailsImpl(*dictionary, entry);
1676       switch (details.kind()) {
1677         case kData: {
1678           Object element_k = dictionary->ValueAt(entry);
1679           if (value->SameValueZero(element_k)) return Just(true);
1680           break;
1681         }
1682         case kAccessor: {
1683           LookupIterator it(isolate, receiver, k,
1684                             LookupIterator::OWN_SKIP_INTERCEPTOR);
1685           DCHECK(it.IsFound());
1686           DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
1687           Handle<Object> element_k;
1688 
1689           ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
1690                                            Object::GetPropertyWithAccessor(&it),
1691                                            Nothing<bool>());
1692 
1693           if (value->SameValueZero(*element_k)) return Just(true);
1694 
1695           // Bailout to slow path if elements on prototype changed
1696           if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
1697             return IncludesValueSlowPath(isolate, receiver, value, k + 1,
1698                                          length);
1699           }
1700 
1701           // Continue if elements unchanged
1702           if (*dictionary == receiver->elements()) continue;
1703 
1704           // Otherwise, bailout or update elements
1705 
1706           // If switched to initial elements, return true if searching for
1707           // undefined, and false otherwise.
1708           if (receiver->map().GetInitialElements() == receiver->elements()) {
1709             return Just(search_for_hole);
1710           }
1711 
1712           // If switched to fast elements, continue with the correct accessor.
1713           if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
1714             ElementsAccessor* accessor = receiver->GetElementsAccessor();
1715             return accessor->IncludesValue(isolate, receiver, value, k + 1,
1716                                            length);
1717           }
1718           dictionary =
1719               handle(NumberDictionary::cast(receiver->elements()), isolate);
1720           break;
1721         }
1722       }
1723     }
1724     return Just(false);
1725   }
1726 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)1727   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
1728                                          Handle<JSObject> receiver,
1729                                          Handle<Object> value,
1730                                          size_t start_from, size_t length) {
1731     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
1732 
1733     ElementsKind original_elements_kind = receiver->GetElementsKind();
1734     USE(original_elements_kind);
1735     Handle<NumberDictionary> dictionary(
1736         NumberDictionary::cast(receiver->elements()), isolate);
1737     // Iterate through entire range, as accessing elements out of order is
1738     // observable.
1739     for (size_t k = start_from; k < length; ++k) {
1740       DCHECK_EQ(receiver->GetElementsKind(), original_elements_kind);
1741       DCHECK_LE(k, std::numeric_limits<uint32_t>::max());
1742       InternalIndex entry =
1743           dictionary->FindEntry(isolate, static_cast<uint32_t>(k));
1744       if (entry.is_not_found()) continue;
1745 
1746       PropertyDetails details =
1747           GetDetailsImpl(*dictionary, InternalIndex(entry));
1748       switch (details.kind()) {
1749         case kData: {
1750           Object element_k = dictionary->ValueAt(entry);
1751           if (value->StrictEquals(element_k)) {
1752             return Just<int64_t>(k);
1753           }
1754           break;
1755         }
1756         case kAccessor: {
1757           LookupIterator it(isolate, receiver, k,
1758                             LookupIterator::OWN_SKIP_INTERCEPTOR);
1759           DCHECK(it.IsFound());
1760           DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
1761           Handle<Object> element_k;
1762 
1763           ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
1764                                            Object::GetPropertyWithAccessor(&it),
1765                                            Nothing<int64_t>());
1766 
1767           if (value->StrictEquals(*element_k)) return Just<int64_t>(k);
1768 
1769           // Bailout to slow path if elements on prototype changed.
1770           if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
1771             return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
1772                                         length);
1773           }
1774 
1775           // Continue if elements unchanged.
1776           if (*dictionary == receiver->elements()) continue;
1777 
1778           // Otherwise, bailout or update elements.
1779           if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
1780             // Otherwise, switch to slow path.
1781             return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
1782                                         length);
1783           }
1784           dictionary =
1785               handle(NumberDictionary::cast(receiver->elements()), isolate);
1786           break;
1787         }
1788       }
1789     }
1790     return Just<int64_t>(-1);
1791   }
1792 
ValidateContents(JSObject holder,size_t length)1793   static void ValidateContents(JSObject holder, size_t length) {
1794     DisallowHeapAllocation no_gc;
1795 #if DEBUG
1796     DCHECK_EQ(holder.map().elements_kind(), DICTIONARY_ELEMENTS);
1797     if (!FLAG_enable_slow_asserts) return;
1798     ReadOnlyRoots roots = holder.GetReadOnlyRoots();
1799     NumberDictionary dictionary = NumberDictionary::cast(holder.elements());
1800     // Validate the requires_slow_elements and max_number_key values.
1801     bool requires_slow_elements = false;
1802     int max_key = 0;
1803     for (InternalIndex i : dictionary.IterateEntries()) {
1804       Object k;
1805       if (!dictionary.ToKey(roots, i, &k)) continue;
1806       DCHECK_LE(0.0, k.Number());
1807       if (k.Number() > NumberDictionary::kRequiresSlowElementsLimit) {
1808         requires_slow_elements = true;
1809       } else {
1810         max_key = Max(max_key, Smi::ToInt(k));
1811       }
1812     }
1813     if (requires_slow_elements) {
1814       DCHECK(dictionary.requires_slow_elements());
1815     } else if (!dictionary.requires_slow_elements()) {
1816       DCHECK_LE(max_key, dictionary.max_number_key());
1817     }
1818 #endif
1819   }
1820 };
1821 
1822 // Super class for all fast element arrays.
1823 template <typename Subclass, typename KindTraits>
1824 class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
1825  public:
1826   using BackingStore = typename KindTraits::BackingStore;
1827 
NormalizeImpl(Handle<JSObject> object,Handle<FixedArrayBase> store)1828   static Handle<NumberDictionary> NormalizeImpl(Handle<JSObject> object,
1829                                                 Handle<FixedArrayBase> store) {
1830     Isolate* isolate = object->GetIsolate();
1831     ElementsKind kind = Subclass::kind();
1832 
1833     // Ensure that notifications fire if the array or object prototypes are
1834     // normalizing.
1835     if (IsSmiOrObjectElementsKind(kind) ||
1836         kind == FAST_STRING_WRAPPER_ELEMENTS) {
1837       isolate->UpdateNoElementsProtectorOnNormalizeElements(object);
1838     }
1839 
1840     int capacity = object->GetFastElementsUsage();
1841     Handle<NumberDictionary> dictionary =
1842         NumberDictionary::New(isolate, capacity);
1843 
1844     PropertyDetails details = PropertyDetails::Empty();
1845     int j = 0;
1846     int max_number_key = -1;
1847     for (int i = 0; j < capacity; i++) {
1848       if (IsHoleyElementsKindForRead(kind)) {
1849         if (BackingStore::cast(*store).is_the_hole(isolate, i)) continue;
1850       }
1851       max_number_key = i;
1852       Handle<Object> value =
1853           Subclass::GetImpl(isolate, *store, InternalIndex(i));
1854       dictionary =
1855           NumberDictionary::Add(isolate, dictionary, i, value, details);
1856       j++;
1857     }
1858 
1859     if (max_number_key > 0) {
1860       dictionary->UpdateMaxNumberKey(static_cast<uint32_t>(max_number_key),
1861                                      object);
1862     }
1863     return dictionary;
1864   }
1865 
DeleteAtEnd(Handle<JSObject> obj,Handle<BackingStore> backing_store,uint32_t entry)1866   static void DeleteAtEnd(Handle<JSObject> obj,
1867                           Handle<BackingStore> backing_store, uint32_t entry) {
1868     uint32_t length = static_cast<uint32_t>(backing_store->length());
1869     Isolate* isolate = obj->GetIsolate();
1870     for (; entry > 0; entry--) {
1871       if (!backing_store->is_the_hole(isolate, entry - 1)) break;
1872     }
1873     if (entry == 0) {
1874       FixedArray empty = ReadOnlyRoots(isolate).empty_fixed_array();
1875       // Dynamically ask for the elements kind here since we manually redirect
1876       // the operations for argument backing stores.
1877       if (obj->GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
1878         SloppyArgumentsElements::cast(obj->elements()).set_arguments(empty);
1879       } else {
1880         obj->set_elements(empty);
1881       }
1882       return;
1883     }
1884 
1885     isolate->heap()->RightTrimFixedArray(*backing_store, length - entry);
1886   }
1887 
DeleteCommon(Handle<JSObject> obj,uint32_t entry,Handle<FixedArrayBase> store)1888   static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1889                            Handle<FixedArrayBase> store) {
1890     DCHECK(obj->HasSmiOrObjectElements() || obj->HasDoubleElements() ||
1891            obj->HasNonextensibleElements() || obj->HasFastArgumentsElements() ||
1892            obj->HasFastStringWrapperElements());
1893     Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
1894     if (!obj->IsJSArray() &&
1895         entry == static_cast<uint32_t>(store->length()) - 1) {
1896       DeleteAtEnd(obj, backing_store, entry);
1897       return;
1898     }
1899 
1900     Isolate* isolate = obj->GetIsolate();
1901     backing_store->set_the_hole(isolate, entry);
1902 
1903     // TODO(verwaest): Move this out of elements.cc.
1904     // If an old space backing store is larger than a certain size and
1905     // has too few used values, normalize it.
1906     const int kMinLengthForSparsenessCheck = 64;
1907     if (backing_store->length() < kMinLengthForSparsenessCheck) return;
1908     // TODO(ulan): Check if it works with young large objects.
1909     if (ObjectInYoungGeneration(*backing_store)) return;
1910     uint32_t length = 0;
1911     if (obj->IsJSArray()) {
1912       JSArray::cast(*obj).length().ToArrayLength(&length);
1913     } else {
1914       length = static_cast<uint32_t>(store->length());
1915     }
1916 
1917     // To avoid doing the check on every delete, use a counter-based heuristic.
1918     const int kLengthFraction = 16;
1919     // The above constant must be large enough to ensure that we check for
1920     // normalization frequently enough. At a minimum, it should be large
1921     // enough to reliably hit the "window" of remaining elements count where
1922     // normalization would be beneficial.
1923     STATIC_ASSERT(kLengthFraction >=
1924                   NumberDictionary::kEntrySize *
1925                       NumberDictionary::kPreferFastElementsSizeFactor);
1926     size_t current_counter = isolate->elements_deletion_counter();
1927     if (current_counter < length / kLengthFraction) {
1928       isolate->set_elements_deletion_counter(current_counter + 1);
1929       return;
1930     }
1931     // Reset the counter whenever the full check is performed.
1932     isolate->set_elements_deletion_counter(0);
1933 
1934     if (!obj->IsJSArray()) {
1935       uint32_t i;
1936       for (i = entry + 1; i < length; i++) {
1937         if (!backing_store->is_the_hole(isolate, i)) break;
1938       }
1939       if (i == length) {
1940         DeleteAtEnd(obj, backing_store, entry);
1941         return;
1942       }
1943     }
1944     int num_used = 0;
1945     for (int i = 0; i < backing_store->length(); ++i) {
1946       if (!backing_store->is_the_hole(isolate, i)) {
1947         ++num_used;
1948         // Bail out if a number dictionary wouldn't be able to save much space.
1949         if (NumberDictionary::kPreferFastElementsSizeFactor *
1950                 NumberDictionary::ComputeCapacity(num_used) *
1951                 NumberDictionary::kEntrySize >
1952             static_cast<uint32_t>(backing_store->length())) {
1953           return;
1954         }
1955       }
1956     }
1957     JSObject::NormalizeElements(obj);
1958   }
1959 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,InternalIndex entry,Handle<Object> value,PropertyAttributes attributes)1960   static void ReconfigureImpl(Handle<JSObject> object,
1961                               Handle<FixedArrayBase> store, InternalIndex entry,
1962                               Handle<Object> value,
1963                               PropertyAttributes attributes) {
1964     Handle<NumberDictionary> dictionary = JSObject::NormalizeElements(object);
1965     entry = InternalIndex(
1966         dictionary->FindEntry(object->GetIsolate(), entry.as_uint32()));
1967     DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
1968                                                 value, attributes);
1969   }
1970 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)1971   static void AddImpl(Handle<JSObject> object, uint32_t index,
1972                       Handle<Object> value, PropertyAttributes attributes,
1973                       uint32_t new_capacity) {
1974     DCHECK_EQ(NONE, attributes);
1975     ElementsKind from_kind = object->GetElementsKind();
1976     ElementsKind to_kind = Subclass::kind();
1977     if (IsDictionaryElementsKind(from_kind) ||
1978         IsDoubleElementsKind(from_kind) != IsDoubleElementsKind(to_kind) ||
1979         Subclass::GetCapacityImpl(*object, object->elements()) !=
1980             new_capacity) {
1981       Subclass::GrowCapacityAndConvertImpl(object, new_capacity);
1982     } else {
1983       if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
1984         JSObject::TransitionElementsKind(object, to_kind);
1985       }
1986       if (IsSmiOrObjectElementsKind(from_kind)) {
1987         DCHECK(IsSmiOrObjectElementsKind(to_kind));
1988         JSObject::EnsureWritableFastElements(object);
1989       }
1990     }
1991     Subclass::SetImpl(object, InternalIndex(index), *value);
1992   }
1993 
DeleteImpl(Handle<JSObject> obj,InternalIndex entry)1994   static void DeleteImpl(Handle<JSObject> obj, InternalIndex entry) {
1995     ElementsKind kind = KindTraits::Kind;
1996     if (IsFastPackedElementsKind(kind) ||
1997         kind == PACKED_NONEXTENSIBLE_ELEMENTS) {
1998       JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
1999     }
2000     if (IsSmiOrObjectElementsKind(KindTraits::Kind) ||
2001         IsNonextensibleElementsKind(kind)) {
2002       JSObject::EnsureWritableFastElements(obj);
2003     }
2004     DeleteCommon(obj, entry.as_uint32(),
2005                  handle(obj->elements(), obj->GetIsolate()));
2006   }
2007 
HasEntryImpl(Isolate * isolate,FixedArrayBase backing_store,InternalIndex entry)2008   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase backing_store,
2009                            InternalIndex entry) {
2010     return !BackingStore::cast(backing_store)
2011                 .is_the_hole(isolate, entry.as_int());
2012   }
2013 
NumberOfElementsImpl(JSObject receiver,FixedArrayBase backing_store)2014   static uint32_t NumberOfElementsImpl(JSObject receiver,
2015                                        FixedArrayBase backing_store) {
2016     size_t max_index = Subclass::GetMaxIndex(receiver, backing_store);
2017     DCHECK_LE(max_index, std::numeric_limits<uint32_t>::max());
2018     if (IsFastPackedElementsKind(Subclass::kind())) {
2019       return static_cast<uint32_t>(max_index);
2020     }
2021     Isolate* isolate = receiver.GetIsolate();
2022     uint32_t count = 0;
2023     for (size_t i = 0; i < max_index; i++) {
2024       if (Subclass::HasEntryImpl(isolate, backing_store, InternalIndex(i))) {
2025         count++;
2026       }
2027     }
2028     return count;
2029   }
2030 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)2031   V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
2032       Handle<JSObject> receiver, KeyAccumulator* accumulator,
2033       AddKeyConversion convert) {
2034     Isolate* isolate = accumulator->isolate();
2035     Handle<FixedArrayBase> elements(receiver->elements(), isolate);
2036     size_t length = Subclass::GetMaxNumberOfEntries(*receiver, *elements);
2037     for (size_t i = 0; i < length; i++) {
2038       if (IsFastPackedElementsKind(KindTraits::Kind) ||
2039           HasEntryImpl(isolate, *elements, InternalIndex(i))) {
2040         RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(
2041             Subclass::GetImpl(isolate, *elements, InternalIndex(i)), convert));
2042       }
2043     }
2044     return ExceptionStatus::kSuccess;
2045   }
2046 
ValidateContents(JSObject holder,size_t length)2047   static void ValidateContents(JSObject holder, size_t length) {
2048 #if DEBUG
2049     Isolate* isolate = holder.GetIsolate();
2050     Heap* heap = isolate->heap();
2051     FixedArrayBase elements = holder.elements();
2052     Map map = elements.map();
2053     if (IsSmiOrObjectElementsKind(KindTraits::Kind)) {
2054       DCHECK_NE(map, ReadOnlyRoots(heap).fixed_double_array_map());
2055     } else if (IsDoubleElementsKind(KindTraits::Kind)) {
2056       DCHECK_NE(map, ReadOnlyRoots(heap).fixed_cow_array_map());
2057       if (map == ReadOnlyRoots(heap).fixed_array_map()) DCHECK_EQ(0u, length);
2058     } else {
2059       UNREACHABLE();
2060     }
2061     if (length == 0u) return;  // nothing to do!
2062 #if ENABLE_SLOW_DCHECKS
2063     DisallowHeapAllocation no_gc;
2064     BackingStore backing_store = BackingStore::cast(elements);
2065     DCHECK(length <= std::numeric_limits<int>::max());
2066     int length_int = static_cast<int>(length);
2067     if (IsSmiElementsKind(KindTraits::Kind)) {
2068       HandleScope scope(isolate);
2069       for (int i = 0; i < length_int; i++) {
2070         DCHECK(BackingStore::get(backing_store, i, isolate)->IsSmi() ||
2071                (IsHoleyElementsKind(KindTraits::Kind) &&
2072                 backing_store.is_the_hole(isolate, i)));
2073       }
2074     } else if (KindTraits::Kind == PACKED_ELEMENTS ||
2075                KindTraits::Kind == PACKED_DOUBLE_ELEMENTS) {
2076       for (int i = 0; i < length_int; i++) {
2077         DCHECK(!backing_store.is_the_hole(isolate, i));
2078       }
2079     } else {
2080       DCHECK(IsHoleyElementsKind(KindTraits::Kind));
2081     }
2082 #endif
2083 #endif
2084   }
2085 
PopImpl(Handle<JSArray> receiver)2086   static Handle<Object> PopImpl(Handle<JSArray> receiver) {
2087     return Subclass::RemoveElement(receiver, AT_END);
2088   }
2089 
ShiftImpl(Handle<JSArray> receiver)2090   static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
2091     return Subclass::RemoveElement(receiver, AT_START);
2092   }
2093 
PushImpl(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t push_size)2094   static uint32_t PushImpl(Handle<JSArray> receiver, BuiltinArguments* args,
2095                            uint32_t push_size) {
2096     Handle<FixedArrayBase> backing_store(receiver->elements(),
2097                                          receiver->GetIsolate());
2098     return Subclass::AddArguments(receiver, backing_store, args, push_size,
2099                                   AT_END);
2100   }
2101 
UnshiftImpl(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t unshift_size)2102   static uint32_t UnshiftImpl(Handle<JSArray> receiver, BuiltinArguments* args,
2103                               uint32_t unshift_size) {
2104     Handle<FixedArrayBase> backing_store(receiver->elements(),
2105                                          receiver->GetIsolate());
2106     return Subclass::AddArguments(receiver, backing_store, args, unshift_size,
2107                                   AT_START);
2108   }
2109 
MoveElements(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,int dst_index,int src_index,int len,int hole_start,int hole_end)2110   static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
2111                            Handle<FixedArrayBase> backing_store, int dst_index,
2112                            int src_index, int len, int hole_start,
2113                            int hole_end) {
2114     Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store);
2115     if (len > JSArray::kMaxCopyElements && dst_index == 0 &&
2116         isolate->heap()->CanMoveObjectStart(*dst_elms)) {
2117       // Update all the copies of this backing_store handle.
2118       *dst_elms.location() =
2119           BackingStore::cast(
2120               isolate->heap()->LeftTrimFixedArray(*dst_elms, src_index))
2121               .ptr();
2122       receiver->set_elements(*dst_elms);
2123       // Adjust the hole offset as the array has been shrunk.
2124       hole_end -= src_index;
2125       DCHECK_LE(hole_start, backing_store->length());
2126       DCHECK_LE(hole_end, backing_store->length());
2127     } else if (len != 0) {
2128       WriteBarrierMode mode = GetWriteBarrierMode(KindTraits::Kind);
2129       dst_elms->MoveElements(isolate, dst_index, src_index, len, mode);
2130     }
2131     if (hole_start != hole_end) {
2132       dst_elms->FillWithHoles(hole_start, hole_end);
2133     }
2134   }
2135 
FillImpl(Handle<JSObject> receiver,Handle<Object> obj_value,size_t start,size_t end)2136   static Object FillImpl(Handle<JSObject> receiver, Handle<Object> obj_value,
2137                          size_t start, size_t end) {
2138     // Ensure indexes are within array bounds
2139     DCHECK_LE(0, start);
2140     DCHECK_LE(start, end);
2141 
2142     // Make sure COW arrays are copied.
2143     if (IsSmiOrObjectElementsKind(Subclass::kind())) {
2144       JSObject::EnsureWritableFastElements(receiver);
2145     }
2146 
2147     // Make sure we have enough space.
2148     DCHECK_LE(end, std::numeric_limits<uint32_t>::max());
2149     if (end > Subclass::GetCapacityImpl(*receiver, receiver->elements())) {
2150       Subclass::GrowCapacityAndConvertImpl(receiver,
2151                                            static_cast<uint32_t>(end));
2152       CHECK_EQ(Subclass::kind(), receiver->GetElementsKind());
2153     }
2154     DCHECK_LE(end, Subclass::GetCapacityImpl(*receiver, receiver->elements()));
2155 
2156     for (size_t index = start; index < end; ++index) {
2157       Subclass::SetImpl(receiver, InternalIndex(index), *obj_value);
2158     }
2159     return *receiver;
2160   }
2161 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> search_value,size_t start_from,size_t length)2162   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
2163                                        Handle<JSObject> receiver,
2164                                        Handle<Object> search_value,
2165                                        size_t start_from, size_t length) {
2166     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2167     DisallowHeapAllocation no_gc;
2168     FixedArrayBase elements_base = receiver->elements();
2169     Object the_hole = ReadOnlyRoots(isolate).the_hole_value();
2170     Object undefined = ReadOnlyRoots(isolate).undefined_value();
2171     Object value = *search_value;
2172 
2173     if (start_from >= length) return Just(false);
2174 
2175     // Elements beyond the capacity of the backing store treated as undefined.
2176     size_t elements_length = static_cast<size_t>(elements_base.length());
2177     if (value == undefined && elements_length < length) return Just(true);
2178     if (elements_length == 0) {
2179       DCHECK_NE(value, undefined);
2180       return Just(false);
2181     }
2182 
2183     length = std::min(elements_length, length);
2184     DCHECK_LE(length, std::numeric_limits<int>::max());
2185 
2186     if (!value.IsNumber()) {
2187       if (value == undefined) {
2188         // Search for `undefined` or The Hole. Even in the case of
2189         // PACKED_DOUBLE_ELEMENTS or PACKED_SMI_ELEMENTS, we might encounter The
2190         // Hole here, since the {length} used here can be larger than
2191         // JSArray::length.
2192         if (IsSmiOrObjectElementsKind(Subclass::kind()) ||
2193             IsAnyNonextensibleElementsKind(Subclass::kind())) {
2194           FixedArray elements = FixedArray::cast(receiver->elements());
2195 
2196           for (size_t k = start_from; k < length; ++k) {
2197             Object element_k = elements.get(static_cast<int>(k));
2198 
2199             if (element_k == the_hole || element_k == undefined) {
2200               return Just(true);
2201             }
2202           }
2203           return Just(false);
2204         } else {
2205           // Search for The Hole in HOLEY_DOUBLE_ELEMENTS or
2206           // PACKED_DOUBLE_ELEMENTS.
2207           DCHECK(IsDoubleElementsKind(Subclass::kind()));
2208           FixedDoubleArray elements =
2209               FixedDoubleArray::cast(receiver->elements());
2210 
2211           for (size_t k = start_from; k < length; ++k) {
2212             if (elements.is_the_hole(static_cast<int>(k))) return Just(true);
2213           }
2214           return Just(false);
2215         }
2216       } else if (!IsObjectElementsKind(Subclass::kind()) &&
2217                  !IsAnyNonextensibleElementsKind(Subclass::kind())) {
2218         // Search for non-number, non-Undefined value, with either
2219         // PACKED_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS, HOLEY_SMI_ELEMENTS or
2220         // HOLEY_DOUBLE_ELEMENTS. Guaranteed to return false, since these
2221         // elements kinds can only contain Number values or undefined.
2222         return Just(false);
2223       } else {
2224         // Search for non-number, non-Undefined value with either
2225         // PACKED_ELEMENTS or HOLEY_ELEMENTS.
2226         DCHECK(IsObjectElementsKind(Subclass::kind()) ||
2227                IsAnyNonextensibleElementsKind(Subclass::kind()));
2228         FixedArray elements = FixedArray::cast(receiver->elements());
2229 
2230         for (size_t k = start_from; k < length; ++k) {
2231           Object element_k = elements.get(static_cast<int>(k));
2232           if (element_k == the_hole) continue;
2233           if (value.SameValueZero(element_k)) return Just(true);
2234         }
2235         return Just(false);
2236       }
2237     } else {
2238       if (!value.IsNaN()) {
2239         double search_value = value.Number();
2240         if (IsDoubleElementsKind(Subclass::kind())) {
2241           // Search for non-NaN Number in PACKED_DOUBLE_ELEMENTS or
2242           // HOLEY_DOUBLE_ELEMENTS --- Skip TheHole, and trust UCOMISD or
2243           // similar operation for result.
2244           FixedDoubleArray elements =
2245               FixedDoubleArray::cast(receiver->elements());
2246 
2247           for (size_t k = start_from; k < length; ++k) {
2248             if (elements.is_the_hole(static_cast<int>(k))) continue;
2249             if (elements.get_scalar(static_cast<int>(k)) == search_value) {
2250               return Just(true);
2251             }
2252           }
2253           return Just(false);
2254         } else {
2255           // Search for non-NaN Number in PACKED_ELEMENTS, HOLEY_ELEMENTS,
2256           // PACKED_SMI_ELEMENTS or HOLEY_SMI_ELEMENTS --- Skip non-Numbers,
2257           // and trust UCOMISD or similar operation for result
2258           FixedArray elements = FixedArray::cast(receiver->elements());
2259 
2260           for (size_t k = start_from; k < length; ++k) {
2261             Object element_k = elements.get(static_cast<int>(k));
2262             if (element_k.IsNumber() && element_k.Number() == search_value) {
2263               return Just(true);
2264             }
2265           }
2266           return Just(false);
2267         }
2268       } else {
2269         // Search for NaN --- NaN cannot be represented with Smi elements, so
2270         // abort if ElementsKind is PACKED_SMI_ELEMENTS or HOLEY_SMI_ELEMENTS
2271         if (IsSmiElementsKind(Subclass::kind())) return Just(false);
2272 
2273         if (IsDoubleElementsKind(Subclass::kind())) {
2274           // Search for NaN in PACKED_DOUBLE_ELEMENTS or
2275           // HOLEY_DOUBLE_ELEMENTS --- Skip The Hole and trust
2276           // std::isnan(elementK) for result
2277           FixedDoubleArray elements =
2278               FixedDoubleArray::cast(receiver->elements());
2279 
2280           for (size_t k = start_from; k < length; ++k) {
2281             if (elements.is_the_hole(static_cast<int>(k))) continue;
2282             if (std::isnan(elements.get_scalar(static_cast<int>(k)))) {
2283               return Just(true);
2284             }
2285           }
2286           return Just(false);
2287         } else {
2288           // Search for NaN in PACKED_ELEMENTS or HOLEY_ELEMENTS. Return true
2289           // if elementK->IsHeapNumber() && std::isnan(elementK->Number())
2290           DCHECK(IsObjectElementsKind(Subclass::kind()) ||
2291                  IsAnyNonextensibleElementsKind(Subclass::kind()));
2292           FixedArray elements = FixedArray::cast(receiver->elements());
2293 
2294           for (size_t k = start_from; k < length; ++k) {
2295             if (elements.get(static_cast<int>(k)).IsNaN()) return Just(true);
2296           }
2297           return Just(false);
2298         }
2299       }
2300     }
2301   }
2302 
CreateListFromArrayLikeImpl(Isolate * isolate,Handle<JSObject> object,uint32_t length)2303   static Handle<FixedArray> CreateListFromArrayLikeImpl(Isolate* isolate,
2304                                                         Handle<JSObject> object,
2305                                                         uint32_t length) {
2306     Handle<FixedArray> result = isolate->factory()->NewFixedArray(length);
2307     Handle<FixedArrayBase> elements(object->elements(), isolate);
2308     for (uint32_t i = 0; i < length; i++) {
2309       InternalIndex entry(i);
2310       if (!Subclass::HasEntryImpl(isolate, *elements, entry)) continue;
2311       Handle<Object> value;
2312       value = Subclass::GetImpl(isolate, *elements, entry);
2313       if (value->IsName()) {
2314         value = isolate->factory()->InternalizeName(Handle<Name>::cast(value));
2315       }
2316       result->set(i, *value);
2317     }
2318     return result;
2319   }
2320 
RemoveElement(Handle<JSArray> receiver,Where remove_position)2321   static Handle<Object> RemoveElement(Handle<JSArray> receiver,
2322                                       Where remove_position) {
2323     Isolate* isolate = receiver->GetIsolate();
2324     ElementsKind kind = KindTraits::Kind;
2325     if (IsSmiOrObjectElementsKind(kind)) {
2326       HandleScope scope(isolate);
2327       JSObject::EnsureWritableFastElements(receiver);
2328     }
2329     Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
2330     uint32_t length = static_cast<uint32_t>(Smi::ToInt(receiver->length()));
2331     DCHECK_GT(length, 0);
2332     int new_length = length - 1;
2333     int remove_index = remove_position == AT_START ? 0 : new_length;
2334     Handle<Object> result =
2335         Subclass::GetImpl(isolate, *backing_store, InternalIndex(remove_index));
2336     if (remove_position == AT_START) {
2337       Subclass::MoveElements(isolate, receiver, backing_store, 0, 1, new_length,
2338                              0, 0);
2339     }
2340     Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store);
2341 
2342     if (IsHoleyElementsKind(kind) && result->IsTheHole(isolate)) {
2343       return isolate->factory()->undefined_value();
2344     }
2345     return result;
2346   }
2347 
AddArguments(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,BuiltinArguments * args,uint32_t add_size,Where add_position)2348   static uint32_t AddArguments(Handle<JSArray> receiver,
2349                                Handle<FixedArrayBase> backing_store,
2350                                BuiltinArguments* args, uint32_t add_size,
2351                                Where add_position) {
2352     uint32_t length = Smi::ToInt(receiver->length());
2353     DCHECK_LT(0, add_size);
2354     uint32_t elms_len = backing_store->length();
2355     // Check we do not overflow the new_length.
2356     DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
2357     uint32_t new_length = length + add_size;
2358 
2359     if (new_length > elms_len) {
2360       // New backing storage is needed.
2361       uint32_t capacity = JSObject::NewElementsCapacity(new_length);
2362       // If we add arguments to the start we have to shift the existing objects.
2363       int copy_dst_index = add_position == AT_START ? add_size : 0;
2364       // Copy over all objects to a new backing_store.
2365       backing_store = Subclass::ConvertElementsWithCapacity(
2366           receiver, backing_store, KindTraits::Kind, capacity, 0,
2367           copy_dst_index);
2368       receiver->set_elements(*backing_store);
2369     } else if (add_position == AT_START) {
2370       // If the backing store has enough capacity and we add elements to the
2371       // start we have to shift the existing objects.
2372       Isolate* isolate = receiver->GetIsolate();
2373       Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0,
2374                              length, 0, 0);
2375     }
2376 
2377     int insertion_index = add_position == AT_START ? 0 : length;
2378     // Copy the arguments to the start.
2379     Subclass::CopyArguments(args, backing_store, add_size, 1, insertion_index);
2380     // Set the length.
2381     receiver->set_length(Smi::FromInt(new_length));
2382     return new_length;
2383   }
2384 
CopyArguments(BuiltinArguments * args,Handle<FixedArrayBase> dst_store,uint32_t copy_size,uint32_t src_index,uint32_t dst_index)2385   static void CopyArguments(BuiltinArguments* args,
2386                             Handle<FixedArrayBase> dst_store,
2387                             uint32_t copy_size, uint32_t src_index,
2388                             uint32_t dst_index) {
2389     // Add the provided values.
2390     DisallowHeapAllocation no_gc;
2391     FixedArrayBase raw_backing_store = *dst_store;
2392     WriteBarrierMode mode = raw_backing_store.GetWriteBarrierMode(no_gc);
2393     for (uint32_t i = 0; i < copy_size; i++) {
2394       Object argument = (*args)[src_index + i];
2395       DCHECK(!argument.IsTheHole());
2396       Subclass::SetImpl(raw_backing_store, InternalIndex(dst_index + i),
2397                         argument, mode);
2398     }
2399   }
2400 };
2401 
2402 template <typename Subclass, typename KindTraits>
2403 class FastSmiOrObjectElementsAccessor
2404     : public FastElementsAccessor<Subclass, KindTraits> {
2405  public:
SetImpl(Handle<JSObject> holder,InternalIndex entry,Object value)2406   static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
2407                              Object value) {
2408     SetImpl(holder->elements(), entry, value);
2409   }
2410 
SetImpl(FixedArrayBase backing_store,InternalIndex entry,Object value)2411   static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
2412                              Object value) {
2413     FixedArray::cast(backing_store).set(entry.as_int(), value);
2414   }
2415 
SetImpl(FixedArrayBase backing_store,InternalIndex entry,Object value,WriteBarrierMode mode)2416   static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
2417                              Object value, WriteBarrierMode mode) {
2418     FixedArray::cast(backing_store).set(entry.as_int(), value, mode);
2419   }
2420 
GetRaw(FixedArray backing_store,InternalIndex entry)2421   static Object GetRaw(FixedArray backing_store, InternalIndex entry) {
2422     return backing_store.get(entry.as_int());
2423   }
2424 
2425   // NOTE: this method violates the handlified function signature convention:
2426   // raw pointer parameters in the function that allocates.
2427   // See ElementsAccessor::CopyElements() for details.
2428   // This method could actually allocate if copying from double elements to
2429   // object elements.
CopyElementsImpl(Isolate * isolate,FixedArrayBase from,uint32_t from_start,FixedArrayBase to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)2430   static void CopyElementsImpl(Isolate* isolate, FixedArrayBase from,
2431                                uint32_t from_start, FixedArrayBase to,
2432                                ElementsKind from_kind, uint32_t to_start,
2433                                int packed_size, int copy_size) {
2434     DisallowHeapAllocation no_gc;
2435     ElementsKind to_kind = KindTraits::Kind;
2436     switch (from_kind) {
2437       case PACKED_SMI_ELEMENTS:
2438       case HOLEY_SMI_ELEMENTS:
2439       case PACKED_ELEMENTS:
2440       case PACKED_FROZEN_ELEMENTS:
2441       case PACKED_SEALED_ELEMENTS:
2442       case PACKED_NONEXTENSIBLE_ELEMENTS:
2443       case HOLEY_ELEMENTS:
2444       case HOLEY_FROZEN_ELEMENTS:
2445       case HOLEY_SEALED_ELEMENTS:
2446       case HOLEY_NONEXTENSIBLE_ELEMENTS:
2447         CopyObjectToObjectElements(isolate, from, from_kind, from_start, to,
2448                                    to_kind, to_start, copy_size);
2449         break;
2450       case PACKED_DOUBLE_ELEMENTS:
2451       case HOLEY_DOUBLE_ELEMENTS: {
2452         AllowHeapAllocation allow_allocation;
2453         DCHECK(IsObjectElementsKind(to_kind));
2454         CopyDoubleToObjectElements(isolate, from, from_start, to, to_start,
2455                                    copy_size);
2456         break;
2457       }
2458       case DICTIONARY_ELEMENTS:
2459         CopyDictionaryToObjectElements(isolate, from, from_start, to, to_kind,
2460                                        to_start, copy_size);
2461         break;
2462       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
2463       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
2464       case FAST_STRING_WRAPPER_ELEMENTS:
2465       case SLOW_STRING_WRAPPER_ELEMENTS:
2466 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
2467         TYPED_ARRAYS(TYPED_ARRAY_CASE)
2468 #undef TYPED_ARRAY_CASE
2469         // This function is currently only used for JSArrays with non-zero
2470         // length.
2471         UNREACHABLE();
2472       case NO_ELEMENTS:
2473         break;  // Nothing to do.
2474     }
2475   }
2476 
CollectValuesOrEntriesImpl(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)2477   static Maybe<bool> CollectValuesOrEntriesImpl(
2478       Isolate* isolate, Handle<JSObject> object,
2479       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
2480       PropertyFilter filter) {
2481     int count = 0;
2482     if (get_entries) {
2483       // Collecting entries needs to allocate, so this code must be handlified.
2484       Handle<FixedArray> elements(FixedArray::cast(object->elements()),
2485                                   isolate);
2486       uint32_t length = elements->length();
2487       for (uint32_t index = 0; index < length; ++index) {
2488         InternalIndex entry(index);
2489         if (!Subclass::HasEntryImpl(isolate, *elements, entry)) continue;
2490         Handle<Object> value = Subclass::GetImpl(isolate, *elements, entry);
2491         value = MakeEntryPair(isolate, index, value);
2492         values_or_entries->set(count++, *value);
2493       }
2494     } else {
2495       // No allocations here, so we can avoid handlification overhead.
2496       DisallowHeapAllocation no_gc;
2497       FixedArray elements = FixedArray::cast(object->elements());
2498       uint32_t length = elements.length();
2499       for (uint32_t index = 0; index < length; ++index) {
2500         InternalIndex entry(index);
2501         if (!Subclass::HasEntryImpl(isolate, elements, entry)) continue;
2502         Object value = GetRaw(elements, entry);
2503         values_or_entries->set(count++, value);
2504       }
2505     }
2506     *nof_items = count;
2507     return Just(true);
2508   }
2509 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> search_value,size_t start_from,size_t length)2510   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2511                                          Handle<JSObject> receiver,
2512                                          Handle<Object> search_value,
2513                                          size_t start_from, size_t length) {
2514     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2515     DisallowHeapAllocation no_gc;
2516     FixedArrayBase elements_base = receiver->elements();
2517     Object value = *search_value;
2518 
2519     if (start_from >= length) return Just<int64_t>(-1);
2520 
2521     length = std::min(static_cast<size_t>(elements_base.length()), length);
2522 
2523     // Only FAST_{,HOLEY_}ELEMENTS can store non-numbers.
2524     if (!value.IsNumber() && !IsObjectElementsKind(Subclass::kind()) &&
2525         !IsAnyNonextensibleElementsKind(Subclass::kind())) {
2526       return Just<int64_t>(-1);
2527     }
2528     // NaN can never be found by strict equality.
2529     if (value.IsNaN()) return Just<int64_t>(-1);
2530 
2531     // k can be greater than receiver->length() below, but it is bounded by
2532     // elements_base->length() so we never read out of bounds. This means that
2533     // elements->get(k) can return the hole, for which the StrictEquals will
2534     // always fail.
2535     FixedArray elements = FixedArray::cast(receiver->elements());
2536     STATIC_ASSERT(FixedArray::kMaxLength <=
2537                   std::numeric_limits<uint32_t>::max());
2538     for (size_t k = start_from; k < length; ++k) {
2539       if (value.StrictEquals(elements.get(static_cast<uint32_t>(k)))) {
2540         return Just<int64_t>(k);
2541       }
2542     }
2543     return Just<int64_t>(-1);
2544   }
2545 };
2546 
2547 class FastPackedSmiElementsAccessor
2548     : public FastSmiOrObjectElementsAccessor<
2549           FastPackedSmiElementsAccessor,
2550           ElementsKindTraits<PACKED_SMI_ELEMENTS>> {};
2551 
2552 class FastHoleySmiElementsAccessor
2553     : public FastSmiOrObjectElementsAccessor<
2554           FastHoleySmiElementsAccessor,
2555           ElementsKindTraits<HOLEY_SMI_ELEMENTS>> {};
2556 
2557 class FastPackedObjectElementsAccessor
2558     : public FastSmiOrObjectElementsAccessor<
2559           FastPackedObjectElementsAccessor,
2560           ElementsKindTraits<PACKED_ELEMENTS>> {};
2561 
2562 template <typename Subclass, typename KindTraits>
2563 class FastNonextensibleObjectElementsAccessor
2564     : public FastSmiOrObjectElementsAccessor<Subclass, KindTraits> {
2565  public:
2566   using BackingStore = typename KindTraits::BackingStore;
2567 
PushImpl(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t push_size)2568   static uint32_t PushImpl(Handle<JSArray> receiver, BuiltinArguments* args,
2569                            uint32_t push_size) {
2570     UNREACHABLE();
2571   }
2572 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)2573   static void AddImpl(Handle<JSObject> object, uint32_t index,
2574                       Handle<Object> value, PropertyAttributes attributes,
2575                       uint32_t new_capacity) {
2576     UNREACHABLE();
2577   }
2578 
2579   // TODO(duongn): refactor this due to code duplication of sealed version.
2580   // Consider using JSObject::NormalizeElements(). Also consider follow the fast
2581   // element logic instead of changing to dictionary mode.
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)2582   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2583                             uint32_t length,
2584                             Handle<FixedArrayBase> backing_store) {
2585     uint32_t old_length = 0;
2586     CHECK(array->length().ToArrayIndex(&old_length));
2587     if (length == old_length) {
2588       // Do nothing.
2589       return;
2590     }
2591 
2592     // Transition to DICTIONARY_ELEMENTS.
2593     // Convert to dictionary mode.
2594     Handle<NumberDictionary> new_element_dictionary =
2595         old_length == 0 ? isolate->factory()->empty_slow_element_dictionary()
2596                         : array->GetElementsAccessor()->Normalize(array);
2597 
2598     // Migrate map.
2599     Handle<Map> new_map = Map::Copy(isolate, handle(array->map(), isolate),
2600                                     "SlowCopyForSetLengthImpl");
2601     new_map->set_is_extensible(false);
2602     new_map->set_elements_kind(DICTIONARY_ELEMENTS);
2603     JSObject::MigrateToMap(isolate, array, new_map);
2604 
2605     if (!new_element_dictionary.is_null()) {
2606       array->set_elements(*new_element_dictionary);
2607     }
2608 
2609     if (array->elements() !=
2610         ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
2611       Handle<NumberDictionary> dictionary(array->element_dictionary(), isolate);
2612       // Make sure we never go back to the fast case
2613       array->RequireSlowElements(*dictionary);
2614       JSObject::ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate),
2615                                             dictionary,
2616                                             PropertyAttributes::NONE);
2617     }
2618 
2619     // Set length.
2620     Handle<FixedArrayBase> new_backing_store(array->elements(), isolate);
2621     DictionaryElementsAccessor::SetLengthImpl(isolate, array, length,
2622                                               new_backing_store);
2623   }
2624 };
2625 
2626 class FastPackedNonextensibleObjectElementsAccessor
2627     : public FastNonextensibleObjectElementsAccessor<
2628           FastPackedNonextensibleObjectElementsAccessor,
2629           ElementsKindTraits<PACKED_NONEXTENSIBLE_ELEMENTS>> {};
2630 
2631 class FastHoleyNonextensibleObjectElementsAccessor
2632     : public FastNonextensibleObjectElementsAccessor<
2633           FastHoleyNonextensibleObjectElementsAccessor,
2634           ElementsKindTraits<HOLEY_NONEXTENSIBLE_ELEMENTS>> {};
2635 
2636 template <typename Subclass, typename KindTraits>
2637 class FastSealedObjectElementsAccessor
2638     : public FastSmiOrObjectElementsAccessor<Subclass, KindTraits> {
2639  public:
2640   using BackingStore = typename KindTraits::BackingStore;
2641 
RemoveElement(Handle<JSArray> receiver,Where remove_position)2642   static Handle<Object> RemoveElement(Handle<JSArray> receiver,
2643                                       Where remove_position) {
2644     UNREACHABLE();
2645   }
2646 
DeleteImpl(Handle<JSObject> obj,InternalIndex entry)2647   static void DeleteImpl(Handle<JSObject> obj, InternalIndex entry) {
2648     UNREACHABLE();
2649   }
2650 
DeleteAtEnd(Handle<JSObject> obj,Handle<BackingStore> backing_store,uint32_t entry)2651   static void DeleteAtEnd(Handle<JSObject> obj,
2652                           Handle<BackingStore> backing_store, uint32_t entry) {
2653     UNREACHABLE();
2654   }
2655 
DeleteCommon(Handle<JSObject> obj,uint32_t entry,Handle<FixedArrayBase> store)2656   static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
2657                            Handle<FixedArrayBase> store) {
2658     UNREACHABLE();
2659   }
2660 
PopImpl(Handle<JSArray> receiver)2661   static Handle<Object> PopImpl(Handle<JSArray> receiver) { UNREACHABLE(); }
2662 
PushImpl(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t push_size)2663   static uint32_t PushImpl(Handle<JSArray> receiver, BuiltinArguments* args,
2664                            uint32_t push_size) {
2665     UNREACHABLE();
2666   }
2667 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)2668   static void AddImpl(Handle<JSObject> object, uint32_t index,
2669                       Handle<Object> value, PropertyAttributes attributes,
2670                       uint32_t new_capacity) {
2671     UNREACHABLE();
2672   }
2673 
2674   // TODO(duongn): refactor this due to code duplication of nonextensible
2675   // version. Consider using JSObject::NormalizeElements(). Also consider follow
2676   // the fast element logic instead of changing to dictionary mode.
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)2677   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2678                             uint32_t length,
2679                             Handle<FixedArrayBase> backing_store) {
2680     uint32_t old_length = 0;
2681     CHECK(array->length().ToArrayIndex(&old_length));
2682     if (length == old_length) {
2683       // Do nothing.
2684       return;
2685     }
2686 
2687     // Transition to DICTIONARY_ELEMENTS.
2688     // Convert to dictionary mode
2689     Handle<NumberDictionary> new_element_dictionary =
2690         old_length == 0 ? isolate->factory()->empty_slow_element_dictionary()
2691                         : array->GetElementsAccessor()->Normalize(array);
2692 
2693     // Migrate map.
2694     Handle<Map> new_map = Map::Copy(isolate, handle(array->map(), isolate),
2695                                     "SlowCopyForSetLengthImpl");
2696     new_map->set_is_extensible(false);
2697     new_map->set_elements_kind(DICTIONARY_ELEMENTS);
2698     JSObject::MigrateToMap(isolate, array, new_map);
2699 
2700     if (!new_element_dictionary.is_null()) {
2701       array->set_elements(*new_element_dictionary);
2702     }
2703 
2704     if (array->elements() !=
2705         ReadOnlyRoots(isolate).empty_slow_element_dictionary()) {
2706       Handle<NumberDictionary> dictionary(array->element_dictionary(), isolate);
2707       // Make sure we never go back to the fast case
2708       array->RequireSlowElements(*dictionary);
2709       JSObject::ApplyAttributesToDictionary(isolate, ReadOnlyRoots(isolate),
2710                                             dictionary,
2711                                             PropertyAttributes::SEALED);
2712     }
2713 
2714     // Set length
2715     Handle<FixedArrayBase> new_backing_store(array->elements(), isolate);
2716     DictionaryElementsAccessor::SetLengthImpl(isolate, array, length,
2717                                               new_backing_store);
2718   }
2719 };
2720 
2721 class FastPackedSealedObjectElementsAccessor
2722     : public FastSealedObjectElementsAccessor<
2723           FastPackedSealedObjectElementsAccessor,
2724           ElementsKindTraits<PACKED_SEALED_ELEMENTS>> {};
2725 
2726 class FastHoleySealedObjectElementsAccessor
2727     : public FastSealedObjectElementsAccessor<
2728           FastHoleySealedObjectElementsAccessor,
2729           ElementsKindTraits<HOLEY_SEALED_ELEMENTS>> {};
2730 
2731 template <typename Subclass, typename KindTraits>
2732 class FastFrozenObjectElementsAccessor
2733     : public FastSmiOrObjectElementsAccessor<Subclass, KindTraits> {
2734  public:
2735   using BackingStore = typename KindTraits::BackingStore;
2736 
SetImpl(Handle<JSObject> holder,InternalIndex entry,Object value)2737   static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
2738                              Object value) {
2739     UNREACHABLE();
2740   }
2741 
SetImpl(FixedArrayBase backing_store,InternalIndex entry,Object value)2742   static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
2743                              Object value) {
2744     UNREACHABLE();
2745   }
2746 
SetImpl(FixedArrayBase backing_store,InternalIndex entry,Object value,WriteBarrierMode mode)2747   static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
2748                              Object value, WriteBarrierMode mode) {
2749     UNREACHABLE();
2750   }
2751 
RemoveElement(Handle<JSArray> receiver,Where remove_position)2752   static Handle<Object> RemoveElement(Handle<JSArray> receiver,
2753                                       Where remove_position) {
2754     UNREACHABLE();
2755   }
2756 
DeleteImpl(Handle<JSObject> obj,InternalIndex entry)2757   static void DeleteImpl(Handle<JSObject> obj, InternalIndex entry) {
2758     UNREACHABLE();
2759   }
2760 
DeleteAtEnd(Handle<JSObject> obj,Handle<BackingStore> backing_store,uint32_t entry)2761   static void DeleteAtEnd(Handle<JSObject> obj,
2762                           Handle<BackingStore> backing_store, uint32_t entry) {
2763     UNREACHABLE();
2764   }
2765 
DeleteCommon(Handle<JSObject> obj,uint32_t entry,Handle<FixedArrayBase> store)2766   static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
2767                            Handle<FixedArrayBase> store) {
2768     UNREACHABLE();
2769   }
2770 
PopImpl(Handle<JSArray> receiver)2771   static Handle<Object> PopImpl(Handle<JSArray> receiver) { UNREACHABLE(); }
2772 
PushImpl(Handle<JSArray> receiver,BuiltinArguments * args,uint32_t push_size)2773   static uint32_t PushImpl(Handle<JSArray> receiver, BuiltinArguments* args,
2774                            uint32_t push_size) {
2775     UNREACHABLE();
2776   }
2777 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)2778   static void AddImpl(Handle<JSObject> object, uint32_t index,
2779                       Handle<Object> value, PropertyAttributes attributes,
2780                       uint32_t new_capacity) {
2781     UNREACHABLE();
2782   }
2783 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)2784   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2785                             uint32_t length,
2786                             Handle<FixedArrayBase> backing_store) {
2787     UNREACHABLE();
2788   }
2789 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,InternalIndex entry,Handle<Object> value,PropertyAttributes attributes)2790   static void ReconfigureImpl(Handle<JSObject> object,
2791                               Handle<FixedArrayBase> store, InternalIndex entry,
2792                               Handle<Object> value,
2793                               PropertyAttributes attributes) {
2794     UNREACHABLE();
2795   }
2796 };
2797 
2798 class FastPackedFrozenObjectElementsAccessor
2799     : public FastFrozenObjectElementsAccessor<
2800           FastPackedFrozenObjectElementsAccessor,
2801           ElementsKindTraits<PACKED_FROZEN_ELEMENTS>> {};
2802 
2803 class FastHoleyFrozenObjectElementsAccessor
2804     : public FastFrozenObjectElementsAccessor<
2805           FastHoleyFrozenObjectElementsAccessor,
2806           ElementsKindTraits<HOLEY_FROZEN_ELEMENTS>> {};
2807 
2808 class FastHoleyObjectElementsAccessor
2809     : public FastSmiOrObjectElementsAccessor<
2810           FastHoleyObjectElementsAccessor, ElementsKindTraits<HOLEY_ELEMENTS>> {
2811 };
2812 
2813 template <typename Subclass, typename KindTraits>
2814 class FastDoubleElementsAccessor
2815     : public FastElementsAccessor<Subclass, KindTraits> {
2816  public:
GetImpl(Isolate * isolate,FixedArrayBase backing_store,InternalIndex entry)2817   static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
2818                                 InternalIndex entry) {
2819     return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store),
2820                                  entry.as_int(), isolate);
2821   }
2822 
SetImpl(Handle<JSObject> holder,InternalIndex entry,Object value)2823   static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
2824                              Object value) {
2825     SetImpl(holder->elements(), entry, value);
2826   }
2827 
SetImpl(FixedArrayBase backing_store,InternalIndex entry,Object value)2828   static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
2829                              Object value) {
2830     FixedDoubleArray::cast(backing_store).set(entry.as_int(), value.Number());
2831   }
2832 
SetImpl(FixedArrayBase backing_store,InternalIndex entry,Object value,WriteBarrierMode mode)2833   static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
2834                              Object value, WriteBarrierMode mode) {
2835     FixedDoubleArray::cast(backing_store).set(entry.as_int(), value.Number());
2836   }
2837 
CopyElementsImpl(Isolate * isolate,FixedArrayBase from,uint32_t from_start,FixedArrayBase to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)2838   static void CopyElementsImpl(Isolate* isolate, FixedArrayBase from,
2839                                uint32_t from_start, FixedArrayBase to,
2840                                ElementsKind from_kind, uint32_t to_start,
2841                                int packed_size, int copy_size) {
2842     DisallowHeapAllocation no_allocation;
2843     switch (from_kind) {
2844       case PACKED_SMI_ELEMENTS:
2845         CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
2846                                       packed_size, copy_size);
2847         break;
2848       case HOLEY_SMI_ELEMENTS:
2849         CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
2850         break;
2851       case PACKED_DOUBLE_ELEMENTS:
2852       case HOLEY_DOUBLE_ELEMENTS:
2853         CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
2854         break;
2855       case PACKED_ELEMENTS:
2856       case PACKED_FROZEN_ELEMENTS:
2857       case PACKED_SEALED_ELEMENTS:
2858       case PACKED_NONEXTENSIBLE_ELEMENTS:
2859       case HOLEY_ELEMENTS:
2860       case HOLEY_FROZEN_ELEMENTS:
2861       case HOLEY_SEALED_ELEMENTS:
2862       case HOLEY_NONEXTENSIBLE_ELEMENTS:
2863         CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
2864         break;
2865       case DICTIONARY_ELEMENTS:
2866         CopyDictionaryToDoubleElements(isolate, from, from_start, to, to_start,
2867                                        copy_size);
2868         break;
2869       case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
2870       case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
2871       case FAST_STRING_WRAPPER_ELEMENTS:
2872       case SLOW_STRING_WRAPPER_ELEMENTS:
2873       case NO_ELEMENTS:
2874 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
2875         TYPED_ARRAYS(TYPED_ARRAY_CASE)
2876 #undef TYPED_ARRAY_CASE
2877         // This function is currently only used for JSArrays with non-zero
2878         // length.
2879         UNREACHABLE();
2880     }
2881   }
2882 
CollectValuesOrEntriesImpl(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)2883   static Maybe<bool> CollectValuesOrEntriesImpl(
2884       Isolate* isolate, Handle<JSObject> object,
2885       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
2886       PropertyFilter filter) {
2887     Handle<FixedDoubleArray> elements(
2888         FixedDoubleArray::cast(object->elements()), isolate);
2889     int count = 0;
2890     uint32_t length = elements->length();
2891     for (uint32_t index = 0; index < length; ++index) {
2892       InternalIndex entry(index);
2893       if (!Subclass::HasEntryImpl(isolate, *elements, entry)) continue;
2894       Handle<Object> value = Subclass::GetImpl(isolate, *elements, entry);
2895       if (get_entries) {
2896         value = MakeEntryPair(isolate, index, value);
2897       }
2898       values_or_entries->set(count++, *value);
2899     }
2900     *nof_items = count;
2901     return Just(true);
2902   }
2903 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> search_value,size_t start_from,size_t length)2904   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2905                                          Handle<JSObject> receiver,
2906                                          Handle<Object> search_value,
2907                                          size_t start_from, size_t length) {
2908     DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2909     DisallowHeapAllocation no_gc;
2910     FixedArrayBase elements_base = receiver->elements();
2911     Object value = *search_value;
2912 
2913     length = std::min(static_cast<size_t>(elements_base.length()), length);
2914 
2915     if (start_from >= length) return Just<int64_t>(-1);
2916 
2917     if (!value.IsNumber()) {
2918       return Just<int64_t>(-1);
2919     }
2920     if (value.IsNaN()) {
2921       return Just<int64_t>(-1);
2922     }
2923     double numeric_search_value = value.Number();
2924     FixedDoubleArray elements = FixedDoubleArray::cast(receiver->elements());
2925 
2926     STATIC_ASSERT(FixedDoubleArray::kMaxLength <=
2927                   std::numeric_limits<int>::max());
2928     for (size_t k = start_from; k < length; ++k) {
2929       int k_int = static_cast<int>(k);
2930       if (elements.is_the_hole(k_int)) {
2931         continue;
2932       }
2933       if (elements.get_scalar(k_int) == numeric_search_value) {
2934         return Just<int64_t>(k);
2935       }
2936     }
2937     return Just<int64_t>(-1);
2938   }
2939 };
2940 
2941 class FastPackedDoubleElementsAccessor
2942     : public FastDoubleElementsAccessor<
2943           FastPackedDoubleElementsAccessor,
2944           ElementsKindTraits<PACKED_DOUBLE_ELEMENTS>> {};
2945 
2946 class FastHoleyDoubleElementsAccessor
2947     : public FastDoubleElementsAccessor<
2948           FastHoleyDoubleElementsAccessor,
2949           ElementsKindTraits<HOLEY_DOUBLE_ELEMENTS>> {};
2950 
2951 // Super class for all external element arrays.
2952 template <ElementsKind Kind, typename ElementType>
2953 class TypedElementsAccessor
2954     : public ElementsAccessorBase<TypedElementsAccessor<Kind, ElementType>,
2955                                   ElementsKindTraits<Kind>> {
2956  public:
2957   using BackingStore = typename ElementsKindTraits<Kind>::BackingStore;
2958   using AccessorClass = TypedElementsAccessor<Kind, ElementType>;
2959 
2960   // Conversions from (other) scalar values.
FromScalar(int value)2961   static ElementType FromScalar(int value) {
2962     return static_cast<ElementType>(value);
2963   }
FromScalar(uint32_t value)2964   static ElementType FromScalar(uint32_t value) {
2965     return static_cast<ElementType>(value);
2966   }
FromScalar(double value)2967   static ElementType FromScalar(double value) {
2968     return FromScalar(DoubleToInt32(value));
2969   }
FromScalar(int64_t value)2970   static ElementType FromScalar(int64_t value) { UNREACHABLE(); }
FromScalar(uint64_t value)2971   static ElementType FromScalar(uint64_t value) { UNREACHABLE(); }
2972 
2973   // Conversions from objects / handles.
FromObject(Object value,bool * lossless=nullptr)2974   static ElementType FromObject(Object value, bool* lossless = nullptr) {
2975     if (value.IsSmi()) {
2976       return FromScalar(Smi::ToInt(value));
2977     } else if (value.IsHeapNumber()) {
2978       return FromScalar(HeapNumber::cast(value).value());
2979     } else {
2980       // Clamp undefined here as well. All other types have been
2981       // converted to a number type further up in the call chain.
2982       DCHECK(value.IsUndefined());
2983       return FromScalar(Oddball::cast(value).to_number_raw());
2984     }
2985   }
FromHandle(Handle<Object> value,bool * lossless=nullptr)2986   static ElementType FromHandle(Handle<Object> value,
2987                                 bool* lossless = nullptr) {
2988     return FromObject(*value, lossless);
2989   }
2990 
2991   // Conversion of scalar value to handlified object.
2992   static Handle<Object> ToHandle(Isolate* isolate, ElementType value);
2993 
SetImpl(Handle<JSObject> holder,InternalIndex entry,Object value)2994   static void SetImpl(Handle<JSObject> holder, InternalIndex entry,
2995                       Object value) {
2996     Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(holder);
2997     DCHECK_LE(entry.raw_value(), typed_array->length());
2998     SetImpl(static_cast<ElementType*>(typed_array->DataPtr()),
2999             entry.raw_value(), FromObject(value));
3000   }
3001 
SetImpl(ElementType * data_ptr,size_t entry,ElementType value)3002   static void SetImpl(ElementType* data_ptr, size_t entry, ElementType value) {
3003     // The JavaScript memory model allows for racy reads and writes to a
3004     // SharedArrayBuffer's backing store. ThreadSanitizer will catch these
3005     // racy accesses and warn about them, so we disable TSAN for these reads
3006     // and writes using annotations.
3007     //
3008     // We don't use relaxed atomics here, as it is not a requirement of the
3009     // JavaScript memory model to have tear-free reads of overlapping accesses,
3010     // and using relaxed atomics may introduce overhead.
3011     TSAN_ANNOTATE_IGNORE_WRITES_BEGIN;
3012     if (COMPRESS_POINTERS_BOOL && alignof(ElementType) > kTaggedSize) {
3013       // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
3014       // fields (external pointers, doubles and BigInt data) are only
3015       // kTaggedSize aligned so we have to use unaligned pointer friendly way of
3016       // accessing them in order to avoid undefined behavior in C++ code.
3017       base::WriteUnalignedValue<ElementType>(
3018           reinterpret_cast<Address>(data_ptr + entry), value);
3019     } else {
3020       data_ptr[entry] = value;
3021     }
3022     TSAN_ANNOTATE_IGNORE_WRITES_END;
3023   }
3024 
GetInternalImpl(Handle<JSObject> holder,InternalIndex entry)3025   static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
3026                                         InternalIndex entry) {
3027     Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(holder);
3028     Isolate* isolate = typed_array->GetIsolate();
3029     DCHECK_LE(entry.raw_value(), typed_array->length());
3030     DCHECK(!typed_array->WasDetached());
3031     ElementType elem = GetImpl(
3032         static_cast<ElementType*>(typed_array->DataPtr()), entry.raw_value());
3033     return ToHandle(isolate, elem);
3034   }
3035 
GetImpl(Isolate * isolate,FixedArrayBase backing_store,InternalIndex entry)3036   static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
3037                                 InternalIndex entry) {
3038     UNREACHABLE();
3039   }
3040 
GetImpl(ElementType * data_ptr,size_t entry)3041   static ElementType GetImpl(ElementType* data_ptr, size_t entry) {
3042     // The JavaScript memory model allows for racy reads and writes to a
3043     // SharedArrayBuffer's backing store. ThreadSanitizer will catch these
3044     // racy accesses and warn about them, so we disable TSAN for these reads
3045     // and writes using annotations.
3046     //
3047     // We don't use relaxed atomics here, as it is not a requirement of the
3048     // JavaScript memory model to have tear-free reads of overlapping accesses,
3049     // and using relaxed atomics may introduce overhead.
3050     TSAN_ANNOTATE_IGNORE_READS_BEGIN;
3051     ElementType result;
3052     if (COMPRESS_POINTERS_BOOL && alignof(ElementType) > kTaggedSize) {
3053       // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size
3054       // fields (external pointers, doubles and BigInt data) are only
3055       // kTaggedSize aligned so we have to use unaligned pointer friendly way of
3056       // accessing them in order to avoid undefined behavior in C++ code.
3057       result = base::ReadUnalignedValue<ElementType>(
3058           reinterpret_cast<Address>(data_ptr + entry));
3059     } else {
3060       result = data_ptr[entry];
3061     }
3062     TSAN_ANNOTATE_IGNORE_READS_END;
3063     return result;
3064   }
3065 
GetDetailsImpl(JSObject holder,InternalIndex entry)3066   static PropertyDetails GetDetailsImpl(JSObject holder, InternalIndex entry) {
3067     return PropertyDetails(kData, DONT_DELETE, PropertyCellType::kNoCell);
3068   }
3069 
GetDetailsImpl(FixedArrayBase backing_store,InternalIndex entry)3070   static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
3071                                         InternalIndex entry) {
3072     return PropertyDetails(kData, DONT_DELETE, PropertyCellType::kNoCell);
3073   }
3074 
HasElementImpl(Isolate * isolate,JSObject holder,size_t index,FixedArrayBase backing_store,PropertyFilter filter)3075   static bool HasElementImpl(Isolate* isolate, JSObject holder, size_t index,
3076                              FixedArrayBase backing_store,
3077                              PropertyFilter filter) {
3078     return index < AccessorClass::GetCapacityImpl(holder, backing_store);
3079   }
3080 
HasAccessorsImpl(JSObject holder,FixedArrayBase backing_store)3081   static bool HasAccessorsImpl(JSObject holder, FixedArrayBase backing_store) {
3082     return false;
3083   }
3084 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)3085   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
3086                             uint32_t length,
3087                             Handle<FixedArrayBase> backing_store) {
3088     // External arrays do not support changing their length.
3089     UNREACHABLE();
3090   }
3091 
DeleteImpl(Handle<JSObject> obj,InternalIndex entry)3092   static void DeleteImpl(Handle<JSObject> obj, InternalIndex entry) {
3093     UNREACHABLE();
3094   }
3095 
GetEntryForIndexImpl(Isolate * isolate,JSObject holder,FixedArrayBase backing_store,size_t index,PropertyFilter filter)3096   static InternalIndex GetEntryForIndexImpl(Isolate* isolate, JSObject holder,
3097                                             FixedArrayBase backing_store,
3098                                             size_t index,
3099                                             PropertyFilter filter) {
3100     return index < AccessorClass::GetCapacityImpl(holder, backing_store)
3101                ? InternalIndex(index)
3102                : InternalIndex::NotFound();
3103   }
3104 
GetCapacityImpl(JSObject holder,FixedArrayBase backing_store)3105   static size_t GetCapacityImpl(JSObject holder, FixedArrayBase backing_store) {
3106     JSTypedArray typed_array = JSTypedArray::cast(holder);
3107     if (typed_array.WasDetached()) return 0;
3108     return typed_array.length();
3109   }
3110 
NumberOfElementsImpl(JSObject receiver,FixedArrayBase backing_store)3111   static size_t NumberOfElementsImpl(JSObject receiver,
3112                                      FixedArrayBase backing_store) {
3113     return AccessorClass::GetCapacityImpl(receiver, backing_store);
3114   }
3115 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)3116   V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
3117       Handle<JSObject> receiver, KeyAccumulator* accumulator,
3118       AddKeyConversion convert) {
3119     Isolate* isolate = receiver->GetIsolate();
3120     Handle<FixedArrayBase> elements(receiver->elements(), isolate);
3121     size_t length = AccessorClass::GetCapacityImpl(*receiver, *elements);
3122     for (size_t i = 0; i < length; i++) {
3123       Handle<Object> value =
3124           AccessorClass::GetInternalImpl(receiver, InternalIndex(i));
3125       RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(value, convert));
3126     }
3127     return ExceptionStatus::kSuccess;
3128   }
3129 
CollectValuesOrEntriesImpl(Isolate * isolate,Handle<JSObject> object,Handle<FixedArray> values_or_entries,bool get_entries,int * nof_items,PropertyFilter filter)3130   static Maybe<bool> CollectValuesOrEntriesImpl(
3131       Isolate* isolate, Handle<JSObject> object,
3132       Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
3133       PropertyFilter filter) {
3134     int count = 0;
3135     if ((filter & ONLY_CONFIGURABLE) == 0) {
3136       Handle<FixedArrayBase> elements(object->elements(), isolate);
3137       size_t length = AccessorClass::GetCapacityImpl(*object, *elements);
3138       for (size_t index = 0; index < length; ++index) {
3139         Handle<Object> value =
3140             AccessorClass::GetInternalImpl(object, InternalIndex(index));
3141         if (get_entries) {
3142           value = MakeEntryPair(isolate, index, value);
3143         }
3144         values_or_entries->set(count++, *value);
3145       }
3146     }
3147     *nof_items = count;
3148     return Just(true);
3149   }
3150 
FillImpl(Handle<JSObject> receiver,Handle<Object> value,size_t start,size_t end)3151   static Object FillImpl(Handle<JSObject> receiver, Handle<Object> value,
3152                          size_t start, size_t end) {
3153     Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(receiver);
3154     DCHECK(!typed_array->WasDetached());
3155     DCHECK_LE(start, end);
3156     DCHECK_LE(end, typed_array->length());
3157     DisallowHeapAllocation no_gc;
3158     ElementType scalar = FromHandle(value);
3159     ElementType* data = static_cast<ElementType*>(typed_array->DataPtr());
3160     if (COMPRESS_POINTERS_BOOL && alignof(ElementType) > kTaggedSize) {
3161       // TODO(ishell, v8:8875): See UnalignedSlot<T> for details.
3162       std::fill(UnalignedSlot<ElementType>(data + start),
3163                 UnalignedSlot<ElementType>(data + end), scalar);
3164     } else {
3165       std::fill(data + start, data + end, scalar);
3166     }
3167     return *typed_array;
3168   }
3169 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)3170   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
3171                                        Handle<JSObject> receiver,
3172                                        Handle<Object> value, size_t start_from,
3173                                        size_t length) {
3174     DisallowHeapAllocation no_gc;
3175     JSTypedArray typed_array = JSTypedArray::cast(*receiver);
3176 
3177     // TODO(caitp): return Just(false) here when implementing strict throwing on
3178     // detached views.
3179     if (typed_array.WasDetached()) {
3180       return Just(value->IsUndefined(isolate) && length > start_from);
3181     }
3182 
3183     if (value->IsUndefined(isolate) && length > typed_array.length()) {
3184       return Just(true);
3185     }
3186 
3187     // Prototype has no elements, and not searching for the hole --- limit
3188     // search to backing store length.
3189     if (typed_array.length() < length) {
3190       length = typed_array.length();
3191     }
3192 
3193     ElementType typed_search_value;
3194     ElementType* data_ptr =
3195         reinterpret_cast<ElementType*>(typed_array.DataPtr());
3196     if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
3197       if (!value->IsBigInt()) return Just(false);
3198       bool lossless;
3199       typed_search_value = FromHandle(value, &lossless);
3200       if (!lossless) return Just(false);
3201     } else {
3202       if (!value->IsNumber()) return Just(false);
3203       double search_value = value->Number();
3204       if (!std::isfinite(search_value)) {
3205         // Integral types cannot represent +Inf or NaN.
3206         if (Kind < FLOAT32_ELEMENTS || Kind > FLOAT64_ELEMENTS) {
3207           return Just(false);
3208         }
3209         if (std::isnan(search_value)) {
3210           for (size_t k = start_from; k < length; ++k) {
3211             double elem_k =
3212                 static_cast<double>(AccessorClass::GetImpl(data_ptr, k));
3213             if (std::isnan(elem_k)) return Just(true);
3214           }
3215           return Just(false);
3216         }
3217       } else if (search_value < std::numeric_limits<ElementType>::lowest() ||
3218                  search_value > std::numeric_limits<ElementType>::max()) {
3219         // Return false if value can't be represented in this space.
3220         return Just(false);
3221       }
3222       typed_search_value = static_cast<ElementType>(search_value);
3223       if (static_cast<double>(typed_search_value) != search_value) {
3224         return Just(false);  // Loss of precision.
3225       }
3226     }
3227 
3228     for (size_t k = start_from; k < length; ++k) {
3229       ElementType elem_k = AccessorClass::GetImpl(data_ptr, k);
3230       if (elem_k == typed_search_value) return Just(true);
3231     }
3232     return Just(false);
3233   }
3234 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> receiver,Handle<Object> value,size_t start_from,size_t length)3235   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
3236                                          Handle<JSObject> receiver,
3237                                          Handle<Object> value,
3238                                          size_t start_from, size_t length) {
3239     DisallowHeapAllocation no_gc;
3240     JSTypedArray typed_array = JSTypedArray::cast(*receiver);
3241 
3242     if (typed_array.WasDetached()) return Just<int64_t>(-1);
3243 
3244     ElementType typed_search_value;
3245 
3246     ElementType* data_ptr =
3247         reinterpret_cast<ElementType*>(typed_array.DataPtr());
3248     if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
3249       if (!value->IsBigInt()) return Just<int64_t>(-1);
3250       bool lossless;
3251       typed_search_value = FromHandle(value, &lossless);
3252       if (!lossless) return Just<int64_t>(-1);
3253     } else {
3254       if (!value->IsNumber()) return Just<int64_t>(-1);
3255       double search_value = value->Number();
3256       if (!std::isfinite(search_value)) {
3257         // Integral types cannot represent +Inf or NaN.
3258         if (Kind < FLOAT32_ELEMENTS || Kind > FLOAT64_ELEMENTS) {
3259           return Just<int64_t>(-1);
3260         }
3261         if (std::isnan(search_value)) {
3262           return Just<int64_t>(-1);
3263         }
3264       } else if (search_value < std::numeric_limits<ElementType>::lowest() ||
3265                  search_value > std::numeric_limits<ElementType>::max()) {
3266         // Return false if value can't be represented in this ElementsKind.
3267         return Just<int64_t>(-1);
3268       }
3269       typed_search_value = static_cast<ElementType>(search_value);
3270       if (static_cast<double>(typed_search_value) != search_value) {
3271         return Just<int64_t>(-1);  // Loss of precision.
3272       }
3273     }
3274 
3275     // Prototype has no elements, and not searching for the hole --- limit
3276     // search to backing store length.
3277     if (typed_array.length() < length) {
3278       length = typed_array.length();
3279     }
3280 
3281     for (size_t k = start_from; k < length; ++k) {
3282       ElementType elem_k = AccessorClass::GetImpl(data_ptr, k);
3283       if (elem_k == typed_search_value) return Just<int64_t>(k);
3284     }
3285     return Just<int64_t>(-1);
3286   }
3287 
LastIndexOfValueImpl(Handle<JSObject> receiver,Handle<Object> value,size_t start_from)3288   static Maybe<int64_t> LastIndexOfValueImpl(Handle<JSObject> receiver,
3289                                              Handle<Object> value,
3290                                              size_t start_from) {
3291     DisallowHeapAllocation no_gc;
3292     JSTypedArray typed_array = JSTypedArray::cast(*receiver);
3293 
3294     DCHECK(!typed_array.WasDetached());
3295 
3296     ElementType typed_search_value;
3297 
3298     ElementType* data_ptr =
3299         reinterpret_cast<ElementType*>(typed_array.DataPtr());
3300     if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
3301       if (!value->IsBigInt()) return Just<int64_t>(-1);
3302       bool lossless;
3303       typed_search_value = FromHandle(value, &lossless);
3304       if (!lossless) return Just<int64_t>(-1);
3305     } else {
3306       if (!value->IsNumber()) return Just<int64_t>(-1);
3307       double search_value = value->Number();
3308       if (!std::isfinite(search_value)) {
3309         if (std::is_integral<ElementType>::value) {
3310           // Integral types cannot represent +Inf or NaN.
3311           return Just<int64_t>(-1);
3312         } else if (std::isnan(search_value)) {
3313           // Strict Equality Comparison of NaN is always false.
3314           return Just<int64_t>(-1);
3315         }
3316       } else if (search_value < std::numeric_limits<ElementType>::lowest() ||
3317                  search_value > std::numeric_limits<ElementType>::max()) {
3318         // Return -1 if value can't be represented in this ElementsKind.
3319         return Just<int64_t>(-1);
3320       }
3321       typed_search_value = static_cast<ElementType>(search_value);
3322       if (static_cast<double>(typed_search_value) != search_value) {
3323         return Just<int64_t>(-1);  // Loss of precision.
3324       }
3325     }
3326 
3327     DCHECK_LT(start_from, typed_array.length());
3328     size_t k = start_from;
3329     do {
3330       ElementType elem_k = AccessorClass::GetImpl(data_ptr, k);
3331       if (elem_k == typed_search_value) return Just<int64_t>(k);
3332     } while (k-- != 0);
3333     return Just<int64_t>(-1);
3334   }
3335 
ReverseImpl(JSObject receiver)3336   static void ReverseImpl(JSObject receiver) {
3337     DisallowHeapAllocation no_gc;
3338     JSTypedArray typed_array = JSTypedArray::cast(receiver);
3339 
3340     DCHECK(!typed_array.WasDetached());
3341 
3342     size_t len = typed_array.length();
3343     if (len == 0) return;
3344 
3345     ElementType* data = static_cast<ElementType*>(typed_array.DataPtr());
3346     if (COMPRESS_POINTERS_BOOL && alignof(ElementType) > kTaggedSize) {
3347       // TODO(ishell, v8:8875): See UnalignedSlot<T> for details.
3348       std::reverse(UnalignedSlot<ElementType>(data),
3349                    UnalignedSlot<ElementType>(data + len));
3350     } else {
3351       std::reverse(data, data + len);
3352     }
3353   }
3354 
CreateListFromArrayLikeImpl(Isolate * isolate,Handle<JSObject> object,uint32_t length)3355   static Handle<FixedArray> CreateListFromArrayLikeImpl(Isolate* isolate,
3356                                                         Handle<JSObject> object,
3357                                                         uint32_t length) {
3358     Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
3359     Handle<FixedArray> result = isolate->factory()->NewFixedArray(length);
3360     for (uint32_t i = 0; i < length; i++) {
3361       Handle<Object> value =
3362           AccessorClass::GetInternalImpl(typed_array, InternalIndex(i));
3363       result->set(i, *value);
3364     }
3365     return result;
3366   }
3367 
CopyTypedArrayElementsSliceImpl(JSTypedArray source,JSTypedArray destination,size_t start,size_t end)3368   static void CopyTypedArrayElementsSliceImpl(JSTypedArray source,
3369                                               JSTypedArray destination,
3370                                               size_t start, size_t end) {
3371     DisallowHeapAllocation no_gc;
3372     DCHECK_EQ(destination.GetElementsKind(), AccessorClass::kind());
3373     CHECK(!source.WasDetached());
3374     CHECK(!destination.WasDetached());
3375     DCHECK_LE(start, end);
3376     DCHECK_LE(end, source.length());
3377     size_t count = end - start;
3378     DCHECK_LE(count, destination.length());
3379     ElementType* dest_data = static_cast<ElementType*>(destination.DataPtr());
3380     switch (source.GetElementsKind()) {
3381 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                            \
3382   case TYPE##_ELEMENTS: {                                                    \
3383     ctype* source_data = reinterpret_cast<ctype*>(source.DataPtr()) + start; \
3384     CopyBetweenBackingStores<TYPE##_ELEMENTS, ctype>(source_data, dest_data, \
3385                                                      count);                 \
3386     break;                                                                   \
3387   }
3388       TYPED_ARRAYS(TYPED_ARRAY_CASE)
3389 #undef TYPED_ARRAY_CASE
3390       default:
3391         UNREACHABLE();
3392         break;
3393     }
3394   }
3395 
HasSimpleRepresentation(ExternalArrayType type)3396   static bool HasSimpleRepresentation(ExternalArrayType type) {
3397     return !(type == kExternalFloat32Array || type == kExternalFloat64Array ||
3398              type == kExternalUint8ClampedArray);
3399   }
3400 
3401   template <ElementsKind SourceKind, typename SourceElementType>
CopyBetweenBackingStores(SourceElementType * source_data_ptr,ElementType * dest_data_ptr,size_t length)3402   static void CopyBetweenBackingStores(SourceElementType* source_data_ptr,
3403                                        ElementType* dest_data_ptr,
3404                                        size_t length) {
3405     DisallowHeapAllocation no_gc;
3406     for (size_t i = 0; i < length; i++) {
3407       // We use scalar accessors to avoid boxing/unboxing, so there are no
3408       // allocations.
3409       SourceElementType source_elem =
3410           TypedElementsAccessor<SourceKind, SourceElementType>::GetImpl(
3411               source_data_ptr, i);
3412       ElementType dest_elem = FromScalar(source_elem);
3413       SetImpl(dest_data_ptr, i, dest_elem);
3414     }
3415   }
3416 
CopyElementsFromTypedArray(JSTypedArray source,JSTypedArray destination,size_t length,size_t offset)3417   static void CopyElementsFromTypedArray(JSTypedArray source,
3418                                          JSTypedArray destination,
3419                                          size_t length, size_t offset) {
3420     // The source is a typed array, so we know we don't need to do ToNumber
3421     // side-effects, as the source elements will always be a number.
3422     DisallowHeapAllocation no_gc;
3423 
3424     CHECK(!source.WasDetached());
3425     CHECK(!destination.WasDetached());
3426 
3427     DCHECK_LE(offset, destination.length());
3428     DCHECK_LE(length, destination.length() - offset);
3429     DCHECK_LE(length, source.length());
3430 
3431     ExternalArrayType source_type = source.type();
3432     ExternalArrayType destination_type = destination.type();
3433 
3434     bool same_type = source_type == destination_type;
3435     bool same_size = source.element_size() == destination.element_size();
3436     bool both_are_simple = HasSimpleRepresentation(source_type) &&
3437                            HasSimpleRepresentation(destination_type);
3438 
3439     uint8_t* source_data = static_cast<uint8_t*>(source.DataPtr());
3440     uint8_t* dest_data = static_cast<uint8_t*>(destination.DataPtr());
3441     size_t source_byte_length = source.byte_length();
3442     size_t dest_byte_length = destination.byte_length();
3443 
3444     // We can simply copy the backing store if the types are the same, or if
3445     // we are converting e.g. Uint8 <-> Int8, as the binary representation
3446     // will be the same. This is not the case for floats or clamped Uint8,
3447     // which have special conversion operations.
3448     if (same_type || (same_size && both_are_simple)) {
3449       size_t element_size = source.element_size();
3450       std::memmove(dest_data + offset * element_size, source_data,
3451                    length * element_size);
3452     } else {
3453       std::unique_ptr<uint8_t[]> cloned_source_elements;
3454 
3455       // If the typedarrays are overlapped, clone the source.
3456       if (dest_data + dest_byte_length > source_data &&
3457           source_data + source_byte_length > dest_data) {
3458         cloned_source_elements.reset(new uint8_t[source_byte_length]);
3459         std::memcpy(cloned_source_elements.get(), source_data,
3460                     source_byte_length);
3461         source_data = cloned_source_elements.get();
3462       }
3463 
3464       switch (source.GetElementsKind()) {
3465 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)                    \
3466   case TYPE##_ELEMENTS:                                              \
3467     CopyBetweenBackingStores<TYPE##_ELEMENTS, ctype>(                \
3468         reinterpret_cast<ctype*>(source_data),                       \
3469         reinterpret_cast<ElementType*>(dest_data) + offset, length); \
3470     break;
3471         TYPED_ARRAYS(TYPED_ARRAY_CASE)
3472         default:
3473           UNREACHABLE();
3474           break;
3475       }
3476 #undef TYPED_ARRAY_CASE
3477     }
3478   }
3479 
HoleyPrototypeLookupRequired(Isolate * isolate,Context context,JSArray source)3480   static bool HoleyPrototypeLookupRequired(Isolate* isolate, Context context,
3481                                            JSArray source) {
3482     DisallowHeapAllocation no_gc;
3483     DisallowJavascriptExecution no_js(isolate);
3484 
3485 #ifdef V8_ENABLE_FORCE_SLOW_PATH
3486     if (isolate->force_slow_path()) return true;
3487 #endif
3488 
3489     Object source_proto = source.map().prototype();
3490 
3491     // Null prototypes are OK - we don't need to do prototype chain lookups on
3492     // them.
3493     if (source_proto.IsNull(isolate)) return false;
3494     if (source_proto.IsJSProxy()) return true;
3495     if (!context.native_context().is_initial_array_prototype(
3496             JSObject::cast(source_proto))) {
3497       return true;
3498     }
3499 
3500     return !Protectors::IsNoElementsIntact(isolate);
3501   }
3502 
TryCopyElementsFastNumber(Context context,JSArray source,JSTypedArray destination,size_t length,size_t offset)3503   static bool TryCopyElementsFastNumber(Context context, JSArray source,
3504                                         JSTypedArray destination, size_t length,
3505                                         size_t offset) {
3506     if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) return false;
3507     Isolate* isolate = source.GetIsolate();
3508     DisallowHeapAllocation no_gc;
3509     DisallowJavascriptExecution no_js(isolate);
3510 
3511     CHECK(!destination.WasDetached());
3512 
3513     size_t current_length;
3514     DCHECK(source.length().IsNumber() &&
3515            TryNumberToSize(source.length(), &current_length) &&
3516            length <= current_length);
3517     USE(current_length);
3518 
3519     size_t dest_length = destination.length();
3520     DCHECK(length + offset <= dest_length);
3521     USE(dest_length);
3522 
3523     ElementsKind kind = source.GetElementsKind();
3524 
3525     // When we find the hole, we normally have to look up the element on the
3526     // prototype chain, which is not handled here and we return false instead.
3527     // When the array has the original array prototype, and that prototype has
3528     // not been changed in a way that would affect lookups, we can just convert
3529     // the hole into undefined.
3530     if (HoleyPrototypeLookupRequired(isolate, context, source)) return false;
3531 
3532     Oddball undefined = ReadOnlyRoots(isolate).undefined_value();
3533     ElementType* dest_data =
3534         reinterpret_cast<ElementType*>(destination.DataPtr()) + offset;
3535 
3536     // Fast-path for packed Smi kind.
3537     if (kind == PACKED_SMI_ELEMENTS) {
3538       FixedArray source_store = FixedArray::cast(source.elements());
3539 
3540       for (size_t i = 0; i < length; i++) {
3541         Object elem = source_store.get(static_cast<int>(i));
3542         SetImpl(dest_data, i, FromScalar(Smi::ToInt(elem)));
3543       }
3544       return true;
3545     } else if (kind == HOLEY_SMI_ELEMENTS) {
3546       FixedArray source_store = FixedArray::cast(source.elements());
3547       for (size_t i = 0; i < length; i++) {
3548         if (source_store.is_the_hole(isolate, static_cast<int>(i))) {
3549           SetImpl(dest_data, i, FromObject(undefined));
3550         } else {
3551           Object elem = source_store.get(static_cast<int>(i));
3552           SetImpl(dest_data, i, FromScalar(Smi::ToInt(elem)));
3553         }
3554       }
3555       return true;
3556     } else if (kind == PACKED_DOUBLE_ELEMENTS) {
3557       // Fast-path for packed double kind. We avoid boxing and then immediately
3558       // unboxing the double here by using get_scalar.
3559       FixedDoubleArray source_store = FixedDoubleArray::cast(source.elements());
3560 
3561       for (size_t i = 0; i < length; i++) {
3562         // Use the from_double conversion for this specific TypedArray type,
3563         // rather than relying on C++ to convert elem.
3564         double elem = source_store.get_scalar(static_cast<int>(i));
3565         SetImpl(dest_data, i, FromScalar(elem));
3566       }
3567       return true;
3568     } else if (kind == HOLEY_DOUBLE_ELEMENTS) {
3569       FixedDoubleArray source_store = FixedDoubleArray::cast(source.elements());
3570       for (size_t i = 0; i < length; i++) {
3571         if (source_store.is_the_hole(static_cast<int>(i))) {
3572           SetImpl(dest_data, i, FromObject(undefined));
3573         } else {
3574           double elem = source_store.get_scalar(static_cast<int>(i));
3575           SetImpl(dest_data, i, FromScalar(elem));
3576         }
3577       }
3578       return true;
3579     }
3580     return false;
3581   }
3582 
CopyElementsHandleSlow(Handle<Object> source,Handle<JSTypedArray> destination,size_t length,size_t offset)3583   static Object CopyElementsHandleSlow(Handle<Object> source,
3584                                        Handle<JSTypedArray> destination,
3585                                        size_t length, size_t offset) {
3586     Isolate* isolate = destination->GetIsolate();
3587     for (size_t i = 0; i < length; i++) {
3588       Handle<Object> elem;
3589       LookupIterator it(isolate, source, i);
3590       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
3591                                          Object::GetProperty(&it));
3592       if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
3593         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
3594                                            BigInt::FromObject(isolate, elem));
3595       } else {
3596         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
3597                                            Object::ToNumber(isolate, elem));
3598       }
3599 
3600       if (V8_UNLIKELY(destination->WasDetached())) {
3601         const char* op = "set";
3602         const MessageTemplate message = MessageTemplate::kDetachedOperation;
3603         Handle<String> operation =
3604             isolate->factory()->NewStringFromAsciiChecked(op);
3605         THROW_NEW_ERROR_RETURN_FAILURE(isolate,
3606                                        NewTypeError(message, operation));
3607       }
3608       // The spec says we store the length, then get each element, so we don't
3609       // need to check changes to length.
3610       SetImpl(destination, InternalIndex(offset + i), *elem);
3611     }
3612     return *isolate->factory()->undefined_value();
3613   }
3614 
3615   // This doesn't guarantee that the destination array will be completely
3616   // filled. The caller must do this by passing a source with equal length, if
3617   // that is required.
CopyElementsHandleImpl(Handle<Object> source,Handle<JSObject> destination,size_t length,size_t offset)3618   static Object CopyElementsHandleImpl(Handle<Object> source,
3619                                        Handle<JSObject> destination,
3620                                        size_t length, size_t offset) {
3621     Isolate* isolate = destination->GetIsolate();
3622     Handle<JSTypedArray> destination_ta =
3623         Handle<JSTypedArray>::cast(destination);
3624     DCHECK_LE(offset + length, destination_ta->length());
3625     CHECK(!destination_ta->WasDetached());
3626 
3627     if (length == 0) return *isolate->factory()->undefined_value();
3628 
3629     // All conversions from TypedArrays can be done without allocation.
3630     if (source->IsJSTypedArray()) {
3631       Handle<JSTypedArray> source_ta = Handle<JSTypedArray>::cast(source);
3632       ElementsKind source_kind = source_ta->GetElementsKind();
3633       bool source_is_bigint =
3634           source_kind == BIGINT64_ELEMENTS || source_kind == BIGUINT64_ELEMENTS;
3635       bool target_is_bigint =
3636           Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS;
3637       // If we have to copy more elements than we have in the source, we need to
3638       // do special handling and conversion; that happens in the slow case.
3639       if (source_is_bigint == target_is_bigint && !source_ta->WasDetached() &&
3640           length + offset <= source_ta->length()) {
3641         CopyElementsFromTypedArray(*source_ta, *destination_ta, length, offset);
3642         return *isolate->factory()->undefined_value();
3643       }
3644     } else if (source->IsJSArray()) {
3645       // Fast cases for packed numbers kinds where we don't need to allocate.
3646       Handle<JSArray> source_js_array = Handle<JSArray>::cast(source);
3647       size_t current_length;
3648       DCHECK(source_js_array->length().IsNumber());
3649       if (TryNumberToSize(source_js_array->length(), &current_length) &&
3650           length <= current_length) {
3651         Handle<JSArray> source_array = Handle<JSArray>::cast(source);
3652         if (TryCopyElementsFastNumber(isolate->context(), *source_array,
3653                                       *destination_ta, length, offset)) {
3654           return *isolate->factory()->undefined_value();
3655         }
3656       }
3657     }
3658     // Final generic case that handles prototype chain lookups, getters, proxies
3659     // and observable side effects via valueOf, etc.
3660     return CopyElementsHandleSlow(source, destination_ta, length, offset);
3661   }
3662 };
3663 
3664 // static
3665 template <>
ToHandle(Isolate * isolate,int8_t value)3666 Handle<Object> TypedElementsAccessor<INT8_ELEMENTS, int8_t>::ToHandle(
3667     Isolate* isolate, int8_t value) {
3668   return handle(Smi::FromInt(value), isolate);
3669 }
3670 
3671 // static
3672 template <>
ToHandle(Isolate * isolate,uint8_t value)3673 Handle<Object> TypedElementsAccessor<UINT8_ELEMENTS, uint8_t>::ToHandle(
3674     Isolate* isolate, uint8_t value) {
3675   return handle(Smi::FromInt(value), isolate);
3676 }
3677 
3678 // static
3679 template <>
ToHandle(Isolate * isolate,int16_t value)3680 Handle<Object> TypedElementsAccessor<INT16_ELEMENTS, int16_t>::ToHandle(
3681     Isolate* isolate, int16_t value) {
3682   return handle(Smi::FromInt(value), isolate);
3683 }
3684 
3685 // static
3686 template <>
ToHandle(Isolate * isolate,uint16_t value)3687 Handle<Object> TypedElementsAccessor<UINT16_ELEMENTS, uint16_t>::ToHandle(
3688     Isolate* isolate, uint16_t value) {
3689   return handle(Smi::FromInt(value), isolate);
3690 }
3691 
3692 // static
3693 template <>
ToHandle(Isolate * isolate,int32_t value)3694 Handle<Object> TypedElementsAccessor<INT32_ELEMENTS, int32_t>::ToHandle(
3695     Isolate* isolate, int32_t value) {
3696   return isolate->factory()->NewNumberFromInt(value);
3697 }
3698 
3699 // static
3700 template <>
ToHandle(Isolate * isolate,uint32_t value)3701 Handle<Object> TypedElementsAccessor<UINT32_ELEMENTS, uint32_t>::ToHandle(
3702     Isolate* isolate, uint32_t value) {
3703   return isolate->factory()->NewNumberFromUint(value);
3704 }
3705 
3706 // static
3707 template <>
FromScalar(double value)3708 float TypedElementsAccessor<FLOAT32_ELEMENTS, float>::FromScalar(double value) {
3709   return DoubleToFloat32(value);
3710 }
3711 
3712 // static
3713 template <>
ToHandle(Isolate * isolate,float value)3714 Handle<Object> TypedElementsAccessor<FLOAT32_ELEMENTS, float>::ToHandle(
3715     Isolate* isolate, float value) {
3716   return isolate->factory()->NewNumber(value);
3717 }
3718 
3719 // static
3720 template <>
FromScalar(double value)3721 double TypedElementsAccessor<FLOAT64_ELEMENTS, double>::FromScalar(
3722     double value) {
3723   return value;
3724 }
3725 
3726 // static
3727 template <>
ToHandle(Isolate * isolate,double value)3728 Handle<Object> TypedElementsAccessor<FLOAT64_ELEMENTS, double>::ToHandle(
3729     Isolate* isolate, double value) {
3730   return isolate->factory()->NewNumber(value);
3731 }
3732 
3733 // static
3734 template <>
FromScalar(int value)3735 uint8_t TypedElementsAccessor<UINT8_CLAMPED_ELEMENTS, uint8_t>::FromScalar(
3736     int value) {
3737   if (value < 0x00) return 0x00;
3738   if (value > 0xFF) return 0xFF;
3739   return static_cast<uint8_t>(value);
3740 }
3741 
3742 // static
3743 template <>
FromScalar(uint32_t value)3744 uint8_t TypedElementsAccessor<UINT8_CLAMPED_ELEMENTS, uint8_t>::FromScalar(
3745     uint32_t value) {
3746   // We need this special case for Uint32 -> Uint8Clamped, because the highest
3747   // Uint32 values will be negative as an int, clamping to 0, rather than 255.
3748   if (value > 0xFF) return 0xFF;
3749   return static_cast<uint8_t>(value);
3750 }
3751 
3752 // static
3753 template <>
FromScalar(double value)3754 uint8_t TypedElementsAccessor<UINT8_CLAMPED_ELEMENTS, uint8_t>::FromScalar(
3755     double value) {
3756   // Handle NaNs and less than zero values which clamp to zero.
3757   if (!(value > 0)) return 0;
3758   if (value > 0xFF) return 0xFF;
3759   return static_cast<uint8_t>(lrint(value));
3760 }
3761 
3762 // static
3763 template <>
ToHandle(Isolate * isolate,uint8_t value)3764 Handle<Object> TypedElementsAccessor<UINT8_CLAMPED_ELEMENTS, uint8_t>::ToHandle(
3765     Isolate* isolate, uint8_t value) {
3766   return handle(Smi::FromInt(value), isolate);
3767 }
3768 
3769 // static
3770 template <>
FromScalar(int value)3771 int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
3772     int value) {
3773   UNREACHABLE();
3774 }
3775 
3776 // static
3777 template <>
FromScalar(uint32_t value)3778 int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
3779     uint32_t value) {
3780   UNREACHABLE();
3781 }
3782 
3783 // static
3784 template <>
FromScalar(double value)3785 int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
3786     double value) {
3787   UNREACHABLE();
3788 }
3789 
3790 // static
3791 template <>
FromScalar(int64_t value)3792 int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
3793     int64_t value) {
3794   return value;
3795 }
3796 
3797 // static
3798 template <>
FromScalar(uint64_t value)3799 int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
3800     uint64_t value) {
3801   return static_cast<int64_t>(value);
3802 }
3803 
3804 // static
3805 template <>
FromObject(Object value,bool * lossless)3806 int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromObject(
3807     Object value, bool* lossless) {
3808   return BigInt::cast(value).AsInt64(lossless);
3809 }
3810 
3811 // static
3812 template <>
ToHandle(Isolate * isolate,int64_t value)3813 Handle<Object> TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::ToHandle(
3814     Isolate* isolate, int64_t value) {
3815   return BigInt::FromInt64(isolate, value);
3816 }
3817 
3818 // static
3819 template <>
FromScalar(int value)3820 uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
3821     int value) {
3822   UNREACHABLE();
3823 }
3824 
3825 // static
3826 template <>
FromScalar(uint32_t value)3827 uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
3828     uint32_t value) {
3829   UNREACHABLE();
3830 }
3831 
3832 // static
3833 template <>
FromScalar(double value)3834 uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
3835     double value) {
3836   UNREACHABLE();
3837 }
3838 
3839 // static
3840 template <>
FromScalar(int64_t value)3841 uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
3842     int64_t value) {
3843   return static_cast<uint64_t>(value);
3844 }
3845 
3846 // static
3847 template <>
FromScalar(uint64_t value)3848 uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
3849     uint64_t value) {
3850   return value;
3851 }
3852 
3853 // static
3854 template <>
FromObject(Object value,bool * lossless)3855 uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromObject(
3856     Object value, bool* lossless) {
3857   return BigInt::cast(value).AsUint64(lossless);
3858 }
3859 
3860 // static
3861 template <>
ToHandle(Isolate * isolate,uint64_t value)3862 Handle<Object> TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::ToHandle(
3863     Isolate* isolate, uint64_t value) {
3864   return BigInt::FromUint64(isolate, value);
3865 }
3866 
3867 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype) \
3868   using Type##ElementsAccessor = TypedElementsAccessor<TYPE##_ELEMENTS, ctype>;
3869 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
3870 #undef FIXED_ELEMENTS_ACCESSOR
3871 
3872 template <typename Subclass, typename ArgumentsAccessor, typename KindTraits>
3873 class SloppyArgumentsElementsAccessor
3874     : public ElementsAccessorBase<Subclass, KindTraits> {
3875  public:
ConvertArgumentsStoreResult(Handle<SloppyArgumentsElements> elements,Handle<Object> result)3876   static void ConvertArgumentsStoreResult(
3877       Handle<SloppyArgumentsElements> elements, Handle<Object> result) {
3878     UNREACHABLE();
3879   }
3880 
GetImpl(Isolate * isolate,FixedArrayBase parameters,InternalIndex entry)3881   static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase parameters,
3882                                 InternalIndex entry) {
3883     Handle<SloppyArgumentsElements> elements(
3884         SloppyArgumentsElements::cast(parameters), isolate);
3885     uint32_t length = elements->parameter_map_length();
3886     if (entry.as_uint32() < length) {
3887       // Read context mapped entry.
3888       DisallowHeapAllocation no_gc;
3889       Object probe = elements->get_mapped_entry(entry.as_uint32());
3890       DCHECK(!probe.IsTheHole(isolate));
3891       Context context = elements->context();
3892       int context_entry = Smi::ToInt(probe);
3893       DCHECK(!context.get(context_entry).IsTheHole(isolate));
3894       return handle(context.get(context_entry), isolate);
3895     } else {
3896       // Entry is not context mapped, defer to the arguments.
3897       Handle<Object> result = ArgumentsAccessor::GetImpl(
3898           isolate, elements->arguments(), entry.adjust_down(length));
3899       return Subclass::ConvertArgumentsStoreResult(isolate, elements, result);
3900     }
3901   }
3902 
TransitionElementsKindImpl(Handle<JSObject> object,Handle<Map> map)3903   static void TransitionElementsKindImpl(Handle<JSObject> object,
3904                                          Handle<Map> map) {
3905     UNREACHABLE();
3906   }
3907 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)3908   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
3909                                          uint32_t capacity) {
3910     UNREACHABLE();
3911   }
3912 
SetImpl(Handle<JSObject> holder,InternalIndex entry,Object value)3913   static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
3914                              Object value) {
3915     SetImpl(holder->elements(), entry, value);
3916   }
3917 
SetImpl(FixedArrayBase store,InternalIndex entry,Object value)3918   static inline void SetImpl(FixedArrayBase store, InternalIndex entry,
3919                              Object value) {
3920     SloppyArgumentsElements elements = SloppyArgumentsElements::cast(store);
3921     uint32_t length = elements.parameter_map_length();
3922     if (entry.as_uint32() < length) {
3923       // Store context mapped entry.
3924       DisallowHeapAllocation no_gc;
3925       Object probe = elements.get_mapped_entry(entry.as_uint32());
3926       DCHECK(!probe.IsTheHole());
3927       Context context = elements.context();
3928       int context_entry = Smi::ToInt(probe);
3929       DCHECK(!context.get(context_entry).IsTheHole());
3930       context.set(context_entry, value);
3931     } else {
3932       //  Entry is not context mapped defer to arguments.
3933       FixedArray arguments = elements.arguments();
3934       Object current =
3935           ArgumentsAccessor::GetRaw(arguments, entry.adjust_down(length));
3936       if (current.IsAliasedArgumentsEntry()) {
3937         AliasedArgumentsEntry alias = AliasedArgumentsEntry::cast(current);
3938         Context context = elements.context();
3939         int context_entry = alias.aliased_context_slot();
3940         DCHECK(!context.get(context_entry).IsTheHole());
3941         context.set(context_entry, value);
3942       } else {
3943         ArgumentsAccessor::SetImpl(arguments, entry.adjust_down(length), value);
3944       }
3945     }
3946   }
3947 
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> parameter_map)3948   static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
3949                             uint32_t length,
3950                             Handle<FixedArrayBase> parameter_map) {
3951     // Sloppy arguments objects are not arrays.
3952     UNREACHABLE();
3953   }
3954 
GetCapacityImpl(JSObject holder,FixedArrayBase store)3955   static uint32_t GetCapacityImpl(JSObject holder, FixedArrayBase store) {
3956     SloppyArgumentsElements elements = SloppyArgumentsElements::cast(store);
3957     FixedArray arguments = elements.arguments();
3958     return elements.parameter_map_length() +
3959            ArgumentsAccessor::GetCapacityImpl(holder, arguments);
3960   }
3961 
GetMaxNumberOfEntries(JSObject holder,FixedArrayBase backing_store)3962   static uint32_t GetMaxNumberOfEntries(JSObject holder,
3963                                         FixedArrayBase backing_store) {
3964     SloppyArgumentsElements elements =
3965         SloppyArgumentsElements::cast(backing_store);
3966     FixedArrayBase arguments = elements.arguments();
3967     size_t max_entries =
3968         ArgumentsAccessor::GetMaxNumberOfEntries(holder, arguments);
3969     DCHECK_LE(max_entries, std::numeric_limits<uint32_t>::max());
3970     return elements.parameter_map_length() + static_cast<uint32_t>(max_entries);
3971   }
3972 
NumberOfElementsImpl(JSObject receiver,FixedArrayBase backing_store)3973   static uint32_t NumberOfElementsImpl(JSObject receiver,
3974                                        FixedArrayBase backing_store) {
3975     Isolate* isolate = receiver.GetIsolate();
3976     SloppyArgumentsElements elements =
3977         SloppyArgumentsElements::cast(backing_store);
3978     FixedArrayBase arguments = elements.arguments();
3979     uint32_t nof_elements = 0;
3980     uint32_t length = elements.parameter_map_length();
3981     for (uint32_t index = 0; index < length; index++) {
3982       if (HasParameterMapArg(isolate, elements, index)) nof_elements++;
3983     }
3984     return nof_elements +
3985            ArgumentsAccessor::NumberOfElementsImpl(receiver, arguments);
3986   }
3987 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)3988   V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
3989       Handle<JSObject> receiver, KeyAccumulator* accumulator,
3990       AddKeyConversion convert) {
3991     Isolate* isolate = accumulator->isolate();
3992     Handle<FixedArrayBase> elements(receiver->elements(), isolate);
3993     uint32_t length = GetCapacityImpl(*receiver, *elements);
3994     for (uint32_t index = 0; index < length; index++) {
3995       InternalIndex entry(index);
3996       if (!HasEntryImpl(isolate, *elements, entry)) continue;
3997       Handle<Object> value = GetImpl(isolate, *elements, entry);
3998       RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(value, convert));
3999     }
4000     return ExceptionStatus::kSuccess;
4001   }
4002 
HasEntryImpl(Isolate * isolate,FixedArrayBase parameters,InternalIndex entry)4003   static bool HasEntryImpl(Isolate* isolate, FixedArrayBase parameters,
4004                            InternalIndex entry) {
4005     SloppyArgumentsElements elements =
4006         SloppyArgumentsElements::cast(parameters);
4007     uint32_t length = elements.parameter_map_length();
4008     if (entry.raw_value() < length) {
4009       return HasParameterMapArg(isolate, elements, entry.raw_value());
4010     }
4011     FixedArrayBase arguments = elements.arguments();
4012     return ArgumentsAccessor::HasEntryImpl(isolate, arguments,
4013                                            entry.adjust_down(length));
4014   }
4015 
HasAccessorsImpl(JSObject holder,FixedArrayBase backing_store)4016   static bool HasAccessorsImpl(JSObject holder, FixedArrayBase backing_store) {
4017     SloppyArgumentsElements elements =
4018         SloppyArgumentsElements::cast(backing_store);
4019     FixedArray arguments = elements.arguments();
4020     return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
4021   }
4022 
GetEntryForIndexImpl(Isolate * isolate,JSObject holder,FixedArrayBase parameters,size_t index,PropertyFilter filter)4023   static InternalIndex GetEntryForIndexImpl(Isolate* isolate, JSObject holder,
4024                                             FixedArrayBase parameters,
4025                                             size_t index,
4026                                             PropertyFilter filter) {
4027     SloppyArgumentsElements elements =
4028         SloppyArgumentsElements::cast(parameters);
4029     if (HasParameterMapArg(isolate, elements, index)) {
4030       return InternalIndex(index);
4031     }
4032     FixedArray arguments = elements.arguments();
4033     InternalIndex entry = ArgumentsAccessor::GetEntryForIndexImpl(
4034         isolate, holder, arguments, index, filter);
4035     if (entry.is_not_found()) return entry;
4036     // Arguments entries could overlap with the dictionary entries, hence offset
4037     // them by the number of context mapped entries.
4038     return entry.adjust_up(elements.parameter_map_length());
4039   }
4040 
GetDetailsImpl(JSObject holder,InternalIndex entry)4041   static PropertyDetails GetDetailsImpl(JSObject holder, InternalIndex entry) {
4042     SloppyArgumentsElements elements =
4043         SloppyArgumentsElements::cast(holder.elements());
4044     uint32_t length = elements.parameter_map_length();
4045     if (entry.as_uint32() < length) {
4046       return PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
4047     }
4048     FixedArray arguments = elements.arguments();
4049     return ArgumentsAccessor::GetDetailsImpl(arguments,
4050                                              entry.adjust_down(length));
4051   }
4052 
HasParameterMapArg(Isolate * isolate,SloppyArgumentsElements elements,size_t index)4053   static bool HasParameterMapArg(Isolate* isolate,
4054                                  SloppyArgumentsElements elements,
4055                                  size_t index) {
4056     uint32_t length = elements.parameter_map_length();
4057     if (index >= length) return false;
4058     return !elements.get_mapped_entry(static_cast<uint32_t>(index))
4059                 .IsTheHole(isolate);
4060   }
4061 
DeleteImpl(Handle<JSObject> obj,InternalIndex entry)4062   static void DeleteImpl(Handle<JSObject> obj, InternalIndex entry) {
4063     Handle<SloppyArgumentsElements> elements(
4064         SloppyArgumentsElements::cast(obj->elements()), obj->GetIsolate());
4065     uint32_t length = elements->parameter_map_length();
4066     InternalIndex delete_or_entry = entry;
4067     if (entry.as_uint32() < length) {
4068       delete_or_entry = InternalIndex::NotFound();
4069     }
4070     Subclass::SloppyDeleteImpl(obj, elements, delete_or_entry);
4071     // SloppyDeleteImpl allocates a new dictionary elements store. For making
4072     // heap verification happy we postpone clearing out the mapped entry.
4073     if (entry.as_uint32() < length) {
4074       elements->set_mapped_entry(entry.as_uint32(),
4075                                  obj->GetReadOnlyRoots().the_hole_value());
4076     }
4077   }
4078 
SloppyDeleteImpl(Handle<JSObject> obj,Handle<SloppyArgumentsElements> elements,InternalIndex entry)4079   static void SloppyDeleteImpl(Handle<JSObject> obj,
4080                                Handle<SloppyArgumentsElements> elements,
4081                                InternalIndex entry) {
4082     // Implemented in subclasses.
4083     UNREACHABLE();
4084   }
4085 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)4086   V8_WARN_UNUSED_RESULT static ExceptionStatus CollectElementIndicesImpl(
4087       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
4088       KeyAccumulator* keys) {
4089     Isolate* isolate = keys->isolate();
4090     uint32_t nof_indices = 0;
4091     Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
4092         GetCapacityImpl(*object, *backing_store));
4093     DirectCollectElementIndicesImpl(isolate, object, backing_store,
4094                                     GetKeysConversion::kKeepNumbers,
4095                                     ENUMERABLE_STRINGS, indices, &nof_indices);
4096     SortIndices(isolate, indices, nof_indices);
4097     for (uint32_t i = 0; i < nof_indices; i++) {
4098       RETURN_FAILURE_IF_NOT_SUCCESSFUL(keys->AddKey(indices->get(i)));
4099     }
4100     return ExceptionStatus::kSuccess;
4101   }
4102 
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)4103   static Handle<FixedArray> DirectCollectElementIndicesImpl(
4104       Isolate* isolate, Handle<JSObject> object,
4105       Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
4106       PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
4107       uint32_t insertion_index = 0) {
4108     Handle<SloppyArgumentsElements> elements =
4109         Handle<SloppyArgumentsElements>::cast(backing_store);
4110     uint32_t length = elements->parameter_map_length();
4111 
4112     for (uint32_t i = 0; i < length; ++i) {
4113       if (elements->get_mapped_entry(i).IsTheHole(isolate)) continue;
4114       if (convert == GetKeysConversion::kConvertToString) {
4115         Handle<String> index_string = isolate->factory()->Uint32ToString(i);
4116         list->set(insertion_index, *index_string);
4117       } else {
4118         list->set(insertion_index, Smi::FromInt(i));
4119       }
4120       insertion_index++;
4121     }
4122 
4123     Handle<FixedArray> store(elements->arguments(), isolate);
4124     return ArgumentsAccessor::DirectCollectElementIndicesImpl(
4125         isolate, object, store, convert, filter, list, nof_indices,
4126         insertion_index);
4127   }
4128 
IncludesValueImpl(Isolate * isolate,Handle<JSObject> object,Handle<Object> value,size_t start_from,size_t length)4129   static Maybe<bool> IncludesValueImpl(Isolate* isolate,
4130                                        Handle<JSObject> object,
4131                                        Handle<Object> value, size_t start_from,
4132                                        size_t length) {
4133     DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
4134     Handle<Map> original_map(object->map(), isolate);
4135     Handle<SloppyArgumentsElements> elements(
4136         SloppyArgumentsElements::cast(object->elements()), isolate);
4137     bool search_for_hole = value->IsUndefined(isolate);
4138 
4139     for (size_t k = start_from; k < length; ++k) {
4140       DCHECK_EQ(object->map(), *original_map);
4141       InternalIndex entry =
4142           GetEntryForIndexImpl(isolate, *object, *elements, k, ALL_PROPERTIES);
4143       if (entry.is_not_found()) {
4144         if (search_for_hole) return Just(true);
4145         continue;
4146       }
4147 
4148       Handle<Object> element_k = Subclass::GetImpl(isolate, *elements, entry);
4149 
4150       if (element_k->IsAccessorPair()) {
4151         LookupIterator it(isolate, object, k, LookupIterator::OWN);
4152         DCHECK(it.IsFound());
4153         DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
4154         ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
4155                                          Object::GetPropertyWithAccessor(&it),
4156                                          Nothing<bool>());
4157 
4158         if (value->SameValueZero(*element_k)) return Just(true);
4159 
4160         if (object->map() != *original_map) {
4161           // Some mutation occurred in accessor. Abort "fast" path
4162           return IncludesValueSlowPath(isolate, object, value, k + 1, length);
4163         }
4164       } else if (value->SameValueZero(*element_k)) {
4165         return Just(true);
4166       }
4167     }
4168     return Just(false);
4169   }
4170 
IndexOfValueImpl(Isolate * isolate,Handle<JSObject> object,Handle<Object> value,size_t start_from,size_t length)4171   static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
4172                                          Handle<JSObject> object,
4173                                          Handle<Object> value,
4174                                          size_t start_from, size_t length) {
4175     DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
4176     Handle<Map> original_map(object->map(), isolate);
4177     Handle<SloppyArgumentsElements> elements(
4178         SloppyArgumentsElements::cast(object->elements()), isolate);
4179 
4180     for (size_t k = start_from; k < length; ++k) {
4181       DCHECK_EQ(object->map(), *original_map);
4182       InternalIndex entry =
4183           GetEntryForIndexImpl(isolate, *object, *elements, k, ALL_PROPERTIES);
4184       if (entry.is_not_found()) {
4185         continue;
4186       }
4187 
4188       Handle<Object> element_k = Subclass::GetImpl(isolate, *elements, entry);
4189 
4190       if (element_k->IsAccessorPair()) {
4191         LookupIterator it(isolate, object, k, LookupIterator::OWN);
4192         DCHECK(it.IsFound());
4193         DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
4194         ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
4195                                          Object::GetPropertyWithAccessor(&it),
4196                                          Nothing<int64_t>());
4197 
4198         if (value->StrictEquals(*element_k)) {
4199           return Just<int64_t>(k);
4200         }
4201 
4202         if (object->map() != *original_map) {
4203           // Some mutation occurred in accessor. Abort "fast" path.
4204           return IndexOfValueSlowPath(isolate, object, value, k + 1, length);
4205         }
4206       } else if (value->StrictEquals(*element_k)) {
4207         return Just<int64_t>(k);
4208       }
4209     }
4210     return Just<int64_t>(-1);
4211   }
4212 };
4213 
4214 class SlowSloppyArgumentsElementsAccessor
4215     : public SloppyArgumentsElementsAccessor<
4216           SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
4217           ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS>> {
4218  public:
ConvertArgumentsStoreResult(Isolate * isolate,Handle<SloppyArgumentsElements> elements,Handle<Object> result)4219   static Handle<Object> ConvertArgumentsStoreResult(
4220       Isolate* isolate, Handle<SloppyArgumentsElements> elements,
4221       Handle<Object> result) {
4222     // Elements of the arguments object in slow mode might be slow aliases.
4223     if (result->IsAliasedArgumentsEntry()) {
4224       DisallowHeapAllocation no_gc;
4225       AliasedArgumentsEntry alias = AliasedArgumentsEntry::cast(*result);
4226       Context context = elements->context();
4227       int context_entry = alias.aliased_context_slot();
4228       DCHECK(!context.get(context_entry).IsTheHole(isolate));
4229       return handle(context.get(context_entry), isolate);
4230     }
4231     return result;
4232   }
SloppyDeleteImpl(Handle<JSObject> obj,Handle<SloppyArgumentsElements> elements,InternalIndex entry)4233   static void SloppyDeleteImpl(Handle<JSObject> obj,
4234                                Handle<SloppyArgumentsElements> elements,
4235                                InternalIndex entry) {
4236     // No need to delete a context mapped entry from the arguments elements.
4237     if (entry.is_not_found()) return;
4238     Isolate* isolate = obj->GetIsolate();
4239     Handle<NumberDictionary> dict(NumberDictionary::cast(elements->arguments()),
4240                                   isolate);
4241     uint32_t length = elements->parameter_map_length();
4242     dict =
4243         NumberDictionary::DeleteEntry(isolate, dict, entry.adjust_down(length));
4244     elements->set_arguments(*dict);
4245   }
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)4246   static void AddImpl(Handle<JSObject> object, uint32_t index,
4247                       Handle<Object> value, PropertyAttributes attributes,
4248                       uint32_t new_capacity) {
4249     Isolate* isolate = object->GetIsolate();
4250     Handle<SloppyArgumentsElements> elements(
4251         SloppyArgumentsElements::cast(object->elements()), isolate);
4252     Handle<FixedArrayBase> old_arguments(
4253         FixedArrayBase::cast(elements->arguments()), isolate);
4254     Handle<NumberDictionary> dictionary =
4255         old_arguments->IsNumberDictionary()
4256             ? Handle<NumberDictionary>::cast(old_arguments)
4257             : JSObject::NormalizeElements(object);
4258     PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
4259     Handle<NumberDictionary> new_dictionary =
4260         NumberDictionary::Add(isolate, dictionary, index, value, details);
4261     if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
4262     if (*dictionary != *new_dictionary) {
4263       elements->set_arguments(*new_dictionary);
4264     }
4265   }
4266 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,InternalIndex entry,Handle<Object> value,PropertyAttributes attributes)4267   static void ReconfigureImpl(Handle<JSObject> object,
4268                               Handle<FixedArrayBase> store, InternalIndex entry,
4269                               Handle<Object> value,
4270                               PropertyAttributes attributes) {
4271     Isolate* isolate = object->GetIsolate();
4272     Handle<SloppyArgumentsElements> elements =
4273         Handle<SloppyArgumentsElements>::cast(store);
4274     uint32_t length = elements->parameter_map_length();
4275     if (entry.as_uint32() < length) {
4276       Object probe = elements->get_mapped_entry(entry.as_uint32());
4277       DCHECK(!probe.IsTheHole(isolate));
4278       Context context = elements->context();
4279       int context_entry = Smi::ToInt(probe);
4280       DCHECK(!context.get(context_entry).IsTheHole(isolate));
4281       context.set(context_entry, *value);
4282 
4283       // Redefining attributes of an aliased element destroys fast aliasing.
4284       elements->set_mapped_entry(entry.as_uint32(),
4285                                  ReadOnlyRoots(isolate).the_hole_value());
4286       // For elements that are still writable we re-establish slow aliasing.
4287       if ((attributes & READ_ONLY) == 0) {
4288         value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
4289       }
4290 
4291       PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
4292       Handle<NumberDictionary> arguments(
4293           NumberDictionary::cast(elements->arguments()), isolate);
4294       arguments = NumberDictionary::Add(isolate, arguments, entry.as_uint32(),
4295                                         value, details);
4296       // If the attributes were NONE, we would have called set rather than
4297       // reconfigure.
4298       DCHECK_NE(NONE, attributes);
4299       object->RequireSlowElements(*arguments);
4300       elements->set_arguments(*arguments);
4301     } else {
4302       Handle<FixedArrayBase> arguments(elements->arguments(), isolate);
4303       DictionaryElementsAccessor::ReconfigureImpl(
4304           object, arguments, entry.adjust_down(length), value, attributes);
4305     }
4306   }
4307 };
4308 
4309 class FastSloppyArgumentsElementsAccessor
4310     : public SloppyArgumentsElementsAccessor<
4311           FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
4312           ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS>> {
4313  public:
ConvertArgumentsStoreResult(Isolate * isolate,Handle<SloppyArgumentsElements> paramtere_map,Handle<Object> result)4314   static Handle<Object> ConvertArgumentsStoreResult(
4315       Isolate* isolate, Handle<SloppyArgumentsElements> paramtere_map,
4316       Handle<Object> result) {
4317     DCHECK(!result->IsAliasedArgumentsEntry());
4318     return result;
4319   }
4320 
GetArguments(Isolate * isolate,FixedArrayBase store)4321   static Handle<FixedArray> GetArguments(Isolate* isolate,
4322                                          FixedArrayBase store) {
4323     SloppyArgumentsElements elements = SloppyArgumentsElements::cast(store);
4324     return Handle<FixedArray>(elements.arguments(), isolate);
4325   }
4326 
NormalizeImpl(Handle<JSObject> object,Handle<FixedArrayBase> elements)4327   static Handle<NumberDictionary> NormalizeImpl(
4328       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
4329     Handle<FixedArray> arguments =
4330         GetArguments(object->GetIsolate(), *elements);
4331     return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments);
4332   }
4333 
NormalizeArgumentsElements(Handle<JSObject> object,Handle<SloppyArgumentsElements> elements,InternalIndex * entry)4334   static Handle<NumberDictionary> NormalizeArgumentsElements(
4335       Handle<JSObject> object, Handle<SloppyArgumentsElements> elements,
4336       InternalIndex* entry) {
4337     Handle<NumberDictionary> dictionary = JSObject::NormalizeElements(object);
4338     elements->set_arguments(*dictionary);
4339     // kMaxUInt32 indicates that a context mapped element got deleted. In this
4340     // case we only normalize the elements (aka. migrate to SLOW_SLOPPY).
4341     if (entry->is_not_found()) return dictionary;
4342     uint32_t length = elements->parameter_map_length();
4343     if (entry->as_uint32() >= length) {
4344       *entry =
4345           dictionary
4346               ->FindEntry(object->GetIsolate(), entry->as_uint32() - length)
4347               .adjust_up(length);
4348     }
4349     return dictionary;
4350   }
4351 
SloppyDeleteImpl(Handle<JSObject> obj,Handle<SloppyArgumentsElements> elements,InternalIndex entry)4352   static void SloppyDeleteImpl(Handle<JSObject> obj,
4353                                Handle<SloppyArgumentsElements> elements,
4354                                InternalIndex entry) {
4355     // Always normalize element on deleting an entry.
4356     NormalizeArgumentsElements(obj, elements, &entry);
4357     SlowSloppyArgumentsElementsAccessor::SloppyDeleteImpl(obj, elements, entry);
4358   }
4359 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)4360   static void AddImpl(Handle<JSObject> object, uint32_t index,
4361                       Handle<Object> value, PropertyAttributes attributes,
4362                       uint32_t new_capacity) {
4363     DCHECK_EQ(NONE, attributes);
4364     Isolate* isolate = object->GetIsolate();
4365     Handle<SloppyArgumentsElements> elements(
4366         SloppyArgumentsElements::cast(object->elements()), isolate);
4367     Handle<FixedArray> old_arguments(elements->arguments(), isolate);
4368     if (old_arguments->IsNumberDictionary() ||
4369         static_cast<uint32_t>(old_arguments->length()) < new_capacity) {
4370       GrowCapacityAndConvertImpl(object, new_capacity);
4371     }
4372     FixedArray arguments = elements->arguments();
4373     // For fast holey objects, the entry equals the index. The code above made
4374     // sure that there's enough space to store the value. We cannot convert
4375     // index to entry explicitly since the slot still contains the hole, so the
4376     // current EntryForIndex would indicate that it is "absent" by returning
4377     // kMaxUInt32.
4378     FastHoleyObjectElementsAccessor::SetImpl(arguments, InternalIndex(index),
4379                                              *value);
4380   }
4381 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,InternalIndex entry,Handle<Object> value,PropertyAttributes attributes)4382   static void ReconfigureImpl(Handle<JSObject> object,
4383                               Handle<FixedArrayBase> store, InternalIndex entry,
4384                               Handle<Object> value,
4385                               PropertyAttributes attributes) {
4386     DCHECK_EQ(object->elements(), *store);
4387     Handle<SloppyArgumentsElements> elements(
4388         SloppyArgumentsElements::cast(*store), object->GetIsolate());
4389     NormalizeArgumentsElements(object, elements, &entry);
4390     SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
4391                                                          value, attributes);
4392   }
4393 
CopyElementsImpl(Isolate * isolate,FixedArrayBase from,uint32_t from_start,FixedArrayBase to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)4394   static void CopyElementsImpl(Isolate* isolate, FixedArrayBase from,
4395                                uint32_t from_start, FixedArrayBase to,
4396                                ElementsKind from_kind, uint32_t to_start,
4397                                int packed_size, int copy_size) {
4398     DCHECK(!to.IsNumberDictionary());
4399     if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
4400       CopyDictionaryToObjectElements(isolate, from, from_start, to,
4401                                      HOLEY_ELEMENTS, to_start, copy_size);
4402     } else {
4403       DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
4404       CopyObjectToObjectElements(isolate, from, HOLEY_ELEMENTS, from_start, to,
4405                                  HOLEY_ELEMENTS, to_start, copy_size);
4406     }
4407   }
4408 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)4409   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
4410                                          uint32_t capacity) {
4411     Isolate* isolate = object->GetIsolate();
4412     Handle<SloppyArgumentsElements> elements(
4413         SloppyArgumentsElements::cast(object->elements()), isolate);
4414     Handle<FixedArray> old_arguments(FixedArray::cast(elements->arguments()),
4415                                      isolate);
4416     ElementsKind from_kind = object->GetElementsKind();
4417     // This method should only be called if there's a reason to update the
4418     // elements.
4419     DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
4420            static_cast<uint32_t>(old_arguments->length()) < capacity);
4421     Handle<FixedArrayBase> arguments =
4422         ConvertElementsWithCapacity(object, old_arguments, from_kind, capacity);
4423     Handle<Map> new_map = JSObject::GetElementsTransitionMap(
4424         object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
4425     JSObject::MigrateToMap(isolate, object, new_map);
4426     elements->set_arguments(FixedArray::cast(*arguments));
4427     JSObject::ValidateElements(*object);
4428   }
4429 };
4430 
4431 template <typename Subclass, typename BackingStoreAccessor, typename KindTraits>
4432 class StringWrapperElementsAccessor
4433     : public ElementsAccessorBase<Subclass, KindTraits> {
4434  public:
GetInternalImpl(Handle<JSObject> holder,InternalIndex entry)4435   static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
4436                                         InternalIndex entry) {
4437     return GetImpl(holder, entry);
4438   }
4439 
GetImpl(Handle<JSObject> holder,InternalIndex entry)4440   static Handle<Object> GetImpl(Handle<JSObject> holder, InternalIndex entry) {
4441     Isolate* isolate = holder->GetIsolate();
4442     Handle<String> string(GetString(*holder), isolate);
4443     uint32_t length = static_cast<uint32_t>(string->length());
4444     if (entry.as_uint32() < length) {
4445       return isolate->factory()->LookupSingleCharacterStringFromCode(
4446           String::Flatten(isolate, string)->Get(entry.as_int()));
4447     }
4448     return BackingStoreAccessor::GetImpl(isolate, holder->elements(),
4449                                          entry.adjust_down(length));
4450   }
4451 
GetImpl(Isolate * isolate,FixedArrayBase elements,InternalIndex entry)4452   static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase elements,
4453                                 InternalIndex entry) {
4454     UNREACHABLE();
4455   }
4456 
GetDetailsImpl(JSObject holder,InternalIndex entry)4457   static PropertyDetails GetDetailsImpl(JSObject holder, InternalIndex entry) {
4458     uint32_t length = static_cast<uint32_t>(GetString(holder).length());
4459     if (entry.as_uint32() < length) {
4460       PropertyAttributes attributes =
4461           static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
4462       return PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
4463     }
4464     return BackingStoreAccessor::GetDetailsImpl(holder,
4465                                                 entry.adjust_down(length));
4466   }
4467 
GetEntryForIndexImpl(Isolate * isolate,JSObject holder,FixedArrayBase backing_store,size_t index,PropertyFilter filter)4468   static InternalIndex GetEntryForIndexImpl(Isolate* isolate, JSObject holder,
4469                                             FixedArrayBase backing_store,
4470                                             size_t index,
4471                                             PropertyFilter filter) {
4472     uint32_t length = static_cast<uint32_t>(GetString(holder).length());
4473     if (index < length) return InternalIndex(index);
4474     InternalIndex backing_store_entry =
4475         BackingStoreAccessor::GetEntryForIndexImpl(
4476             isolate, holder, backing_store, index, filter);
4477     if (backing_store_entry.is_not_found()) return backing_store_entry;
4478     return backing_store_entry.adjust_up(length);
4479   }
4480 
DeleteImpl(Handle<JSObject> holder,InternalIndex entry)4481   static void DeleteImpl(Handle<JSObject> holder, InternalIndex entry) {
4482     uint32_t length = static_cast<uint32_t>(GetString(*holder).length());
4483     if (entry.as_uint32() < length) {
4484       return;  // String contents can't be deleted.
4485     }
4486     BackingStoreAccessor::DeleteImpl(holder, entry.adjust_down(length));
4487   }
4488 
SetImpl(Handle<JSObject> holder,InternalIndex entry,Object value)4489   static void SetImpl(Handle<JSObject> holder, InternalIndex entry,
4490                       Object value) {
4491     uint32_t length = static_cast<uint32_t>(GetString(*holder).length());
4492     if (entry.as_uint32() < length) {
4493       return;  // String contents are read-only.
4494     }
4495     BackingStoreAccessor::SetImpl(holder->elements(), entry.adjust_down(length),
4496                                   value);
4497   }
4498 
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)4499   static void AddImpl(Handle<JSObject> object, uint32_t index,
4500                       Handle<Object> value, PropertyAttributes attributes,
4501                       uint32_t new_capacity) {
4502     DCHECK(index >= static_cast<uint32_t>(GetString(*object).length()));
4503     // Explicitly grow fast backing stores if needed. Dictionaries know how to
4504     // extend their capacity themselves.
4505     if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
4506         (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
4507          BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
4508              new_capacity)) {
4509       GrowCapacityAndConvertImpl(object, new_capacity);
4510     }
4511     BackingStoreAccessor::AddImpl(object, index, value, attributes,
4512                                   new_capacity);
4513   }
4514 
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,InternalIndex entry,Handle<Object> value,PropertyAttributes attributes)4515   static void ReconfigureImpl(Handle<JSObject> object,
4516                               Handle<FixedArrayBase> store, InternalIndex entry,
4517                               Handle<Object> value,
4518                               PropertyAttributes attributes) {
4519     uint32_t length = static_cast<uint32_t>(GetString(*object).length());
4520     if (entry.as_uint32() < length) {
4521       return;  // String contents can't be reconfigured.
4522     }
4523     BackingStoreAccessor::ReconfigureImpl(
4524         object, store, entry.adjust_down(length), value, attributes);
4525   }
4526 
AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)4527   V8_WARN_UNUSED_RESULT static ExceptionStatus AddElementsToKeyAccumulatorImpl(
4528       Handle<JSObject> receiver, KeyAccumulator* accumulator,
4529       AddKeyConversion convert) {
4530     Isolate* isolate = receiver->GetIsolate();
4531     Handle<String> string(GetString(*receiver), isolate);
4532     string = String::Flatten(isolate, string);
4533     uint32_t length = static_cast<uint32_t>(string->length());
4534     for (uint32_t i = 0; i < length; i++) {
4535       Handle<String> key =
4536           isolate->factory()->LookupSingleCharacterStringFromCode(
4537               string->Get(i));
4538       RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(key, convert));
4539     }
4540     return BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(
4541         receiver, accumulator, convert);
4542   }
4543 
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys)4544   V8_WARN_UNUSED_RESULT static ExceptionStatus CollectElementIndicesImpl(
4545       Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
4546       KeyAccumulator* keys) {
4547     uint32_t length = GetString(*object).length();
4548     Factory* factory = keys->isolate()->factory();
4549     for (uint32_t i = 0; i < length; i++) {
4550       RETURN_FAILURE_IF_NOT_SUCCESSFUL(
4551           keys->AddKey(factory->NewNumberFromUint(i)));
4552     }
4553     return BackingStoreAccessor::CollectElementIndicesImpl(object,
4554                                                            backing_store, keys);
4555   }
4556 
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)4557   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
4558                                          uint32_t capacity) {
4559     Handle<FixedArrayBase> old_elements(object->elements(),
4560                                         object->GetIsolate());
4561     ElementsKind from_kind = object->GetElementsKind();
4562     if (from_kind == FAST_STRING_WRAPPER_ELEMENTS) {
4563       // The optimizing compiler relies on the prototype lookups of String
4564       // objects always returning undefined. If there's a store to the
4565       // initial String.prototype object, make sure all the optimizations
4566       // are invalidated.
4567       object->GetIsolate()->UpdateNoElementsProtectorOnSetLength(object);
4568     }
4569     // This method should only be called if there's a reason to update the
4570     // elements.
4571     DCHECK(from_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
4572            static_cast<uint32_t>(old_elements->length()) < capacity);
4573     Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
4574                                               FAST_STRING_WRAPPER_ELEMENTS,
4575                                               capacity);
4576   }
4577 
CopyElementsImpl(Isolate * isolate,FixedArrayBase from,uint32_t from_start,FixedArrayBase to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)4578   static void CopyElementsImpl(Isolate* isolate, FixedArrayBase from,
4579                                uint32_t from_start, FixedArrayBase to,
4580                                ElementsKind from_kind, uint32_t to_start,
4581                                int packed_size, int copy_size) {
4582     DCHECK(!to.IsNumberDictionary());
4583     if (from_kind == SLOW_STRING_WRAPPER_ELEMENTS) {
4584       CopyDictionaryToObjectElements(isolate, from, from_start, to,
4585                                      HOLEY_ELEMENTS, to_start, copy_size);
4586     } else {
4587       DCHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, from_kind);
4588       CopyObjectToObjectElements(isolate, from, HOLEY_ELEMENTS, from_start, to,
4589                                  HOLEY_ELEMENTS, to_start, copy_size);
4590     }
4591   }
4592 
NumberOfElementsImpl(JSObject object,FixedArrayBase backing_store)4593   static uint32_t NumberOfElementsImpl(JSObject object,
4594                                        FixedArrayBase backing_store) {
4595     uint32_t length = GetString(object).length();
4596     return length +
4597            BackingStoreAccessor::NumberOfElementsImpl(object, backing_store);
4598   }
4599 
4600  private:
GetString(JSObject holder)4601   static String GetString(JSObject holder) {
4602     DCHECK(holder.IsJSPrimitiveWrapper());
4603     JSPrimitiveWrapper js_value = JSPrimitiveWrapper::cast(holder);
4604     DCHECK(js_value.value().IsString());
4605     return String::cast(js_value.value());
4606   }
4607 };
4608 
4609 class FastStringWrapperElementsAccessor
4610     : public StringWrapperElementsAccessor<
4611           FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
4612           ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
4613  public:
NormalizeImpl(Handle<JSObject> object,Handle<FixedArrayBase> elements)4614   static Handle<NumberDictionary> NormalizeImpl(
4615       Handle<JSObject> object, Handle<FixedArrayBase> elements) {
4616     return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
4617   }
4618 };
4619 
4620 class SlowStringWrapperElementsAccessor
4621     : public StringWrapperElementsAccessor<
4622           SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
4623           ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
4624  public:
HasAccessorsImpl(JSObject holder,FixedArrayBase backing_store)4625   static bool HasAccessorsImpl(JSObject holder, FixedArrayBase backing_store) {
4626     return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
4627   }
4628 };
4629 
4630 }  // namespace
4631 
ArrayConstructInitializeElements(Handle<JSArray> array,JavaScriptArguments * args)4632 MaybeHandle<Object> ArrayConstructInitializeElements(
4633     Handle<JSArray> array, JavaScriptArguments* args) {
4634   if (args->length() == 0) {
4635     // Optimize the case where there are no parameters passed.
4636     JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
4637     return array;
4638 
4639   } else if (args->length() == 1 && args->at(0)->IsNumber()) {
4640     uint32_t length;
4641     if (!args->at(0)->ToArrayLength(&length)) {
4642       return ThrowArrayLengthRangeError(array->GetIsolate());
4643     }
4644 
4645     // Optimize the case where there is one argument and the argument is a small
4646     // smi.
4647     if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
4648       ElementsKind elements_kind = array->GetElementsKind();
4649       JSArray::Initialize(array, length, length);
4650 
4651       if (!IsHoleyElementsKind(elements_kind)) {
4652         elements_kind = GetHoleyElementsKind(elements_kind);
4653         JSObject::TransitionElementsKind(array, elements_kind);
4654       }
4655     } else if (length == 0) {
4656       JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
4657     } else {
4658       // Take the argument as the length.
4659       JSArray::Initialize(array, 0);
4660       JSArray::SetLength(array, length);
4661     }
4662     return array;
4663   }
4664 
4665   Factory* factory = array->GetIsolate()->factory();
4666 
4667   // Set length and elements on the array.
4668   int number_of_elements = args->length();
4669   JSObject::EnsureCanContainElements(array, args, number_of_elements,
4670                                      ALLOW_CONVERTED_DOUBLE_ELEMENTS);
4671 
4672   // Allocate an appropriately typed elements array.
4673   ElementsKind elements_kind = array->GetElementsKind();
4674   Handle<FixedArrayBase> elms;
4675   if (IsDoubleElementsKind(elements_kind)) {
4676     elms = Handle<FixedArrayBase>::cast(
4677         factory->NewFixedDoubleArray(number_of_elements));
4678   } else {
4679     elms = Handle<FixedArrayBase>::cast(
4680         factory->NewFixedArrayWithHoles(number_of_elements));
4681   }
4682 
4683   // Fill in the content
4684   switch (elements_kind) {
4685     case HOLEY_SMI_ELEMENTS:
4686     case PACKED_SMI_ELEMENTS: {
4687       Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
4688       for (int entry = 0; entry < number_of_elements; entry++) {
4689         smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
4690       }
4691       break;
4692     }
4693     case HOLEY_ELEMENTS:
4694     case PACKED_ELEMENTS: {
4695       DisallowHeapAllocation no_gc;
4696       WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
4697       Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
4698       for (int entry = 0; entry < number_of_elements; entry++) {
4699         object_elms->set(entry, (*args)[entry], mode);
4700       }
4701       break;
4702     }
4703     case HOLEY_DOUBLE_ELEMENTS:
4704     case PACKED_DOUBLE_ELEMENTS: {
4705       Handle<FixedDoubleArray> double_elms =
4706           Handle<FixedDoubleArray>::cast(elms);
4707       for (int entry = 0; entry < number_of_elements; entry++) {
4708         double_elms->set(entry, (*args)[entry].Number());
4709       }
4710       break;
4711     }
4712     default:
4713       UNREACHABLE();
4714   }
4715 
4716   array->set_elements(*elms);
4717   array->set_length(Smi::FromInt(number_of_elements));
4718   return array;
4719 }
4720 
CopyFastNumberJSArrayElementsToTypedArray(Address raw_context,Address raw_source,Address raw_destination,uintptr_t length,uintptr_t offset)4721 void CopyFastNumberJSArrayElementsToTypedArray(Address raw_context,
4722                                                Address raw_source,
4723                                                Address raw_destination,
4724                                                uintptr_t length,
4725                                                uintptr_t offset) {
4726   Context context = Context::cast(Object(raw_context));
4727   JSArray source = JSArray::cast(Object(raw_source));
4728   JSTypedArray destination = JSTypedArray::cast(Object(raw_destination));
4729 
4730   switch (destination.GetElementsKind()) {
4731 #define TYPED_ARRAYS_CASE(Type, type, TYPE, ctype)           \
4732   case TYPE##_ELEMENTS:                                      \
4733     CHECK(Type##ElementsAccessor::TryCopyElementsFastNumber( \
4734         context, source, destination, length, offset));      \
4735     break;
4736     TYPED_ARRAYS(TYPED_ARRAYS_CASE)
4737 #undef TYPED_ARRAYS_CASE
4738     default:
4739       UNREACHABLE();
4740   }
4741 }
4742 
CopyTypedArrayElementsToTypedArray(Address raw_source,Address raw_destination,uintptr_t length,uintptr_t offset)4743 void CopyTypedArrayElementsToTypedArray(Address raw_source,
4744                                         Address raw_destination,
4745                                         uintptr_t length, uintptr_t offset) {
4746   JSTypedArray source = JSTypedArray::cast(Object(raw_source));
4747   JSTypedArray destination = JSTypedArray::cast(Object(raw_destination));
4748 
4749   switch (destination.GetElementsKind()) {
4750 #define TYPED_ARRAYS_CASE(Type, type, TYPE, ctype)                          \
4751   case TYPE##_ELEMENTS:                                                     \
4752     Type##ElementsAccessor::CopyElementsFromTypedArray(source, destination, \
4753                                                        length, offset);     \
4754     break;
4755     TYPED_ARRAYS(TYPED_ARRAYS_CASE)
4756 #undef TYPED_ARRAYS_CASE
4757     default:
4758       UNREACHABLE();
4759   }
4760 }
4761 
CopyTypedArrayElementsSlice(Address raw_source,Address raw_destination,uintptr_t start,uintptr_t end)4762 void CopyTypedArrayElementsSlice(Address raw_source, Address raw_destination,
4763                                  uintptr_t start, uintptr_t end) {
4764   JSTypedArray source = JSTypedArray::cast(Object(raw_source));
4765   JSTypedArray destination = JSTypedArray::cast(Object(raw_destination));
4766 
4767   destination.GetElementsAccessor()->CopyTypedArrayElementsSlice(
4768       source, destination, start, end);
4769 }
4770 
InitializeOncePerProcess()4771 void ElementsAccessor::InitializeOncePerProcess() {
4772   static ElementsAccessor* accessor_array[] = {
4773 #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(),
4774       ELEMENTS_LIST(ACCESSOR_ARRAY)
4775 #undef ACCESSOR_ARRAY
4776   };
4777 
4778   STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
4779                 kElementsKindCount);
4780 
4781   elements_accessors_ = accessor_array;
4782 }
4783 
TearDown()4784 void ElementsAccessor::TearDown() {
4785   if (elements_accessors_ == nullptr) return;
4786 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
4787   ELEMENTS_LIST(ACCESSOR_DELETE)
4788 #undef ACCESSOR_DELETE
4789   elements_accessors_ = nullptr;
4790 }
4791 
Concat(Isolate * isolate,BuiltinArguments * args,uint32_t concat_size,uint32_t result_len)4792 Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate,
4793                                          BuiltinArguments* args,
4794                                          uint32_t concat_size,
4795                                          uint32_t result_len) {
4796   ElementsKind result_elements_kind = GetInitialFastElementsKind();
4797   bool has_raw_doubles = false;
4798   {
4799     DisallowHeapAllocation no_gc;
4800     bool is_holey = false;
4801     for (uint32_t i = 0; i < concat_size; i++) {
4802       Object arg = (*args)[i];
4803       ElementsKind arg_kind = JSArray::cast(arg).GetElementsKind();
4804       has_raw_doubles = has_raw_doubles || IsDoubleElementsKind(arg_kind);
4805       is_holey = is_holey || IsHoleyElementsKind(arg_kind);
4806       result_elements_kind =
4807           GetMoreGeneralElementsKind(result_elements_kind, arg_kind);
4808     }
4809     if (is_holey) {
4810       result_elements_kind = GetHoleyElementsKind(result_elements_kind);
4811     }
4812   }
4813 
4814   // If a double array is concatted into a fast elements array, the fast
4815   // elements array needs to be initialized to contain proper holes, since
4816   // boxing doubles may cause incremental marking.
4817   bool requires_double_boxing =
4818       has_raw_doubles && !IsDoubleElementsKind(result_elements_kind);
4819   ArrayStorageAllocationMode mode = requires_double_boxing
4820                                         ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
4821                                         : DONT_INITIALIZE_ARRAY_ELEMENTS;
4822   Handle<JSArray> result_array = isolate->factory()->NewJSArray(
4823       result_elements_kind, result_len, result_len, mode);
4824   if (result_len == 0) return result_array;
4825 
4826   uint32_t insertion_index = 0;
4827   Handle<FixedArrayBase> storage(result_array->elements(), isolate);
4828   ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind);
4829   for (uint32_t i = 0; i < concat_size; i++) {
4830     // It is crucial to keep |array| in a raw pointer form to avoid
4831     // performance degradation.
4832     JSArray array = JSArray::cast((*args)[i]);
4833     uint32_t len = 0;
4834     array.length().ToArrayLength(&len);
4835     if (len == 0) continue;
4836     ElementsKind from_kind = array.GetElementsKind();
4837     accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len);
4838     insertion_index += len;
4839   }
4840 
4841   DCHECK_EQ(insertion_index, result_len);
4842   return result_array;
4843 }
4844 
4845 ElementsAccessor** ElementsAccessor::elements_accessors_ = nullptr;
4846 
4847 #undef ELEMENTS_LIST
4848 #undef RETURN_NOTHING_IF_NOT_SUCCESSFUL
4849 #undef RETURN_FAILURE_IF_NOT_SUCCESSFUL
4850 }  // namespace internal
4851 }  // namespace v8
4852