5 #include "src/elements.h" 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" 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" 66 static const int kPackedSizeNotKnown = -1;
68 enum Where { AT_START, AT_END };
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, \ 83 V(FastHoleyDoubleElementsAccessor, HOLEY_DOUBLE_ELEMENTS, FixedDoubleArray) \ 84 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, NumberDictionary) \ 85 V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS, \ 87 V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \ 89 V(FastStringWrapperElementsAccessor, FAST_STRING_WRAPPER_ELEMENTS, \ 91 V(SlowStringWrapperElementsAccessor, SLOW_STRING_WRAPPER_ELEMENTS, \ 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) 106 template<ElementsKind Kind>
class ElementsKindTraits {
108 typedef FixedArrayBase BackingStore;
111 #define ELEMENTS_TRAITS(Class, KindParam, Store) \ 113 class ElementsKindTraits<KindParam> { \ 115 static constexpr ElementsKind Kind = KindParam; \ 116 typedef Store BackingStore; \ 118 constexpr ElementsKind ElementsKindTraits<KindParam>::Kind; 119 ELEMENTS_LIST(ELEMENTS_TRAITS)
120 #undef ELEMENTS_TRAITS 122 V8_WARN_UNUSED_RESULT
123 MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
124 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
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;
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;
151 MemsetPointer(FixedArray::cast(to_base)->RawFieldOfElementAt(start),
152 roots.the_hole_value(), length);
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));
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);
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,
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;
189 MemsetPointer(FixedArray::cast(to_base)->RawFieldOfElementAt(start),
190 ReadOnlyRoots(isolate).the_hole_value(), length);
194 DCHECK(to_base != from_base);
195 DCHECK(IsSmiOrObjectElementsKind(to_kind));
196 if (copy_size == 0)
return;
197 FixedArray to = FixedArray::cast(to_base);
199 if (to_start + copy_size > to_length) {
200 copy_size = to_length - to_start;
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);
210 to->set_the_hole(isolate,
i + to_start);
218 static void CopyDoubleToObjectElements(Isolate* isolate,
219 FixedArrayBase from_base,
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) {
234 int start = to_start;
235 int length = to_base->length() - start;
237 MemsetPointer(FixedArray::cast(to_base)->RawFieldOfElementAt(start),
238 ReadOnlyRoots(isolate).the_hole_value(), length);
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;
249 Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
250 Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
256 while (offset < copy_size) {
257 HandleScope scope(isolate);
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);
267 static void CopyDoubleToDoubleElements(FixedArrayBase from_base,
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);
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));
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);
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);
325 to->set(to_start, Smi::ToInt(hole_or_smi));
330 static void CopyPackedSmiToDoubleElements(FixedArrayBase from_base,
332 FixedArrayBase to_base,
335 DisallowHeapAllocation no_allocation;
336 int copy_size = raw_copy_size;
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);
348 to_end = to_start +
static_cast<uint32_t>(copy_size);
351 to_end = to_start +
static_cast<uint32_t>(copy_size);
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));
368 static void CopyObjectToDoubleElements(FixedArrayBase from_base,
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);
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);
396 to->set(to_start, hole_or_object->Number());
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;
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);
417 if (copy_size == 0)
return;
418 FixedDoubleArray to = FixedDoubleArray::cast(to_base);
420 if (to_start + copy_size > to_length) {
421 copy_size = to_length - to_start;
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());
428 to->set_the_hole(
i + to_start);
433 static void TraceTopFrame(Isolate* isolate) {
434 StackFrameIterator it(isolate);
436 PrintF(
"unknown location (no JavaScript frames present)");
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 ");
447 raw_frame = it.frame();
450 JavaScriptFrame::PrintTop(isolate, stdout,
false,
true);
453 static void SortIndices(
454 Isolate* isolate, Handle<FixedArray> indices,
uint32_t sort_size,
455 WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER) {
458 AtomicSlot start(indices->GetFirstElementAddress());
459 std::sort(start, start + sort_size,
460 [isolate](Tagged_t elementA, Tagged_t elementB) {
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)) {
469 return a->Number() < b->Number();
471 return !b->IsSmi() && b->IsUndefined(isolate);
473 if (write_barrier_mode != SKIP_WRITE_BARRIER) {
474 FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(isolate->heap(), *indices, 0, sort_size);
478 static Maybe<bool> IncludesValueSlowPath(Isolate* isolate,
479 Handle<JSObject> receiver,
480 Handle<Object> value,
482 bool search_for_hole = value->IsUndefined(isolate);
483 for (
uint32_t k = start_from; k < length; ++k) {
484 LookupIterator it(isolate, receiver, k);
486 if (search_for_hole)
return Just(
true);
489 Handle<Object> element_k;
490 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k,
491 Object::GetProperty(&it), Nothing<bool>());
493 if (value->SameValueZero(*element_k))
return Just(
true);
499 static Maybe<int64_t> IndexOfValueSlowPath(Isolate* isolate,
500 Handle<JSObject> receiver,
501 Handle<Object> value,
504 for (
uint32_t k = start_from; k < length; ++k) {
505 LookupIterator it(isolate, receiver, k);
509 Handle<Object> element_k;
510 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
511 isolate, element_k, Object::GetProperty(&it), Nothing<int64_t>());
513 if (value->StrictEquals(*element_k))
return Just<int64_t>(k);
516 return Just<int64_t>(-1);
522 class InternalElementsAccessor :
public ElementsAccessor {
524 explicit InternalElementsAccessor(
const char* name)
525 : ElementsAccessor(name) {}
527 uint32_t GetEntryForIndex(Isolate* isolate, JSObject* holder,
528 FixedArrayBase backing_store,
531 PropertyDetails GetDetails(JSObject* holder,
uint32_t entry)
override = 0;
551 template <
typename Sub
class,
typename ElementsTraitsParam>
552 class ElementsAccessorBase :
public InternalElementsAccessor {
554 explicit ElementsAccessorBase(
const char* name)
555 : InternalElementsAccessor(name) {}
557 typedef ElementsTraitsParam ElementsTraits;
558 typedef typename ElementsTraitsParam::BackingStore BackingStore;
560 static ElementsKind kind() {
return ElementsTraits::Kind; }
562 static void ValidateContents(JSObject* holder,
int length) {}
564 static void ValidateImpl(JSObject* holder) {
565 FixedArrayBase fixed_array_base = holder->elements();
566 if (!fixed_array_base->IsHeapObject())
return;
568 if (fixed_array_base->IsFiller())
return;
570 if (holder->IsJSArray()) {
571 Object* length_obj = JSArray::cast(holder)->length();
572 if (length_obj->IsSmi()) {
573 length = Smi::ToInt(length_obj);
576 length = fixed_array_base->length();
578 Subclass::ValidateContents(holder, length);
581 void Validate(JSObject* holder)
final {
582 DisallowHeapAllocation no_gc;
583 Subclass::ValidateImpl(holder);
586 static bool IsPackedImpl(JSObject* holder, FixedArrayBase backing_store,
588 DisallowHeapAllocation no_gc;
589 if (IsFastPackedElementsKind(kind()))
return true;
590 Isolate* isolate = holder->GetIsolate();
592 if (!Subclass::HasElementImpl(isolate, holder,
i, backing_store,
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;
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);
617 bool HasElement(JSObject* holder,
uint32_t index,
619 return Subclass::HasElementImpl(holder->GetIsolate(), holder, index,
620 backing_store, filter);
623 static bool HasElementImpl(Isolate* isolate, JSObject* holder,
uint32_t index,
624 FixedArrayBase backing_store,
626 return Subclass::GetEntryForIndexImpl(isolate, holder, backing_store, index,
627 filter) != kMaxUInt32;
630 bool HasEntry(JSObject* holder,
uint32_t entry)
final {
631 return Subclass::HasEntryImpl(holder->GetIsolate(), holder->elements(),
635 static bool HasEntryImpl(Isolate* isolate, FixedArrayBase backing_store,
640 bool HasAccessors(JSObject* holder)
final {
641 return Subclass::HasAccessorsImpl(holder, holder->elements());
644 static bool HasAccessorsImpl(JSObject* holder, FixedArrayBase backing_store) {
648 Handle<Object> Get(Handle<JSObject> holder,
uint32_t entry)
final {
649 return Subclass::GetInternalImpl(holder, entry);
652 static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
654 return Subclass::GetImpl(holder->GetIsolate(), holder->elements(), entry);
657 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
659 uint32_t index = GetIndexForEntryImpl(backing_store, entry);
660 return handle(BackingStore::cast(backing_store)->
get(index), isolate);
663 void Set(Handle<JSObject> holder,
uint32_t entry, Object* value)
final {
664 Subclass::SetImpl(holder, entry, value);
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);
673 static void ReconfigureImpl(Handle<JSObject>
object,
674 Handle<FixedArrayBase> store,
uint32_t entry,
675 Handle<Object> value,
676 PropertyAttributes attributes) {
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);
685 static void AddImpl(Handle<JSObject>
object,
uint32_t index,
686 Handle<Object> value, PropertyAttributes attributes,
691 uint32_t Push(Handle<JSArray> receiver, Arguments* args,
693 return Subclass::PushImpl(receiver, args, push_size);
696 static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args,
701 uint32_t Unshift(Handle<JSArray> receiver, Arguments* args,
703 return Subclass::UnshiftImpl(receiver, args, unshift_size);
706 static uint32_t UnshiftImpl(Handle<JSArray> receiver, Arguments* args,
711 Handle<JSObject> Slice(Handle<JSObject> receiver,
uint32_t start,
713 return Subclass::SliceImpl(receiver, start, end);
716 static Handle<JSObject> SliceImpl(Handle<JSObject> receiver,
uint32_t start,
721 Handle<Object> Pop(Handle<JSArray> receiver)
final {
722 return Subclass::PopImpl(receiver);
725 static Handle<Object> PopImpl(Handle<JSArray> receiver) {
729 Handle<Object> Shift(Handle<JSArray> receiver)
final {
730 return Subclass::ShiftImpl(receiver);
733 static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
737 void SetLength(Handle<JSArray> array,
uint32_t length)
final {
738 Subclass::SetLengthImpl(array->GetIsolate(), array, length,
739 handle(array->elements(), array->GetIsolate()));
742 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
744 Handle<FixedArrayBase> backing_store) {
745 DCHECK(!array->SetLengthWouldNormalize(length));
746 DCHECK(IsFastElementsKind(array->GetElementsKind()));
748 CHECK(array->length()->ToArrayIndex(&old_length));
750 if (old_length < length) {
751 ElementsKind kind = array->GetElementsKind();
752 if (!IsHoleyElementsKind(kind)) {
753 kind = GetHoleyElementsKind(kind);
754 JSObject::TransitionElementsKind(array, kind);
759 uint32_t capacity = backing_store->length();
760 old_length = Min(old_length, capacity);
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);
770 if (2 * length + JSObject::kMinAddedElementsCapacity <= capacity) {
775 int elements_to_trim = length + 1 == old_length
776 ? (capacity - length) / 2
778 isolate->heap()->RightTrimFixedArray(*backing_store, elements_to_trim);
780 BackingStore::cast(*backing_store)
781 ->FillWithHoles(length,
782 std::min(old_length, capacity - elements_to_trim));
785 BackingStore::cast(*backing_store)->FillWithHoles(length, old_length);
789 capacity = Max(length, JSObject::NewElementsCapacity(capacity));
790 Subclass::GrowCapacityAndConvertImpl(array, capacity);
793 array->set_length(Smi::FromInt(length));
794 JSObject::ValidateElements(*array);
797 uint32_t NumberOfElements(JSObject* receiver)
final {
798 return Subclass::NumberOfElementsImpl(receiver, receiver->elements());
801 static uint32_t NumberOfElementsImpl(JSObject* receiver,
802 FixedArrayBase backing_store) {
806 static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase elements) {
807 if (receiver->IsJSArray()) {
808 DCHECK(JSArray::cast(receiver)->length()->IsSmi());
810 Smi::ToInt(JSArray::cast(receiver)->length()));
812 return Subclass::GetCapacityImpl(receiver, elements);
815 static uint32_t GetMaxNumberOfEntries(JSObject* receiver,
816 FixedArrayBase elements) {
817 return Subclass::GetMaxIndex(receiver, elements);
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);
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);
835 static Handle<FixedArrayBase> ConvertElementsWithCapacity(
836 Handle<JSObject>
object, Handle<FixedArrayBase> old_elements,
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);
844 new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
847 int packed_size = kPackedSizeNotKnown;
848 if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
849 packed_size = Smi::ToInt(JSArray::cast(*object)->length());
852 Subclass::CopyElementsImpl(isolate, *old_elements, src_index, *new_elements,
853 from_kind, dst_index, packed_size, copy_size);
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);
866 if (from_kind != to_kind) {
868 DCHECK(IsFastElementsKind(from_kind));
869 DCHECK(IsFastElementsKind(to_kind));
870 DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
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)) {
879 JSObject::MigrateToMap(
object, to_map);
882 (IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) ||
883 (IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind)));
885 Handle<FixedArrayBase> elements = ConvertElementsWithCapacity(
886 object, from_elements, from_kind, capacity);
887 JSObject::SetMapAndElements(
object, to_map, elements);
889 if (FLAG_trace_elements_transitions) {
890 JSObject::PrintElementsTransition(
891 stdout,
object, from_kind, from_elements, to_kind,
892 handle(object->elements(),
object->GetIsolate()));
897 static void GrowCapacityAndConvertImpl(Handle<JSObject>
object,
899 ElementsKind from_kind =
object->GetElementsKind();
900 if (IsSmiOrObjectElementsKind(from_kind)) {
904 object->GetIsolate()->UpdateNoElementsProtectorOnSetLength(
object);
906 Handle<FixedArrayBase> old_elements(object->elements(),
907 object->GetIsolate());
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,
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);
923 if (IsHoleyElementsKind(from_kind)) {
924 to_kind = GetHoleyElementsKind(to_kind);
926 Handle<Map> new_map = JSObject::GetElementsTransitionMap(
object, to_kind);
927 JSObject::SetMapAndElements(
object, new_map, elements);
930 JSObject::UpdateAllocationSite(
object, to_kind);
932 if (FLAG_trace_elements_transitions) {
933 JSObject::PrintElementsTransition(stdout,
object, from_kind, old_elements,
938 void TransitionElementsKind(Handle<JSObject>
object, Handle<Map> map)
final {
939 Subclass::TransitionElementsKindImpl(
object, map);
942 void GrowCapacityAndConvert(Handle<JSObject>
object,
944 Subclass::GrowCapacityAndConvertImpl(
object, capacity);
947 bool GrowCapacity(Handle<JSObject>
object,
uint32_t index)
final {
950 if (object->map()->is_prototype_map() ||
951 object->WouldConvertToSlowElements(index)) {
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);
961 DCHECK_EQ(object->GetElementsKind(), kind());
963 if (JSObject::UpdateAllocationSite<AllocationSiteUpdateMode::kCheckOnly>(
968 object->set_elements(*elements);
972 void Delete(Handle<JSObject> obj,
uint32_t entry)
final {
973 Subclass::DeleteImpl(obj, entry);
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) {
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();
990 packed_size = Smi::ToInt(JSArray::cast(from_holder)->length());
991 if (copy_size >= 0 && packed_size > copy_size) {
992 packed_size = copy_size;
995 FixedArrayBase from = from_holder->elements();
1005 Subclass::CopyElementsImpl(from_holder->GetIsolate(), from, from_start, *to,
1006 from_kind, to_start, packed_size, copy_size);
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);
1016 void CopyTypedArrayElementsSlice(JSTypedArray* source,
1017 JSTypedArray* destination,
size_t start,
1018 size_t end)
override {
1019 Subclass::CopyTypedArrayElementsSliceImpl(source, destination, start, end);
1022 static void CopyTypedArrayElementsSliceImpl(JSTypedArray* source,
1023 JSTypedArray* destination,
1024 size_t start,
size_t end) {
1028 Object* CopyElements(Handle<Object> source, Handle<JSObject> destination,
1029 size_t length,
uint32_t offset)
final {
1030 return Subclass::CopyElementsHandleImpl(source, destination, length,
1034 static Object* CopyElementsHandleImpl(Handle<Object> source,
1035 Handle<JSObject> destination,
1040 Handle<NumberDictionary> Normalize(Handle<JSObject>
object)
final {
1041 return Subclass::NormalizeImpl(
1042 object, handle(object->elements(),
object->GetIsolate()));
1045 static Handle<NumberDictionary> NormalizeImpl(
1046 Handle<JSObject>
object, Handle<FixedArrayBase> elements) {
1050 Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject>
object,
1051 Handle<FixedArray> values_or_entries,
1052 bool get_entries,
int* nof_items,
1054 return Subclass::CollectValuesOrEntriesImpl(
1055 isolate,
object, values_or_entries, get_entries, nof_items, filter);
1058 static Maybe<bool> CollectValuesOrEntriesImpl(
1059 Isolate* isolate, Handle<JSObject>
object,
1060 Handle<FixedArray> values_or_entries,
bool get_entries,
int* nof_items,
1062 DCHECK_EQ(*nof_items, 0);
1063 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
1065 Subclass::CollectElementIndicesImpl(
1066 object, handle(object->elements(), isolate), &accumulator);
1067 Handle<FixedArray> keys = accumulator.GetKeys();
1071 ElementsKind original_elements_kind =
object->GetElementsKind();
1073 for (;
i < keys->length(); ++
i) {
1074 Handle<Object> key(keys->get(
i), isolate);
1076 if (!key->ToUint32(&index))
continue;
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);
1084 Handle<Object> value;
1085 if (details.kind() == kData) {
1086 value = Subclass::GetImpl(isolate, object->elements(), entry);
1089 LookupIterator it(isolate,
object, index, LookupIterator::OWN);
1090 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1091 isolate, value, Object::GetProperty(&it), Nothing<bool>());
1093 if (get_entries) value = MakeEntryPair(isolate, index, value);
1094 values_or_entries->set(count++, *value);
1095 if (object->GetElementsKind() != original_elements_kind)
break;
1099 for (;
i < keys->length();
i++) {
1100 Handle<Object> key(keys->get(
i), isolate);
1102 if (!key->ToUint32(&index))
continue;
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;
1115 Handle<Object> value;
1116 LookupIterator it(isolate,
object, index, LookupIterator::OWN);
1117 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::GetProperty(&it),
1120 if (get_entries) value = MakeEntryPair(isolate, index, value);
1121 values_or_entries->set(count++, *value);
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);
1135 static void CollectElementIndicesImpl(Handle<JSObject>
object,
1136 Handle<FixedArrayBase> backing_store,
1137 KeyAccumulator* keys) {
1138 DCHECK_NE(DICTIONARY_ELEMENTS, kind());
1140 uint32_t length = Subclass::GetMaxIndex(*
object, *backing_store);
1142 Isolate* isolate = keys->isolate();
1143 Factory* factory = isolate->factory();
1145 if (Subclass::HasElementImpl(isolate, *
object,
i, *backing_store,
1147 keys->AddKey(factory->NewNumberFromUint(
i));
1152 static Handle<FixedArray> DirectCollectElementIndicesImpl(
1153 Isolate* isolate, Handle<JSObject>
object,
1154 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1157 uint32_t length = Subclass::GetMaxIndex(*
object, *backing_store);
1158 uint32_t const kMaxStringTableEntries =
1159 isolate->heap()->MaxNumberToStringCacheSize();
1161 if (Subclass::HasElementImpl(isolate, *
object,
i, *backing_store,
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);
1169 list->set(insertion_index, Smi::FromInt(
i), SKIP_WRITE_BARRIER);
1174 *nof_indices = insertion_index;
1178 MaybeHandle<FixedArray> PrependElementIndices(
1179 Handle<JSObject>
object, Handle<FixedArrayBase> backing_store,
1180 Handle<FixedArray> keys, GetKeysConversion convert,
1182 return Subclass::PrependElementIndicesImpl(
object, backing_store, keys,
1186 static MaybeHandle<FixedArray> PrependElementIndicesImpl(
1187 Handle<JSObject>
object, Handle<FixedArrayBase> backing_store,
1188 Handle<FixedArray> keys, GetKeysConversion convert,
1190 Isolate* isolate =
object->GetIsolate();
1191 uint32_t nof_property_keys = keys->length();
1193 Subclass::GetMaxNumberOfEntries(*
object, *backing_store);
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));
1203 MaybeHandle<FixedArray> raw_array =
1204 isolate->factory()->TryNewFixedArray(initial_list_length);
1205 Handle<FixedArray> combined_keys;
1210 if (!raw_array.ToHandle(&combined_keys)) {
1211 if (IsHoleyOrDictionaryElementsKind(kind())) {
1216 initial_list_length =
1217 Subclass::NumberOfElementsImpl(*
object, *backing_store);
1218 initial_list_length += nof_property_keys;
1220 combined_keys = isolate->factory()->NewFixedArray(initial_list_length);
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);
1231 if (needs_sorting) {
1232 SortIndices(isolate, combined_keys, nof_indices);
1235 if (convert == GetKeysConversion::kConvertToString) {
1237 Handle<Object> index_string = isolate->factory()->Uint32ToString(
1238 combined_keys->get(
i)->Number());
1239 combined_keys->set(
i, *index_string);
1245 CopyObjectToObjectElements(isolate, *keys, PACKED_ELEMENTS, 0,
1246 *combined_keys, PACKED_ELEMENTS, nof_indices,
1251 if (IsHoleyOrDictionaryElementsKind(kind()) ||
1252 IsSloppyArgumentsElementsKind(kind())) {
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);
1259 return combined_keys;
1262 void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
1263 KeyAccumulator* accumulator,
1264 AddKeyConversion convert)
final {
1265 Subclass::AddElementsToKeyAccumulatorImpl(receiver, accumulator, convert);
1268 static uint32_t GetCapacityImpl(JSObject* holder,
1269 FixedArrayBase backing_store) {
1270 return backing_store->length();
1273 uint32_t GetCapacity(JSObject* holder, FixedArrayBase backing_store)
final {
1274 return Subclass::GetCapacityImpl(holder, backing_store);
1277 static Object* FillImpl(Handle<JSObject> receiver, Handle<Object> obj_value,
1282 Object* Fill(Handle<JSObject> receiver, Handle<Object> obj_value,
1284 return Subclass::FillImpl(receiver, obj_value, start, end);
1287 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1288 Handle<JSObject> receiver,
1289 Handle<Object> value,
1291 return IncludesValueSlowPath(isolate, receiver, value, start_from, length);
1294 Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
1295 Handle<Object> value,
uint32_t start_from,
1297 return Subclass::IncludesValueImpl(isolate, receiver, value, start_from,
1301 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
1302 Handle<JSObject> receiver,
1303 Handle<Object> value,
1305 return IndexOfValueSlowPath(isolate, receiver, value, start_from, length);
1308 Maybe<int64_t> IndexOfValue(Isolate* isolate, Handle<JSObject> receiver,
1309 Handle<Object> value,
uint32_t start_from,
1311 return Subclass::IndexOfValueImpl(isolate, receiver, value, start_from,
1315 static Maybe<int64_t> LastIndexOfValueImpl(Handle<JSObject> receiver,
1316 Handle<Object> value,
1321 Maybe<int64_t> LastIndexOfValue(Handle<JSObject> receiver,
1322 Handle<Object> value,
1324 return Subclass::LastIndexOfValueImpl(receiver, value, start_from);
1327 static void ReverseImpl(JSObject* receiver) { UNREACHABLE(); }
1329 void Reverse(JSObject* receiver)
final { Subclass::ReverseImpl(receiver); }
1331 static uint32_t GetIndexForEntryImpl(FixedArrayBase backing_store,
1336 static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
1337 FixedArrayBase backing_store,
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)
1348 return index < length ? index : kMaxUInt32;
1352 uint32_t GetEntryForIndex(Isolate* isolate, JSObject* holder,
1353 FixedArrayBase backing_store,
1355 return Subclass::GetEntryForIndexImpl(isolate, holder, backing_store, index,
1359 static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
1361 return PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
1364 static PropertyDetails GetDetailsImpl(JSObject* holder,
uint32_t entry) {
1365 return PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
1368 PropertyDetails GetDetails(JSObject* holder,
uint32_t entry)
final {
1369 return Subclass::GetDetailsImpl(holder, entry);
1372 Handle<FixedArray> CreateListFromArrayLike(Isolate* isolate,
1373 Handle<JSObject>
object,
1375 return Subclass::CreateListFromArrayLikeImpl(isolate,
object, length);
1378 static Handle<FixedArray> CreateListFromArrayLikeImpl(Isolate* isolate,
1379 Handle<JSObject>
object,
1385 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
1389 class DictionaryElementsAccessor
1390 :
public ElementsAccessorBase<DictionaryElementsAccessor,
1391 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
1393 explicit DictionaryElementsAccessor(
const char* name)
1394 : ElementsAccessorBase<DictionaryElementsAccessor,
1395 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
1397 static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase elements) {
1402 static uint32_t GetMaxNumberOfEntries(JSObject* receiver,
1403 FixedArrayBase backing_store) {
1404 return NumberOfElementsImpl(receiver, backing_store);
1407 static uint32_t NumberOfElementsImpl(JSObject* receiver,
1408 FixedArrayBase backing_store) {
1409 NumberDictionary dict = NumberDictionary::cast(backing_store);
1410 return dict->NumberOfElements();
1413 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
1415 Handle<FixedArrayBase> backing_store) {
1416 Handle<NumberDictionary> dict =
1417 Handle<NumberDictionary>::cast(backing_store);
1418 int capacity = dict->Capacity();
1420 CHECK(array->length()->ToArrayLength(&old_length));
1422 DisallowHeapAllocation no_gc;
1423 ReadOnlyRoots roots(isolate);
1424 if (length < old_length) {
1425 if (dict->requires_slow_elements()) {
1428 for (
int entry = 0; entry < capacity; entry++) {
1429 Object* index = dict->KeyAt(entry);
1430 if (dict->IsKey(roots, index)) {
1432 if (length <= number && number < old_length) {
1433 PropertyDetails details = dict->DetailsAt(entry);
1434 if (!details.IsConfigurable()) length = number + 1;
1442 array->initialize_elements();
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)) {
1450 if (length <= number && number < old_length) {
1451 dict->ClearEntry(isolate, entry);
1457 if (removed_entries > 0) {
1459 dict->ElementsRemoved(removed_entries);
1465 Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
1466 array->set_length(*length_obj);
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) {
1476 static Handle<JSObject> SliceImpl(Handle<JSObject> receiver,
uint32_t start,
1478 Isolate* isolate = receiver->GetIsolate();
1479 uint32_t result_length = end < start ? 0u : end - start;
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,
1505 return result_array;
1508 static void DeleteImpl(Handle<JSObject> obj,
uint32_t entry) {
1509 Handle<NumberDictionary> dict(NumberDictionary::cast(obj->elements()),
1511 dict = NumberDictionary::DeleteEntry(obj->GetIsolate(), dict, entry);
1512 obj->set_elements(*dict);
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;
1530 static Object* GetRaw(FixedArrayBase store,
uint32_t entry) {
1531 NumberDictionary backing_store = NumberDictionary::cast(store);
1532 return backing_store->ValueAt(entry);
1535 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
1537 return handle(GetRaw(backing_store, entry), isolate);
1540 static inline void SetImpl(Handle<JSObject> holder,
uint32_t entry,
1542 SetImpl(holder->elements(), entry, value);
1545 static inline void SetImpl(FixedArrayBase backing_store,
uint32_t entry,
1547 NumberDictionary::cast(backing_store)->ValueAtPut(entry, value);
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());
1561 dictionary->DetailsAtPut(object->GetIsolate(), entry, details);
1564 static void AddImpl(Handle<JSObject>
object,
uint32_t index,
1565 Handle<Object> value, PropertyAttributes attributes,
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);
1581 static bool HasEntryImpl(Isolate* isolate, FixedArrayBase store,
1583 DisallowHeapAllocation no_gc;
1584 NumberDictionary dict = NumberDictionary::cast(store);
1585 Object* index = dict->KeyAt(entry);
1586 return !index->IsTheHole(isolate);
1589 static uint32_t GetIndexForEntryImpl(FixedArrayBase store,
uint32_t entry) {
1590 DisallowHeapAllocation no_gc;
1591 NumberDictionary dict = NumberDictionary::cast(store);
1593 CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
1597 static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
1598 FixedArrayBase store,
uint32_t index,
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;
1609 return static_cast<uint32_t>(entry);
1612 static PropertyDetails GetDetailsImpl(JSObject* holder,
uint32_t entry) {
1613 return GetDetailsImpl(holder->elements(), entry);
1616 static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
1618 return NumberDictionary::cast(backing_store)->DetailsAt(entry);
1621 static uint32_t FilterKey(Handle<NumberDictionary> dictionary,
int entry,
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());
1631 static uint32_t GetKeyForEntryImpl(Isolate* isolate,
1632 Handle<NumberDictionary> dictionary,
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);
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;
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);
1661 elements->set(insertion_index, raw_key);
1664 SortIndices(isolate, elements, insertion_index);
1665 for (
int i = 0;
i < insertion_index;
i++) {
1666 keys->AddKey(elements->get(
i));
1670 static Handle<FixedArray> DirectCollectElementIndicesImpl(
1671 Isolate* isolate, Handle<JSObject>
object,
1672 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
1675 if (filter & SKIP_STRINGS)
return list;
1676 if (filter & ONLY_ALL_CAN_READ)
return list;
1678 Handle<NumberDictionary> dictionary =
1679 Handle<NumberDictionary>::cast(backing_store);
1680 uint32_t capacity = dictionary->Capacity();
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);
1688 *nof_indices = insertion_index;
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);
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();
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;
1729 if (!k->ToArrayIndex(&index) || index < start_from || index >= length) {
1733 if (dictionary->DetailsAt(
i).kind() == kAccessor) {
1737 }
else if (!found) {
1738 Object* element_k = dictionary->ValueAt(
i);
1739 if (value->SameValueZero(element_k)) found =
true;
1743 *result = Just(found);
1747 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
1748 Handle<JSObject> receiver,
1749 Handle<Object> value,
1751 DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
1752 bool search_for_hole = value->IsUndefined(isolate);
1754 if (!search_for_hole) {
1755 Maybe<bool> result = Nothing<bool>();
1756 if (DictionaryElementsAccessor::IncludesValueFastPath(
1757 isolate, receiver, value, start_from, length, &result)) {
1761 ElementsKind original_elements_kind = receiver->GetElementsKind();
1762 USE(original_elements_kind);
1763 Handle<NumberDictionary> dictionary(
1764 NumberDictionary::cast(receiver->elements()), isolate);
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);
1775 PropertyDetails details = GetDetailsImpl(*dictionary, entry);
1776 switch (details.kind()) {
1778 Object* element_k = dictionary->ValueAt(entry);
1779 if (value->SameValueZero(element_k))
return Just(
true);
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;
1789 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1790 isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
1793 if (value->SameValueZero(*element_k))
return Just(
true);
1796 if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
1797 return IncludesValueSlowPath(isolate, receiver, value, k + 1,
1802 if (*dictionary == receiver->elements())
continue;
1808 if (receiver->map()->GetInitialElements() == receiver->elements()) {
1809 return Just(search_for_hole);
1813 if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
1814 ElementsAccessor* accessor = receiver->GetElementsAccessor();
1815 return accessor->IncludesValue(isolate, receiver, value, k + 1,
1819 handle(NumberDictionary::cast(receiver->elements()), isolate);
1827 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
1828 Handle<JSObject> receiver,
1829 Handle<Object> value,
1831 DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
1833 ElementsKind original_elements_kind = receiver->GetElementsKind();
1834 USE(original_elements_kind);
1835 Handle<NumberDictionary> dictionary(
1836 NumberDictionary::cast(receiver->elements()), isolate);
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;
1844 PropertyDetails details = GetDetailsImpl(*dictionary, entry);
1845 switch (details.kind()) {
1847 Object* element_k = dictionary->ValueAt(entry);
1848 if (value->StrictEquals(element_k)) {
1849 return Just<int64_t>(k);
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;
1860 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1861 isolate, element_k, JSObject::GetPropertyWithAccessor(&it),
1862 Nothing<int64_t>());
1864 if (value->StrictEquals(*element_k))
return Just<int64_t>(k);
1867 if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) {
1868 return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
1873 if (*dictionary == receiver->elements())
continue;
1876 if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) {
1878 return IndexOfValueSlowPath(isolate, receiver, value, k + 1,
1882 handle(NumberDictionary::cast(receiver->elements()), isolate);
1887 return Just<int64_t>(-1);
1890 static void ValidateContents(JSObject* holder,
int length) {
1891 DisallowHeapAllocation no_gc;
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());
1898 int capacity = dictionary->Capacity();
1899 bool requires_slow_elements =
false;
1901 for (
int i = 0;
i < capacity; ++
i) {
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;
1908 max_key = Max(max_key, Smi::ToInt(k));
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());
1922 template <
typename Sub
class,
typename KindTraits>
1923 class FastElementsAccessor :
public ElementsAccessorBase<Subclass, KindTraits> {
1925 explicit FastElementsAccessor(
const char* name)
1926 : ElementsAccessorBase<Subclass, KindTraits>(name) {}
1928 typedef typename KindTraits::BackingStore BackingStore;
1930 static Handle<NumberDictionary> NormalizeImpl(Handle<JSObject>
object,
1931 Handle<FixedArrayBase> store) {
1932 Isolate* isolate =
object->GetIsolate();
1933 ElementsKind kind = Subclass::kind();
1937 if (IsSmiOrObjectElementsKind(kind) ||
1938 kind == FAST_STRING_WRAPPER_ELEMENTS) {
1939 isolate->UpdateNoElementsProtectorOnNormalizeElements(
object);
1942 int capacity =
object->GetFastElementsUsage();
1943 Handle<NumberDictionary> dictionary =
1944 NumberDictionary::New(isolate, capacity);
1946 PropertyDetails details = PropertyDetails::Empty();
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;
1954 Handle<Object> value = Subclass::GetImpl(isolate, *store,
i);
1956 NumberDictionary::Add(isolate, dictionary,
i, value, details);
1960 if (max_number_key > 0) {
1961 dictionary->UpdateMaxNumberKey(static_cast<uint32_t>(max_number_key),
1967 static void DeleteAtEnd(Handle<JSObject> obj,
1968 Handle<BackingStore> backing_store,
uint32_t entry) {
1970 Isolate* isolate = obj->GetIsolate();
1971 for (; entry > 0; entry--) {
1972 if (!backing_store->is_the_hole(isolate, entry - 1))
break;
1975 FixedArray empty = ReadOnlyRoots(isolate).empty_fixed_array();
1978 if (obj->GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
1979 SloppyArgumentsElements::cast(obj->elements())->set_arguments(empty);
1981 obj->set_elements(empty);
1986 isolate->heap()->RightTrimFixedArray(*backing_store, length - entry);
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);
2001 Isolate* isolate = obj->GetIsolate();
2002 backing_store->set_the_hole(isolate, entry);
2007 const int kMinLengthForSparsenessCheck = 64;
2008 if (backing_store->length() < kMinLengthForSparsenessCheck)
return;
2009 if (Heap::InNewSpace(*backing_store))
return;
2011 if (obj->IsJSArray()) {
2012 JSArray::cast(*obj)->length()->ToArrayLength(&length);
2014 length =
static_cast<uint32_t>(store->length());
2018 const int kLengthFraction = 16;
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);
2032 isolate->set_elements_deletion_counter(0);
2034 if (!obj->IsJSArray()) {
2036 for (
i = entry + 1;
i < length;
i++) {
2037 if (!backing_store->is_the_hole(isolate,
i))
break;
2040 DeleteAtEnd(obj, backing_store, entry);
2045 for (
int i = 0;
i < backing_store->length(); ++
i) {
2046 if (!backing_store->is_the_hole(isolate,
i)) {
2049 if (NumberDictionary::kPreferFastElementsSizeFactor *
2050 NumberDictionary::ComputeCapacity(num_used) *
2051 NumberDictionary::kEntrySize >
2052 static_cast<uint32_t>(backing_store->length())) {
2057 JSObject::NormalizeElements(obj);
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);
2067 DictionaryElementsAccessor::ReconfigureImpl(
2068 object, Handle<FixedArrayBase>(dictionary.location()), entry, value,
2072 static void AddImpl(Handle<JSObject>
object,
uint32_t index,
2073 Handle<Object> value, PropertyAttributes attributes,
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()) !=
2082 Subclass::GrowCapacityAndConvertImpl(
object, new_capacity);
2084 if (IsFastElementsKind(from_kind) && from_kind != to_kind) {
2085 JSObject::TransitionElementsKind(
object, to_kind);
2087 if (IsSmiOrObjectElementsKind(from_kind)) {
2088 DCHECK(IsSmiOrObjectElementsKind(to_kind));
2089 JSObject::EnsureWritableFastElements(
object);
2092 Subclass::SetImpl(
object, index, *value);
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));
2100 if (IsSmiOrObjectElementsKind(KindTraits::Kind)) {
2101 JSObject::EnsureWritableFastElements(obj);
2103 DeleteCommon(obj, entry, handle(obj->elements(), obj->GetIsolate()));
2106 static bool HasEntryImpl(Isolate* isolate, FixedArrayBase backing_store,
2108 return !BackingStore::cast(backing_store)->is_the_hole(isolate, entry);
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();
2118 if (Subclass::HasEntryImpl(isolate, backing_store,
i)) count++;
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);
2130 if (IsFastPackedElementsKind(KindTraits::Kind) ||
2131 HasEntryImpl(isolate, *elements,
i)) {
2132 accumulator->AddKey(Subclass::GetImpl(isolate, *elements,
i), convert);
2137 static void ValidateContents(JSObject* holder,
int length) {
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);
2151 if (length == 0)
return;
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)));
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));
2168 DCHECK(IsHoleyElementsKind(KindTraits::Kind));
2174 static Handle<Object> PopImpl(Handle<JSArray> receiver) {
2175 return Subclass::RemoveElement(receiver, AT_END);
2178 static Handle<Object> ShiftImpl(Handle<JSArray> receiver) {
2179 return Subclass::RemoveElement(receiver, AT_START);
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,
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,
2198 static Handle<JSObject> SliceImpl(Handle<JSObject> receiver,
uint32_t start,
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;
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,
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)) {
2222 *dst_elms.location() =
2223 BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index))
2225 receiver->set_elements(*dst_elms);
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);
2234 if (hole_start != hole_end) {
2235 dst_elms->FillWithHoles(hole_start, hole_end);
2239 static Object* FillImpl(Handle<JSObject> receiver, Handle<Object> obj_value,
2242 DCHECK_LE(0, start);
2243 DCHECK_LE(start, end);
2246 if (IsSmiOrObjectElementsKind(Subclass::kind())) {
2247 JSObject::EnsureWritableFastElements(receiver);
2252 Subclass::GetCapacityImpl(*receiver, receiver->elements());
2253 if (end > capacity) {
2254 Subclass::GrowCapacityAndConvertImpl(receiver, end);
2255 CHECK_EQ(Subclass::kind(), receiver->GetElementsKind());
2257 DCHECK_LE(end, Subclass::GetCapacityImpl(*receiver, receiver->elements()));
2259 for (
uint32_t index = start; index < end; ++index) {
2260 Subclass::SetImpl(receiver, index, *obj_value);
2265 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
2266 Handle<JSObject> receiver,
2267 Handle<Object> search_value,
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;
2276 if (start_from >= length)
return Just(
false);
2280 if (value == undefined && elements_length < length)
return Just(
true);
2281 if (elements_length == 0) {
2282 DCHECK_NE(value, undefined);
2286 length = std::min(elements_length, length);
2288 if (!value->IsNumber()) {
2289 if (value == undefined) {
2294 if (IsSmiOrObjectElementsKind(Subclass::kind())) {
2295 auto elements = FixedArray::cast(receiver->elements());
2297 for (
uint32_t k = start_from; k < length; ++k) {
2298 Object* element_k = elements->get(k);
2300 if (element_k == the_hole || element_k == undefined) {
2308 DCHECK(IsDoubleElementsKind(Subclass::kind()));
2309 auto elements = FixedDoubleArray::cast(receiver->elements());
2311 for (
uint32_t k = start_from; k < length; ++k) {
2312 if (elements->is_the_hole(k)) {
2318 }
else if (!IsObjectElementsKind(Subclass::kind())) {
2327 DCHECK(IsObjectElementsKind(Subclass::kind()));
2328 auto elements = FixedArray::cast(receiver->elements());
2330 for (
uint32_t k = start_from; k < length; ++k) {
2331 Object* element_k = elements->get(k);
2332 if (element_k == the_hole) {
2336 if (value->SameValueZero(element_k))
return Just(
true);
2341 if (!value->IsNaN()) {
2342 double search_value = value->Number();
2343 if (IsDoubleElementsKind(Subclass::kind())) {
2347 auto elements = FixedDoubleArray::cast(receiver->elements());
2349 for (
uint32_t k = start_from; k < length; ++k) {
2350 if (elements->is_the_hole(k)) {
2353 if (elements->get_scalar(k) == search_value)
return Just(
true);
2360 auto elements = FixedArray::cast(receiver->elements());
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) {
2373 if (IsSmiElementsKind(Subclass::kind()))
return Just(
false);
2375 if (IsDoubleElementsKind(Subclass::kind())) {
2379 auto elements = FixedDoubleArray::cast(receiver->elements());
2381 for (
uint32_t k = start_from; k < length; ++k) {
2382 if (elements->is_the_hole(k)) {
2385 if (std::isnan(elements->get_scalar(k)))
return Just(
true);
2392 DCHECK(IsSmiOrObjectElementsKind(Subclass::kind()));
2393 auto elements = FixedArray::cast(receiver->elements());
2395 for (
uint32_t k = start_from; k < length; ++k) {
2396 if (elements->get(k)->IsNaN())
return Just(
true);
2404 static Handle<FixedArray> CreateListFromArrayLikeImpl(Isolate* isolate,
2405 Handle<JSObject>
object,
2407 Handle<FixedArray> result = isolate->factory()->NewFixedArray(length);
2408 Handle<FixedArrayBase> elements(object->elements(), isolate);
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));
2416 result->set(
i, *value);
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);
2429 Handle<FixedArrayBase> backing_store(receiver->elements(), isolate);
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,
2440 Subclass::SetLengthImpl(isolate, receiver, new_length, backing_store);
2442 if (IsHoleyElementsKind(kind) && result->IsTheHole(isolate)) {
2443 return isolate->factory()->undefined_value();
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();
2456 DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
2457 uint32_t new_length = length + add_size;
2459 if (new_length > elms_len) {
2461 uint32_t capacity = JSObject::NewElementsCapacity(new_length);
2463 int copy_dst_index = add_position == AT_START ? add_size : 0;
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) {
2472 Isolate* isolate = receiver->GetIsolate();
2473 Subclass::MoveElements(isolate, receiver, backing_store, add_size, 0,
2477 int insertion_index = add_position == AT_START ? 0 : length;
2479 Subclass::CopyArguments(args, backing_store, add_size, 1, insertion_index);
2481 receiver->set_length(Smi::FromInt(new_length));
2485 static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
2489 DisallowHeapAllocation no_gc;
2490 FixedArrayBase raw_backing_store = *dst_store;
2491 WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
2493 Object* argument = (*args)[src_index +
i];
2494 DCHECK(!argument->IsTheHole());
2495 Subclass::SetImpl(raw_backing_store, dst_index +
i, argument, mode);
2500 template <
typename Sub
class,
typename KindTraits>
2501 class FastSmiOrObjectElementsAccessor
2502 :
public FastElementsAccessor<Subclass, KindTraits> {
2504 explicit FastSmiOrObjectElementsAccessor(
const char* name)
2505 : FastElementsAccessor<Subclass, KindTraits>(name) {}
2507 static inline void SetImpl(Handle<JSObject> holder,
uint32_t entry,
2509 SetImpl(holder->elements(), entry, value);
2512 static inline void SetImpl(FixedArrayBase backing_store,
uint32_t entry,
2514 FixedArray::cast(backing_store)->set(entry, value);
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);
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);
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);
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,
2554 case DICTIONARY_ELEMENTS:
2555 CopyDictionaryToObjectElements(isolate, from, from_start, to, to_kind,
2556 to_start, copy_size);
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 2574 static Maybe<bool> CollectValuesOrEntriesImpl(
2575 Isolate* isolate, Handle<JSObject>
object,
2576 Handle<FixedArray> values_or_entries,
bool get_entries,
int* nof_items,
2581 Handle<FixedArray> elements(FixedArray::cast(object->elements()),
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);
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);
2605 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2606 Handle<JSObject> receiver,
2607 Handle<Object> search_value,
2609 DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2610 DisallowHeapAllocation no_gc;
2611 FixedArrayBase elements_base = receiver->elements();
2612 Object* value = *search_value;
2614 if (start_from >= length)
return Just<int64_t>(-1);
2616 length = std::min(static_cast<uint32_t>(elements_base->length()), length);
2619 if (!value->IsNumber() && !IsObjectElementsKind(Subclass::kind())) {
2620 return Just<int64_t>(-1);
2623 if (value->IsNaN())
return Just<int64_t>(-1);
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);
2633 return Just<int64_t>(-1);
2637 class FastPackedSmiElementsAccessor
2638 :
public FastSmiOrObjectElementsAccessor<
2639 FastPackedSmiElementsAccessor,
2640 ElementsKindTraits<PACKED_SMI_ELEMENTS>> {
2642 explicit FastPackedSmiElementsAccessor(
const char* name)
2643 : FastSmiOrObjectElementsAccessor<
2644 FastPackedSmiElementsAccessor,
2645 ElementsKindTraits<PACKED_SMI_ELEMENTS>>(name) {}
2648 class FastHoleySmiElementsAccessor
2649 :
public FastSmiOrObjectElementsAccessor<
2650 FastHoleySmiElementsAccessor,
2651 ElementsKindTraits<HOLEY_SMI_ELEMENTS>> {
2653 explicit FastHoleySmiElementsAccessor(
const char* name)
2654 : FastSmiOrObjectElementsAccessor<FastHoleySmiElementsAccessor,
2655 ElementsKindTraits<HOLEY_SMI_ELEMENTS>>(
2659 class FastPackedObjectElementsAccessor
2660 :
public FastSmiOrObjectElementsAccessor<
2661 FastPackedObjectElementsAccessor,
2662 ElementsKindTraits<PACKED_ELEMENTS>> {
2664 explicit FastPackedObjectElementsAccessor(
const char* name)
2665 : FastSmiOrObjectElementsAccessor<FastPackedObjectElementsAccessor,
2666 ElementsKindTraits<PACKED_ELEMENTS>>(
2670 class FastHoleyObjectElementsAccessor
2671 :
public FastSmiOrObjectElementsAccessor<
2672 FastHoleyObjectElementsAccessor, ElementsKindTraits<HOLEY_ELEMENTS>> {
2674 explicit FastHoleyObjectElementsAccessor(
const char* name)
2675 : FastSmiOrObjectElementsAccessor<FastHoleyObjectElementsAccessor,
2676 ElementsKindTraits<HOLEY_ELEMENTS>>(
2680 template <
typename Sub
class,
typename KindTraits>
2681 class FastDoubleElementsAccessor
2682 :
public FastElementsAccessor<Subclass, KindTraits> {
2684 explicit FastDoubleElementsAccessor(
const char* name)
2685 : FastElementsAccessor<Subclass, KindTraits>(name) {}
2687 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
2689 return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry,
2693 static inline void SetImpl(Handle<JSObject> holder,
uint32_t entry,
2695 SetImpl(holder->elements(), entry, value);
2698 static inline void SetImpl(FixedArrayBase backing_store,
uint32_t entry,
2700 FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
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());
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);
2718 case HOLEY_SMI_ELEMENTS:
2719 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
2721 case PACKED_DOUBLE_ELEMENTS:
2722 case HOLEY_DOUBLE_ELEMENTS:
2723 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
2725 case PACKED_ELEMENTS:
2726 case HOLEY_ELEMENTS:
2727 CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
2729 case DICTIONARY_ELEMENTS:
2730 CopyDictionaryToDoubleElements(isolate, from, from_start, to, to_start,
2733 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
2734 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
2735 case FAST_STRING_WRAPPER_ELEMENTS:
2736 case SLOW_STRING_WRAPPER_ELEMENTS:
2738 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 2739 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2740 #undef TYPED_ARRAY_CASE 2748 static Maybe<bool> CollectValuesOrEntriesImpl(
2749 Isolate* isolate, Handle<JSObject>
object,
2750 Handle<FixedArray> values_or_entries,
bool get_entries,
int* nof_items,
2752 Handle<FixedDoubleArray> elements(
2753 FixedDoubleArray::cast(object->elements()), isolate);
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);
2760 value = MakeEntryPair(isolate, index, value);
2762 values_or_entries->set(count++, *value);
2768 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
2769 Handle<JSObject> receiver,
2770 Handle<Object> search_value,
2772 DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver));
2773 DisallowHeapAllocation no_gc;
2774 FixedArrayBase elements_base = receiver->elements();
2775 Object* value = *search_value;
2777 length = std::min(static_cast<uint32_t>(elements_base->length()), length);
2779 if (start_from >= length)
return Just<int64_t>(-1);
2781 if (!value->IsNumber()) {
2782 return Just<int64_t>(-1);
2784 if (value->IsNaN()) {
2785 return Just<int64_t>(-1);
2787 double numeric_search_value = value->Number();
2788 FixedDoubleArray elements = FixedDoubleArray::cast(receiver->elements());
2790 for (
uint32_t k = start_from; k < length; ++k) {
2791 if (elements->is_the_hole(k)) {
2794 if (elements->get_scalar(k) == numeric_search_value) {
2795 return Just<int64_t>(k);
2798 return Just<int64_t>(-1);
2802 class FastPackedDoubleElementsAccessor
2803 :
public FastDoubleElementsAccessor<
2804 FastPackedDoubleElementsAccessor,
2805 ElementsKindTraits<PACKED_DOUBLE_ELEMENTS>> {
2807 explicit FastPackedDoubleElementsAccessor(
const char* name)
2808 : FastDoubleElementsAccessor<FastPackedDoubleElementsAccessor,
2809 ElementsKindTraits<PACKED_DOUBLE_ELEMENTS>>(
2813 class FastHoleyDoubleElementsAccessor
2814 :
public FastDoubleElementsAccessor<
2815 FastHoleyDoubleElementsAccessor,
2816 ElementsKindTraits<HOLEY_DOUBLE_ELEMENTS>> {
2818 explicit FastHoleyDoubleElementsAccessor(
const char* name)
2819 : FastDoubleElementsAccessor<FastHoleyDoubleElementsAccessor,
2820 ElementsKindTraits<HOLEY_DOUBLE_ELEMENTS>>(
2826 template <ElementsKind Kind,
typename ctype>
2827 class TypedElementsAccessor
2828 :
public ElementsAccessorBase<TypedElementsAccessor<Kind, ctype>,
2829 ElementsKindTraits<Kind>> {
2831 explicit TypedElementsAccessor(
const char* name)
2832 : ElementsAccessorBase<AccessorClass,
2833 ElementsKindTraits<Kind> >(name) {}
2835 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
2836 typedef TypedElementsAccessor<Kind, ctype> AccessorClass;
2838 static inline void SetImpl(Handle<JSObject> holder,
uint32_t entry,
2840 SetImpl(holder->elements(), entry, value);
2843 static inline void SetImpl(FixedArrayBase backing_store,
uint32_t entry,
2845 BackingStore::cast(backing_store)->SetValue(entry, value);
2848 static inline void SetImpl(FixedArrayBase backing_store,
uint32_t entry,
2849 Object* value, WriteBarrierMode mode) {
2850 BackingStore::cast(backing_store)->SetValue(entry, value);
2853 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase backing_store,
2855 return BackingStore::get(isolate, BackingStore::cast(backing_store), entry);
2858 static PropertyDetails GetDetailsImpl(JSObject* holder,
uint32_t entry) {
2859 return PropertyDetails(kData, DONT_DELETE, PropertyCellType::kNoCell);
2862 static PropertyDetails GetDetailsImpl(FixedArrayBase backing_store,
2864 return PropertyDetails(kData, DONT_DELETE, PropertyCellType::kNoCell);
2867 static bool HasElementImpl(Isolate* isolate, JSObject* holder,
uint32_t index,
2868 FixedArrayBase backing_store,
2870 return index < AccessorClass::GetCapacityImpl(holder, backing_store);
2873 static bool HasAccessorsImpl(JSObject* holder, FixedArrayBase backing_store) {
2877 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
2879 Handle<FixedArrayBase> backing_store) {
2884 static void DeleteImpl(Handle<JSObject> obj,
uint32_t entry) {
2888 static uint32_t GetIndexForEntryImpl(FixedArrayBase backing_store,
2893 static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
2894 FixedArrayBase backing_store,
2896 return index < AccessorClass::GetCapacityImpl(holder, backing_store)
2901 static bool WasNeutered(JSObject* holder) {
2902 JSArrayBufferView* view = JSArrayBufferView::cast(holder);
2903 return view->WasNeutered();
2906 static uint32_t GetCapacityImpl(JSObject* holder,
2907 FixedArrayBase backing_store) {
2908 if (WasNeutered(holder))
return 0;
2909 return backing_store->length();
2912 static uint32_t NumberOfElementsImpl(JSObject* receiver,
2913 FixedArrayBase backing_store) {
2914 return AccessorClass::GetCapacityImpl(receiver, backing_store);
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);
2924 Handle<Object> value = AccessorClass::GetImpl(isolate, *elements,
i);
2925 accumulator->AddKey(value, convert);
2929 static Maybe<bool> CollectValuesOrEntriesImpl(
2930 Isolate* isolate, Handle<JSObject>
object,
2931 Handle<FixedArray> values_or_entries,
bool get_entries,
int* nof_items,
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);
2941 value = MakeEntryPair(isolate, index, value);
2943 values_or_entries->set(count++, *value);
2950 static Object* FillImpl(Handle<JSObject> receiver, Handle<Object> obj_value,
2952 Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(receiver);
2953 DCHECK(!array->WasNeutered());
2954 DCHECK(obj_value->IsNumeric());
2956 ctype value = BackingStore::FromHandle(obj_value);
2960 CHECK_LE(start, end);
2961 CHECK_LE(end, array->length_value());
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);
2970 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
2971 Handle<JSObject> receiver,
2972 Handle<Object> value,
2974 DisallowHeapAllocation no_gc;
2978 if (WasNeutered(*receiver)) {
2979 return Just(value->IsUndefined(isolate) && length > start_from);
2982 BackingStore elements = BackingStore::cast(receiver->elements());
2983 if (value->IsUndefined(isolate) &&
2984 length >
static_cast<uint32_t>(elements->length())) {
2987 ctype typed_search_value;
2990 if (static_cast<uint32_t>(elements->length()) < length) {
2991 length = elements->length();
2994 if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
2995 if (!value->IsBigInt())
return Just(
false);
2997 typed_search_value = BackingStore::FromHandle(value, &lossless);
2998 if (!lossless)
return Just(
false);
3000 if (!value->IsNumber())
return Just(
false);
3001 double search_value = value->Number();
3002 if (!std::isfinite(search_value)) {
3004 if (Kind < FLOAT32_ELEMENTS || Kind > FLOAT64_ELEMENTS) {
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);
3014 }
else if (search_value < std::numeric_limits<ctype>::lowest() ||
3015 search_value > std::numeric_limits<ctype>::max()) {
3019 typed_search_value =
static_cast<ctype
>(search_value);
3020 if (static_cast<double>(typed_search_value) != search_value) {
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);
3032 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
3033 Handle<JSObject> receiver,
3034 Handle<Object> value,
3036 DisallowHeapAllocation no_gc;
3038 if (WasNeutered(*receiver))
return Just<int64_t>(-1);
3040 BackingStore elements = BackingStore::cast(receiver->elements());
3041 ctype typed_search_value;
3043 if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
3044 if (!value->IsBigInt())
return Just<int64_t>(-1);
3046 typed_search_value = BackingStore::FromHandle(value, &lossless);
3047 if (!lossless)
return Just<int64_t>(-1);
3049 if (!value->IsNumber())
return Just<int64_t>(-1);
3050 double search_value = value->Number();
3051 if (!std::isfinite(search_value)) {
3053 if (Kind < FLOAT32_ELEMENTS || Kind > FLOAT64_ELEMENTS) {
3054 return Just<int64_t>(-1);
3056 if (std::isnan(search_value)) {
3057 return Just<int64_t>(-1);
3059 }
else if (search_value < std::numeric_limits<ctype>::lowest() ||
3060 search_value > std::numeric_limits<ctype>::max()) {
3062 return Just<int64_t>(-1);
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);
3072 if (static_cast<uint32_t>(elements->length()) < length) {
3073 length = elements->length();
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);
3080 return Just<int64_t>(-1);
3083 static Maybe<int64_t> LastIndexOfValueImpl(Handle<JSObject> receiver,
3084 Handle<Object> value,
3086 DisallowHeapAllocation no_gc;
3087 DCHECK(!WasNeutered(*receiver));
3089 BackingStore elements = BackingStore::cast(receiver->elements());
3090 ctype typed_search_value;
3092 if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS) {
3093 if (!value->IsBigInt())
return Just<int64_t>(-1);
3095 typed_search_value = BackingStore::FromHandle(value, &lossless);
3096 if (!lossless)
return Just<int64_t>(-1);
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) {
3103 return Just<int64_t>(-1);
3104 }
else if (std::isnan(search_value)) {
3106 return Just<int64_t>(-1);
3108 }
else if (search_value < std::numeric_limits<ctype>::lowest() ||
3109 search_value > std::numeric_limits<ctype>::max()) {
3111 return Just<int64_t>(-1);
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);
3119 DCHECK_LT(start_from, elements->length());
3123 ctype element_k = elements->get_scalar(k);
3124 if (element_k == typed_search_value)
return Just<int64_t>(k);
3126 return Just<int64_t>(-1);
3129 static void ReverseImpl(JSObject* receiver) {
3130 DisallowHeapAllocation no_gc;
3131 DCHECK(!WasNeutered(receiver));
3133 BackingStore elements = BackingStore::cast(receiver->elements());
3136 if (len == 0)
return;
3138 ctype* data =
static_cast<ctype*
>(elements->DataPtr());
3139 std::reverse(data, data + len);
3142 static Handle<FixedArray> CreateListFromArrayLikeImpl(Isolate* isolate,
3143 Handle<JSObject>
object,
3145 DCHECK(!WasNeutered(*
object));
3146 DCHECK(object->IsJSTypedArray());
3147 Handle<FixedArray> result = isolate->factory()->NewFixedArray(length);
3148 Handle<BackingStore> elements(BackingStore::cast(object->elements()),
3151 Handle<Object> value = AccessorClass::GetImpl(isolate, *elements,
i);
3152 result->set(
i, *value);
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());
3167 size_t count = end - start;
3168 DCHECK_LE(count, destination->length_value());
3170 FixedTypedArrayBase src_elements =
3171 FixedTypedArrayBase::cast(source->elements());
3172 BackingStore dest_elements = BackingStore::cast(destination->elements());
3174 size_t element_size = source->element_size();
3175 uint8_t* source_data =
3176 static_cast<uint8_t*
>(src_elements->DataPtr()) + start * element_size;
3179 if (source->type() == destination->type()) {
3180 uint8_t* dest_data =
static_cast<uint8_t*
>(dest_elements->DataPtr());
3184 uint8_t* end_ptr = source_data + count * element_size;
3185 while (source_data < end_ptr) {
3186 *dest_data++ = *source_data++;
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, \ 3197 TYPED_ARRAYS(TYPED_ARRAY_CASE)
3198 #undef TYPED_ARRAY_CASE 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);
3211 template <
typename SourceTraits>
3212 static void CopyBetweenBackingStores(
void* source_data_ptr, BackingStore dest,
3214 DisallowHeapAllocation no_gc;
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));
3225 static void CopyElementsFromTypedArray(JSTypedArray* source,
3226 JSTypedArray* destination,
3230 DisallowHeapAllocation no_gc;
3232 CHECK(!source->WasNeutered());
3233 CHECK(!destination->WasNeutered());
3235 FixedTypedArrayBase source_elements =
3236 FixedTypedArrayBase::cast(source->elements());
3237 BackingStore destination_elements =
3238 BackingStore::cast(destination->elements());
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());
3245 InstanceType source_type = source_elements->map()->instance_type();
3246 InstanceType destination_type =
3247 destination_elements->map()->instance_type();
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);
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();
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);
3268 std::unique_ptr<uint8_t[]> cloned_source_elements;
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();
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); \ 3285 TYPED_ARRAYS(TYPED_ARRAY_CASE)
3290 #undef TYPED_ARRAY_CASE 3294 static bool HoleyPrototypeLookupRequired(Isolate* isolate, Context context,
3296 DisallowHeapAllocation no_gc;
3297 DisallowJavascriptExecution no_js(isolate);
3299 #ifdef V8_ENABLE_FORCE_SLOW_PATH 3300 if (isolate->force_slow_path())
return true;
3303 Object* source_proto = source->map()->prototype();
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))) {
3314 return !isolate->IsNoElementsProtectorIntact(context);
3317 static bool TryCopyElementsFastNumber(Context context, JSArray* source,
3318 JSTypedArray* destination,
3320 if (Kind == BIGINT64_ELEMENTS || Kind == BIGUINT64_ELEMENTS)
return false;
3321 Isolate* isolate = source->GetIsolate();
3322 DisallowHeapAllocation no_gc;
3323 DisallowJavascriptExecution no_js(isolate);
3325 CHECK(!destination->WasNeutered());
3327 size_t current_length;
3328 DCHECK(source->length()->IsNumber() &&
3329 TryNumberToSize(source->length(), ¤t_length) &&
3330 length <= current_length);
3331 USE(current_length);
3333 size_t dest_length = destination->length_value();
3334 DCHECK(length + offset <= dest_length);
3337 ElementsKind kind = source->GetElementsKind();
3338 BackingStore dest = BackingStore::cast(destination->elements());
3345 if (HoleyPrototypeLookupRequired(isolate, context, source))
return false;
3347 Object* undefined = ReadOnlyRoots(isolate).undefined_value();
3350 if (kind == PACKED_SMI_ELEMENTS) {
3351 FixedArray source_store = FixedArray::cast(source->elements());
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));
3360 }
else if (kind == HOLEY_SMI_ELEMENTS) {
3361 FixedArray source_store = FixedArray::cast(source->elements());
3363 if (source_store->is_the_hole(isolate,
i)) {
3364 dest->SetValue(offset +
i, undefined);
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));
3373 }
else if (kind == PACKED_DOUBLE_ELEMENTS) {
3376 FixedDoubleArray source_store =
3377 FixedDoubleArray::cast(source->elements());
3382 double elem = source_store->get_scalar(
i);
3383 dest->set(offset +
i, dest->from(elem));
3386 }
else if (kind == HOLEY_DOUBLE_ELEMENTS) {
3387 FixedDoubleArray source_store =
3388 FixedDoubleArray::cast(source->elements());
3390 if (source_store->is_the_hole(
i)) {
3391 dest->SetValue(offset +
i, undefined);
3393 double elem = source_store->get_scalar(
i);
3394 dest->set(offset +
i, dest->from(elem));
3402 static Object* CopyElementsHandleSlow(Handle<Object> source,
3403 Handle<JSTypedArray> destination,
3405 Isolate* isolate = destination->GetIsolate();
3406 Handle<BackingStore> destination_elements(
3407 BackingStore::cast(destination->elements()), isolate);
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));
3417 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, elem,
3418 Object::ToNumber(isolate, elem));
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));
3431 destination_elements->SetValue(offset +
i, *elem);
3433 return *isolate->factory()->undefined_value();
3439 static Object* CopyElementsHandleImpl(Handle<Object> source,
3440 Handle<JSObject> destination,
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());
3448 if (length == 0)
return *isolate->factory()->undefined_value();
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));
3466 if (V8_UNLIKELY(source_is_bigint)) {
3467 THROW_NEW_ERROR_RETURN_FAILURE(
3468 isolate, NewTypeError(MessageTemplate::kBigIntToNumber));
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();
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(), ¤t_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();
3497 return CopyElementsHandleSlow(source, destination_ta, length, offset);
3501 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype) \ 3502 typedef TypedElementsAccessor<TYPE##_ELEMENTS, ctype> \ 3503 Fixed##Type##ElementsAccessor; 3505 TYPED_ARRAYS(FIXED_ELEMENTS_ACCESSOR)
3506 #undef FIXED_ELEMENTS_ACCESSOR 3508 template <
typename Sub
class,
typename ArgumentsAccessor,
typename KindTraits>
3509 class SloppyArgumentsElementsAccessor
3510 :
public ElementsAccessorBase<Subclass, KindTraits> {
3512 explicit SloppyArgumentsElementsAccessor(
const char* name)
3513 : ElementsAccessorBase<Subclass, KindTraits>(name) {
3514 USE(KindTraits::Kind);
3517 static void ConvertArgumentsStoreResult(
3518 Handle<SloppyArgumentsElements> elements, Handle<Object> result) {
3522 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase parameters,
3524 Handle<SloppyArgumentsElements> elements(
3525 SloppyArgumentsElements::cast(parameters), isolate);
3526 uint32_t length = elements->parameter_map_length();
3527 if (entry < length) {
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);
3538 Handle<Object> result = ArgumentsAccessor::GetImpl(
3539 isolate, elements->arguments(), entry - length);
3540 return Subclass::ConvertArgumentsStoreResult(isolate, elements, result);
3544 static void TransitionElementsKindImpl(Handle<JSObject>
object,
3549 static void GrowCapacityAndConvertImpl(Handle<JSObject>
object,
3554 static inline void SetImpl(Handle<JSObject> holder,
uint32_t entry,
3556 SetImpl(holder->elements(), entry, value);
3559 static inline void SetImpl(FixedArrayBase store,
uint32_t entry,
3561 SloppyArgumentsElements elements = SloppyArgumentsElements::cast(store);
3562 uint32_t length = elements->parameter_map_length();
3563 if (entry < length) {
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);
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);
3583 ArgumentsAccessor::SetImpl(arguments, entry - length, value);
3588 static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
3590 Handle<FixedArrayBase> parameter_map) {
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);
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);
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();
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++;
3622 return nof_elements +
3623 ArgumentsAccessor::NumberOfElementsImpl(receiver, arguments);
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);
3639 static bool HasEntryImpl(Isolate* isolate, FixedArrayBase parameters,
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);
3647 FixedArrayBase arguments = elements->arguments();
3648 return ArgumentsAccessor::HasEntryImpl(isolate, arguments, entry - length);
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);
3658 static uint32_t GetIndexForEntryImpl(FixedArrayBase parameters,
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);
3668 static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
3669 FixedArrayBase parameters,
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;
3680 return elements->parameter_map_length() + entry;
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);
3690 FixedArray arguments = elements->arguments();
3691 return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
3694 static bool HasParameterMapArg(Isolate* isolate,
3695 SloppyArgumentsElements elements,
3697 uint32_t length = elements->parameter_map_length();
3698 if (index >= length)
return false;
3699 return !elements->get_mapped_entry(index)->IsTheHole(isolate);
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();
3707 if (entry < length) {
3708 delete_or_entry = kMaxUInt32;
3710 Subclass::SloppyDeleteImpl(obj, elements, delete_or_entry);
3713 if (entry < length) {
3714 elements->set_mapped_entry(entry,
3715 obj->GetReadOnlyRoots().the_hole_value());
3719 static void SloppyDeleteImpl(Handle<JSObject> obj,
3720 Handle<SloppyArgumentsElements> elements,
3726 static void CollectElementIndicesImpl(Handle<JSObject>
object,
3727 Handle<FixedArrayBase> backing_store,
3728 KeyAccumulator* keys) {
3729 Isolate* isolate = keys->isolate();
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);
3738 keys->AddKey(indices->get(
i));
3742 static Handle<FixedArray> DirectCollectElementIndicesImpl(
3743 Isolate* isolate, Handle<JSObject>
object,
3744 Handle<FixedArrayBase> backing_store, GetKeysConversion convert,
3747 Handle<SloppyArgumentsElements> elements =
3748 Handle<SloppyArgumentsElements>::cast(backing_store);
3749 uint32_t length = elements->parameter_map_length();
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);
3757 list->set(insertion_index, Smi::FromInt(
i), SKIP_WRITE_BARRIER);
3762 Handle<FixedArray> store(elements->arguments(), isolate);
3763 return ArgumentsAccessor::DirectCollectElementIndicesImpl(
3764 isolate,
object, store, convert, filter, list, nof_indices,
3768 static Maybe<bool> IncludesValueImpl(Isolate* isolate,
3769 Handle<JSObject>
object,
3770 Handle<Object> value,
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);
3778 for (
uint32_t k = start_from; k < length; ++k) {
3779 DCHECK_EQ(object->map(), *original_map);
3781 GetEntryForIndexImpl(isolate, *
object, *elements, k, ALL_PROPERTIES);
3782 if (entry == kMaxUInt32) {
3783 if (search_for_hole)
return Just(
true);
3787 Handle<Object> element_k = Subclass::GetImpl(isolate, *elements, entry);
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),
3797 if (value->SameValueZero(*element_k))
return Just(
true);
3799 if (object->map() != *original_map) {
3801 return IncludesValueSlowPath(isolate,
object, value, k + 1, length);
3803 }
else if (value->SameValueZero(*element_k)) {
3810 static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate,
3811 Handle<JSObject>
object,
3812 Handle<Object> value,
3814 DCHECK(JSObject::PrototypeHasNoElements(isolate, *
object));
3815 Handle<Map> original_map(object->map(), isolate);
3816 Handle<SloppyArgumentsElements> elements(
3817 SloppyArgumentsElements::cast(object->elements()), isolate);
3819 for (
uint32_t k = start_from; k < length; ++k) {
3820 DCHECK_EQ(object->map(), *original_map);
3822 GetEntryForIndexImpl(isolate, *
object, *elements, k, ALL_PROPERTIES);
3823 if (entry == kMaxUInt32) {
3827 Handle<Object> element_k = Subclass::GetImpl(isolate, *elements, entry);
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>());
3837 if (value->StrictEquals(*element_k)) {
3838 return Just<int64_t>(k);
3841 if (object->map() != *original_map) {
3843 return IndexOfValueSlowPath(isolate,
object, value, k + 1, length);
3845 }
else if (value->StrictEquals(*element_k)) {
3846 return Just<int64_t>(k);
3849 return Just<int64_t>(-1);
3852 static Handle<JSObject> SliceImpl(Handle<JSObject> receiver,
uint32_t start,
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());
3863 uint32_t entry = GetEntryForIndexImpl(isolate, *receiver, parameters,
i,
3865 if (entry != kMaxUInt32 && HasEntryImpl(isolate, parameters, entry)) {
3866 elements->set(insertion_index, *GetImpl(isolate, parameters, entry));
3868 elements->set_the_hole(isolate, insertion_index);
3872 return result_array;
3877 class SlowSloppyArgumentsElementsAccessor
3878 :
public SloppyArgumentsElementsAccessor<
3879 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
3880 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
3882 explicit SlowSloppyArgumentsElementsAccessor(
const char* name)
3883 : SloppyArgumentsElementsAccessor<
3884 SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
3885 ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
3887 static Handle<Object> ConvertArgumentsStoreResult(
3888 Isolate* isolate, Handle<SloppyArgumentsElements> elements,
3889 Handle<Object> result) {
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);
3901 static void SloppyDeleteImpl(Handle<JSObject> obj,
3902 Handle<SloppyArgumentsElements> elements,
3905 if (entry == kMaxUInt32)
return;
3906 Isolate* isolate = obj->GetIsolate();
3907 Handle<NumberDictionary> dict(NumberDictionary::cast(elements->arguments()),
3909 int length = elements->parameter_map_length();
3910 dict = NumberDictionary::DeleteEntry(isolate, dict, entry - length);
3911 elements->set_arguments(*dict);
3913 static void AddImpl(Handle<JSObject>
object,
uint32_t index,
3914 Handle<Object> value, PropertyAttributes attributes,
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);
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);
3951 elements->set_mapped_entry(entry,
3952 ReadOnlyRoots(isolate).the_hole_value());
3954 if ((attributes & READ_ONLY) == 0) {
3955 value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
3958 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
3959 Handle<NumberDictionary> arguments(
3960 NumberDictionary::cast(elements->arguments()), isolate);
3962 NumberDictionary::Add(isolate, arguments, entry, value, details);
3965 DCHECK_NE(NONE, attributes);
3966 object->RequireSlowElements(*arguments);
3967 elements->set_arguments(*arguments);
3969 Handle<FixedArrayBase> arguments(elements->arguments(), isolate);
3970 DictionaryElementsAccessor::ReconfigureImpl(
3971 object, arguments, entry - length, value, attributes);
3977 class FastSloppyArgumentsElementsAccessor
3978 :
public SloppyArgumentsElementsAccessor<
3979 FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
3980 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
3982 explicit FastSloppyArgumentsElementsAccessor(
const char* name)
3983 : SloppyArgumentsElementsAccessor<
3984 FastSloppyArgumentsElementsAccessor,
3985 FastHoleyObjectElementsAccessor,
3986 ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
3988 static Handle<Object> ConvertArgumentsStoreResult(
3989 Isolate* isolate, Handle<SloppyArgumentsElements> paramtere_map,
3990 Handle<Object> result) {
3991 DCHECK(!result->IsAliasedArgumentsEntry());
3995 static Handle<FixedArray> GetArguments(Isolate* isolate,
3996 FixedArrayBase store) {
3997 SloppyArgumentsElements elements = SloppyArgumentsElements::cast(store);
3998 return Handle<FixedArray>(elements->arguments(), isolate);
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);
4008 static Handle<NumberDictionary> NormalizeArgumentsElements(
4009 Handle<JSObject>
object, Handle<SloppyArgumentsElements> elements,
4011 Handle<NumberDictionary> dictionary = JSObject::NormalizeElements(
object);
4012 elements->set_arguments(*dictionary);
4015 if (*entry == kMaxUInt32)
return dictionary;
4016 uint32_t length = elements->parameter_map_length();
4017 if (*entry >= length) {
4019 dictionary->FindEntry(object->GetIsolate(), *entry - length) + length;
4024 static void SloppyDeleteImpl(Handle<JSObject> obj,
4025 Handle<SloppyArgumentsElements> elements,
4028 NormalizeArgumentsElements(obj, elements, &entry);
4029 SlowSloppyArgumentsElementsAccessor::SloppyDeleteImpl(obj, elements, entry);
4032 static void AddImpl(Handle<JSObject>
object,
uint32_t index,
4033 Handle<Object> value, PropertyAttributes attributes,
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);
4044 FixedArray arguments = elements->arguments();
4050 FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
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,
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);
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);
4080 static void GrowCapacityAndConvertImpl(Handle<JSObject>
object,
4082 Isolate* isolate =
object->GetIsolate();
4083 Handle<SloppyArgumentsElements> elements(
4084 SloppyArgumentsElements::cast(object->elements()), isolate);
4085 Handle<FixedArray> old_arguments(FixedArray::cast(elements->arguments()),
4087 ElementsKind from_kind =
object->GetElementsKind();
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);
4102 template <
typename Sub
class,
typename BackingStoreAccessor,
typename KindTraits>
4103 class StringWrapperElementsAccessor
4104 :
public ElementsAccessorBase<Subclass, KindTraits> {
4106 explicit StringWrapperElementsAccessor(
const char* name)
4107 : ElementsAccessorBase<Subclass, KindTraits>(name) {
4108 USE(KindTraits::Kind);
4111 static Handle<Object> GetInternalImpl(Handle<JSObject> holder,
4113 return GetImpl(holder, entry);
4116 static Handle<Object> GetImpl(Handle<JSObject> holder,
uint32_t entry) {
4117 Isolate* isolate = holder->GetIsolate();
4118 Handle<String> string(GetString(*holder), isolate);
4120 if (entry < length) {
4121 return isolate->factory()->LookupSingleCharacterStringFromCode(
4122 String::Flatten(isolate,
string)->Get(entry));
4124 return BackingStoreAccessor::GetImpl(isolate, holder->elements(),
4128 static Handle<Object> GetImpl(Isolate* isolate, FixedArrayBase elements,
4133 static PropertyDetails GetDetailsImpl(JSObject* holder,
uint32_t entry) {
4135 if (entry < length) {
4136 PropertyAttributes attributes =
4137 static_cast<PropertyAttributes
>(READ_ONLY | DONT_DELETE);
4138 return PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
4140 return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
4143 static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
4144 FixedArrayBase backing_store,
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;
4155 static void DeleteImpl(Handle<JSObject> holder,
uint32_t entry) {
4157 if (entry < length) {
4160 BackingStoreAccessor::DeleteImpl(holder, entry - length);
4163 static void SetImpl(Handle<JSObject> holder,
uint32_t entry, Object* value) {
4165 if (entry < length) {
4168 BackingStoreAccessor::SetImpl(holder->elements(), entry - length, value);
4171 static void AddImpl(Handle<JSObject>
object,
uint32_t index,
4172 Handle<Object> value, PropertyAttributes attributes,
4174 DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length()));
4177 if (KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS &&
4178 (object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS ||
4179 BackingStoreAccessor::GetCapacityImpl(*
object, object->elements()) !=
4181 GrowCapacityAndConvertImpl(
object, new_capacity);
4183 BackingStoreAccessor::AddImpl(
object, index, value, attributes,
4187 static void ReconfigureImpl(Handle<JSObject>
object,
4188 Handle<FixedArrayBase> store,
uint32_t entry,
4189 Handle<Object> value,
4190 PropertyAttributes attributes) {
4192 if (entry < length) {
4195 BackingStoreAccessor::ReconfigureImpl(
object, store, entry - length, value,
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);
4207 accumulator->AddKey(
4208 isolate->factory()->LookupSingleCharacterStringFromCode(
4212 BackingStoreAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator,
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();
4222 keys->AddKey(factory->NewNumberFromUint(
i));
4224 BackingStoreAccessor::CollectElementIndicesImpl(
object, backing_store,
4228 static void GrowCapacityAndConvertImpl(Handle<JSObject>
object,
4230 Handle<FixedArrayBase> old_elements(object->elements(),
4231 object->GetIsolate());
4232 ElementsKind from_kind =
object->GetElementsKind();
4233 if (from_kind == FAST_STRING_WRAPPER_ELEMENTS) {
4238 object->GetIsolate()->UpdateNoElementsProtectorOnSetLength(
object);
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,
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);
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);
4264 static uint32_t NumberOfElementsImpl(JSObject*
object,
4265 FixedArrayBase backing_store) {
4266 uint32_t length = GetString(
object)->length();
4268 BackingStoreAccessor::NumberOfElementsImpl(
object, backing_store);
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());
4280 class FastStringWrapperElementsAccessor
4281 :
public StringWrapperElementsAccessor<
4282 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
4283 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> {
4285 explicit FastStringWrapperElementsAccessor(
const char* name)
4286 : StringWrapperElementsAccessor<
4287 FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor,
4288 ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {}
4290 static Handle<NumberDictionary> NormalizeImpl(
4291 Handle<JSObject>
object, Handle<FixedArrayBase> elements) {
4292 return FastHoleyObjectElementsAccessor::NormalizeImpl(
object, elements);
4296 class SlowStringWrapperElementsAccessor
4297 :
public StringWrapperElementsAccessor<
4298 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
4299 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> {
4301 explicit SlowStringWrapperElementsAccessor(
const char* name)
4302 : StringWrapperElementsAccessor<
4303 SlowStringWrapperElementsAccessor, DictionaryElementsAccessor,
4304 ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {}
4306 static bool HasAccessorsImpl(JSObject* holder, FixedArrayBase backing_store) {
4307 return DictionaryElementsAccessor::HasAccessorsImpl(holder, backing_store);
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();
4323 raw_length = Smi::FromInt(obj->elements()->length());
4324 elements_type =
"object";
4327 if (raw_length->IsNumber()) {
4328 double n = raw_length->Number();
4329 if (FastI2D(FastD2UI(n)) == n) {
4330 int32_t int32_length = DoubleToInt32(n);
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());
4341 PrintF(
"[%s elements length not integer value in ", elements_type);
4342 TraceTopFrame(obj->GetIsolate());
4346 PrintF(
"[%s elements length not a number in ", elements_type);
4347 TraceTopFrame(obj->GetIsolate());
4353 MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
4355 if (args->length() == 0) {
4357 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
4360 }
else if (args->length() == 1 && args->at(0)->IsNumber()) {
4362 if (!args->at(0)->ToArrayLength(&length)) {
4363 return ThrowArrayLengthRangeError(array->GetIsolate());
4368 if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
4369 ElementsKind elements_kind = array->GetElementsKind();
4370 JSArray::Initialize(array, length, length);
4372 if (!IsHoleyElementsKind(elements_kind)) {
4373 elements_kind = GetHoleyElementsKind(elements_kind);
4374 JSObject::TransitionElementsKind(array, elements_kind);
4376 }
else if (length == 0) {
4377 JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
4380 JSArray::Initialize(array, 0);
4381 JSArray::SetLength(array, length);
4386 Factory* factory = array->GetIsolate()->factory();
4389 int number_of_elements = args->length();
4390 JSObject::EnsureCanContainElements(
4391 array, args, 0, number_of_elements, ALLOW_CONVERTED_DOUBLE_ELEMENTS);
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));
4400 elms = Handle<FixedArrayBase>::cast(
4401 factory->NewFixedArrayWithHoles(number_of_elements));
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);
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);
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());
4438 array->set_elements(*elms);
4439 array->set_length(Smi::FromInt(number_of_elements));
4443 void CopyFastNumberJSArrayElementsToTypedArray(Address raw_context,
4445 JSTypedArray* destination,
4448 Context context = Context::cast(ObjectPtr(raw_context));
4449 DCHECK(source->IsJSArray());
4450 DCHECK(destination->IsJSTypedArray());
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))); \ 4458 TYPED_ARRAYS(TYPED_ARRAYS_CASE)
4459 #undef TYPED_ARRAYS_CASE 4465 void CopyTypedArrayElementsToTypedArray(JSTypedArray* source,
4466 JSTypedArray* destination,
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)); \ 4474 TYPED_ARRAYS(TYPED_ARRAYS_CASE)
4475 #undef TYPED_ARRAYS_CASE 4481 void CopyTypedArrayElementsSlice(JSTypedArray* source,
4482 JSTypedArray* destination,
uintptr_t start,
4484 destination->GetElementsAccessor()->CopyTypedArrayElementsSlice(
4485 source, destination, start, end);
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 4495 STATIC_ASSERT((
sizeof(accessor_array) /
sizeof(*accessor_array)) ==
4496 kElementsKindCount);
4498 elements_accessors_ = accessor_array;
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;
4510 Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
4513 ElementsKind result_elements_kind = GetInitialFastElementsKind();
4514 bool has_raw_doubles =
false;
4516 DisallowHeapAllocation no_gc;
4517 bool is_holey =
false;
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);
4527 result_elements_kind = GetHoleyElementsKind(result_elements_kind);
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;
4544 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
4545 ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind);
4549 JSArray* array = JSArray::cast((*args)[
i]);
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;
4558 DCHECK_EQ(insertion_index, result_len);
4559 return result_array;
4562 ElementsAccessor** ElementsAccessor::elements_accessors_ =
nullptr;
4564 #undef ELEMENTS_LIST