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 4264642 : 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 4264642 : 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 3363765 : to_base->length() - to_start);
128 1121255 : if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
129 1121255 : int start = to_start + copy_size;
130 1121255 : int length = to_base->length() - start;
131 1121255 : if (length > 0) {
132 1121255 : Heap* heap = from_base->GetHeap();
133 1121255 : MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
134 1121255 : 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 8529284 : 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 1509621 : (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
148 : ? UPDATE_WRITE_BARRIER
149 1581316 : : SKIP_WRITE_BARRIER;
150 1001781233 : for (int i = 0; i < copy_size; i++) {
151 1000199917 : Object* value = from->get(from_start + i);
152 1000199917 : 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 3267 : 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 3267 : 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 6534 : if (copy_size == 0) return;
276 : FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
277 : FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
278 2357 : Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
279 2357 : Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
280 2357 : to_address += kDoubleSize * to_start;
281 2357 : 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 2357 : static_cast<size_t>(words_per_double * copy_size));
286 : }
287 :
288 :
289 181676 : 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 181676 : if (raw_copy_size < 0) {
296 : DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
297 : raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
298 181676 : copy_size = from_base->length() - from_start;
299 181676 : if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
300 7566746 : 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 363352 : if (copy_size == 0) return;
308 : FixedArray* from = FixedArray::cast(from_base);
309 : FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
310 1615 : Object* the_hole = from->GetHeap()->the_hole_value();
311 32306619 : for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
312 : from_start < from_end; from_start++, to_start++) {
313 32305004 : Object* hole_or_smi = from->get(from_start);
314 32305004 : if (hole_or_smi == the_hole) {
315 28090898 : 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 13670 : 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 13670 : if (raw_copy_size < 0) {
332 : DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
333 : raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
334 13583 : copy_size = packed_size - from_start;
335 13583 : if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
336 13583 : to_end = to_base->length();
337 545917 : 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 27340 : if (copy_size == 0) return;
351 : FixedArray* from = FixedArray::cast(from_base);
352 : FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
353 3981211 : for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
354 : from_start < from_end; from_start++, to_start++) {
355 3974879 : Object* smi = from->get(from_start);
356 : DCHECK(!smi->IsTheHole(from->GetIsolate()));
357 3974879 : to->set(to_start, Smi::cast(smi)->value());
358 : }
359 : }
360 :
361 :
362 3063 : 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 3063 : 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 6126 : if (copy_size == 0) return;
381 : FixedArray* from = FixedArray::cast(from_base);
382 : FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
383 3063 : Object* the_hole = from->GetHeap()->the_hole_value();
384 1013205 : for (uint32_t from_end = from_start + copy_size;
385 : from_start < from_end; from_start++, to_start++) {
386 1010142 : Object* hole_or_object = from->get(from_start);
387 1010142 : if (hole_or_object == the_hole) {
388 758 : to->set_the_hole(to_start);
389 : } else {
390 1009384 : 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 648960 : class ElementsAccessorBase : public ElementsAccessor {
533 : public:
534 : explicit ElementsAccessorBase(const char* name)
535 1189220 : : 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 75634372 : Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final {
621 75634372 : return Subclass::GetInternalImpl(holder, entry);
622 : }
623 :
624 74982712 : static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
625 : uint32_t entry) {
626 74982712 : return Subclass::GetImpl(holder->GetIsolate(), holder->elements(), entry);
627 : }
628 :
629 76375126 : static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase* backing_store,
630 : uint32_t entry) {
631 : uint32_t index = GetIndexForEntryImpl(backing_store, entry);
632 152750252 : return handle(BackingStore::cast(backing_store)->get(index), isolate);
633 : }
634 :
635 1397228 : void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final {
636 239 : Subclass::SetImpl(holder, entry, value);
637 1397228 : }
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 3711839 : void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
653 : PropertyAttributes attributes, uint32_t new_capacity) final {
654 3701419 : Subclass::AddImpl(object, index, value, attributes, new_capacity);
655 3711839 : }
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 769388 : Handle<JSObject> Slice(Handle<JSObject> receiver, uint32_t start,
686 : uint32_t end) final {
687 769388 : 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 750387 : Handle<Object> Pop(Handle<JSArray> receiver) final {
722 750387 : 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 315869 : Handle<Object> Shift(Handle<JSArray> receiver) final {
731 315869 : 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 1562733 : void SetLength(Handle<JSArray> array, uint32_t length) final {
740 1562732 : Subclass::SetLengthImpl(array->GetIsolate(), array, length,
741 : handle(array->elements()));
742 1562733 : }
743 :
744 2602584 : 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 2602584 : uint32_t old_length = 0;
750 2602584 : CHECK(array->length()->ToArrayIndex(&old_length));
751 :
752 2602584 : if (old_length < length) {
753 : ElementsKind kind = array->GetElementsKind();
754 1106729 : 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 2602584 : uint32_t capacity = backing_store->length();
762 5205168 : old_length = Min(old_length, capacity);
763 2602584 : if (length == 0) {
764 57583 : array->initialize_elements();
765 2545001 : } else if (length <= capacity) {
766 : if (IsFastSmiOrObjectElementsKind(kind())) {
767 1178998 : JSObject::EnsureWritableFastElements(array);
768 1178999 : if (array->elements() != *backing_store) {
769 : backing_store = handle(array->elements(), isolate);
770 : }
771 : }
772 1838628 : if (2 * length <= capacity) {
773 : // If more than half the elements won't be used, trim the array.
774 1119429 : isolate->heap()->RightTrimFixedArray(*backing_store, capacity - length);
775 : } else {
776 : // Otherwise, fill the unused tail with holes.
777 1898198 : 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 706374 : Subclass::GrowCapacityAndConvertImpl(array, capacity);
783 : }
784 :
785 2602585 : array->set_length(Smi::FromInt(length));
786 2602585 : JSObject::ValidateElements(array);
787 2602585 : }
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 331191140 : static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase* elements) {
799 331191140 : if (receiver->IsJSArray()) {
800 : DCHECK(JSArray::cast(receiver)->length()->IsSmi());
801 : return static_cast<uint32_t>(
802 193502111 : Smi::cast(JSArray::cast(receiver)->length())->value());
803 : }
804 137689029 : 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 1315496 : 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 1324349 : 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 197744 : new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
835 : } else {
836 1126605 : new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
837 : }
838 :
839 : int packed_size = kPackedSizeNotKnown;
840 1340144 : if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
841 : packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
842 : }
843 :
844 1324349 : Subclass::CopyElementsImpl(*old_elements, src_index, *new_elements,
845 : from_kind, dst_index, packed_size, copy_size);
846 :
847 1324349 : return new_elements;
848 : }
849 :
850 321 : 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 321 : if (IsFastHoleyElementsKind(from_kind)) {
856 : to_kind = GetHoleyElementsKind(to_kind);
857 : }
858 321 : 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 622 : 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 20 : 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 301 : uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
877 : Handle<FixedArrayBase> elements = ConvertElementsWithCapacity(
878 301 : object, from_elements, from_kind, capacity);
879 301 : 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 321 : }
888 :
889 1281049 : static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
890 : uint32_t capacity) {
891 : ElementsKind from_kind = object->GetElementsKind();
892 1281049 : 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 1281049 : Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
906 : kind(), capacity);
907 1281049 : }
908 :
909 1281501 : 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 1281501 : ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
914 :
915 1281501 : if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
916 1281501 : Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
917 1281501 : JSObject::SetMapAndElements(object, new_map, elements);
918 :
919 : // Transition through the allocation site as well if present.
920 1281501 : 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 1281501 : }
927 :
928 321 : void TransitionElementsKind(Handle<JSObject> object, Handle<Map> map) final {
929 321 : Subclass::TransitionElementsKindImpl(object, map);
930 321 : }
931 :
932 7899 : void GrowCapacityAndConvert(Handle<JSObject> object,
933 : uint32_t capacity) final {
934 7899 : Subclass::GrowCapacityAndConvertImpl(object, capacity);
935 7899 : }
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 3063 : void CopyElements(Handle<FixedArrayBase> source, ElementsKind source_kind,
1000 : Handle<FixedArrayBase> destination, int size) {
1001 3063 : Subclass::CopyElementsImpl(*source, 0, *destination, source_kind, 0,
1002 : kPackedSizeNotKnown, size);
1003 3063 : }
1004 :
1005 35098 : Object* CopyElements(Handle<JSReceiver> source, Handle<JSObject> destination,
1006 : size_t length) final {
1007 35098 : 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 464962 : Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final {
1018 464962 : 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 15169890 : void CollectElementIndices(Handle<JSObject> object,
1076 : Handle<FixedArrayBase> backing_store,
1077 15169890 : KeyAccumulator* keys) final {
1078 30339780 : if (keys->filter() & ONLY_ALL_CAN_READ) return;
1079 15169831 : Subclass::CollectElementIndicesImpl(object, backing_store, keys);
1080 : }
1081 :
1082 15161022 : static void CollectElementIndicesImpl(Handle<JSObject> object,
1083 : Handle<FixedArrayBase> backing_store,
1084 15161022 : KeyAccumulator* keys) {
1085 : DCHECK_NE(DICTIONARY_ELEMENTS, kind());
1086 : // Non-dictionary elements can't have all-can-read accessors.
1087 15161022 : uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
1088 : PropertyFilter filter = keys->filter();
1089 : Isolate* isolate = keys->isolate();
1090 : Factory* factory = isolate->factory();
1091 16152944 : 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 15161022 : }
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 86 : initial_list_length =
1160 : Subclass::NumberOfElementsImpl(*object, *backing_store);
1161 86 : initial_list_length += nof_property_keys;
1162 : }
1163 86 : 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 138981105 : 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 229237095 : static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
1282 : FixedArrayBase* backing_store,
1283 : uint32_t index, PropertyFilter filter) {
1284 313054960 : uint32_t length = Subclass::GetMaxIndex(holder, backing_store);
1285 : if (IsHoleyElementsKind(kind())) {
1286 : return index < length &&
1287 81928153 : !BackingStore::cast(backing_store)
1288 : ->is_the_hole(isolate, index)
1289 : ? index
1290 311165248 : : kMaxUInt32;
1291 : } else {
1292 83817865 : return index < length ? index : kMaxUInt32;
1293 : }
1294 : }
1295 :
1296 414308518 : 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 414308518 : 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 76486118 : PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final {
1313 76486118 : 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 64896 : class DictionaryElementsAccessor
1333 : : public ElementsAccessorBase<DictionaryElementsAccessor,
1334 : ElementsKindTraits<DICTIONARY_ELEMENTS> > {
1335 : public:
1336 : explicit DictionaryElementsAccessor(const char* name)
1337 : : ElementsAccessorBase<DictionaryElementsAccessor,
1338 59461 : 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 268720 : return backing_store->ValueAt(entry);
1450 : }
1451 :
1452 268337 : static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase* backing_store,
1453 : uint32_t entry) {
1454 268337 : 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 2146853 : 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 3889633 : object->HasFastElements() || object->HasFastStringWrapperElements()
1486 : ? JSObject::NormalizeElements(object)
1487 2551058 : : handle(SeededNumberDictionary::cast(object->elements()));
1488 : Handle<SeededNumberDictionary> new_dictionary =
1489 : SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
1490 2146853 : details, object);
1491 2194098 : if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1492 4285359 : 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 111545701 : 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 111545701 : int entry = dictionary->FindEntry(isolate, index);
1518 111545701 : if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
1519 277792 : 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 277764 : 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 277412 : 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 194688 : class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
1808 : public:
1809 : explicit FastElementsAccessor(const char* name)
1810 356766 : : ElementsAccessorBase<Subclass, KindTraits>(name) {}
1811 :
1812 : typedef typename KindTraits::BackingStore BackingStore;
1813 :
1814 464962 : 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 464962 : int capacity = object->GetFastElementsUsage();
1826 : Handle<SeededNumberDictionary> dictionary =
1827 464962 : SeededNumberDictionary::New(isolate, capacity);
1828 :
1829 464962 : PropertyDetails details = PropertyDetails::Empty();
1830 : int j = 0;
1831 39570438 : 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 5039321 : Handle<Object> value = Subclass::GetImpl(isolate, *store, i);
1836 3570045 : dictionary = SeededNumberDictionary::AddNumberEntry(dictionary, i, value,
1837 2100769 : details, object);
1838 3570045 : j++;
1839 : }
1840 464962 : 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 1365910 : 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 3902390 : if (IsDictionaryElementsKind(from_kind) ||
1942 : IsFastDoubleElementsKind(from_kind) !=
1943 : IsFastDoubleElementsKind(to_kind) ||
1944 : Subclass::GetCapacityImpl(*object, object->elements()) !=
1945 : new_capacity) {
1946 566776 : Subclass::GrowCapacityAndConvertImpl(object, new_capacity);
1947 : } else {
1948 799134 : if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
1949 173390 : JSObject::TransitionElementsKind(object, to_kind);
1950 : }
1951 799134 : if (IsFastSmiOrObjectElementsKind(from_kind)) {
1952 : DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
1953 517638 : JSObject::EnsureWritableFastElements(object);
1954 : }
1955 : }
1956 : Subclass::SetImpl(object, index, *value);
1957 1365910 : }
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 605283 : return !BackingStore::cast(backing_store)->is_the_hole(isolate, entry);
1973 : }
1974 :
1975 86 : static uint32_t NumberOfElementsImpl(JSObject* receiver,
1976 : FixedArrayBase* backing_store) {
1977 86 : 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 518694 : for (uint32_t i = 0; i < max_index; i++) {
1982 518608 : 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 750387 : return Subclass::RemoveElement(receiver, AT_END);
2040 : }
2041 :
2042 : static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
2043 315869 : 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 769182 : 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 769182 : int result_len = end < start ? 0u : end - start;
2065 : Handle<JSArray> result_array = isolate->factory()->NewJSArray(
2066 769182 : KindTraits::Kind, result_len, result_len);
2067 : DisallowHeapAllocation no_gc;
2068 769182 : Subclass::CopyElementsImpl(*backing_store, start, result_array->elements(),
2069 : KindTraits::Kind, 0, kPackedSizeNotKnown,
2070 : result_len);
2071 302700 : Subclass::TryTransitionResultArrayToPacked(result_array);
2072 769182 : 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 6151 : if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) &&
2085 : IsFastSmiOrObjectElementsKind(kind)) {
2086 : HandleScope scope(isolate);
2087 5709 : 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 318973 : 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 318973 : Heap* heap = isolate->heap();
2152 : Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store);
2153 318973 : if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
2154 : // Update all the copies of this backing_store handle.
2155 308031 : *dst_elms.location() =
2156 308031 : BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
2157 308031 : receiver->set_elements(*dst_elms);
2158 : // Adjust the hole offset as the array has been shrunk.
2159 308031 : hole_end -= src_index;
2160 : DCHECK_LE(hole_start, backing_store->length());
2161 : DCHECK_LE(hole_end, backing_store->length());
2162 10942 : } 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 9941 : heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index,
2169 : len);
2170 : }
2171 : }
2172 318973 : if (hole_start != hole_end) {
2173 307672 : dst_elms->FillWithHoles(hole_start, hole_end);
2174 : }
2175 318973 : }
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 1066256 : 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 376434 : JSObject::EnsureWritableFastElements(receiver);
2396 : }
2397 : Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
2398 : uint32_t length =
2399 1066256 : static_cast<uint32_t>(Smi::cast(receiver->length())->value());
2400 : DCHECK(length > 0);
2401 1066256 : int new_length = length - 1;
2402 1066256 : int remove_index = remove_position == AT_START ? 0 : new_length;
2403 : Handle<Object> result =
2404 752868 : Subclass::GetImpl(isolate, *backing_store, remove_index);
2405 1066256 : if (remove_position == AT_START) {
2406 315869 : Subclass::MoveElements(isolate, receiver, backing_store, 0, 1, new_length,
2407 : 0, 0);
2408 : }
2409 1066256 : 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 1042999 : 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 8291 : int copy_dst_index = add_position == AT_START ? add_size : 0;
2433 : // Copy over all objects to a new backing_store.
2434 8291 : backing_store = Subclass::ConvertElementsWithCapacity(
2435 : receiver, backing_store, KindTraits::Kind, capacity, 0,
2436 16582 : copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
2437 8291 : receiver->set_elements(*backing_store);
2438 890 : } 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 875 : Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0,
2443 875 : 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 13092 : 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 129792 : class FastSmiOrObjectElementsAccessor
2471 : : public FastElementsAccessor<Subclass, KindTraits> {
2472 : public:
2473 : explicit FastSmiOrObjectElementsAccessor(const char* name)
2474 237844 : : 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 1354105 : 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 10886 : 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 2747989 : 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 2747989 : switch (from_kind) {
2508 : case FAST_SMI_ELEMENTS:
2509 : case FAST_HOLEY_SMI_ELEMENTS:
2510 : case FAST_ELEMENTS:
2511 : case FAST_HOLEY_ELEMENTS:
2512 2742604 : 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 2747989 : }
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 64896 : 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 59461 : ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
2580 : };
2581 :
2582 :
2583 64896 : 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 59461 : ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
2592 : };
2593 :
2594 :
2595 64896 : class FastPackedObjectElementsAccessor
2596 : : public FastSmiOrObjectElementsAccessor<
2597 : FastPackedObjectElementsAccessor,
2598 : ElementsKindTraits<FAST_ELEMENTS> > {
2599 : public:
2600 : explicit FastPackedObjectElementsAccessor(const char* name)
2601 : : FastSmiOrObjectElementsAccessor<
2602 : FastPackedObjectElementsAccessor,
2603 59461 : ElementsKindTraits<FAST_ELEMENTS> >(name) {}
2604 : };
2605 :
2606 :
2607 64896 : 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 59461 : ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
2616 : };
2617 :
2618 : template <typename Subclass, typename KindTraits>
2619 64896 : class FastDoubleElementsAccessor
2620 : : public FastElementsAccessor<Subclass, KindTraits> {
2621 : public:
2622 : explicit FastDoubleElementsAccessor(const char* name)
2623 118922 : : 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 2952982 : isolate);
2629 : }
2630 :
2631 : static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
2632 : Object* value) {
2633 342587 : SetImpl(holder->elements(), entry, value);
2634 : }
2635 :
2636 342587 : static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2637 : Object* value) {
2638 342587 : FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
2639 342587 : }
2640 :
2641 380 : static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
2642 : Object* value, WriteBarrierMode mode) {
2643 380 : FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
2644 380 : }
2645 :
2646 201736 : 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 201736 : switch (from_kind) {
2652 : case FAST_SMI_ELEMENTS:
2653 13670 : CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
2654 : packed_size, copy_size);
2655 13670 : break;
2656 : case FAST_HOLEY_SMI_ELEMENTS:
2657 181676 : CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
2658 181676 : break;
2659 : case FAST_DOUBLE_ELEMENTS:
2660 : case FAST_HOLEY_DOUBLE_ELEMENTS:
2661 3267 : CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
2662 3267 : break;
2663 : case FAST_ELEMENTS:
2664 : case FAST_HOLEY_ELEMENTS:
2665 3063 : CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
2666 3063 : 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 201736 : }
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 64896 : 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 59461 : ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
2730 : };
2731 :
2732 :
2733 64896 : 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 59461 : ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
2742 : };
2743 :
2744 :
2745 : // Super class for all external element arrays.
2746 : template <ElementsKind Kind, typename ctype>
2747 584064 : class TypedElementsAccessor
2748 : : public ElementsAccessorBase<TypedElementsAccessor<Kind, ctype>,
2749 : ElementsKindTraits<Kind>> {
2750 : public:
2751 : explicit TypedElementsAccessor(const char* name)
2752 : : ElementsAccessorBase<AccessorClass,
2753 535149 : 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 1173675 : 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 631785 : 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 2916682 : : 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 3018964 : if (WasNeutered(holder)) return 0;
2830 3018306 : 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 1936 : 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 7801 : for (uint32_t i = 0; i < length; i++) {
3116 7577 : typename SourceTraits::ElementType elem = source_fta->get_scalar(i);
3117 2716 : dest->set(i, dest->from(elem));
3118 : }
3119 224 : }
3120 :
3121 1136 : 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 1136 : bool same_size = FixedTypedArrayBase::ElementSize(source_type) ==
3144 1136 : FixedTypedArrayBase::ElementSize(destination_type);
3145 : bool both_are_simple = HasSimpleRepresentation(source_type) &&
3146 1936 : 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 1136 : 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 169 : 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 169 : 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 967 : 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 1136 : }
3179 :
3180 32436 : static bool HoleyPrototypeLookupRequired(Isolate* isolate,
3181 : Handle<JSArray> source) {
3182 : Object* source_proto = source->map()->prototype();
3183 : // Null prototypes are OK - we don't need to do prototype chain lookups on
3184 : // them.
3185 32436 : if (source_proto->IsNull(isolate)) return false;
3186 32436 : if (source_proto->IsJSProxy()) return true;
3187 : DCHECK(source_proto->IsJSObject());
3188 32184 : if (!isolate->is_initial_array_prototype(JSObject::cast(source_proto))) {
3189 : return true;
3190 : }
3191 28204 : return !isolate->IsFastArrayConstructorPrototypeChainIntact();
3192 : }
3193 :
3194 32436 : static bool TryCopyElementsHandleFastNumber(Handle<JSArray> source,
3195 : Handle<JSTypedArray> destination,
3196 : size_t length) {
3197 : Isolate* isolate = source->GetIsolate();
3198 : DisallowHeapAllocation no_gc;
3199 32436 : DisallowJavascriptExecution no_js(isolate);
3200 :
3201 : ElementsKind kind = source->GetElementsKind();
3202 : BackingStore* dest = BackingStore::cast(destination->elements());
3203 :
3204 : // When we find the hole, we normally have to look up the element on the
3205 : // prototype chain, which is not handled here and we return false instead.
3206 : // When the array has the original array prototype, and that prototype has
3207 : // not been changed in a way that would affect lookups, we can just convert
3208 : // the hole into undefined.
3209 32436 : if (HoleyPrototypeLookupRequired(isolate, source)) return false;
3210 :
3211 28070 : Object* undefined = isolate->heap()->undefined_value();
3212 :
3213 : // Fastpath for packed Smi kind.
3214 28070 : if (kind == FAST_SMI_ELEMENTS) {
3215 : FixedArray* source_store = FixedArray::cast(source->elements());
3216 :
3217 105089 : for (uint32_t i = 0; i < length; i++) {
3218 86259 : Object* elem = source_store->get(i);
3219 : DCHECK(elem->IsSmi());
3220 : int int_value = Smi::cast(elem)->value();
3221 : dest->set(i, dest->from(int_value));
3222 : }
3223 : return true;
3224 9240 : } else if (kind == FAST_HOLEY_SMI_ELEMENTS) {
3225 : FixedArray* source_store = FixedArray::cast(source->elements());
3226 571902 : for (uint32_t i = 0; i < length; i++) {
3227 566036 : if (source_store->is_the_hole(isolate, i)) {
3228 22508 : dest->SetValue(i, undefined);
3229 : } else {
3230 : Object* elem = source_store->get(i);
3231 : DCHECK(elem->IsSmi());
3232 : int int_value = Smi::cast(elem)->value();
3233 : dest->set(i, dest->from(int_value));
3234 : }
3235 : }
3236 : return true;
3237 3374 : } else if (kind == FAST_DOUBLE_ELEMENTS) {
3238 : // Fastpath for packed double kind. We avoid boxing and then immediately
3239 : // unboxing the double here by using get_scalar.
3240 : FixedDoubleArray* source_store =
3241 : FixedDoubleArray::cast(source->elements());
3242 :
3243 27398 : for (uint32_t i = 0; i < length; i++) {
3244 : // Use the from_double conversion for this specific TypedArray type,
3245 : // rather than relying on C++ to convert elem.
3246 24192 : double elem = source_store->get_scalar(i);
3247 : dest->set(i, dest->from(elem));
3248 : }
3249 : return true;
3250 168 : } else if (kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
3251 : FixedDoubleArray* source_store =
3252 : FixedDoubleArray::cast(source->elements());
3253 120054 : for (uint32_t i = 0; i < length; i++) {
3254 240024 : if (source_store->is_the_hole(i)) {
3255 0 : dest->SetValue(i, undefined);
3256 : } else {
3257 : double elem = source_store->get_scalar(i);
3258 : dest->set(i, dest->from(elem));
3259 : }
3260 : }
3261 : return true;
3262 : }
3263 32436 : return false;
3264 : }
3265 :
3266 6018 : static Object* CopyElementsHandleSlow(Handle<JSReceiver> source,
3267 : Handle<JSTypedArray> destination,
3268 : size_t length) {
3269 : Isolate* isolate = source->GetIsolate();
3270 : Handle<BackingStore> destination_elements(
3271 : BackingStore::cast(destination->elements()));
3272 485504 : for (uint32_t i = 0; i < length; i++) {
3273 : LookupIterator it(isolate, source, i, source);
3274 : Handle<Object> elem;
3275 474980 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
3276 : Object::GetProperty(&it));
3277 474476 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem, Object::ToNumber(elem));
3278 : // We don't need to check for buffer neutering here, because the
3279 : // source cannot be a TypedArray.
3280 : // The spec says we store the length, then get each element, so we don't
3281 : // need to check changes to length.
3282 236734 : destination_elements->SetValue(i, *elem);
3283 : }
3284 : return Smi::kZero;
3285 : }
3286 :
3287 35098 : static Object* CopyElementsHandleImpl(Handle<JSReceiver> source,
3288 : Handle<JSObject> destination,
3289 : size_t length) {
3290 : Handle<JSTypedArray> destination_ta =
3291 35098 : Handle<JSTypedArray>::cast(destination);
3292 :
3293 : // All conversions from TypedArrays can be done without allocation.
3294 35098 : if (source->IsJSTypedArray()) {
3295 1136 : Handle<JSTypedArray> source_ta = Handle<JSTypedArray>::cast(source);
3296 1136 : CopyElementsHandleFromTypedArray(source_ta, destination_ta, length);
3297 : return Smi::kZero;
3298 : }
3299 :
3300 : // Fast cases for packed numbers kinds where we don't need to allocate.
3301 33962 : if (source->IsJSArray()) {
3302 32436 : Handle<JSArray> source_array = Handle<JSArray>::cast(source);
3303 32436 : if (TryCopyElementsHandleFastNumber(source_array, destination_ta,
3304 : length)) {
3305 27944 : return Smi::kZero;
3306 : }
3307 : }
3308 : // Final generic case that handles prototype chain lookups, getters, proxies
3309 : // and observable side effects via valueOf, etc.
3310 6018 : return CopyElementsHandleSlow(source, destination_ta, length);
3311 : }
3312 : };
3313 :
3314 : #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
3315 : typedef TypedElementsAccessor<TYPE##_ELEMENTS, ctype> \
3316 : Fixed##Type##ElementsAccessor;
3317 :
3318 : TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
3319 : #undef FIXED_ELEMENTS_ACCESSOR
3320 :
3321 : template <typename Subclass, typename ArgumentsAccessor, typename KindTraits>
3322 64896 : class SloppyArgumentsElementsAccessor
3323 : : public ElementsAccessorBase<Subclass, KindTraits> {
3324 : public:
3325 : explicit SloppyArgumentsElementsAccessor(const char* name)
3326 118922 : : ElementsAccessorBase<Subclass, KindTraits>(name) {
3327 : USE(KindTraits::Kind);
3328 : }
3329 :
3330 : static void ConvertArgumentsStoreResult(
3331 : Isolate* isolate, Handle<SloppyArgumentsElements> elements,
3332 : Handle<Object> result) {
3333 : UNREACHABLE();
3334 : }
3335 :
3336 50461 : static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase* parameters,
3337 : uint32_t entry) {
3338 : Handle<SloppyArgumentsElements> elements(
3339 : SloppyArgumentsElements::cast(parameters), isolate);
3340 : uint32_t length = elements->parameter_map_length();
3341 50461 : if (entry < length) {
3342 : // Read context mapped entry.
3343 : DisallowHeapAllocation no_gc;
3344 : Object* probe = elements->get_mapped_entry(entry);
3345 : DCHECK(!probe->IsTheHole(isolate));
3346 : Context* context = elements->context();
3347 : int context_entry = Smi::cast(probe)->value();
3348 : DCHECK(!context->get(context_entry)->IsTheHole(isolate));
3349 : return handle(context->get(context_entry), isolate);
3350 : } else {
3351 : // Entry is not context mapped, defer to the arguments.
3352 : Handle<Object> result = ArgumentsAccessor::GetImpl(
3353 14980 : isolate, elements->arguments(), entry - length);
3354 1666 : return Subclass::ConvertArgumentsStoreResult(isolate, elements, result);
3355 : }
3356 : }
3357 :
3358 0 : static void TransitionElementsKindImpl(Handle<JSObject> object,
3359 : Handle<Map> map) {
3360 0 : UNREACHABLE();
3361 : }
3362 :
3363 0 : static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
3364 : uint32_t capacity) {
3365 0 : UNREACHABLE();
3366 : }
3367 :
3368 : static inline void SetImpl(Handle<JSObject> holder, uint32_t entry,
3369 : Object* value) {
3370 35011 : SetImpl(holder->elements(), entry, value);
3371 : }
3372 :
3373 35011 : static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
3374 : Object* value) {
3375 : SloppyArgumentsElements* elements = SloppyArgumentsElements::cast(store);
3376 : uint32_t length = elements->parameter_map_length();
3377 35011 : if (entry < length) {
3378 : // Store context mapped entry.
3379 : DisallowHeapAllocation no_gc;
3380 : Object* probe = elements->get_mapped_entry(entry);
3381 : DCHECK(!probe->IsTheHole(store->GetIsolate()));
3382 : Context* context = elements->context();
3383 : int context_entry = Smi::cast(probe)->value();
3384 : DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
3385 34570 : context->set(context_entry, value);
3386 : } else {
3387 : // Entry is not context mapped defer to arguments.
3388 : FixedArray* arguments = elements->arguments();
3389 441 : Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
3390 441 : if (current->IsAliasedArgumentsEntry()) {
3391 : AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
3392 : Context* context = elements->context();
3393 : int context_entry = alias->aliased_context_slot();
3394 : DCHECK(!context->get(context_entry)->IsTheHole(store->GetIsolate()));
3395 103 : context->set(context_entry, value);
3396 : } else {
3397 : ArgumentsAccessor::SetImpl(arguments, entry - length, value);
3398 : }
3399 : }
3400 35011 : }
3401 :
3402 0 : static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
3403 : uint32_t length,
3404 : Handle<FixedArrayBase> parameter_map) {
3405 : // Sloppy arguments objects are not arrays.
3406 0 : UNREACHABLE();
3407 : }
3408 :
3409 366 : static uint32_t GetCapacityImpl(JSObject* holder, FixedArrayBase* store) {
3410 : SloppyArgumentsElements* elements = SloppyArgumentsElements::cast(store);
3411 : FixedArray* arguments = elements->arguments();
3412 : return elements->parameter_map_length() +
3413 366 : ArgumentsAccessor::GetCapacityImpl(holder, arguments);
3414 : }
3415 :
3416 280 : static uint32_t GetMaxNumberOfEntries(JSObject* holder,
3417 : FixedArrayBase* backing_store) {
3418 : SloppyArgumentsElements* elements =
3419 : SloppyArgumentsElements::cast(backing_store);
3420 : FixedArrayBase* arguments = elements->arguments();
3421 : return elements->parameter_map_length() +
3422 280 : ArgumentsAccessor::GetMaxNumberOfEntries(holder, arguments);
3423 : }
3424 :
3425 0 : static uint32_t NumberOfElementsImpl(JSObject* receiver,
3426 : FixedArrayBase* backing_store) {
3427 : Isolate* isolate = receiver->GetIsolate();
3428 : SloppyArgumentsElements* elements =
3429 : SloppyArgumentsElements::cast(backing_store);
3430 : FixedArrayBase* arguments = elements->arguments();
3431 : uint32_t nof_elements = 0;
3432 : uint32_t length = elements->parameter_map_length();
3433 0 : for (uint32_t entry = 0; entry < length; entry++) {
3434 0 : if (HasParameterMapArg(isolate, elements, entry)) nof_elements++;
3435 : }
3436 : return nof_elements +
3437 0 : ArgumentsAccessor::NumberOfElementsImpl(receiver, arguments);
3438 : }
3439 :
3440 7 : static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
3441 7 : KeyAccumulator* accumulator,
3442 : AddKeyConversion convert) {
3443 : Isolate* isolate = accumulator->isolate();
3444 : Handle<FixedArrayBase> elements(receiver->elements(), isolate);
3445 7 : uint32_t length = GetCapacityImpl(*receiver, *elements);
3446 49 : for (uint32_t entry = 0; entry < length; entry++) {
3447 56 : if (!HasEntryImpl(isolate, *elements, entry)) continue;
3448 28 : Handle<Object> value = GetImpl(isolate, *elements, entry);
3449 28 : accumulator->AddKey(value, convert);
3450 : }
3451 7 : }
3452 :
3453 471 : static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* parameters,
3454 : uint32_t entry) {
3455 : SloppyArgumentsElements* elements =
3456 : SloppyArgumentsElements::cast(parameters);
3457 : uint32_t length = elements->parameter_map_length();
3458 471 : if (entry < length) {
3459 341 : return HasParameterMapArg(isolate, elements, entry);
3460 : }
3461 : FixedArrayBase* arguments = elements->arguments();
3462 260 : return ArgumentsAccessor::HasEntryImpl(isolate, arguments, entry - length);
3463 : }
3464 :
3465 0 : static bool HasAccessorsImpl(JSObject* holder,
3466 : FixedArrayBase* backing_store) {
3467 : SloppyArgumentsElements* elements =
3468 : SloppyArgumentsElements::cast(backing_store);
3469 : FixedArray* arguments = elements->arguments();
3470 0 : return ArgumentsAccessor::HasAccessorsImpl(holder, arguments);
3471 : }
3472 :
3473 59 : static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
3474 : uint32_t entry) {
3475 : SloppyArgumentsElements* elements =
3476 : SloppyArgumentsElements::cast(parameters);
3477 : uint32_t length = elements->parameter_map_length();
3478 59 : if (entry < length) return entry;
3479 : FixedArray* arguments = elements->arguments();
3480 0 : return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
3481 : }
3482 :
3483 739530 : static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
3484 : FixedArrayBase* parameters,
3485 : uint32_t index, PropertyFilter filter) {
3486 : SloppyArgumentsElements* elements =
3487 : SloppyArgumentsElements::cast(parameters);
3488 739530 : if (HasParameterMapArg(isolate, elements, index)) return index;
3489 : FixedArray* arguments = elements->arguments();
3490 : uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(
3491 659843 : isolate, holder, arguments, index, filter);
3492 659843 : if (entry == kMaxUInt32) return kMaxUInt32;
3493 8966 : return elements->parameter_map_length() + entry;
3494 : }
3495 :
3496 87506 : static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
3497 : SloppyArgumentsElements* elements =
3498 : SloppyArgumentsElements::cast(holder->elements());
3499 : uint32_t length = elements->parameter_map_length();
3500 87506 : if (entry < length) {
3501 79111 : return PropertyDetails(kData, NONE, 0, PropertyCellType::kNoCell);
3502 : }
3503 : FixedArray* arguments = elements->arguments();
3504 2154 : return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
3505 : }
3506 :
3507 739871 : static bool HasParameterMapArg(Isolate* isolate,
3508 : SloppyArgumentsElements* elements,
3509 : uint32_t index) {
3510 : uint32_t length = elements->parameter_map_length();
3511 739871 : if (index >= length) return false;
3512 82072 : return !elements->get_mapped_entry(index)->IsTheHole(isolate);
3513 : }
3514 :
3515 771 : static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
3516 : SloppyArgumentsElements* elements =
3517 : SloppyArgumentsElements::cast(obj->elements());
3518 : uint32_t length = elements->parameter_map_length();
3519 771 : if (entry < length) {
3520 : // TODO(kmillikin): We could check if this was the last aliased
3521 : // parameter, and revert to normal elements in that case. That
3522 : // would enable GC of the context.
3523 569 : elements->set_mapped_entry(entry, obj->GetHeap()->the_hole_value());
3524 : } else {
3525 202 : Subclass::DeleteFromArguments(obj, entry - length);
3526 : }
3527 771 : }
3528 :
3529 303 : static void CollectElementIndicesImpl(Handle<JSObject> object,
3530 : Handle<FixedArrayBase> backing_store,
3531 303 : KeyAccumulator* keys) {
3532 : Isolate* isolate = keys->isolate();
3533 303 : uint32_t nof_indices = 0;
3534 : Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
3535 303 : GetCapacityImpl(*object, *backing_store));
3536 303 : DirectCollectElementIndicesImpl(isolate, object, backing_store,
3537 : GetKeysConversion::kKeepNumbers,
3538 : ENUMERABLE_STRINGS, indices, &nof_indices);
3539 303 : SortIndices(indices, nof_indices);
3540 931 : for (uint32_t i = 0; i < nof_indices; i++) {
3541 1604 : keys->AddKey(indices->get(i));
3542 : }
3543 303 : }
3544 :
3545 583 : static Handle<FixedArray> DirectCollectElementIndicesImpl(
3546 : Isolate* isolate, Handle<JSObject> object,
3547 : Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
3548 : PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices,
3549 : uint32_t insertion_index = 0) {
3550 : Handle<SloppyArgumentsElements> elements =
3551 : Handle<SloppyArgumentsElements>::cast(backing_store);
3552 : uint32_t length = elements->parameter_map_length();
3553 :
3554 1324 : for (uint32_t i = 0; i < length; ++i) {
3555 1324 : if (elements->get_mapped_entry(i)->IsTheHole(isolate)) continue;
3556 1019 : if (convert == GetKeysConversion::kConvertToString) {
3557 0 : Handle<String> index_string = isolate->factory()->Uint32ToString(i);
3558 0 : list->set(insertion_index, *index_string);
3559 : } else {
3560 3057 : list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER);
3561 : }
3562 1019 : insertion_index++;
3563 : }
3564 :
3565 : Handle<FixedArray> store(elements->arguments(), isolate);
3566 : return ArgumentsAccessor::DirectCollectElementIndicesImpl(
3567 : isolate, object, store, convert, filter, list, nof_indices,
3568 583 : insertion_index);
3569 : }
3570 :
3571 141 : static Maybe<bool> IncludesValueImpl(Isolate* isolate,
3572 : Handle<JSObject> object,
3573 : Handle<Object> value,
3574 : uint32_t start_from, uint32_t length) {
3575 : DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
3576 : Handle<Map> original_map = handle(object->map(), isolate);
3577 : Handle<SloppyArgumentsElements> elements(
3578 : SloppyArgumentsElements::cast(object->elements()), isolate);
3579 : bool search_for_hole = value->IsUndefined(isolate);
3580 :
3581 354 : for (uint32_t k = start_from; k < length; ++k) {
3582 : uint32_t entry =
3583 283 : GetEntryForIndexImpl(isolate, *object, *elements, k, ALL_PROPERTIES);
3584 283 : if (entry == kMaxUInt32) {
3585 0 : if (search_for_hole) return Just(true);
3586 : continue;
3587 : }
3588 :
3589 283 : Handle<Object> element_k = Subclass::GetImpl(isolate, *elements, entry);
3590 :
3591 283 : if (element_k->IsAccessorPair()) {
3592 57 : LookupIterator it(isolate, object, k, LookupIterator::OWN);
3593 : DCHECK(it.IsFound());
3594 : DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
3595 128 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
3596 : Object::GetPropertyWithAccessor(&it),
3597 : Nothing<bool>());
3598 :
3599 57 : if (value->SameValueZero(*element_k)) return Just(true);
3600 :
3601 43 : if (object->map() != *original_map) {
3602 : // Some mutation occurred in accessor. Abort "fast" path
3603 0 : return IncludesValueSlowPath(isolate, object, value, k + 1, length);
3604 : }
3605 226 : } else if (value->SameValueZero(*element_k)) {
3606 : return Just(true);
3607 : }
3608 : }
3609 : return Just(false);
3610 : }
3611 :
3612 150 : static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
3613 : Handle<JSObject> object,
3614 : Handle<Object> value,
3615 : uint32_t start_from, uint32_t length) {
3616 : DCHECK(JSObject::PrototypeHasNoElements(isolate, *object));
3617 : Handle<Map> original_map = handle(object->map(), isolate);
3618 : Handle<SloppyArgumentsElements> elements(
3619 : SloppyArgumentsElements::cast(object->elements()), isolate);
3620 :
3621 450 : for (uint32_t k = start_from; k < length; ++k) {
3622 : uint32_t entry =
3623 345 : GetEntryForIndexImpl(isolate, *object, *elements, k, ALL_PROPERTIES);
3624 345 : if (entry == kMaxUInt32) {
3625 : continue;
3626 : }
3627 :
3628 345 : Handle<Object> element_k = Subclass::GetImpl(isolate, *elements, entry);
3629 :
3630 345 : if (element_k->IsAccessorPair()) {
3631 75 : LookupIterator it(isolate, object, k, LookupIterator::OWN);
3632 : DCHECK(it.IsFound());
3633 : DCHECK_EQ(it.state(), LookupIterator::ACCESSOR);
3634 165 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
3635 : Object::GetPropertyWithAccessor(&it),
3636 : Nothing<int64_t>());
3637 :
3638 75 : if (value->StrictEquals(*element_k)) {
3639 15 : return Just<int64_t>(k);
3640 : }
3641 :
3642 60 : if (object->map() != *original_map) {
3643 : // Some mutation occurred in accessor. Abort "fast" path.
3644 0 : return IndexOfValueSlowPath(isolate, object, value, k + 1, length);
3645 : }
3646 270 : } else if (value->StrictEquals(*element_k)) {
3647 30 : return Just<int64_t>(k);
3648 : }
3649 : }
3650 : return Just<int64_t>(-1);
3651 : }
3652 : };
3653 :
3654 :
3655 64896 : class SlowSloppyArgumentsElementsAccessor
3656 : : public SloppyArgumentsElementsAccessor<
3657 : SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
3658 : ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
3659 : public:
3660 : explicit SlowSloppyArgumentsElementsAccessor(const char* name)
3661 : : SloppyArgumentsElementsAccessor<
3662 : SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
3663 59461 : ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
3664 :
3665 1666 : static Handle<Object> ConvertArgumentsStoreResult(
3666 : Isolate* isolate, Handle<SloppyArgumentsElements> elements,
3667 : Handle<Object> result) {
3668 : // Elements of the arguments object in slow mode might be slow aliases.
3669 1666 : if (result->IsAliasedArgumentsEntry()) {
3670 : DisallowHeapAllocation no_gc;
3671 : AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
3672 : Context* context = elements->context();
3673 : int context_entry = alias->aliased_context_slot();
3674 : DCHECK(!context->get(context_entry)->IsTheHole(isolate));
3675 : return handle(context->get(context_entry), isolate);
3676 : }
3677 1622 : return result;
3678 : }
3679 59 : static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
3680 : Isolate* isolate = obj->GetIsolate();
3681 : Handle<SloppyArgumentsElements> elements(
3682 : SloppyArgumentsElements::cast(obj->elements()), isolate);
3683 : Handle<SeededNumberDictionary> dict(
3684 : SeededNumberDictionary::cast(elements->arguments()), isolate);
3685 : // TODO(verwaest): Remove reliance on index in Shrink.
3686 59 : uint32_t index = GetIndexForEntryImpl(*dict, entry);
3687 59 : Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
3688 : USE(result);
3689 : DCHECK(result->IsTrue(dict->GetIsolate()));
3690 : Handle<FixedArray> new_elements =
3691 : SeededNumberDictionary::Shrink(dict, index);
3692 : elements->set_arguments(*new_elements);
3693 59 : }
3694 :
3695 21205 : static void AddImpl(Handle<JSObject> object, uint32_t index,
3696 : Handle<Object> value, PropertyAttributes attributes,
3697 : uint32_t new_capacity) {
3698 : Isolate* isolate = object->GetIsolate();
3699 : Handle<SloppyArgumentsElements> elements(
3700 : SloppyArgumentsElements::cast(object->elements()), isolate);
3701 : Handle<FixedArrayBase> old_arguments(
3702 : FixedArrayBase::cast(elements->arguments()), isolate);
3703 : Handle<SeededNumberDictionary> dictionary =
3704 : old_arguments->IsSeededNumberDictionary()
3705 : ? Handle<SeededNumberDictionary>::cast(old_arguments)
3706 21205 : : JSObject::NormalizeElements(object);
3707 : PropertyDetails details(kData, attributes, 0, PropertyCellType::kNoCell);
3708 : Handle<SeededNumberDictionary> new_dictionary =
3709 : SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
3710 21205 : details, object);
3711 21337 : if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
3712 21205 : if (*dictionary != *new_dictionary) {
3713 : elements->set_arguments(*new_dictionary);
3714 : }
3715 21205 : }
3716 :
3717 323 : static void ReconfigureImpl(Handle<JSObject> object,
3718 : Handle<FixedArrayBase> store, uint32_t entry,
3719 : Handle<Object> value,
3720 : PropertyAttributes attributes) {
3721 : Isolate* isolate = store->GetIsolate();
3722 : Handle<SloppyArgumentsElements> elements =
3723 : Handle<SloppyArgumentsElements>::cast(store);
3724 : uint32_t length = elements->parameter_map_length();
3725 323 : if (entry < length) {
3726 : Object* probe = elements->get_mapped_entry(entry);
3727 : DCHECK(!probe->IsTheHole(isolate));
3728 : Context* context = elements->context();
3729 : int context_entry = Smi::cast(probe)->value();
3730 : DCHECK(!context->get(context_entry)->IsTheHole(isolate));
3731 265 : context->set(context_entry, *value);
3732 :
3733 : // Redefining attributes of an aliased element destroys fast aliasing.
3734 265 : elements->set_mapped_entry(entry, isolate->heap()->the_hole_value());
3735 : // For elements that are still writable we re-establish slow aliasing.
3736 265 : if ((attributes & READ_ONLY) == 0) {
3737 88 : value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
3738 : }
3739 :
3740 : PropertyDetails details(kData, attributes, 0, PropertyCellType::kNoCell);
3741 : Handle<SeededNumberDictionary> arguments(
3742 : SeededNumberDictionary::cast(elements->arguments()), isolate);
3743 : arguments = SeededNumberDictionary::AddNumberEntry(
3744 265 : arguments, entry, value, details, object);
3745 : // If the attributes were NONE, we would have called set rather than
3746 : // reconfigure.
3747 : DCHECK_NE(NONE, attributes);
3748 265 : object->RequireSlowElements(*arguments);
3749 : elements->set_arguments(*arguments);
3750 : } else {
3751 : Handle<FixedArrayBase> arguments(elements->arguments(), isolate);
3752 : DictionaryElementsAccessor::ReconfigureImpl(
3753 58 : object, arguments, entry - length, value, attributes);
3754 : }
3755 323 : }
3756 : };
3757 :
3758 :
3759 64896 : class FastSloppyArgumentsElementsAccessor
3760 : : public SloppyArgumentsElementsAccessor<
3761 : FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
3762 : ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
3763 : public:
3764 : explicit FastSloppyArgumentsElementsAccessor(const char* name)
3765 : : SloppyArgumentsElementsAccessor<
3766 : FastSloppyArgumentsElementsAccessor,
3767 : FastHoleyObjectElementsAccessor,
3768 59461 : ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
3769 :
3770 : static Handle<Object> ConvertArgumentsStoreResult(
3771 : Isolate* isolate, Handle<SloppyArgumentsElements> paramtere_map,
3772 : Handle<Object> result) {
3773 : DCHECK(!result->IsAliasedArgumentsEntry());
3774 : return result;
3775 : }
3776 :
3777 675 : static Handle<FixedArray> GetArguments(Isolate* isolate,
3778 : FixedArrayBase* store) {
3779 : SloppyArgumentsElements* elements = SloppyArgumentsElements::cast(store);
3780 675 : return Handle<FixedArray>(elements->arguments(), isolate);
3781 : }
3782 :
3783 206 : static Handle<JSObject> SliceImpl(Handle<JSObject> receiver, uint32_t start,
3784 : uint32_t end) {
3785 : Isolate* isolate = receiver->GetIsolate();
3786 206 : uint32_t result_len = end < start ? 0u : end - start;
3787 : Handle<JSArray> result_array = isolate->factory()->NewJSArray(
3788 206 : FAST_HOLEY_ELEMENTS, result_len, result_len);
3789 : DisallowHeapAllocation no_gc;
3790 : FixedArray* elements = FixedArray::cast(result_array->elements());
3791 : FixedArray* parameters = FixedArray::cast(receiver->elements());
3792 : uint32_t insertion_index = 0;
3793 650 : for (uint32_t i = start; i < end; i++) {
3794 : uint32_t entry = GetEntryForIndexImpl(isolate, *receiver, parameters, i,
3795 444 : ALL_PROPERTIES);
3796 444 : if (entry != kMaxUInt32 && HasEntryImpl(isolate, parameters, entry)) {
3797 858 : elements->set(insertion_index, *GetImpl(isolate, parameters, entry));
3798 : } else {
3799 15 : elements->set_the_hole(isolate, insertion_index);
3800 : }
3801 444 : insertion_index++;
3802 : }
3803 206 : return result_array;
3804 : }
3805 :
3806 532 : static Handle<SeededNumberDictionary> NormalizeImpl(
3807 : Handle<JSObject> object, Handle<FixedArrayBase> elements) {
3808 : Handle<FixedArray> arguments =
3809 532 : GetArguments(elements->GetIsolate(), *elements);
3810 532 : return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments);
3811 : }
3812 :
3813 143 : static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
3814 : Handle<FixedArray> arguments =
3815 143 : GetArguments(obj->GetIsolate(), obj->elements());
3816 143 : FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
3817 143 : }
3818 :
3819 177871 : static void AddImpl(Handle<JSObject> object, uint32_t index,
3820 : Handle<Object> value, PropertyAttributes attributes,
3821 : uint32_t new_capacity) {
3822 : DCHECK_EQ(NONE, attributes);
3823 : Isolate* isolate = object->GetIsolate();
3824 : Handle<SloppyArgumentsElements> elements(
3825 : SloppyArgumentsElements::cast(object->elements()), isolate);
3826 : Handle<FixedArray> old_arguments(elements->arguments(), isolate);
3827 355712 : if (old_arguments->IsSeededNumberDictionary() ||
3828 177841 : static_cast<uint32_t>(old_arguments->length()) < new_capacity) {
3829 33260 : GrowCapacityAndConvertImpl(object, new_capacity);
3830 : }
3831 : FixedArray* arguments = elements->arguments();
3832 : // For fast holey objects, the entry equals the index. The code above made
3833 : // sure that there's enough space to store the value. We cannot convert
3834 : // index to entry explicitly since the slot still contains the hole, so the
3835 : // current EntryForIndex would indicate that it is "absent" by returning
3836 : // kMaxUInt32.
3837 : FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
3838 177871 : }
3839 :
3840 103 : static void ReconfigureImpl(Handle<JSObject> object,
3841 : Handle<FixedArrayBase> store, uint32_t entry,
3842 : Handle<Object> value,
3843 : PropertyAttributes attributes) {
3844 : Handle<SeededNumberDictionary> dictionary =
3845 103 : JSObject::NormalizeElements(object);
3846 : SloppyArgumentsElements* elements = SloppyArgumentsElements::cast(*store);
3847 : elements->set_arguments(*dictionary);
3848 : uint32_t length = elements->parameter_map_length();
3849 103 : if (entry >= length) {
3850 0 : entry = dictionary->FindEntry(entry - length) + length;
3851 : }
3852 : SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
3853 103 : value, attributes);
3854 103 : }
3855 :
3856 33260 : static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
3857 : FixedArrayBase* to, ElementsKind from_kind,
3858 : uint32_t to_start, int packed_size,
3859 : int copy_size) {
3860 : DCHECK(!to->IsDictionary());
3861 33260 : if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
3862 : CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
3863 30 : to_start, copy_size);
3864 : } else {
3865 : DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
3866 : CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
3867 33230 : FAST_HOLEY_ELEMENTS, to_start, copy_size);
3868 : }
3869 33260 : }
3870 :
3871 33260 : static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
3872 : uint32_t capacity) {
3873 : Isolate* isolate = object->GetIsolate();
3874 : Handle<SloppyArgumentsElements> elements(
3875 : SloppyArgumentsElements::cast(object->elements()), isolate);
3876 : Handle<FixedArray> old_arguments(FixedArray::cast(elements->arguments()),
3877 : isolate);
3878 : ElementsKind from_kind = object->GetElementsKind();
3879 : // This method should only be called if there's a reason to update the
3880 : // elements.
3881 : DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
3882 : static_cast<uint32_t>(old_arguments->length()) < capacity);
3883 : Handle<FixedArrayBase> arguments =
3884 : ConvertElementsWithCapacity(object, old_arguments, from_kind, capacity);
3885 : Handle<Map> new_map = JSObject::GetElementsTransitionMap(
3886 33260 : object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
3887 33260 : JSObject::MigrateToMap(object, new_map);
3888 : elements->set_arguments(FixedArray::cast(*arguments));
3889 33260 : JSObject::ValidateElements(object);
3890 33260 : }
3891 : };
3892 :
3893 : template <typename Subclass, typename BackingStoreAccessor, typename KindTraits>
3894 64896 : class StringWrapperElementsAccessor
3895 : : public ElementsAccessorBase<Subclass, KindTraits> {
3896 : public:
3897 : explicit StringWrapperElementsAccessor(const char* name)
3898 118922 : : ElementsAccessorBase<Subclass, KindTraits>(name) {
3899 : USE(KindTraits::Kind);
3900 : }
3901 :
3902 : static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
3903 : uint32_t entry) {
3904 30963 : return GetImpl(holder, entry);
3905 : }
3906 :
3907 30963 : static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) {
3908 : Isolate* isolate = holder->GetIsolate();
3909 : Handle<String> string(GetString(*holder), isolate);
3910 30963 : uint32_t length = static_cast<uint32_t>(string->length());
3911 30963 : if (entry < length) {
3912 : return isolate->factory()->LookupSingleCharacterStringFromCode(
3913 53700 : String::Flatten(string)->Get(entry));
3914 : }
3915 : return BackingStoreAccessor::GetImpl(isolate, holder->elements(),
3916 8226 : entry - length);
3917 : }
3918 :
3919 0 : static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase* elements,
3920 : uint32_t entry) {
3921 0 : UNREACHABLE();
3922 : return Handle<Object>();
3923 : }
3924 :
3925 2982 : static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) {
3926 182631 : uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
3927 182631 : if (entry < length) {
3928 : PropertyAttributes attributes =
3929 : static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
3930 983 : return PropertyDetails(kData, attributes, 0, PropertyCellType::kNoCell);
3931 : }
3932 1999 : return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
3933 : }
3934 :
3935 487127 : static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
3936 : FixedArrayBase* backing_store,
3937 : uint32_t index, PropertyFilter filter) {
3938 487127 : uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
3939 487127 : if (index < length) return index;
3940 : uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl(
3941 458041 : isolate, holder, backing_store, index, filter);
3942 458041 : if (backing_store_entry == kMaxUInt32) return kMaxUInt32;
3943 : DCHECK(backing_store_entry < kMaxUInt32 - length);
3944 153545 : return backing_store_entry + length;
3945 : }
3946 :
3947 150100 : static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) {
3948 150100 : uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
3949 150100 : if (entry < length) {
3950 150100 : return; // String contents can't be deleted.
3951 : }
3952 150100 : BackingStoreAccessor::DeleteImpl(holder, entry - length);
3953 : }
3954 :
3955 239 : static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) {
3956 239 : uint32_t length = static_cast<uint32_t>(GetString(*holder)->length());
3957 239 : if (entry < length) {
3958 239 : return; // String contents are read-only.
3959 : }
3960 239 : BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value);
3961 : }
3962 :
3963 140041 : static void AddImpl(Handle<JSObject> object, uint32_t index,
3964 : Handle<Object> value, PropertyAttributes attributes,
3965 : uint32_t new_capacity) {
3966 : DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length()));
3967 : // Explicitly grow fast backing stores if needed. Dictionaries know how to
3968 : // extend their capacity themselves.
3969 280067 : if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
3970 : (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
3971 : BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
3972 : new_capacity)) {
3973 452 : GrowCapacityAndConvertImpl(object, new_capacity);
3974 : }
3975 150461 : BackingStoreAccessor::AddImpl(object, index, value, attributes,
3976 : new_capacity);
3977 140041 : }
3978 :
3979 15 : static void ReconfigureImpl(Handle<JSObject> object,
3980 : Handle<FixedArrayBase> store, uint32_t entry,
3981 : Handle<Object> value,
3982 : PropertyAttributes attributes) {
3983 15 : uint32_t length = static_cast<uint32_t>(GetString(*object)->length());
3984 15 : if (entry < length) {
3985 15 : return; // String contents can't be reconfigured.
3986 : }
3987 15 : BackingStoreAccessor::ReconfigureImpl(object, store, entry - length, value,
3988 15 : attributes);
3989 : }
3990 :
3991 0 : static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
3992 : KeyAccumulator* accumulator,
3993 : AddKeyConversion convert) {
3994 : Isolate* isolate = receiver->GetIsolate();
3995 : Handle<String> string(GetString(*receiver), isolate);
3996 0 : string = String::Flatten(string);
3997 0 : uint32_t length = static_cast<uint32_t>(string->length());
3998 0 : for (uint32_t i = 0; i < length; i++) {
3999 0 : accumulator->AddKey(
4000 : isolate->factory()->LookupSingleCharacterStringFromCode(
4001 0 : string->Get(i)),
4002 0 : convert);
4003 : }
4004 0 : BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
4005 : convert);
4006 0 : }
4007 :
4008 3804 : static void CollectElementIndicesImpl(Handle<JSObject> object,
4009 : Handle<FixedArrayBase> backing_store,
4010 3804 : KeyAccumulator* keys) {
4011 3804 : uint32_t length = GetString(*object)->length();
4012 : Factory* factory = keys->isolate()->factory();
4013 18532 : for (uint32_t i = 0; i < length; i++) {
4014 14728 : keys->AddKey(factory->NewNumberFromUint(i));
4015 : }
4016 3804 : BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store,
4017 : keys);
4018 3804 : }
4019 :
4020 452 : static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
4021 : uint32_t capacity) {
4022 : Handle<FixedArrayBase> old_elements(object->elements());
4023 : ElementsKind from_kind = object->GetElementsKind();
4024 : // This method should only be called if there's a reason to update the
4025 : // elements.
4026 : DCHECK(from_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
4027 : static_cast<uint32_t>(old_elements->length()) < capacity);
4028 452 : Subclass::BasicGrowCapacityAndConvertImpl(object, old_elements, from_kind,
4029 : FAST_STRING_WRAPPER_ELEMENTS,
4030 : capacity);
4031 452 : }
4032 :
4033 452 : static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
4034 : FixedArrayBase* to, ElementsKind from_kind,
4035 : uint32_t to_start, int packed_size,
4036 : int copy_size) {
4037 : DCHECK(!to->IsDictionary());
4038 452 : if (from_kind == SLOW_STRING_WRAPPER_ELEMENTS) {
4039 15 : CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
4040 : to_start, copy_size);
4041 : } else {
4042 : DCHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, from_kind);
4043 437 : CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
4044 : FAST_HOLEY_ELEMENTS, to_start, copy_size);
4045 : }
4046 452 : }
4047 :
4048 0 : static uint32_t NumberOfElementsImpl(JSObject* object,
4049 : FixedArrayBase* backing_store) {
4050 0 : uint32_t length = GetString(object)->length();
4051 : return length +
4052 0 : BackingStoreAccessor::NumberOfElementsImpl(object, backing_store);
4053 : }
4054 :
4055 : private:
4056 : static String* GetString(JSObject* holder) {
4057 : DCHECK(holder->IsJSValue());
4058 : JSValue* js_value = JSValue::cast(holder);
4059 : DCHECK(js_value->value()->IsString());
4060 : return String::cast(js_value->value());
4061 : }
4062 : };
4063 :
4064 64896 : class FastStringWrapperElementsAccessor
4065 : : public StringWrapperElementsAccessor<
4066 : FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
4067 : ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
4068 : public:
4069 : explicit FastStringWrapperElementsAccessor(const char* name)
4070 : : StringWrapperElementsAccessor<
4071 : FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
4072 59461 : ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
4073 :
4074 : static Handle<SeededNumberDictionary> NormalizeImpl(
4075 : Handle<JSObject> object, Handle<FixedArrayBase> elements) {
4076 212 : return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements);
4077 : }
4078 : };
4079 :
4080 64896 : class SlowStringWrapperElementsAccessor
4081 : : public StringWrapperElementsAccessor<
4082 : SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
4083 : ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
4084 : public:
4085 : explicit SlowStringWrapperElementsAccessor(const char* name)
4086 : : StringWrapperElementsAccessor<
4087 : SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
4088 59461 : ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {}
4089 :
4090 : static bool HasAccessorsImpl(JSObject* holder,
4091 : FixedArrayBase* backing_store) {
4092 0 : return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
4093 : }
4094 : };
4095 :
4096 : } // namespace
4097 :
4098 :
4099 0 : void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
4100 : bool allow_appending) {
4101 : DisallowHeapAllocation no_allocation;
4102 : Object* raw_length = NULL;
4103 : const char* elements_type = "array";
4104 0 : if (obj->IsJSArray()) {
4105 : JSArray* array = JSArray::cast(*obj);
4106 : raw_length = array->length();
4107 : } else {
4108 : raw_length = Smi::FromInt(obj->elements()->length());
4109 : elements_type = "object";
4110 : }
4111 :
4112 0 : if (raw_length->IsNumber()) {
4113 : double n = raw_length->Number();
4114 0 : if (FastI2D(FastD2UI(n)) == n) {
4115 0 : int32_t int32_length = DoubleToInt32(n);
4116 0 : uint32_t compare_length = static_cast<uint32_t>(int32_length);
4117 0 : if (allow_appending) compare_length++;
4118 0 : if (index >= compare_length) {
4119 : PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
4120 : elements_type, op, elements_type, static_cast<int>(int32_length),
4121 0 : static_cast<int>(index));
4122 0 : TraceTopFrame(obj->GetIsolate());
4123 0 : PrintF("]\n");
4124 : }
4125 : } else {
4126 0 : PrintF("[%s elements length not integer value in ", elements_type);
4127 0 : TraceTopFrame(obj->GetIsolate());
4128 0 : PrintF("]\n");
4129 : }
4130 : } else {
4131 0 : PrintF("[%s elements length not a number in ", elements_type);
4132 0 : TraceTopFrame(obj->GetIsolate());
4133 0 : PrintF("]\n");
4134 : }
4135 0 : }
4136 :
4137 :
4138 1516326 : MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
4139 26493729 : Arguments* args) {
4140 1516326 : if (args->length() == 0) {
4141 : // Optimize the case where there are no parameters passed.
4142 170063 : JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
4143 : return array;
4144 :
4145 1529552 : } else if (args->length() == 1 && args->at(0)->IsNumber()) {
4146 : uint32_t length;
4147 182346 : if (!args->at(0)->ToArrayLength(&length)) {
4148 164 : return ThrowArrayLengthRangeError(array->GetIsolate());
4149 : }
4150 :
4151 : // Optimize the case where there is one argument and the argument is a small
4152 : // smi.
4153 182182 : if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
4154 : ElementsKind elements_kind = array->GetElementsKind();
4155 172391 : JSArray::Initialize(array, length, length);
4156 :
4157 172391 : if (!IsFastHoleyElementsKind(elements_kind)) {
4158 : elements_kind = GetHoleyElementsKind(elements_kind);
4159 297 : JSObject::TransitionElementsKind(array, elements_kind);
4160 : }
4161 9791 : } else if (length == 0) {
4162 5824 : JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
4163 : } else {
4164 : // Take the argument as the length.
4165 3967 : JSArray::Initialize(array, 0);
4166 3967 : JSArray::SetLength(array, length);
4167 : }
4168 : return array;
4169 : }
4170 :
4171 : Factory* factory = array->GetIsolate()->factory();
4172 :
4173 : // Set length and elements on the array.
4174 : int number_of_elements = args->length();
4175 : JSObject::EnsureCanContainElements(
4176 2327834 : array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
4177 :
4178 : // Allocate an appropriately typed elements array.
4179 : ElementsKind elements_kind = array->GetElementsKind();
4180 : Handle<FixedArrayBase> elms;
4181 1163917 : if (IsFastDoubleElementsKind(elements_kind)) {
4182 : elms = Handle<FixedArrayBase>::cast(
4183 700130 : factory->NewFixedDoubleArray(number_of_elements));
4184 : } else {
4185 : elms = Handle<FixedArrayBase>::cast(
4186 463787 : factory->NewFixedArrayWithHoles(number_of_elements));
4187 : }
4188 :
4189 : // Fill in the content
4190 1163917 : switch (elements_kind) {
4191 : case FAST_HOLEY_SMI_ELEMENTS:
4192 : case FAST_SMI_ELEMENTS: {
4193 : Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
4194 17239568 : for (int entry = 0; entry < number_of_elements; entry++) {
4195 34479136 : smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
4196 : }
4197 : break;
4198 : }
4199 : case FAST_HOLEY_ELEMENTS:
4200 : case FAST_ELEMENTS: {
4201 : DisallowHeapAllocation no_gc;
4202 1515 : WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
4203 : Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
4204 5174963 : for (int entry = 0; entry < number_of_elements; entry++) {
4205 10346896 : object_elms->set(entry, (*args)[entry], mode);
4206 : }
4207 : break;
4208 : }
4209 : case FAST_HOLEY_DOUBLE_ELEMENTS:
4210 : case FAST_DOUBLE_ELEMENTS: {
4211 : Handle<FixedDoubleArray> double_elms =
4212 : Handle<FixedDoubleArray>::cast(elms);
4213 1400470 : for (int entry = 0; entry < number_of_elements; entry++) {
4214 1400470 : double_elms->set(entry, (*args)[entry]->Number());
4215 : }
4216 : break;
4217 : }
4218 : default:
4219 0 : UNREACHABLE();
4220 : break;
4221 : }
4222 :
4223 1163917 : array->set_elements(*elms);
4224 : array->set_length(Smi::FromInt(number_of_elements));
4225 : return array;
4226 : }
4227 :
4228 :
4229 59461 : void ElementsAccessor::InitializeOncePerProcess() {
4230 : static ElementsAccessor* accessor_array[] = {
4231 : #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
4232 : ELEMENTS_LIST(ACCESSOR_ARRAY)
4233 : #undef ACCESSOR_ARRAY
4234 1248681 : };
4235 :
4236 : STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
4237 : kElementsKindCount);
4238 :
4239 59461 : elements_accessors_ = accessor_array;
4240 59461 : }
4241 :
4242 :
4243 32496 : void ElementsAccessor::TearDown() {
4244 64992 : if (elements_accessors_ == NULL) return;
4245 : #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
4246 32448 : ELEMENTS_LIST(ACCESSOR_DELETE)
4247 : #undef ACCESSOR_DELETE
4248 32448 : elements_accessors_ = NULL;
4249 : }
4250 :
4251 2213675 : Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
4252 : uint32_t concat_size,
4253 : uint32_t result_len) {
4254 : ElementsKind result_elements_kind = GetInitialFastElementsKind();
4255 : bool has_raw_doubles = false;
4256 : {
4257 : DisallowHeapAllocation no_gc;
4258 : bool is_holey = false;
4259 1328066 : for (uint32_t i = 0; i < concat_size; i++) {
4260 1771218 : Object* arg = (*args)[i];
4261 : ElementsKind arg_kind = JSArray::cast(arg)->GetElementsKind();
4262 1771058 : has_raw_doubles = has_raw_doubles || IsFastDoubleElementsKind(arg_kind);
4263 1346145 : is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
4264 : result_elements_kind =
4265 : GetMoreGeneralElementsKind(result_elements_kind, arg_kind);
4266 : }
4267 442457 : if (is_holey) {
4268 : result_elements_kind = GetHoleyElementsKind(result_elements_kind);
4269 : }
4270 : }
4271 :
4272 : // If a double array is concatted into a fast elements array, the fast
4273 : // elements array needs to be initialized to contain proper holes, since
4274 : // boxing doubles may cause incremental marking.
4275 : bool requires_double_boxing =
4276 442704 : has_raw_doubles && !IsFastDoubleElementsKind(result_elements_kind);
4277 : ArrayStorageAllocationMode mode = requires_double_boxing
4278 : ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
4279 442457 : : DONT_INITIALIZE_ARRAY_ELEMENTS;
4280 : Handle<JSArray> result_array = isolate->factory()->NewJSArray(
4281 442457 : result_elements_kind, result_len, result_len, mode);
4282 442457 : if (result_len == 0) return result_array;
4283 :
4284 : uint32_t insertion_index = 0;
4285 : Handle<FixedArrayBase> storage(result_array->elements(), isolate);
4286 : ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind);
4287 1328066 : for (uint32_t i = 0; i < concat_size; i++) {
4288 : // It is crucial to keep |array| in a raw pointer form to avoid
4289 : // performance degradation.
4290 1771218 : JSArray* array = JSArray::cast((*args)[i]);
4291 885609 : uint32_t len = 0;
4292 : array->length()->ToArrayLength(&len);
4293 887525 : if (len == 0) continue;
4294 : ElementsKind from_kind = array->GetElementsKind();
4295 883693 : accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len);
4296 883693 : insertion_index += len;
4297 : }
4298 :
4299 : DCHECK_EQ(insertion_index, result_len);
4300 442457 : return result_array;
4301 : }
4302 :
4303 : ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
4304 : } // namespace internal
4305 : } // namespace v8
|