11cb0ef41Sopenharmony_ci// Copyright 2016 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/base/logging.h" 61cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-inl.h" 71cb0ef41Sopenharmony_ci#include "src/builtins/builtins.h" 81cb0ef41Sopenharmony_ci#include "src/codegen/code-factory.h" 91cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h" 101cb0ef41Sopenharmony_ci#include "src/debug/debug.h" 111cb0ef41Sopenharmony_ci#include "src/execution/isolate.h" 121cb0ef41Sopenharmony_ci#include "src/execution/protectors-inl.h" 131cb0ef41Sopenharmony_ci#include "src/handles/global-handles-inl.h" 141cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 151cb0ef41Sopenharmony_ci#include "src/objects/contexts.h" 161cb0ef41Sopenharmony_ci#include "src/objects/elements-inl.h" 171cb0ef41Sopenharmony_ci#include "src/objects/hash-table-inl.h" 181cb0ef41Sopenharmony_ci#include "src/objects/js-array-buffer-inl.h" 191cb0ef41Sopenharmony_ci#include "src/objects/js-array-inl.h" 201cb0ef41Sopenharmony_ci#include "src/objects/js-collection-inl.h" 211cb0ef41Sopenharmony_ci#include "src/objects/lookup.h" 221cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 231cb0ef41Sopenharmony_ci#include "src/objects/prototype.h" 241cb0ef41Sopenharmony_ci#include "src/objects/smi.h" 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_cinamespace v8 { 271cb0ef41Sopenharmony_cinamespace internal { 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_cinamespace { 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciinline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, 321cb0ef41Sopenharmony_ci JSArray receiver) { 331cb0ef41Sopenharmony_ci return JSObject::PrototypeHasNoElements(isolate, receiver); 341cb0ef41Sopenharmony_ci} 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ciinline bool HasSimpleElements(JSObject current) { 371cb0ef41Sopenharmony_ci return !current.map().IsCustomElementsReceiverMap() && 381cb0ef41Sopenharmony_ci !current.GetElementsAccessor()->HasAccessors(current); 391cb0ef41Sopenharmony_ci} 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ciinline bool HasOnlySimpleReceiverElements(Isolate* isolate, JSObject receiver) { 421cb0ef41Sopenharmony_ci // Check that we have no accessors on the receiver's elements. 431cb0ef41Sopenharmony_ci if (!HasSimpleElements(receiver)) return false; 441cb0ef41Sopenharmony_ci return JSObject::PrototypeHasNoElements(isolate, receiver); 451cb0ef41Sopenharmony_ci} 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ciinline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver receiver) { 481cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 491cb0ef41Sopenharmony_ci PrototypeIterator iter(isolate, receiver, kStartAtReceiver); 501cb0ef41Sopenharmony_ci for (; !iter.IsAtEnd(); iter.Advance()) { 511cb0ef41Sopenharmony_ci if (iter.GetCurrent().IsJSProxy()) return false; 521cb0ef41Sopenharmony_ci JSObject current = iter.GetCurrent<JSObject>(); 531cb0ef41Sopenharmony_ci if (!HasSimpleElements(current)) return false; 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci return true; 561cb0ef41Sopenharmony_ci} 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci// This method may transition the elements kind of the JSArray once, to make 591cb0ef41Sopenharmony_ci// sure that all elements provided as arguments in the specified range can be 601cb0ef41Sopenharmony_ci// added without further elements kinds transitions. 611cb0ef41Sopenharmony_civoid MatchArrayElementsKindToArguments(Isolate* isolate, Handle<JSArray> array, 621cb0ef41Sopenharmony_ci BuiltinArguments* args, 631cb0ef41Sopenharmony_ci int first_arg_index, int num_arguments) { 641cb0ef41Sopenharmony_ci int args_length = args->length(); 651cb0ef41Sopenharmony_ci if (first_arg_index >= args_length) return; 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci ElementsKind origin_kind = array->GetElementsKind(); 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci // We do not need to transition for PACKED/HOLEY_ELEMENTS. 701cb0ef41Sopenharmony_ci if (IsObjectElementsKind(origin_kind)) return; 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci ElementsKind target_kind = origin_kind; 731cb0ef41Sopenharmony_ci { 741cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 751cb0ef41Sopenharmony_ci int last_arg_index = std::min(first_arg_index + num_arguments, args_length); 761cb0ef41Sopenharmony_ci for (int i = first_arg_index; i < last_arg_index; i++) { 771cb0ef41Sopenharmony_ci Object arg = (*args)[i]; 781cb0ef41Sopenharmony_ci if (arg.IsHeapObject()) { 791cb0ef41Sopenharmony_ci if (arg.IsHeapNumber()) { 801cb0ef41Sopenharmony_ci target_kind = PACKED_DOUBLE_ELEMENTS; 811cb0ef41Sopenharmony_ci } else { 821cb0ef41Sopenharmony_ci target_kind = PACKED_ELEMENTS; 831cb0ef41Sopenharmony_ci break; 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci } 871cb0ef41Sopenharmony_ci } 881cb0ef41Sopenharmony_ci if (target_kind != origin_kind) { 891cb0ef41Sopenharmony_ci // Use a short-lived HandleScope to avoid creating several copies of the 901cb0ef41Sopenharmony_ci // elements handle which would cause issues when left-trimming later-on. 911cb0ef41Sopenharmony_ci HandleScope scope(isolate); 921cb0ef41Sopenharmony_ci JSObject::TransitionElementsKind(array, target_kind); 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci} 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci// Returns |false| if not applicable. 971cb0ef41Sopenharmony_ci// TODO(szuend): Refactor this function because it is getting hard to 981cb0ef41Sopenharmony_ci// understand what each call-site actually checks. 991cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT 1001cb0ef41Sopenharmony_ciinline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, 1011cb0ef41Sopenharmony_ci Handle<Object> receiver, 1021cb0ef41Sopenharmony_ci BuiltinArguments* args, 1031cb0ef41Sopenharmony_ci int first_arg_index, 1041cb0ef41Sopenharmony_ci int num_arguments) { 1051cb0ef41Sopenharmony_ci if (!receiver->IsJSArray()) return false; 1061cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 1071cb0ef41Sopenharmony_ci ElementsKind origin_kind = array->GetElementsKind(); 1081cb0ef41Sopenharmony_ci if (IsDictionaryElementsKind(origin_kind)) return false; 1091cb0ef41Sopenharmony_ci if (!array->map().is_extensible()) return false; 1101cb0ef41Sopenharmony_ci if (args == nullptr) return true; 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci // If there may be elements accessors in the prototype chain, the fast path 1131cb0ef41Sopenharmony_ci // cannot be used if there arguments to add to the array. 1141cb0ef41Sopenharmony_ci if (!IsJSArrayFastElementMovingAllowed(isolate, *array)) return false; 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci // Adding elements to the array prototype would break code that makes sure 1171cb0ef41Sopenharmony_ci // it has no elements. Handle that elsewhere. 1181cb0ef41Sopenharmony_ci if (isolate->IsAnyInitialArrayPrototype(*array)) return false; 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci // Need to ensure that the arguments passed in args can be contained in 1211cb0ef41Sopenharmony_ci // the array. 1221cb0ef41Sopenharmony_ci MatchArrayElementsKindToArguments(isolate, array, args, first_arg_index, 1231cb0ef41Sopenharmony_ci num_arguments); 1241cb0ef41Sopenharmony_ci return true; 1251cb0ef41Sopenharmony_ci} 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci// If |index| is Undefined, returns init_if_undefined. 1281cb0ef41Sopenharmony_ci// If |index| is negative, returns length + index. 1291cb0ef41Sopenharmony_ci// If |index| is positive, returns index. 1301cb0ef41Sopenharmony_ci// Returned value is guaranteed to be in the interval of [0, length]. 1311cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT Maybe<double> GetRelativeIndex(Isolate* isolate, 1321cb0ef41Sopenharmony_ci double length, 1331cb0ef41Sopenharmony_ci Handle<Object> index, 1341cb0ef41Sopenharmony_ci double init_if_undefined) { 1351cb0ef41Sopenharmony_ci double relative_index = init_if_undefined; 1361cb0ef41Sopenharmony_ci if (!index->IsUndefined()) { 1371cb0ef41Sopenharmony_ci Handle<Object> relative_index_obj; 1381cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, relative_index_obj, 1391cb0ef41Sopenharmony_ci Object::ToInteger(isolate, index), 1401cb0ef41Sopenharmony_ci Nothing<double>()); 1411cb0ef41Sopenharmony_ci relative_index = relative_index_obj->Number(); 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci if (relative_index < 0) { 1451cb0ef41Sopenharmony_ci return Just(std::max(length + relative_index, 0.0)); 1461cb0ef41Sopenharmony_ci } 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci return Just(std::min(relative_index, length)); 1491cb0ef41Sopenharmony_ci} 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci// Returns "length", has "fast-path" for JSArrays. 1521cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT Maybe<double> GetLengthProperty( 1531cb0ef41Sopenharmony_ci Isolate* isolate, Handle<JSReceiver> receiver) { 1541cb0ef41Sopenharmony_ci if (receiver->IsJSArray()) { 1551cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 1561cb0ef41Sopenharmony_ci double length = array->length().Number(); 1571cb0ef41Sopenharmony_ci DCHECK(0 <= length && length <= kMaxSafeInteger); 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci return Just(length); 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci Handle<Object> raw_length_number; 1631cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1641cb0ef41Sopenharmony_ci isolate, raw_length_number, 1651cb0ef41Sopenharmony_ci Object::GetLengthFromArrayLike(isolate, receiver), Nothing<double>()); 1661cb0ef41Sopenharmony_ci return Just(raw_length_number->Number()); 1671cb0ef41Sopenharmony_ci} 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci// Set "length" property, has "fast-path" for JSArrays. 1701cb0ef41Sopenharmony_ci// Returns Nothing if something went wrong. 1711cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT MaybeHandle<Object> SetLengthProperty( 1721cb0ef41Sopenharmony_ci Isolate* isolate, Handle<JSReceiver> receiver, double length) { 1731cb0ef41Sopenharmony_ci if (receiver->IsJSArray()) { 1741cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 1751cb0ef41Sopenharmony_ci if (!JSArray::HasReadOnlyLength(array)) { 1761cb0ef41Sopenharmony_ci DCHECK_LE(length, kMaxUInt32); 1771cb0ef41Sopenharmony_ci MAYBE_RETURN_NULL( 1781cb0ef41Sopenharmony_ci JSArray::SetLength(array, static_cast<uint32_t>(length))); 1791cb0ef41Sopenharmony_ci return receiver; 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci } 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci return Object::SetProperty( 1841cb0ef41Sopenharmony_ci isolate, receiver, isolate->factory()->length_string(), 1851cb0ef41Sopenharmony_ci isolate->factory()->NewNumber(length), StoreOrigin::kMaybeKeyed, 1861cb0ef41Sopenharmony_ci Just(ShouldThrow::kThrowOnError)); 1871cb0ef41Sopenharmony_ci} 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT Object GenericArrayFill(Isolate* isolate, 1901cb0ef41Sopenharmony_ci Handle<JSReceiver> receiver, 1911cb0ef41Sopenharmony_ci Handle<Object> value, 1921cb0ef41Sopenharmony_ci double start, double end) { 1931cb0ef41Sopenharmony_ci // 7. Repeat, while k < final. 1941cb0ef41Sopenharmony_ci while (start < end) { 1951cb0ef41Sopenharmony_ci // a. Let Pk be ! ToString(k). 1961cb0ef41Sopenharmony_ci Handle<String> index = isolate->factory()->NumberToString( 1971cb0ef41Sopenharmony_ci isolate->factory()->NewNumber(start)); 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci // b. Perform ? Set(O, Pk, value, true). 2001cb0ef41Sopenharmony_ci RETURN_FAILURE_ON_EXCEPTION(isolate, Object::SetPropertyOrElement( 2011cb0ef41Sopenharmony_ci isolate, receiver, index, value, 2021cb0ef41Sopenharmony_ci Just(ShouldThrow::kThrowOnError))); 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci // c. Increase k by 1. 2051cb0ef41Sopenharmony_ci ++start; 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci // 8. Return O. 2091cb0ef41Sopenharmony_ci return *receiver; 2101cb0ef41Sopenharmony_ci} 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT Maybe<bool> TryFastArrayFill( 2131cb0ef41Sopenharmony_ci Isolate* isolate, BuiltinArguments* args, Handle<JSReceiver> receiver, 2141cb0ef41Sopenharmony_ci Handle<Object> value, double start_index, double end_index) { 2151cb0ef41Sopenharmony_ci // If indices are too large, use generic path since they are stored as 2161cb0ef41Sopenharmony_ci // properties, not in the element backing store. 2171cb0ef41Sopenharmony_ci if (end_index > kMaxUInt32) return Just(false); 2181cb0ef41Sopenharmony_ci if (!receiver->IsJSObject()) return Just(false); 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_ci if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, args, 1, 1)) { 2211cb0ef41Sopenharmony_ci return Just(false); 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci // If no argument was provided, we fill the array with 'undefined'. 2271cb0ef41Sopenharmony_ci // EnsureJSArrayWith... does not handle that case so we do it here. 2281cb0ef41Sopenharmony_ci // TODO(szuend): Pass target elements kind to EnsureJSArrayWith... when 2291cb0ef41Sopenharmony_ci // it gets refactored. 2301cb0ef41Sopenharmony_ci if (args->length() == 1 && array->GetElementsKind() != PACKED_ELEMENTS) { 2311cb0ef41Sopenharmony_ci // Use a short-lived HandleScope to avoid creating several copies of the 2321cb0ef41Sopenharmony_ci // elements handle which would cause issues when left-trimming later-on. 2331cb0ef41Sopenharmony_ci HandleScope scope(isolate); 2341cb0ef41Sopenharmony_ci JSObject::TransitionElementsKind(array, PACKED_ELEMENTS); 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci DCHECK_LE(start_index, kMaxUInt32); 2381cb0ef41Sopenharmony_ci DCHECK_LE(end_index, kMaxUInt32); 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci uint32_t start, end; 2411cb0ef41Sopenharmony_ci CHECK(DoubleToUint32IfEqualToSelf(start_index, &start)); 2421cb0ef41Sopenharmony_ci CHECK(DoubleToUint32IfEqualToSelf(end_index, &end)); 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci ElementsAccessor* accessor = array->GetElementsAccessor(); 2451cb0ef41Sopenharmony_ci RETURN_ON_EXCEPTION_VALUE(isolate, accessor->Fill(array, value, start, end), 2461cb0ef41Sopenharmony_ci Nothing<bool>()); 2471cb0ef41Sopenharmony_ci return Just(true); 2481cb0ef41Sopenharmony_ci} 2491cb0ef41Sopenharmony_ci} // namespace 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ciBUILTIN(ArrayPrototypeFill) { 2521cb0ef41Sopenharmony_ci HandleScope scope(isolate); 2531cb0ef41Sopenharmony_ci if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) { 2541cb0ef41Sopenharmony_ci if (!isolate->debug()->PerformSideEffectCheckForObject(args.receiver())) { 2551cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).exception(); 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci // 1. Let O be ? ToObject(this value). 2601cb0ef41Sopenharmony_ci Handle<JSReceiver> receiver; 2611cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2621cb0ef41Sopenharmony_ci isolate, receiver, Object::ToObject(isolate, args.receiver())); 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci // 2. Let len be ? ToLength(? Get(O, "length")). 2651cb0ef41Sopenharmony_ci double length; 2661cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2671cb0ef41Sopenharmony_ci isolate, length, GetLengthProperty(isolate, receiver)); 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci // 3. Let relativeStart be ? ToInteger(start). 2701cb0ef41Sopenharmony_ci // 4. If relativeStart < 0, let k be max((len + relativeStart), 0); 2711cb0ef41Sopenharmony_ci // else let k be min(relativeStart, len). 2721cb0ef41Sopenharmony_ci Handle<Object> start = args.atOrUndefined(isolate, 2); 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci double start_index; 2751cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2761cb0ef41Sopenharmony_ci isolate, start_index, GetRelativeIndex(isolate, length, start, 0)); 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci // 5. If end is undefined, let relativeEnd be len; 2791cb0ef41Sopenharmony_ci // else let relativeEnd be ? ToInteger(end). 2801cb0ef41Sopenharmony_ci // 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0); 2811cb0ef41Sopenharmony_ci // else let final be min(relativeEnd, len). 2821cb0ef41Sopenharmony_ci Handle<Object> end = args.atOrUndefined(isolate, 3); 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci double end_index; 2851cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2861cb0ef41Sopenharmony_ci isolate, end_index, GetRelativeIndex(isolate, length, end, length)); 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_ci if (start_index >= end_index) return *receiver; 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci // Ensure indexes are within array bounds 2911cb0ef41Sopenharmony_ci DCHECK_LE(0, start_index); 2921cb0ef41Sopenharmony_ci DCHECK_LE(start_index, end_index); 2931cb0ef41Sopenharmony_ci DCHECK_LE(end_index, length); 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci Handle<Object> value = args.atOrUndefined(isolate, 1); 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci bool success; 2981cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2991cb0ef41Sopenharmony_ci isolate, success, 3001cb0ef41Sopenharmony_ci TryFastArrayFill(isolate, &args, receiver, value, start_index, 3011cb0ef41Sopenharmony_ci end_index)); 3021cb0ef41Sopenharmony_ci if (success) return *receiver; 3031cb0ef41Sopenharmony_ci return GenericArrayFill(isolate, receiver, value, start_index, end_index); 3041cb0ef41Sopenharmony_ci} 3051cb0ef41Sopenharmony_ci 3061cb0ef41Sopenharmony_cinamespace { 3071cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT Object GenericArrayPush(Isolate* isolate, 3081cb0ef41Sopenharmony_ci BuiltinArguments* args) { 3091cb0ef41Sopenharmony_ci // 1. Let O be ? ToObject(this value). 3101cb0ef41Sopenharmony_ci Handle<JSReceiver> receiver; 3111cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3121cb0ef41Sopenharmony_ci isolate, receiver, Object::ToObject(isolate, args->receiver())); 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci // 2. Let len be ? ToLength(? Get(O, "length")). 3151cb0ef41Sopenharmony_ci Handle<Object> raw_length_number; 3161cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3171cb0ef41Sopenharmony_ci isolate, raw_length_number, 3181cb0ef41Sopenharmony_ci Object::GetLengthFromArrayLike(isolate, receiver)); 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci // 3. Let args be a List whose elements are, in left to right order, 3211cb0ef41Sopenharmony_ci // the arguments that were passed to this function invocation. 3221cb0ef41Sopenharmony_ci // 4. Let arg_count be the number of elements in args. 3231cb0ef41Sopenharmony_ci int arg_count = args->length() - 1; 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci // 5. If len + arg_count > 2^53-1, throw a TypeError exception. 3261cb0ef41Sopenharmony_ci double length = raw_length_number->Number(); 3271cb0ef41Sopenharmony_ci if (arg_count > kMaxSafeInteger - length) { 3281cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 3291cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kPushPastSafeLength, 3301cb0ef41Sopenharmony_ci isolate->factory()->NewNumberFromInt(arg_count), 3311cb0ef41Sopenharmony_ci raw_length_number)); 3321cb0ef41Sopenharmony_ci } 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci // 6. Repeat, while args is not empty. 3351cb0ef41Sopenharmony_ci for (int i = 0; i < arg_count; ++i) { 3361cb0ef41Sopenharmony_ci // a. Remove the first element from args and let E be the value of the 3371cb0ef41Sopenharmony_ci // element. 3381cb0ef41Sopenharmony_ci Handle<Object> element = args->at(i + 1); 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci // b. Perform ? Set(O, ! ToString(len), E, true). 3411cb0ef41Sopenharmony_ci if (length <= JSObject::kMaxElementIndex) { 3421cb0ef41Sopenharmony_ci RETURN_FAILURE_ON_EXCEPTION( 3431cb0ef41Sopenharmony_ci isolate, Object::SetElement(isolate, receiver, length, element, 3441cb0ef41Sopenharmony_ci ShouldThrow::kThrowOnError)); 3451cb0ef41Sopenharmony_ci } else { 3461cb0ef41Sopenharmony_ci PropertyKey key(isolate, length); 3471cb0ef41Sopenharmony_ci LookupIterator it(isolate, receiver, key); 3481cb0ef41Sopenharmony_ci MAYBE_RETURN(Object::SetProperty(&it, element, StoreOrigin::kMaybeKeyed, 3491cb0ef41Sopenharmony_ci Just(ShouldThrow::kThrowOnError)), 3501cb0ef41Sopenharmony_ci ReadOnlyRoots(isolate).exception()); 3511cb0ef41Sopenharmony_ci } 3521cb0ef41Sopenharmony_ci 3531cb0ef41Sopenharmony_ci // c. Let len be len+1. 3541cb0ef41Sopenharmony_ci ++length; 3551cb0ef41Sopenharmony_ci } 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci // 7. Perform ? Set(O, "length", len, true). 3581cb0ef41Sopenharmony_ci Handle<Object> final_length = isolate->factory()->NewNumber(length); 3591cb0ef41Sopenharmony_ci RETURN_FAILURE_ON_EXCEPTION( 3601cb0ef41Sopenharmony_ci isolate, Object::SetProperty(isolate, receiver, 3611cb0ef41Sopenharmony_ci isolate->factory()->length_string(), 3621cb0ef41Sopenharmony_ci final_length, StoreOrigin::kMaybeKeyed, 3631cb0ef41Sopenharmony_ci Just(ShouldThrow::kThrowOnError))); 3641cb0ef41Sopenharmony_ci 3651cb0ef41Sopenharmony_ci // 8. Return len. 3661cb0ef41Sopenharmony_ci return *final_length; 3671cb0ef41Sopenharmony_ci} 3681cb0ef41Sopenharmony_ci} // namespace 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ciBUILTIN(ArrayPush) { 3711cb0ef41Sopenharmony_ci HandleScope scope(isolate); 3721cb0ef41Sopenharmony_ci Handle<Object> receiver = args.receiver(); 3731cb0ef41Sopenharmony_ci if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1, 3741cb0ef41Sopenharmony_ci args.length() - 1)) { 3751cb0ef41Sopenharmony_ci return GenericArrayPush(isolate, &args); 3761cb0ef41Sopenharmony_ci } 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_ci // Fast Elements Path 3791cb0ef41Sopenharmony_ci int to_add = args.length() - 1; 3801cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 3811cb0ef41Sopenharmony_ci uint32_t len = static_cast<uint32_t>(array->length().Number()); 3821cb0ef41Sopenharmony_ci if (to_add == 0) return *isolate->factory()->NewNumberFromUint(len); 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ci // Currently fixed arrays cannot grow too big, so we should never hit this. 3851cb0ef41Sopenharmony_ci DCHECK_LE(to_add, Smi::kMaxValue - Smi::ToInt(array->length())); 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ci if (JSArray::HasReadOnlyLength(array)) { 3881cb0ef41Sopenharmony_ci return GenericArrayPush(isolate, &args); 3891cb0ef41Sopenharmony_ci } 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_ci ElementsAccessor* accessor = array->GetElementsAccessor(); 3921cb0ef41Sopenharmony_ci uint32_t new_length; 3931cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3941cb0ef41Sopenharmony_ci isolate, new_length, accessor->Push(array, &args, to_add)); 3951cb0ef41Sopenharmony_ci return *isolate->factory()->NewNumberFromUint((new_length)); 3961cb0ef41Sopenharmony_ci} 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_cinamespace { 3991cb0ef41Sopenharmony_ci 4001cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT Object GenericArrayPop(Isolate* isolate, 4011cb0ef41Sopenharmony_ci BuiltinArguments* args) { 4021cb0ef41Sopenharmony_ci // 1. Let O be ? ToObject(this value). 4031cb0ef41Sopenharmony_ci Handle<JSReceiver> receiver; 4041cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4051cb0ef41Sopenharmony_ci isolate, receiver, Object::ToObject(isolate, args->receiver())); 4061cb0ef41Sopenharmony_ci 4071cb0ef41Sopenharmony_ci // 2. Let len be ? ToLength(? Get(O, "length")). 4081cb0ef41Sopenharmony_ci Handle<Object> raw_length_number; 4091cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4101cb0ef41Sopenharmony_ci isolate, raw_length_number, 4111cb0ef41Sopenharmony_ci Object::GetLengthFromArrayLike(isolate, receiver)); 4121cb0ef41Sopenharmony_ci double length = raw_length_number->Number(); 4131cb0ef41Sopenharmony_ci 4141cb0ef41Sopenharmony_ci // 3. If len is zero, then. 4151cb0ef41Sopenharmony_ci if (length == 0) { 4161cb0ef41Sopenharmony_ci // a. Perform ? Set(O, "length", 0, true). 4171cb0ef41Sopenharmony_ci RETURN_FAILURE_ON_EXCEPTION( 4181cb0ef41Sopenharmony_ci isolate, Object::SetProperty(isolate, receiver, 4191cb0ef41Sopenharmony_ci isolate->factory()->length_string(), 4201cb0ef41Sopenharmony_ci Handle<Smi>(Smi::zero(), isolate), 4211cb0ef41Sopenharmony_ci StoreOrigin::kMaybeKeyed, 4221cb0ef41Sopenharmony_ci Just(ShouldThrow::kThrowOnError))); 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_ci // b. Return undefined. 4251cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).undefined_value(); 4261cb0ef41Sopenharmony_ci } 4271cb0ef41Sopenharmony_ci 4281cb0ef41Sopenharmony_ci // 4. Else len > 0. 4291cb0ef41Sopenharmony_ci // a. Let new_len be len-1. 4301cb0ef41Sopenharmony_ci Handle<Object> new_length = isolate->factory()->NewNumber(length - 1); 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ci // b. Let index be ! ToString(newLen). 4331cb0ef41Sopenharmony_ci Handle<String> index = isolate->factory()->NumberToString(new_length); 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci // c. Let element be ? Get(O, index). 4361cb0ef41Sopenharmony_ci Handle<Object> element; 4371cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4381cb0ef41Sopenharmony_ci isolate, element, Object::GetPropertyOrElement(isolate, receiver, index)); 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci // d. Perform ? DeletePropertyOrThrow(O, index). 4411cb0ef41Sopenharmony_ci MAYBE_RETURN(JSReceiver::DeletePropertyOrElement(receiver, index, 4421cb0ef41Sopenharmony_ci LanguageMode::kStrict), 4431cb0ef41Sopenharmony_ci ReadOnlyRoots(isolate).exception()); 4441cb0ef41Sopenharmony_ci 4451cb0ef41Sopenharmony_ci // e. Perform ? Set(O, "length", newLen, true). 4461cb0ef41Sopenharmony_ci RETURN_FAILURE_ON_EXCEPTION( 4471cb0ef41Sopenharmony_ci isolate, Object::SetProperty(isolate, receiver, 4481cb0ef41Sopenharmony_ci isolate->factory()->length_string(), 4491cb0ef41Sopenharmony_ci new_length, StoreOrigin::kMaybeKeyed, 4501cb0ef41Sopenharmony_ci Just(ShouldThrow::kThrowOnError))); 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_ci // f. Return element. 4531cb0ef41Sopenharmony_ci return *element; 4541cb0ef41Sopenharmony_ci} 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci} // namespace 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ciBUILTIN(ArrayPop) { 4591cb0ef41Sopenharmony_ci HandleScope scope(isolate); 4601cb0ef41Sopenharmony_ci Handle<Object> receiver = args.receiver(); 4611cb0ef41Sopenharmony_ci if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0, 4621cb0ef41Sopenharmony_ci 0)) { 4631cb0ef41Sopenharmony_ci return GenericArrayPop(isolate, &args); 4641cb0ef41Sopenharmony_ci } 4651cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_ci uint32_t len = static_cast<uint32_t>(array->length().Number()); 4681cb0ef41Sopenharmony_ci 4691cb0ef41Sopenharmony_ci if (JSArray::HasReadOnlyLength(array)) { 4701cb0ef41Sopenharmony_ci return GenericArrayPop(isolate, &args); 4711cb0ef41Sopenharmony_ci } 4721cb0ef41Sopenharmony_ci if (len == 0) return ReadOnlyRoots(isolate).undefined_value(); 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ci Handle<Object> result; 4751cb0ef41Sopenharmony_ci if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { 4761cb0ef41Sopenharmony_ci // Fast Elements Path 4771cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4781cb0ef41Sopenharmony_ci isolate, result, array->GetElementsAccessor()->Pop(array)); 4791cb0ef41Sopenharmony_ci } else { 4801cb0ef41Sopenharmony_ci // Use Slow Lookup otherwise 4811cb0ef41Sopenharmony_ci uint32_t new_length = len - 1; 4821cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4831cb0ef41Sopenharmony_ci isolate, result, JSReceiver::GetElement(isolate, array, new_length)); 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci // The length could have become read-only during the last GetElement() call, 4861cb0ef41Sopenharmony_ci // so check again. 4871cb0ef41Sopenharmony_ci if (JSArray::HasReadOnlyLength(array)) { 4881cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 4891cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kStrictReadOnlyProperty, 4901cb0ef41Sopenharmony_ci isolate->factory()->length_string(), 4911cb0ef41Sopenharmony_ci Object::TypeOf(isolate, array), array)); 4921cb0ef41Sopenharmony_ci } 4931cb0ef41Sopenharmony_ci bool set_len_ok; 4941cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4951cb0ef41Sopenharmony_ci isolate, set_len_ok, JSArray::SetLength(array, new_length)); 4961cb0ef41Sopenharmony_ci } 4971cb0ef41Sopenharmony_ci 4981cb0ef41Sopenharmony_ci return *result; 4991cb0ef41Sopenharmony_ci} 5001cb0ef41Sopenharmony_ci 5011cb0ef41Sopenharmony_cinamespace { 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci// Returns true, iff we can use ElementsAccessor for shifting. 5041cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT bool CanUseFastArrayShift(Isolate* isolate, 5051cb0ef41Sopenharmony_ci Handle<JSReceiver> receiver) { 5061cb0ef41Sopenharmony_ci if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0, 5071cb0ef41Sopenharmony_ci 0) || 5081cb0ef41Sopenharmony_ci !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { 5091cb0ef41Sopenharmony_ci return false; 5101cb0ef41Sopenharmony_ci } 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 5131cb0ef41Sopenharmony_ci return !JSArray::HasReadOnlyLength(array); 5141cb0ef41Sopenharmony_ci} 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_ciV8_WARN_UNUSED_RESULT Object GenericArrayShift(Isolate* isolate, 5171cb0ef41Sopenharmony_ci Handle<JSReceiver> receiver, 5181cb0ef41Sopenharmony_ci double length) { 5191cb0ef41Sopenharmony_ci // 4. Let first be ? Get(O, "0"). 5201cb0ef41Sopenharmony_ci Handle<Object> first; 5211cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, first, 5221cb0ef41Sopenharmony_ci Object::GetElement(isolate, receiver, 0)); 5231cb0ef41Sopenharmony_ci 5241cb0ef41Sopenharmony_ci // 5. Let k be 1. 5251cb0ef41Sopenharmony_ci double k = 1; 5261cb0ef41Sopenharmony_ci 5271cb0ef41Sopenharmony_ci // 6. Repeat, while k < len. 5281cb0ef41Sopenharmony_ci while (k < length) { 5291cb0ef41Sopenharmony_ci // a. Let from be ! ToString(k). 5301cb0ef41Sopenharmony_ci Handle<String> from = 5311cb0ef41Sopenharmony_ci isolate->factory()->NumberToString(isolate->factory()->NewNumber(k)); 5321cb0ef41Sopenharmony_ci 5331cb0ef41Sopenharmony_ci // b. Let to be ! ToString(k-1). 5341cb0ef41Sopenharmony_ci Handle<String> to = isolate->factory()->NumberToString( 5351cb0ef41Sopenharmony_ci isolate->factory()->NewNumber(k - 1)); 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_ci // c. Let fromPresent be ? HasProperty(O, from). 5381cb0ef41Sopenharmony_ci bool from_present; 5391cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5401cb0ef41Sopenharmony_ci isolate, from_present, 5411cb0ef41Sopenharmony_ci JSReceiver::HasProperty(isolate, receiver, from)); 5421cb0ef41Sopenharmony_ci 5431cb0ef41Sopenharmony_ci // d. If fromPresent is true, then. 5441cb0ef41Sopenharmony_ci if (from_present) { 5451cb0ef41Sopenharmony_ci // i. Let fromVal be ? Get(O, from). 5461cb0ef41Sopenharmony_ci Handle<Object> from_val; 5471cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5481cb0ef41Sopenharmony_ci isolate, from_val, 5491cb0ef41Sopenharmony_ci Object::GetPropertyOrElement(isolate, receiver, from)); 5501cb0ef41Sopenharmony_ci 5511cb0ef41Sopenharmony_ci // ii. Perform ? Set(O, to, fromVal, true). 5521cb0ef41Sopenharmony_ci RETURN_FAILURE_ON_EXCEPTION( 5531cb0ef41Sopenharmony_ci isolate, 5541cb0ef41Sopenharmony_ci Object::SetPropertyOrElement(isolate, receiver, to, from_val, 5551cb0ef41Sopenharmony_ci Just(ShouldThrow::kThrowOnError))); 5561cb0ef41Sopenharmony_ci } else { // e. Else fromPresent is false, 5571cb0ef41Sopenharmony_ci // i. Perform ? DeletePropertyOrThrow(O, to). 5581cb0ef41Sopenharmony_ci MAYBE_RETURN(JSReceiver::DeletePropertyOrElement(receiver, to, 5591cb0ef41Sopenharmony_ci LanguageMode::kStrict), 5601cb0ef41Sopenharmony_ci ReadOnlyRoots(isolate).exception()); 5611cb0ef41Sopenharmony_ci } 5621cb0ef41Sopenharmony_ci 5631cb0ef41Sopenharmony_ci // f. Increase k by 1. 5641cb0ef41Sopenharmony_ci ++k; 5651cb0ef41Sopenharmony_ci } 5661cb0ef41Sopenharmony_ci 5671cb0ef41Sopenharmony_ci // 7. Perform ? DeletePropertyOrThrow(O, ! ToString(len-1)). 5681cb0ef41Sopenharmony_ci Handle<String> new_length = isolate->factory()->NumberToString( 5691cb0ef41Sopenharmony_ci isolate->factory()->NewNumber(length - 1)); 5701cb0ef41Sopenharmony_ci MAYBE_RETURN(JSReceiver::DeletePropertyOrElement(receiver, new_length, 5711cb0ef41Sopenharmony_ci LanguageMode::kStrict), 5721cb0ef41Sopenharmony_ci ReadOnlyRoots(isolate).exception()); 5731cb0ef41Sopenharmony_ci 5741cb0ef41Sopenharmony_ci // 8. Perform ? Set(O, "length", len-1, true). 5751cb0ef41Sopenharmony_ci RETURN_FAILURE_ON_EXCEPTION(isolate, 5761cb0ef41Sopenharmony_ci SetLengthProperty(isolate, receiver, length - 1)); 5771cb0ef41Sopenharmony_ci 5781cb0ef41Sopenharmony_ci // 9. Return first. 5791cb0ef41Sopenharmony_ci return *first; 5801cb0ef41Sopenharmony_ci} 5811cb0ef41Sopenharmony_ci} // namespace 5821cb0ef41Sopenharmony_ci 5831cb0ef41Sopenharmony_ciBUILTIN(ArrayShift) { 5841cb0ef41Sopenharmony_ci HandleScope scope(isolate); 5851cb0ef41Sopenharmony_ci 5861cb0ef41Sopenharmony_ci // 1. Let O be ? ToObject(this value). 5871cb0ef41Sopenharmony_ci Handle<JSReceiver> receiver; 5881cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5891cb0ef41Sopenharmony_ci isolate, receiver, Object::ToObject(isolate, args.receiver())); 5901cb0ef41Sopenharmony_ci 5911cb0ef41Sopenharmony_ci // 2. Let len be ? ToLength(? Get(O, "length")). 5921cb0ef41Sopenharmony_ci double length; 5931cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5941cb0ef41Sopenharmony_ci isolate, length, GetLengthProperty(isolate, receiver)); 5951cb0ef41Sopenharmony_ci 5961cb0ef41Sopenharmony_ci // 3. If len is zero, then. 5971cb0ef41Sopenharmony_ci if (length == 0) { 5981cb0ef41Sopenharmony_ci // a. Perform ? Set(O, "length", 0, true). 5991cb0ef41Sopenharmony_ci RETURN_FAILURE_ON_EXCEPTION(isolate, 6001cb0ef41Sopenharmony_ci SetLengthProperty(isolate, receiver, length)); 6011cb0ef41Sopenharmony_ci 6021cb0ef41Sopenharmony_ci // b. Return undefined. 6031cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).undefined_value(); 6041cb0ef41Sopenharmony_ci } 6051cb0ef41Sopenharmony_ci 6061cb0ef41Sopenharmony_ci if (CanUseFastArrayShift(isolate, receiver)) { 6071cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 6081cb0ef41Sopenharmony_ci RETURN_RESULT_OR_FAILURE(isolate, 6091cb0ef41Sopenharmony_ci array->GetElementsAccessor()->Shift(array)); 6101cb0ef41Sopenharmony_ci } 6111cb0ef41Sopenharmony_ci 6121cb0ef41Sopenharmony_ci return GenericArrayShift(isolate, receiver, length); 6131cb0ef41Sopenharmony_ci} 6141cb0ef41Sopenharmony_ci 6151cb0ef41Sopenharmony_ciBUILTIN(ArrayUnshift) { 6161cb0ef41Sopenharmony_ci HandleScope scope(isolate); 6171cb0ef41Sopenharmony_ci DCHECK(args.receiver()->IsJSArray()); 6181cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(args.receiver()); 6191cb0ef41Sopenharmony_ci 6201cb0ef41Sopenharmony_ci // These are checked in the Torque builtin. 6211cb0ef41Sopenharmony_ci DCHECK(array->map().is_extensible()); 6221cb0ef41Sopenharmony_ci DCHECK(!IsDictionaryElementsKind(array->GetElementsKind())); 6231cb0ef41Sopenharmony_ci DCHECK(IsJSArrayFastElementMovingAllowed(isolate, *array)); 6241cb0ef41Sopenharmony_ci DCHECK(!isolate->IsAnyInitialArrayPrototype(*array)); 6251cb0ef41Sopenharmony_ci 6261cb0ef41Sopenharmony_ci MatchArrayElementsKindToArguments(isolate, array, &args, 1, 6271cb0ef41Sopenharmony_ci args.length() - 1); 6281cb0ef41Sopenharmony_ci 6291cb0ef41Sopenharmony_ci int to_add = args.length() - 1; 6301cb0ef41Sopenharmony_ci if (to_add == 0) return array->length(); 6311cb0ef41Sopenharmony_ci 6321cb0ef41Sopenharmony_ci // Currently fixed arrays cannot grow too big, so we should never hit this. 6331cb0ef41Sopenharmony_ci DCHECK_LE(to_add, Smi::kMaxValue - Smi::ToInt(array->length())); 6341cb0ef41Sopenharmony_ci DCHECK(!JSArray::HasReadOnlyLength(array)); 6351cb0ef41Sopenharmony_ci 6361cb0ef41Sopenharmony_ci ElementsAccessor* accessor = array->GetElementsAccessor(); 6371cb0ef41Sopenharmony_ci uint32_t new_length; 6381cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6391cb0ef41Sopenharmony_ci isolate, new_length, accessor->Unshift(array, &args, to_add)); 6401cb0ef41Sopenharmony_ci return Smi::FromInt(new_length); 6411cb0ef41Sopenharmony_ci} 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ci// Array Concat ------------------------------------------------------------- 6441cb0ef41Sopenharmony_ci 6451cb0ef41Sopenharmony_cinamespace { 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci/** 6481cb0ef41Sopenharmony_ci * A simple visitor visits every element of Array's. 6491cb0ef41Sopenharmony_ci * The backend storage can be a fixed array for fast elements case, 6501cb0ef41Sopenharmony_ci * or a dictionary for sparse array. Since Dictionary is a subtype 6511cb0ef41Sopenharmony_ci * of FixedArray, the class can be used by both fast and slow cases. 6521cb0ef41Sopenharmony_ci * The second parameter of the constructor, fast_elements, specifies 6531cb0ef41Sopenharmony_ci * whether the storage is a FixedArray or Dictionary. 6541cb0ef41Sopenharmony_ci * 6551cb0ef41Sopenharmony_ci * An index limit is used to deal with the situation that a result array 6561cb0ef41Sopenharmony_ci * length overflows 32-bit non-negative integer. 6571cb0ef41Sopenharmony_ci */ 6581cb0ef41Sopenharmony_ciclass ArrayConcatVisitor { 6591cb0ef41Sopenharmony_ci public: 6601cb0ef41Sopenharmony_ci ArrayConcatVisitor(Isolate* isolate, Handle<HeapObject> storage, 6611cb0ef41Sopenharmony_ci bool fast_elements) 6621cb0ef41Sopenharmony_ci : isolate_(isolate), 6631cb0ef41Sopenharmony_ci storage_(isolate->global_handles()->Create(*storage)), 6641cb0ef41Sopenharmony_ci index_offset_(0u), 6651cb0ef41Sopenharmony_ci bit_field_(FastElementsField::encode(fast_elements) | 6661cb0ef41Sopenharmony_ci ExceedsLimitField::encode(false) | 6671cb0ef41Sopenharmony_ci IsFixedArrayField::encode(storage->IsFixedArray(isolate)) | 6681cb0ef41Sopenharmony_ci HasSimpleElementsField::encode( 6691cb0ef41Sopenharmony_ci storage->IsFixedArray(isolate) || 6701cb0ef41Sopenharmony_ci // Don't take fast path for storages that might have 6711cb0ef41Sopenharmony_ci // side effects when storing to them. 6721cb0ef41Sopenharmony_ci (!storage->map(isolate).IsCustomElementsReceiverMap() && 6731cb0ef41Sopenharmony_ci !storage->IsJSTypedArray(isolate)))) { 6741cb0ef41Sopenharmony_ci DCHECK_IMPLIES(this->fast_elements(), is_fixed_array()); 6751cb0ef41Sopenharmony_ci } 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_ci ~ArrayConcatVisitor() { clear_storage(); } 6781cb0ef41Sopenharmony_ci 6791cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT bool visit(uint32_t i, Handle<Object> elm) { 6801cb0ef41Sopenharmony_ci uint32_t index = index_offset_ + i; 6811cb0ef41Sopenharmony_ci 6821cb0ef41Sopenharmony_ci // Note we use >=kMaxArrayLength instead of the more appropriate 6831cb0ef41Sopenharmony_ci // >kMaxArrayIndex here due to overflowing arithmetic and 6841cb0ef41Sopenharmony_ci // increase_index_offset. 6851cb0ef41Sopenharmony_ci if (i >= JSArray::kMaxArrayLength - index_offset_) { 6861cb0ef41Sopenharmony_ci set_exceeds_array_limit(true); 6871cb0ef41Sopenharmony_ci // Exception hasn't been thrown at this point. Return true to 6881cb0ef41Sopenharmony_ci // break out, and caller will throw. !visit would imply that 6891cb0ef41Sopenharmony_ci // there is already a pending exception. 6901cb0ef41Sopenharmony_ci return true; 6911cb0ef41Sopenharmony_ci } 6921cb0ef41Sopenharmony_ci 6931cb0ef41Sopenharmony_ci if (!is_fixed_array()) { 6941cb0ef41Sopenharmony_ci LookupIterator it(isolate_, storage_, index, LookupIterator::OWN); 6951cb0ef41Sopenharmony_ci MAYBE_RETURN( 6961cb0ef41Sopenharmony_ci JSReceiver::CreateDataProperty(&it, elm, Just(kThrowOnError)), false); 6971cb0ef41Sopenharmony_ci return true; 6981cb0ef41Sopenharmony_ci } 6991cb0ef41Sopenharmony_ci 7001cb0ef41Sopenharmony_ci if (fast_elements()) { 7011cb0ef41Sopenharmony_ci if (index < static_cast<uint32_t>(storage_fixed_array()->length())) { 7021cb0ef41Sopenharmony_ci storage_fixed_array()->set(index, *elm); 7031cb0ef41Sopenharmony_ci return true; 7041cb0ef41Sopenharmony_ci } 7051cb0ef41Sopenharmony_ci // Our initial estimate of length was foiled, possibly by 7061cb0ef41Sopenharmony_ci // getters on the arrays increasing the length of later arrays 7071cb0ef41Sopenharmony_ci // during iteration. 7081cb0ef41Sopenharmony_ci // This shouldn't happen in anything but pathological cases. 7091cb0ef41Sopenharmony_ci SetDictionaryMode(); 7101cb0ef41Sopenharmony_ci // Fall-through to dictionary mode. 7111cb0ef41Sopenharmony_ci } 7121cb0ef41Sopenharmony_ci DCHECK(!fast_elements()); 7131cb0ef41Sopenharmony_ci Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_), isolate_); 7141cb0ef41Sopenharmony_ci // The object holding this backing store has just been allocated, so 7151cb0ef41Sopenharmony_ci // it cannot yet be used as a prototype. 7161cb0ef41Sopenharmony_ci Handle<JSObject> not_a_prototype_holder; 7171cb0ef41Sopenharmony_ci Handle<NumberDictionary> result = NumberDictionary::Set( 7181cb0ef41Sopenharmony_ci isolate_, dict, index, elm, not_a_prototype_holder); 7191cb0ef41Sopenharmony_ci if (!result.is_identical_to(dict)) { 7201cb0ef41Sopenharmony_ci // Dictionary needed to grow. 7211cb0ef41Sopenharmony_ci clear_storage(); 7221cb0ef41Sopenharmony_ci set_storage(*result); 7231cb0ef41Sopenharmony_ci } 7241cb0ef41Sopenharmony_ci return true; 7251cb0ef41Sopenharmony_ci } 7261cb0ef41Sopenharmony_ci 7271cb0ef41Sopenharmony_ci uint32_t index_offset() const { return index_offset_; } 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_ci void increase_index_offset(uint32_t delta) { 7301cb0ef41Sopenharmony_ci if (JSArray::kMaxArrayLength - index_offset_ < delta) { 7311cb0ef41Sopenharmony_ci index_offset_ = JSArray::kMaxArrayLength; 7321cb0ef41Sopenharmony_ci } else { 7331cb0ef41Sopenharmony_ci index_offset_ += delta; 7341cb0ef41Sopenharmony_ci } 7351cb0ef41Sopenharmony_ci // If the initial length estimate was off (see special case in visit()), 7361cb0ef41Sopenharmony_ci // but the array blowing the limit didn't contain elements beyond the 7371cb0ef41Sopenharmony_ci // provided-for index range, go to dictionary mode now. 7381cb0ef41Sopenharmony_ci if (fast_elements() && 7391cb0ef41Sopenharmony_ci index_offset_ > 7401cb0ef41Sopenharmony_ci static_cast<uint32_t>(FixedArrayBase::cast(*storage_).length())) { 7411cb0ef41Sopenharmony_ci SetDictionaryMode(); 7421cb0ef41Sopenharmony_ci } 7431cb0ef41Sopenharmony_ci } 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_ci bool exceeds_array_limit() const { 7461cb0ef41Sopenharmony_ci return ExceedsLimitField::decode(bit_field_); 7471cb0ef41Sopenharmony_ci } 7481cb0ef41Sopenharmony_ci 7491cb0ef41Sopenharmony_ci Handle<JSArray> ToArray() { 7501cb0ef41Sopenharmony_ci DCHECK(is_fixed_array()); 7511cb0ef41Sopenharmony_ci Handle<JSArray> array = isolate_->factory()->NewJSArray(0); 7521cb0ef41Sopenharmony_ci Handle<Object> length = 7531cb0ef41Sopenharmony_ci isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); 7541cb0ef41Sopenharmony_ci Handle<Map> map = JSObject::GetElementsTransitionMap( 7551cb0ef41Sopenharmony_ci array, fast_elements() ? HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); 7561cb0ef41Sopenharmony_ci array->set_length(*length); 7571cb0ef41Sopenharmony_ci array->set_elements(*storage_fixed_array()); 7581cb0ef41Sopenharmony_ci array->set_map(*map, kReleaseStore); 7591cb0ef41Sopenharmony_ci return array; 7601cb0ef41Sopenharmony_ci } 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT MaybeHandle<JSReceiver> ToJSReceiver() { 7631cb0ef41Sopenharmony_ci DCHECK(!is_fixed_array()); 7641cb0ef41Sopenharmony_ci Handle<JSReceiver> result = Handle<JSReceiver>::cast(storage_); 7651cb0ef41Sopenharmony_ci Handle<Object> length = 7661cb0ef41Sopenharmony_ci isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); 7671cb0ef41Sopenharmony_ci RETURN_ON_EXCEPTION( 7681cb0ef41Sopenharmony_ci isolate_, 7691cb0ef41Sopenharmony_ci Object::SetProperty( 7701cb0ef41Sopenharmony_ci isolate_, result, isolate_->factory()->length_string(), length, 7711cb0ef41Sopenharmony_ci StoreOrigin::kMaybeKeyed, Just(ShouldThrow::kThrowOnError)), 7721cb0ef41Sopenharmony_ci JSReceiver); 7731cb0ef41Sopenharmony_ci return result; 7741cb0ef41Sopenharmony_ci } 7751cb0ef41Sopenharmony_ci bool has_simple_elements() const { 7761cb0ef41Sopenharmony_ci return HasSimpleElementsField::decode(bit_field_); 7771cb0ef41Sopenharmony_ci } 7781cb0ef41Sopenharmony_ci 7791cb0ef41Sopenharmony_ci private: 7801cb0ef41Sopenharmony_ci // Convert storage to dictionary mode. 7811cb0ef41Sopenharmony_ci void SetDictionaryMode() { 7821cb0ef41Sopenharmony_ci DCHECK(fast_elements() && is_fixed_array()); 7831cb0ef41Sopenharmony_ci Handle<FixedArray> current_storage = storage_fixed_array(); 7841cb0ef41Sopenharmony_ci Handle<NumberDictionary> slow_storage( 7851cb0ef41Sopenharmony_ci NumberDictionary::New(isolate_, current_storage->length())); 7861cb0ef41Sopenharmony_ci uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 7871cb0ef41Sopenharmony_ci FOR_WITH_HANDLE_SCOPE( 7881cb0ef41Sopenharmony_ci isolate_, uint32_t, i = 0, i, i < current_length, i++, { 7891cb0ef41Sopenharmony_ci Handle<Object> element(current_storage->get(i), isolate_); 7901cb0ef41Sopenharmony_ci if (!element->IsTheHole(isolate_)) { 7911cb0ef41Sopenharmony_ci // The object holding this backing store has just been allocated, so 7921cb0ef41Sopenharmony_ci // it cannot yet be used as a prototype. 7931cb0ef41Sopenharmony_ci Handle<JSObject> not_a_prototype_holder; 7941cb0ef41Sopenharmony_ci Handle<NumberDictionary> new_storage = NumberDictionary::Set( 7951cb0ef41Sopenharmony_ci isolate_, slow_storage, i, element, not_a_prototype_holder); 7961cb0ef41Sopenharmony_ci if (!new_storage.is_identical_to(slow_storage)) { 7971cb0ef41Sopenharmony_ci slow_storage = loop_scope.CloseAndEscape(new_storage); 7981cb0ef41Sopenharmony_ci } 7991cb0ef41Sopenharmony_ci } 8001cb0ef41Sopenharmony_ci }); 8011cb0ef41Sopenharmony_ci clear_storage(); 8021cb0ef41Sopenharmony_ci set_storage(*slow_storage); 8031cb0ef41Sopenharmony_ci set_fast_elements(false); 8041cb0ef41Sopenharmony_ci } 8051cb0ef41Sopenharmony_ci 8061cb0ef41Sopenharmony_ci inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); } 8071cb0ef41Sopenharmony_ci 8081cb0ef41Sopenharmony_ci inline void set_storage(FixedArray storage) { 8091cb0ef41Sopenharmony_ci DCHECK(is_fixed_array()); 8101cb0ef41Sopenharmony_ci DCHECK(has_simple_elements()); 8111cb0ef41Sopenharmony_ci storage_ = isolate_->global_handles()->Create(storage); 8121cb0ef41Sopenharmony_ci } 8131cb0ef41Sopenharmony_ci 8141cb0ef41Sopenharmony_ci using FastElementsField = base::BitField<bool, 0, 1>; 8151cb0ef41Sopenharmony_ci using ExceedsLimitField = base::BitField<bool, 1, 1>; 8161cb0ef41Sopenharmony_ci using IsFixedArrayField = base::BitField<bool, 2, 1>; 8171cb0ef41Sopenharmony_ci using HasSimpleElementsField = base::BitField<bool, 3, 1>; 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_ci bool fast_elements() const { return FastElementsField::decode(bit_field_); } 8201cb0ef41Sopenharmony_ci void set_fast_elements(bool fast) { 8211cb0ef41Sopenharmony_ci bit_field_ = FastElementsField::update(bit_field_, fast); 8221cb0ef41Sopenharmony_ci } 8231cb0ef41Sopenharmony_ci void set_exceeds_array_limit(bool exceeds) { 8241cb0ef41Sopenharmony_ci bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); 8251cb0ef41Sopenharmony_ci } 8261cb0ef41Sopenharmony_ci bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); } 8271cb0ef41Sopenharmony_ci Handle<FixedArray> storage_fixed_array() { 8281cb0ef41Sopenharmony_ci DCHECK(is_fixed_array()); 8291cb0ef41Sopenharmony_ci DCHECK(has_simple_elements()); 8301cb0ef41Sopenharmony_ci return Handle<FixedArray>::cast(storage_); 8311cb0ef41Sopenharmony_ci } 8321cb0ef41Sopenharmony_ci 8331cb0ef41Sopenharmony_ci Isolate* isolate_; 8341cb0ef41Sopenharmony_ci Handle<Object> storage_; // Always a global handle. 8351cb0ef41Sopenharmony_ci // Index after last seen index. Always less than or equal to 8361cb0ef41Sopenharmony_ci // JSArray::kMaxArrayLength. 8371cb0ef41Sopenharmony_ci uint32_t index_offset_; 8381cb0ef41Sopenharmony_ci uint32_t bit_field_; 8391cb0ef41Sopenharmony_ci}; 8401cb0ef41Sopenharmony_ci 8411cb0ef41Sopenharmony_ciuint32_t EstimateElementCount(Isolate* isolate, Handle<JSArray> array) { 8421cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 8431cb0ef41Sopenharmony_ci uint32_t length = static_cast<uint32_t>(array->length().Number()); 8441cb0ef41Sopenharmony_ci int element_count = 0; 8451cb0ef41Sopenharmony_ci switch (array->GetElementsKind()) { 8461cb0ef41Sopenharmony_ci case PACKED_SMI_ELEMENTS: 8471cb0ef41Sopenharmony_ci case HOLEY_SMI_ELEMENTS: 8481cb0ef41Sopenharmony_ci case PACKED_ELEMENTS: 8491cb0ef41Sopenharmony_ci case PACKED_FROZEN_ELEMENTS: 8501cb0ef41Sopenharmony_ci case PACKED_SEALED_ELEMENTS: 8511cb0ef41Sopenharmony_ci case PACKED_NONEXTENSIBLE_ELEMENTS: 8521cb0ef41Sopenharmony_ci case HOLEY_FROZEN_ELEMENTS: 8531cb0ef41Sopenharmony_ci case HOLEY_SEALED_ELEMENTS: 8541cb0ef41Sopenharmony_ci case HOLEY_NONEXTENSIBLE_ELEMENTS: 8551cb0ef41Sopenharmony_ci case HOLEY_ELEMENTS: { 8561cb0ef41Sopenharmony_ci // Fast elements can't have lengths that are not representable by 8571cb0ef41Sopenharmony_ci // a 32-bit signed integer. 8581cb0ef41Sopenharmony_ci DCHECK_GE(static_cast<int32_t>(FixedArray::kMaxLength), 0); 8591cb0ef41Sopenharmony_ci int fast_length = static_cast<int>(length); 8601cb0ef41Sopenharmony_ci FixedArray elements = FixedArray::cast(array->elements()); 8611cb0ef41Sopenharmony_ci for (int i = 0; i < fast_length; i++) { 8621cb0ef41Sopenharmony_ci if (!elements.get(i).IsTheHole(isolate)) element_count++; 8631cb0ef41Sopenharmony_ci } 8641cb0ef41Sopenharmony_ci break; 8651cb0ef41Sopenharmony_ci } 8661cb0ef41Sopenharmony_ci case PACKED_DOUBLE_ELEMENTS: 8671cb0ef41Sopenharmony_ci case HOLEY_DOUBLE_ELEMENTS: { 8681cb0ef41Sopenharmony_ci // Fast elements can't have lengths that are not representable by 8691cb0ef41Sopenharmony_ci // a 32-bit signed integer. 8701cb0ef41Sopenharmony_ci DCHECK_GE(static_cast<int32_t>(FixedDoubleArray::kMaxLength), 0); 8711cb0ef41Sopenharmony_ci int fast_length = static_cast<int>(length); 8721cb0ef41Sopenharmony_ci if (array->elements().IsFixedArray()) { 8731cb0ef41Sopenharmony_ci DCHECK_EQ(FixedArray::cast(array->elements()).length(), 0); 8741cb0ef41Sopenharmony_ci break; 8751cb0ef41Sopenharmony_ci } 8761cb0ef41Sopenharmony_ci FixedDoubleArray elements = FixedDoubleArray::cast(array->elements()); 8771cb0ef41Sopenharmony_ci for (int i = 0; i < fast_length; i++) { 8781cb0ef41Sopenharmony_ci if (!elements.is_the_hole(i)) element_count++; 8791cb0ef41Sopenharmony_ci } 8801cb0ef41Sopenharmony_ci break; 8811cb0ef41Sopenharmony_ci } 8821cb0ef41Sopenharmony_ci case DICTIONARY_ELEMENTS: { 8831cb0ef41Sopenharmony_ci NumberDictionary dictionary = NumberDictionary::cast(array->elements()); 8841cb0ef41Sopenharmony_ci ReadOnlyRoots roots(isolate); 8851cb0ef41Sopenharmony_ci for (InternalIndex i : dictionary.IterateEntries()) { 8861cb0ef41Sopenharmony_ci Object key = dictionary.KeyAt(i); 8871cb0ef41Sopenharmony_ci if (dictionary.IsKey(roots, key)) { 8881cb0ef41Sopenharmony_ci element_count++; 8891cb0ef41Sopenharmony_ci } 8901cb0ef41Sopenharmony_ci } 8911cb0ef41Sopenharmony_ci break; 8921cb0ef41Sopenharmony_ci } 8931cb0ef41Sopenharmony_ci#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 8941cb0ef41Sopenharmony_ci 8951cb0ef41Sopenharmony_ci TYPED_ARRAYS(TYPED_ARRAY_CASE) 8961cb0ef41Sopenharmony_ci RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) 8971cb0ef41Sopenharmony_ci // External arrays are always dense. 8981cb0ef41Sopenharmony_ci return length; 8991cb0ef41Sopenharmony_ci 9001cb0ef41Sopenharmony_ci#undef TYPED_ARRAY_CASE 9011cb0ef41Sopenharmony_ci case NO_ELEMENTS: 9021cb0ef41Sopenharmony_ci return 0; 9031cb0ef41Sopenharmony_ci case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 9041cb0ef41Sopenharmony_ci case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 9051cb0ef41Sopenharmony_ci case FAST_STRING_WRAPPER_ELEMENTS: 9061cb0ef41Sopenharmony_ci case SLOW_STRING_WRAPPER_ELEMENTS: 9071cb0ef41Sopenharmony_ci case WASM_ARRAY_ELEMENTS: 9081cb0ef41Sopenharmony_ci UNREACHABLE(); 9091cb0ef41Sopenharmony_ci } 9101cb0ef41Sopenharmony_ci // As an estimate, we assume that the prototype doesn't contain any 9111cb0ef41Sopenharmony_ci // inherited elements. 9121cb0ef41Sopenharmony_ci return element_count; 9131cb0ef41Sopenharmony_ci} 9141cb0ef41Sopenharmony_ci 9151cb0ef41Sopenharmony_civoid CollectElementIndices(Isolate* isolate, Handle<JSObject> object, 9161cb0ef41Sopenharmony_ci uint32_t range, std::vector<uint32_t>* indices) { 9171cb0ef41Sopenharmony_ci ElementsKind kind = object->GetElementsKind(); 9181cb0ef41Sopenharmony_ci switch (kind) { 9191cb0ef41Sopenharmony_ci case PACKED_SMI_ELEMENTS: 9201cb0ef41Sopenharmony_ci case PACKED_ELEMENTS: 9211cb0ef41Sopenharmony_ci case PACKED_FROZEN_ELEMENTS: 9221cb0ef41Sopenharmony_ci case PACKED_SEALED_ELEMENTS: 9231cb0ef41Sopenharmony_ci case PACKED_NONEXTENSIBLE_ELEMENTS: 9241cb0ef41Sopenharmony_ci case HOLEY_SMI_ELEMENTS: 9251cb0ef41Sopenharmony_ci case HOLEY_FROZEN_ELEMENTS: 9261cb0ef41Sopenharmony_ci case HOLEY_SEALED_ELEMENTS: 9271cb0ef41Sopenharmony_ci case HOLEY_NONEXTENSIBLE_ELEMENTS: 9281cb0ef41Sopenharmony_ci case HOLEY_ELEMENTS: { 9291cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 9301cb0ef41Sopenharmony_ci FixedArray elements = FixedArray::cast(object->elements()); 9311cb0ef41Sopenharmony_ci uint32_t length = static_cast<uint32_t>(elements.length()); 9321cb0ef41Sopenharmony_ci if (range < length) length = range; 9331cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < length; i++) { 9341cb0ef41Sopenharmony_ci if (!elements.get(i).IsTheHole(isolate)) { 9351cb0ef41Sopenharmony_ci indices->push_back(i); 9361cb0ef41Sopenharmony_ci } 9371cb0ef41Sopenharmony_ci } 9381cb0ef41Sopenharmony_ci break; 9391cb0ef41Sopenharmony_ci } 9401cb0ef41Sopenharmony_ci case HOLEY_DOUBLE_ELEMENTS: 9411cb0ef41Sopenharmony_ci case PACKED_DOUBLE_ELEMENTS: { 9421cb0ef41Sopenharmony_ci if (object->elements().IsFixedArray()) { 9431cb0ef41Sopenharmony_ci DCHECK_EQ(object->elements().length(), 0); 9441cb0ef41Sopenharmony_ci break; 9451cb0ef41Sopenharmony_ci } 9461cb0ef41Sopenharmony_ci Handle<FixedDoubleArray> elements( 9471cb0ef41Sopenharmony_ci FixedDoubleArray::cast(object->elements()), isolate); 9481cb0ef41Sopenharmony_ci uint32_t length = static_cast<uint32_t>(elements->length()); 9491cb0ef41Sopenharmony_ci if (range < length) length = range; 9501cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < length; i++) { 9511cb0ef41Sopenharmony_ci if (!elements->is_the_hole(i)) { 9521cb0ef41Sopenharmony_ci indices->push_back(i); 9531cb0ef41Sopenharmony_ci } 9541cb0ef41Sopenharmony_ci } 9551cb0ef41Sopenharmony_ci break; 9561cb0ef41Sopenharmony_ci } 9571cb0ef41Sopenharmony_ci case DICTIONARY_ELEMENTS: { 9581cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 9591cb0ef41Sopenharmony_ci NumberDictionary dict = NumberDictionary::cast(object->elements()); 9601cb0ef41Sopenharmony_ci uint32_t capacity = dict.Capacity(); 9611cb0ef41Sopenharmony_ci ReadOnlyRoots roots(isolate); 9621cb0ef41Sopenharmony_ci FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, j = 0, j, j < capacity, j++, { 9631cb0ef41Sopenharmony_ci Object k = dict.KeyAt(InternalIndex(j)); 9641cb0ef41Sopenharmony_ci if (!dict.IsKey(roots, k)) continue; 9651cb0ef41Sopenharmony_ci DCHECK(k.IsNumber()); 9661cb0ef41Sopenharmony_ci uint32_t index = static_cast<uint32_t>(k.Number()); 9671cb0ef41Sopenharmony_ci if (index < range) { 9681cb0ef41Sopenharmony_ci indices->push_back(index); 9691cb0ef41Sopenharmony_ci } 9701cb0ef41Sopenharmony_ci }); 9711cb0ef41Sopenharmony_ci break; 9721cb0ef41Sopenharmony_ci } 9731cb0ef41Sopenharmony_ci#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 9741cb0ef41Sopenharmony_ci 9751cb0ef41Sopenharmony_ci TYPED_ARRAYS(TYPED_ARRAY_CASE) { 9761cb0ef41Sopenharmony_ci size_t length = Handle<JSTypedArray>::cast(object)->length(); 9771cb0ef41Sopenharmony_ci if (range <= length) { 9781cb0ef41Sopenharmony_ci length = range; 9791cb0ef41Sopenharmony_ci // We will add all indices, so we might as well clear it first 9801cb0ef41Sopenharmony_ci // and avoid duplicates. 9811cb0ef41Sopenharmony_ci indices->clear(); 9821cb0ef41Sopenharmony_ci } 9831cb0ef41Sopenharmony_ci // {range} puts a cap on {length}. 9841cb0ef41Sopenharmony_ci DCHECK_LE(length, std::numeric_limits<uint32_t>::max()); 9851cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < length; i++) { 9861cb0ef41Sopenharmony_ci indices->push_back(i); 9871cb0ef41Sopenharmony_ci } 9881cb0ef41Sopenharmony_ci if (length == range) return; // All indices accounted for already. 9891cb0ef41Sopenharmony_ci break; 9901cb0ef41Sopenharmony_ci } 9911cb0ef41Sopenharmony_ci RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) 9921cb0ef41Sopenharmony_ci // TODO(v8:11111): Support RAB / GSAB. 9931cb0ef41Sopenharmony_ci UNREACHABLE(); 9941cb0ef41Sopenharmony_ci 9951cb0ef41Sopenharmony_ci#undef TYPED_ARRAY_CASE 9961cb0ef41Sopenharmony_ci case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 9971cb0ef41Sopenharmony_ci case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 9981cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 9991cb0ef41Sopenharmony_ci DisableGCMole no_gc_mole; 10001cb0ef41Sopenharmony_ci FixedArrayBase elements = object->elements(); 10011cb0ef41Sopenharmony_ci JSObject raw_object = *object; 10021cb0ef41Sopenharmony_ci ElementsAccessor* accessor = object->GetElementsAccessor(); 10031cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < range; i++) { 10041cb0ef41Sopenharmony_ci if (accessor->HasElement(raw_object, i, elements)) { 10051cb0ef41Sopenharmony_ci indices->push_back(i); 10061cb0ef41Sopenharmony_ci } 10071cb0ef41Sopenharmony_ci } 10081cb0ef41Sopenharmony_ci break; 10091cb0ef41Sopenharmony_ci } 10101cb0ef41Sopenharmony_ci case FAST_STRING_WRAPPER_ELEMENTS: 10111cb0ef41Sopenharmony_ci case SLOW_STRING_WRAPPER_ELEMENTS: { 10121cb0ef41Sopenharmony_ci DCHECK(object->IsJSPrimitiveWrapper()); 10131cb0ef41Sopenharmony_ci Handle<JSPrimitiveWrapper> js_value = 10141cb0ef41Sopenharmony_ci Handle<JSPrimitiveWrapper>::cast(object); 10151cb0ef41Sopenharmony_ci DCHECK(js_value->value().IsString()); 10161cb0ef41Sopenharmony_ci Handle<String> string(String::cast(js_value->value()), isolate); 10171cb0ef41Sopenharmony_ci uint32_t length = static_cast<uint32_t>(string->length()); 10181cb0ef41Sopenharmony_ci uint32_t i = 0; 10191cb0ef41Sopenharmony_ci uint32_t limit = std::min(length, range); 10201cb0ef41Sopenharmony_ci for (; i < limit; i++) { 10211cb0ef41Sopenharmony_ci indices->push_back(i); 10221cb0ef41Sopenharmony_ci } 10231cb0ef41Sopenharmony_ci ElementsAccessor* accessor = object->GetElementsAccessor(); 10241cb0ef41Sopenharmony_ci for (; i < range; i++) { 10251cb0ef41Sopenharmony_ci if (accessor->HasElement(*object, i)) { 10261cb0ef41Sopenharmony_ci indices->push_back(i); 10271cb0ef41Sopenharmony_ci } 10281cb0ef41Sopenharmony_ci } 10291cb0ef41Sopenharmony_ci break; 10301cb0ef41Sopenharmony_ci } 10311cb0ef41Sopenharmony_ci case WASM_ARRAY_ELEMENTS: 10321cb0ef41Sopenharmony_ci // TODO(ishell): implement 10331cb0ef41Sopenharmony_ci UNIMPLEMENTED(); 10341cb0ef41Sopenharmony_ci case NO_ELEMENTS: 10351cb0ef41Sopenharmony_ci break; 10361cb0ef41Sopenharmony_ci } 10371cb0ef41Sopenharmony_ci 10381cb0ef41Sopenharmony_ci PrototypeIterator iter(isolate, object); 10391cb0ef41Sopenharmony_ci if (!iter.IsAtEnd()) { 10401cb0ef41Sopenharmony_ci // The prototype will usually have no inherited element indices, 10411cb0ef41Sopenharmony_ci // but we have to check. 10421cb0ef41Sopenharmony_ci CollectElementIndices( 10431cb0ef41Sopenharmony_ci isolate, PrototypeIterator::GetCurrent<JSObject>(iter), range, indices); 10441cb0ef41Sopenharmony_ci } 10451cb0ef41Sopenharmony_ci} 10461cb0ef41Sopenharmony_ci 10471cb0ef41Sopenharmony_cibool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver, 10481cb0ef41Sopenharmony_ci uint32_t length, ArrayConcatVisitor* visitor) { 10491cb0ef41Sopenharmony_ci FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, ++i, { 10501cb0ef41Sopenharmony_ci Maybe<bool> maybe = JSReceiver::HasElement(isolate, receiver, i); 10511cb0ef41Sopenharmony_ci if (maybe.IsNothing()) return false; 10521cb0ef41Sopenharmony_ci if (maybe.FromJust()) { 10531cb0ef41Sopenharmony_ci Handle<Object> element_value; 10541cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION_VALUE( 10551cb0ef41Sopenharmony_ci isolate, element_value, JSReceiver::GetElement(isolate, receiver, i), 10561cb0ef41Sopenharmony_ci false); 10571cb0ef41Sopenharmony_ci if (!visitor->visit(i, element_value)) return false; 10581cb0ef41Sopenharmony_ci } 10591cb0ef41Sopenharmony_ci }); 10601cb0ef41Sopenharmony_ci visitor->increase_index_offset(length); 10611cb0ef41Sopenharmony_ci return true; 10621cb0ef41Sopenharmony_ci} 10631cb0ef41Sopenharmony_ci/** 10641cb0ef41Sopenharmony_ci * A helper function that visits "array" elements of a JSReceiver in numerical 10651cb0ef41Sopenharmony_ci * order. 10661cb0ef41Sopenharmony_ci * 10671cb0ef41Sopenharmony_ci * The visitor argument called for each existing element in the array 10681cb0ef41Sopenharmony_ci * with the element index and the element's value. 10691cb0ef41Sopenharmony_ci * Afterwards it increments the base-index of the visitor by the array 10701cb0ef41Sopenharmony_ci * length. 10711cb0ef41Sopenharmony_ci * Returns false if any access threw an exception, otherwise true. 10721cb0ef41Sopenharmony_ci */ 10731cb0ef41Sopenharmony_cibool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, 10741cb0ef41Sopenharmony_ci ArrayConcatVisitor* visitor) { 10751cb0ef41Sopenharmony_ci uint32_t length = 0; 10761cb0ef41Sopenharmony_ci 10771cb0ef41Sopenharmony_ci if (receiver->IsJSArray()) { 10781cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(receiver); 10791cb0ef41Sopenharmony_ci length = static_cast<uint32_t>(array->length().Number()); 10801cb0ef41Sopenharmony_ci } else { 10811cb0ef41Sopenharmony_ci Handle<Object> val; 10821cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION_VALUE( 10831cb0ef41Sopenharmony_ci isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false); 10841cb0ef41Sopenharmony_ci if (visitor->index_offset() + val->Number() > kMaxSafeInteger) { 10851cb0ef41Sopenharmony_ci isolate->Throw(*isolate->factory()->NewTypeError( 10861cb0ef41Sopenharmony_ci MessageTemplate::kInvalidArrayLength)); 10871cb0ef41Sopenharmony_ci return false; 10881cb0ef41Sopenharmony_ci } 10891cb0ef41Sopenharmony_ci // TODO(caitp): Support larger element indexes (up to 2^53-1). 10901cb0ef41Sopenharmony_ci if (!val->ToUint32(&length)) { 10911cb0ef41Sopenharmony_ci length = 0; 10921cb0ef41Sopenharmony_ci } 10931cb0ef41Sopenharmony_ci // TODO(cbruni): handle other element kind as well 10941cb0ef41Sopenharmony_ci return IterateElementsSlow(isolate, receiver, length, visitor); 10951cb0ef41Sopenharmony_ci } 10961cb0ef41Sopenharmony_ci 10971cb0ef41Sopenharmony_ci if (!visitor->has_simple_elements() || 10981cb0ef41Sopenharmony_ci !HasOnlySimpleElements(isolate, *receiver)) { 10991cb0ef41Sopenharmony_ci return IterateElementsSlow(isolate, receiver, length, visitor); 11001cb0ef41Sopenharmony_ci } 11011cb0ef41Sopenharmony_ci Handle<JSObject> array = Handle<JSObject>::cast(receiver); 11021cb0ef41Sopenharmony_ci 11031cb0ef41Sopenharmony_ci switch (array->GetElementsKind()) { 11041cb0ef41Sopenharmony_ci case PACKED_SMI_ELEMENTS: 11051cb0ef41Sopenharmony_ci case PACKED_ELEMENTS: 11061cb0ef41Sopenharmony_ci case PACKED_FROZEN_ELEMENTS: 11071cb0ef41Sopenharmony_ci case PACKED_SEALED_ELEMENTS: 11081cb0ef41Sopenharmony_ci case PACKED_NONEXTENSIBLE_ELEMENTS: 11091cb0ef41Sopenharmony_ci case HOLEY_SMI_ELEMENTS: 11101cb0ef41Sopenharmony_ci case HOLEY_FROZEN_ELEMENTS: 11111cb0ef41Sopenharmony_ci case HOLEY_SEALED_ELEMENTS: 11121cb0ef41Sopenharmony_ci case HOLEY_NONEXTENSIBLE_ELEMENTS: 11131cb0ef41Sopenharmony_ci case HOLEY_ELEMENTS: { 11141cb0ef41Sopenharmony_ci // Disallow execution so the cached elements won't change mid execution. 11151cb0ef41Sopenharmony_ci DisallowJavascriptExecution no_js(isolate); 11161cb0ef41Sopenharmony_ci 11171cb0ef41Sopenharmony_ci // Run through the elements FixedArray and use HasElement and GetElement 11181cb0ef41Sopenharmony_ci // to check the prototype for missing elements. 11191cb0ef41Sopenharmony_ci Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate); 11201cb0ef41Sopenharmony_ci int fast_length = static_cast<int>(length); 11211cb0ef41Sopenharmony_ci DCHECK(fast_length <= elements->length()); 11221cb0ef41Sopenharmony_ci FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, { 11231cb0ef41Sopenharmony_ci Handle<Object> element_value(elements->get(j), isolate); 11241cb0ef41Sopenharmony_ci if (!element_value->IsTheHole(isolate)) { 11251cb0ef41Sopenharmony_ci if (!visitor->visit(j, element_value)) return false; 11261cb0ef41Sopenharmony_ci } else { 11271cb0ef41Sopenharmony_ci Maybe<bool> maybe = JSReceiver::HasElement(isolate, array, j); 11281cb0ef41Sopenharmony_ci if (maybe.IsNothing()) return false; 11291cb0ef41Sopenharmony_ci if (maybe.FromJust()) { 11301cb0ef41Sopenharmony_ci // Call GetElement on array, not its prototype, or getters won't 11311cb0ef41Sopenharmony_ci // have the correct receiver. 11321cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION_VALUE( 11331cb0ef41Sopenharmony_ci isolate, element_value, 11341cb0ef41Sopenharmony_ci JSReceiver::GetElement(isolate, array, j), false); 11351cb0ef41Sopenharmony_ci if (!visitor->visit(j, element_value)) return false; 11361cb0ef41Sopenharmony_ci } 11371cb0ef41Sopenharmony_ci } 11381cb0ef41Sopenharmony_ci }); 11391cb0ef41Sopenharmony_ci break; 11401cb0ef41Sopenharmony_ci } 11411cb0ef41Sopenharmony_ci case HOLEY_DOUBLE_ELEMENTS: 11421cb0ef41Sopenharmony_ci case PACKED_DOUBLE_ELEMENTS: { 11431cb0ef41Sopenharmony_ci // Disallow execution so the cached elements won't change mid execution. 11441cb0ef41Sopenharmony_ci DisallowJavascriptExecution no_js(isolate); 11451cb0ef41Sopenharmony_ci 11461cb0ef41Sopenharmony_ci // Empty array is FixedArray but not FixedDoubleArray. 11471cb0ef41Sopenharmony_ci if (length == 0) break; 11481cb0ef41Sopenharmony_ci // Run through the elements FixedArray and use HasElement and GetElement 11491cb0ef41Sopenharmony_ci // to check the prototype for missing elements. 11501cb0ef41Sopenharmony_ci if (array->elements().IsFixedArray()) { 11511cb0ef41Sopenharmony_ci DCHECK_EQ(array->elements().length(), 0); 11521cb0ef41Sopenharmony_ci break; 11531cb0ef41Sopenharmony_ci } 11541cb0ef41Sopenharmony_ci Handle<FixedDoubleArray> elements( 11551cb0ef41Sopenharmony_ci FixedDoubleArray::cast(array->elements()), isolate); 11561cb0ef41Sopenharmony_ci int fast_length = static_cast<int>(length); 11571cb0ef41Sopenharmony_ci DCHECK(fast_length <= elements->length()); 11581cb0ef41Sopenharmony_ci FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, { 11591cb0ef41Sopenharmony_ci if (!elements->is_the_hole(j)) { 11601cb0ef41Sopenharmony_ci double double_value = elements->get_scalar(j); 11611cb0ef41Sopenharmony_ci Handle<Object> element_value = 11621cb0ef41Sopenharmony_ci isolate->factory()->NewNumber(double_value); 11631cb0ef41Sopenharmony_ci if (!visitor->visit(j, element_value)) return false; 11641cb0ef41Sopenharmony_ci } else { 11651cb0ef41Sopenharmony_ci Maybe<bool> maybe = JSReceiver::HasElement(isolate, array, j); 11661cb0ef41Sopenharmony_ci if (maybe.IsNothing()) return false; 11671cb0ef41Sopenharmony_ci if (maybe.FromJust()) { 11681cb0ef41Sopenharmony_ci // Call GetElement on array, not its prototype, or getters won't 11691cb0ef41Sopenharmony_ci // have the correct receiver. 11701cb0ef41Sopenharmony_ci Handle<Object> element_value; 11711cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION_VALUE( 11721cb0ef41Sopenharmony_ci isolate, element_value, 11731cb0ef41Sopenharmony_ci JSReceiver::GetElement(isolate, array, j), false); 11741cb0ef41Sopenharmony_ci if (!visitor->visit(j, element_value)) return false; 11751cb0ef41Sopenharmony_ci } 11761cb0ef41Sopenharmony_ci } 11771cb0ef41Sopenharmony_ci }); 11781cb0ef41Sopenharmony_ci break; 11791cb0ef41Sopenharmony_ci } 11801cb0ef41Sopenharmony_ci 11811cb0ef41Sopenharmony_ci case DICTIONARY_ELEMENTS: { 11821cb0ef41Sopenharmony_ci // Disallow execution so the cached dictionary won't change mid execution. 11831cb0ef41Sopenharmony_ci DisallowJavascriptExecution no_js(isolate); 11841cb0ef41Sopenharmony_ci 11851cb0ef41Sopenharmony_ci Handle<NumberDictionary> dict(array->element_dictionary(), isolate); 11861cb0ef41Sopenharmony_ci std::vector<uint32_t> indices; 11871cb0ef41Sopenharmony_ci indices.reserve(dict->Capacity() / 2); 11881cb0ef41Sopenharmony_ci 11891cb0ef41Sopenharmony_ci // Collect all indices in the object and the prototypes less 11901cb0ef41Sopenharmony_ci // than length. This might introduce duplicates in the indices list. 11911cb0ef41Sopenharmony_ci CollectElementIndices(isolate, array, length, &indices); 11921cb0ef41Sopenharmony_ci std::sort(indices.begin(), indices.end()); 11931cb0ef41Sopenharmony_ci size_t n = indices.size(); 11941cb0ef41Sopenharmony_ci FOR_WITH_HANDLE_SCOPE(isolate, size_t, j = 0, j, j < n, (void)0, { 11951cb0ef41Sopenharmony_ci uint32_t index = indices[j]; 11961cb0ef41Sopenharmony_ci Handle<Object> element; 11971cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION_VALUE( 11981cb0ef41Sopenharmony_ci isolate, element, JSReceiver::GetElement(isolate, array, index), 11991cb0ef41Sopenharmony_ci false); 12001cb0ef41Sopenharmony_ci if (!visitor->visit(index, element)) return false; 12011cb0ef41Sopenharmony_ci // Skip to next different index (i.e., omit duplicates). 12021cb0ef41Sopenharmony_ci do { 12031cb0ef41Sopenharmony_ci j++; 12041cb0ef41Sopenharmony_ci } while (j < n && indices[j] == index); 12051cb0ef41Sopenharmony_ci }); 12061cb0ef41Sopenharmony_ci break; 12071cb0ef41Sopenharmony_ci } 12081cb0ef41Sopenharmony_ci case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 12091cb0ef41Sopenharmony_ci case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 12101cb0ef41Sopenharmony_ci FOR_WITH_HANDLE_SCOPE( 12111cb0ef41Sopenharmony_ci isolate, uint32_t, index = 0, index, index < length, index++, { 12121cb0ef41Sopenharmony_ci Handle<Object> element; 12131cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION_VALUE( 12141cb0ef41Sopenharmony_ci isolate, element, JSReceiver::GetElement(isolate, array, index), 12151cb0ef41Sopenharmony_ci false); 12161cb0ef41Sopenharmony_ci if (!visitor->visit(index, element)) return false; 12171cb0ef41Sopenharmony_ci }); 12181cb0ef41Sopenharmony_ci break; 12191cb0ef41Sopenharmony_ci } 12201cb0ef41Sopenharmony_ci case WASM_ARRAY_ELEMENTS: 12211cb0ef41Sopenharmony_ci // TODO(ishell): implement 12221cb0ef41Sopenharmony_ci UNIMPLEMENTED(); 12231cb0ef41Sopenharmony_ci case NO_ELEMENTS: 12241cb0ef41Sopenharmony_ci break; 12251cb0ef41Sopenharmony_ci#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS: 12261cb0ef41Sopenharmony_ci TYPED_ARRAYS(TYPED_ARRAY_CASE) 12271cb0ef41Sopenharmony_ci return IterateElementsSlow(isolate, receiver, length, visitor); 12281cb0ef41Sopenharmony_ci RAB_GSAB_TYPED_ARRAYS(TYPED_ARRAY_CASE) 12291cb0ef41Sopenharmony_ci // TODO(v8:11111): Support RAB / GSAB. 12301cb0ef41Sopenharmony_ci UNREACHABLE(); 12311cb0ef41Sopenharmony_ci#undef TYPED_ARRAY_CASE 12321cb0ef41Sopenharmony_ci case FAST_STRING_WRAPPER_ELEMENTS: 12331cb0ef41Sopenharmony_ci case SLOW_STRING_WRAPPER_ELEMENTS: 12341cb0ef41Sopenharmony_ci // |array| is guaranteed to be an array or typed array. 12351cb0ef41Sopenharmony_ci UNREACHABLE(); 12361cb0ef41Sopenharmony_ci } 12371cb0ef41Sopenharmony_ci visitor->increase_index_offset(length); 12381cb0ef41Sopenharmony_ci return true; 12391cb0ef41Sopenharmony_ci} 12401cb0ef41Sopenharmony_ci 12411cb0ef41Sopenharmony_cistatic Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { 12421cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate); 12431cb0ef41Sopenharmony_ci if (!obj->IsJSReceiver()) return Just(false); 12441cb0ef41Sopenharmony_ci if (!Protectors::IsIsConcatSpreadableLookupChainIntact(isolate) || 12451cb0ef41Sopenharmony_ci JSReceiver::cast(*obj).HasProxyInPrototype(isolate)) { 12461cb0ef41Sopenharmony_ci // Slow path if @@isConcatSpreadable has been used. 12471cb0ef41Sopenharmony_ci Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); 12481cb0ef41Sopenharmony_ci Handle<Object> value; 12491cb0ef41Sopenharmony_ci MaybeHandle<Object> maybeValue = 12501cb0ef41Sopenharmony_ci i::Runtime::GetObjectProperty(isolate, obj, key); 12511cb0ef41Sopenharmony_ci if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); 12521cb0ef41Sopenharmony_ci if (!value->IsUndefined(isolate)) return Just(value->BooleanValue(isolate)); 12531cb0ef41Sopenharmony_ci } 12541cb0ef41Sopenharmony_ci return Object::IsArray(obj); 12551cb0ef41Sopenharmony_ci} 12561cb0ef41Sopenharmony_ci 12571cb0ef41Sopenharmony_ciObject Slow_ArrayConcat(BuiltinArguments* args, Handle<Object> species, 12581cb0ef41Sopenharmony_ci Isolate* isolate) { 12591cb0ef41Sopenharmony_ci int argument_count = args->length(); 12601cb0ef41Sopenharmony_ci 12611cb0ef41Sopenharmony_ci bool is_array_species = *species == isolate->context().array_function(); 12621cb0ef41Sopenharmony_ci 12631cb0ef41Sopenharmony_ci // Pass 1: estimate the length and number of elements of the result. 12641cb0ef41Sopenharmony_ci // The actual length can be larger if any of the arguments have getters 12651cb0ef41Sopenharmony_ci // that mutate other arguments (but will otherwise be precise). 12661cb0ef41Sopenharmony_ci // The number of elements is precise if there are no inherited elements. 12671cb0ef41Sopenharmony_ci 12681cb0ef41Sopenharmony_ci ElementsKind kind = PACKED_SMI_ELEMENTS; 12691cb0ef41Sopenharmony_ci 12701cb0ef41Sopenharmony_ci uint32_t estimate_result_length = 0; 12711cb0ef41Sopenharmony_ci uint32_t estimate_nof = 0; 12721cb0ef41Sopenharmony_ci FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < argument_count, i++, { 12731cb0ef41Sopenharmony_ci Handle<Object> obj = args->at(i); 12741cb0ef41Sopenharmony_ci uint32_t length_estimate; 12751cb0ef41Sopenharmony_ci uint32_t element_estimate; 12761cb0ef41Sopenharmony_ci if (obj->IsJSArray()) { 12771cb0ef41Sopenharmony_ci Handle<JSArray> array(Handle<JSArray>::cast(obj)); 12781cb0ef41Sopenharmony_ci length_estimate = static_cast<uint32_t>(array->length().Number()); 12791cb0ef41Sopenharmony_ci if (length_estimate != 0) { 12801cb0ef41Sopenharmony_ci ElementsKind array_kind = 12811cb0ef41Sopenharmony_ci GetPackedElementsKind(array->GetElementsKind()); 12821cb0ef41Sopenharmony_ci if (IsAnyNonextensibleElementsKind(array_kind)) { 12831cb0ef41Sopenharmony_ci array_kind = PACKED_ELEMENTS; 12841cb0ef41Sopenharmony_ci } 12851cb0ef41Sopenharmony_ci kind = GetMoreGeneralElementsKind(kind, array_kind); 12861cb0ef41Sopenharmony_ci } 12871cb0ef41Sopenharmony_ci element_estimate = EstimateElementCount(isolate, array); 12881cb0ef41Sopenharmony_ci } else { 12891cb0ef41Sopenharmony_ci if (obj->IsHeapObject()) { 12901cb0ef41Sopenharmony_ci kind = GetMoreGeneralElementsKind( 12911cb0ef41Sopenharmony_ci kind, obj->IsNumber() ? PACKED_DOUBLE_ELEMENTS : PACKED_ELEMENTS); 12921cb0ef41Sopenharmony_ci } 12931cb0ef41Sopenharmony_ci length_estimate = 1; 12941cb0ef41Sopenharmony_ci element_estimate = 1; 12951cb0ef41Sopenharmony_ci } 12961cb0ef41Sopenharmony_ci // Avoid overflows by capping at kMaxArrayLength. 12971cb0ef41Sopenharmony_ci if (JSArray::kMaxArrayLength - estimate_result_length < length_estimate) { 12981cb0ef41Sopenharmony_ci estimate_result_length = JSArray::kMaxArrayLength; 12991cb0ef41Sopenharmony_ci } else { 13001cb0ef41Sopenharmony_ci estimate_result_length += length_estimate; 13011cb0ef41Sopenharmony_ci } 13021cb0ef41Sopenharmony_ci if (JSArray::kMaxArrayLength - estimate_nof < element_estimate) { 13031cb0ef41Sopenharmony_ci estimate_nof = JSArray::kMaxArrayLength; 13041cb0ef41Sopenharmony_ci } else { 13051cb0ef41Sopenharmony_ci estimate_nof += element_estimate; 13061cb0ef41Sopenharmony_ci } 13071cb0ef41Sopenharmony_ci }); 13081cb0ef41Sopenharmony_ci 13091cb0ef41Sopenharmony_ci // If estimated number of elements is more than half of length, a 13101cb0ef41Sopenharmony_ci // fixed array (fast case) is more time and space-efficient than a 13111cb0ef41Sopenharmony_ci // dictionary. 13121cb0ef41Sopenharmony_ci bool fast_case = is_array_species && 13131cb0ef41Sopenharmony_ci (estimate_nof * 2) >= estimate_result_length && 13141cb0ef41Sopenharmony_ci Protectors::IsIsConcatSpreadableLookupChainIntact(isolate); 13151cb0ef41Sopenharmony_ci 13161cb0ef41Sopenharmony_ci if (fast_case && kind == PACKED_DOUBLE_ELEMENTS) { 13171cb0ef41Sopenharmony_ci Handle<FixedArrayBase> storage = 13181cb0ef41Sopenharmony_ci isolate->factory()->NewFixedDoubleArray(estimate_result_length); 13191cb0ef41Sopenharmony_ci int j = 0; 13201cb0ef41Sopenharmony_ci bool failure = false; 13211cb0ef41Sopenharmony_ci if (estimate_result_length > 0) { 13221cb0ef41Sopenharmony_ci Handle<FixedDoubleArray> double_storage = 13231cb0ef41Sopenharmony_ci Handle<FixedDoubleArray>::cast(storage); 13241cb0ef41Sopenharmony_ci for (int i = 0; i < argument_count; i++) { 13251cb0ef41Sopenharmony_ci Handle<Object> obj = args->at(i); 13261cb0ef41Sopenharmony_ci if (obj->IsSmi()) { 13271cb0ef41Sopenharmony_ci double_storage->set(j, Smi::ToInt(*obj)); 13281cb0ef41Sopenharmony_ci j++; 13291cb0ef41Sopenharmony_ci } else if (obj->IsNumber()) { 13301cb0ef41Sopenharmony_ci double_storage->set(j, obj->Number()); 13311cb0ef41Sopenharmony_ci j++; 13321cb0ef41Sopenharmony_ci } else { 13331cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 13341cb0ef41Sopenharmony_ci JSArray array = JSArray::cast(*obj); 13351cb0ef41Sopenharmony_ci uint32_t length = static_cast<uint32_t>(array.length().Number()); 13361cb0ef41Sopenharmony_ci switch (array.GetElementsKind()) { 13371cb0ef41Sopenharmony_ci case HOLEY_DOUBLE_ELEMENTS: 13381cb0ef41Sopenharmony_ci case PACKED_DOUBLE_ELEMENTS: { 13391cb0ef41Sopenharmony_ci // Empty array is FixedArray but not FixedDoubleArray. 13401cb0ef41Sopenharmony_ci if (length == 0) break; 13411cb0ef41Sopenharmony_ci FixedDoubleArray elements = 13421cb0ef41Sopenharmony_ci FixedDoubleArray::cast(array.elements()); 13431cb0ef41Sopenharmony_ci for (uint32_t k = 0; k < length; k++) { 13441cb0ef41Sopenharmony_ci if (elements.is_the_hole(k)) { 13451cb0ef41Sopenharmony_ci // TODO(jkummerow/verwaest): We could be a bit more clever 13461cb0ef41Sopenharmony_ci // here: Check if there are no elements/getters on the 13471cb0ef41Sopenharmony_ci // prototype chain, and if so, allow creation of a holey 13481cb0ef41Sopenharmony_ci // result array. 13491cb0ef41Sopenharmony_ci // Same thing below (holey smi case). 13501cb0ef41Sopenharmony_ci failure = true; 13511cb0ef41Sopenharmony_ci break; 13521cb0ef41Sopenharmony_ci } 13531cb0ef41Sopenharmony_ci double double_value = elements.get_scalar(k); 13541cb0ef41Sopenharmony_ci double_storage->set(j, double_value); 13551cb0ef41Sopenharmony_ci j++; 13561cb0ef41Sopenharmony_ci } 13571cb0ef41Sopenharmony_ci break; 13581cb0ef41Sopenharmony_ci } 13591cb0ef41Sopenharmony_ci case HOLEY_SMI_ELEMENTS: 13601cb0ef41Sopenharmony_ci case PACKED_SMI_ELEMENTS: { 13611cb0ef41Sopenharmony_ci Object the_hole = ReadOnlyRoots(isolate).the_hole_value(); 13621cb0ef41Sopenharmony_ci FixedArray elements(FixedArray::cast(array.elements())); 13631cb0ef41Sopenharmony_ci for (uint32_t k = 0; k < length; k++) { 13641cb0ef41Sopenharmony_ci Object element = elements.get(k); 13651cb0ef41Sopenharmony_ci if (element == the_hole) { 13661cb0ef41Sopenharmony_ci failure = true; 13671cb0ef41Sopenharmony_ci break; 13681cb0ef41Sopenharmony_ci } 13691cb0ef41Sopenharmony_ci int32_t int_value = Smi::ToInt(element); 13701cb0ef41Sopenharmony_ci double_storage->set(j, int_value); 13711cb0ef41Sopenharmony_ci j++; 13721cb0ef41Sopenharmony_ci } 13731cb0ef41Sopenharmony_ci break; 13741cb0ef41Sopenharmony_ci } 13751cb0ef41Sopenharmony_ci case HOLEY_ELEMENTS: 13761cb0ef41Sopenharmony_ci case HOLEY_FROZEN_ELEMENTS: 13771cb0ef41Sopenharmony_ci case HOLEY_SEALED_ELEMENTS: 13781cb0ef41Sopenharmony_ci case HOLEY_NONEXTENSIBLE_ELEMENTS: 13791cb0ef41Sopenharmony_ci case PACKED_ELEMENTS: 13801cb0ef41Sopenharmony_ci case PACKED_FROZEN_ELEMENTS: 13811cb0ef41Sopenharmony_ci case PACKED_SEALED_ELEMENTS: 13821cb0ef41Sopenharmony_ci case PACKED_NONEXTENSIBLE_ELEMENTS: 13831cb0ef41Sopenharmony_ci case DICTIONARY_ELEMENTS: 13841cb0ef41Sopenharmony_ci case NO_ELEMENTS: 13851cb0ef41Sopenharmony_ci DCHECK_EQ(0u, length); 13861cb0ef41Sopenharmony_ci break; 13871cb0ef41Sopenharmony_ci default: 13881cb0ef41Sopenharmony_ci UNREACHABLE(); 13891cb0ef41Sopenharmony_ci } 13901cb0ef41Sopenharmony_ci } 13911cb0ef41Sopenharmony_ci if (failure) break; 13921cb0ef41Sopenharmony_ci } 13931cb0ef41Sopenharmony_ci } 13941cb0ef41Sopenharmony_ci if (!failure) { 13951cb0ef41Sopenharmony_ci return *isolate->factory()->NewJSArrayWithElements(storage, kind, j); 13961cb0ef41Sopenharmony_ci } 13971cb0ef41Sopenharmony_ci // In case of failure, fall through. 13981cb0ef41Sopenharmony_ci } 13991cb0ef41Sopenharmony_ci 14001cb0ef41Sopenharmony_ci Handle<HeapObject> storage; 14011cb0ef41Sopenharmony_ci if (fast_case) { 14021cb0ef41Sopenharmony_ci // The backing storage array must have non-existing elements to preserve 14031cb0ef41Sopenharmony_ci // holes across concat operations. 14041cb0ef41Sopenharmony_ci storage = 14051cb0ef41Sopenharmony_ci isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); 14061cb0ef41Sopenharmony_ci } else if (is_array_species) { 14071cb0ef41Sopenharmony_ci storage = NumberDictionary::New(isolate, estimate_nof); 14081cb0ef41Sopenharmony_ci } else { 14091cb0ef41Sopenharmony_ci DCHECK(species->IsConstructor()); 14101cb0ef41Sopenharmony_ci Handle<Object> length(Smi::zero(), isolate); 14111cb0ef41Sopenharmony_ci Handle<Object> storage_object; 14121cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14131cb0ef41Sopenharmony_ci isolate, storage_object, 14141cb0ef41Sopenharmony_ci Execution::New(isolate, species, species, 1, &length)); 14151cb0ef41Sopenharmony_ci storage = Handle<HeapObject>::cast(storage_object); 14161cb0ef41Sopenharmony_ci } 14171cb0ef41Sopenharmony_ci 14181cb0ef41Sopenharmony_ci ArrayConcatVisitor visitor(isolate, storage, fast_case); 14191cb0ef41Sopenharmony_ci 14201cb0ef41Sopenharmony_ci for (int i = 0; i < argument_count; i++) { 14211cb0ef41Sopenharmony_ci Handle<Object> obj = args->at(i); 14221cb0ef41Sopenharmony_ci Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj); 14231cb0ef41Sopenharmony_ci MAYBE_RETURN(spreadable, ReadOnlyRoots(isolate).exception()); 14241cb0ef41Sopenharmony_ci if (spreadable.FromJust()) { 14251cb0ef41Sopenharmony_ci Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj); 14261cb0ef41Sopenharmony_ci if (!IterateElements(isolate, object, &visitor)) { 14271cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).exception(); 14281cb0ef41Sopenharmony_ci } 14291cb0ef41Sopenharmony_ci } else { 14301cb0ef41Sopenharmony_ci if (!visitor.visit(0, obj)) return ReadOnlyRoots(isolate).exception(); 14311cb0ef41Sopenharmony_ci visitor.increase_index_offset(1); 14321cb0ef41Sopenharmony_ci } 14331cb0ef41Sopenharmony_ci } 14341cb0ef41Sopenharmony_ci 14351cb0ef41Sopenharmony_ci if (visitor.exceeds_array_limit()) { 14361cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 14371cb0ef41Sopenharmony_ci isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); 14381cb0ef41Sopenharmony_ci } 14391cb0ef41Sopenharmony_ci 14401cb0ef41Sopenharmony_ci if (is_array_species) { 14411cb0ef41Sopenharmony_ci return *visitor.ToArray(); 14421cb0ef41Sopenharmony_ci } else { 14431cb0ef41Sopenharmony_ci RETURN_RESULT_OR_FAILURE(isolate, visitor.ToJSReceiver()); 14441cb0ef41Sopenharmony_ci } 14451cb0ef41Sopenharmony_ci} 14461cb0ef41Sopenharmony_ci 14471cb0ef41Sopenharmony_cibool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) { 14481cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 14491cb0ef41Sopenharmony_ci Map map = obj->map(); 14501cb0ef41Sopenharmony_ci // If there is only the 'length' property we are fine. 14511cb0ef41Sopenharmony_ci if (map.prototype() == isolate->native_context()->initial_array_prototype() && 14521cb0ef41Sopenharmony_ci map.NumberOfOwnDescriptors() == 1) { 14531cb0ef41Sopenharmony_ci return true; 14541cb0ef41Sopenharmony_ci } 14551cb0ef41Sopenharmony_ci // TODO(cbruni): slower lookup for array subclasses and support slow 14561cb0ef41Sopenharmony_ci // @@IsConcatSpreadable lookup. 14571cb0ef41Sopenharmony_ci return false; 14581cb0ef41Sopenharmony_ci} 14591cb0ef41Sopenharmony_ci 14601cb0ef41Sopenharmony_ciMaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, 14611cb0ef41Sopenharmony_ci BuiltinArguments* args) { 14621cb0ef41Sopenharmony_ci if (!Protectors::IsIsConcatSpreadableLookupChainIntact(isolate)) { 14631cb0ef41Sopenharmony_ci return MaybeHandle<JSArray>(); 14641cb0ef41Sopenharmony_ci } 14651cb0ef41Sopenharmony_ci // We shouldn't overflow when adding another len. 14661cb0ef41Sopenharmony_ci const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); 14671cb0ef41Sopenharmony_ci STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); 14681cb0ef41Sopenharmony_ci STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt); 14691cb0ef41Sopenharmony_ci USE(kHalfOfMaxInt); 14701cb0ef41Sopenharmony_ci 14711cb0ef41Sopenharmony_ci int n_arguments = args->length(); 14721cb0ef41Sopenharmony_ci int result_len = 0; 14731cb0ef41Sopenharmony_ci { 14741cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 14751cb0ef41Sopenharmony_ci // Iterate through all the arguments performing checks 14761cb0ef41Sopenharmony_ci // and calculating total length. 14771cb0ef41Sopenharmony_ci for (int i = 0; i < n_arguments; i++) { 14781cb0ef41Sopenharmony_ci Object arg = (*args)[i]; 14791cb0ef41Sopenharmony_ci if (!arg.IsJSArray()) return MaybeHandle<JSArray>(); 14801cb0ef41Sopenharmony_ci if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { 14811cb0ef41Sopenharmony_ci return MaybeHandle<JSArray>(); 14821cb0ef41Sopenharmony_ci } 14831cb0ef41Sopenharmony_ci // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. 14841cb0ef41Sopenharmony_ci if (!JSObject::cast(arg).HasFastElements()) { 14851cb0ef41Sopenharmony_ci return MaybeHandle<JSArray>(); 14861cb0ef41Sopenharmony_ci } 14871cb0ef41Sopenharmony_ci Handle<JSArray> array(JSArray::cast(arg), isolate); 14881cb0ef41Sopenharmony_ci if (!IsSimpleArray(isolate, array)) { 14891cb0ef41Sopenharmony_ci return MaybeHandle<JSArray>(); 14901cb0ef41Sopenharmony_ci } 14911cb0ef41Sopenharmony_ci // The Array length is guaranted to be <= kHalfOfMaxInt thus we won't 14921cb0ef41Sopenharmony_ci // overflow. 14931cb0ef41Sopenharmony_ci result_len += Smi::ToInt(array->length()); 14941cb0ef41Sopenharmony_ci DCHECK_GE(result_len, 0); 14951cb0ef41Sopenharmony_ci // Throw an Error if we overflow the FixedArray limits 14961cb0ef41Sopenharmony_ci if (FixedDoubleArray::kMaxLength < result_len || 14971cb0ef41Sopenharmony_ci FixedArray::kMaxLength < result_len) { 14981cb0ef41Sopenharmony_ci AllowGarbageCollection gc; 14991cb0ef41Sopenharmony_ci THROW_NEW_ERROR(isolate, 15001cb0ef41Sopenharmony_ci NewRangeError(MessageTemplate::kInvalidArrayLength), 15011cb0ef41Sopenharmony_ci JSArray); 15021cb0ef41Sopenharmony_ci } 15031cb0ef41Sopenharmony_ci } 15041cb0ef41Sopenharmony_ci } 15051cb0ef41Sopenharmony_ci return ElementsAccessor::Concat(isolate, args, n_arguments, result_len); 15061cb0ef41Sopenharmony_ci} 15071cb0ef41Sopenharmony_ci 15081cb0ef41Sopenharmony_ci} // namespace 15091cb0ef41Sopenharmony_ci 15101cb0ef41Sopenharmony_ci// ES6 22.1.3.1 Array.prototype.concat 15111cb0ef41Sopenharmony_ciBUILTIN(ArrayConcat) { 15121cb0ef41Sopenharmony_ci HandleScope scope(isolate); 15131cb0ef41Sopenharmony_ci 15141cb0ef41Sopenharmony_ci Handle<Object> receiver = args.receiver(); 15151cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 15161cb0ef41Sopenharmony_ci isolate, receiver, 15171cb0ef41Sopenharmony_ci Object::ToObject(isolate, args.receiver(), "Array.prototype.concat")); 15181cb0ef41Sopenharmony_ci args.set_at(0, *receiver); 15191cb0ef41Sopenharmony_ci 15201cb0ef41Sopenharmony_ci Handle<JSArray> result_array; 15211cb0ef41Sopenharmony_ci 15221cb0ef41Sopenharmony_ci // Avoid a real species read to avoid extra lookups to the array constructor 15231cb0ef41Sopenharmony_ci if (V8_LIKELY(receiver->IsJSArray() && 15241cb0ef41Sopenharmony_ci Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) && 15251cb0ef41Sopenharmony_ci Protectors::IsArraySpeciesLookupChainIntact(isolate))) { 15261cb0ef41Sopenharmony_ci if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { 15271cb0ef41Sopenharmony_ci return *result_array; 15281cb0ef41Sopenharmony_ci } 15291cb0ef41Sopenharmony_ci if (isolate->has_pending_exception()) 15301cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).exception(); 15311cb0ef41Sopenharmony_ci } 15321cb0ef41Sopenharmony_ci // Reading @@species happens before anything else with a side effect, so 15331cb0ef41Sopenharmony_ci // we can do it here to determine whether to take the fast path. 15341cb0ef41Sopenharmony_ci Handle<Object> species; 15351cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 15361cb0ef41Sopenharmony_ci isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); 15371cb0ef41Sopenharmony_ci if (*species == *isolate->array_function()) { 15381cb0ef41Sopenharmony_ci if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { 15391cb0ef41Sopenharmony_ci return *result_array; 15401cb0ef41Sopenharmony_ci } 15411cb0ef41Sopenharmony_ci if (isolate->has_pending_exception()) 15421cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).exception(); 15431cb0ef41Sopenharmony_ci } 15441cb0ef41Sopenharmony_ci return Slow_ArrayConcat(&args, species, isolate); 15451cb0ef41Sopenharmony_ci} 15461cb0ef41Sopenharmony_ci 15471cb0ef41Sopenharmony_cinamespace { 15481cb0ef41Sopenharmony_ci 15491cb0ef41Sopenharmony_ci// https://tc39.es/proposal-array-grouping/#sec-add-value-to-keyed-group 15501cb0ef41Sopenharmony_ci// Each keyed group is an array list. 15511cb0ef41Sopenharmony_ciinline Handle<OrderedHashMap> AddValueToKeyedGroup( 15521cb0ef41Sopenharmony_ci Isolate* isolate, Handle<OrderedHashMap> groups, Handle<Object> key, 15531cb0ef41Sopenharmony_ci Handle<Object> value) { 15541cb0ef41Sopenharmony_ci InternalIndex entry = groups->FindEntry(isolate, *key); 15551cb0ef41Sopenharmony_ci if (!entry.is_found()) { 15561cb0ef41Sopenharmony_ci Handle<ArrayList> array = ArrayList::New(isolate, 1); 15571cb0ef41Sopenharmony_ci array = ArrayList::Add(isolate, array, value); 15581cb0ef41Sopenharmony_ci return OrderedHashMap::Add(isolate, groups, key, array).ToHandleChecked(); 15591cb0ef41Sopenharmony_ci } 15601cb0ef41Sopenharmony_ci Handle<ArrayList> array = 15611cb0ef41Sopenharmony_ci Handle<ArrayList>(ArrayList::cast(groups->ValueAt(entry)), isolate); 15621cb0ef41Sopenharmony_ci array = ArrayList::Add(isolate, array, value); 15631cb0ef41Sopenharmony_ci groups->SetEntry(entry, *key, *array); 15641cb0ef41Sopenharmony_ci return groups; 15651cb0ef41Sopenharmony_ci} 15661cb0ef41Sopenharmony_ci 15671cb0ef41Sopenharmony_ciinline bool IsFastArray(Handle<JSReceiver> object) { 15681cb0ef41Sopenharmony_ci Isolate* isolate = object->GetIsolate(); 15691cb0ef41Sopenharmony_ci if (isolate->force_slow_path()) return false; 15701cb0ef41Sopenharmony_ci if (!object->IsJSArray()) return false; 15711cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(object); 15721cb0ef41Sopenharmony_ci if (!array->HasFastElements(isolate)) return false; 15731cb0ef41Sopenharmony_ci 15741cb0ef41Sopenharmony_ci Context context = isolate->context(); 15751cb0ef41Sopenharmony_ci if (array->map().prototype() != 15761cb0ef41Sopenharmony_ci context.get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) { 15771cb0ef41Sopenharmony_ci return false; 15781cb0ef41Sopenharmony_ci } 15791cb0ef41Sopenharmony_ci 15801cb0ef41Sopenharmony_ci return Protectors::IsNoElementsIntact(isolate); 15811cb0ef41Sopenharmony_ci} 15821cb0ef41Sopenharmony_ci 15831cb0ef41Sopenharmony_ciinline bool CheckArrayMapNotModified(Handle<JSArray> array, 15841cb0ef41Sopenharmony_ci Handle<Map> original_map) { 15851cb0ef41Sopenharmony_ci if (array->map() != *original_map) { 15861cb0ef41Sopenharmony_ci return false; 15871cb0ef41Sopenharmony_ci } 15881cb0ef41Sopenharmony_ci return Protectors::IsNoElementsIntact(array->GetIsolate()); 15891cb0ef41Sopenharmony_ci} 15901cb0ef41Sopenharmony_ci 15911cb0ef41Sopenharmony_cienum class GroupByMode { kToObject, kToMap }; 15921cb0ef41Sopenharmony_ci 15931cb0ef41Sopenharmony_citemplate <GroupByMode mode> 15941cb0ef41Sopenharmony_ciinline MaybeHandle<OrderedHashMap> GenericArrayGroupBy( 15951cb0ef41Sopenharmony_ci Isolate* isolate, Handle<JSReceiver> O, Handle<Object> callbackfn, 15961cb0ef41Sopenharmony_ci Handle<OrderedHashMap> groups, double initialK, double len) { 15971cb0ef41Sopenharmony_ci // 6. Repeat, while k < len 15981cb0ef41Sopenharmony_ci for (double k = initialK; k < len; ++k) { 15991cb0ef41Sopenharmony_ci // 6a. Let Pk be ! ToString((k)). 16001cb0ef41Sopenharmony_ci Handle<Name> Pk; 16011cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION( 16021cb0ef41Sopenharmony_ci isolate, Pk, Object::ToName(isolate, isolate->factory()->NewNumber(k)), 16031cb0ef41Sopenharmony_ci OrderedHashMap); 16041cb0ef41Sopenharmony_ci // 6b. Let kValue be ? Get(O, Pk). 16051cb0ef41Sopenharmony_ci Handle<Object> kValue; 16061cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION(isolate, kValue, 16071cb0ef41Sopenharmony_ci Object::GetPropertyOrElement(isolate, O, Pk), 16081cb0ef41Sopenharmony_ci OrderedHashMap); 16091cb0ef41Sopenharmony_ci 16101cb0ef41Sopenharmony_ci // Common steps for ArrayPrototypeGroupBy and ArrayPrototypeGroupByToMap 16111cb0ef41Sopenharmony_ci // 6c. Let key be ? Call(callbackfn, thisArg, « kValue, (k), O »). 16121cb0ef41Sopenharmony_ci Handle<Object> propertyKey; 16131cb0ef41Sopenharmony_ci Handle<Object> argv[] = {kValue, isolate->factory()->NewNumber(k), O}; 16141cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION(isolate, propertyKey, 16151cb0ef41Sopenharmony_ci Execution::Call(isolate, callbackfn, O, 3, argv), 16161cb0ef41Sopenharmony_ci OrderedHashMap); 16171cb0ef41Sopenharmony_ci 16181cb0ef41Sopenharmony_ci if (mode == GroupByMode::kToMap) { 16191cb0ef41Sopenharmony_ci // 6d. If key is -0, set key to +0. 16201cb0ef41Sopenharmony_ci if (propertyKey->IsMinusZero()) { 16211cb0ef41Sopenharmony_ci propertyKey = Handle<Smi>(Smi::FromInt(0), isolate); 16221cb0ef41Sopenharmony_ci } 16231cb0ef41Sopenharmony_ci } else { 16241cb0ef41Sopenharmony_ci // 6c. Let propertyKey be ? ToPropertyKey(? Call(callbackfn, thisArg, « 16251cb0ef41Sopenharmony_ci // kValue, (k), O »)). 16261cb0ef41Sopenharmony_ci Handle<Name> propertyKeyName; 16271cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION(isolate, propertyKeyName, 16281cb0ef41Sopenharmony_ci Object::ToName(isolate, propertyKey), 16291cb0ef41Sopenharmony_ci OrderedHashMap); 16301cb0ef41Sopenharmony_ci propertyKey = isolate->factory()->InternalizeName(propertyKeyName); 16311cb0ef41Sopenharmony_ci } 16321cb0ef41Sopenharmony_ci 16331cb0ef41Sopenharmony_ci // 6e. Perform ! AddValueToKeyedGroup(groups, propertyKey, kValue). 16341cb0ef41Sopenharmony_ci groups = AddValueToKeyedGroup(isolate, groups, propertyKey, kValue); 16351cb0ef41Sopenharmony_ci 16361cb0ef41Sopenharmony_ci // 6f. Set k to k + 1. 16371cb0ef41Sopenharmony_ci // done by the loop. 16381cb0ef41Sopenharmony_ci } 16391cb0ef41Sopenharmony_ci 16401cb0ef41Sopenharmony_ci return groups; 16411cb0ef41Sopenharmony_ci} 16421cb0ef41Sopenharmony_ci 16431cb0ef41Sopenharmony_citemplate <GroupByMode mode> 16441cb0ef41Sopenharmony_ciinline MaybeHandle<OrderedHashMap> FastArrayGroupBy( 16451cb0ef41Sopenharmony_ci Isolate* isolate, Handle<JSArray> array, Handle<Object> callbackfn, 16461cb0ef41Sopenharmony_ci Handle<OrderedHashMap> groups, double len, 16471cb0ef41Sopenharmony_ci ElementsKind* result_elements_kind) { 16481cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(result_elements_kind); 16491cb0ef41Sopenharmony_ci 16501cb0ef41Sopenharmony_ci Handle<Map> original_map = Handle<Map>(array->map(), isolate); 16511cb0ef41Sopenharmony_ci uint32_t uint_len = static_cast<uint32_t>(len); 16521cb0ef41Sopenharmony_ci ElementsAccessor* accessor = array->GetElementsAccessor(); 16531cb0ef41Sopenharmony_ci 16541cb0ef41Sopenharmony_ci // 4. Let k be 0. 16551cb0ef41Sopenharmony_ci // 6. Repeat, while k < len 16561cb0ef41Sopenharmony_ci for (InternalIndex k : InternalIndex::Range(uint_len)) { 16571cb0ef41Sopenharmony_ci if (!CheckArrayMapNotModified(array, original_map) || 16581cb0ef41Sopenharmony_ci k.as_uint32() >= static_cast<uint32_t>(array->length().Number())) { 16591cb0ef41Sopenharmony_ci return GenericArrayGroupBy<mode>(isolate, array, callbackfn, groups, 16601cb0ef41Sopenharmony_ci k.as_uint32(), len); 16611cb0ef41Sopenharmony_ci } 16621cb0ef41Sopenharmony_ci // 6a. Let Pk be ! ToString((k)). 16631cb0ef41Sopenharmony_ci // 6b. Let kValue be ? Get(O, Pk). 16641cb0ef41Sopenharmony_ci Handle<Object> kValue = accessor->Get(array, k); 16651cb0ef41Sopenharmony_ci if (kValue->IsTheHole()) { 16661cb0ef41Sopenharmony_ci kValue = isolate->factory()->undefined_value(); 16671cb0ef41Sopenharmony_ci } 16681cb0ef41Sopenharmony_ci 16691cb0ef41Sopenharmony_ci // Common steps for ArrayPrototypeGroupBy and ArrayPrototypeGroupByToMap 16701cb0ef41Sopenharmony_ci // 6c. Let key be ? Call(callbackfn, thisArg, « kValue, (k), O »). 16711cb0ef41Sopenharmony_ci Handle<Object> propertyKey; 16721cb0ef41Sopenharmony_ci Handle<Object> argv[] = { 16731cb0ef41Sopenharmony_ci kValue, isolate->factory()->NewNumber(k.as_uint32()), array}; 16741cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION( 16751cb0ef41Sopenharmony_ci isolate, propertyKey, 16761cb0ef41Sopenharmony_ci Execution::Call(isolate, callbackfn, array, 3, argv), OrderedHashMap); 16771cb0ef41Sopenharmony_ci 16781cb0ef41Sopenharmony_ci if (mode == GroupByMode::kToMap) { 16791cb0ef41Sopenharmony_ci // 6d. If key is -0, set key to +0. 16801cb0ef41Sopenharmony_ci if (propertyKey->IsMinusZero()) { 16811cb0ef41Sopenharmony_ci propertyKey = Handle<Smi>(Smi::FromInt(0), isolate); 16821cb0ef41Sopenharmony_ci } 16831cb0ef41Sopenharmony_ci } else { 16841cb0ef41Sopenharmony_ci // 6c. Let propertyKey be ? ToPropertyKey(? Call(callbackfn, thisArg, « 16851cb0ef41Sopenharmony_ci // kValue, (k), O »)). 16861cb0ef41Sopenharmony_ci Handle<Name> propertyKeyName; 16871cb0ef41Sopenharmony_ci ASSIGN_RETURN_ON_EXCEPTION(isolate, propertyKeyName, 16881cb0ef41Sopenharmony_ci Object::ToName(isolate, propertyKey), 16891cb0ef41Sopenharmony_ci OrderedHashMap); 16901cb0ef41Sopenharmony_ci propertyKey = isolate->factory()->InternalizeName(propertyKeyName); 16911cb0ef41Sopenharmony_ci } 16921cb0ef41Sopenharmony_ci 16931cb0ef41Sopenharmony_ci // 6e. Perform ! AddValueToKeyedGroup(groups, propertyKey, kValue). 16941cb0ef41Sopenharmony_ci groups = AddValueToKeyedGroup(isolate, groups, propertyKey, kValue); 16951cb0ef41Sopenharmony_ci 16961cb0ef41Sopenharmony_ci // 6f. Set k to k + 1. 16971cb0ef41Sopenharmony_ci // done by the loop. 16981cb0ef41Sopenharmony_ci } 16991cb0ef41Sopenharmony_ci 17001cb0ef41Sopenharmony_ci // When staying on the fast path, we can deduce a more specific results 17011cb0ef41Sopenharmony_ci // ElementsKind for the keyed groups based on the input ElementsKind. 17021cb0ef41Sopenharmony_ci // 17031cb0ef41Sopenharmony_ci // Double elements are stored as HeapNumbers in the keyed group elements 17041cb0ef41Sopenharmony_ci // so that we don't need to cast all the keyed groups when switching from 17051cb0ef41Sopenharmony_ci // fast path to the generic path. 17061cb0ef41Sopenharmony_ci // TODO(v8:12499) add unboxed double elements support 17071cb0ef41Sopenharmony_ci if (array->GetElementsKind() == ElementsKind::PACKED_SMI_ELEMENTS) { 17081cb0ef41Sopenharmony_ci *result_elements_kind = ElementsKind::PACKED_SMI_ELEMENTS; 17091cb0ef41Sopenharmony_ci } 17101cb0ef41Sopenharmony_ci 17111cb0ef41Sopenharmony_ci return groups; 17121cb0ef41Sopenharmony_ci} 17131cb0ef41Sopenharmony_ci 17141cb0ef41Sopenharmony_ci} // namespace 17151cb0ef41Sopenharmony_ci 17161cb0ef41Sopenharmony_ci// https://tc39.es/proposal-array-grouping/#sec-array.prototype.groupby 17171cb0ef41Sopenharmony_ciBUILTIN(ArrayPrototypeGroupBy) { 17181cb0ef41Sopenharmony_ci const char* const kMethodName = "Array.prototype.groupBy"; 17191cb0ef41Sopenharmony_ci HandleScope scope(isolate); 17201cb0ef41Sopenharmony_ci 17211cb0ef41Sopenharmony_ci Handle<JSReceiver> O; 17221cb0ef41Sopenharmony_ci // 1. Let O be ? ToObject(this value). 17231cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 17241cb0ef41Sopenharmony_ci isolate, O, Object::ToObject(isolate, args.receiver(), kMethodName)); 17251cb0ef41Sopenharmony_ci 17261cb0ef41Sopenharmony_ci // 2. Let len be ? LengthOfArrayLike(O). 17271cb0ef41Sopenharmony_ci double len; 17281cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len, 17291cb0ef41Sopenharmony_ci GetLengthProperty(isolate, O)); 17301cb0ef41Sopenharmony_ci 17311cb0ef41Sopenharmony_ci // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. 17321cb0ef41Sopenharmony_ci Handle<Object> callbackfn = args.atOrUndefined(isolate, 1); 17331cb0ef41Sopenharmony_ci if (!callbackfn->IsCallable()) { 17341cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 17351cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kCalledNonCallable, callbackfn)); 17361cb0ef41Sopenharmony_ci } 17371cb0ef41Sopenharmony_ci 17381cb0ef41Sopenharmony_ci // 5. Let groups be a new empty List. 17391cb0ef41Sopenharmony_ci Handle<OrderedHashMap> groups = isolate->factory()->NewOrderedHashMap(); 17401cb0ef41Sopenharmony_ci ElementsKind result_elements_kind = ElementsKind::PACKED_ELEMENTS; 17411cb0ef41Sopenharmony_ci if (IsFastArray(O)) { 17421cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(O); 17431cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 17441cb0ef41Sopenharmony_ci isolate, groups, 17451cb0ef41Sopenharmony_ci FastArrayGroupBy<GroupByMode::kToObject>( 17461cb0ef41Sopenharmony_ci isolate, array, callbackfn, groups, len, &result_elements_kind)); 17471cb0ef41Sopenharmony_ci } else { 17481cb0ef41Sopenharmony_ci // 4. Let k be 0. 17491cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 17501cb0ef41Sopenharmony_ci isolate, groups, 17511cb0ef41Sopenharmony_ci GenericArrayGroupBy<GroupByMode::kToObject>(isolate, O, callbackfn, 17521cb0ef41Sopenharmony_ci groups, 0, len)); 17531cb0ef41Sopenharmony_ci } 17541cb0ef41Sopenharmony_ci 17551cb0ef41Sopenharmony_ci // 7. Let obj be ! OrdinaryObjectCreate(null). 17561cb0ef41Sopenharmony_ci Handle<JSObject> obj = isolate->factory()->NewJSObjectWithNullProto(); 17571cb0ef41Sopenharmony_ci 17581cb0ef41Sopenharmony_ci // 8. For each Record { [[Key]], [[Elements]] } g of groups, do 17591cb0ef41Sopenharmony_ci for (InternalIndex entry : groups->IterateEntries()) { 17601cb0ef41Sopenharmony_ci Handle<Name> key = Handle<Name>(Name::cast(groups->KeyAt(entry)), isolate); 17611cb0ef41Sopenharmony_ci // 8a. Let elements be ! CreateArrayFromList(g.[[Elements]]). 17621cb0ef41Sopenharmony_ci Handle<ArrayList> array_list = 17631cb0ef41Sopenharmony_ci Handle<ArrayList>(ArrayList::cast(groups->ValueAt(entry)), isolate); 17641cb0ef41Sopenharmony_ci Handle<FixedArray> elements = ArrayList::Elements(isolate, array_list); 17651cb0ef41Sopenharmony_ci Handle<JSArray> array = isolate->factory()->NewJSArrayWithElements( 17661cb0ef41Sopenharmony_ci elements, result_elements_kind, array_list->Length()); 17671cb0ef41Sopenharmony_ci 17681cb0ef41Sopenharmony_ci // 8b. Perform ! CreateDataPropertyOrThrow(obj, g.[[Key]], elements). 17691cb0ef41Sopenharmony_ci JSReceiver::CreateDataProperty(isolate, obj, key, array, 17701cb0ef41Sopenharmony_ci Just(kThrowOnError)) 17711cb0ef41Sopenharmony_ci .Check(); 17721cb0ef41Sopenharmony_ci } 17731cb0ef41Sopenharmony_ci 17741cb0ef41Sopenharmony_ci // 9. Return obj. 17751cb0ef41Sopenharmony_ci return *obj; 17761cb0ef41Sopenharmony_ci} 17771cb0ef41Sopenharmony_ci 17781cb0ef41Sopenharmony_ci// https://tc39.es/proposal-array-grouping/#sec-array.prototype.groupbymap 17791cb0ef41Sopenharmony_ciBUILTIN(ArrayPrototypeGroupByToMap) { 17801cb0ef41Sopenharmony_ci const char* const kMethodName = "Array.prototype.groupByToMap"; 17811cb0ef41Sopenharmony_ci HandleScope scope(isolate); 17821cb0ef41Sopenharmony_ci 17831cb0ef41Sopenharmony_ci Handle<JSReceiver> O; 17841cb0ef41Sopenharmony_ci // 1. Let O be ? ToObject(this value). 17851cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 17861cb0ef41Sopenharmony_ci isolate, O, Object::ToObject(isolate, args.receiver(), kMethodName)); 17871cb0ef41Sopenharmony_ci 17881cb0ef41Sopenharmony_ci // 2. Let len be ? LengthOfArrayLike(O). 17891cb0ef41Sopenharmony_ci double len; 17901cb0ef41Sopenharmony_ci MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len, 17911cb0ef41Sopenharmony_ci GetLengthProperty(isolate, O)); 17921cb0ef41Sopenharmony_ci 17931cb0ef41Sopenharmony_ci // 3. If IsCallable(callbackfn) is false, throw a TypeError exception. 17941cb0ef41Sopenharmony_ci Handle<Object> callbackfn = args.atOrUndefined(isolate, 1); 17951cb0ef41Sopenharmony_ci if (!callbackfn->IsCallable()) { 17961cb0ef41Sopenharmony_ci THROW_NEW_ERROR_RETURN_FAILURE( 17971cb0ef41Sopenharmony_ci isolate, NewTypeError(MessageTemplate::kCalledNonCallable, callbackfn)); 17981cb0ef41Sopenharmony_ci } 17991cb0ef41Sopenharmony_ci 18001cb0ef41Sopenharmony_ci // 5. Let groups be a new empty List. 18011cb0ef41Sopenharmony_ci Handle<OrderedHashMap> groups = isolate->factory()->NewOrderedHashMap(); 18021cb0ef41Sopenharmony_ci ElementsKind result_elements_kind = ElementsKind::PACKED_ELEMENTS; 18031cb0ef41Sopenharmony_ci if (IsFastArray(O)) { 18041cb0ef41Sopenharmony_ci Handle<JSArray> array = Handle<JSArray>::cast(O); 18051cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 18061cb0ef41Sopenharmony_ci isolate, groups, 18071cb0ef41Sopenharmony_ci FastArrayGroupBy<GroupByMode::kToMap>( 18081cb0ef41Sopenharmony_ci isolate, array, callbackfn, groups, len, &result_elements_kind)); 18091cb0ef41Sopenharmony_ci } else { 18101cb0ef41Sopenharmony_ci // 4. Let k be 0. 18111cb0ef41Sopenharmony_ci ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 18121cb0ef41Sopenharmony_ci isolate, groups, 18131cb0ef41Sopenharmony_ci GenericArrayGroupBy<GroupByMode::kToMap>(isolate, O, callbackfn, groups, 18141cb0ef41Sopenharmony_ci 0, len)); 18151cb0ef41Sopenharmony_ci } 18161cb0ef41Sopenharmony_ci 18171cb0ef41Sopenharmony_ci // 7. Let map be ! Construct(%Map%). 18181cb0ef41Sopenharmony_ci Handle<JSMap> map = isolate->factory()->NewJSMap(); 18191cb0ef41Sopenharmony_ci Handle<OrderedHashMap> map_table = isolate->factory()->NewOrderedHashMap(); 18201cb0ef41Sopenharmony_ci // 8. For each Record { [[Key]], [[Elements]] } g of groups, do 18211cb0ef41Sopenharmony_ci for (InternalIndex entry : groups->IterateEntries()) { 18221cb0ef41Sopenharmony_ci Handle<Object> key = Handle<Object>(groups->KeyAt(entry), isolate); 18231cb0ef41Sopenharmony_ci // 8a. Let elements be ! CreateArrayFromList(g.[[Elements]]). 18241cb0ef41Sopenharmony_ci Handle<ArrayList> array_list = 18251cb0ef41Sopenharmony_ci Handle<ArrayList>(ArrayList::cast(groups->ValueAt(entry)), isolate); 18261cb0ef41Sopenharmony_ci Handle<FixedArray> elements = ArrayList::Elements(isolate, array_list); 18271cb0ef41Sopenharmony_ci Handle<JSArray> array = isolate->factory()->NewJSArrayWithElements( 18281cb0ef41Sopenharmony_ci elements, result_elements_kind, array_list->Length()); 18291cb0ef41Sopenharmony_ci 18301cb0ef41Sopenharmony_ci // 8b. Let entry be the Record { [[Key]]: g.[[Key]], [[Value]]: elements }. 18311cb0ef41Sopenharmony_ci // 8c. Append entry as the last element of map.[[MapData]]. 18321cb0ef41Sopenharmony_ci map_table = 18331cb0ef41Sopenharmony_ci OrderedHashMap::Add(isolate, map_table, key, array).ToHandleChecked(); 18341cb0ef41Sopenharmony_ci } 18351cb0ef41Sopenharmony_ci map->set_table(*map_table); 18361cb0ef41Sopenharmony_ci 18371cb0ef41Sopenharmony_ci // 9. Return map. 18381cb0ef41Sopenharmony_ci return *map; 18391cb0ef41Sopenharmony_ci} 18401cb0ef41Sopenharmony_ci 18411cb0ef41Sopenharmony_ci} // namespace internal 18421cb0ef41Sopenharmony_ci} // namespace v8 1843