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