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