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