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