Bug Summary

File:out/../deps/v8/src/objects/elements.cc
Warning:line 3483, column 11
Branch condition evaluates to a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name elements.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D V8_GYP_BUILD -D V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64 -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D V8_TARGET_ARCH_X64 -D V8_HAVE_TARGET_OS -D V8_TARGET_OS_LINUX -D V8_EMBEDDER_STRING="-node.8" -D ENABLE_DISASSEMBLER -D V8_PROMISE_INTERNAL_FIELD_COUNT=1 -D V8_SHORT_BUILTIN_CALLS -D OBJECT_PRINT -D V8_INTL_SUPPORT -D V8_ATOMIC_OBJECT_FIELD_WRITES -D V8_ENABLE_LAZY_SOURCE_POSITIONS -D V8_USE_SIPHASH -D V8_SHARED_RO_HEAP -D V8_WIN64_UNWINDING_INFO -D V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -D V8_SNAPSHOT_COMPRESSION -D V8_ENABLE_WEBASSEMBLY -D V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS -D V8_ALLOCATION_FOLDING -D V8_ALLOCATION_SITE_TRACKING -D V8_SCRIPTORMODULE_LEGACY_LIFETIME -D V8_ADVANCED_BIGINT_ALGORITHMS -D ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/v8 -I ../deps/v8/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/inspector-generated-output-root -I ../deps/v8/third_party/inspector_protocol -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/generate-bytecode-output-root -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/v8/third_party/zlib -I ../deps/v8/third_party/zlib/google -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-return-type -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/v8/src/objects/elements.cc
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
83namespace v8 {
84namespace internal {
85
86namespace {
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
99static const int kPackedSizeNotKnown = -1;
100
101enum 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
159template <ElementsKind Kind>
160class 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;
173ELEMENTS_LIST(ELEMENTS_TRAITS)
174#undef ELEMENTS_TRAITS
175
176V8_WARN_UNUSED_RESULT__attribute__((warn_unused_result))
177MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
178 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),do { auto* __isolate__ = (isolate); return __isolate__->template
Throw<Object>(__isolate__->factory()->NewRangeError
(MessageTemplate::kInvalidArrayLength)); } while (false)
179 Object)do { auto* __isolate__ = (isolate); return __isolate__->template
Throw<Object>(__isolate__->factory()->NewRangeError
(MessageTemplate::kInvalidArrayLength)); } while (false)
;
180}
181
182WriteBarrierMode 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.
193constexpr int kCopyToEndAndInitializeToHole = -1;
194
195void 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())((void) 0);
201 DisallowGarbageCollection no_gc;
202 int copy_size = raw_copy_size;
203 if (raw_copy_size < 0) {
204 DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size)((void) 0);
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() &&((void) 0)
215 (copy_size + static_cast<int>(from_start)) <= from_base.length())((void) 0);
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))((void) 0);
220 DCHECK(IsSmiOrObjectElementsKind(to_kind))((void) 0);
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
230void 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)((void) 0);
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)((void) 0);
248 DCHECK(IsSmiOrObjectElementsKind(to_kind))((void) 0);
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))((void) 0);
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.
271void 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)((void) 0);
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() &&((void) 0)
292 (copy_size + static_cast<int>(from_start)) <= from_base.length())((void) 0);
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
315void 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)((void) 0);
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() &&((void) 0)
329 (copy_size + static_cast<int>(from_start)) <= from_base.length())((void) 0);
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
351void 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)((void) 0);
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() &&((void) 0)
364 (copy_size + static_cast<int>(from_start)) <= from_base.length())((void) 0);
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
380void 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)((void) 0);
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())((void) 0);
398 DCHECK(packed_size >= 0 && packed_size <= copy_size)((void) 0);
399 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() &&((void) 0)
400 (copy_size + static_cast<int>(from_start)) <= from_base.length())((void) 0);
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())((void) 0);
408 to.set(to_start, Smi::ToInt(smi));
409 }
410}
411
412void 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)((void) 0);
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() &&((void) 0)
425 (copy_size + static_cast<int>(from_start)) <= from_base.length())((void) 0);
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
441void 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)((void) 0);
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
470void 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
498Maybe<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,do { if (!(Object::GetProperty(&it)).ToHandle(&element_k
)) { ((void) 0); return Nothing<bool>(); } } while (false
)
510 Object::GetProperty(&it), Nothing<bool>())do { if (!(Object::GetProperty(&it)).ToHandle(&element_k
)) { ((void) 0); return Nothing<bool>(); } } while (false
)
;
511
512 if (value->SameValueZero(*element_k)) return Just(true);
513 }
514
515 return Just(false);
516}
517
518Maybe<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(do { if (!(Object::GetProperty(&it)).ToHandle(&element_k
)) { ((void) 0); return Nothing<int64_t>(); } } while (
false)
528 isolate, element_k, Object::GetProperty(&it), Nothing<int64_t>())do { if (!(Object::GetProperty(&it)).ToHandle(&element_k
)) { ((void) 0); return Nothing<int64_t>(); } } while (
false)
;
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.
539class 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).
565template <typename Subclass, typename ElementsTraitsParam>
566class 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
575 static ElementsKind kind() { return ElementsTraits::Kind; }
576
577 static void ValidateContents(JSObject holder, size_t length) {}
578
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
598 void Validate(JSObject holder) final {
599 DisallowGarbageCollection no_gc;
600 Subclass::ValidateImpl(holder);
601 }
602
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
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
617 bool HasEntry(JSObject holder, InternalIndex entry) final {
618 return Subclass::HasEntryImpl(holder.GetIsolate(), holder.elements(),
619 entry);
620 }
621
622 static bool HasEntryImpl(Isolate* isolate, FixedArrayBase backing_store,
623 InternalIndex entry) {
624 UNIMPLEMENTED()V8_Fatal("unimplemented code");
625 }
626
627 bool HasAccessors(JSObject holder) final {
628 return Subclass::HasAccessorsImpl(holder, holder.elements());
629 }
630
631 static bool HasAccessorsImpl(JSObject holder, FixedArrayBase backing_store) {
632 return false;
633 }
634
635 Handle<Object> Get(Handle<JSObject> holder, InternalIndex entry) final {
636 return Subclass::GetInternalImpl(holder, entry);
637 }
638
639 static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
640 InternalIndex entry) {
641 return Subclass::GetImpl(holder->GetIsolate(), holder->elements(), entry);
642 }
643
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
650 void Set(Handle<JSObject> holder, InternalIndex entry, Object value) final {
651 Subclass::SetImpl(holder, entry, value);
652 }
653
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
660 static void ReconfigureImpl(Handle<JSObject> object,
661 Handle<FixedArrayBase> store, InternalIndex entry,
662 Handle<Object> value,
663 PropertyAttributes attributes) {
664 UNREACHABLE()V8_Fatal("unreachable code");
665 }
666
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
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()V8_Fatal("unreachable code");
677 }
678
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
684 static Maybe<uint32_t> PushImpl(Handle<JSArray> receiver,
685 BuiltinArguments* args, uint32_t push_sized) {
686 UNREACHABLE()V8_Fatal("unreachable code");
687 }
688
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
694 static Maybe<uint32_t> UnshiftImpl(Handle<JSArray> receiver,
695 BuiltinArguments* args,
696 uint32_t unshift_size) {
697 UNREACHABLE()V8_Fatal("unreachable code");
698 }
699
700 MaybeHandle<Object> Pop(Handle<JSArray> receiver) final {
701 return Subclass::PopImpl(receiver);
702 }
703
704 static MaybeHandle<Object> PopImpl(Handle<JSArray> receiver) {
705 UNREACHABLE()V8_Fatal("unreachable code");
706 }
707
708 MaybeHandle<Object> Shift(Handle<JSArray> receiver) final {
709 return Subclass::ShiftImpl(receiver);
710 }
711
712 static MaybeHandle<Object> ShiftImpl(Handle<JSArray> receiver) {
713 UNREACHABLE()V8_Fatal("unreachable code");
714 }
715
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
722 static Maybe<bool> SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
723 uint32_t length,
724 Handle<FixedArrayBase> backing_store) {
725 DCHECK(!array->SetLengthWouldNormalize(length))((void) 0);
726 DCHECK(IsFastElementsKind(array->GetElementsKind()))((void) 0);
727 uint32_t old_length = 0;
728 CHECK(array->length().ToArrayIndex(&old_length))do { if ((__builtin_expect(!!(!(array->length().ToArrayIndex
(&old_length))), 0))) { V8_Fatal("Check failed: %s.", "array->length().ToArrayIndex(&old_length)"
); } } while (false)
;
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),do { if ((Subclass::GrowCapacityAndConvertImpl(array, capacity
)).IsNothing()) return Nothing<bool>(); } while (false)
771 Nothing<bool>())do { if ((Subclass::GrowCapacityAndConvertImpl(array, capacity
)).IsNothing()) return Nothing<bool>(); } while (false)
;
772 }
773
774 array->set_length(Smi::FromInt(length));
775 JSObject::ValidateElements(*array);
776 return Just(true);
777 }
778
779 size_t NumberOfElements(JSObject receiver) final {
780 return Subclass::NumberOfElementsImpl(receiver, receiver.elements());
781 }
782
783 static uint32_t NumberOfElementsImpl(JSObject receiver,
784 FixedArrayBase backing_store) {
785 UNREACHABLE()V8_Fatal("unreachable code");
786 }
787
788 static size_t GetMaxIndex(JSObject receiver, FixedArrayBase elements) {
789 if (receiver.IsJSArray()) {
790 DCHECK(JSArray::cast(receiver).length().IsSmi())((void) 0);
791 return static_cast<uint32_t>(
792 Smi::ToInt(JSArray::cast(receiver).length()));
793 }
794 return Subclass::GetCapacityImpl(receiver, elements);
795 }
796
797 static size_t GetMaxNumberOfEntries(JSObject receiver,
798 FixedArrayBase elements) {
799 return Subclass::GetMaxIndex(receiver, elements);
800 }
801
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
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
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))((void) 0);
857 DCHECK(IsFastElementsKind(to_kind))((void) 0);
858 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind)((void) 0);
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(((void) 0)
868 (IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||((void) 0)
869 (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)))((void) 0);
870 uint32_t capacity = static_cast<uint32_t>(object->elements().length());
871 Handle<FixedArrayBase> elements;
872 ASSIGN_RETURN_ON_EXCEPTION_VALUE(do { if (!(ConvertElementsWithCapacity(object, from_elements,
from_kind, capacity)).ToHandle(&elements)) { ((void) 0);
return Nothing<bool>(); } } while (false)
873 object->GetIsolate(), elements,do { if (!(ConvertElementsWithCapacity(object, from_elements,
from_kind, capacity)).ToHandle(&elements)) { ((void) 0);
return Nothing<bool>(); } } while (false)
874 ConvertElementsWithCapacity(object, from_elements, from_kind,do { if (!(ConvertElementsWithCapacity(object, from_elements,
from_kind, capacity)).ToHandle(&elements)) { ((void) 0);
return Nothing<bool>(); } } while (false)
875 capacity),do { if (!(ConvertElementsWithCapacity(object, from_elements,
from_kind, capacity)).ToHandle(&elements)) { ((void) 0);
return Nothing<bool>(); } } while (false)
876 Nothing<bool>())do { if (!(ConvertElementsWithCapacity(object, from_elements,
from_kind, capacity)).ToHandle(&elements)) { ((void) 0);
return Nothing<bool>(); } } while (false)
;
877 JSObject::SetMapAndElements(object, to_map, elements);
878 }
879 if (FLAG_trace_elements_transitions) {
880 JSObject::PrintElementsTransition(stdoutstdout, object, from_kind,
881 from_elements, to_kind,
882 handle(object->elements(), isolate));
883 }
884 }
885 return Just(true);
886 }
887
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()) ||((void) 0)
902 IsDictionaryElementsKind(from_kind) ||((void) 0)
903 static_cast<uint32_t>(old_elements->length()) < capacity)((void) 0);
904 return Subclass::BasicGrowCapacityAndConvertImpl(
905 object, old_elements, from_kind, kind(), capacity);
906 }
907
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(do { if (!(ConvertElementsWithCapacity(object, old_elements, from_kind
, capacity)).ToHandle(&elements)) { ((void) 0); return Nothing
<bool>(); } } while (false)
913 object->GetIsolate(), elements,do { if (!(ConvertElementsWithCapacity(object, old_elements, from_kind
, capacity)).ToHandle(&elements)) { ((void) 0); return Nothing
<bool>(); } } while (false)
914 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity),do { if (!(ConvertElementsWithCapacity(object, old_elements, from_kind
, capacity)).ToHandle(&elements)) { ((void) 0); return Nothing
<bool>(); } } while (false)
915 Nothing<bool>())do { if (!(ConvertElementsWithCapacity(object, old_elements, from_kind
, capacity)).ToHandle(&elements)) { ((void) 0); return Nothing
<bool>(); } } while (false)
;
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(stdoutstdout, object, from_kind, old_elements,
928 to_kind, elements);
929 }
930 return Just(true);
931 }
932
933 Maybe<bool> TransitionElementsKind(Handle<JSObject> object,
934 Handle<Map> map) final {
935 return Subclass::TransitionElementsKindImpl(object, map);
936 }
937
938 Maybe<bool> GrowCapacityAndConvert(Handle<JSObject> object,
939 uint32_t capacity) final {
940 return Subclass::GrowCapacityAndConvertImpl(object, capacity);
941 }
942
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)((void) 0);
954 Handle<FixedArrayBase> elements;
955 ASSIGN_RETURN_ON_EXCEPTION_VALUE(do { if (!(ConvertElementsWithCapacity(object, old_elements, kind
(), new_capacity)).ToHandle(&elements)) { ((void) 0); return
Nothing<bool>(); } } while (false)
956 object->GetIsolate(), elements,do { if (!(ConvertElementsWithCapacity(object, old_elements, kind
(), new_capacity)).ToHandle(&elements)) { ((void) 0); return
Nothing<bool>(); } } while (false)
957 ConvertElementsWithCapacity(object, old_elements, kind(), new_capacity),do { if (!(ConvertElementsWithCapacity(object, old_elements, kind
(), new_capacity)).ToHandle(&elements)) { ((void) 0); return
Nothing<bool>(); } } while (false)
958 Nothing<bool>())do { if (!(ConvertElementsWithCapacity(object, old_elements, kind
(), new_capacity)).ToHandle(&elements)) { ((void) 0); return
Nothing<bool>(); } } while (false)
;
959
960 DCHECK_EQ(object->GetElementsKind(), kind())((void) 0);
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
971 void Delete(Handle<JSObject> obj, InternalIndex entry) final {
972 Subclass::DeleteImpl(obj, entry);
973 }
974
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()V8_Fatal("unreachable code");
980 }
981
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
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
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
1021 static void CopyTypedArrayElementsSliceImpl(JSTypedArray source,
1022 JSTypedArray destination,
1023 size_t start, size_t end) {
1024 UNREACHABLE()V8_Fatal("unreachable code");
1025 }
1026
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
1033 static Object CopyElementsHandleImpl(Handle<Object> source,
1034 Handle<JSObject> destination,
1035 size_t length, size_t offset) {
1036 UNREACHABLE()V8_Fatal("unreachable code");
1037 }
1038
1039 Handle<NumberDictionary> Normalize(Handle<JSObject> object) final {
1040 return Subclass::NormalizeImpl(
1041 object, handle(object->elements(), object->GetIsolate()));
1042 }
1043
1044 static Handle<NumberDictionary> NormalizeImpl(
1045 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
1046 UNREACHABLE()V8_Fatal("unreachable code");
1047 }
1048
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
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)((void) 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)((void) 0);
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(do { if (!(Object::GetProperty(&it)).ToHandle(&value)
) { ((void) 0); return Nothing<bool>(); } } while (false
)
1090 isolate, value, Object::GetProperty(&it), Nothing<bool>())do { if (!(Object::GetProperty(&it)).ToHandle(&value)
) { ((void) 0); return Nothing<bool>(); } } while (false
)
;
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),do { if (!(Object::GetProperty(&it)).ToHandle(&value)
) { ((void) 0); return Nothing<bool>(); } } while (false
)
1117 Nothing<bool>())do { if (!(Object::GetProperty(&it)).ToHandle(&value)
) { ((void) 0); return Nothing<bool>(); } } while (false
)
;
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
1127 V8_WARN_UNUSED_RESULT__attribute__((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
1134 V8_WARN_UNUSED_RESULT__attribute__((warn_unused_result)) static ExceptionStatus CollectElementIndicesImpl(
1135 Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
1136 KeyAccumulator* keys) {
1137 DCHECK_NE(DICTIONARY_ELEMENTS, kind())((void) 0);
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
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
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
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())((void) 0);
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())((void) 0);
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())((void) 0);
1260 return FixedArray::ShrinkOrEmpty(isolate, combined_keys, final_size);
1261 }
1262
1263 return combined_keys;
1264 }
1265
1266 V8_WARN_UNUSED_RESULT__attribute__((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
1273 static uint32_t GetCapacityImpl(JSObject holder,
1274 FixedArrayBase backing_store) {
1275 return backing_store.length();
1276 }
1277
1278 size_t GetCapacity(JSObject holder, FixedArrayBase backing_store) final {
1279 return Subclass::GetCapacityImpl(holder, backing_store);
1280 }
1281
1282 static MaybeHandle<Object> FillImpl(Handle<JSObject> receiver,
1283 Handle<Object> obj_value, size_t start,
1284 size_t end) {
1285 UNREACHABLE()V8_Fatal("unreachable code");
1286 }
1287
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
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
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
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
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
1321 static Maybe<int64_t> LastIndexOfValueImpl(Handle<JSObject> receiver,
1322 Handle<Object> value,
1323 size_t start_from) {
1324 UNREACHABLE()V8_Fatal("unreachable code");
1325 }
1326
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);
1
Calling 'TypedElementsAccessor::LastIndexOfValueImpl'
1331 }
1332
1333 static void ReverseImpl(JSObject receiver) { UNREACHABLE()V8_Fatal("unreachable code"); }
1334
1335 void Reverse(JSObject receiver) final { Subclass::ReverseImpl(receiver); }
1336
1337 static InternalIndex GetEntryForIndexImpl(Isolate* isolate, JSObject holder,
1338 FixedArrayBase backing_store,
1339 size_t index,
1340 PropertyFilter filter) {
1341 DCHECK(IsFastElementsKind(kind()) ||((void) 0)
1342 IsAnyNonextensibleElementsKind(kind()))((void) 0);
1343 size_t length = Subclass::GetMaxIndex(holder, backing_store);
1344 if (IsHoleyElementsKindForRead(kind())) {
1345 DCHECK_IMPLIES(((void) 0)
1346 index < length,((void) 0)
1347 index <= static_cast<size_t>(std::numeric_limits<int>::max()))((void) 0);
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
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
1365 static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
1366 InternalIndex entry) {
1367 return PropertyDetails(PropertyKind::kData, NONE,
1368 PropertyCellType::kNoCell);
1369 }
1370
1371 static PropertyDetails GetDetailsImpl(JSObject holder, InternalIndex entry) {
1372 return PropertyDetails(PropertyKind::kData, NONE,
1373 PropertyCellType::kNoCell);
1374 }
1375
1376 PropertyDetails GetDetails(JSObject holder, InternalIndex entry) final {
1377 return Subclass::GetDetailsImpl(holder, entry);
1378 }
1379
1380 Handle<FixedArray> CreateListFromArrayLike(Isolate* isolate,
1381 Handle<JSObject> object,
1382 uint32_t length) final {
1383 return Subclass::CreateListFromArrayLikeImpl(isolate, object, length);
1384 }
1385
1386 static Handle<FixedArray> CreateListFromArrayLikeImpl(Isolate* isolate,
1387 Handle<JSObject> object,
1388 uint32_t length) {
1389 UNREACHABLE()V8_Fatal("unreachable code");
1390 }
1391};
1392
1393class DictionaryElementsAccessor
1394 : public ElementsAccessorBase<DictionaryElementsAccessor,
1395 ElementsKindTraits<DICTIONARY_ELEMENTS>> {
1396 public:
1397 static uint32_t GetMaxIndex(JSObject receiver, FixedArrayBase elements) {
1398 // We cannot properly estimate this for dictionaries.
1399 UNREACHABLE()V8_Fatal("unreachable code");
1400 }
1401
1402 static uint32_t GetMaxNumberOfEntries(JSObject receiver,
1403 FixedArrayBase backing_store) {
1404 return NumberOfElementsImpl(receiver, backing_store);
1405 }
1406
1407 static uint32_t NumberOfElementsImpl(JSObject receiver,
1408 FixedArrayBase backing_store) {
1409 NumberDictionary dict = NumberDictionary::cast(backing_store);
1410 return dict.NumberOfElements();
1411 }
1412
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))do { if ((__builtin_expect(!!(!(array->length().ToArrayLength
(&old_length))), 0))) { V8_Fatal("Check failed: %s.", "array->length().ToArrayLength(&old_length)"
); } } while (false)
;
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
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()V8_Fatal("unreachable code");
1474 }
1475
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
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
1498 static Object GetRaw(FixedArrayBase store, InternalIndex entry) {
1499 NumberDictionary backing_store = NumberDictionary::cast(store);
1500 return backing_store.ValueAt(entry);
1501 }
1502
1503 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
1504 InternalIndex entry) {
1505 return handle(GetRaw(backing_store, entry), isolate);
1506 }
1507
1508 static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
1509 Object value) {
1510 SetImpl(holder->elements(), entry, value);
1511 }
1512
1513 static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
1514 Object value) {
1515 NumberDictionary::cast(backing_store).ValueAtPut(entry, value);
1516 }
1517
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
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
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
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())((void) 0);
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
1579 static PropertyDetails GetDetailsImpl(JSObject holder, InternalIndex entry) {
1580 return GetDetailsImpl(holder.elements(), entry);
1581 }
1582
1583 static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
1584 InternalIndex entry) {
1585 return NumberDictionary::cast(backing_store).DetailsAt(entry);
1586 }
1587
1588 static uint32_t FilterKey(Handle<NumberDictionary> dictionary,
1589 InternalIndex entry, Object raw_key,
1590 PropertyFilter filter) {
1591 DCHECK(raw_key.IsNumber())((void) 0);
1592 DCHECK_LE(raw_key.Number(), kMaxUInt32)((void) 0);
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
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
1609 V8_WARN_UNUSED_RESULT__attribute__((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
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
1662 V8_WARN_UNUSED_RESULT__attribute__((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))((void) 0);
1674 DCHECK(!value.IsAccessorPair())((void) 0);
1675 DCHECK(!value.IsAccessorInfo())((void) 0);
1676 RETURN_FAILURE_IF_NOT_SUCCESSFUL(accumulator->AddKey(value, convert));
1677 }
1678 return ExceptionStatus::kSuccess;
1679 }
1680
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
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))((void) 0);
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)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{original_elements_kind
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
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)((void) 0);
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())((void) 0);
1756 DCHECK_EQ(it.state(), LookupIterator::ACCESSOR)((void) 0);
1757 Handle<Object> element_k;
1758
1759 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<bool>();
} } while (false)
1760 Object::GetPropertyWithAccessor(&it),do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<bool>();
} } while (false)
1761 Nothing<bool>())do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<bool>();
} } while (false)
;
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
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))((void) 0);
1802
1803 ElementsKind original_elements_kind = receiver->GetElementsKind();
1804 USE(original_elements_kind)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{original_elements_kind
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
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)((void) 0);
1811 DCHECK_LE(k, std::numeric_limits<uint32_t>::max())((void) 0);
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())((void) 0);
1830 DCHECK_EQ(it.state(), LookupIterator::ACCESSOR)((void) 0);
1831 Handle<Object> element_k;
1832
1833 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<int64_t>
(); } } while (false)
1834 Object::GetPropertyWithAccessor(&it),do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<int64_t>
(); } } while (false)
1835 Nothing<int64_t>())do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<int64_t>
(); } } while (false)
;
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
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)((void) 0);
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())((void) 0);
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())((void) 0);
1885 } else if (!dictionary.requires_slow_elements()) {
1886 DCHECK_LE(max_key, dictionary.max_number_key())((void) 0);
1887 }
1888#endif
1889 }
1890};
1891
1892// Super class for all fast element arrays.
1893template <typename Subclass, typename KindTraits>
1894class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
1895 public:
1896 using BackingStore = typename KindTraits::BackingStore;
1897
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
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
1958 static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1959 Handle<FixedArrayBase> store) {
1960 DCHECK(obj->HasSmiOrObjectElements() || obj->HasDoubleElements() ||((void) 0)
1961 obj->HasNonextensibleElements() || obj->HasFastArgumentsElements() ||((void) 0)
1962 obj->HasFastStringWrapperElements())((void) 0);
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 >=static_assert(kLengthFraction >= NumberDictionary::kEntrySize
* NumberDictionary::kPreferFastElementsSizeFactor, "kLengthFraction >= NumberDictionary::kEntrySize * NumberDictionary::kPreferFastElementsSizeFactor"
)
1992 NumberDictionary::kEntrySize *static_assert(kLengthFraction >= NumberDictionary::kEntrySize
* NumberDictionary::kPreferFastElementsSizeFactor, "kLengthFraction >= NumberDictionary::kEntrySize * NumberDictionary::kPreferFastElementsSizeFactor"
)
1993 NumberDictionary::kPreferFastElementsSizeFactor)static_assert(kLengthFraction >= NumberDictionary::kEntrySize
* NumberDictionary::kPreferFastElementsSizeFactor, "kLengthFraction >= NumberDictionary::kEntrySize * 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
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
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)((void) 0);
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),do { if ((Subclass::GrowCapacityAndConvertImpl(object, new_capacity
)).IsNothing()) return Nothing<bool>(); } while (false)
2051 Nothing<bool>())do { if ((Subclass::GrowCapacityAndConvertImpl(object, new_capacity
)).IsNothing()) return Nothing<bool>(); } while (false)
;
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))((void) 0);
2058 JSObject::EnsureWritableFastElements(object);
2059 }
2060 }
2061 Subclass::SetImpl(object, InternalIndex(index), *value);
2062 return Just(true);
2063 }
2064
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
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
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())((void) 0);
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
2102 V8_WARN_UNUSED_RESULT__attribute__((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
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())((void) 0);
2126 } else if (IsDoubleElementsKind(KindTraits::Kind)) {
2127 DCHECK_NE(map, ReadOnlyRoots(heap).fixed_cow_array_map())((void) 0);
2128 if (map == ReadOnlyRoots(heap).fixed_array_map()) DCHECK_EQ(0u, length)((void) 0);
2129 } else {
2130 UNREACHABLE()V8_Fatal("unreachable code");
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())((void) 0);
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() ||((void) 0)
2142 (IsHoleyElementsKind(KindTraits::Kind) &&((void) 0)
2143 backing_store.is_the_hole(isolate, i)))((void) 0);
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))((void) 0);
2149 }
2150 } else {
2151 DCHECK(IsHoleyElementsKind(KindTraits::Kind))((void) 0);
2152 }
2153#endif
2154#endif
2155 }
2156
2157 static MaybeHandle<Object> PopImpl(Handle<JSArray> receiver) {
2158 return Subclass::RemoveElement(receiver, AT_END);
2159 }
2160
2161 static MaybeHandle<Object> ShiftImpl(Handle<JSArray> receiver) {
2162 return Subclass::RemoveElement(receiver, AT_START);
2163 }
2164
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
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
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())((void) 0);
2198 DCHECK_LE(hole_end, backing_store->length())((void) 0);
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
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)((void) 0);
2214 DCHECK_LE(start, end)((void) 0);
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())((void) 0);
2223 if (end > Subclass::GetCapacityImpl(*receiver, receiver->elements())) {
2224 MAYBE_RETURN_NULL(Subclass::GrowCapacityAndConvertImpl(do { if ((Subclass::GrowCapacityAndConvertImpl( receiver, static_cast
<uint32_t>(end))).IsNothing()) return MaybeHandle<Object
>(); } while (false)
2225 receiver, static_cast<uint32_t>(end)))do { if ((Subclass::GrowCapacityAndConvertImpl( receiver, static_cast
<uint32_t>(end))).IsNothing()) return MaybeHandle<Object
>(); } while (false)
;
2226 CHECK_EQ(Subclass::kind(), receiver->GetElementsKind())do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(Subclass::kind())>::type, typename
::v8::base::pass_value_or_ref<decltype(receiver->GetElementsKind
())>::type>((Subclass::kind()), (receiver->GetElementsKind
())); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal
("Check failed: %s.", "Subclass::kind()" " " "==" " " "receiver->GetElementsKind()"
); } } while (false); } while (false)
;
2227 }
2228 DCHECK_LE(end, Subclass::GetCapacityImpl(*receiver, receiver->elements()))((void) 0);
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
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))((void) 0);
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)((void) 0);
2254 return Just(false);
2255 }
2256
2257 length = std::min(elements_length, length);
2258 DCHECK_LE(length, std::numeric_limits<int>::max())((void) 0);
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()))((void) 0);
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()) ||((void) 0)
2301 IsAnyNonextensibleElementsKind(Subclass::kind()))((void) 0);
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()) ||((void) 0)
2365 IsAnyNonextensibleElementsKind(Subclass::kind()))((void) 0);
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
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
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)((void) 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(do { if ((Subclass::SetLengthImpl(isolate, receiver, new_length
, backing_store)).IsNothing()) return MaybeHandle<Object>
(); } while (false)
2415 Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store))do { if ((Subclass::SetLengthImpl(isolate, receiver, new_length
, backing_store)).IsNothing()) return MaybeHandle<Object>
(); } while (false)
;
2416
2417 if (IsHoleyElementsKind(kind) && result->IsTheHole(isolate)) {
2418 return isolate->factory()->undefined_value();
2419 }
2420 return MaybeHandle<Object>(result);
2421 }
2422
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)((void) 0);
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))((void) 0);
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(do { if (!(Subclass::ConvertElementsWithCapacity(receiver, backing_store
, KindTraits::Kind, capacity, 0, copy_dst_index)).ToHandle(&
backing_store)) { ((void) 0); return Nothing<uint32_t>(
); } } while (false)
2442 isolate, backing_store,do { if (!(Subclass::ConvertElementsWithCapacity(receiver, backing_store
, KindTraits::Kind, capacity, 0, copy_dst_index)).ToHandle(&
backing_store)) { ((void) 0); return Nothing<uint32_t>(
); } } while (false)
2443 Subclass::ConvertElementsWithCapacity(receiver, backing_store,do { if (!(Subclass::ConvertElementsWithCapacity(receiver, backing_store
, KindTraits::Kind, capacity, 0, copy_dst_index)).ToHandle(&
backing_store)) { ((void) 0); return Nothing<uint32_t>(
); } } while (false)
2444 KindTraits::Kind, capacity, 0,do { if (!(Subclass::ConvertElementsWithCapacity(receiver, backing_store
, KindTraits::Kind, capacity, 0, copy_dst_index)).ToHandle(&
backing_store)) { ((void) 0); return Nothing<uint32_t>(
); } } while (false)
2445 copy_dst_index),do { if (!(Subclass::ConvertElementsWithCapacity(receiver, backing_store
, KindTraits::Kind, capacity, 0, copy_dst_index)).ToHandle(&
backing_store)) { ((void) 0); return Nothing<uint32_t>(
); } } while (false)
2446 Nothing<uint32_t>())do { if (!(Subclass::ConvertElementsWithCapacity(receiver, backing_store
, KindTraits::Kind, capacity, 0, copy_dst_index)).ToHandle(&
backing_store)) { ((void) 0); return Nothing<uint32_t>(
); } } while (false)
;
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
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())((void) 0);
2474 Subclass::SetImpl(raw_backing_store, InternalIndex(dst_index + i),
2475 argument, mode);
2476 }
2477 }
2478};
2479
2480template <typename Subclass, typename KindTraits>
2481class FastSmiOrObjectElementsAccessor
2482 : public FastElementsAccessor<Subclass, KindTraits> {
2483 public:
2484 static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
2485 Object value) {
2486 SetImpl(holder->elements(), entry, value);
2487 }
2488
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
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
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.
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))((void) 0);
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)TYPED_ARRAY_CASE(Uint8, uint8, UINT8, uint8_t) TYPED_ARRAY_CASE
(Int8, int8, INT8, int8_t) TYPED_ARRAY_CASE(Uint16, uint16, UINT16
, uint16_t) TYPED_ARRAY_CASE(Int16, int16, INT16, int16_t) TYPED_ARRAY_CASE
(Uint32, uint32, UINT32, uint32_t) TYPED_ARRAY_CASE(Int32, int32
, INT32, int32_t) TYPED_ARRAY_CASE(Float32, float32, FLOAT32,
float) TYPED_ARRAY_CASE(Float64, float64, FLOAT64, double) TYPED_ARRAY_CASE
(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t) TYPED_ARRAY_CASE
(BigUint64, biguint64, BIGUINT64, uint64_t) TYPED_ARRAY_CASE(
BigInt64, bigint64, BIGINT64, int64_t)
2546 RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)TYPED_ARRAY_CASE(RabGsabUint8, rab_gsab_uint8, RAB_GSAB_UINT8
, uint8_t) TYPED_ARRAY_CASE(RabGsabInt8, rab_gsab_int8, RAB_GSAB_INT8
, int8_t) TYPED_ARRAY_CASE(RabGsabUint16, rab_gsab_uint16, RAB_GSAB_UINT16
, uint16_t) TYPED_ARRAY_CASE(RabGsabInt16, rab_gsab_int16, RAB_GSAB_INT16
, int16_t) TYPED_ARRAY_CASE(RabGsabUint32, rab_gsab_uint32, RAB_GSAB_UINT32
, uint32_t) TYPED_ARRAY_CASE(RabGsabInt32, rab_gsab_int32, RAB_GSAB_INT32
, int32_t) TYPED_ARRAY_CASE(RabGsabFloat32, rab_gsab_float32,
RAB_GSAB_FLOAT32, float) TYPED_ARRAY_CASE(RabGsabFloat64, rab_gsab_float64
, RAB_GSAB_FLOAT64, double) TYPED_ARRAY_CASE(RabGsabUint8Clamped
, rab_gsab_uint8_clamped, RAB_GSAB_UINT8_CLAMPED, uint8_t) TYPED_ARRAY_CASE
(RabGsabBigUint64, rab_gsab_biguint64, RAB_GSAB_BIGUINT64, uint64_t
) TYPED_ARRAY_CASE(RabGsabBigInt64, rab_gsab_bigint64, RAB_GSAB_BIGINT64
, int64_t)
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()V8_Fatal("unreachable code");
2552 case NO_ELEMENTS:
2553 break; // Nothing to do.
2554 }
2555 }
2556
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
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))((void) 0);
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 <=static_assert(FixedArray::kMaxLength <= std::numeric_limits
<uint32_t>::max(), "FixedArray::kMaxLength <= std::numeric_limits<uint32_t>::max()"
)
2617 std::numeric_limits<uint32_t>::max())static_assert(FixedArray::kMaxLength <= std::numeric_limits
<uint32_t>::max(), "FixedArray::kMaxLength <= 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
2627class FastPackedSmiElementsAccessor
2628 : public FastSmiOrObjectElementsAccessor<
2629 FastPackedSmiElementsAccessor,
2630 ElementsKindTraits<PACKED_SMI_ELEMENTS>> {};
2631
2632class FastHoleySmiElementsAccessor
2633 : public FastSmiOrObjectElementsAccessor<
2634 FastHoleySmiElementsAccessor,
2635 ElementsKindTraits<HOLEY_SMI_ELEMENTS>> {};
2636
2637class FastPackedObjectElementsAccessor
2638 : public FastSmiOrObjectElementsAccessor<
2639 FastPackedObjectElementsAccessor,
2640 ElementsKindTraits<PACKED_ELEMENTS>> {};
2641
2642template <typename Subclass, typename KindTraits>
2643class FastNonextensibleObjectElementsAccessor
2644 : public FastSmiOrObjectElementsAccessor<Subclass, KindTraits> {
2645 public:
2646 using BackingStore = typename KindTraits::BackingStore;
2647
2648 static Maybe<uint32_t> PushImpl(Handle<JSArray> receiver,
2649 BuiltinArguments* args, uint32_t push_size) {
2650 UNREACHABLE()V8_Fatal("unreachable code");
2651 }
2652
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()V8_Fatal("unreachable code");
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.
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))do { if ((__builtin_expect(!!(!(array->length().ToArrayIndex
(&old_length))), 0))) { V8_Fatal("Check failed: %s.", "array->length().ToArrayIndex(&old_length)"
); } } while (false)
;
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
2707class FastPackedNonextensibleObjectElementsAccessor
2708 : public FastNonextensibleObjectElementsAccessor<
2709 FastPackedNonextensibleObjectElementsAccessor,
2710 ElementsKindTraits<PACKED_NONEXTENSIBLE_ELEMENTS>> {};
2711
2712class FastHoleyNonextensibleObjectElementsAccessor
2713 : public FastNonextensibleObjectElementsAccessor<
2714 FastHoleyNonextensibleObjectElementsAccessor,
2715 ElementsKindTraits<HOLEY_NONEXTENSIBLE_ELEMENTS>> {};
2716
2717template <typename Subclass, typename KindTraits>
2718class FastSealedObjectElementsAccessor
2719 : public FastSmiOrObjectElementsAccessor<Subclass, KindTraits> {
2720 public:
2721 using BackingStore = typename KindTraits::BackingStore;
2722
2723 static Handle<Object> RemoveElement(Handle<JSArray> receiver,
2724 Where remove_position) {
2725 UNREACHABLE()V8_Fatal("unreachable code");
2726 }
2727
2728 static void DeleteImpl(Handle<JSObject> obj, InternalIndex entry) {
2729 UNREACHABLE()V8_Fatal("unreachable code");
2730 }
2731
2732 static void DeleteAtEnd(Handle<JSObject> obj,
2733 Handle<BackingStore> backing_store, uint32_t entry) {
2734 UNREACHABLE()V8_Fatal("unreachable code");
2735 }
2736
2737 static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
2738 Handle<FixedArrayBase> store) {
2739 UNREACHABLE()V8_Fatal("unreachable code");
2740 }
2741
2742 static MaybeHandle<Object> PopImpl(Handle<JSArray> receiver) {
2743 UNREACHABLE()V8_Fatal("unreachable code");
2744 }
2745
2746 static Maybe<uint32_t> PushImpl(Handle<JSArray> receiver,
2747 BuiltinArguments* args, uint32_t push_size) {
2748 UNREACHABLE()V8_Fatal("unreachable code");
2749 }
2750
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()V8_Fatal("unreachable code");
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.
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))do { if ((__builtin_expect(!!(!(array->length().ToArrayIndex
(&old_length))), 0))) { V8_Fatal("Check failed: %s.", "array->length().ToArrayIndex(&old_length)"
); } } while (false)
;
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
2805class FastPackedSealedObjectElementsAccessor
2806 : public FastSealedObjectElementsAccessor<
2807 FastPackedSealedObjectElementsAccessor,
2808 ElementsKindTraits<PACKED_SEALED_ELEMENTS>> {};
2809
2810class FastHoleySealedObjectElementsAccessor
2811 : public FastSealedObjectElementsAccessor<
2812 FastHoleySealedObjectElementsAccessor,
2813 ElementsKindTraits<HOLEY_SEALED_ELEMENTS>> {};
2814
2815template <typename Subclass, typename KindTraits>
2816class FastFrozenObjectElementsAccessor
2817 : public FastSmiOrObjectElementsAccessor<Subclass, KindTraits> {
2818 public:
2819 using BackingStore = typename KindTraits::BackingStore;
2820
2821 static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
2822 Object value) {
2823 UNREACHABLE()V8_Fatal("unreachable code");
2824 }
2825
2826 static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
2827 Object value) {
2828 UNREACHABLE()V8_Fatal("unreachable code");
2829 }
2830
2831 static inline void SetImpl(FixedArrayBase backing_store, InternalIndex entry,
2832 Object value, WriteBarrierMode mode) {
2833 UNREACHABLE()V8_Fatal("unreachable code");
2834 }
2835
2836 static Handle<Object> RemoveElement(Handle<JSArray> receiver,
2837 Where remove_position) {
2838 UNREACHABLE()V8_Fatal("unreachable code");
2839 }
2840
2841 static void DeleteImpl(Handle<JSObject> obj, InternalIndex entry) {
2842 UNREACHABLE()V8_Fatal("unreachable code");
2843 }
2844
2845 static void DeleteAtEnd(Handle<JSObject> obj,
2846 Handle<BackingStore> backing_store, uint32_t entry) {
2847 UNREACHABLE()V8_Fatal("unreachable code");
2848 }
2849
2850 static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
2851 Handle<FixedArrayBase> store) {
2852 UNREACHABLE()V8_Fatal("unreachable code");
2853 }
2854
2855 static MaybeHandle<Object> PopImpl(Handle<JSArray> receiver) {
2856 UNREACHABLE()V8_Fatal("unreachable code");
2857 }
2858
2859 static Maybe<uint32_t> PushImpl(Handle<JSArray> receiver,
2860 BuiltinArguments* args, uint32_t push_size) {
2861 UNREACHABLE()V8_Fatal("unreachable code");
2862 }
2863
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()V8_Fatal("unreachable code");
2869 }
2870
2871 static Maybe<bool> SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2872 uint32_t length,
2873 Handle<FixedArrayBase> backing_store) {
2874 UNREACHABLE()V8_Fatal("unreachable code");
2875 }
2876
2877 static void ReconfigureImpl(Handle<JSObject> object,
2878 Handle<FixedArrayBase> store, InternalIndex entry,
2879 Handle<Object> value,
2880 PropertyAttributes attributes) {
2881 UNREACHABLE()V8_Fatal("unreachable code");
2882 }
2883};
2884
2885class FastPackedFrozenObjectElementsAccessor
2886 : public FastFrozenObjectElementsAccessor<
2887 FastPackedFrozenObjectElementsAccessor,
2888 ElementsKindTraits<PACKED_FROZEN_ELEMENTS>> {};
2889
2890class FastHoleyFrozenObjectElementsAccessor
2891 : public FastFrozenObjectElementsAccessor<
2892 FastHoleyFrozenObjectElementsAccessor,
2893 ElementsKindTraits<HOLEY_FROZEN_ELEMENTS>> {};
2894
2895class FastHoleyObjectElementsAccessor
2896 : public FastSmiOrObjectElementsAccessor<
2897 FastHoleyObjectElementsAccessor, ElementsKindTraits<HOLEY_ELEMENTS>> {
2898};
2899
2900template <typename Subclass, typename KindTraits>
2901class FastDoubleElementsAccessor
2902 : public FastElementsAccessor<Subclass, KindTraits> {
2903 public:
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
2910 static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
2911 Object value) {
2912 SetImpl(holder->elements(), entry, value);
2913 }
2914
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
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
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)TYPED_ARRAY_CASE(Uint8, uint8, UINT8, uint8_t) TYPED_ARRAY_CASE
(Int8, int8, INT8, int8_t) TYPED_ARRAY_CASE(Uint16, uint16, UINT16
, uint16_t) TYPED_ARRAY_CASE(Int16, int16, INT16, int16_t) TYPED_ARRAY_CASE
(Uint32, uint32, UINT32, uint32_t) TYPED_ARRAY_CASE(Int32, int32
, INT32, int32_t) TYPED_ARRAY_CASE(Float32, float32, FLOAT32,
float) TYPED_ARRAY_CASE(Float64, float64, FLOAT64, double) TYPED_ARRAY_CASE
(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t) TYPED_ARRAY_CASE
(BigUint64, biguint64, BIGUINT64, uint64_t) TYPED_ARRAY_CASE(
BigInt64, bigint64, BIGINT64, int64_t)
2964 RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)TYPED_ARRAY_CASE(RabGsabUint8, rab_gsab_uint8, RAB_GSAB_UINT8
, uint8_t) TYPED_ARRAY_CASE(RabGsabInt8, rab_gsab_int8, RAB_GSAB_INT8
, int8_t) TYPED_ARRAY_CASE(RabGsabUint16, rab_gsab_uint16, RAB_GSAB_UINT16
, uint16_t) TYPED_ARRAY_CASE(RabGsabInt16, rab_gsab_int16, RAB_GSAB_INT16
, int16_t) TYPED_ARRAY_CASE(RabGsabUint32, rab_gsab_uint32, RAB_GSAB_UINT32
, uint32_t) TYPED_ARRAY_CASE(RabGsabInt32, rab_gsab_int32, RAB_GSAB_INT32
, int32_t) TYPED_ARRAY_CASE(RabGsabFloat32, rab_gsab_float32,
RAB_GSAB_FLOAT32, float) TYPED_ARRAY_CASE(RabGsabFloat64, rab_gsab_float64
, RAB_GSAB_FLOAT64, double) TYPED_ARRAY_CASE(RabGsabUint8Clamped
, rab_gsab_uint8_clamped, RAB_GSAB_UINT8_CLAMPED, uint8_t) TYPED_ARRAY_CASE
(RabGsabBigUint64, rab_gsab_biguint64, RAB_GSAB_BIGUINT64, uint64_t
) TYPED_ARRAY_CASE(RabGsabBigInt64, rab_gsab_bigint64, RAB_GSAB_BIGINT64
, int64_t)
2965#undef TYPED_ARRAY_CASE
2966 // This function is currently only used for JSArrays with non-zero
2967 // length.
2968 UNREACHABLE()V8_Fatal("unreachable code");
2969 }
2970 }
2971
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
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))((void) 0);
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 <=static_assert(FixedDoubleArray::kMaxLength <= std::numeric_limits
<int>::max(), "FixedDoubleArray::kMaxLength <= std::numeric_limits<int>::max()"
)
3016 std::numeric_limits<int>::max())static_assert(FixedDoubleArray::kMaxLength <= std::numeric_limits
<int>::max(), "FixedDoubleArray::kMaxLength <= 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
3030class FastPackedDoubleElementsAccessor
3031 : public FastDoubleElementsAccessor<
3032 FastPackedDoubleElementsAccessor,
3033 ElementsKindTraits<PACKED_DOUBLE_ELEMENTS>> {};
3034
3035class FastHoleyDoubleElementsAccessor
3036 : public FastDoubleElementsAccessor<
3037 FastHoleyDoubleElementsAccessor,
3038 ElementsKindTraits<HOLEY_DOUBLE_ELEMENTS>> {};
3039
3040enum IsSharedBuffer : bool { kShared = true, kUnshared = false };
3041
3042// Super class for all external element arrays.
3043template <ElementsKind Kind, typename ElementType>
3044class 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.
3052 static ElementType FromScalar(int value) {
3053 return static_cast<ElementType>(value);
3054 }
3055 static ElementType FromScalar(uint32_t value) {
3056 return static_cast<ElementType>(value);
3057 }
3058 static ElementType FromScalar(double value) {
3059 return FromScalar(DoubleToInt32(value));
3060 }
3061 static ElementType FromScalar(int64_t value) { UNREACHABLE()V8_Fatal("unreachable code"); }
3062 static ElementType FromScalar(uint64_t value) { UNREACHABLE()V8_Fatal("unreachable code"); }
3063
3064 // Conversions from objects / handles.
3065 static ElementType FromObject(Object value, bool* lossless = nullptr) {
3066 if (value.IsSmi()) {
7
Taking false branch
3067 return FromScalar(Smi::ToInt(value));
3068 } else if (value.IsHeapNumber()) {
8
Taking false branch
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())((void) 0);
3074 return FromScalar(Oddball::cast(value).to_number_raw());
9
Returning without writing to '*lossless'
3075 }
3076 }
3077 static ElementType FromHandle(Handle<Object> value,
3078 bool* lossless = nullptr) {
3079 return FromObject(*value, lossless);
6
Calling 'TypedElementsAccessor::FromObject'
10
Returning from 'TypedElementsAccessor::FromObject'
11
Returning without writing to '*lossless'
3080 }
3081
3082 // Conversion of scalar value to handlified object.
3083 static Handle<Object> ToHandle(Isolate* isolate, ElementType value);
3084
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())((void) 0);
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
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))static_assert(sizeof(std::atomic<ElementType>) == sizeof
(ElementType), "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))do { bool _cmp = ::v8::base::CmpLEImpl< typename ::v8::base
::pass_value_or_ref<decltype(kInt32Size)>::type, typename
::v8::base::pass_value_or_ref<decltype(alignof(ElementType
))>::type>((kInt32Size), (alignof(ElementType))); do { if
((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal("Check failed: %s."
, "kInt32Size" " " "<=" " " "alignof(ElementType)"); } } while
(false); } while (false)
;
3124 CHECK_EQ(kInt32Size, alignof(std::atomic<uint32_t>))do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(kInt32Size)>::type, typename
::v8::base::pass_value_or_ref<decltype(alignof(std::atomic
<uint32_t>))>::type>((kInt32Size), (alignof(std::
atomic<uint32_t>))); do { if ((__builtin_expect(!!(!(_cmp
)), 0))) { V8_Fatal("Check failed: %s.", "kInt32Size" " " "=="
" " "alignof(std::atomic<uint32_t>)"); } } while (false
); } while (false)
;
3125 CHECK_EQ(kInt32Size, sizeof(std::atomic<uint32_t>))do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(kInt32Size)>::type, typename
::v8::base::pass_value_or_ref<decltype(sizeof(std::atomic
<uint32_t>))>::type>((kInt32Size), (sizeof(std::atomic
<uint32_t>))); do { if ((__builtin_expect(!!(!(_cmp)), 0
))) { V8_Fatal("Check failed: %s.", "kInt32Size" " " "==" " "
"sizeof(std::atomic<uint32_t>)"); } } while (false); }
while (false)
;
3126 // And dynamically check that we indeed have at least four byte alignment.
3127 DCHECK(IsAligned(reinterpret_cast<uintptr_t>(data_ptr), kInt32Size))((void) 0);
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))do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(sizeof(words))>::type, typename
::v8::base::pass_value_or_ref<decltype(sizeof(value))>
::type>((sizeof(words)), (sizeof(value))); do { if ((__builtin_expect
(!!(!(_cmp)), 0))) { V8_Fatal("Check failed: %s.", "sizeof(words)"
" " "==" " " "sizeof(value)"); } } while (false); } while (false
)
;
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))static_assert(sizeof(std::atomic<uint32_t>) == sizeof(uint32_t
), "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
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())((void) 0);
3147 DCHECK(!typed_array->IsDetachedOrOutOfBounds())((void) 0);
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
3155 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
3156 InternalIndex entry) {
3157 UNREACHABLE()V8_Fatal("unreachable code");
3158 }
3159
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))static_assert(sizeof(std::atomic<ElementType>) == sizeof
(ElementType), "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))do { bool _cmp = ::v8::base::CmpLEImpl< typename ::v8::base
::pass_value_or_ref<decltype(kInt32Size)>::type, typename
::v8::base::pass_value_or_ref<decltype(alignof(ElementType
))>::type>((kInt32Size), (alignof(ElementType))); do { if
((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal("Check failed: %s."
, "kInt32Size" " " "<=" " " "alignof(ElementType)"); } } while
(false); } while (false)
;
3189 CHECK_EQ(kInt32Size, alignof(std::atomic<uint32_t>))do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(kInt32Size)>::type, typename
::v8::base::pass_value_or_ref<decltype(alignof(std::atomic
<uint32_t>))>::type>((kInt32Size), (alignof(std::
atomic<uint32_t>))); do { if ((__builtin_expect(!!(!(_cmp
)), 0))) { V8_Fatal("Check failed: %s.", "kInt32Size" " " "=="
" " "alignof(std::atomic<uint32_t>)"); } } while (false
); } while (false)
;
3190 CHECK_EQ(kInt32Size, sizeof(std::atomic<uint32_t>))do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(kInt32Size)>::type, typename
::v8::base::pass_value_or_ref<decltype(sizeof(std::atomic
<uint32_t>))>::type>((kInt32Size), (sizeof(std::atomic
<uint32_t>))); do { if ((__builtin_expect(!!(!(_cmp)), 0
))) { V8_Fatal("Check failed: %s.", "kInt32Size" " " "==" " "
"sizeof(std::atomic<uint32_t>)"); } } while (false); }
while (false)
;
3191 // And dynamically check that we indeed have at least four byte alignment.
3192 DCHECK(IsAligned(reinterpret_cast<uintptr_t>(data_ptr), kInt32Size))((void) 0);
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))static_assert(sizeof(std::atomic<uint32_t>) == sizeof(uint32_t
), "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))do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(sizeof(words))>::type, typename
::v8::base::pass_value_or_ref<decltype(sizeof(result))>
::type>((sizeof(words)), (sizeof(result))); do { if ((__builtin_expect
(!!(!(_cmp)), 0))) { V8_Fatal("Check failed: %s.", "sizeof(words)"
" " "==" " " "sizeof(result)"); } } while (false); } while (
false)
;
3206 memcpy(&result, words, sizeof(result));
3207 return result;
3208 }
3209
3210 static PropertyDetails GetDetailsImpl(JSObject holder, InternalIndex entry) {
3211 return PropertyDetails(PropertyKind::kData, NONE,
3212 PropertyCellType::kNoCell);
3213 }
3214
3215 static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
3216 InternalIndex entry) {
3217 return PropertyDetails(PropertyKind::kData, NONE,
3218 PropertyCellType::kNoCell);
3219 }
3220
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
3227 static bool HasAccessorsImpl(JSObject holder, FixedArrayBase backing_store) {
3228 return false;
3229 }
3230
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()V8_Fatal("unreachable code");
3236 }
3237
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
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
3254 static size_t GetCapacityImpl(JSObject holder, FixedArrayBase backing_store) {
3255 JSTypedArray typed_array = JSTypedArray::cast(holder);
3256 return typed_array.GetLength();
3257 }
3258
3259 static size_t NumberOfElementsImpl(JSObject receiver,
3260 FixedArrayBase backing_store) {
3261 return AccessorClass::GetCapacityImpl(receiver, backing_store);
3262 }
3263
3264 V8_WARN_UNUSED_RESULT__attribute__((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
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
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())((void) 0);
3304 DCHECK_LE(start, end)((void) 0);
3305 DCHECK_LE(end, typed_array->GetLength())((void) 0);
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_BOOLfalse && 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
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)(__builtin_expect(!!(out_of_bounds), 0))) {
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
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())(__builtin_expect(!!(typed_array.WasDetached()), 0)) 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)(__builtin_expect(!!(out_of_bounds), 0)) {
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
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())((void) 0);
3474
3475 ElementType typed_search_value;
3476
3477 ElementType* data_ptr =
3478 reinterpret_cast<ElementType*>(typed_array.DataPtr());
3479 if (IsBigIntTypedArrayElementsKind(Kind)) {
2
Taking true branch
3480 if (!value->IsBigInt()) return Just<int64_t>(-1);
3
Taking false branch
3481 bool lossless;
4
'lossless' declared without an initial value
3482 typed_search_value = FromHandle(value, &lossless);
5
Calling 'TypedElementsAccessor::FromHandle'
12
Returning from 'TypedElementsAccessor::FromHandle'
3483 if (!lossless) return Just<int64_t>(-1);
13
Branch condition evaluates to a garbage value
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())((void) 0);
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
3523 static void ReverseImpl(JSObject receiver) {
3524 DisallowGarbageCollection no_gc;
3525 JSTypedArray typed_array = JSTypedArray::cast(receiver);
3526
3527 DCHECK(!typed_array.IsDetachedOrOutOfBounds())((void) 0);
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_BOOLfalse && 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
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
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())((void) 0);
3572 CHECK(!source.IsDetachedOrOutOfBounds())do { if ((__builtin_expect(!!(!(!source.IsDetachedOrOutOfBounds
())), 0))) { V8_Fatal("Check failed: %s.", "!source.IsDetachedOrOutOfBounds()"
); } } while (false)
;
3573 CHECK(!destination.IsDetachedOrOutOfBounds())do { if ((__builtin_expect(!!(!(!destination.IsDetachedOrOutOfBounds
())), 0))) { V8_Fatal("Check failed: %s.", "!destination.IsDetachedOrOutOfBounds()"
); } } while (false)
;
3574 DCHECK_LE(start, end)((void) 0);
3575 DCHECK_LE(end, source.GetLength())((void) 0);
3576 size_t count = end - start;
3577 DCHECK_LE(count, destination.length())((void) 0);
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)TYPED_ARRAY_CASE(Uint8, uint8, UINT8, uint8_t) TYPED_ARRAY_CASE
(Int8, int8, INT8, int8_t) TYPED_ARRAY_CASE(Uint16, uint16, UINT16
, uint16_t) TYPED_ARRAY_CASE(Int16, int16, INT16, int16_t) TYPED_ARRAY_CASE
(Uint32, uint32, UINT32, uint32_t) TYPED_ARRAY_CASE(Int32, int32
, INT32, int32_t) TYPED_ARRAY_CASE(Float32, float32, FLOAT32,
float) TYPED_ARRAY_CASE(Float64, float64, FLOAT64, double) TYPED_ARRAY_CASE
(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t) TYPED_ARRAY_CASE
(BigUint64, biguint64, BIGUINT64, uint64_t) TYPED_ARRAY_CASE(
BigInt64, bigint64, BIGINT64, int64_t)
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)TYPED_ARRAY_CASE(RabGsabUint8, rab_gsab_uint8, RAB_GSAB_UINT8
, uint8_t, UINT8) TYPED_ARRAY_CASE(RabGsabInt8, rab_gsab_int8
, RAB_GSAB_INT8, int8_t, INT8) TYPED_ARRAY_CASE(RabGsabUint16
, rab_gsab_uint16, RAB_GSAB_UINT16, uint16_t, UINT16) TYPED_ARRAY_CASE
(RabGsabInt16, rab_gsab_int16, RAB_GSAB_INT16, int16_t, INT16
) TYPED_ARRAY_CASE(RabGsabUint32, rab_gsab_uint32, RAB_GSAB_UINT32
, uint32_t, UINT32) TYPED_ARRAY_CASE(RabGsabInt32, rab_gsab_int32
, RAB_GSAB_INT32, int32_t, INT32) TYPED_ARRAY_CASE(RabGsabFloat32
, rab_gsab_float32, RAB_GSAB_FLOAT32, float, FLOAT32) TYPED_ARRAY_CASE
(RabGsabFloat64, rab_gsab_float64, RAB_GSAB_FLOAT64, double, FLOAT64
) TYPED_ARRAY_CASE(RabGsabUint8Clamped, rab_gsab_uint8_clamped
, RAB_GSAB_UINT8_CLAMPED, uint8_t, UINT8_CLAMPED) TYPED_ARRAY_CASE
(RabGsabBigUint64, rab_gsab_biguint64, RAB_GSAB_BIGUINT64, uint64_t
, BIGUINT64) TYPED_ARRAY_CASE(RabGsabBigInt64, rab_gsab_bigint64
, RAB_GSAB_BIGINT64, int64_t, BIGINT64)
3602#undef TYPED_ARRAY_CASE
3603 default:
3604 UNREACHABLE()V8_Fatal("unreachable code");
3605 break;
3606 }
3607 }
3608
3609 // TODO(v8:11111): Update this once we have external RAB / GSAB array types.
3610 static bool HasSimpleRepresentation(ExternalArrayType type) {
3611 return !(type == kExternalFloat32Array || type == kExternalFloat64Array ||
3612 type == kExternalUint8ClampedArray);
3613 }
3614
3615 template <ElementsKind SourceKind, typename SourceElementType>
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
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())do { if ((__builtin_expect(!!(!(!source.IsDetachedOrOutOfBounds
())), 0))) { V8_Fatal("Check failed: %s.", "!source.IsDetachedOrOutOfBounds()"
); } } while (false)
;
3639 CHECK(!destination.IsDetachedOrOutOfBounds())do { if ((__builtin_expect(!!(!(!destination.IsDetachedOrOutOfBounds
())), 0))) { V8_Fatal("Check failed: %s.", "!destination.IsDetachedOrOutOfBounds()"
); } } while (false)
;
3640
3641 DCHECK_LE(offset, destination.GetLength())((void) 0);
3642 DCHECK_LE(length, destination.GetLength() - offset)((void) 0);
3643 DCHECK_LE(length, source.GetLength())((void) 0);
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)TYPED_ARRAY_CASE(Uint8, uint8, UINT8, uint8_t) TYPED_ARRAY_CASE
(Int8, int8, INT8, int8_t) TYPED_ARRAY_CASE(Uint16, uint16, UINT16
, uint16_t) TYPED_ARRAY_CASE(Int16, int16, INT16, int16_t) TYPED_ARRAY_CASE
(Uint32, uint32, UINT32, uint32_t) TYPED_ARRAY_CASE(Int32, int32
, INT32, int32_t) TYPED_ARRAY_CASE(Float32, float32, FLOAT32,
float) TYPED_ARRAY_CASE(Float64, float64, FLOAT64, double) TYPED_ARRAY_CASE
(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t) TYPED_ARRAY_CASE
(BigUint64, biguint64, BIGUINT64, uint64_t) TYPED_ARRAY_CASE(
BigInt64, bigint64, BIGINT64, int64_t)
3704 RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE)TYPED_ARRAY_CASE(RabGsabUint8, rab_gsab_uint8, RAB_GSAB_UINT8
, uint8_t) TYPED_ARRAY_CASE(RabGsabInt8, rab_gsab_int8, RAB_GSAB_INT8
, int8_t) TYPED_ARRAY_CASE(RabGsabUint16, rab_gsab_uint16, RAB_GSAB_UINT16
, uint16_t) TYPED_ARRAY_CASE(RabGsabInt16, rab_gsab_int16, RAB_GSAB_INT16
, int16_t) TYPED_ARRAY_CASE(RabGsabUint32, rab_gsab_uint32, RAB_GSAB_UINT32
, uint32_t) TYPED_ARRAY_CASE(RabGsabInt32, rab_gsab_int32, RAB_GSAB_INT32
, int32_t) TYPED_ARRAY_CASE(RabGsabFloat32, rab_gsab_float32,
RAB_GSAB_FLOAT32, float) TYPED_ARRAY_CASE(RabGsabFloat64, rab_gsab_float64
, RAB_GSAB_FLOAT64, double) TYPED_ARRAY_CASE(RabGsabUint8Clamped
, rab_gsab_uint8_clamped, RAB_GSAB_UINT8_CLAMPED, uint8_t) TYPED_ARRAY_CASE
(RabGsabBigUint64, rab_gsab_biguint64, RAB_GSAB_BIGUINT64, uint64_t
) TYPED_ARRAY_CASE(RabGsabBigInt64, rab_gsab_bigint64, RAB_GSAB_BIGINT64
, int64_t)
3705 default:
3706 UNREACHABLE()V8_Fatal("unreachable code");
3707 break;
3708 }
3709#undef TYPED_ARRAY_CASE
3710 }
3711 }
3712
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
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())do { if ((__builtin_expect(!!(!(!destination.WasDetached())),
0))) { V8_Fatal("Check failed: %s.", "!destination.WasDetached()"
); } } while (false)
;
3745 bool out_of_bounds = false;
3746 CHECK_GE(destination.GetLengthOrOutOfBounds(out_of_bounds), length)do { bool _cmp = ::v8::base::CmpGEImpl< typename ::v8::base
::pass_value_or_ref<decltype(destination.GetLengthOrOutOfBounds
(out_of_bounds))>::type, typename ::v8::base::pass_value_or_ref
<decltype(length)>::type>((destination.GetLengthOrOutOfBounds
(out_of_bounds)), (length)); do { if ((__builtin_expect(!!(!(
_cmp)), 0))) { V8_Fatal("Check failed: %s.", "destination.GetLengthOrOutOfBounds(out_of_bounds)"
" " ">=" " " "length"); } } while (false); } while (false
)
;
3747 CHECK(!out_of_bounds)do { if ((__builtin_expect(!!(!(!out_of_bounds)), 0))) { V8_Fatal
("Check failed: %s.", "!out_of_bounds"); } } while (false)
;
3748
3749 size_t current_length;
3750 DCHECK(source.length().IsNumber() &&((void) 0)
3751 TryNumberToSize(source.length(), &current_length) &&((void) 0)
3752 length <= current_length)((void) 0);
3753 USE(current_length)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{current_length
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
3754
3755 size_t dest_length = destination.GetLength();
3756 DCHECK(length + offset <= dest_length)((void) 0);
3757 USE(dest_length)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{dest_length
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
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
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,do { auto* __isolate__ = (isolate); do { if (!(Object::GetProperty
(&it)).ToHandle(&elem)) { ((void) 0); return ReadOnlyRoots
(__isolate__).exception(); } } while (false); } while (false)
3837 Object::GetProperty(&it))do { auto* __isolate__ = (isolate); do { if (!(Object::GetProperty
(&it)).ToHandle(&elem)) { ((void) 0); return ReadOnlyRoots
(__isolate__).exception(); } } while (false); } while (false)
;
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,do { auto* __isolate__ = (isolate); do { if (!(BigInt::FromObject
(isolate, elem)).ToHandle(&elem)) { ((void) 0); return ReadOnlyRoots
(__isolate__).exception(); } } while (false); } while (false)
3845 BigInt::FromObject(isolate, elem))do { auto* __isolate__ = (isolate); do { if (!(BigInt::FromObject
(isolate, elem)).ToHandle(&elem)) { ((void) 0); return ReadOnlyRoots
(__isolate__).exception(); } } while (false); } while (false)
;
3846 } else {
3847 // 2. Otherwise, let numValue be ? ToNumber(value).
3848 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,do { auto* __isolate__ = (isolate); do { if (!(Object::ToNumber
(isolate, elem)).ToHandle(&elem)) { ((void) 0); return ReadOnlyRoots
(__isolate__).exception(); } } while (false); } while (false)
3849 Object::ToNumber(isolate, elem))do { auto* __isolate__ = (isolate); do { if (!(Object::ToNumber
(isolate, elem)).ToHandle(&elem)) { ((void) 0); return ReadOnlyRoots
(__isolate__).exception(); } } while (false); } while (false)
;
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() ||(__builtin_expect(!!(out_of_bounds || destination->WasDetached
() || new_length <= offset + i), 0))
3861 new_length <= offset + i)(__builtin_expect(!!(out_of_bounds || destination->WasDetached
() || new_length <= offset + i), 0))
) {
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.
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())do { if ((__builtin_expect(!!(!(!destination_ta->WasDetached
())), 0))) { V8_Fatal("Check failed: %s.", "!destination_ta->WasDetached()"
); } } while (false)
;
3888 bool out_of_bounds = false;
3889 CHECK_LE(offset + length,do { bool _cmp = ::v8::base::CmpLEImpl< typename ::v8::base
::pass_value_or_ref<decltype(offset + length)>::type, typename
::v8::base::pass_value_or_ref<decltype(destination_ta->
GetLengthOrOutOfBounds(out_of_bounds))>::type>((offset +
length), (destination_ta->GetLengthOrOutOfBounds(out_of_bounds
))); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal(
"Check failed: %s.", "offset + length" " " "<=" " " "destination_ta->GetLengthOrOutOfBounds(out_of_bounds)"
); } } while (false); } while (false)
3890 destination_ta->GetLengthOrOutOfBounds(out_of_bounds))do { bool _cmp = ::v8::base::CmpLEImpl< typename ::v8::base
::pass_value_or_ref<decltype(offset + length)>::type, typename
::v8::base::pass_value_or_ref<decltype(destination_ta->
GetLengthOrOutOfBounds(out_of_bounds))>::type>((offset +
length), (destination_ta->GetLengthOrOutOfBounds(out_of_bounds
))); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal(
"Check failed: %s.", "offset + length" " " "<=" " " "destination_ta->GetLengthOrOutOfBounds(out_of_bounds)"
); } } while (false); } while (false)
;
3891 CHECK(!out_of_bounds)do { if ((__builtin_expect(!!(!(!out_of_bounds)), 0))) { V8_Fatal
("Check failed: %s.", "!out_of_bounds"); } } while (false)
;
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())do { if ((__builtin_expect(!!(!(!destination_ta->WasDetached
())), 0))) { V8_Fatal("Check failed: %s.", "!destination_ta->WasDetached()"
); } } while (false)
;
3907 bool out_of_bounds = false;
3908 CHECK_LE(offset + length,do { bool _cmp = ::v8::base::CmpLEImpl< typename ::v8::base
::pass_value_or_ref<decltype(offset + length)>::type, typename
::v8::base::pass_value_or_ref<decltype(destination_ta->
GetLengthOrOutOfBounds(out_of_bounds))>::type>((offset +
length), (destination_ta->GetLengthOrOutOfBounds(out_of_bounds
))); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal(
"Check failed: %s.", "offset + length" " " "<=" " " "destination_ta->GetLengthOrOutOfBounds(out_of_bounds)"
); } } while (false); } while (false)
3909 destination_ta->GetLengthOrOutOfBounds(out_of_bounds))do { bool _cmp = ::v8::base::CmpLEImpl< typename ::v8::base
::pass_value_or_ref<decltype(offset + length)>::type, typename
::v8::base::pass_value_or_ref<decltype(destination_ta->
GetLengthOrOutOfBounds(out_of_bounds))>::type>((offset +
length), (destination_ta->GetLengthOrOutOfBounds(out_of_bounds
))); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal(
"Check failed: %s.", "offset + length" " " "<=" " " "destination_ta->GetLengthOrOutOfBounds(out_of_bounds)"
); } } while (false); } while (false)
;
3910 CHECK(!out_of_bounds)do { if ((__builtin_expect(!!(!(!out_of_bounds)), 0))) { V8_Fatal
("Check failed: %s.", "!out_of_bounds"); } } while (false)
;
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())((void) 0);
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
3932template <>
3933Handle<Object> TypedElementsAccessor<INT8_ELEMENTS, int8_t>::ToHandle(
3934 Isolate* isolate, int8_t value) {
3935 return handle(Smi::FromInt(value), isolate);
3936}
3937
3938// static
3939template <>
3940Handle<Object> TypedElementsAccessor<UINT8_ELEMENTS, uint8_t>::ToHandle(
3941 Isolate* isolate, uint8_t value) {
3942 return handle(Smi::FromInt(value), isolate);
3943}
3944
3945// static
3946template <>
3947Handle<Object> TypedElementsAccessor<INT16_ELEMENTS, int16_t>::ToHandle(
3948 Isolate* isolate, int16_t value) {
3949 return handle(Smi::FromInt(value), isolate);
3950}
3951
3952// static
3953template <>
3954Handle<Object> TypedElementsAccessor<UINT16_ELEMENTS, uint16_t>::ToHandle(
3955 Isolate* isolate, uint16_t value) {
3956 return handle(Smi::FromInt(value), isolate);
3957}
3958
3959// static
3960template <>
3961Handle<Object> TypedElementsAccessor<INT32_ELEMENTS, int32_t>::ToHandle(
3962 Isolate* isolate, int32_t value) {
3963 return isolate->factory()->NewNumberFromInt(value);
3964}
3965
3966// static
3967template <>
3968Handle<Object> TypedElementsAccessor<UINT32_ELEMENTS, uint32_t>::ToHandle(
3969 Isolate* isolate, uint32_t value) {
3970 return isolate->factory()->NewNumberFromUint(value);
3971}
3972
3973// static
3974template <>
3975float TypedElementsAccessor<FLOAT32_ELEMENTS, float>::FromScalar(double value) {
3976 return DoubleToFloat32(value);
3977}
3978
3979// static
3980template <>
3981Handle<Object> TypedElementsAccessor<FLOAT32_ELEMENTS, float>::ToHandle(
3982 Isolate* isolate, float value) {
3983 return isolate->factory()->NewNumber(value);
3984}
3985
3986// static
3987template <>
3988double TypedElementsAccessor<FLOAT64_ELEMENTS, double>::FromScalar(
3989 double value) {
3990 return value;
3991}
3992
3993// static
3994template <>
3995Handle<Object> TypedElementsAccessor<FLOAT64_ELEMENTS, double>::ToHandle(
3996 Isolate* isolate, double value) {
3997 return isolate->factory()->NewNumber(value);
3998}
3999
4000// static
4001template <>
4002uint8_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
4010template <>
4011uint8_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
4020template <>
4021uint8_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
4030template <>
4031Handle<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
4037template <>
4038int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
4039 int value) {
4040 UNREACHABLE()V8_Fatal("unreachable code");
4041}
4042
4043// static
4044template <>
4045int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
4046 uint32_t value) {
4047 UNREACHABLE()V8_Fatal("unreachable code");
4048}
4049
4050// static
4051template <>
4052int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
4053 double value) {
4054 UNREACHABLE()V8_Fatal("unreachable code");
4055}
4056
4057// static
4058template <>
4059int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
4060 int64_t value) {
4061 return value;
4062}
4063
4064// static
4065template <>
4066int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromScalar(
4067 uint64_t value) {
4068 return static_cast<int64_t>(value);
4069}
4070
4071// static
4072template <>
4073int64_t TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::FromObject(
4074 Object value, bool* lossless) {
4075 return BigInt::cast(value).AsInt64(lossless);
4076}
4077
4078// static
4079template <>
4080Handle<Object> TypedElementsAccessor<BIGINT64_ELEMENTS, int64_t>::ToHandle(
4081 Isolate* isolate, int64_t value) {
4082 return BigInt::FromInt64(isolate, value);
4083}
4084
4085// static
4086template <>
4087uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
4088 int value) {
4089 UNREACHABLE()V8_Fatal("unreachable code");
4090}
4091
4092// static
4093template <>
4094uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
4095 uint32_t value) {
4096 UNREACHABLE()V8_Fatal("unreachable code");
4097}
4098
4099// static
4100template <>
4101uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
4102 double value) {
4103 UNREACHABLE()V8_Fatal("unreachable code");
4104}
4105
4106// static
4107template <>
4108uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
4109 int64_t value) {
4110 return static_cast<uint64_t>(value);
4111}
4112
4113// static
4114template <>
4115uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromScalar(
4116 uint64_t value) {
4117 return value;
4118}
4119
4120// static
4121template <>
4122uint64_t TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::FromObject(
4123 Object value, bool* lossless) {
4124 return BigInt::cast(value).AsUint64(lossless);
4125}
4126
4127// static
4128template <>
4129Handle<Object> TypedElementsAccessor<BIGUINT64_ELEMENTS, uint64_t>::ToHandle(
4130 Isolate* isolate, uint64_t value) {
4131 return BigInt::FromUint64(isolate, value);
4132}
4133
4134// static
4135template <>
4136Handle<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
4142template <>
4143Handle<Object> TypedElementsAccessor<RAB_GSAB_UINT8_ELEMENTS,
4144 uint8_t>::ToHandle(Isolate* isolate,
4145 uint8_t value) {
4146 return handle(Smi::FromInt(value), isolate);
4147}
4148
4149// static
4150template <>
4151Handle<Object> TypedElementsAccessor<RAB_GSAB_INT16_ELEMENTS,
4152 int16_t>::ToHandle(Isolate* isolate,
4153 int16_t value) {
4154 return handle(Smi::FromInt(value), isolate);
4155}
4156
4157// static
4158template <>
4159Handle<Object> TypedElementsAccessor<RAB_GSAB_UINT16_ELEMENTS,
4160 uint16_t>::ToHandle(Isolate* isolate,
4161 uint16_t value) {
4162 return handle(Smi::FromInt(value), isolate);
4163}
4164
4165// static
4166template <>
4167Handle<Object> TypedElementsAccessor<RAB_GSAB_INT32_ELEMENTS,
4168 int32_t>::ToHandle(Isolate* isolate,
4169 int32_t value) {
4170 return isolate->factory()->NewNumberFromInt(value);
4171}
4172
4173// static
4174template <>
4175Handle<Object> TypedElementsAccessor<RAB_GSAB_UINT32_ELEMENTS,
4176 uint32_t>::ToHandle(Isolate* isolate,
4177 uint32_t value) {
4178 return isolate->factory()->NewNumberFromUint(value);
4179}
4180
4181// static
4182template <>
4183float TypedElementsAccessor<RAB_GSAB_FLOAT32_ELEMENTS, float>::FromScalar(
4184 double value) {
4185 return DoubleToFloat32(value);
4186}
4187
4188// static
4189template <>
4190Handle<Object> TypedElementsAccessor<RAB_GSAB_FLOAT32_ELEMENTS,
4191 float>::ToHandle(Isolate* isolate,
4192 float value) {
4193 return isolate->factory()->NewNumber(value);
4194}
4195
4196// static
4197template <>
4198double TypedElementsAccessor<RAB_GSAB_FLOAT64_ELEMENTS, double>::FromScalar(
4199 double value) {
4200 return value;
4201}
4202
4203// static
4204template <>
4205Handle<Object> TypedElementsAccessor<RAB_GSAB_FLOAT64_ELEMENTS,
4206 double>::ToHandle(Isolate* isolate,
4207 double value) {
4208 return isolate->factory()->NewNumber(value);
4209}
4210
4211// static
4212template <>
4213uint8_t TypedElementsAccessor<RAB_GSAB_UINT8_CLAMPED_ELEMENTS,
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
4221template <>
4222uint8_t TypedElementsAccessor<RAB_GSAB_UINT8_CLAMPED_ELEMENTS,
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
4231template <>
4232uint8_t TypedElementsAccessor<RAB_GSAB_UINT8_CLAMPED_ELEMENTS,
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
4241template <>
4242Handle<Object> TypedElementsAccessor<RAB_GSAB_UINT8_CLAMPED_ELEMENTS,
4243 uint8_t>::ToHandle(Isolate* isolate,
4244 uint8_t value) {
4245 return handle(Smi::FromInt(value), isolate);
4246}
4247
4248// static
4249template <>
4250int64_t TypedElementsAccessor<RAB_GSAB_BIGINT64_ELEMENTS, int64_t>::FromScalar(
4251 int value) {
4252 UNREACHABLE()V8_Fatal("unreachable code");
4253}
4254
4255// static
4256template <>
4257int64_t TypedElementsAccessor<RAB_GSAB_BIGINT64_ELEMENTS, int64_t>::FromScalar(
4258 uint32_t value) {
4259 UNREACHABLE()V8_Fatal("unreachable code");
4260}
4261
4262// static
4263template <>
4264int64_t TypedElementsAccessor<RAB_GSAB_BIGINT64_ELEMENTS, int64_t>::FromScalar(
4265 double value) {
4266 UNREACHABLE()V8_Fatal("unreachable code");
4267}
4268
4269// static
4270template <>
4271int64_t TypedElementsAccessor<RAB_GSAB_BIGINT64_ELEMENTS, int64_t>::FromScalar(
4272 int64_t value) {
4273 return value;
4274}
4275
4276// static
4277template <>
4278int64_t TypedElementsAccessor<RAB_GSAB_BIGINT64_ELEMENTS, int64_t>::FromScalar(
4279 uint64_t value) {
4280 return static_cast<int64_t>(value);
4281}
4282
4283// static
4284template <>
4285int64_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
4291template <>
4292Handle<Object> TypedElementsAccessor<RAB_GSAB_BIGINT64_ELEMENTS,
4293 int64_t>::ToHandle(Isolate* isolate,
4294 int64_t value) {
4295 return BigInt::FromInt64(isolate, value);
4296}
4297
4298// static
4299template <>
4300uint64_t TypedElementsAccessor<RAB_GSAB_BIGUINT64_ELEMENTS,
4301 uint64_t>::FromScalar(int value) {
4302 UNREACHABLE()V8_Fatal("unreachable code");
4303}
4304
4305// static
4306template <>
4307uint64_t TypedElementsAccessor<RAB_GSAB_BIGUINT64_ELEMENTS,
4308 uint64_t>::FromScalar(uint32_t value) {
4309 UNREACHABLE()V8_Fatal("unreachable code");
4310}
4311
4312// static
4313template <>
4314uint64_t TypedElementsAccessor<RAB_GSAB_BIGUINT64_ELEMENTS,
4315 uint64_t>::FromScalar(double value) {
4316 UNREACHABLE()V8_Fatal("unreachable code");
4317}
4318
4319// static
4320template <>
4321uint64_t TypedElementsAccessor<RAB_GSAB_BIGUINT64_ELEMENTS,
4322 uint64_t>::FromScalar(int64_t value) {
4323 return static_cast<uint64_t>(value);
4324}
4325
4326// static
4327template <>
4328uint64_t TypedElementsAccessor<RAB_GSAB_BIGUINT64_ELEMENTS,
4329 uint64_t>::FromScalar(uint64_t value) {
4330 return value;
4331}
4332
4333// static
4334template <>
4335uint64_t TypedElementsAccessor<RAB_GSAB_BIGUINT64_ELEMENTS,
4336 uint64_t>::FromObject(Object value,
4337 bool* lossless) {
4338 return BigInt::cast(value).AsUint64(lossless);
4339}
4340
4341// static
4342template <>
4343Handle<Object> TypedElementsAccessor<RAB_GSAB_BIGUINT64_ELEMENTS,
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>;
4351TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)FIXED_ELEMENTS_ACCESSOR(Uint8, uint8, UINT8, uint8_t) FIXED_ELEMENTS_ACCESSOR
(Int8, int8, INT8, int8_t) FIXED_ELEMENTS_ACCESSOR(Uint16, uint16
, UINT16, uint16_t) FIXED_ELEMENTS_ACCESSOR(Int16, int16, INT16
, int16_t) FIXED_ELEMENTS_ACCESSOR(Uint32, uint32, UINT32, uint32_t
) FIXED_ELEMENTS_ACCESSOR(Int32, int32, INT32, int32_t) FIXED_ELEMENTS_ACCESSOR
(Float32, float32, FLOAT32, float) FIXED_ELEMENTS_ACCESSOR(Float64
, float64, FLOAT64, double) FIXED_ELEMENTS_ACCESSOR(Uint8Clamped
, uint8_clamped, UINT8_CLAMPED, uint8_t) FIXED_ELEMENTS_ACCESSOR
(BigUint64, biguint64, BIGUINT64, uint64_t) FIXED_ELEMENTS_ACCESSOR
(BigInt64, bigint64, BIGINT64, int64_t)
4352RAB_GSAB_TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)FIXED_ELEMENTS_ACCESSOR(RabGsabUint8, rab_gsab_uint8, RAB_GSAB_UINT8
, uint8_t) FIXED_ELEMENTS_ACCESSOR(RabGsabInt8, rab_gsab_int8
, RAB_GSAB_INT8, int8_t) FIXED_ELEMENTS_ACCESSOR(RabGsabUint16
, rab_gsab_uint16, RAB_GSAB_UINT16, uint16_t) FIXED_ELEMENTS_ACCESSOR
(RabGsabInt16, rab_gsab_int16, RAB_GSAB_INT16, int16_t) FIXED_ELEMENTS_ACCESSOR
(RabGsabUint32, rab_gsab_uint32, RAB_GSAB_UINT32, uint32_t) FIXED_ELEMENTS_ACCESSOR
(RabGsabInt32, rab_gsab_int32, RAB_GSAB_INT32, int32_t) FIXED_ELEMENTS_ACCESSOR
(RabGsabFloat32, rab_gsab_float32, RAB_GSAB_FLOAT32, float) FIXED_ELEMENTS_ACCESSOR
(RabGsabFloat64, rab_gsab_float64, RAB_GSAB_FLOAT64, double) FIXED_ELEMENTS_ACCESSOR
(RabGsabUint8Clamped, rab_gsab_uint8_clamped, RAB_GSAB_UINT8_CLAMPED
, uint8_t) FIXED_ELEMENTS_ACCESSOR(RabGsabBigUint64, rab_gsab_biguint64
, RAB_GSAB_BIGUINT64, uint64_t) FIXED_ELEMENTS_ACCESSOR(RabGsabBigInt64
, rab_gsab_bigint64, RAB_GSAB_BIGINT64, int64_t)
4353#undef FIXED_ELEMENTS_ACCESSOR
4354
4355template <typename Subclass, typename ArgumentsAccessor, typename KindTraits>
4356class SloppyArgumentsElementsAccessor
4357 : public ElementsAccessorBase<Subclass, KindTraits> {
4358 public:
4359 static void ConvertArgumentsStoreResult(
4360 Handle<SloppyArgumentsElements> elements, Handle<Object> result) {
4361 UNREACHABLE()V8_Fatal("unreachable code");
4362 }
4363
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))((void) 0);
4374 Context context = elements->context();
4375 int context_entry = Smi::ToInt(probe);
4376 DCHECK(!context.get(context_entry).IsTheHole(isolate))((void) 0);
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
4386 static Maybe<bool> TransitionElementsKindImpl(Handle<JSObject> object,
4387 Handle<Map> map) {
4388 UNREACHABLE()V8_Fatal("unreachable code");
4389 }
4390
4391 static Maybe<bool> GrowCapacityAndConvertImpl(Handle<JSObject> object,
4392 uint32_t capacity) {
4393 UNREACHABLE()V8_Fatal("unreachable code");
4394 }
4395
4396 static inline void SetImpl(Handle<JSObject> holder, InternalIndex entry,
4397 Object value) {
4398 SetImpl(holder->elements(), entry, value);
4399 }
4400
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())((void) 0);
4410 Context context = Context::cast(elements.context());
4411 int context_entry = Smi::ToInt(probe);
4412 DCHECK(!context.get(context_entry).IsTheHole())((void) 0);
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())((void) 0);
4424 context.set(context_entry, value);
4425 } else {
4426 ArgumentsAccessor::SetImpl(arguments, entry.adjust_down(length), value);
4427 }
4428 }
4429 }
4430
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()V8_Fatal("unreachable code");
4436 }
4437
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
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())((void) 0);
4453 return elements.length() + static_cast<uint32_t>(max_entries);
4454 }
4455
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
4471 V8_WARN_UNUSED_RESULT__attribute__((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
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
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
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
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
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
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
4563 static void SloppyDeleteImpl(Handle<JSObject> obj,
4564 Handle<SloppyArgumentsElements> elements,
4565 InternalIndex entry) {
4566 // Implemented in subclasses.
4567 UNREACHABLE()V8_Fatal("unreachable code");
4568 }
4569
4570 V8_WARN_UNUSED_RESULT__attribute__((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
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
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))((void) 0);
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)((void) 0);
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())((void) 0);
4638 DCHECK_EQ(it.state(), LookupIterator::ACCESSOR)((void) 0);
4639 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<bool>();
} } while (false)
4640 Object::GetPropertyWithAccessor(&it),do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<bool>();
} } while (false)
4641 Nothing<bool>())do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<bool>();
} } while (false)
;
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
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))((void) 0);
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)((void) 0);
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())((void) 0);
4678 DCHECK_EQ(it.state(), LookupIterator::ACCESSOR)((void) 0);
4679 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<int64_t>
(); } } while (false)
4680 Object::GetPropertyWithAccessor(&it),do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<int64_t>
(); } } while (false)
4681 Nothing<int64_t>())do { if (!(Object::GetPropertyWithAccessor(&it)).ToHandle
(&element_k)) { ((void) 0); return Nothing<int64_t>
(); } } while (false)
;
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
4699class SlowSloppyArgumentsElementsAccessor
4700 : public SloppyArgumentsElementsAccessor<
4701 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
4702 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS>> {
4703 public:
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))((void) 0);
4714 return handle(context.get(context_entry), isolate);
4715 }
4716 return result;
4717 }
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 }
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
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))((void) 0);
4766 Context context = elements->context();
4767 int context_entry = Smi::ToInt(probe);
4768 DCHECK(!context.get(context_entry).IsTheHole(isolate))((void) 0);
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)((void) 0);
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
4798class FastSloppyArgumentsElementsAccessor
4799 : public SloppyArgumentsElementsAccessor<
4800 FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
4801 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS>> {
4802 public:
4803 static Handle<Object> ConvertArgumentsStoreResult(
4804 Isolate* isolate, Handle<SloppyArgumentsElements> paramtere_map,
4805 Handle<Object> result) {
4806 DCHECK(!result->IsAliasedArgumentsEntry())((void) 0);
4807 return result;
4808 }
4809
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
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
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
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
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)((void) 0);
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),do { if ((GrowCapacityAndConvertImpl(object, new_capacity)).IsNothing
()) return Nothing<bool>(); } while (false)
4861 Nothing<bool>())do { if ((GrowCapacityAndConvertImpl(object, new_capacity)).IsNothing
()) return Nothing<bool>(); } while (false)
;
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
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)((void) 0);
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
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())((void) 0);
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)((void) 0);
4896 CopyObjectToObjectElements(isolate, from, HOLEY_ELEMENTS, from_start, to,
4897 HOLEY_ELEMENTS, to_start, copy_size);
4898 }
4899 }
4900
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 ||((void) 0)
4912 static_cast<uint32_t>(old_arguments->length()) < capacity)((void) 0);
4913 Handle<FixedArrayBase> arguments;
4914 ASSIGN_RETURN_ON_EXCEPTION_VALUE(do { if (!(ConvertElementsWithCapacity(object, old_arguments,
from_kind, capacity)).ToHandle(&arguments)) { ((void) 0)
; return Nothing<bool>(); } } while (false)
4915 isolate, arguments,do { if (!(ConvertElementsWithCapacity(object, old_arguments,
from_kind, capacity)).ToHandle(&arguments)) { ((void) 0)
; return Nothing<bool>(); } } while (false)
4916 ConvertElementsWithCapacity(object, old_arguments, from_kind, capacity),do { if (!(ConvertElementsWithCapacity(object, old_arguments,
from_kind, capacity)).ToHandle(&arguments)) { ((void) 0)
; return Nothing<bool>(); } } while (false)
4917 Nothing<bool>())do { if (!(ConvertElementsWithCapacity(object, old_arguments,
from_kind, capacity)).ToHandle(&arguments)) { ((void) 0)
; return Nothing<bool>(); } } while (false)
;
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
4927template <typename Subclass, typename BackingStoreAccessor, typename KindTraits>
4928class StringWrapperElementsAccessor
4929 : public ElementsAccessorBase<Subclass, KindTraits> {
4930 public:
4931 static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
4932 InternalIndex entry) {
4933 return GetImpl(holder, entry);
4934 }
4935
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
4948 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase elements,
4949 InternalIndex entry) {
4950 UNREACHABLE()V8_Fatal("unreachable code");
4951 }
4952
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
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
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
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
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()))((void) 0);
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),do { if ((GrowCapacityAndConvertImpl(object, new_capacity)).IsNothing
()) return Nothing<bool>(); } while (false)
5008 Nothing<bool>())do { if ((GrowCapacityAndConvertImpl(object, new_capacity)).IsNothing
()) return Nothing<bool>(); } while (false)
;
5009 }
5010 BackingStoreAccessor::AddImpl(object, index, value, attributes,
5011 new_capacity);
5012 return Just(true);
5013 }
5014
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
5027 V8_WARN_UNUSED_RESULT__attribute__((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
5044 V8_WARN_UNUSED_RESULT__attribute__((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
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 ||((void) 0)
5072 static_cast<uint32_t>(old_elements->length()) < capacity)((void) 0);
5073 return Subclass::BasicGrowCapacityAndConvertImpl(
5074 object, old_elements, from_kind, FAST_STRING_WRAPPER_ELEMENTS,
5075 capacity);
5076 }
5077
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())((void) 0);
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)((void) 0);
5088 CopyObjectToObjectElements(isolate, from, HOLEY_ELEMENTS, from_start, to,
5089 HOLEY_ELEMENTS, to_start, copy_size);
5090 }
5091 }
5092
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:
5101 static String GetString(JSObject holder) {
5102 DCHECK(holder.IsJSPrimitiveWrapper())((void) 0);
5103 JSPrimitiveWrapper js_value = JSPrimitiveWrapper::cast(holder);
5104 DCHECK(js_value.value().IsString())((void) 0);
5105 return String::cast(js_value.value());
5106 }
5107};
5108
5109class FastStringWrapperElementsAccessor
5110 : public StringWrapperElementsAccessor<
5111 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
5112 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
5113 public:
5114 static Handle<NumberDictionary> NormalizeImpl(
5115 Handle<JSObject> object, Handle<FixedArrayBase> elements) {
5116 return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
5117 }
5118};
5119
5120class SlowStringWrapperElementsAccessor
5121 : public StringWrapperElementsAccessor<
5122 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
5123 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
5124 public:
5125 static bool HasAccessorsImpl(JSObject holder, FixedArrayBase backing_store) {
5126 return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
5127 }
5128};
5129
5130} // namespace
5131
5132MaybeHandle<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))do { if ((JSArray::SetLength(array, length)).IsNothing()) return
MaybeHandle<Object>(); } while (false)
;
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()V8_Fatal("unreachable code");
5214 }
5215
5216 array->set_elements(*elms);
5217 array->set_length(Smi::FromInt(number_of_elements));
5218 return array;
5219}
5220
5221void 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( \do { if ((__builtin_expect(!!(!(Type##ElementsAccessor::TryCopyElementsFastNumber
( context, source, destination, length, offset))), 0))) { V8_Fatal
("Check failed: %s.", "Type##ElementsAccessor::TryCopyElementsFastNumber( context, source, destination, length, offset)"
); } } while (false)
5234 context, source, destination, length, offset))do { if ((__builtin_expect(!!(!(Type##ElementsAccessor::TryCopyElementsFastNumber
( context, source, destination, length, offset))), 0))) { V8_Fatal
("Check failed: %s.", "Type##ElementsAccessor::TryCopyElementsFastNumber( context, source, destination, length, offset)"
); } } while (false)
; \
5235 break;
5236 TYPED_ARRAYS(TYPED_ARRAYS_CASE)TYPED_ARRAYS_CASE(Uint8, uint8, UINT8, uint8_t) TYPED_ARRAYS_CASE
(Int8, int8, INT8, int8_t) TYPED_ARRAYS_CASE(Uint16, uint16, UINT16
, uint16_t) TYPED_ARRAYS_CASE(Int16, int16, INT16, int16_t) TYPED_ARRAYS_CASE
(Uint32, uint32, UINT32, uint32_t) TYPED_ARRAYS_CASE(Int32, int32
, INT32, int32_t) TYPED_ARRAYS_CASE(Float32, float32, FLOAT32
, float) TYPED_ARRAYS_CASE(Float64, float64, FLOAT64, double)
TYPED_ARRAYS_CASE(Uint8Clamped, uint8_clamped, UINT8_CLAMPED
, uint8_t) TYPED_ARRAYS_CASE(BigUint64, biguint64, BIGUINT64,
uint64_t) TYPED_ARRAYS_CASE(BigInt64, bigint64, BIGINT64, int64_t
)
5237 RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAYS_CASE)TYPED_ARRAYS_CASE(RabGsabUint8, rab_gsab_uint8, RAB_GSAB_UINT8
, uint8_t) TYPED_ARRAYS_CASE(RabGsabInt8, rab_gsab_int8, RAB_GSAB_INT8
, int8_t) TYPED_ARRAYS_CASE(RabGsabUint16, rab_gsab_uint16, RAB_GSAB_UINT16
, uint16_t) TYPED_ARRAYS_CASE(RabGsabInt16, rab_gsab_int16, RAB_GSAB_INT16
, int16_t) TYPED_ARRAYS_CASE(RabGsabUint32, rab_gsab_uint32, RAB_GSAB_UINT32
, uint32_t) TYPED_ARRAYS_CASE(RabGsabInt32, rab_gsab_int32, RAB_GSAB_INT32
, int32_t) TYPED_ARRAYS_CASE(RabGsabFloat32, rab_gsab_float32
, RAB_GSAB_FLOAT32, float) TYPED_ARRAYS_CASE(RabGsabFloat64, rab_gsab_float64
, RAB_GSAB_FLOAT64, double) TYPED_ARRAYS_CASE(RabGsabUint8Clamped
, rab_gsab_uint8_clamped, RAB_GSAB_UINT8_CLAMPED, uint8_t) TYPED_ARRAYS_CASE
(RabGsabBigUint64, rab_gsab_biguint64, RAB_GSAB_BIGUINT64, uint64_t
) TYPED_ARRAYS_CASE(RabGsabBigInt64, rab_gsab_bigint64, RAB_GSAB_BIGINT64
, int64_t)
5238#undef TYPED_ARRAYS_CASE
5239 default:
5240 UNREACHABLE()V8_Fatal("unreachable code");
5241 }
5242}
5243
5244void 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)TYPED_ARRAYS_CASE(Uint8, uint8, UINT8, uint8_t) TYPED_ARRAYS_CASE
(Int8, int8, INT8, int8_t) TYPED_ARRAYS_CASE(Uint16, uint16, UINT16
, uint16_t) TYPED_ARRAYS_CASE(Int16, int16, INT16, int16_t) TYPED_ARRAYS_CASE
(Uint32, uint32, UINT32, uint32_t) TYPED_ARRAYS_CASE(Int32, int32
, INT32, int32_t) TYPED_ARRAYS_CASE(Float32, float32, FLOAT32
, float) TYPED_ARRAYS_CASE(Float64, float64, FLOAT64, double)
TYPED_ARRAYS_CASE(Uint8Clamped, uint8_clamped, UINT8_CLAMPED
, uint8_t) TYPED_ARRAYS_CASE(BigUint64, biguint64, BIGUINT64,
uint64_t) TYPED_ARRAYS_CASE(BigInt64, bigint64, BIGINT64, int64_t
)
5257 RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAYS_CASE)TYPED_ARRAYS_CASE(RabGsabUint8, rab_gsab_uint8, RAB_GSAB_UINT8
, uint8_t) TYPED_ARRAYS_CASE(RabGsabInt8, rab_gsab_int8, RAB_GSAB_INT8
, int8_t) TYPED_ARRAYS_CASE(RabGsabUint16, rab_gsab_uint16, RAB_GSAB_UINT16
, uint16_t) TYPED_ARRAYS_CASE(RabGsabInt16, rab_gsab_int16, RAB_GSAB_INT16
, int16_t) TYPED_ARRAYS_CASE(RabGsabUint32, rab_gsab_uint32, RAB_GSAB_UINT32
, uint32_t) TYPED_ARRAYS_CASE(RabGsabInt32, rab_gsab_int32, RAB_GSAB_INT32
, int32_t) TYPED_ARRAYS_CASE(RabGsabFloat32, rab_gsab_float32
, RAB_GSAB_FLOAT32, float) TYPED_ARRAYS_CASE(RabGsabFloat64, rab_gsab_float64
, RAB_GSAB_FLOAT64, double) TYPED_ARRAYS_CASE(RabGsabUint8Clamped
, rab_gsab_uint8_clamped, RAB_GSAB_UINT8_CLAMPED, uint8_t) TYPED_ARRAYS_CASE
(RabGsabBigUint64, rab_gsab_biguint64, RAB_GSAB_BIGUINT64, uint64_t
) TYPED_ARRAYS_CASE(RabGsabBigInt64, rab_gsab_bigint64, RAB_GSAB_BIGINT64
, int64_t)
5258#undef TYPED_ARRAYS_CASE
5259 default:
5260 UNREACHABLE()V8_Fatal("unreachable code");
5261 }
5262}
5263
5264void 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
5273void 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)) ==static_assert((sizeof(accessor_array) / sizeof(*accessor_array
)) == kElementsKindCount, "(sizeof(accessor_array) / sizeof(*accessor_array)) == kElementsKindCount"
)
5281 kElementsKindCount)static_assert((sizeof(accessor_array) / sizeof(*accessor_array
)) == kElementsKindCount, "(sizeof(accessor_array) / sizeof(*accessor_array)) == kElementsKindCount"
)
;
5282
5283 elements_accessors_ = accessor_array;
5284}
5285
5286void 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
5294Handle<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)((void) 0);
5344 return result_array;
5345}
5346
5347ElementsAccessor** 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