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