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