5 #include "src/builtins/builtins-utils-inl.h" 6 #include "src/builtins/builtins.h" 7 #include "src/code-factory.h" 8 #include "src/contexts.h" 9 #include "src/counters.h" 10 #include "src/debug/debug.h" 11 #include "src/elements-inl.h" 12 #include "src/global-handles.h" 13 #include "src/isolate.h" 14 #include "src/lookup.h" 15 #include "src/objects-inl.h" 16 #include "src/objects/hash-table-inl.h" 17 #include "src/objects/js-array-inl.h" 18 #include "src/objects/smi.h" 19 #include "src/prototype.h" 26 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
28 return JSObject::PrototypeHasNoElements(isolate, receiver);
31 inline bool HasSimpleElements(JSObject* current) {
32 return !current->map()->IsCustomElementsReceiverMap() &&
33 !current->GetElementsAccessor()->HasAccessors(current);
36 inline bool HasOnlySimpleReceiverElements(Isolate* isolate,
39 if (!HasSimpleElements(receiver))
return false;
40 return JSObject::PrototypeHasNoElements(isolate, receiver);
43 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) {
44 DisallowHeapAllocation no_gc;
45 PrototypeIterator iter(isolate, receiver, kStartAtReceiver);
46 for (; !iter.IsAtEnd(); iter.Advance()) {
47 if (iter.GetCurrent()->IsJSProxy())
return false;
48 JSObject* current = iter.GetCurrent<JSObject>();
49 if (!HasSimpleElements(current))
return false;
57 void MatchArrayElementsKindToArguments(Isolate* isolate, Handle<JSArray> array,
58 BuiltinArguments* args,
59 int first_arg_index,
int num_arguments) {
60 int args_length = args->length();
61 if (first_arg_index >= args_length)
return;
63 ElementsKind origin_kind = array->GetElementsKind();
66 if (IsObjectElementsKind(origin_kind))
return;
68 ElementsKind target_kind = origin_kind;
70 DisallowHeapAllocation no_gc;
71 int last_arg_index = std::min(first_arg_index + num_arguments, args_length);
72 for (
int i = first_arg_index;
i < last_arg_index;
i++) {
73 ObjectPtr arg = (*args)[
i];
74 if (arg->IsHeapObject()) {
75 if (arg->IsHeapNumber()) {
76 target_kind = PACKED_DOUBLE_ELEMENTS;
78 target_kind = PACKED_ELEMENTS;
84 if (target_kind != origin_kind) {
87 HandleScope scope(isolate);
88 JSObject::TransitionElementsKind(array, target_kind);
96 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate,
97 Handle<Object> receiver,
98 BuiltinArguments* args,
101 if (!receiver->IsJSArray())
return false;
102 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
103 ElementsKind origin_kind = array->GetElementsKind();
104 if (IsDictionaryElementsKind(origin_kind))
return false;
105 if (!array->map()->is_extensible())
return false;
106 if (args ==
nullptr)
return true;
110 if (!IsJSArrayFastElementMovingAllowed(isolate, *array))
return false;
114 if (isolate->IsAnyInitialArrayPrototype(array))
return false;
118 MatchArrayElementsKindToArguments(isolate, array, args, first_arg_index,
127 V8_WARN_UNUSED_RESULT Maybe<double> GetRelativeIndex(Isolate* isolate,
129 Handle<Object> index,
130 double init_if_undefined) {
131 double relative_index = init_if_undefined;
132 if (!index->IsUndefined()) {
133 Handle<Object> relative_index_obj;
134 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, relative_index_obj,
135 Object::ToInteger(isolate, index),
137 relative_index = relative_index_obj->Number();
140 if (relative_index < 0) {
141 return Just(std::max(length + relative_index, 0.0));
144 return Just(std::min(relative_index, length));
148 V8_WARN_UNUSED_RESULT Maybe<double> GetLengthProperty(
149 Isolate* isolate, Handle<JSReceiver> receiver) {
150 if (receiver->IsJSArray()) {
151 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
152 double length = array->length()->Number();
153 DCHECK(0 <= length && length <= kMaxSafeInteger);
158 Handle<Object> raw_length_number;
159 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
160 isolate, raw_length_number,
161 Object::GetLengthFromArrayLike(isolate, receiver), Nothing<double>());
162 return Just(raw_length_number->Number());
167 V8_WARN_UNUSED_RESULT MaybeHandle<Object> SetLengthProperty(
168 Isolate* isolate, Handle<JSReceiver> receiver,
double length) {
169 if (receiver->IsJSArray()) {
170 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
171 if (!JSArray::HasReadOnlyLength(array)) {
172 DCHECK_LE(length, kMaxUInt32);
173 JSArray::SetLength(array, static_cast<uint32_t>(length));
178 return Object::SetProperty(
179 isolate, receiver, isolate->factory()->length_string(),
180 isolate->factory()->NewNumber(length), LanguageMode::kStrict);
183 V8_WARN_UNUSED_RESULT Object* GenericArrayFill(Isolate* isolate,
184 Handle<JSReceiver> receiver,
185 Handle<Object> value,
186 double start,
double end) {
188 while (start < end) {
190 Handle<String> index = isolate->factory()->NumberToString(
191 isolate->factory()->NewNumber(start));
194 RETURN_FAILURE_ON_EXCEPTION(
195 isolate, Object::SetPropertyOrElement(isolate, receiver, index, value,
196 LanguageMode::kStrict));
206 V8_WARN_UNUSED_RESULT
bool TryFastArrayFill(
207 Isolate* isolate, BuiltinArguments* args, Handle<JSReceiver> receiver,
208 Handle<Object> value,
double start_index,
double end_index) {
211 if (end_index > kMaxUInt32)
return false;
212 if (!receiver->IsJSObject())
return false;
214 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, args, 1, 1)) {
218 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
224 if (args->length() == 1 && array->GetElementsKind() != PACKED_ELEMENTS) {
227 HandleScope scope(isolate);
228 JSObject::TransitionElementsKind(array, PACKED_ELEMENTS);
231 DCHECK_LE(start_index, kMaxUInt32);
232 DCHECK_LE(end_index, kMaxUInt32);
235 CHECK(DoubleToUint32IfEqualToSelf(start_index, &start));
236 CHECK(DoubleToUint32IfEqualToSelf(end_index, &end));
238 ElementsAccessor* accessor = array->GetElementsAccessor();
239 accessor->Fill(array, value, start, end);
244 BUILTIN(ArrayPrototypeFill) {
245 HandleScope scope(isolate);
247 if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) {
248 if (!isolate->debug()->PerformSideEffectCheckForObject(args.receiver())) {
249 return ReadOnlyRoots(isolate).exception();
254 Handle<JSReceiver> receiver;
255 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
256 isolate, receiver, Object::ToObject(isolate, args.receiver()));
260 MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
261 isolate, length, GetLengthProperty(isolate, receiver));
266 Handle<Object> start = args.atOrUndefined(isolate, 2);
269 MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
270 isolate, start_index, GetRelativeIndex(isolate, length, start, 0));
276 Handle<Object> end = args.atOrUndefined(isolate, 3);
279 MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
280 isolate, end_index, GetRelativeIndex(isolate, length, end, length));
282 if (start_index >= end_index)
return *receiver;
285 DCHECK_LE(0, start_index);
286 DCHECK_LE(start_index, end_index);
287 DCHECK_LE(end_index, length);
289 Handle<Object> value = args.atOrUndefined(isolate, 1);
291 if (TryFastArrayFill(isolate, &args, receiver, value, start_index,
295 return GenericArrayFill(isolate, receiver, value, start_index, end_index);
299 V8_WARN_UNUSED_RESULT Object* GenericArrayPush(Isolate* isolate,
300 BuiltinArguments* args) {
302 Handle<JSReceiver> receiver;
303 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
304 isolate, receiver, Object::ToObject(isolate, args->receiver()));
307 Handle<Object> raw_length_number;
308 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
309 isolate, raw_length_number,
310 Object::GetLengthFromArrayLike(isolate, receiver));
315 int arg_count = args->length() - 1;
318 double length = raw_length_number->Number();
319 if (arg_count > kMaxSafeInteger - length) {
320 THROW_NEW_ERROR_RETURN_FAILURE(
321 isolate, NewTypeError(MessageTemplate::kPushPastSafeLength,
322 isolate->factory()->NewNumberFromInt(arg_count),
327 for (
int i = 0;
i < arg_count; ++
i) {
330 Handle<Object> element = args->at(
i + 1);
333 if (length <= static_cast<double>(JSArray::kMaxArrayIndex)) {
334 RETURN_FAILURE_ON_EXCEPTION(
335 isolate, Object::SetElement(isolate, receiver, length, element,
336 LanguageMode::kStrict));
339 LookupIterator it = LookupIterator::PropertyOrElement(
340 isolate, receiver, isolate->factory()->NewNumber(length), &success);
343 MAYBE_RETURN(Object::SetProperty(&it, element, LanguageMode::kStrict,
344 StoreOrigin::kMaybeKeyed),
345 ReadOnlyRoots(isolate).exception());
353 Handle<Object> final_length = isolate->factory()->NewNumber(length);
354 RETURN_FAILURE_ON_EXCEPTION(
355 isolate, Object::SetProperty(isolate, receiver,
356 isolate->factory()->length_string(),
357 final_length, LanguageMode::kStrict));
360 return *final_length;
365 HandleScope scope(isolate);
366 Handle<Object> receiver = args.receiver();
367 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1,
368 args.length() - 1)) {
369 return GenericArrayPush(isolate, &args);
373 int to_add = args.length() - 1;
374 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
376 if (to_add == 0)
return *isolate->factory()->NewNumberFromUint(len);
379 DCHECK_LE(to_add, Smi::kMaxValue - Smi::ToInt(array->length()));
381 if (JSArray::HasReadOnlyLength(array)) {
382 return GenericArrayPush(isolate, &args);
385 ElementsAccessor* accessor = array->GetElementsAccessor();
386 uint32_t new_length = accessor->Push(array, &args, to_add);
387 return *isolate->factory()->NewNumberFromUint((new_length));
392 V8_WARN_UNUSED_RESULT Object* GenericArrayPop(Isolate* isolate,
393 BuiltinArguments* args) {
395 Handle<JSReceiver> receiver;
396 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
397 isolate, receiver, Object::ToObject(isolate, args->receiver()));
400 Handle<Object> raw_length_number;
401 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
402 isolate, raw_length_number,
403 Object::GetLengthFromArrayLike(isolate, receiver));
404 double length = raw_length_number->Number();
409 RETURN_FAILURE_ON_EXCEPTION(
410 isolate, Object::SetProperty(
411 isolate, receiver, isolate->factory()->length_string(),
412 Handle<Smi>(Smi::zero(), isolate), LanguageMode::kStrict));
415 return ReadOnlyRoots(isolate).undefined_value();
420 Handle<Object> new_length = isolate->factory()->NewNumber(length - 1);
423 Handle<String> index = isolate->factory()->NumberToString(new_length);
426 Handle<Object> element;
427 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
429 JSReceiver::GetPropertyOrElement(isolate, receiver, index));
432 MAYBE_RETURN(JSReceiver::DeletePropertyOrElement(receiver, index,
433 LanguageMode::kStrict),
434 ReadOnlyRoots(isolate).exception());
437 RETURN_FAILURE_ON_EXCEPTION(
438 isolate, Object::SetProperty(isolate, receiver,
439 isolate->factory()->length_string(),
440 new_length, LanguageMode::kStrict));
449 HandleScope scope(isolate);
450 Handle<Object> receiver = args.receiver();
451 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver,
nullptr, 0,
453 return GenericArrayPop(isolate, &args);
455 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
458 if (len == 0)
return ReadOnlyRoots(isolate).undefined_value();
460 if (JSArray::HasReadOnlyLength(array)) {
461 return GenericArrayPop(isolate, &args);
464 Handle<Object> result;
465 if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
467 result = array->GetElementsAccessor()->Pop(array);
471 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
472 isolate, result, JSReceiver::GetElement(isolate, array, new_length));
473 JSArray::SetLength(array, new_length);
482 V8_WARN_UNUSED_RESULT
bool CanUseFastArrayShift(Isolate* isolate,
483 Handle<JSReceiver> receiver) {
484 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver,
nullptr, 0,
486 !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
490 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
491 return !JSArray::HasReadOnlyLength(array);
494 V8_WARN_UNUSED_RESULT Object* GenericArrayShift(Isolate* isolate,
495 Handle<JSReceiver> receiver,
498 Handle<Object> first;
499 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, first,
500 Object::GetElement(isolate, receiver, 0));
508 Handle<String> from =
509 isolate->factory()->NumberToString(isolate->factory()->NewNumber(k));
512 Handle<String> to = isolate->factory()->NumberToString(
513 isolate->factory()->NewNumber(k - 1));
517 MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
518 isolate, from_present, JSReceiver::HasProperty(receiver, from));
523 Handle<Object> from_val;
524 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
526 Object::GetPropertyOrElement(isolate, receiver, from));
529 RETURN_FAILURE_ON_EXCEPTION(
530 isolate, Object::SetPropertyOrElement(isolate, receiver, to, from_val,
531 LanguageMode::kStrict));
534 MAYBE_RETURN(JSReceiver::DeletePropertyOrElement(receiver, to,
535 LanguageMode::kStrict),
536 ReadOnlyRoots(isolate).exception());
544 Handle<String> new_length = isolate->factory()->NumberToString(
545 isolate->factory()->NewNumber(length - 1));
546 MAYBE_RETURN(JSReceiver::DeletePropertyOrElement(receiver, new_length,
547 LanguageMode::kStrict),
548 ReadOnlyRoots(isolate).exception());
551 RETURN_FAILURE_ON_EXCEPTION(isolate,
552 SetLengthProperty(isolate, receiver, length - 1));
559 BUILTIN(ArrayShift) {
560 HandleScope scope(isolate);
563 Handle<JSReceiver> receiver;
564 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
565 isolate, receiver, Object::ToObject(isolate, args.receiver()));
569 MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
570 isolate, length, GetLengthProperty(isolate, receiver));
575 RETURN_FAILURE_ON_EXCEPTION(isolate,
576 SetLengthProperty(isolate, receiver, length));
579 return ReadOnlyRoots(isolate).undefined_value();
582 if (CanUseFastArrayShift(isolate, receiver)) {
583 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
584 return *array->GetElementsAccessor()->Shift(array);
587 return GenericArrayShift(isolate, receiver, length);
590 BUILTIN(ArrayUnshift) {
591 HandleScope scope(isolate);
592 DCHECK(args.receiver()->IsJSArray());
593 Handle<JSArray> array = Handle<JSArray>::cast(args.receiver());
596 DCHECK(array->map()->is_extensible());
597 DCHECK(!IsDictionaryElementsKind(array->GetElementsKind()));
598 DCHECK(IsJSArrayFastElementMovingAllowed(isolate, *array));
599 DCHECK(!isolate->IsAnyInitialArrayPrototype(array));
601 MatchArrayElementsKindToArguments(isolate, array, &args, 1,
604 int to_add = args.length() - 1;
605 if (to_add == 0)
return array->length();
608 DCHECK_LE(to_add, Smi::kMaxValue - Smi::ToInt(array->length()));
609 DCHECK(!JSArray::HasReadOnlyLength(array));
611 ElementsAccessor* accessor = array->GetElementsAccessor();
612 int new_length = accessor->Unshift(array, &args, to_add);
613 return Smi::FromInt(new_length);
631 class ArrayConcatVisitor {
633 ArrayConcatVisitor(Isolate* isolate, Handle<HeapObject> storage,
636 storage_(isolate->global_handles()->Create(*storage)),
638 bit_field_(FastElementsField::encode(fast_elements) |
639 ExceedsLimitField::encode(false) |
640 IsFixedArrayField::encode(storage->IsFixedArray()) |
641 HasSimpleElementsField::encode(
642 storage->IsFixedArray() ||
643 !storage->map()->IsCustomElementsReceiverMap())) {
644 DCHECK(!(this->fast_elements() && !is_fixed_array()));
647 ~ArrayConcatVisitor() { clear_storage(); }
649 V8_WARN_UNUSED_RESULT
bool visit(
uint32_t i, Handle<Object> elm) {
652 if (
i >= JSObject::kMaxElementCount - index_offset_) {
653 set_exceeds_array_limit(
true);
660 if (!is_fixed_array()) {
661 LookupIterator it(isolate_, storage_, index, LookupIterator::OWN);
662 MAYBE_RETURN(JSReceiver::CreateDataProperty(&it, elm, kThrowOnError),
667 if (fast_elements()) {
668 if (index < static_cast<uint32_t>(storage_fixed_array()->length())) {
669 storage_fixed_array()->set(index, *elm);
679 DCHECK(!fast_elements());
680 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_), isolate_);
683 Handle<JSObject> not_a_prototype_holder;
684 Handle<NumberDictionary> result = NumberDictionary::Set(
685 isolate_, dict, index, elm, not_a_prototype_holder);
686 if (!result.is_identical_to(dict)) {
689 set_storage(*result);
694 uint32_t index_offset()
const {
return index_offset_; }
696 void increase_index_offset(
uint32_t delta) {
697 if (JSObject::kMaxElementCount - index_offset_ < delta) {
698 index_offset_ = JSObject::kMaxElementCount;
700 index_offset_ += delta;
705 if (fast_elements() &&
707 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
712 bool exceeds_array_limit()
const {
713 return ExceedsLimitField::decode(bit_field_);
716 Handle<JSArray> ToArray() {
717 DCHECK(is_fixed_array());
718 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
719 Handle<Object> length =
720 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
721 Handle<Map> map = JSObject::GetElementsTransitionMap(
722 array, fast_elements() ? HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
723 array->set_length(*length);
724 array->set_elements(*storage_fixed_array());
725 array->synchronized_set_map(*map);
729 V8_WARN_UNUSED_RESULT MaybeHandle<JSReceiver> ToJSReceiver() {
730 DCHECK(!is_fixed_array());
731 Handle<JSReceiver> result = Handle<JSReceiver>::cast(storage_);
732 Handle<Object> length =
733 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
736 JSReceiver::SetProperty(isolate_, result,
737 isolate_->factory()->length_string(), length,
738 LanguageMode::kStrict),
742 bool has_simple_elements()
const {
743 return HasSimpleElementsField::decode(bit_field_);
748 void SetDictionaryMode() {
749 DCHECK(fast_elements() && is_fixed_array());
750 Handle<FixedArray> current_storage = storage_fixed_array();
751 Handle<NumberDictionary> slow_storage(
752 NumberDictionary::New(isolate_, current_storage->length()));
754 FOR_WITH_HANDLE_SCOPE(
755 isolate_,
uint32_t,
i = 0,
i,
i < current_length,
i++, {
756 Handle<Object> element(current_storage->get(
i), isolate_);
757 if (!element->IsTheHole(isolate_)) {
760 Handle<JSObject> not_a_prototype_holder;
761 Handle<NumberDictionary> new_storage = NumberDictionary::Set(
762 isolate_, slow_storage,
i, element, not_a_prototype_holder);
763 if (!new_storage.is_identical_to(slow_storage)) {
764 slow_storage = loop_scope.CloseAndEscape(new_storage);
769 set_storage(*slow_storage);
770 set_fast_elements(
false);
773 inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); }
775 inline void set_storage(FixedArray storage) {
776 DCHECK(is_fixed_array());
777 DCHECK(has_simple_elements());
778 storage_ = isolate_->global_handles()->Create(storage);
781 class FastElementsField :
public BitField<bool, 0, 1> {};
782 class ExceedsLimitField :
public BitField<bool, 1, 1> {};
783 class IsFixedArrayField :
public BitField<bool, 2, 1> {};
784 class HasSimpleElementsField :
public BitField<bool, 3, 1> {};
786 bool fast_elements()
const {
return FastElementsField::decode(bit_field_); }
787 void set_fast_elements(
bool fast) {
788 bit_field_ = FastElementsField::update(bit_field_, fast);
790 void set_exceeds_array_limit(
bool exceeds) {
791 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
793 bool is_fixed_array()
const {
return IsFixedArrayField::decode(bit_field_); }
794 Handle<FixedArray> storage_fixed_array() {
795 DCHECK(is_fixed_array());
796 DCHECK(has_simple_elements());
797 return Handle<FixedArray>::cast(storage_);
801 Handle<Object> storage_;
808 uint32_t EstimateElementCount(Isolate* isolate, Handle<JSArray> array) {
809 DisallowHeapAllocation no_gc;
811 int element_count = 0;
812 switch (array->GetElementsKind()) {
813 case PACKED_SMI_ELEMENTS:
814 case HOLEY_SMI_ELEMENTS:
815 case PACKED_ELEMENTS:
816 case HOLEY_ELEMENTS: {
819 DCHECK_GE(static_cast<int32_t>(FixedArray::kMaxLength), 0);
820 int fast_length =
static_cast<int>(length);
821 FixedArray elements = FixedArray::cast(array->elements());
822 for (
int i = 0;
i < fast_length;
i++) {
823 if (!elements->get(
i)->IsTheHole(isolate)) element_count++;
827 case PACKED_DOUBLE_ELEMENTS:
828 case HOLEY_DOUBLE_ELEMENTS: {
831 DCHECK_GE(static_cast<int32_t>(FixedDoubleArray::kMaxLength), 0);
832 int fast_length =
static_cast<int>(length);
833 if (array->elements()->IsFixedArray()) {
834 DCHECK_EQ(FixedArray::cast(array->elements())->length(), 0);
837 FixedDoubleArray elements = FixedDoubleArray::cast(array->elements());
838 for (
int i = 0;
i < fast_length;
i++) {
839 if (!elements->is_the_hole(
i)) element_count++;
843 case DICTIONARY_ELEMENTS: {
844 NumberDictionary dictionary = NumberDictionary::cast(array->elements());
845 int capacity = dictionary->Capacity();
846 ReadOnlyRoots roots(isolate);
847 for (
int i = 0;
i < capacity;
i++) {
848 Object* key = dictionary->KeyAt(
i);
849 if (dictionary->IsKey(roots, key)) {
855 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 857 TYPED_ARRAYS(TYPED_ARRAY_CASE)
858 #undef TYPED_ARRAY_CASE 863 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
864 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
865 case FAST_STRING_WRAPPER_ELEMENTS:
866 case SLOW_STRING_WRAPPER_ELEMENTS:
871 return element_count;
874 void CollectElementIndices(Isolate* isolate, Handle<JSObject>
object,
875 uint32_t range, std::vector<uint32_t>* indices) {
876 ElementsKind kind =
object->GetElementsKind();
878 case PACKED_SMI_ELEMENTS:
879 case PACKED_ELEMENTS:
880 case HOLEY_SMI_ELEMENTS:
881 case HOLEY_ELEMENTS: {
882 DisallowHeapAllocation no_gc;
883 FixedArray elements = FixedArray::cast(object->elements());
885 if (range < length) length = range;
887 if (!elements->get(
i)->IsTheHole(isolate)) {
888 indices->push_back(
i);
893 case HOLEY_DOUBLE_ELEMENTS:
894 case PACKED_DOUBLE_ELEMENTS: {
895 if (object->elements()->IsFixedArray()) {
896 DCHECK_EQ(object->elements()->length(), 0);
899 Handle<FixedDoubleArray> elements(
900 FixedDoubleArray::cast(object->elements()), isolate);
902 if (range < length) length = range;
904 if (!elements->is_the_hole(
i)) {
905 indices->push_back(
i);
910 case DICTIONARY_ELEMENTS: {
911 DisallowHeapAllocation no_gc;
912 NumberDictionary dict = NumberDictionary::cast(object->elements());
913 uint32_t capacity = dict->Capacity();
914 ReadOnlyRoots roots(isolate);
915 FOR_WITH_HANDLE_SCOPE(isolate,
uint32_t, j = 0, j, j < capacity, j++, {
916 Object* k = dict->KeyAt(j);
917 if (!dict->IsKey(roots, k))
continue;
918 DCHECK(k->IsNumber());
921 indices->push_back(index);
926 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 928 TYPED_ARRAYS(TYPED_ARRAY_CASE)
929 #undef TYPED_ARRAY_CASE 932 if (range <= length) {
939 indices->push_back(
i);
941 if (length == range)
return;
944 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
945 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
946 DisallowHeapAllocation no_gc;
947 FixedArrayBase elements =
object->elements();
948 JSObject* raw_object = *object;
949 ElementsAccessor* accessor =
object->GetElementsAccessor();
951 if (accessor->HasElement(raw_object,
i, elements)) {
952 indices->push_back(
i);
957 case FAST_STRING_WRAPPER_ELEMENTS:
958 case SLOW_STRING_WRAPPER_ELEMENTS: {
959 DCHECK(object->IsJSValue());
960 Handle<JSValue> js_value = Handle<JSValue>::cast(
object);
961 DCHECK(js_value->value()->IsString());
962 Handle<String> string(String::cast(js_value->value()), isolate);
965 uint32_t limit = Min(length, range);
966 for (;
i < limit;
i++) {
967 indices->push_back(
i);
969 ElementsAccessor* accessor =
object->GetElementsAccessor();
970 for (;
i < range;
i++) {
971 if (accessor->HasElement(*
object,
i)) {
972 indices->push_back(
i);
981 PrototypeIterator iter(isolate,
object);
982 if (!iter.IsAtEnd()) {
985 CollectElementIndices(
986 isolate, PrototypeIterator::GetCurrent<JSObject>(iter), range, indices);
990 bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver,
991 uint32_t length, ArrayConcatVisitor* visitor) {
992 FOR_WITH_HANDLE_SCOPE(isolate,
uint32_t,
i = 0,
i,
i < length, ++
i, {
993 Maybe<bool> maybe = JSReceiver::HasElement(receiver,
i);
994 if (maybe.IsNothing())
return false;
995 if (maybe.FromJust()) {
996 Handle<Object> element_value;
997 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
998 isolate, element_value, JSReceiver::GetElement(isolate, receiver,
i),
1000 if (!visitor->visit(
i, element_value))
return false;
1003 visitor->increase_index_offset(length);
1016 bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
1017 ArrayConcatVisitor* visitor) {
1020 if (receiver->IsJSArray()) {
1021 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
1022 length =
static_cast<uint32_t>(array->length()->Number());
1025 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1026 isolate, val, Object::GetLengthFromArrayLike(isolate, receiver),
false);
1027 if (visitor->index_offset() + val->Number() > kMaxSafeInteger) {
1028 isolate->Throw(*isolate->factory()->NewTypeError(
1029 MessageTemplate::kInvalidArrayLength));
1033 if (!val->ToUint32(&length)) {
1037 return IterateElementsSlow(isolate, receiver, length, visitor);
1040 if (!HasOnlySimpleElements(isolate, *receiver) ||
1041 !visitor->has_simple_elements()) {
1042 return IterateElementsSlow(isolate, receiver, length, visitor);
1044 Handle<JSObject> array = Handle<JSObject>::cast(receiver);
1046 switch (array->GetElementsKind()) {
1047 case PACKED_SMI_ELEMENTS:
1048 case PACKED_ELEMENTS:
1049 case HOLEY_SMI_ELEMENTS:
1050 case HOLEY_ELEMENTS: {
1053 Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate);
1054 int fast_length =
static_cast<int>(length);
1055 DCHECK(fast_length <= elements->length());
1056 FOR_WITH_HANDLE_SCOPE(isolate,
int, j = 0, j, j < fast_length, j++, {
1057 Handle<Object> element_value(elements->get(j), isolate);
1058 if (!element_value->IsTheHole(isolate)) {
1059 if (!visitor->visit(j, element_value))
return false;
1061 Maybe<bool> maybe = JSReceiver::HasElement(array, j);
1062 if (maybe.IsNothing())
return false;
1063 if (maybe.FromJust()) {
1066 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1067 isolate, element_value,
1068 JSReceiver::GetElement(isolate, array, j),
false);
1069 if (!visitor->visit(j, element_value))
return false;
1075 case HOLEY_DOUBLE_ELEMENTS:
1076 case PACKED_DOUBLE_ELEMENTS: {
1078 if (length == 0)
break;
1081 if (array->elements()->IsFixedArray()) {
1082 DCHECK_EQ(array->elements()->length(), 0);
1085 Handle<FixedDoubleArray> elements(
1086 FixedDoubleArray::cast(array->elements()), isolate);
1087 int fast_length =
static_cast<int>(length);
1088 DCHECK(fast_length <= elements->length());
1089 FOR_WITH_HANDLE_SCOPE(isolate,
int, j = 0, j, j < fast_length, j++, {
1090 if (!elements->is_the_hole(j)) {
1091 double double_value = elements->get_scalar(j);
1092 Handle<Object> element_value =
1093 isolate->factory()->NewNumber(double_value);
1094 if (!visitor->visit(j, element_value))
return false;
1096 Maybe<bool> maybe = JSReceiver::HasElement(array, j);
1097 if (maybe.IsNothing())
return false;
1098 if (maybe.FromJust()) {
1101 Handle<Object> element_value;
1102 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1103 isolate, element_value,
1104 JSReceiver::GetElement(isolate, array, j),
false);
1105 if (!visitor->visit(j, element_value))
return false;
1112 case DICTIONARY_ELEMENTS: {
1113 Handle<NumberDictionary> dict(array->element_dictionary(), isolate);
1114 std::vector<uint32_t> indices;
1115 indices.reserve(dict->Capacity() / 2);
1119 CollectElementIndices(isolate, array, length, &indices);
1120 std::sort(indices.begin(), indices.end());
1121 size_t n = indices.size();
1122 FOR_WITH_HANDLE_SCOPE(isolate,
size_t, j = 0, j, j < n, (
void)0, {
1124 Handle<Object> element;
1125 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1126 isolate, element, JSReceiver::GetElement(isolate, array, index),
1128 if (!visitor->visit(index, element))
return false;
1132 }
while (j < n && indices[j] == index);
1136 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1137 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
1138 FOR_WITH_HANDLE_SCOPE(
1139 isolate,
uint32_t, index = 0, index, index < length, index++, {
1140 Handle<Object> element;
1141 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1142 isolate, element, JSReceiver::GetElement(isolate, array, index),
1144 if (!visitor->visit(index, element))
return false;
1150 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 1151 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1152 #undef TYPED_ARRAY_CASE 1153 return IterateElementsSlow(isolate, receiver, length, visitor);
1154 case FAST_STRING_WRAPPER_ELEMENTS:
1155 case SLOW_STRING_WRAPPER_ELEMENTS:
1160 visitor->increase_index_offset(length);
1164 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) {
1165 HandleScope handle_scope(isolate);
1166 if (!obj->IsJSReceiver())
return Just(
false);
1167 if (!isolate->IsIsConcatSpreadableLookupChainIntact(JSReceiver::cast(*obj))) {
1169 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol());
1170 Handle<Object> value;
1171 MaybeHandle<Object> maybeValue =
1172 i::Runtime::GetObjectProperty(isolate, obj, key);
1173 if (!maybeValue.ToHandle(&value))
return Nothing<bool>();
1174 if (!value->IsUndefined(isolate))
return Just(value->BooleanValue(isolate));
1176 return Object::IsArray(obj);
1179 Object* Slow_ArrayConcat(BuiltinArguments* args, Handle<Object> species,
1181 int argument_count = args->length();
1183 bool is_array_species = *species == isolate->context()->array_function();
1190 ElementsKind kind = PACKED_SMI_ELEMENTS;
1192 uint32_t estimate_result_length = 0;
1194 FOR_WITH_HANDLE_SCOPE(isolate,
int,
i = 0,
i,
i < argument_count,
i++, {
1195 Handle<Object> obj = args->at(
i);
1198 if (obj->IsJSArray()) {
1199 Handle<JSArray> array(Handle<JSArray>::cast(obj));
1200 length_estimate =
static_cast<uint32_t>(array->length()->Number());
1201 if (length_estimate != 0) {
1202 ElementsKind array_kind =
1203 GetPackedElementsKind(array->GetElementsKind());
1204 kind = GetMoreGeneralElementsKind(kind, array_kind);
1206 element_estimate = EstimateElementCount(isolate, array);
1208 if (obj->IsHeapObject()) {
1209 kind = GetMoreGeneralElementsKind(
1210 kind, obj->IsNumber() ? PACKED_DOUBLE_ELEMENTS : PACKED_ELEMENTS);
1212 length_estimate = 1;
1213 element_estimate = 1;
1216 if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) {
1217 estimate_result_length = JSObject::kMaxElementCount;
1219 estimate_result_length += length_estimate;
1221 if (JSObject::kMaxElementCount - estimate_nof < element_estimate) {
1222 estimate_nof = JSObject::kMaxElementCount;
1224 estimate_nof += element_estimate;
1231 bool fast_case = is_array_species &&
1232 (estimate_nof * 2) >= estimate_result_length &&
1233 isolate->IsIsConcatSpreadableLookupChainIntact();
1235 if (fast_case && kind == PACKED_DOUBLE_ELEMENTS) {
1236 Handle<FixedArrayBase> storage =
1237 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
1239 bool failure =
false;
1240 if (estimate_result_length > 0) {
1241 Handle<FixedDoubleArray> double_storage =
1242 Handle<FixedDoubleArray>::cast(storage);
1243 for (
int i = 0;
i < argument_count;
i++) {
1244 Handle<Object> obj = args->at(
i);
1246 double_storage->set(j, Smi::ToInt(*obj));
1248 }
else if (obj->IsNumber()) {
1249 double_storage->set(j, obj->Number());
1252 DisallowHeapAllocation no_gc;
1253 JSArray* array = JSArray::cast(*obj);
1255 switch (array->GetElementsKind()) {
1256 case HOLEY_DOUBLE_ELEMENTS:
1257 case PACKED_DOUBLE_ELEMENTS: {
1259 if (length == 0)
break;
1260 FixedDoubleArray elements =
1261 FixedDoubleArray::cast(array->elements());
1263 if (elements->is_the_hole(
i)) {
1272 double double_value = elements->get_scalar(
i);
1273 double_storage->set(j, double_value);
1278 case HOLEY_SMI_ELEMENTS:
1279 case PACKED_SMI_ELEMENTS: {
1280 Object* the_hole = ReadOnlyRoots(isolate).the_hole_value();
1281 FixedArray elements(FixedArray::cast(array->elements()));
1283 Object* element = elements->get(
i);
1284 if (element == the_hole) {
1288 int32_t int_value = Smi::ToInt(element);
1289 double_storage->set(j, int_value);
1294 case HOLEY_ELEMENTS:
1295 case PACKED_ELEMENTS:
1296 case DICTIONARY_ELEMENTS:
1298 DCHECK_EQ(0u, length);
1308 return *isolate->factory()->NewJSArrayWithElements(storage, kind, j);
1313 Handle<HeapObject> storage;
1318 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
1319 }
else if (is_array_species) {
1320 storage = NumberDictionary::New(isolate, estimate_nof);
1322 DCHECK(species->IsConstructor());
1323 Handle<Object> length(Smi::kZero, isolate);
1324 Handle<Object> storage_object;
1325 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1326 isolate, storage_object,
1327 Execution::New(isolate, species, species, 1, &length));
1328 storage = Handle<HeapObject>::cast(storage_object);
1331 ArrayConcatVisitor visitor(isolate, storage, fast_case);
1333 for (
int i = 0;
i < argument_count;
i++) {
1334 Handle<Object> obj = args->at(
i);
1335 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj);
1336 MAYBE_RETURN(spreadable, ReadOnlyRoots(isolate).exception());
1337 if (spreadable.FromJust()) {
1338 Handle<JSReceiver>
object = Handle<JSReceiver>::cast(obj);
1339 if (!IterateElements(isolate,
object, &visitor)) {
1340 return ReadOnlyRoots(isolate).exception();
1343 if (!visitor.visit(0, obj))
return ReadOnlyRoots(isolate).exception();
1344 visitor.increase_index_offset(1);
1348 if (visitor.exceeds_array_limit()) {
1349 THROW_NEW_ERROR_RETURN_FAILURE(
1350 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength));
1353 if (is_array_species) {
1354 return *visitor.ToArray();
1356 RETURN_RESULT_OR_FAILURE(isolate, visitor.ToJSReceiver());
1360 bool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) {
1361 DisallowHeapAllocation no_gc;
1362 Map map = obj->map();
1364 if (map->prototype() ==
1365 isolate->native_context()->initial_array_prototype() &&
1366 map->NumberOfOwnDescriptors() == 1) {
1374 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate,
1375 BuiltinArguments* args) {
1376 if (!isolate->IsIsConcatSpreadableLookupChainIntact()) {
1377 return MaybeHandle<JSArray>();
1380 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
1381 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
1382 STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt);
1385 int n_arguments = args->length();
1388 DisallowHeapAllocation no_gc;
1391 for (
int i = 0;
i < n_arguments;
i++) {
1392 ObjectPtr arg = (*args)[
i];
1393 if (!arg->IsJSArray())
return MaybeHandle<JSArray>();
1394 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) {
1395 return MaybeHandle<JSArray>();
1398 if (!JSObject::cast(arg)->HasFastElements()) {
1399 return MaybeHandle<JSArray>();
1401 Handle<JSArray> array(JSArray::cast(arg), isolate);
1402 if (!IsSimpleArray(isolate, array)) {
1403 return MaybeHandle<JSArray>();
1407 result_len += Smi::ToInt(array->length());
1408 DCHECK_GE(result_len, 0);
1410 if (FixedDoubleArray::kMaxLength < result_len ||
1411 FixedArray::kMaxLength < result_len) {
1412 AllowHeapAllocation gc;
1413 THROW_NEW_ERROR(isolate,
1414 NewRangeError(MessageTemplate::kInvalidArrayLength),
1419 return ElementsAccessor::Concat(isolate, args, n_arguments, result_len);
1425 BUILTIN(ArrayConcat) {
1426 HandleScope scope(isolate);
1428 Handle<Object> receiver = args.receiver();
1429 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1431 Object::ToObject(isolate, args.receiver(),
"Array.prototype.concat"));
1432 args.set_at(0, *receiver);
1434 Handle<JSArray> result_array;
1437 if (V8_LIKELY(receiver->IsJSArray() &&
1438 Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) &&
1439 isolate->IsArraySpeciesLookupChainIntact())) {
1440 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
1441 return *result_array;
1443 if (isolate->has_pending_exception())
1444 return ReadOnlyRoots(isolate).exception();
1448 Handle<Object> species;
1449 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1450 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver));
1451 if (*species == *isolate->array_function()) {
1452 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
1453 return *result_array;
1455 if (isolate->has_pending_exception())
1456 return ReadOnlyRoots(isolate).exception();
1458 return Slow_ArrayConcat(&args, species, isolate);