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