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/messages.h"
11 #include "src/objects-inl.h"
12 #include "src/utils.h"
13
14 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
15 // several abstract ElementsAccessor classes are used to allow sharing
16 // common code.
17 //
18 // Inheritance hierarchy:
19 // - ElementsAccessorBase (abstract)
20 // - FastElementsAccessor (abstract)
21 // - FastSmiOrObjectElementsAccessor
22 // - FastPackedSmiElementsAccessor
23 // - FastHoleySmiElementsAccessor
24 // - FastPackedObjectElementsAccessor
25 // - FastHoleyObjectElementsAccessor
26 // - FastDoubleElementsAccessor
27 // - FastPackedDoubleElementsAccessor
28 // - FastHoleyDoubleElementsAccessor
29 // - TypedElementsAccessor: template, with instantiations:
30 // - FixedUint8ElementsAccessor
31 // - FixedInt8ElementsAccessor
32 // - FixedUint16ElementsAccessor
33 // - FixedInt16ElementsAccessor
34 // - FixedUint32ElementsAccessor
35 // - FixedInt32ElementsAccessor
36 // - FixedFloat32ElementsAccessor
37 // - FixedFloat64ElementsAccessor
38 // - FixedUint8ClampedElementsAccessor
39 // - DictionaryElementsAccessor
40 // - SloppyArgumentsElementsAccessor
41 // - FastSloppyArgumentsElementsAccessor
42 // - SlowSloppyArgumentsElementsAccessor
43
44
45 namespace v8 {
46 namespace internal {
47
48
49 namespace {
50
51
52 static const int kPackedSizeNotKnown = -1;
53
54 enum Where { AT_START, AT_END };
55
56
57 // First argument in list is the accessor class, the second argument is the
58 // accessor ElementsKind, and the third is the backing store class. Use the
59 // fast element handler for smi-only arrays. The implementation is currently
60 // identical. Note that the order must match that of the ElementsKind enum for
61 // the |accessor_array[]| below to work.
62 #define ELEMENTS_LIST(V) \
63 V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \
64 V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray) \
65 V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \
66 V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \
67 V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
68 V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \
69 FixedDoubleArray) \
70 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary) \
71 V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS, \
72 FixedArray) \
73 V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \
74 FixedArray) \
75 V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \
76 V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \
77 V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \
78 V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array) \
79 V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array) \
80 V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array) \
81 V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array) \
82 V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array) \
83 V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \
84 FixedUint8ClampedArray)
85
86
87 template<ElementsKind Kind> class ElementsKindTraits {
88 public:
89 typedef FixedArrayBase BackingStore;
90 };
91
92 #define ELEMENTS_TRAITS(Class, KindParam, Store) \
93 template<> class ElementsKindTraits<KindParam> { \
94 public: /* NOLINT */ \
95 static const ElementsKind Kind = KindParam; \
96 typedef Store BackingStore; \
97 };
ELEMENTS_LIST(ELEMENTS_TRAITS)98 ELEMENTS_LIST(ELEMENTS_TRAITS)
99 #undef ELEMENTS_TRAITS
100
101
102 MUST_USE_RESULT
103 MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
104 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
105 Object);
106 }
107
108
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)109 void CopyObjectToObjectElements(FixedArrayBase* from_base,
110 ElementsKind from_kind, uint32_t from_start,
111 FixedArrayBase* to_base, ElementsKind to_kind,
112 uint32_t to_start, int raw_copy_size) {
113 DCHECK(to_base->map() !=
114 from_base->GetIsolate()->heap()->fixed_cow_array_map());
115 DisallowHeapAllocation no_allocation;
116 int copy_size = raw_copy_size;
117 if (raw_copy_size < 0) {
118 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
119 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
120 copy_size = Min(from_base->length() - from_start,
121 to_base->length() - to_start);
122 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
123 int start = to_start + copy_size;
124 int length = to_base->length() - start;
125 if (length > 0) {
126 Heap* heap = from_base->GetHeap();
127 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
128 heap->the_hole_value(), length);
129 }
130 }
131 }
132 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
133 (copy_size + static_cast<int>(from_start)) <= from_base->length());
134 if (copy_size == 0) return;
135 FixedArray* from = FixedArray::cast(from_base);
136 FixedArray* to = FixedArray::cast(to_base);
137 DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
138 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
139
140 WriteBarrierMode write_barrier_mode =
141 (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
142 ? UPDATE_WRITE_BARRIER
143 : SKIP_WRITE_BARRIER;
144 for (int i = 0; i < copy_size; i++) {
145 Object* value = from->get(from_start + i);
146 to->set(to_start + i, value, write_barrier_mode);
147 }
148 }
149
150
CopyDictionaryToObjectElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)151 static void CopyDictionaryToObjectElements(
152 FixedArrayBase* from_base, uint32_t from_start, FixedArrayBase* to_base,
153 ElementsKind to_kind, uint32_t to_start, int raw_copy_size) {
154 DisallowHeapAllocation no_allocation;
155 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
156 int copy_size = raw_copy_size;
157 if (raw_copy_size < 0) {
158 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
159 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
160 copy_size = from->max_number_key() + 1 - from_start;
161 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
162 int start = to_start + copy_size;
163 int length = to_base->length() - start;
164 if (length > 0) {
165 Heap* heap = from->GetHeap();
166 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
167 heap->the_hole_value(), length);
168 }
169 }
170 }
171 DCHECK(to_base != from_base);
172 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
173 if (copy_size == 0) return;
174 FixedArray* to = FixedArray::cast(to_base);
175 uint32_t to_length = to->length();
176 if (to_start + copy_size > to_length) {
177 copy_size = to_length - to_start;
178 }
179 WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
180 ? UPDATE_WRITE_BARRIER
181 : SKIP_WRITE_BARRIER;
182 for (int i = 0; i < copy_size; i++) {
183 int entry = from->FindEntry(i + from_start);
184 if (entry != SeededNumberDictionary::kNotFound) {
185 Object* value = from->ValueAt(entry);
186 DCHECK(!value->IsTheHole());
187 to->set(i + to_start, value, write_barrier_mode);
188 } else {
189 to->set_the_hole(i + to_start);
190 }
191 }
192 }
193
194
195 // NOTE: this method violates the handlified function signature convention:
196 // raw pointer parameters in the function that allocates.
197 // See ElementsAccessorBase::CopyElements() for details.
CopyDoubleToObjectElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)198 static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
199 uint32_t from_start,
200 FixedArrayBase* to_base,
201 uint32_t to_start, int raw_copy_size) {
202 int copy_size = raw_copy_size;
203 if (raw_copy_size < 0) {
204 DisallowHeapAllocation no_allocation;
205 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
206 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
207 copy_size = Min(from_base->length() - from_start,
208 to_base->length() - to_start);
209 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
210 // Also initialize the area that will be copied over since HeapNumber
211 // allocation below can cause an incremental marking step, requiring all
212 // existing heap objects to be propertly initialized.
213 int start = to_start;
214 int length = to_base->length() - start;
215 if (length > 0) {
216 Heap* heap = from_base->GetHeap();
217 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
218 heap->the_hole_value(), length);
219 }
220 }
221 }
222
223 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
224 (copy_size + static_cast<int>(from_start)) <= from_base->length());
225 if (copy_size == 0) return;
226
227 // From here on, the code below could actually allocate. Therefore the raw
228 // values are wrapped into handles.
229 Isolate* isolate = from_base->GetIsolate();
230 Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
231 Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
232
233 // create an outer loop to not waste too much time on creating HandleScopes
234 // on the other hand we might overflow a single handle scope depending on
235 // the copy_size
236 int offset = 0;
237 while (offset < copy_size) {
238 HandleScope scope(isolate);
239 offset += 100;
240 for (int i = offset - 100; i < offset && i < copy_size; ++i) {
241 Handle<Object> value = FixedDoubleArray::get(from, i + from_start);
242 to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
243 }
244 }
245 }
246
247
CopyDoubleToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)248 static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
249 uint32_t from_start,
250 FixedArrayBase* to_base,
251 uint32_t to_start, int raw_copy_size) {
252 DisallowHeapAllocation no_allocation;
253 int copy_size = raw_copy_size;
254 if (raw_copy_size < 0) {
255 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
256 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
257 copy_size = Min(from_base->length() - from_start,
258 to_base->length() - to_start);
259 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
260 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
261 FixedDoubleArray::cast(to_base)->set_the_hole(i);
262 }
263 }
264 }
265 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
266 (copy_size + static_cast<int>(from_start)) <= from_base->length());
267 if (copy_size == 0) return;
268 FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
269 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
270 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
271 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
272 to_address += kDoubleSize * to_start;
273 from_address += kDoubleSize * from_start;
274 int words_per_double = (kDoubleSize / kPointerSize);
275 CopyWords(reinterpret_cast<Object**>(to_address),
276 reinterpret_cast<Object**>(from_address),
277 static_cast<size_t>(words_per_double * copy_size));
278 }
279
280
CopySmiToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)281 static void CopySmiToDoubleElements(FixedArrayBase* from_base,
282 uint32_t from_start,
283 FixedArrayBase* to_base, uint32_t to_start,
284 int raw_copy_size) {
285 DisallowHeapAllocation no_allocation;
286 int copy_size = raw_copy_size;
287 if (raw_copy_size < 0) {
288 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
289 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
290 copy_size = from_base->length() - from_start;
291 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
292 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
293 FixedDoubleArray::cast(to_base)->set_the_hole(i);
294 }
295 }
296 }
297 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
298 (copy_size + static_cast<int>(from_start)) <= from_base->length());
299 if (copy_size == 0) return;
300 FixedArray* from = FixedArray::cast(from_base);
301 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
302 Object* the_hole = from->GetHeap()->the_hole_value();
303 for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
304 from_start < from_end; from_start++, to_start++) {
305 Object* hole_or_smi = from->get(from_start);
306 if (hole_or_smi == the_hole) {
307 to->set_the_hole(to_start);
308 } else {
309 to->set(to_start, Smi::cast(hole_or_smi)->value());
310 }
311 }
312 }
313
314
CopyPackedSmiToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int packed_size,int raw_copy_size)315 static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
316 uint32_t from_start,
317 FixedArrayBase* to_base,
318 uint32_t to_start, int packed_size,
319 int raw_copy_size) {
320 DisallowHeapAllocation no_allocation;
321 int copy_size = raw_copy_size;
322 uint32_t to_end;
323 if (raw_copy_size < 0) {
324 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
325 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
326 copy_size = packed_size - from_start;
327 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
328 to_end = to_base->length();
329 for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
330 FixedDoubleArray::cast(to_base)->set_the_hole(i);
331 }
332 } else {
333 to_end = to_start + static_cast<uint32_t>(copy_size);
334 }
335 } else {
336 to_end = to_start + static_cast<uint32_t>(copy_size);
337 }
338 DCHECK(static_cast<int>(to_end) <= to_base->length());
339 DCHECK(packed_size >= 0 && packed_size <= copy_size);
340 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
341 (copy_size + static_cast<int>(from_start)) <= from_base->length());
342 if (copy_size == 0) return;
343 FixedArray* from = FixedArray::cast(from_base);
344 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
345 for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
346 from_start < from_end; from_start++, to_start++) {
347 Object* smi = from->get(from_start);
348 DCHECK(!smi->IsTheHole());
349 to->set(to_start, Smi::cast(smi)->value());
350 }
351 }
352
353
CopyObjectToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)354 static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
355 uint32_t from_start,
356 FixedArrayBase* to_base,
357 uint32_t to_start, int raw_copy_size) {
358 DisallowHeapAllocation no_allocation;
359 int copy_size = raw_copy_size;
360 if (raw_copy_size < 0) {
361 DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
362 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
363 copy_size = from_base->length() - from_start;
364 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
365 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
366 FixedDoubleArray::cast(to_base)->set_the_hole(i);
367 }
368 }
369 }
370 DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
371 (copy_size + static_cast<int>(from_start)) <= from_base->length());
372 if (copy_size == 0) return;
373 FixedArray* from = FixedArray::cast(from_base);
374 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
375 Object* the_hole = from->GetHeap()->the_hole_value();
376 for (uint32_t from_end = from_start + copy_size;
377 from_start < from_end; from_start++, to_start++) {
378 Object* hole_or_object = from->get(from_start);
379 if (hole_or_object == the_hole) {
380 to->set_the_hole(to_start);
381 } else {
382 to->set(to_start, hole_or_object->Number());
383 }
384 }
385 }
386
387
CopyDictionaryToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)388 static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
389 uint32_t from_start,
390 FixedArrayBase* to_base,
391 uint32_t to_start,
392 int raw_copy_size) {
393 DisallowHeapAllocation no_allocation;
394 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
395 int copy_size = raw_copy_size;
396 if (copy_size < 0) {
397 DCHECK(copy_size == ElementsAccessor::kCopyToEnd ||
398 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
399 copy_size = from->max_number_key() + 1 - from_start;
400 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
401 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
402 FixedDoubleArray::cast(to_base)->set_the_hole(i);
403 }
404 }
405 }
406 if (copy_size == 0) return;
407 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
408 uint32_t to_length = to->length();
409 if (to_start + copy_size > to_length) {
410 copy_size = to_length - to_start;
411 }
412 for (int i = 0; i < copy_size; i++) {
413 int entry = from->FindEntry(i + from_start);
414 if (entry != SeededNumberDictionary::kNotFound) {
415 to->set(i + to_start, from->ValueAt(entry)->Number());
416 } else {
417 to->set_the_hole(i + to_start);
418 }
419 }
420 }
421
422
TraceTopFrame(Isolate * isolate)423 static void TraceTopFrame(Isolate* isolate) {
424 StackFrameIterator it(isolate);
425 if (it.done()) {
426 PrintF("unknown location (no JavaScript frames present)");
427 return;
428 }
429 StackFrame* raw_frame = it.frame();
430 if (raw_frame->is_internal()) {
431 Code* apply_builtin =
432 isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
433 if (raw_frame->unchecked_code() == apply_builtin) {
434 PrintF("apply from ");
435 it.Advance();
436 raw_frame = it.frame();
437 }
438 }
439 JavaScriptFrame::PrintTop(isolate, stdout, false, true);
440 }
441
442
443 // Base class for element handler implementations. Contains the
444 // the common logic for objects with different ElementsKinds.
445 // Subclasses must specialize method for which the element
446 // implementation differs from the base class implementation.
447 //
448 // This class is intended to be used in the following way:
449 //
450 // class SomeElementsAccessor :
451 // public ElementsAccessorBase<SomeElementsAccessor,
452 // BackingStoreClass> {
453 // ...
454 // }
455 //
456 // This is an example of the Curiously Recurring Template Pattern (see
457 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
458 // CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
459 // specialization of SomeElementsAccessor methods).
460 template <typename ElementsAccessorSubclass,
461 typename ElementsTraitsParam>
462 class ElementsAccessorBase : public ElementsAccessor {
463 public:
ElementsAccessorBase(const char * name)464 explicit ElementsAccessorBase(const char* name)
465 : ElementsAccessor(name) { }
466
467 typedef ElementsTraitsParam ElementsTraits;
468 typedef typename ElementsTraitsParam::BackingStore BackingStore;
469
kind()470 static ElementsKind kind() { return ElementsTraits::Kind; }
471
ValidateContents(Handle<JSObject> holder,int length)472 static void ValidateContents(Handle<JSObject> holder, int length) {
473 }
474
ValidateImpl(Handle<JSObject> holder)475 static void ValidateImpl(Handle<JSObject> holder) {
476 Handle<FixedArrayBase> fixed_array_base(holder->elements());
477 if (!fixed_array_base->IsHeapObject()) return;
478 // Arrays that have been shifted in place can't be verified.
479 if (fixed_array_base->IsFiller()) return;
480 int length = 0;
481 if (holder->IsJSArray()) {
482 Object* length_obj = Handle<JSArray>::cast(holder)->length();
483 if (length_obj->IsSmi()) {
484 length = Smi::cast(length_obj)->value();
485 }
486 } else {
487 length = fixed_array_base->length();
488 }
489 ElementsAccessorSubclass::ValidateContents(holder, length);
490 }
491
Validate(Handle<JSObject> holder)492 void Validate(Handle<JSObject> holder) final {
493 DisallowHeapAllocation no_gc;
494 ElementsAccessorSubclass::ValidateImpl(holder);
495 }
496
IsPacked(Handle<JSObject> holder,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)497 bool IsPacked(Handle<JSObject> holder, Handle<FixedArrayBase> backing_store,
498 uint32_t start, uint32_t end) final {
499 return ElementsAccessorSubclass::IsPackedImpl(holder, backing_store, start,
500 end);
501 }
502
IsPackedImpl(Handle<JSObject> holder,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)503 static bool IsPackedImpl(Handle<JSObject> holder,
504 Handle<FixedArrayBase> backing_store, uint32_t start,
505 uint32_t end) {
506 if (IsFastPackedElementsKind(kind())) return true;
507 for (uint32_t i = start; i < end; i++) {
508 if (!ElementsAccessorSubclass::HasElementImpl(holder, i, backing_store,
509 ALL_PROPERTIES)) {
510 return false;
511 }
512 }
513 return true;
514 }
515
TryTransitionResultArrayToPacked(Handle<JSArray> array)516 static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
517 if (!IsHoleyElementsKind(kind())) return;
518 int length = Smi::cast(array->length())->value();
519 Handle<FixedArrayBase> backing_store(array->elements());
520 if (!ElementsAccessorSubclass::IsPackedImpl(array, backing_store, 0,
521 length)) {
522 return;
523 }
524 ElementsKind packed_kind = GetPackedElementsKind(kind());
525 Handle<Map> new_map =
526 JSObject::GetElementsTransitionMap(array, packed_kind);
527 JSObject::MigrateToMap(array, new_map);
528 if (FLAG_trace_elements_transitions) {
529 JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
530 packed_kind, backing_store);
531 }
532 }
533
HasElement(Handle<JSObject> holder,uint32_t index,Handle<FixedArrayBase> backing_store,PropertyFilter filter)534 bool HasElement(Handle<JSObject> holder, uint32_t index,
535 Handle<FixedArrayBase> backing_store,
536 PropertyFilter filter) final {
537 return ElementsAccessorSubclass::HasElementImpl(holder, index,
538 backing_store, filter);
539 }
540
HasElementImpl(Handle<JSObject> holder,uint32_t index,Handle<FixedArrayBase> backing_store,PropertyFilter filter)541 static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
542 Handle<FixedArrayBase> backing_store,
543 PropertyFilter filter) {
544 return ElementsAccessorSubclass::GetEntryForIndexImpl(
545 *holder, *backing_store, index, filter) != kMaxUInt32;
546 }
547
Get(Handle<FixedArrayBase> backing_store,uint32_t entry)548 Handle<Object> Get(Handle<FixedArrayBase> backing_store,
549 uint32_t entry) final {
550 return ElementsAccessorSubclass::GetImpl(backing_store, entry);
551 }
552
GetImpl(Handle<FixedArrayBase> backing_store,uint32_t entry)553 static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
554 uint32_t entry) {
555 uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
556 return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
557 }
558
Set(FixedArrayBase * backing_store,uint32_t entry,Object * value)559 void Set(FixedArrayBase* backing_store, uint32_t entry, Object* value) final {
560 ElementsAccessorSubclass::SetImpl(backing_store, entry, value);
561 }
562
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)563 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
564 Object* value) {
565 UNREACHABLE();
566 }
567
568
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)569 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
570 Object* value, WriteBarrierMode mode) {
571 UNREACHABLE();
572 }
573
Reconfigure(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)574 void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
575 uint32_t entry, Handle<Object> value,
576 PropertyAttributes attributes) final {
577 ElementsAccessorSubclass::ReconfigureImpl(object, store, entry, value,
578 attributes);
579 }
580
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)581 static void ReconfigureImpl(Handle<JSObject> object,
582 Handle<FixedArrayBase> store, uint32_t entry,
583 Handle<Object> value,
584 PropertyAttributes attributes) {
585 UNREACHABLE();
586 }
587
Add(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)588 void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
589 PropertyAttributes attributes, uint32_t new_capacity) final {
590 ElementsAccessorSubclass::AddImpl(object, index, value, attributes,
591 new_capacity);
592 }
593
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)594 static void AddImpl(Handle<JSObject> object, uint32_t index,
595 Handle<Object> value, PropertyAttributes attributes,
596 uint32_t new_capacity) {
597 UNREACHABLE();
598 }
599
Push(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t push_size)600 uint32_t Push(Handle<JSArray> receiver, Handle<FixedArrayBase> backing_store,
601 Arguments* args, uint32_t push_size) final {
602 return ElementsAccessorSubclass::PushImpl(receiver, backing_store, args,
603 push_size);
604 }
605
PushImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> elms_obj,Arguments * args,uint32_t push_sized)606 static uint32_t PushImpl(Handle<JSArray> receiver,
607 Handle<FixedArrayBase> elms_obj, Arguments* args,
608 uint32_t push_sized) {
609 UNREACHABLE();
610 return 0;
611 }
612
Unshift(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t unshift_size)613 uint32_t Unshift(Handle<JSArray> receiver,
614 Handle<FixedArrayBase> backing_store, Arguments* args,
615 uint32_t unshift_size) final {
616 return ElementsAccessorSubclass::UnshiftImpl(receiver, backing_store, args,
617 unshift_size);
618 }
619
UnshiftImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> elms_obj,Arguments * args,uint32_t unshift_size)620 static uint32_t UnshiftImpl(Handle<JSArray> receiver,
621 Handle<FixedArrayBase> elms_obj, Arguments* args,
622 uint32_t unshift_size) {
623 UNREACHABLE();
624 return 0;
625 }
626
Slice(Handle<JSObject> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)627 Handle<JSArray> Slice(Handle<JSObject> receiver,
628 Handle<FixedArrayBase> backing_store, uint32_t start,
629 uint32_t end) final {
630 return ElementsAccessorSubclass::SliceImpl(receiver, backing_store, start,
631 end);
632 }
633
SliceImpl(Handle<JSObject> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)634 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
635 Handle<FixedArrayBase> backing_store,
636 uint32_t start, uint32_t end) {
637 UNREACHABLE();
638 return Handle<JSArray>();
639 }
640
Splice(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)641 Handle<JSArray> Splice(Handle<JSArray> receiver,
642 Handle<FixedArrayBase> backing_store, uint32_t start,
643 uint32_t delete_count, Arguments* args,
644 uint32_t add_count) final {
645 return ElementsAccessorSubclass::SpliceImpl(receiver, backing_store, start,
646 delete_count, args, add_count);
647 }
648
SpliceImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)649 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
650 Handle<FixedArrayBase> backing_store,
651 uint32_t start, uint32_t delete_count,
652 Arguments* args, uint32_t add_count) {
653 UNREACHABLE();
654 return Handle<JSArray>();
655 }
656
Pop(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)657 Handle<Object> Pop(Handle<JSArray> receiver,
658 Handle<FixedArrayBase> backing_store) final {
659 return ElementsAccessorSubclass::PopImpl(receiver, backing_store);
660 }
661
PopImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)662 static Handle<Object> PopImpl(Handle<JSArray> receiver,
663 Handle<FixedArrayBase> backing_store) {
664 UNREACHABLE();
665 return Handle<Object>();
666 }
667
Shift(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)668 Handle<Object> Shift(Handle<JSArray> receiver,
669 Handle<FixedArrayBase> backing_store) final {
670 return ElementsAccessorSubclass::ShiftImpl(receiver, backing_store);
671 }
672
ShiftImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)673 static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
674 Handle<FixedArrayBase> backing_store) {
675 UNREACHABLE();
676 return Handle<Object>();
677 }
678
SetLength(Handle<JSArray> array,uint32_t length)679 void SetLength(Handle<JSArray> array, uint32_t length) final {
680 ElementsAccessorSubclass::SetLengthImpl(array->GetIsolate(), array, length,
681 handle(array->elements()));
682 }
683
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)684 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
685 uint32_t length,
686 Handle<FixedArrayBase> backing_store) {
687 DCHECK(!array->SetLengthWouldNormalize(length));
688 DCHECK(IsFastElementsKind(array->GetElementsKind()));
689 uint32_t old_length = 0;
690 CHECK(array->length()->ToArrayIndex(&old_length));
691
692 if (old_length < length) {
693 ElementsKind kind = array->GetElementsKind();
694 if (!IsFastHoleyElementsKind(kind)) {
695 kind = GetHoleyElementsKind(kind);
696 JSObject::TransitionElementsKind(array, kind);
697 }
698 }
699
700 // Check whether the backing store should be shrunk.
701 uint32_t capacity = backing_store->length();
702 old_length = Min(old_length, capacity);
703 if (length == 0) {
704 array->initialize_elements();
705 } else if (length <= capacity) {
706 if (array->HasFastSmiOrObjectElements()) {
707 backing_store = JSObject::EnsureWritableFastElements(array);
708 }
709 if (2 * length <= capacity) {
710 // If more than half the elements won't be used, trim the array.
711 isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
712 *backing_store, capacity - length);
713 } else {
714 // Otherwise, fill the unused tail with holes.
715 for (uint32_t i = length; i < old_length; i++) {
716 BackingStore::cast(*backing_store)->set_the_hole(i);
717 }
718 }
719 } else {
720 // Check whether the backing store should be expanded.
721 capacity = Max(length, JSObject::NewElementsCapacity(capacity));
722 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity);
723 }
724
725 array->set_length(Smi::FromInt(length));
726 JSObject::ValidateElements(array);
727 }
728
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity)729 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
730 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
731 ElementsKind from_kind, uint32_t capacity) {
732 return ConvertElementsWithCapacity(
733 object, old_elements, from_kind, capacity, 0, 0,
734 ElementsAccessor::kCopyToEndAndInitializeToHole);
735 }
736
ConvertElementsWithCapacity(Handle<JSObject> object,Handle<FixedArrayBase> old_elements,ElementsKind from_kind,uint32_t capacity,int copy_size)737 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
738 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
739 ElementsKind from_kind, uint32_t capacity, int copy_size) {
740 return ConvertElementsWithCapacity(object, old_elements, from_kind,
741 capacity, 0, 0, copy_size);
742 }
743
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)744 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
745 Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
746 ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
747 uint32_t dst_index, int copy_size) {
748 Isolate* isolate = object->GetIsolate();
749 Handle<FixedArrayBase> new_elements;
750 if (IsFastDoubleElementsKind(kind())) {
751 new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
752 } else {
753 new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
754 }
755
756 int packed_size = kPackedSizeNotKnown;
757 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
758 packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
759 }
760
761 ElementsAccessorSubclass::CopyElementsImpl(
762 *old_elements, src_index, *new_elements, from_kind, dst_index,
763 packed_size, copy_size);
764
765 return new_elements;
766 }
767
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)768 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
769 uint32_t capacity) {
770 ElementsKind from_kind = object->GetElementsKind();
771 if (IsFastSmiOrObjectElementsKind(from_kind)) {
772 // Array optimizations rely on the prototype lookups of Array objects
773 // always returning undefined. If there is a store to the initial
774 // prototype object, make sure all of these optimizations are invalidated.
775 object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
776 }
777 Handle<FixedArrayBase> old_elements(object->elements());
778 // This method should only be called if there's a reason to update the
779 // elements.
780 DCHECK(IsFastDoubleElementsKind(from_kind) !=
781 IsFastDoubleElementsKind(kind()) ||
782 IsDictionaryElementsKind(from_kind) ||
783 static_cast<uint32_t>(old_elements->length()) < capacity);
784 Handle<FixedArrayBase> elements =
785 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
786
787 ElementsKind to_kind = kind();
788 if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
789 Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
790 JSObject::SetMapAndElements(object, new_map, elements);
791
792 // Transition through the allocation site as well if present.
793 JSObject::UpdateAllocationSite(object, to_kind);
794
795 if (FLAG_trace_elements_transitions) {
796 JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
797 to_kind, elements);
798 }
799 }
800
GrowCapacityAndConvert(Handle<JSObject> object,uint32_t capacity)801 void GrowCapacityAndConvert(Handle<JSObject> object,
802 uint32_t capacity) final {
803 ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity);
804 }
805
Delete(Handle<JSObject> obj,uint32_t entry)806 void Delete(Handle<JSObject> obj, uint32_t entry) final {
807 ElementsAccessorSubclass::DeleteImpl(obj, entry);
808 }
809
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)810 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
811 FixedArrayBase* to, ElementsKind from_kind,
812 uint32_t to_start, int packed_size,
813 int copy_size) {
814 UNREACHABLE();
815 }
816
CopyElements(Handle<FixedArrayBase> from,uint32_t from_start,ElementsKind from_kind,Handle<FixedArrayBase> to,uint32_t to_start,int copy_size)817 void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start,
818 ElementsKind from_kind, Handle<FixedArrayBase> to,
819 uint32_t to_start, int copy_size) final {
820 DCHECK(!from.is_null());
821 // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
822 // violate the handlified function signature convention:
823 // raw pointer parameters in the function that allocates. This is done
824 // intentionally to avoid ArrayConcat() builtin performance degradation.
825 // See the comment in another ElementsAccessorBase::CopyElements() for
826 // details.
827 ElementsAccessorSubclass::CopyElementsImpl(*from, from_start, *to,
828 from_kind, to_start,
829 kPackedSizeNotKnown, copy_size);
830 }
831
CopyElements(JSObject * from_holder,uint32_t from_start,ElementsKind from_kind,Handle<FixedArrayBase> to,uint32_t to_start,int copy_size)832 void CopyElements(JSObject* from_holder, uint32_t from_start,
833 ElementsKind from_kind, Handle<FixedArrayBase> to,
834 uint32_t to_start, int copy_size) final {
835 int packed_size = kPackedSizeNotKnown;
836 bool is_packed = IsFastPackedElementsKind(from_kind) &&
837 from_holder->IsJSArray();
838 if (is_packed) {
839 packed_size =
840 Smi::cast(JSArray::cast(from_holder)->length())->value();
841 if (copy_size >= 0 && packed_size > copy_size) {
842 packed_size = copy_size;
843 }
844 }
845 FixedArrayBase* from = from_holder->elements();
846 // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
847 // violate the handlified function signature convention:
848 // raw pointer parameters in the function that allocates. This is done
849 // intentionally to avoid ArrayConcat() builtin performance degradation.
850 //
851 // Details: The idea is that allocations actually happen only in case of
852 // copying from object with fast double elements to object with object
853 // elements. In all the other cases there are no allocations performed and
854 // handle creation causes noticeable performance degradation of the builtin.
855 ElementsAccessorSubclass::CopyElementsImpl(
856 from, from_start, *to, from_kind, to_start, packed_size, copy_size);
857 }
858
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys,uint32_t range,PropertyFilter filter,uint32_t offset)859 static void CollectElementIndicesImpl(Handle<JSObject> object,
860 Handle<FixedArrayBase> backing_store,
861 KeyAccumulator* keys, uint32_t range,
862 PropertyFilter filter,
863 uint32_t offset) {
864 if (filter & ONLY_ALL_CAN_READ) {
865 // Non-dictionary elements can't have all-can-read accessors.
866 return;
867 }
868 uint32_t length = 0;
869 if (object->IsJSArray()) {
870 length = Smi::cast(JSArray::cast(*object)->length())->value();
871 } else {
872 length =
873 ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
874 }
875 if (range < length) length = range;
876 for (uint32_t i = offset; i < length; i++) {
877 if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
878 filter))
879 continue;
880 keys->AddKey(i);
881 }
882 }
883
CollectElementIndices(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys,uint32_t range,PropertyFilter filter,uint32_t offset)884 void CollectElementIndices(Handle<JSObject> object,
885 Handle<FixedArrayBase> backing_store,
886 KeyAccumulator* keys, uint32_t range,
887 PropertyFilter filter, uint32_t offset) final {
888 ElementsAccessorSubclass::CollectElementIndicesImpl(
889 object, backing_store, keys, range, filter, offset);
890 };
891
AddElementsToKeyAccumulator(Handle<JSObject> receiver,KeyAccumulator * accumulator,AddKeyConversion convert)892 void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
893 KeyAccumulator* accumulator,
894 AddKeyConversion convert) final {
895 Handle<FixedArrayBase> from(receiver->elements());
896 uint32_t add_length =
897 ElementsAccessorSubclass::GetCapacityImpl(*receiver, *from);
898 if (add_length == 0) return;
899
900 for (uint32_t i = 0; i < add_length; i++) {
901 if (!ElementsAccessorSubclass::HasEntryImpl(*from, i)) continue;
902 Handle<Object> value = ElementsAccessorSubclass::GetImpl(from, i);
903 DCHECK(!value->IsTheHole());
904 DCHECK(!value->IsAccessorPair());
905 DCHECK(!value->IsExecutableAccessorInfo());
906 accumulator->AddKey(value, convert);
907 }
908 }
909
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)910 static uint32_t GetCapacityImpl(JSObject* holder,
911 FixedArrayBase* backing_store) {
912 return backing_store->length();
913 }
914
GetCapacity(JSObject * holder,FixedArrayBase * backing_store)915 uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
916 return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
917 }
918
HasEntryImpl(FixedArrayBase * backing_store,uint32_t entry)919 static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
920 return true;
921 }
922
GetIndexForEntryImpl(FixedArrayBase * backing_store,uint32_t entry)923 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
924 uint32_t entry) {
925 return entry;
926 }
927
GetEntryForIndexImpl(JSObject * holder,FixedArrayBase * backing_store,uint32_t index,PropertyFilter filter)928 static uint32_t GetEntryForIndexImpl(JSObject* holder,
929 FixedArrayBase* backing_store,
930 uint32_t index, PropertyFilter filter) {
931 if (IsHoleyElementsKind(kind())) {
932 return index < ElementsAccessorSubclass::GetCapacityImpl(holder,
933 backing_store) &&
934 !BackingStore::cast(backing_store)->is_the_hole(index)
935 ? index
936 : kMaxUInt32;
937 } else {
938 uint32_t length =
939 holder->IsJSArray()
940 ? static_cast<uint32_t>(
941 Smi::cast(JSArray::cast(holder)->length())->value())
942 : ElementsAccessorSubclass::GetCapacityImpl(holder,
943 backing_store);
944 return index < length ? index : kMaxUInt32;
945 }
946 }
947
GetEntryForIndex(JSObject * holder,FixedArrayBase * backing_store,uint32_t index)948 uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
949 uint32_t index) final {
950 return ElementsAccessorSubclass::GetEntryForIndexImpl(
951 holder, backing_store, index, ALL_PROPERTIES);
952 }
953
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)954 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
955 uint32_t entry) {
956 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
957 }
958
GetDetails(FixedArrayBase * backing_store,uint32_t entry)959 PropertyDetails GetDetails(FixedArrayBase* backing_store,
960 uint32_t entry) final {
961 return ElementsAccessorSubclass::GetDetailsImpl(backing_store, entry);
962 }
963
964 private:
965 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
966 };
967
968
969 class DictionaryElementsAccessor
970 : public ElementsAccessorBase<DictionaryElementsAccessor,
971 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
972 public:
DictionaryElementsAccessor(const char * name)973 explicit DictionaryElementsAccessor(const char* name)
974 : ElementsAccessorBase<DictionaryElementsAccessor,
975 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
976
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)977 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
978 uint32_t length,
979 Handle<FixedArrayBase> backing_store) {
980 Handle<SeededNumberDictionary> dict =
981 Handle<SeededNumberDictionary>::cast(backing_store);
982 int capacity = dict->Capacity();
983 uint32_t old_length = 0;
984 CHECK(array->length()->ToArrayLength(&old_length));
985 if (length < old_length) {
986 if (dict->requires_slow_elements()) {
987 // Find last non-deletable element in range of elements to be
988 // deleted and adjust range accordingly.
989 for (int entry = 0; entry < capacity; entry++) {
990 DisallowHeapAllocation no_gc;
991 Object* index = dict->KeyAt(entry);
992 if (index->IsNumber()) {
993 uint32_t number = static_cast<uint32_t>(index->Number());
994 if (length <= number && number < old_length) {
995 PropertyDetails details = dict->DetailsAt(entry);
996 if (!details.IsConfigurable()) length = number + 1;
997 }
998 }
999 }
1000 }
1001
1002 if (length == 0) {
1003 // Flush the backing store.
1004 JSObject::ResetElements(array);
1005 } else {
1006 DisallowHeapAllocation no_gc;
1007 // Remove elements that should be deleted.
1008 int removed_entries = 0;
1009 Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
1010 for (int entry = 0; entry < capacity; entry++) {
1011 Object* index = dict->KeyAt(entry);
1012 if (index->IsNumber()) {
1013 uint32_t number = static_cast<uint32_t>(index->Number());
1014 if (length <= number && number < old_length) {
1015 dict->SetEntry(entry, the_hole_value, the_hole_value);
1016 removed_entries++;
1017 }
1018 }
1019 }
1020
1021 // Update the number of elements.
1022 dict->ElementsRemoved(removed_entries);
1023 }
1024 }
1025
1026 Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1027 array->set_length(*length_obj);
1028 }
1029
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)1030 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1031 FixedArrayBase* to, ElementsKind from_kind,
1032 uint32_t to_start, int packed_size,
1033 int copy_size) {
1034 UNREACHABLE();
1035 }
1036
1037
DeleteImpl(Handle<JSObject> obj,uint32_t entry)1038 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1039 // TODO(verwaest): Remove reliance on index in Shrink.
1040 Handle<SeededNumberDictionary> dict(
1041 SeededNumberDictionary::cast(obj->elements()));
1042 uint32_t index = GetIndexForEntryImpl(*dict, entry);
1043 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
1044 USE(result);
1045 DCHECK(result->IsTrue());
1046 Handle<FixedArray> new_elements =
1047 SeededNumberDictionary::Shrink(dict, index);
1048 obj->set_elements(*new_elements);
1049 }
1050
GetRaw(FixedArrayBase * store,uint32_t entry)1051 static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
1052 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
1053 return backing_store->ValueAt(entry);
1054 }
1055
GetImpl(Handle<FixedArrayBase> store,uint32_t entry)1056 static Handle<Object> GetImpl(Handle<FixedArrayBase> store, uint32_t entry) {
1057 Isolate* isolate = store->GetIsolate();
1058 return handle(GetRaw(*store, entry), isolate);
1059 }
1060
SetImpl(FixedArrayBase * store,uint32_t entry,Object * value)1061 static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
1062 Object* value) {
1063 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1064 dictionary->ValueAtPut(entry, value);
1065 }
1066
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)1067 static void ReconfigureImpl(Handle<JSObject> object,
1068 Handle<FixedArrayBase> store, uint32_t entry,
1069 Handle<Object> value,
1070 PropertyAttributes attributes) {
1071 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
1072 if (attributes != NONE) object->RequireSlowElements(dictionary);
1073 dictionary->ValueAtPut(entry, *value);
1074 PropertyDetails details = dictionary->DetailsAt(entry);
1075 details = PropertyDetails(attributes, DATA, details.dictionary_index(),
1076 PropertyCellType::kNoCell);
1077 dictionary->DetailsAtPut(entry, details);
1078 }
1079
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)1080 static void AddImpl(Handle<JSObject> object, uint32_t index,
1081 Handle<Object> value, PropertyAttributes attributes,
1082 uint32_t new_capacity) {
1083 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
1084 Handle<SeededNumberDictionary> dictionary =
1085 object->HasFastElements()
1086 ? JSObject::NormalizeElements(object)
1087 : handle(SeededNumberDictionary::cast(object->elements()));
1088 Handle<SeededNumberDictionary> new_dictionary =
1089 SeededNumberDictionary::AddNumberEntry(
1090 dictionary, index, value, details,
1091 object->map()->is_prototype_map());
1092 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
1093 if (dictionary.is_identical_to(new_dictionary)) return;
1094 object->set_elements(*new_dictionary);
1095 }
1096
HasEntryImpl(FixedArrayBase * store,uint32_t entry)1097 static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
1098 DisallowHeapAllocation no_gc;
1099 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1100 Object* index = dict->KeyAt(entry);
1101 return !index->IsTheHole();
1102 }
1103
GetIndexForEntryImpl(FixedArrayBase * store,uint32_t entry)1104 static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
1105 DisallowHeapAllocation no_gc;
1106 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
1107 uint32_t result = 0;
1108 CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
1109 return result;
1110 }
1111
GetEntryForIndexImpl(JSObject * holder,FixedArrayBase * store,uint32_t index,PropertyFilter filter)1112 static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
1113 uint32_t index, PropertyFilter filter) {
1114 DisallowHeapAllocation no_gc;
1115 SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
1116 int entry = dictionary->FindEntry(index);
1117 if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
1118 if (filter != ALL_PROPERTIES) {
1119 PropertyDetails details = dictionary->DetailsAt(entry);
1120 PropertyAttributes attr = details.attributes();
1121 if ((attr & filter) != 0) return kMaxUInt32;
1122 }
1123 return static_cast<uint32_t>(entry);
1124 }
1125
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)1126 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1127 uint32_t entry) {
1128 return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
1129 }
1130
CollectElementIndicesImpl(Handle<JSObject> object,Handle<FixedArrayBase> backing_store,KeyAccumulator * keys,uint32_t range,PropertyFilter filter,uint32_t offset)1131 static void CollectElementIndicesImpl(Handle<JSObject> object,
1132 Handle<FixedArrayBase> backing_store,
1133 KeyAccumulator* keys, uint32_t range,
1134 PropertyFilter filter,
1135 uint32_t offset) {
1136 Handle<SeededNumberDictionary> dictionary =
1137 Handle<SeededNumberDictionary>::cast(backing_store);
1138 int capacity = dictionary->Capacity();
1139 for (int i = 0; i < capacity; i++) {
1140 Object* k = dictionary->KeyAt(i);
1141 if (!dictionary->IsKey(k)) continue;
1142 if (k->FilterKey(filter)) continue;
1143 if (dictionary->IsDeleted(i)) continue;
1144 DCHECK(k->IsNumber());
1145 DCHECK_LE(k->Number(), kMaxUInt32);
1146 uint32_t index = static_cast<uint32_t>(k->Number());
1147 if (index < offset) continue;
1148 PropertyDetails details = dictionary->DetailsAt(i);
1149 if (filter & ONLY_ALL_CAN_READ) {
1150 if (details.kind() != kAccessor) continue;
1151 Object* accessors = dictionary->ValueAt(i);
1152 if (!accessors->IsAccessorInfo()) continue;
1153 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
1154 }
1155 PropertyAttributes attr = details.attributes();
1156 if ((attr & filter) != 0) continue;
1157 keys->AddKey(index);
1158 }
1159
1160 keys->SortCurrentElementsList();
1161 }
1162 };
1163
1164
1165 // Super class for all fast element arrays.
1166 template<typename FastElementsAccessorSubclass,
1167 typename KindTraits>
1168 class FastElementsAccessor
1169 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
1170 public:
FastElementsAccessor(const char * name)1171 explicit FastElementsAccessor(const char* name)
1172 : ElementsAccessorBase<FastElementsAccessorSubclass,
1173 KindTraits>(name) {}
1174
1175 typedef typename KindTraits::BackingStore BackingStore;
1176
DeleteAtEnd(Handle<JSObject> obj,Handle<BackingStore> backing_store,uint32_t entry)1177 static void DeleteAtEnd(Handle<JSObject> obj,
1178 Handle<BackingStore> backing_store, uint32_t entry) {
1179 uint32_t length = static_cast<uint32_t>(backing_store->length());
1180 Heap* heap = obj->GetHeap();
1181 for (; entry > 0; entry--) {
1182 if (!backing_store->is_the_hole(entry - 1)) break;
1183 }
1184 if (entry == 0) {
1185 FixedArray* empty = heap->empty_fixed_array();
1186 if (obj->HasFastArgumentsElements()) {
1187 FixedArray::cast(obj->elements())->set(1, empty);
1188 } else {
1189 obj->set_elements(empty);
1190 }
1191 return;
1192 }
1193
1194 heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
1195 length - entry);
1196 }
1197
DeleteCommon(Handle<JSObject> obj,uint32_t entry,Handle<FixedArrayBase> store)1198 static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
1199 Handle<FixedArrayBase> store) {
1200 DCHECK(obj->HasFastSmiOrObjectElements() ||
1201 obj->HasFastDoubleElements() ||
1202 obj->HasFastArgumentsElements());
1203 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
1204 if (!obj->IsJSArray() &&
1205 entry == static_cast<uint32_t>(store->length()) - 1) {
1206 DeleteAtEnd(obj, backing_store, entry);
1207 return;
1208 }
1209
1210 backing_store->set_the_hole(entry);
1211
1212 // TODO(verwaest): Move this out of elements.cc.
1213 // If an old space backing store is larger than a certain size and
1214 // has too few used values, normalize it.
1215 // To avoid doing the check on every delete we require at least
1216 // one adjacent hole to the value being deleted.
1217 const int kMinLengthForSparsenessCheck = 64;
1218 if (backing_store->length() < kMinLengthForSparsenessCheck) return;
1219 if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
1220 uint32_t length = 0;
1221 if (obj->IsJSArray()) {
1222 JSArray::cast(*obj)->length()->ToArrayLength(&length);
1223 } else {
1224 length = static_cast<uint32_t>(store->length());
1225 }
1226 if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
1227 (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
1228 if (!obj->IsJSArray()) {
1229 uint32_t i;
1230 for (i = entry + 1; i < length; i++) {
1231 if (!backing_store->is_the_hole(i)) break;
1232 }
1233 if (i == length) {
1234 DeleteAtEnd(obj, backing_store, entry);
1235 return;
1236 }
1237 }
1238 int num_used = 0;
1239 for (int i = 0; i < backing_store->length(); ++i) {
1240 if (!backing_store->is_the_hole(i)) {
1241 ++num_used;
1242 // Bail out if a number dictionary wouldn't be able to save at least
1243 // 75% space.
1244 if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
1245 SeededNumberDictionary::kEntrySize >
1246 backing_store->length()) {
1247 return;
1248 }
1249 }
1250 }
1251 JSObject::NormalizeElements(obj);
1252 }
1253 }
1254
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)1255 static void ReconfigureImpl(Handle<JSObject> object,
1256 Handle<FixedArrayBase> store, uint32_t entry,
1257 Handle<Object> value,
1258 PropertyAttributes attributes) {
1259 Handle<SeededNumberDictionary> dictionary =
1260 JSObject::NormalizeElements(object);
1261 entry = dictionary->FindEntry(entry);
1262 DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
1263 value, attributes);
1264 }
1265
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)1266 static void AddImpl(Handle<JSObject> object, uint32_t index,
1267 Handle<Object> value, PropertyAttributes attributes,
1268 uint32_t new_capacity) {
1269 DCHECK_EQ(NONE, attributes);
1270 ElementsKind from_kind = object->GetElementsKind();
1271 ElementsKind to_kind = FastElementsAccessorSubclass::kind();
1272 if (IsDictionaryElementsKind(from_kind) ||
1273 IsFastDoubleElementsKind(from_kind) !=
1274 IsFastDoubleElementsKind(to_kind) ||
1275 FastElementsAccessorSubclass::GetCapacityImpl(
1276 *object, object->elements()) != new_capacity) {
1277 FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object,
1278 new_capacity);
1279 } else {
1280 if (from_kind != to_kind) {
1281 JSObject::TransitionElementsKind(object, to_kind);
1282 }
1283 if (IsFastSmiOrObjectElementsKind(from_kind)) {
1284 DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
1285 JSObject::EnsureWritableFastElements(object);
1286 }
1287 }
1288 FastElementsAccessorSubclass::SetImpl(object->elements(), index, *value);
1289 }
1290
DeleteImpl(Handle<JSObject> obj,uint32_t entry)1291 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1292 ElementsKind kind = KindTraits::Kind;
1293 if (IsFastPackedElementsKind(kind)) {
1294 JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
1295 }
1296 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1297 JSObject::EnsureWritableFastElements(obj);
1298 }
1299 DeleteCommon(obj, entry, handle(obj->elements()));
1300 }
1301
HasEntryImpl(FixedArrayBase * backing_store,uint32_t entry)1302 static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
1303 return !BackingStore::cast(backing_store)->is_the_hole(entry);
1304 }
1305
ValidateContents(Handle<JSObject> holder,int length)1306 static void ValidateContents(Handle<JSObject> holder, int length) {
1307 #if DEBUG
1308 Isolate* isolate = holder->GetIsolate();
1309 HandleScope scope(isolate);
1310 Handle<FixedArrayBase> elements(holder->elements(), isolate);
1311 Map* map = elements->map();
1312 DCHECK((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
1313 (map == isolate->heap()->fixed_array_map() ||
1314 map == isolate->heap()->fixed_cow_array_map())) ||
1315 (IsFastDoubleElementsKind(KindTraits::Kind) ==
1316 ((map == isolate->heap()->fixed_array_map() && length == 0) ||
1317 map == isolate->heap()->fixed_double_array_map())));
1318 if (length == 0) return; // nothing to do!
1319 DisallowHeapAllocation no_gc;
1320 Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
1321 if (IsFastSmiElementsKind(KindTraits::Kind)) {
1322 for (int i = 0; i < length; i++) {
1323 DCHECK(BackingStore::get(backing_store, i)->IsSmi() ||
1324 (IsFastHoleyElementsKind(KindTraits::Kind) &&
1325 backing_store->is_the_hole(i)));
1326 }
1327 }
1328 #endif
1329 }
1330
PopImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)1331 static Handle<Object> PopImpl(Handle<JSArray> receiver,
1332 Handle<FixedArrayBase> backing_store) {
1333 return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
1334 AT_END);
1335 }
1336
ShiftImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store)1337 static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
1338 Handle<FixedArrayBase> backing_store) {
1339 return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
1340 AT_START);
1341 }
1342
PushImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t push_size)1343 static uint32_t PushImpl(Handle<JSArray> receiver,
1344 Handle<FixedArrayBase> backing_store,
1345 Arguments* args, uint32_t push_size) {
1346 return FastElementsAccessorSubclass::AddArguments(receiver, backing_store,
1347 args, push_size, AT_END);
1348 }
1349
UnshiftImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t unshift_size)1350 static uint32_t UnshiftImpl(Handle<JSArray> receiver,
1351 Handle<FixedArrayBase> backing_store,
1352 Arguments* args, uint32_t unshift_size) {
1353 return FastElementsAccessorSubclass::AddArguments(
1354 receiver, backing_store, args, unshift_size, AT_START);
1355 }
1356
MoveElements(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,int dst_index,int src_index,int len,int hole_start,int hole_end)1357 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1358 Handle<FixedArrayBase> backing_store, int dst_index,
1359 int src_index, int len, int hole_start,
1360 int hole_end) {
1361 UNREACHABLE();
1362 }
1363
SliceImpl(Handle<JSObject> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t end)1364 static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
1365 Handle<FixedArrayBase> backing_store,
1366 uint32_t start, uint32_t end) {
1367 DCHECK(start < end);
1368 Isolate* isolate = receiver->GetIsolate();
1369 int result_len = end - start;
1370 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
1371 KindTraits::Kind, result_len, result_len);
1372 DisallowHeapAllocation no_gc;
1373 FastElementsAccessorSubclass::CopyElementsImpl(
1374 *backing_store, start, result_array->elements(), KindTraits::Kind, 0,
1375 kPackedSizeNotKnown, result_len);
1376 FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
1377 result_array);
1378 return result_array;
1379 }
1380
SpliceImpl(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,uint32_t start,uint32_t delete_count,Arguments * args,uint32_t add_count)1381 static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
1382 Handle<FixedArrayBase> backing_store,
1383 uint32_t start, uint32_t delete_count,
1384 Arguments* args, uint32_t add_count) {
1385 Isolate* isolate = receiver->GetIsolate();
1386 Heap* heap = isolate->heap();
1387 uint32_t length = Smi::cast(receiver->length())->value();
1388 uint32_t new_length = length - delete_count + add_count;
1389
1390 if (new_length == 0) {
1391 receiver->set_elements(heap->empty_fixed_array());
1392 receiver->set_length(Smi::FromInt(0));
1393 return isolate->factory()->NewJSArrayWithElements(
1394 backing_store, KindTraits::Kind, delete_count);
1395 }
1396
1397 // Construct the result array which holds the deleted elements.
1398 Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
1399 KindTraits::Kind, delete_count, delete_count);
1400 if (delete_count > 0) {
1401 DisallowHeapAllocation no_gc;
1402 FastElementsAccessorSubclass::CopyElementsImpl(
1403 *backing_store, start, deleted_elements->elements(), KindTraits::Kind,
1404 0, kPackedSizeNotKnown, delete_count);
1405 }
1406
1407 // Delete and move elements to make space for add_count new elements.
1408 if (add_count < delete_count) {
1409 FastElementsAccessorSubclass::SpliceShrinkStep(
1410 isolate, receiver, backing_store, start, delete_count, add_count,
1411 length, new_length);
1412 } else if (add_count > delete_count) {
1413 backing_store = FastElementsAccessorSubclass::SpliceGrowStep(
1414 isolate, receiver, backing_store, start, delete_count, add_count,
1415 length, new_length);
1416 }
1417
1418 // Copy over the arguments.
1419 FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count,
1420 3, start);
1421
1422 receiver->set_length(Smi::FromInt(new_length));
1423 FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
1424 deleted_elements);
1425 return deleted_elements;
1426 }
1427
1428 private:
1429 // 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)1430 static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
1431 Handle<FixedArrayBase> backing_store,
1432 uint32_t start, uint32_t delete_count,
1433 uint32_t add_count, uint32_t len,
1434 uint32_t new_length) {
1435 const int move_left_count = len - delete_count - start;
1436 const int move_left_dst_index = start + add_count;
1437 FastElementsAccessorSubclass::MoveElements(
1438 isolate, receiver, backing_store, move_left_dst_index,
1439 start + delete_count, move_left_count, new_length, len);
1440 }
1441
1442 // 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)1443 static Handle<FixedArrayBase> SpliceGrowStep(
1444 Isolate* isolate, Handle<JSArray> receiver,
1445 Handle<FixedArrayBase> backing_store, uint32_t start,
1446 uint32_t delete_count, uint32_t add_count, uint32_t length,
1447 uint32_t new_length) {
1448 // Check we do not overflow the new_length.
1449 DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
1450 // Check if backing_store is big enough.
1451 if (new_length <= static_cast<uint32_t>(backing_store->length())) {
1452 FastElementsAccessorSubclass::MoveElements(
1453 isolate, receiver, backing_store, start + add_count,
1454 start + delete_count, (length - delete_count - start), 0, 0);
1455 // MoveElements updates the backing_store in-place.
1456 return backing_store;
1457 }
1458 // New backing storage is needed.
1459 int capacity = JSObject::NewElementsCapacity(new_length);
1460 // Partially copy all elements up to start.
1461 Handle<FixedArrayBase> new_elms =
1462 FastElementsAccessorSubclass::ConvertElementsWithCapacity(
1463 receiver, backing_store, KindTraits::Kind, capacity, start);
1464 // Copy the trailing elements after start + delete_count
1465 FastElementsAccessorSubclass::CopyElementsImpl(
1466 *backing_store, start + delete_count, *new_elms, KindTraits::Kind,
1467 start + add_count, kPackedSizeNotKnown,
1468 ElementsAccessor::kCopyToEndAndInitializeToHole);
1469 receiver->set_elements(*new_elms);
1470 return new_elms;
1471 }
1472
RemoveElement(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Where remove_position)1473 static Handle<Object> RemoveElement(Handle<JSArray> receiver,
1474 Handle<FixedArrayBase> backing_store,
1475 Where remove_position) {
1476 Isolate* isolate = receiver->GetIsolate();
1477 uint32_t length =
1478 static_cast<uint32_t>(Smi::cast(receiver->length())->value());
1479 DCHECK(length > 0);
1480 int new_length = length - 1;
1481 int remove_index = remove_position == AT_START ? 0 : new_length;
1482 Handle<Object> result =
1483 FastElementsAccessorSubclass::GetImpl(backing_store, remove_index);
1484 if (remove_position == AT_START) {
1485 FastElementsAccessorSubclass::MoveElements(
1486 isolate, receiver, backing_store, 0, 1, new_length, 0, 0);
1487 }
1488 FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length,
1489 backing_store);
1490
1491 if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
1492 return receiver->GetIsolate()->factory()->undefined_value();
1493 }
1494 return result;
1495 }
1496
AddArguments(Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,Arguments * args,uint32_t add_size,Where remove_position)1497 static uint32_t AddArguments(Handle<JSArray> receiver,
1498 Handle<FixedArrayBase> backing_store,
1499 Arguments* args, uint32_t add_size,
1500 Where remove_position) {
1501 uint32_t length = Smi::cast(receiver->length())->value();
1502 DCHECK(add_size > 0);
1503 uint32_t elms_len = backing_store->length();
1504 // Check we do not overflow the new_length.
1505 DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
1506 uint32_t new_length = length + add_size;
1507
1508 if (new_length > elms_len) {
1509 // New backing storage is needed.
1510 uint32_t capacity = JSObject::NewElementsCapacity(new_length);
1511 // If we add arguments to the start we have to shift the existing objects.
1512 int copy_dst_index = remove_position == AT_START ? add_size : 0;
1513 // Copy over all objects to a new backing_store.
1514 backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
1515 receiver, backing_store, KindTraits::Kind, capacity, 0,
1516 copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
1517 receiver->set_elements(*backing_store);
1518 } else if (remove_position == AT_START) {
1519 // If the backing store has enough capacity and we add elements to the
1520 // start we have to shift the existing objects.
1521 Isolate* isolate = receiver->GetIsolate();
1522 FastElementsAccessorSubclass::MoveElements(
1523 isolate, receiver, backing_store, add_size, 0, length, 0, 0);
1524 }
1525
1526 int insertion_index = remove_position == AT_START ? 0 : length;
1527 // Copy the arguments to the start.
1528 FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_size,
1529 1, insertion_index);
1530 // Set the length.
1531 receiver->set_length(Smi::FromInt(new_length));
1532 return new_length;
1533 }
1534
CopyArguments(Arguments * args,Handle<FixedArrayBase> dst_store,uint32_t copy_size,uint32_t src_index,uint32_t dst_index)1535 static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
1536 uint32_t copy_size, uint32_t src_index,
1537 uint32_t dst_index) {
1538 // Add the provided values.
1539 DisallowHeapAllocation no_gc;
1540 FixedArrayBase* raw_backing_store = *dst_store;
1541 WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
1542 for (uint32_t i = 0; i < copy_size; i++) {
1543 Object* argument = (*args)[i + src_index];
1544 FastElementsAccessorSubclass::SetImpl(raw_backing_store, i + dst_index,
1545 argument, mode);
1546 }
1547 }
1548 };
1549
1550
1551 template<typename FastElementsAccessorSubclass,
1552 typename KindTraits>
1553 class FastSmiOrObjectElementsAccessor
1554 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
1555 public:
FastSmiOrObjectElementsAccessor(const char * name)1556 explicit FastSmiOrObjectElementsAccessor(const char* name)
1557 : FastElementsAccessor<FastElementsAccessorSubclass,
1558 KindTraits>(name) {}
1559
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)1560 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1561 Object* value) {
1562 FixedArray::cast(backing_store)->set(entry, value);
1563 }
1564
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)1565 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1566 Object* value, WriteBarrierMode mode) {
1567 FixedArray::cast(backing_store)->set(entry, value, mode);
1568 }
1569
GetRaw(FixedArray * backing_store,uint32_t entry)1570 static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
1571 uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl(
1572 backing_store, entry);
1573 return backing_store->get(index);
1574 }
1575
MoveElements(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,int dst_index,int src_index,int len,int hole_start,int hole_end)1576 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1577 Handle<FixedArrayBase> backing_store, int dst_index,
1578 int src_index, int len, int hole_start,
1579 int hole_end) {
1580 Heap* heap = isolate->heap();
1581 Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store);
1582 if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1583 // Update all the copies of this backing_store handle.
1584 *dst_elms.location() =
1585 FixedArray::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
1586 receiver->set_elements(*dst_elms);
1587 // Adjust the hole offset as the array has been shrunk.
1588 hole_end -= src_index;
1589 DCHECK_LE(hole_start, backing_store->length());
1590 DCHECK_LE(hole_end, backing_store->length());
1591 } else if (len != 0) {
1592 DisallowHeapAllocation no_gc;
1593 heap->MoveElements(*dst_elms, dst_index, src_index, len);
1594 }
1595 if (hole_start != hole_end) {
1596 dst_elms->FillWithHoles(hole_start, hole_end);
1597 }
1598 }
1599
1600 // NOTE: this method violates the handlified function signature convention:
1601 // raw pointer parameters in the function that allocates.
1602 // See ElementsAccessor::CopyElements() for details.
1603 // This method could actually allocate if copying from double elements to
1604 // object elements.
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)1605 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1606 FixedArrayBase* to, ElementsKind from_kind,
1607 uint32_t to_start, int packed_size,
1608 int copy_size) {
1609 DisallowHeapAllocation no_gc;
1610 ElementsKind to_kind = KindTraits::Kind;
1611 switch (from_kind) {
1612 case FAST_SMI_ELEMENTS:
1613 case FAST_HOLEY_SMI_ELEMENTS:
1614 case FAST_ELEMENTS:
1615 case FAST_HOLEY_ELEMENTS:
1616 CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind,
1617 to_start, copy_size);
1618 break;
1619 case FAST_DOUBLE_ELEMENTS:
1620 case FAST_HOLEY_DOUBLE_ELEMENTS: {
1621 AllowHeapAllocation allow_allocation;
1622 DCHECK(IsFastObjectElementsKind(to_kind));
1623 CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
1624 break;
1625 }
1626 case DICTIONARY_ELEMENTS:
1627 CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
1628 copy_size);
1629 break;
1630 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1631 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
1632 UNREACHABLE();
1633 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
1634 case TYPE##_ELEMENTS: \
1635 UNREACHABLE();
1636 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1637 #undef TYPED_ARRAY_CASE
1638 }
1639 }
1640 };
1641
1642
1643 class FastPackedSmiElementsAccessor
1644 : public FastSmiOrObjectElementsAccessor<
1645 FastPackedSmiElementsAccessor,
1646 ElementsKindTraits<FAST_SMI_ELEMENTS> > {
1647 public:
FastPackedSmiElementsAccessor(const char * name)1648 explicit FastPackedSmiElementsAccessor(const char* name)
1649 : FastSmiOrObjectElementsAccessor<
1650 FastPackedSmiElementsAccessor,
1651 ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
1652 };
1653
1654
1655 class FastHoleySmiElementsAccessor
1656 : public FastSmiOrObjectElementsAccessor<
1657 FastHoleySmiElementsAccessor,
1658 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
1659 public:
FastHoleySmiElementsAccessor(const char * name)1660 explicit FastHoleySmiElementsAccessor(const char* name)
1661 : FastSmiOrObjectElementsAccessor<
1662 FastHoleySmiElementsAccessor,
1663 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
1664 };
1665
1666
1667 class FastPackedObjectElementsAccessor
1668 : public FastSmiOrObjectElementsAccessor<
1669 FastPackedObjectElementsAccessor,
1670 ElementsKindTraits<FAST_ELEMENTS> > {
1671 public:
FastPackedObjectElementsAccessor(const char * name)1672 explicit FastPackedObjectElementsAccessor(const char* name)
1673 : FastSmiOrObjectElementsAccessor<
1674 FastPackedObjectElementsAccessor,
1675 ElementsKindTraits<FAST_ELEMENTS> >(name) {}
1676 };
1677
1678
1679 class FastHoleyObjectElementsAccessor
1680 : public FastSmiOrObjectElementsAccessor<
1681 FastHoleyObjectElementsAccessor,
1682 ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
1683 public:
FastHoleyObjectElementsAccessor(const char * name)1684 explicit FastHoleyObjectElementsAccessor(const char* name)
1685 : FastSmiOrObjectElementsAccessor<
1686 FastHoleyObjectElementsAccessor,
1687 ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
1688 };
1689
1690
1691 template<typename FastElementsAccessorSubclass,
1692 typename KindTraits>
1693 class FastDoubleElementsAccessor
1694 : public FastElementsAccessor<FastElementsAccessorSubclass, KindTraits> {
1695 public:
FastDoubleElementsAccessor(const char * name)1696 explicit FastDoubleElementsAccessor(const char* name)
1697 : FastElementsAccessor<FastElementsAccessorSubclass,
1698 KindTraits>(name) {}
1699
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)1700 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1701 Object* value) {
1702 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
1703 }
1704
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)1705 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1706 Object* value, WriteBarrierMode mode) {
1707 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
1708 }
1709
MoveElements(Isolate * isolate,Handle<JSArray> receiver,Handle<FixedArrayBase> backing_store,int dst_index,int src_index,int len,int hole_start,int hole_end)1710 static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
1711 Handle<FixedArrayBase> backing_store, int dst_index,
1712 int src_index, int len, int hole_start,
1713 int hole_end) {
1714 Heap* heap = isolate->heap();
1715 Handle<FixedDoubleArray> dst_elms =
1716 Handle<FixedDoubleArray>::cast(backing_store);
1717 if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
1718 // Update all the copies of this backing_store handle.
1719 *dst_elms.location() = FixedDoubleArray::cast(
1720 heap->LeftTrimFixedArray(*dst_elms, src_index));
1721 receiver->set_elements(*dst_elms);
1722 // Adjust the hole offset as the array has been shrunk.
1723 hole_end -= src_index;
1724 DCHECK_LE(hole_start, backing_store->length());
1725 DCHECK_LE(hole_end, backing_store->length());
1726 } else if (len != 0) {
1727 MemMove(dst_elms->data_start() + dst_index,
1728 dst_elms->data_start() + src_index, len * kDoubleSize);
1729 }
1730 if (hole_start != hole_end) {
1731 dst_elms->FillWithHoles(hole_start, hole_end);
1732 }
1733 }
1734
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)1735 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
1736 FixedArrayBase* to, ElementsKind from_kind,
1737 uint32_t to_start, int packed_size,
1738 int copy_size) {
1739 DisallowHeapAllocation no_allocation;
1740 switch (from_kind) {
1741 case FAST_SMI_ELEMENTS:
1742 CopyPackedSmiToDoubleElements(from, from_start, to, to_start,
1743 packed_size, copy_size);
1744 break;
1745 case FAST_HOLEY_SMI_ELEMENTS:
1746 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
1747 break;
1748 case FAST_DOUBLE_ELEMENTS:
1749 case FAST_HOLEY_DOUBLE_ELEMENTS:
1750 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
1751 break;
1752 case FAST_ELEMENTS:
1753 case FAST_HOLEY_ELEMENTS:
1754 CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
1755 break;
1756 case DICTIONARY_ELEMENTS:
1757 CopyDictionaryToDoubleElements(from, from_start, to, to_start,
1758 copy_size);
1759 break;
1760 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1761 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
1762 UNREACHABLE();
1763
1764 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
1765 case TYPE##_ELEMENTS: \
1766 UNREACHABLE();
1767 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1768 #undef TYPED_ARRAY_CASE
1769 }
1770 }
1771 };
1772
1773
1774 class FastPackedDoubleElementsAccessor
1775 : public FastDoubleElementsAccessor<
1776 FastPackedDoubleElementsAccessor,
1777 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
1778 public:
FastPackedDoubleElementsAccessor(const char * name)1779 explicit FastPackedDoubleElementsAccessor(const char* name)
1780 : FastDoubleElementsAccessor<
1781 FastPackedDoubleElementsAccessor,
1782 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
1783 };
1784
1785
1786 class FastHoleyDoubleElementsAccessor
1787 : public FastDoubleElementsAccessor<
1788 FastHoleyDoubleElementsAccessor,
1789 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
1790 public:
FastHoleyDoubleElementsAccessor(const char * name)1791 explicit FastHoleyDoubleElementsAccessor(const char* name)
1792 : FastDoubleElementsAccessor<
1793 FastHoleyDoubleElementsAccessor,
1794 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
1795 };
1796
1797
1798 // Super class for all external element arrays.
1799 template<ElementsKind Kind>
1800 class TypedElementsAccessor
1801 : public ElementsAccessorBase<TypedElementsAccessor<Kind>,
1802 ElementsKindTraits<Kind> > {
1803 public:
TypedElementsAccessor(const char * name)1804 explicit TypedElementsAccessor(const char* name)
1805 : ElementsAccessorBase<AccessorClass,
1806 ElementsKindTraits<Kind> >(name) {}
1807
1808 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
1809 typedef TypedElementsAccessor<Kind> AccessorClass;
1810
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value)1811 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1812 Object* value) {
1813 BackingStore::cast(backing_store)->SetValue(entry, value);
1814 }
1815
SetImpl(FixedArrayBase * backing_store,uint32_t entry,Object * value,WriteBarrierMode mode)1816 static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
1817 Object* value, WriteBarrierMode mode) {
1818 BackingStore::cast(backing_store)->SetValue(entry, value);
1819 }
1820
GetImpl(Handle<FixedArrayBase> backing_store,uint32_t entry)1821 static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
1822 uint32_t entry) {
1823 uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
1824 return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
1825 }
1826
GetDetailsImpl(FixedArrayBase * backing_store,uint32_t entry)1827 static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
1828 uint32_t entry) {
1829 return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
1830 }
1831
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> backing_store)1832 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1833 uint32_t length,
1834 Handle<FixedArrayBase> backing_store) {
1835 // External arrays do not support changing their length.
1836 UNREACHABLE();
1837 }
1838
DeleteImpl(Handle<JSObject> obj,uint32_t entry)1839 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
1840 UNREACHABLE();
1841 }
1842
GetIndexForEntryImpl(FixedArrayBase * backing_store,uint32_t entry)1843 static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
1844 uint32_t entry) {
1845 return entry;
1846 }
1847
GetEntryForIndexImpl(JSObject * holder,FixedArrayBase * backing_store,uint32_t index,PropertyFilter filter)1848 static uint32_t GetEntryForIndexImpl(JSObject* holder,
1849 FixedArrayBase* backing_store,
1850 uint32_t index, PropertyFilter filter) {
1851 return index < AccessorClass::GetCapacityImpl(holder, backing_store)
1852 ? index
1853 : kMaxUInt32;
1854 }
1855
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)1856 static uint32_t GetCapacityImpl(JSObject* holder,
1857 FixedArrayBase* backing_store) {
1858 JSArrayBufferView* view = JSArrayBufferView::cast(holder);
1859 if (view->WasNeutered()) return 0;
1860 return backing_store->length();
1861 }
1862 };
1863
1864
1865
1866 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \
1867 typedef TypedElementsAccessor<TYPE##_ELEMENTS > \
1868 Fixed##Type##ElementsAccessor;
1869
1870 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
1871 #undef FIXED_ELEMENTS_ACCESSOR
1872
1873
1874 template <typename SloppyArgumentsElementsAccessorSubclass,
1875 typename ArgumentsAccessor, typename KindTraits>
1876 class SloppyArgumentsElementsAccessor
1877 : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
1878 KindTraits> {
1879 public:
SloppyArgumentsElementsAccessor(const char * name)1880 explicit SloppyArgumentsElementsAccessor(const char* name)
1881 : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
1882 KindTraits>(name) {
1883 USE(KindTraits::Kind);
1884 }
1885
GetImpl(Handle<FixedArrayBase> parameters,uint32_t entry)1886 static Handle<Object> GetImpl(Handle<FixedArrayBase> parameters,
1887 uint32_t entry) {
1888 Isolate* isolate = parameters->GetIsolate();
1889 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
1890 uint32_t length = parameter_map->length() - 2;
1891 if (entry < length) {
1892 DisallowHeapAllocation no_gc;
1893 Object* probe = parameter_map->get(entry + 2);
1894 Context* context = Context::cast(parameter_map->get(0));
1895 int context_entry = Smi::cast(probe)->value();
1896 DCHECK(!context->get(context_entry)->IsTheHole());
1897 return handle(context->get(context_entry), isolate);
1898 } else {
1899 // Object is not mapped, defer to the arguments.
1900 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)),
1901 isolate);
1902 Handle<Object> result =
1903 ArgumentsAccessor::GetImpl(arguments, entry - length);
1904 // Elements of the arguments object in slow mode might be slow aliases.
1905 if (result->IsAliasedArgumentsEntry()) {
1906 DisallowHeapAllocation no_gc;
1907 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
1908 Context* context = Context::cast(parameter_map->get(0));
1909 int context_entry = alias->aliased_context_slot();
1910 DCHECK(!context->get(context_entry)->IsTheHole());
1911 return handle(context->get(context_entry), isolate);
1912 }
1913 return result;
1914 }
1915 }
1916
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)1917 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
1918 uint32_t capacity) {
1919 UNREACHABLE();
1920 }
1921
SetImpl(FixedArrayBase * store,uint32_t entry,Object * value)1922 static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
1923 Object* value) {
1924 FixedArray* parameter_map = FixedArray::cast(store);
1925 uint32_t length = parameter_map->length() - 2;
1926 if (entry < length) {
1927 Object* probe = parameter_map->get(entry + 2);
1928 Context* context = Context::cast(parameter_map->get(0));
1929 int context_entry = Smi::cast(probe)->value();
1930 DCHECK(!context->get(context_entry)->IsTheHole());
1931 context->set(context_entry, value);
1932 } else {
1933 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1934 Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
1935 if (current->IsAliasedArgumentsEntry()) {
1936 AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
1937 Context* context = Context::cast(parameter_map->get(0));
1938 int context_entry = alias->aliased_context_slot();
1939 DCHECK(!context->get(context_entry)->IsTheHole());
1940 context->set(context_entry, value);
1941 } else {
1942 ArgumentsAccessor::SetImpl(arguments, entry - length, value);
1943 }
1944 }
1945 }
1946
SetLengthImpl(Isolate * isolate,Handle<JSArray> array,uint32_t length,Handle<FixedArrayBase> parameter_map)1947 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1948 uint32_t length,
1949 Handle<FixedArrayBase> parameter_map) {
1950 // Sloppy arguments objects are not arrays.
1951 UNREACHABLE();
1952 }
1953
GetCapacityImpl(JSObject * holder,FixedArrayBase * backing_store)1954 static uint32_t GetCapacityImpl(JSObject* holder,
1955 FixedArrayBase* backing_store) {
1956 FixedArray* parameter_map = FixedArray::cast(backing_store);
1957 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1958 return parameter_map->length() - 2 +
1959 ArgumentsAccessor::GetCapacityImpl(holder, arguments);
1960 }
1961
HasEntryImpl(FixedArrayBase * parameters,uint32_t entry)1962 static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
1963 FixedArray* parameter_map = FixedArray::cast(parameters);
1964 uint32_t length = parameter_map->length() - 2;
1965 if (entry < length) {
1966 return !GetParameterMapArg(parameter_map, entry)->IsTheHole();
1967 }
1968
1969 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1970 return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
1971 }
1972
GetIndexForEntryImpl(FixedArrayBase * parameters,uint32_t entry)1973 static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
1974 uint32_t entry) {
1975 FixedArray* parameter_map = FixedArray::cast(parameters);
1976 uint32_t length = parameter_map->length() - 2;
1977 if (entry < length) return entry;
1978
1979 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1980 return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
1981 }
1982
GetEntryForIndexImpl(JSObject * holder,FixedArrayBase * parameters,uint32_t index,PropertyFilter filter)1983 static uint32_t GetEntryForIndexImpl(JSObject* holder,
1984 FixedArrayBase* parameters,
1985 uint32_t index, PropertyFilter filter) {
1986 FixedArray* parameter_map = FixedArray::cast(parameters);
1987 Object* probe = GetParameterMapArg(parameter_map, index);
1988 if (!probe->IsTheHole()) return index;
1989
1990 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1991 uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
1992 index, filter);
1993 if (entry == kMaxUInt32) return entry;
1994 return (parameter_map->length() - 2) + entry;
1995 }
1996
GetDetailsImpl(FixedArrayBase * parameters,uint32_t entry)1997 static PropertyDetails GetDetailsImpl(FixedArrayBase* parameters,
1998 uint32_t entry) {
1999 FixedArray* parameter_map = FixedArray::cast(parameters);
2000 uint32_t length = parameter_map->length() - 2;
2001 if (entry < length) {
2002 return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
2003 }
2004 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2005 return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
2006 }
2007
GetParameterMapArg(FixedArray * parameter_map,uint32_t index)2008 static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
2009 uint32_t length = parameter_map->length() - 2;
2010 return index < length
2011 ? parameter_map->get(index + 2)
2012 : Object::cast(parameter_map->GetHeap()->the_hole_value());
2013 }
2014
DeleteImpl(Handle<JSObject> obj,uint32_t entry)2015 static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
2016 FixedArray* parameter_map = FixedArray::cast(obj->elements());
2017 uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
2018 if (entry < length) {
2019 // TODO(kmillikin): We could check if this was the last aliased
2020 // parameter, and revert to normal elements in that case. That
2021 // would enable GC of the context.
2022 parameter_map->set_the_hole(entry + 2);
2023 } else {
2024 SloppyArgumentsElementsAccessorSubclass::DeleteFromArguments(
2025 obj, entry - length);
2026 }
2027 }
2028 };
2029
2030
2031 class SlowSloppyArgumentsElementsAccessor
2032 : public SloppyArgumentsElementsAccessor<
2033 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2034 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
2035 public:
SlowSloppyArgumentsElementsAccessor(const char * name)2036 explicit SlowSloppyArgumentsElementsAccessor(const char* name)
2037 : SloppyArgumentsElementsAccessor<
2038 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
2039 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2040
DeleteFromArguments(Handle<JSObject> obj,uint32_t entry)2041 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2042 Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
2043 Handle<SeededNumberDictionary> dict(
2044 SeededNumberDictionary::cast(parameter_map->get(1)));
2045 // TODO(verwaest): Remove reliance on index in Shrink.
2046 uint32_t index = GetIndexForEntryImpl(*dict, entry);
2047 Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
2048 USE(result);
2049 DCHECK(result->IsTrue());
2050 Handle<FixedArray> new_elements =
2051 SeededNumberDictionary::Shrink(dict, index);
2052 parameter_map->set(1, *new_elements);
2053 }
2054
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)2055 static void AddImpl(Handle<JSObject> object, uint32_t index,
2056 Handle<Object> value, PropertyAttributes attributes,
2057 uint32_t new_capacity) {
2058 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2059 Handle<FixedArrayBase> old_elements(
2060 FixedArrayBase::cast(parameter_map->get(1)));
2061 Handle<SeededNumberDictionary> dictionary =
2062 old_elements->IsSeededNumberDictionary()
2063 ? Handle<SeededNumberDictionary>::cast(old_elements)
2064 : JSObject::NormalizeElements(object);
2065 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2066 Handle<SeededNumberDictionary> new_dictionary =
2067 SeededNumberDictionary::AddNumberEntry(
2068 dictionary, index, value, details,
2069 object->map()->is_prototype_map());
2070 if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
2071 if (*dictionary != *new_dictionary) {
2072 FixedArray::cast(object->elements())->set(1, *new_dictionary);
2073 }
2074 }
2075
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)2076 static void ReconfigureImpl(Handle<JSObject> object,
2077 Handle<FixedArrayBase> store, uint32_t entry,
2078 Handle<Object> value,
2079 PropertyAttributes attributes) {
2080 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
2081 uint32_t length = parameter_map->length() - 2;
2082 if (entry < length) {
2083 Object* probe = parameter_map->get(entry + 2);
2084 DCHECK(!probe->IsTheHole());
2085 Context* context = Context::cast(parameter_map->get(0));
2086 int context_entry = Smi::cast(probe)->value();
2087 DCHECK(!context->get(context_entry)->IsTheHole());
2088 context->set(context_entry, *value);
2089
2090 // Redefining attributes of an aliased element destroys fast aliasing.
2091 parameter_map->set_the_hole(entry + 2);
2092 // For elements that are still writable we re-establish slow aliasing.
2093 if ((attributes & READ_ONLY) == 0) {
2094 Isolate* isolate = store->GetIsolate();
2095 value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
2096 }
2097
2098 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
2099 Handle<SeededNumberDictionary> arguments(
2100 SeededNumberDictionary::cast(parameter_map->get(1)));
2101 arguments = SeededNumberDictionary::AddNumberEntry(
2102 arguments, entry, value, details, object->map()->is_prototype_map());
2103 // If the attributes were NONE, we would have called set rather than
2104 // reconfigure.
2105 DCHECK_NE(NONE, attributes);
2106 object->RequireSlowElements(*arguments);
2107 parameter_map->set(1, *arguments);
2108 } else {
2109 Handle<FixedArrayBase> arguments(
2110 FixedArrayBase::cast(parameter_map->get(1)));
2111 DictionaryElementsAccessor::ReconfigureImpl(
2112 object, arguments, entry - length, value, attributes);
2113 }
2114 }
2115 };
2116
2117
2118 class FastSloppyArgumentsElementsAccessor
2119 : public SloppyArgumentsElementsAccessor<
2120 FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
2121 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
2122 public:
FastSloppyArgumentsElementsAccessor(const char * name)2123 explicit FastSloppyArgumentsElementsAccessor(const char* name)
2124 : SloppyArgumentsElementsAccessor<
2125 FastSloppyArgumentsElementsAccessor,
2126 FastHoleyObjectElementsAccessor,
2127 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
2128
DeleteFromArguments(Handle<JSObject> obj,uint32_t entry)2129 static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
2130 FixedArray* parameter_map = FixedArray::cast(obj->elements());
2131 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
2132 FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
2133 }
2134
AddImpl(Handle<JSObject> object,uint32_t index,Handle<Object> value,PropertyAttributes attributes,uint32_t new_capacity)2135 static void AddImpl(Handle<JSObject> object, uint32_t index,
2136 Handle<Object> value, PropertyAttributes attributes,
2137 uint32_t new_capacity) {
2138 DCHECK_EQ(NONE, attributes);
2139 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2140 Handle<FixedArrayBase> old_elements(
2141 FixedArrayBase::cast(parameter_map->get(1)));
2142 if (old_elements->IsSeededNumberDictionary() ||
2143 static_cast<uint32_t>(old_elements->length()) < new_capacity) {
2144 GrowCapacityAndConvertImpl(object, new_capacity);
2145 }
2146 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
2147 // For fast holey objects, the entry equals the index. The code above made
2148 // sure that there's enough space to store the value. We cannot convert
2149 // index to entry explicitly since the slot still contains the hole, so the
2150 // current EntryForIndex would indicate that it is "absent" by returning
2151 // kMaxUInt32.
2152 FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
2153 }
2154
ReconfigureImpl(Handle<JSObject> object,Handle<FixedArrayBase> store,uint32_t entry,Handle<Object> value,PropertyAttributes attributes)2155 static void ReconfigureImpl(Handle<JSObject> object,
2156 Handle<FixedArrayBase> store, uint32_t entry,
2157 Handle<Object> value,
2158 PropertyAttributes attributes) {
2159 Handle<SeededNumberDictionary> dictionary =
2160 JSObject::NormalizeElements(object);
2161 FixedArray::cast(*store)->set(1, *dictionary);
2162 uint32_t length = static_cast<uint32_t>(store->length()) - 2;
2163 if (entry >= length) {
2164 entry = dictionary->FindEntry(entry - length) + length;
2165 }
2166 SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
2167 value, attributes);
2168 }
2169
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)2170 static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
2171 FixedArrayBase* to, ElementsKind from_kind,
2172 uint32_t to_start, int packed_size,
2173 int copy_size) {
2174 DCHECK(!to->IsDictionary());
2175 if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
2176 CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
2177 to_start, copy_size);
2178 } else {
2179 DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
2180 CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
2181 FAST_HOLEY_ELEMENTS, to_start, copy_size);
2182 }
2183 }
2184
GrowCapacityAndConvertImpl(Handle<JSObject> object,uint32_t capacity)2185 static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
2186 uint32_t capacity) {
2187 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
2188 Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
2189 ElementsKind from_kind = object->GetElementsKind();
2190 // This method should only be called if there's a reason to update the
2191 // elements.
2192 DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
2193 static_cast<uint32_t>(old_elements->length()) < capacity);
2194 Handle<FixedArrayBase> elements =
2195 ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
2196 Handle<Map> new_map = JSObject::GetElementsTransitionMap(
2197 object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
2198 JSObject::MigrateToMap(object, new_map);
2199 parameter_map->set(1, *elements);
2200 JSObject::ValidateElements(object);
2201 }
2202 };
2203
2204
2205 } // namespace
2206
2207
CheckArrayAbuse(Handle<JSObject> obj,const char * op,uint32_t index,bool allow_appending)2208 void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
2209 bool allow_appending) {
2210 DisallowHeapAllocation no_allocation;
2211 Object* raw_length = NULL;
2212 const char* elements_type = "array";
2213 if (obj->IsJSArray()) {
2214 JSArray* array = JSArray::cast(*obj);
2215 raw_length = array->length();
2216 } else {
2217 raw_length = Smi::FromInt(obj->elements()->length());
2218 elements_type = "object";
2219 }
2220
2221 if (raw_length->IsNumber()) {
2222 double n = raw_length->Number();
2223 if (FastI2D(FastD2UI(n)) == n) {
2224 int32_t int32_length = DoubleToInt32(n);
2225 uint32_t compare_length = static_cast<uint32_t>(int32_length);
2226 if (allow_appending) compare_length++;
2227 if (index >= compare_length) {
2228 PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
2229 elements_type, op, elements_type, static_cast<int>(int32_length),
2230 static_cast<int>(index));
2231 TraceTopFrame(obj->GetIsolate());
2232 PrintF("]\n");
2233 }
2234 } else {
2235 PrintF("[%s elements length not integer value in ", elements_type);
2236 TraceTopFrame(obj->GetIsolate());
2237 PrintF("]\n");
2238 }
2239 } else {
2240 PrintF("[%s elements length not a number in ", elements_type);
2241 TraceTopFrame(obj->GetIsolate());
2242 PrintF("]\n");
2243 }
2244 }
2245
2246
ArrayConstructInitializeElements(Handle<JSArray> array,Arguments * args)2247 MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
2248 Arguments* args) {
2249 if (args->length() == 0) {
2250 // Optimize the case where there are no parameters passed.
2251 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2252 return array;
2253
2254 } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
2255 uint32_t length;
2256 if (!args->at<Object>(0)->ToArrayLength(&length)) {
2257 return ThrowArrayLengthRangeError(array->GetIsolate());
2258 }
2259
2260 // Optimize the case where there is one argument and the argument is a small
2261 // smi.
2262 if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
2263 ElementsKind elements_kind = array->GetElementsKind();
2264 JSArray::Initialize(array, length, length);
2265
2266 if (!IsFastHoleyElementsKind(elements_kind)) {
2267 elements_kind = GetHoleyElementsKind(elements_kind);
2268 JSObject::TransitionElementsKind(array, elements_kind);
2269 }
2270 } else if (length == 0) {
2271 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
2272 } else {
2273 // Take the argument as the length.
2274 JSArray::Initialize(array, 0);
2275 JSArray::SetLength(array, length);
2276 }
2277 return array;
2278 }
2279
2280 Factory* factory = array->GetIsolate()->factory();
2281
2282 // Set length and elements on the array.
2283 int number_of_elements = args->length();
2284 JSObject::EnsureCanContainElements(
2285 array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
2286
2287 // Allocate an appropriately typed elements array.
2288 ElementsKind elements_kind = array->GetElementsKind();
2289 Handle<FixedArrayBase> elms;
2290 if (IsFastDoubleElementsKind(elements_kind)) {
2291 elms = Handle<FixedArrayBase>::cast(
2292 factory->NewFixedDoubleArray(number_of_elements));
2293 } else {
2294 elms = Handle<FixedArrayBase>::cast(
2295 factory->NewFixedArrayWithHoles(number_of_elements));
2296 }
2297
2298 // Fill in the content
2299 switch (array->GetElementsKind()) {
2300 case FAST_HOLEY_SMI_ELEMENTS:
2301 case FAST_SMI_ELEMENTS: {
2302 Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
2303 for (int entry = 0; entry < number_of_elements; entry++) {
2304 smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
2305 }
2306 break;
2307 }
2308 case FAST_HOLEY_ELEMENTS:
2309 case FAST_ELEMENTS: {
2310 DisallowHeapAllocation no_gc;
2311 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
2312 Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
2313 for (int entry = 0; entry < number_of_elements; entry++) {
2314 object_elms->set(entry, (*args)[entry], mode);
2315 }
2316 break;
2317 }
2318 case FAST_HOLEY_DOUBLE_ELEMENTS:
2319 case FAST_DOUBLE_ELEMENTS: {
2320 Handle<FixedDoubleArray> double_elms =
2321 Handle<FixedDoubleArray>::cast(elms);
2322 for (int entry = 0; entry < number_of_elements; entry++) {
2323 double_elms->set(entry, (*args)[entry]->Number());
2324 }
2325 break;
2326 }
2327 default:
2328 UNREACHABLE();
2329 break;
2330 }
2331
2332 array->set_elements(*elms);
2333 array->set_length(Smi::FromInt(number_of_elements));
2334 return array;
2335 }
2336
2337
InitializeOncePerProcess()2338 void ElementsAccessor::InitializeOncePerProcess() {
2339 static ElementsAccessor* accessor_array[] = {
2340 #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
2341 ELEMENTS_LIST(ACCESSOR_ARRAY)
2342 #undef ACCESSOR_ARRAY
2343 };
2344
2345 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
2346 kElementsKindCount);
2347
2348 elements_accessors_ = accessor_array;
2349 }
2350
2351
TearDown()2352 void ElementsAccessor::TearDown() {
2353 if (elements_accessors_ == NULL) return;
2354 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
2355 ELEMENTS_LIST(ACCESSOR_DELETE)
2356 #undef ACCESSOR_DELETE
2357 elements_accessors_ = NULL;
2358 }
2359
2360
Concat(Isolate * isolate,Arguments * args,uint32_t concat_size)2361 Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
2362 uint32_t concat_size) {
2363 int result_len = 0;
2364 ElementsKind elements_kind = GetInitialFastElementsKind();
2365 bool has_double = false;
2366 {
2367 DisallowHeapAllocation no_gc;
2368 // Iterate through all the arguments performing checks
2369 // and calculating total length.
2370 bool is_holey = false;
2371 for (uint32_t i = 0; i < concat_size; i++) {
2372 Object* arg = (*args)[i];
2373 int len = Smi::cast(JSArray::cast(arg)->length())->value();
2374
2375 // We shouldn't overflow when adding another len.
2376 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
2377 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
2378 USE(kHalfOfMaxInt);
2379 result_len += len;
2380 DCHECK(0 <= result_len);
2381 DCHECK(result_len <= FixedDoubleArray::kMaxLength);
2382
2383 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
2384 has_double = has_double || IsFastDoubleElementsKind(arg_kind);
2385 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
2386 elements_kind = GetMoreGeneralElementsKind(elements_kind, arg_kind);
2387 }
2388 if (is_holey) {
2389 elements_kind = GetHoleyElementsKind(elements_kind);
2390 }
2391 }
2392
2393 // If a double array is concatted into a fast elements array, the fast
2394 // elements array needs to be initialized to contain proper holes, since
2395 // boxing doubles may cause incremental marking.
2396 ArrayStorageAllocationMode mode =
2397 has_double && IsFastObjectElementsKind(elements_kind)
2398 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
2399 : DONT_INITIALIZE_ARRAY_ELEMENTS;
2400 Handle<JSArray> result_array = isolate->factory()->NewJSArray(
2401 elements_kind, result_len, result_len, Strength::WEAK, mode);
2402 if (result_len == 0) return result_array;
2403 int j = 0;
2404 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
2405 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
2406 for (uint32_t i = 0; i < concat_size; i++) {
2407 // It is crucial to keep |array| in a raw pointer form to avoid
2408 // performance degradation.
2409 JSArray* array = JSArray::cast((*args)[i]);
2410 int len = Smi::cast(array->length())->value();
2411 if (len > 0) {
2412 ElementsKind from_kind = array->GetElementsKind();
2413 accessor->CopyElements(array, 0, from_kind, storage, j, len);
2414 j += len;
2415 }
2416 }
2417
2418 DCHECK(j == result_len);
2419 return result_array;
2420 }
2421
2422 ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
2423 } // namespace internal
2424 } // namespace v8
2425