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