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