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