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