11cb0ef41Sopenharmony_ci// Copyright 2017 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/builtins/builtins-array-gen.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/builtins/builtins-iterator-gen.h" 81cb0ef41Sopenharmony_ci#include "src/builtins/builtins-string-gen.h" 91cb0ef41Sopenharmony_ci#include "src/builtins/builtins-typed-array-gen.h" 101cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-gen.h" 111cb0ef41Sopenharmony_ci#include "src/builtins/builtins.h" 121cb0ef41Sopenharmony_ci#include "src/codegen/code-stub-assembler.h" 131cb0ef41Sopenharmony_ci#include "src/codegen/interface-descriptors-inl.h" 141cb0ef41Sopenharmony_ci#include "src/execution/frame-constants.h" 151cb0ef41Sopenharmony_ci#include "src/heap/factory-inl.h" 161cb0ef41Sopenharmony_ci#include "src/objects/allocation-site-inl.h" 171cb0ef41Sopenharmony_ci#include "src/objects/arguments-inl.h" 181cb0ef41Sopenharmony_ci#include "src/objects/property-cell.h" 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_cinamespace v8 { 211cb0ef41Sopenharmony_cinamespace internal { 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ciArrayBuiltinsAssembler::ArrayBuiltinsAssembler( 241cb0ef41Sopenharmony_ci compiler::CodeAssemblerState* state) 251cb0ef41Sopenharmony_ci : CodeStubAssembler(state), 261cb0ef41Sopenharmony_ci k_(this), 271cb0ef41Sopenharmony_ci a_(this), 281cb0ef41Sopenharmony_ci fully_spec_compliant_(this, {&k_, &a_}) {} 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() { 311cb0ef41Sopenharmony_ci // 6. Let A be ? TypedArraySpeciesCreate(O, len). 321cb0ef41Sopenharmony_ci TNode<JSTypedArray> original_array = CAST(o()); 331cb0ef41Sopenharmony_ci const char* method_name = "%TypedArray%.prototype.map"; 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci TNode<JSTypedArray> a = TypedArraySpeciesCreateByLength( 361cb0ef41Sopenharmony_ci context(), method_name, original_array, len()); 371cb0ef41Sopenharmony_ci // In the Spec and our current implementation, the length check is already 381cb0ef41Sopenharmony_ci // performed in TypedArraySpeciesCreate. 391cb0ef41Sopenharmony_ci CSA_DCHECK(this, UintPtrLessThanOrEqual(len(), LoadJSTypedArrayLength(a))); 401cb0ef41Sopenharmony_ci fast_typed_array_target_ = 411cb0ef41Sopenharmony_ci Word32Equal(LoadElementsKind(original_array), LoadElementsKind(a)); 421cb0ef41Sopenharmony_ci a_ = a; 431cb0ef41Sopenharmony_ci} 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci// See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map. 461cb0ef41Sopenharmony_ciTNode<Object> ArrayBuiltinsAssembler::TypedArrayMapProcessor( 471cb0ef41Sopenharmony_ci TNode<Object> k_value, TNode<UintPtrT> k) { 481cb0ef41Sopenharmony_ci // 7c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »). 491cb0ef41Sopenharmony_ci TNode<Number> k_number = ChangeUintPtrToTagged(k); 501cb0ef41Sopenharmony_ci TNode<Object> mapped_value = 511cb0ef41Sopenharmony_ci Call(context(), callbackfn(), this_arg(), k_value, k_number, o()); 521cb0ef41Sopenharmony_ci Label fast(this), slow(this), done(this), detached(this, Label::kDeferred); 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci // 7d. Perform ? Set(A, Pk, mapped_value, true). 551cb0ef41Sopenharmony_ci // Since we know that A is a TypedArray, this always ends up in 561cb0ef41Sopenharmony_ci // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then 571cb0ef41Sopenharmony_ci // tc39.github.io/ecma262/#sec-integerindexedelementset . 581cb0ef41Sopenharmony_ci Branch(fast_typed_array_target_, &fast, &slow); 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci BIND(&fast); 611cb0ef41Sopenharmony_ci // #sec-integerindexedelementset 621cb0ef41Sopenharmony_ci // 2. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let 631cb0ef41Sopenharmony_ci // numValue be ? ToBigInt(v). 641cb0ef41Sopenharmony_ci // 3. Otherwise, let numValue be ? ToNumber(value). 651cb0ef41Sopenharmony_ci TNode<Object> num_value; 661cb0ef41Sopenharmony_ci if (source_elements_kind_ == BIGINT64_ELEMENTS || 671cb0ef41Sopenharmony_ci source_elements_kind_ == BIGUINT64_ELEMENTS) { 681cb0ef41Sopenharmony_ci num_value = ToBigInt(context(), mapped_value); 691cb0ef41Sopenharmony_ci } else { 701cb0ef41Sopenharmony_ci num_value = ToNumber_Inline(context(), mapped_value); 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci // The only way how this can bailout is because of a detached buffer. 741cb0ef41Sopenharmony_ci // TODO(v8:4153): Consider checking IsDetachedBuffer() and calling 751cb0ef41Sopenharmony_ci // TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric() here 761cb0ef41Sopenharmony_ci // instead to avoid converting k_number back to UintPtrT. 771cb0ef41Sopenharmony_ci EmitElementStore(CAST(a()), k_number, num_value, source_elements_kind_, 781cb0ef41Sopenharmony_ci KeyedAccessStoreMode::STANDARD_STORE, &detached, context()); 791cb0ef41Sopenharmony_ci Goto(&done); 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci BIND(&slow); 821cb0ef41Sopenharmony_ci { 831cb0ef41Sopenharmony_ci SetPropertyStrict(context(), a(), k_number, mapped_value); 841cb0ef41Sopenharmony_ci Goto(&done); 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci BIND(&detached); 881cb0ef41Sopenharmony_ci // tc39.github.io/ecma262/#sec-integerindexedelementset 891cb0ef41Sopenharmony_ci // 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. 901cb0ef41Sopenharmony_ci ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_); 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci BIND(&done); 931cb0ef41Sopenharmony_ci return a(); 941cb0ef41Sopenharmony_ci} 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::ReturnFromBuiltin(TNode<Object> value) { 971cb0ef41Sopenharmony_ci if (argc_ == nullptr) { 981cb0ef41Sopenharmony_ci Return(value); 991cb0ef41Sopenharmony_ci } else { 1001cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc()); 1011cb0ef41Sopenharmony_ci PopAndReturn(args.GetLengthWithReceiver(), value); 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci} 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::InitIteratingArrayBuiltinBody( 1061cb0ef41Sopenharmony_ci TNode<Context> context, TNode<Object> receiver, TNode<Object> callbackfn, 1071cb0ef41Sopenharmony_ci TNode<Object> this_arg, TNode<IntPtrT> argc) { 1081cb0ef41Sopenharmony_ci context_ = context; 1091cb0ef41Sopenharmony_ci receiver_ = receiver; 1101cb0ef41Sopenharmony_ci callbackfn_ = callbackfn; 1111cb0ef41Sopenharmony_ci this_arg_ = this_arg; 1121cb0ef41Sopenharmony_ci argc_ = argc; 1131cb0ef41Sopenharmony_ci} 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::GenerateIteratingTypedArrayBuiltinBody( 1161cb0ef41Sopenharmony_ci const char* name, const BuiltinResultGenerator& generator, 1171cb0ef41Sopenharmony_ci const CallResultProcessor& processor, ForEachDirection direction) { 1181cb0ef41Sopenharmony_ci name_ = name; 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci Label throw_not_typed_array(this, Label::kDeferred); 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array); 1251cb0ef41Sopenharmony_ci TNode<Map> typed_array_map = LoadMap(CAST(receiver_)); 1261cb0ef41Sopenharmony_ci GotoIfNot(IsJSTypedArrayMap(typed_array_map), &throw_not_typed_array); 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci TNode<JSTypedArray> typed_array = CAST(receiver_); 1291cb0ef41Sopenharmony_ci o_ = typed_array; 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci Label throw_detached(this, Label::kDeferred); 1321cb0ef41Sopenharmony_ci len_ = LoadJSTypedArrayLengthAndCheckDetached(typed_array, &throw_detached); 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci Label throw_not_callable(this, Label::kDeferred); 1351cb0ef41Sopenharmony_ci Label distinguish_types(this); 1361cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable); 1371cb0ef41Sopenharmony_ci Branch(IsCallableMap(LoadMap(CAST(callbackfn_))), &distinguish_types, 1381cb0ef41Sopenharmony_ci &throw_not_callable); 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci BIND(&throw_not_typed_array); 1411cb0ef41Sopenharmony_ci ThrowTypeError(context_, MessageTemplate::kNotTypedArray); 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci BIND(&throw_not_callable); 1441cb0ef41Sopenharmony_ci ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_); 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci BIND(&throw_detached); 1471cb0ef41Sopenharmony_ci ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_); 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci Label unexpected_instance_type(this); 1501cb0ef41Sopenharmony_ci BIND(&unexpected_instance_type); 1511cb0ef41Sopenharmony_ci Unreachable(); 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci std::vector<int32_t> elements_kinds = { 1541cb0ef41Sopenharmony_ci#define ELEMENTS_KIND(Type, type, TYPE, ctype) TYPE##_ELEMENTS, 1551cb0ef41Sopenharmony_ci TYPED_ARRAYS(ELEMENTS_KIND) RAB_GSAB_TYPED_ARRAYS(ELEMENTS_KIND) 1561cb0ef41Sopenharmony_ci#undef ELEMENTS_KIND 1571cb0ef41Sopenharmony_ci }; 1581cb0ef41Sopenharmony_ci std::list<Label> labels; 1591cb0ef41Sopenharmony_ci for (size_t i = 0; i < elements_kinds.size(); ++i) { 1601cb0ef41Sopenharmony_ci labels.emplace_back(this); 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci std::vector<Label*> label_ptrs; 1631cb0ef41Sopenharmony_ci for (Label& label : labels) { 1641cb0ef41Sopenharmony_ci label_ptrs.push_back(&label); 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci BIND(&distinguish_types); 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci generator(this); 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ci TNode<JSArrayBuffer> array_buffer = LoadJSArrayBufferViewBuffer(typed_array); 1721cb0ef41Sopenharmony_ci TNode<Int32T> elements_kind = LoadMapElementsKind(typed_array_map); 1731cb0ef41Sopenharmony_ci Switch(elements_kind, &unexpected_instance_type, elements_kinds.data(), 1741cb0ef41Sopenharmony_ci label_ptrs.data(), labels.size()); 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci size_t i = 0; 1771cb0ef41Sopenharmony_ci for (auto it = labels.begin(); it != labels.end(); ++i, ++it) { 1781cb0ef41Sopenharmony_ci BIND(&*it); 1791cb0ef41Sopenharmony_ci source_elements_kind_ = static_cast<ElementsKind>(elements_kinds[i]); 1801cb0ef41Sopenharmony_ci // TODO(v8:11111): Only RAB-backed TAs need special handling here since the 1811cb0ef41Sopenharmony_ci // backing store can shrink mid-iteration. This implementation has an 1821cb0ef41Sopenharmony_ci // overzealous check for GSAB-backed length-tracking TAs. Then again, the 1831cb0ef41Sopenharmony_ci // non-RAB/GSAB code also has an overzealous detached check for SABs. 1841cb0ef41Sopenharmony_ci bool is_rab_gsab = IsRabGsabTypedArrayElementsKind(source_elements_kind_); 1851cb0ef41Sopenharmony_ci if (is_rab_gsab) { 1861cb0ef41Sopenharmony_ci source_elements_kind_ = 1871cb0ef41Sopenharmony_ci GetCorrespondingNonRabGsabElementsKind(source_elements_kind_); 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci VisitAllTypedArrayElements(array_buffer, processor, direction, typed_array, 1901cb0ef41Sopenharmony_ci is_rab_gsab); 1911cb0ef41Sopenharmony_ci ReturnFromBuiltin(a_.value()); 1921cb0ef41Sopenharmony_ci } 1931cb0ef41Sopenharmony_ci} 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::VisitAllTypedArrayElements( 1961cb0ef41Sopenharmony_ci TNode<JSArrayBuffer> array_buffer, const CallResultProcessor& processor, 1971cb0ef41Sopenharmony_ci ForEachDirection direction, TNode<JSTypedArray> typed_array, 1981cb0ef41Sopenharmony_ci bool can_shrink) { 1991cb0ef41Sopenharmony_ci VariableList list({&a_, &k_}, zone()); 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci TNode<UintPtrT> start = UintPtrConstant(0); 2021cb0ef41Sopenharmony_ci TNode<UintPtrT> end = len_; 2031cb0ef41Sopenharmony_ci IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost; 2041cb0ef41Sopenharmony_ci int incr = 1; 2051cb0ef41Sopenharmony_ci if (direction == ForEachDirection::kReverse) { 2061cb0ef41Sopenharmony_ci std::swap(start, end); 2071cb0ef41Sopenharmony_ci advance_mode = IndexAdvanceMode::kPre; 2081cb0ef41Sopenharmony_ci incr = -1; 2091cb0ef41Sopenharmony_ci } 2101cb0ef41Sopenharmony_ci k_ = start; 2111cb0ef41Sopenharmony_ci BuildFastLoop<UintPtrT>( 2121cb0ef41Sopenharmony_ci list, start, end, 2131cb0ef41Sopenharmony_ci [&](TNode<UintPtrT> index) { 2141cb0ef41Sopenharmony_ci TVARIABLE(Object, value); 2151cb0ef41Sopenharmony_ci Label detached(this, Label::kDeferred); 2161cb0ef41Sopenharmony_ci Label process(this); 2171cb0ef41Sopenharmony_ci if (can_shrink) { 2181cb0ef41Sopenharmony_ci // If `index` is out of bounds, Get returns undefined. 2191cb0ef41Sopenharmony_ci CheckJSTypedArrayIndex(index, typed_array, &detached); 2201cb0ef41Sopenharmony_ci } else { 2211cb0ef41Sopenharmony_ci GotoIf(IsDetachedBuffer(array_buffer), &detached); 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci { 2241cb0ef41Sopenharmony_ci TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array); 2251cb0ef41Sopenharmony_ci value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, 2261cb0ef41Sopenharmony_ci source_elements_kind_); 2271cb0ef41Sopenharmony_ci Goto(&process); 2281cb0ef41Sopenharmony_ci } 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci BIND(&detached); 2311cb0ef41Sopenharmony_ci { 2321cb0ef41Sopenharmony_ci value = UndefinedConstant(); 2331cb0ef41Sopenharmony_ci Goto(&process); 2341cb0ef41Sopenharmony_ci } 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci BIND(&process); 2371cb0ef41Sopenharmony_ci { 2381cb0ef41Sopenharmony_ci k_ = index; 2391cb0ef41Sopenharmony_ci a_ = processor(this, value.value(), index); 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci }, 2421cb0ef41Sopenharmony_ci incr, advance_mode); 2431cb0ef41Sopenharmony_ci} 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayPrototypePop, CodeStubAssembler) { 2461cb0ef41Sopenharmony_ci auto argc = UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount); 2471cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 2481cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsUndefined(Parameter<Object>(Descriptor::kJSNewTarget))); 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc); 2511cb0ef41Sopenharmony_ci TNode<Object> receiver = args.GetReceiver(); 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci Label runtime(this, Label::kDeferred); 2541cb0ef41Sopenharmony_ci Label fast(this); 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_ci // Only pop in this stub if 2571cb0ef41Sopenharmony_ci // 1) the array has fast elements 2581cb0ef41Sopenharmony_ci // 2) the length is writable, 2591cb0ef41Sopenharmony_ci // 3) the elements backing store isn't copy-on-write, 2601cb0ef41Sopenharmony_ci // 4) we aren't supposed to shrink the backing store. 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_ci // 1) Check that the array has fast elements. 2631cb0ef41Sopenharmony_ci BranchIfFastJSArray(receiver, context, &fast, &runtime); 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci BIND(&fast); 2661cb0ef41Sopenharmony_ci { 2671cb0ef41Sopenharmony_ci TNode<JSArray> array_receiver = CAST(receiver); 2681cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver))); 2691cb0ef41Sopenharmony_ci TNode<IntPtrT> length = 2701cb0ef41Sopenharmony_ci LoadAndUntagObjectField(array_receiver, JSArray::kLengthOffset); 2711cb0ef41Sopenharmony_ci Label return_undefined(this), fast_elements(this); 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci // 2) Ensure that the length is writable. 2741cb0ef41Sopenharmony_ci EnsureArrayLengthWritable(context, LoadMap(array_receiver), &runtime); 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined); 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci // 3) Check that the elements backing store isn't copy-on-write. 2791cb0ef41Sopenharmony_ci TNode<FixedArrayBase> elements = LoadElements(array_receiver); 2801cb0ef41Sopenharmony_ci GotoIf(TaggedEqual(LoadMap(elements), FixedCOWArrayMapConstant()), 2811cb0ef41Sopenharmony_ci &runtime); 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ci TNode<IntPtrT> new_length = IntPtrSub(length, IntPtrConstant(1)); 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci // 4) Check that we're not supposed to shrink the backing store, as 2861cb0ef41Sopenharmony_ci // implemented in elements.cc:ElementsAccessorBase::SetLengthImpl. 2871cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity = SmiUntag(LoadFixedArrayBaseLength(elements)); 2881cb0ef41Sopenharmony_ci GotoIf(IntPtrLessThan( 2891cb0ef41Sopenharmony_ci IntPtrAdd(IntPtrAdd(new_length, new_length), 2901cb0ef41Sopenharmony_ci IntPtrConstant(JSObject::kMinAddedElementsCapacity)), 2911cb0ef41Sopenharmony_ci capacity), 2921cb0ef41Sopenharmony_ci &runtime); 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset, 2951cb0ef41Sopenharmony_ci SmiTag(new_length)); 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci TNode<Int32T> elements_kind = LoadElementsKind(array_receiver); 2981cb0ef41Sopenharmony_ci GotoIf(Int32LessThanOrEqual(elements_kind, 2991cb0ef41Sopenharmony_ci Int32Constant(TERMINAL_FAST_ELEMENTS_KIND)), 3001cb0ef41Sopenharmony_ci &fast_elements); 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci { 3031cb0ef41Sopenharmony_ci TNode<FixedDoubleArray> elements_known_double_array = 3041cb0ef41Sopenharmony_ci ReinterpretCast<FixedDoubleArray>(elements); 3051cb0ef41Sopenharmony_ci TNode<Float64T> value = LoadFixedDoubleArrayElement( 3061cb0ef41Sopenharmony_ci elements_known_double_array, new_length, &return_undefined); 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci StoreFixedDoubleArrayHole(elements_known_double_array, new_length); 3091cb0ef41Sopenharmony_ci args.PopAndReturn(AllocateHeapNumberWithValue(value)); 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci BIND(&fast_elements); 3131cb0ef41Sopenharmony_ci { 3141cb0ef41Sopenharmony_ci TNode<FixedArray> elements_known_fixed_array = CAST(elements); 3151cb0ef41Sopenharmony_ci TNode<Object> value = 3161cb0ef41Sopenharmony_ci LoadFixedArrayElement(elements_known_fixed_array, new_length); 3171cb0ef41Sopenharmony_ci StoreFixedArrayElement(elements_known_fixed_array, new_length, 3181cb0ef41Sopenharmony_ci TheHoleConstant()); 3191cb0ef41Sopenharmony_ci GotoIf(TaggedEqual(value, TheHoleConstant()), &return_undefined); 3201cb0ef41Sopenharmony_ci args.PopAndReturn(value); 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci BIND(&return_undefined); 3241cb0ef41Sopenharmony_ci { args.PopAndReturn(UndefinedConstant()); } 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_ci BIND(&runtime); 3281cb0ef41Sopenharmony_ci { 3291cb0ef41Sopenharmony_ci // We are not using Parameter(Descriptor::kJSTarget) and loading the value 3301cb0ef41Sopenharmony_ci // from the current frame here in order to reduce register pressure on the 3311cb0ef41Sopenharmony_ci // fast path. 3321cb0ef41Sopenharmony_ci TNode<JSFunction> target = LoadTargetFromFrame(); 3331cb0ef41Sopenharmony_ci TailCallBuiltin(Builtin::kArrayPop, context, target, UndefinedConstant(), 3341cb0ef41Sopenharmony_ci argc); 3351cb0ef41Sopenharmony_ci } 3361cb0ef41Sopenharmony_ci} 3371cb0ef41Sopenharmony_ci 3381cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) { 3391cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, arg_index); 3401cb0ef41Sopenharmony_ci Label default_label(this, &arg_index); 3411cb0ef41Sopenharmony_ci Label smi_transition(this); 3421cb0ef41Sopenharmony_ci Label object_push_pre(this); 3431cb0ef41Sopenharmony_ci Label object_push(this, &arg_index); 3441cb0ef41Sopenharmony_ci Label double_push(this, &arg_index); 3451cb0ef41Sopenharmony_ci Label double_transition(this); 3461cb0ef41Sopenharmony_ci Label runtime(this, Label::kDeferred); 3471cb0ef41Sopenharmony_ci 3481cb0ef41Sopenharmony_ci auto argc = UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount); 3491cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 3501cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsUndefined(Parameter<Object>(Descriptor::kJSNewTarget))); 3511cb0ef41Sopenharmony_ci 3521cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc); 3531cb0ef41Sopenharmony_ci TNode<Object> receiver = args.GetReceiver(); 3541cb0ef41Sopenharmony_ci TNode<JSArray> array_receiver; 3551cb0ef41Sopenharmony_ci TNode<Int32T> kind; 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci Label fast(this); 3581cb0ef41Sopenharmony_ci BranchIfFastJSArray(receiver, context, &fast, &runtime); 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci BIND(&fast); 3611cb0ef41Sopenharmony_ci { 3621cb0ef41Sopenharmony_ci array_receiver = CAST(receiver); 3631cb0ef41Sopenharmony_ci arg_index = IntPtrConstant(0); 3641cb0ef41Sopenharmony_ci kind = EnsureArrayPushable(context, LoadMap(array_receiver), &runtime); 3651cb0ef41Sopenharmony_ci GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS), 3661cb0ef41Sopenharmony_ci &object_push_pre); 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_ci TNode<Smi> new_length = 3691cb0ef41Sopenharmony_ci BuildAppendJSArray(PACKED_SMI_ELEMENTS, array_receiver, &args, 3701cb0ef41Sopenharmony_ci &arg_index, &smi_transition); 3711cb0ef41Sopenharmony_ci args.PopAndReturn(new_length); 3721cb0ef41Sopenharmony_ci } 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci // If the argument is not a smi, then use a heavyweight SetProperty to 3751cb0ef41Sopenharmony_ci // transition the array for only the single next element. If the argument is 3761cb0ef41Sopenharmony_ci // a smi, the failure is due to some other reason and we should fall back on 3771cb0ef41Sopenharmony_ci // the most generic implementation for the rest of the array. 3781cb0ef41Sopenharmony_ci BIND(&smi_transition); 3791cb0ef41Sopenharmony_ci { 3801cb0ef41Sopenharmony_ci TNode<Object> arg = args.AtIndex(arg_index.value()); 3811cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(arg), &default_label); 3821cb0ef41Sopenharmony_ci TNode<Number> length = LoadJSArrayLength(array_receiver); 3831cb0ef41Sopenharmony_ci // TODO(danno): Use the KeyedStoreGeneric stub here when possible, 3841cb0ef41Sopenharmony_ci // calling into the runtime to do the elements transition is overkill. 3851cb0ef41Sopenharmony_ci SetPropertyStrict(context, array_receiver, length, arg); 3861cb0ef41Sopenharmony_ci Increment(&arg_index); 3871cb0ef41Sopenharmony_ci // The runtime SetProperty call could have converted the array to dictionary 3881cb0ef41Sopenharmony_ci // mode, which must be detected to abort the fast-path. 3891cb0ef41Sopenharmony_ci TNode<Int32T> elements_kind = LoadElementsKind(array_receiver); 3901cb0ef41Sopenharmony_ci GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)), 3911cb0ef41Sopenharmony_ci &default_label); 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci GotoIfNotNumber(arg, &object_push); 3941cb0ef41Sopenharmony_ci Goto(&double_push); 3951cb0ef41Sopenharmony_ci } 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci BIND(&object_push_pre); 3981cb0ef41Sopenharmony_ci { 3991cb0ef41Sopenharmony_ci Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push, 4001cb0ef41Sopenharmony_ci &object_push); 4011cb0ef41Sopenharmony_ci } 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_ci BIND(&object_push); 4041cb0ef41Sopenharmony_ci { 4051cb0ef41Sopenharmony_ci TNode<Smi> new_length = BuildAppendJSArray( 4061cb0ef41Sopenharmony_ci PACKED_ELEMENTS, array_receiver, &args, &arg_index, &default_label); 4071cb0ef41Sopenharmony_ci args.PopAndReturn(new_length); 4081cb0ef41Sopenharmony_ci } 4091cb0ef41Sopenharmony_ci 4101cb0ef41Sopenharmony_ci BIND(&double_push); 4111cb0ef41Sopenharmony_ci { 4121cb0ef41Sopenharmony_ci TNode<Smi> new_length = 4131cb0ef41Sopenharmony_ci BuildAppendJSArray(PACKED_DOUBLE_ELEMENTS, array_receiver, &args, 4141cb0ef41Sopenharmony_ci &arg_index, &double_transition); 4151cb0ef41Sopenharmony_ci args.PopAndReturn(new_length); 4161cb0ef41Sopenharmony_ci } 4171cb0ef41Sopenharmony_ci 4181cb0ef41Sopenharmony_ci // If the argument is not a double, then use a heavyweight SetProperty to 4191cb0ef41Sopenharmony_ci // transition the array for only the single next element. If the argument is 4201cb0ef41Sopenharmony_ci // a double, the failure is due to some other reason and we should fall back 4211cb0ef41Sopenharmony_ci // on the most generic implementation for the rest of the array. 4221cb0ef41Sopenharmony_ci BIND(&double_transition); 4231cb0ef41Sopenharmony_ci { 4241cb0ef41Sopenharmony_ci TNode<Object> arg = args.AtIndex(arg_index.value()); 4251cb0ef41Sopenharmony_ci GotoIfNumber(arg, &default_label); 4261cb0ef41Sopenharmony_ci TNode<Number> length = LoadJSArrayLength(array_receiver); 4271cb0ef41Sopenharmony_ci // TODO(danno): Use the KeyedStoreGeneric stub here when possible, 4281cb0ef41Sopenharmony_ci // calling into the runtime to do the elements transition is overkill. 4291cb0ef41Sopenharmony_ci SetPropertyStrict(context, array_receiver, length, arg); 4301cb0ef41Sopenharmony_ci Increment(&arg_index); 4311cb0ef41Sopenharmony_ci // The runtime SetProperty call could have converted the array to dictionary 4321cb0ef41Sopenharmony_ci // mode, which must be detected to abort the fast-path. 4331cb0ef41Sopenharmony_ci TNode<Int32T> elements_kind = LoadElementsKind(array_receiver); 4341cb0ef41Sopenharmony_ci GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)), 4351cb0ef41Sopenharmony_ci &default_label); 4361cb0ef41Sopenharmony_ci Goto(&object_push); 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci // Fallback that stores un-processed arguments using the full, heavyweight 4401cb0ef41Sopenharmony_ci // SetProperty machinery. 4411cb0ef41Sopenharmony_ci BIND(&default_label); 4421cb0ef41Sopenharmony_ci { 4431cb0ef41Sopenharmony_ci args.ForEach( 4441cb0ef41Sopenharmony_ci [=](TNode<Object> arg) { 4451cb0ef41Sopenharmony_ci TNode<Number> length = LoadJSArrayLength(array_receiver); 4461cb0ef41Sopenharmony_ci SetPropertyStrict(context, array_receiver, length, arg); 4471cb0ef41Sopenharmony_ci }, 4481cb0ef41Sopenharmony_ci arg_index.value()); 4491cb0ef41Sopenharmony_ci args.PopAndReturn(LoadJSArrayLength(array_receiver)); 4501cb0ef41Sopenharmony_ci } 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_ci BIND(&runtime); 4531cb0ef41Sopenharmony_ci { 4541cb0ef41Sopenharmony_ci // We are not using Parameter(Descriptor::kJSTarget) and loading the value 4551cb0ef41Sopenharmony_ci // from the current frame here in order to reduce register pressure on the 4561cb0ef41Sopenharmony_ci // fast path. 4571cb0ef41Sopenharmony_ci TNode<JSFunction> target = LoadTargetFromFrame(); 4581cb0ef41Sopenharmony_ci TailCallBuiltin(Builtin::kArrayPush, context, target, UndefinedConstant(), 4591cb0ef41Sopenharmony_ci argc); 4601cb0ef41Sopenharmony_ci } 4611cb0ef41Sopenharmony_ci} 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ciTF_BUILTIN(ExtractFastJSArray, ArrayBuiltinsAssembler) { 4641cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 4651cb0ef41Sopenharmony_ci auto array = Parameter<JSArray>(Descriptor::kSource); 4661cb0ef41Sopenharmony_ci TNode<BInt> begin = SmiToBInt(Parameter<Smi>(Descriptor::kBegin)); 4671cb0ef41Sopenharmony_ci TNode<BInt> count = SmiToBInt(Parameter<Smi>(Descriptor::kCount)); 4681cb0ef41Sopenharmony_ci 4691cb0ef41Sopenharmony_ci CSA_DCHECK(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid())); 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ci Return(ExtractFastJSArray(context, array, begin, count)); 4721cb0ef41Sopenharmony_ci} 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ciTF_BUILTIN(CloneFastJSArray, ArrayBuiltinsAssembler) { 4751cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 4761cb0ef41Sopenharmony_ci auto array = Parameter<JSArray>(Descriptor::kSource); 4771cb0ef41Sopenharmony_ci 4781cb0ef41Sopenharmony_ci CSA_DCHECK(this, 4791cb0ef41Sopenharmony_ci Word32Or(Word32BinaryNot(IsHoleyFastElementsKindForRead( 4801cb0ef41Sopenharmony_ci LoadElementsKind(array))), 4811cb0ef41Sopenharmony_ci Word32BinaryNot(IsNoElementsProtectorCellInvalid()))); 4821cb0ef41Sopenharmony_ci 4831cb0ef41Sopenharmony_ci Return(CloneFastJSArray(context, array)); 4841cb0ef41Sopenharmony_ci} 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci// This builtin copies the backing store of fast arrays, while converting any 4871cb0ef41Sopenharmony_ci// holes to undefined. 4881cb0ef41Sopenharmony_ci// - If there are no holes in the source, its ElementsKind will be preserved. In 4891cb0ef41Sopenharmony_ci// that case, this builtin should perform as fast as CloneFastJSArray. (In fact, 4901cb0ef41Sopenharmony_ci// for fast packed arrays, the behavior is equivalent to CloneFastJSArray.) 4911cb0ef41Sopenharmony_ci// - If there are holes in the source, the ElementsKind of the "copy" will be 4921cb0ef41Sopenharmony_ci// PACKED_ELEMENTS (such that undefined can be stored). 4931cb0ef41Sopenharmony_ciTF_BUILTIN(CloneFastJSArrayFillingHoles, ArrayBuiltinsAssembler) { 4941cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 4951cb0ef41Sopenharmony_ci auto array = Parameter<JSArray>(Descriptor::kSource); 4961cb0ef41Sopenharmony_ci 4971cb0ef41Sopenharmony_ci CSA_DCHECK(this, 4981cb0ef41Sopenharmony_ci Word32Or(Word32BinaryNot(IsHoleyFastElementsKindForRead( 4991cb0ef41Sopenharmony_ci LoadElementsKind(array))), 5001cb0ef41Sopenharmony_ci Word32BinaryNot(IsNoElementsProtectorCellInvalid()))); 5011cb0ef41Sopenharmony_ci 5021cb0ef41Sopenharmony_ci Return(CloneFastJSArray(context, array, base::nullopt, 5031cb0ef41Sopenharmony_ci HoleConversionMode::kConvertToUndefined)); 5041cb0ef41Sopenharmony_ci} 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ciclass ArrayPopulatorAssembler : public CodeStubAssembler { 5071cb0ef41Sopenharmony_ci public: 5081cb0ef41Sopenharmony_ci explicit ArrayPopulatorAssembler(compiler::CodeAssemblerState* state) 5091cb0ef41Sopenharmony_ci : CodeStubAssembler(state) {} 5101cb0ef41Sopenharmony_ci 5111cb0ef41Sopenharmony_ci TNode<Object> ConstructArrayLike(TNode<Context> context, 5121cb0ef41Sopenharmony_ci TNode<Object> receiver) { 5131cb0ef41Sopenharmony_ci TVARIABLE(Object, array); 5141cb0ef41Sopenharmony_ci Label is_constructor(this), is_not_constructor(this), done(this); 5151cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(receiver), &is_not_constructor); 5161cb0ef41Sopenharmony_ci Branch(IsConstructor(CAST(receiver)), &is_constructor, &is_not_constructor); 5171cb0ef41Sopenharmony_ci 5181cb0ef41Sopenharmony_ci BIND(&is_constructor); 5191cb0ef41Sopenharmony_ci { 5201cb0ef41Sopenharmony_ci array = Construct(context, CAST(receiver)); 5211cb0ef41Sopenharmony_ci Goto(&done); 5221cb0ef41Sopenharmony_ci } 5231cb0ef41Sopenharmony_ci 5241cb0ef41Sopenharmony_ci BIND(&is_not_constructor); 5251cb0ef41Sopenharmony_ci { 5261cb0ef41Sopenharmony_ci Label allocate_js_array(this); 5271cb0ef41Sopenharmony_ci 5281cb0ef41Sopenharmony_ci TNode<Map> array_map = CAST(LoadContextElement( 5291cb0ef41Sopenharmony_ci context, Context::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX)); 5301cb0ef41Sopenharmony_ci 5311cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity = IntPtrConstant(0); 5321cb0ef41Sopenharmony_ci TNode<Smi> length = SmiConstant(0); 5331cb0ef41Sopenharmony_ci array = AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, capacity, length); 5341cb0ef41Sopenharmony_ci Goto(&done); 5351cb0ef41Sopenharmony_ci } 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_ci BIND(&done); 5381cb0ef41Sopenharmony_ci return array.value(); 5391cb0ef41Sopenharmony_ci } 5401cb0ef41Sopenharmony_ci 5411cb0ef41Sopenharmony_ci TNode<Object> ConstructArrayLike(TNode<Context> context, 5421cb0ef41Sopenharmony_ci TNode<Object> receiver, 5431cb0ef41Sopenharmony_ci TNode<Number> length) { 5441cb0ef41Sopenharmony_ci TVARIABLE(Object, array); 5451cb0ef41Sopenharmony_ci Label is_constructor(this), is_not_constructor(this), done(this); 5461cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberNormalized(length)); 5471cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(receiver), &is_not_constructor); 5481cb0ef41Sopenharmony_ci Branch(IsConstructor(CAST(receiver)), &is_constructor, &is_not_constructor); 5491cb0ef41Sopenharmony_ci 5501cb0ef41Sopenharmony_ci BIND(&is_constructor); 5511cb0ef41Sopenharmony_ci { 5521cb0ef41Sopenharmony_ci array = Construct(context, CAST(receiver), length); 5531cb0ef41Sopenharmony_ci Goto(&done); 5541cb0ef41Sopenharmony_ci } 5551cb0ef41Sopenharmony_ci 5561cb0ef41Sopenharmony_ci BIND(&is_not_constructor); 5571cb0ef41Sopenharmony_ci { 5581cb0ef41Sopenharmony_ci array = ArrayCreate(context, length); 5591cb0ef41Sopenharmony_ci Goto(&done); 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci 5621cb0ef41Sopenharmony_ci BIND(&done); 5631cb0ef41Sopenharmony_ci return array.value(); 5641cb0ef41Sopenharmony_ci } 5651cb0ef41Sopenharmony_ci}; 5661cb0ef41Sopenharmony_ci 5671cb0ef41Sopenharmony_ciTF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) { 5681cb0ef41Sopenharmony_ci TNode<IntPtrT> argc = ChangeInt32ToIntPtr( 5691cb0ef41Sopenharmony_ci UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount)); 5701cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc); 5711cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 5721cb0ef41Sopenharmony_ci TNode<Object> receiver = args.GetReceiver(); 5731cb0ef41Sopenharmony_ci TNode<Object> callbackfn = args.GetOptionalArgumentValue(0); 5741cb0ef41Sopenharmony_ci TNode<Object> this_arg = args.GetOptionalArgumentValue(1); 5751cb0ef41Sopenharmony_ci 5761cb0ef41Sopenharmony_ci InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc); 5771cb0ef41Sopenharmony_ci 5781cb0ef41Sopenharmony_ci GenerateIteratingTypedArrayBuiltinBody( 5791cb0ef41Sopenharmony_ci "%TypedArray%.prototype.map", 5801cb0ef41Sopenharmony_ci &ArrayBuiltinsAssembler::TypedArrayMapResultGenerator, 5811cb0ef41Sopenharmony_ci &ArrayBuiltinsAssembler::TypedArrayMapProcessor); 5821cb0ef41Sopenharmony_ci} 5831cb0ef41Sopenharmony_ci 5841cb0ef41Sopenharmony_ciclass ArrayIncludesIndexofAssembler : public CodeStubAssembler { 5851cb0ef41Sopenharmony_ci public: 5861cb0ef41Sopenharmony_ci explicit ArrayIncludesIndexofAssembler(compiler::CodeAssemblerState* state) 5871cb0ef41Sopenharmony_ci : CodeStubAssembler(state) {} 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ci enum SearchVariant { kIncludes, kIndexOf }; 5901cb0ef41Sopenharmony_ci 5911cb0ef41Sopenharmony_ci void Generate(SearchVariant variant, TNode<IntPtrT> argc, 5921cb0ef41Sopenharmony_ci TNode<Context> context); 5931cb0ef41Sopenharmony_ci void GenerateSmiOrObject(SearchVariant variant, TNode<Context> context, 5941cb0ef41Sopenharmony_ci TNode<FixedArray> elements, 5951cb0ef41Sopenharmony_ci TNode<Object> search_element, 5961cb0ef41Sopenharmony_ci TNode<Smi> array_length, TNode<Smi> from_index); 5971cb0ef41Sopenharmony_ci void GeneratePackedDoubles(SearchVariant variant, 5981cb0ef41Sopenharmony_ci TNode<FixedDoubleArray> elements, 5991cb0ef41Sopenharmony_ci TNode<Object> search_element, 6001cb0ef41Sopenharmony_ci TNode<Smi> array_length, TNode<Smi> from_index); 6011cb0ef41Sopenharmony_ci void GenerateHoleyDoubles(SearchVariant variant, 6021cb0ef41Sopenharmony_ci TNode<FixedDoubleArray> elements, 6031cb0ef41Sopenharmony_ci TNode<Object> search_element, 6041cb0ef41Sopenharmony_ci TNode<Smi> array_length, TNode<Smi> from_index); 6051cb0ef41Sopenharmony_ci 6061cb0ef41Sopenharmony_ci void ReturnIfEmpty(TNode<Smi> length, TNode<Object> value) { 6071cb0ef41Sopenharmony_ci Label done(this); 6081cb0ef41Sopenharmony_ci GotoIf(SmiGreaterThan(length, SmiConstant(0)), &done); 6091cb0ef41Sopenharmony_ci Return(value); 6101cb0ef41Sopenharmony_ci BIND(&done); 6111cb0ef41Sopenharmony_ci } 6121cb0ef41Sopenharmony_ci}; 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_civoid ArrayIncludesIndexofAssembler::Generate(SearchVariant variant, 6151cb0ef41Sopenharmony_ci TNode<IntPtrT> argc, 6161cb0ef41Sopenharmony_ci TNode<Context> context) { 6171cb0ef41Sopenharmony_ci const int kSearchElementArg = 0; 6181cb0ef41Sopenharmony_ci const int kFromIndexArg = 1; 6191cb0ef41Sopenharmony_ci 6201cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc); 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ci TNode<Object> receiver = args.GetReceiver(); 6231cb0ef41Sopenharmony_ci TNode<Object> search_element = 6241cb0ef41Sopenharmony_ci args.GetOptionalArgumentValue(kSearchElementArg); 6251cb0ef41Sopenharmony_ci 6261cb0ef41Sopenharmony_ci TNode<IntPtrT> intptr_zero = IntPtrConstant(0); 6271cb0ef41Sopenharmony_ci 6281cb0ef41Sopenharmony_ci Label init_index(this), return_not_found(this), call_runtime(this); 6291cb0ef41Sopenharmony_ci 6301cb0ef41Sopenharmony_ci // Take slow path if not a JSArray, if retrieving elements requires 6311cb0ef41Sopenharmony_ci // traversing prototype, or if access checks are required. 6321cb0ef41Sopenharmony_ci BranchIfFastJSArrayForRead(receiver, context, &init_index, &call_runtime); 6331cb0ef41Sopenharmony_ci 6341cb0ef41Sopenharmony_ci BIND(&init_index); 6351cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, index_var, intptr_zero); 6361cb0ef41Sopenharmony_ci TNode<JSArray> array = CAST(receiver); 6371cb0ef41Sopenharmony_ci 6381cb0ef41Sopenharmony_ci // JSArray length is always a positive Smi for fast arrays. 6391cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedIsPositiveSmi(LoadJSArrayLength(array))); 6401cb0ef41Sopenharmony_ci TNode<Smi> array_length = LoadFastJSArrayLength(array); 6411cb0ef41Sopenharmony_ci TNode<IntPtrT> array_length_untagged = SmiUntag(array_length); 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ci { 6441cb0ef41Sopenharmony_ci // Initialize fromIndex. 6451cb0ef41Sopenharmony_ci Label is_smi(this), is_nonsmi(this), done(this); 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci // If no fromIndex was passed, default to 0. 6481cb0ef41Sopenharmony_ci GotoIf(IntPtrLessThanOrEqual(args.GetLengthWithoutReceiver(), 6491cb0ef41Sopenharmony_ci IntPtrConstant(kFromIndexArg)), 6501cb0ef41Sopenharmony_ci &done); 6511cb0ef41Sopenharmony_ci 6521cb0ef41Sopenharmony_ci TNode<Object> start_from = args.AtIndex(kFromIndexArg); 6531cb0ef41Sopenharmony_ci // Handle Smis and undefined here and everything else in runtime. 6541cb0ef41Sopenharmony_ci // We must be very careful with side effects from the ToInteger conversion, 6551cb0ef41Sopenharmony_ci // as the side effects might render previously checked assumptions about 6561cb0ef41Sopenharmony_ci // the receiver being a fast JSArray and its length invalid. 6571cb0ef41Sopenharmony_ci Branch(TaggedIsSmi(start_from), &is_smi, &is_nonsmi); 6581cb0ef41Sopenharmony_ci 6591cb0ef41Sopenharmony_ci BIND(&is_nonsmi); 6601cb0ef41Sopenharmony_ci { 6611cb0ef41Sopenharmony_ci GotoIfNot(IsUndefined(start_from), &call_runtime); 6621cb0ef41Sopenharmony_ci Goto(&done); 6631cb0ef41Sopenharmony_ci } 6641cb0ef41Sopenharmony_ci BIND(&is_smi); 6651cb0ef41Sopenharmony_ci { 6661cb0ef41Sopenharmony_ci TNode<IntPtrT> intptr_start_from = SmiUntag(CAST(start_from)); 6671cb0ef41Sopenharmony_ci index_var = intptr_start_from; 6681cb0ef41Sopenharmony_ci 6691cb0ef41Sopenharmony_ci GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done); 6701cb0ef41Sopenharmony_ci // The fromIndex is negative: add it to the array's length. 6711cb0ef41Sopenharmony_ci index_var = IntPtrAdd(array_length_untagged, index_var.value()); 6721cb0ef41Sopenharmony_ci // Clamp negative results at zero. 6731cb0ef41Sopenharmony_ci GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done); 6741cb0ef41Sopenharmony_ci index_var = intptr_zero; 6751cb0ef41Sopenharmony_ci Goto(&done); 6761cb0ef41Sopenharmony_ci } 6771cb0ef41Sopenharmony_ci BIND(&done); 6781cb0ef41Sopenharmony_ci } 6791cb0ef41Sopenharmony_ci 6801cb0ef41Sopenharmony_ci // Fail early if startIndex >= array.length. 6811cb0ef41Sopenharmony_ci GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), array_length_untagged), 6821cb0ef41Sopenharmony_ci &return_not_found); 6831cb0ef41Sopenharmony_ci 6841cb0ef41Sopenharmony_ci Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this); 6851cb0ef41Sopenharmony_ci 6861cb0ef41Sopenharmony_ci TNode<Int32T> elements_kind = LoadElementsKind(array); 6871cb0ef41Sopenharmony_ci TNode<FixedArrayBase> elements = LoadElements(array); 6881cb0ef41Sopenharmony_ci STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0); 6891cb0ef41Sopenharmony_ci STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1); 6901cb0ef41Sopenharmony_ci STATIC_ASSERT(PACKED_ELEMENTS == 2); 6911cb0ef41Sopenharmony_ci STATIC_ASSERT(HOLEY_ELEMENTS == 3); 6921cb0ef41Sopenharmony_ci GotoIf(IsElementsKindLessThanOrEqual(elements_kind, HOLEY_ELEMENTS), 6931cb0ef41Sopenharmony_ci &if_smiorobjects); 6941cb0ef41Sopenharmony_ci GotoIf( 6951cb0ef41Sopenharmony_ci ElementsKindEqual(elements_kind, Int32Constant(PACKED_DOUBLE_ELEMENTS)), 6961cb0ef41Sopenharmony_ci &if_packed_doubles); 6971cb0ef41Sopenharmony_ci GotoIf(ElementsKindEqual(elements_kind, Int32Constant(HOLEY_DOUBLE_ELEMENTS)), 6981cb0ef41Sopenharmony_ci &if_holey_doubles); 6991cb0ef41Sopenharmony_ci GotoIf(IsElementsKindLessThanOrEqual(elements_kind, 7001cb0ef41Sopenharmony_ci LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND), 7011cb0ef41Sopenharmony_ci &if_smiorobjects); 7021cb0ef41Sopenharmony_ci Goto(&return_not_found); 7031cb0ef41Sopenharmony_ci 7041cb0ef41Sopenharmony_ci BIND(&if_smiorobjects); 7051cb0ef41Sopenharmony_ci { 7061cb0ef41Sopenharmony_ci Callable callable = (variant == kIncludes) 7071cb0ef41Sopenharmony_ci ? Builtins::CallableFor( 7081cb0ef41Sopenharmony_ci isolate(), Builtin::kArrayIncludesSmiOrObject) 7091cb0ef41Sopenharmony_ci : Builtins::CallableFor( 7101cb0ef41Sopenharmony_ci isolate(), Builtin::kArrayIndexOfSmiOrObject); 7111cb0ef41Sopenharmony_ci TNode<Object> result = CallStub(callable, context, elements, search_element, 7121cb0ef41Sopenharmony_ci array_length, SmiTag(index_var.value())); 7131cb0ef41Sopenharmony_ci args.PopAndReturn(result); 7141cb0ef41Sopenharmony_ci } 7151cb0ef41Sopenharmony_ci 7161cb0ef41Sopenharmony_ci BIND(&if_packed_doubles); 7171cb0ef41Sopenharmony_ci { 7181cb0ef41Sopenharmony_ci Callable callable = 7191cb0ef41Sopenharmony_ci (variant == kIncludes) 7201cb0ef41Sopenharmony_ci ? Builtins::CallableFor(isolate(), 7211cb0ef41Sopenharmony_ci Builtin::kArrayIncludesPackedDoubles) 7221cb0ef41Sopenharmony_ci : Builtins::CallableFor(isolate(), 7231cb0ef41Sopenharmony_ci Builtin::kArrayIndexOfPackedDoubles); 7241cb0ef41Sopenharmony_ci TNode<Object> result = CallStub(callable, context, elements, search_element, 7251cb0ef41Sopenharmony_ci array_length, SmiTag(index_var.value())); 7261cb0ef41Sopenharmony_ci args.PopAndReturn(result); 7271cb0ef41Sopenharmony_ci } 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_ci BIND(&if_holey_doubles); 7301cb0ef41Sopenharmony_ci { 7311cb0ef41Sopenharmony_ci Callable callable = 7321cb0ef41Sopenharmony_ci (variant == kIncludes) 7331cb0ef41Sopenharmony_ci ? Builtins::CallableFor(isolate(), 7341cb0ef41Sopenharmony_ci Builtin::kArrayIncludesHoleyDoubles) 7351cb0ef41Sopenharmony_ci : Builtins::CallableFor(isolate(), 7361cb0ef41Sopenharmony_ci Builtin::kArrayIndexOfHoleyDoubles); 7371cb0ef41Sopenharmony_ci TNode<Object> result = CallStub(callable, context, elements, search_element, 7381cb0ef41Sopenharmony_ci array_length, SmiTag(index_var.value())); 7391cb0ef41Sopenharmony_ci args.PopAndReturn(result); 7401cb0ef41Sopenharmony_ci } 7411cb0ef41Sopenharmony_ci 7421cb0ef41Sopenharmony_ci BIND(&return_not_found); 7431cb0ef41Sopenharmony_ci if (variant == kIncludes) { 7441cb0ef41Sopenharmony_ci args.PopAndReturn(FalseConstant()); 7451cb0ef41Sopenharmony_ci } else { 7461cb0ef41Sopenharmony_ci args.PopAndReturn(NumberConstant(-1)); 7471cb0ef41Sopenharmony_ci } 7481cb0ef41Sopenharmony_ci 7491cb0ef41Sopenharmony_ci BIND(&call_runtime); 7501cb0ef41Sopenharmony_ci { 7511cb0ef41Sopenharmony_ci TNode<Object> start_from = args.GetOptionalArgumentValue(kFromIndexArg); 7521cb0ef41Sopenharmony_ci Runtime::FunctionId function = variant == kIncludes 7531cb0ef41Sopenharmony_ci ? Runtime::kArrayIncludes_Slow 7541cb0ef41Sopenharmony_ci : Runtime::kArrayIndexOf; 7551cb0ef41Sopenharmony_ci args.PopAndReturn( 7561cb0ef41Sopenharmony_ci CallRuntime(function, context, array, search_element, start_from)); 7571cb0ef41Sopenharmony_ci } 7581cb0ef41Sopenharmony_ci} 7591cb0ef41Sopenharmony_ci 7601cb0ef41Sopenharmony_civoid ArrayIncludesIndexofAssembler::GenerateSmiOrObject( 7611cb0ef41Sopenharmony_ci SearchVariant variant, TNode<Context> context, TNode<FixedArray> elements, 7621cb0ef41Sopenharmony_ci TNode<Object> search_element, TNode<Smi> array_length, 7631cb0ef41Sopenharmony_ci TNode<Smi> from_index) { 7641cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, index_var, SmiUntag(from_index)); 7651cb0ef41Sopenharmony_ci TVARIABLE(Float64T, search_num); 7661cb0ef41Sopenharmony_ci TNode<IntPtrT> array_length_untagged = SmiUntag(array_length); 7671cb0ef41Sopenharmony_ci 7681cb0ef41Sopenharmony_ci Label ident_loop(this, &index_var), heap_num_loop(this, &search_num), 7691cb0ef41Sopenharmony_ci string_loop(this), bigint_loop(this, &index_var), 7701cb0ef41Sopenharmony_ci undef_loop(this, &index_var), not_smi(this), not_heap_num(this), 7711cb0ef41Sopenharmony_ci return_found(this), return_not_found(this); 7721cb0ef41Sopenharmony_ci 7731cb0ef41Sopenharmony_ci GotoIfNot(TaggedIsSmi(search_element), ¬_smi); 7741cb0ef41Sopenharmony_ci search_num = SmiToFloat64(CAST(search_element)); 7751cb0ef41Sopenharmony_ci Goto(&heap_num_loop); 7761cb0ef41Sopenharmony_ci 7771cb0ef41Sopenharmony_ci BIND(¬_smi); 7781cb0ef41Sopenharmony_ci if (variant == kIncludes) { 7791cb0ef41Sopenharmony_ci GotoIf(IsUndefined(search_element), &undef_loop); 7801cb0ef41Sopenharmony_ci } 7811cb0ef41Sopenharmony_ci TNode<Map> map = LoadMap(CAST(search_element)); 7821cb0ef41Sopenharmony_ci GotoIfNot(IsHeapNumberMap(map), ¬_heap_num); 7831cb0ef41Sopenharmony_ci search_num = LoadHeapNumberValue(CAST(search_element)); 7841cb0ef41Sopenharmony_ci Goto(&heap_num_loop); 7851cb0ef41Sopenharmony_ci 7861cb0ef41Sopenharmony_ci BIND(¬_heap_num); 7871cb0ef41Sopenharmony_ci TNode<Uint16T> search_type = LoadMapInstanceType(map); 7881cb0ef41Sopenharmony_ci GotoIf(IsStringInstanceType(search_type), &string_loop); 7891cb0ef41Sopenharmony_ci GotoIf(IsBigIntInstanceType(search_type), &bigint_loop); 7901cb0ef41Sopenharmony_ci Goto(&ident_loop); 7911cb0ef41Sopenharmony_ci 7921cb0ef41Sopenharmony_ci BIND(&ident_loop); 7931cb0ef41Sopenharmony_ci { 7941cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 7951cb0ef41Sopenharmony_ci &return_not_found); 7961cb0ef41Sopenharmony_ci TNode<Object> element_k = 7971cb0ef41Sopenharmony_ci UnsafeLoadFixedArrayElement(elements, index_var.value()); 7981cb0ef41Sopenharmony_ci GotoIf(TaggedEqual(element_k, search_element), &return_found); 7991cb0ef41Sopenharmony_ci 8001cb0ef41Sopenharmony_ci Increment(&index_var); 8011cb0ef41Sopenharmony_ci Goto(&ident_loop); 8021cb0ef41Sopenharmony_ci } 8031cb0ef41Sopenharmony_ci 8041cb0ef41Sopenharmony_ci if (variant == kIncludes) { 8051cb0ef41Sopenharmony_ci BIND(&undef_loop); 8061cb0ef41Sopenharmony_ci 8071cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 8081cb0ef41Sopenharmony_ci &return_not_found); 8091cb0ef41Sopenharmony_ci TNode<Object> element_k = 8101cb0ef41Sopenharmony_ci UnsafeLoadFixedArrayElement(elements, index_var.value()); 8111cb0ef41Sopenharmony_ci GotoIf(IsUndefined(element_k), &return_found); 8121cb0ef41Sopenharmony_ci GotoIf(IsTheHole(element_k), &return_found); 8131cb0ef41Sopenharmony_ci 8141cb0ef41Sopenharmony_ci Increment(&index_var); 8151cb0ef41Sopenharmony_ci Goto(&undef_loop); 8161cb0ef41Sopenharmony_ci } 8171cb0ef41Sopenharmony_ci 8181cb0ef41Sopenharmony_ci BIND(&heap_num_loop); 8191cb0ef41Sopenharmony_ci { 8201cb0ef41Sopenharmony_ci Label nan_loop(this, &index_var), not_nan_loop(this, &index_var); 8211cb0ef41Sopenharmony_ci Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found; 8221cb0ef41Sopenharmony_ci BranchIfFloat64IsNaN(search_num.value(), nan_handling, ¬_nan_loop); 8231cb0ef41Sopenharmony_ci 8241cb0ef41Sopenharmony_ci BIND(¬_nan_loop); 8251cb0ef41Sopenharmony_ci { 8261cb0ef41Sopenharmony_ci Label continue_loop(this), element_k_not_smi(this); 8271cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 8281cb0ef41Sopenharmony_ci &return_not_found); 8291cb0ef41Sopenharmony_ci TNode<Object> element_k = 8301cb0ef41Sopenharmony_ci UnsafeLoadFixedArrayElement(elements, index_var.value()); 8311cb0ef41Sopenharmony_ci GotoIfNot(TaggedIsSmi(element_k), &element_k_not_smi); 8321cb0ef41Sopenharmony_ci Branch(Float64Equal(search_num.value(), SmiToFloat64(CAST(element_k))), 8331cb0ef41Sopenharmony_ci &return_found, &continue_loop); 8341cb0ef41Sopenharmony_ci 8351cb0ef41Sopenharmony_ci BIND(&element_k_not_smi); 8361cb0ef41Sopenharmony_ci GotoIfNot(IsHeapNumber(CAST(element_k)), &continue_loop); 8371cb0ef41Sopenharmony_ci Branch(Float64Equal(search_num.value(), 8381cb0ef41Sopenharmony_ci LoadHeapNumberValue(CAST(element_k))), 8391cb0ef41Sopenharmony_ci &return_found, &continue_loop); 8401cb0ef41Sopenharmony_ci 8411cb0ef41Sopenharmony_ci BIND(&continue_loop); 8421cb0ef41Sopenharmony_ci Increment(&index_var); 8431cb0ef41Sopenharmony_ci Goto(¬_nan_loop); 8441cb0ef41Sopenharmony_ci } 8451cb0ef41Sopenharmony_ci 8461cb0ef41Sopenharmony_ci // Array.p.includes uses SameValueZero comparisons, where NaN == NaN. 8471cb0ef41Sopenharmony_ci if (variant == kIncludes) { 8481cb0ef41Sopenharmony_ci BIND(&nan_loop); 8491cb0ef41Sopenharmony_ci Label continue_loop(this); 8501cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 8511cb0ef41Sopenharmony_ci &return_not_found); 8521cb0ef41Sopenharmony_ci TNode<Object> element_k = 8531cb0ef41Sopenharmony_ci UnsafeLoadFixedArrayElement(elements, index_var.value()); 8541cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(element_k), &continue_loop); 8551cb0ef41Sopenharmony_ci GotoIfNot(IsHeapNumber(CAST(element_k)), &continue_loop); 8561cb0ef41Sopenharmony_ci BranchIfFloat64IsNaN(LoadHeapNumberValue(CAST(element_k)), &return_found, 8571cb0ef41Sopenharmony_ci &continue_loop); 8581cb0ef41Sopenharmony_ci 8591cb0ef41Sopenharmony_ci BIND(&continue_loop); 8601cb0ef41Sopenharmony_ci Increment(&index_var); 8611cb0ef41Sopenharmony_ci Goto(&nan_loop); 8621cb0ef41Sopenharmony_ci } 8631cb0ef41Sopenharmony_ci } 8641cb0ef41Sopenharmony_ci 8651cb0ef41Sopenharmony_ci BIND(&string_loop); 8661cb0ef41Sopenharmony_ci { 8671cb0ef41Sopenharmony_ci TNode<String> search_element_string = CAST(search_element); 8681cb0ef41Sopenharmony_ci Label continue_loop(this), next_iteration(this, &index_var), 8691cb0ef41Sopenharmony_ci slow_compare(this), runtime(this, Label::kDeferred); 8701cb0ef41Sopenharmony_ci TNode<IntPtrT> search_length = 8711cb0ef41Sopenharmony_ci LoadStringLengthAsWord(search_element_string); 8721cb0ef41Sopenharmony_ci Goto(&next_iteration); 8731cb0ef41Sopenharmony_ci BIND(&next_iteration); 8741cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 8751cb0ef41Sopenharmony_ci &return_not_found); 8761cb0ef41Sopenharmony_ci TNode<Object> element_k = 8771cb0ef41Sopenharmony_ci UnsafeLoadFixedArrayElement(elements, index_var.value()); 8781cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(element_k), &continue_loop); 8791cb0ef41Sopenharmony_ci GotoIf(TaggedEqual(search_element_string, element_k), &return_found); 8801cb0ef41Sopenharmony_ci TNode<Uint16T> element_k_type = LoadInstanceType(CAST(element_k)); 8811cb0ef41Sopenharmony_ci GotoIfNot(IsStringInstanceType(element_k_type), &continue_loop); 8821cb0ef41Sopenharmony_ci Branch(IntPtrEqual(search_length, LoadStringLengthAsWord(CAST(element_k))), 8831cb0ef41Sopenharmony_ci &slow_compare, &continue_loop); 8841cb0ef41Sopenharmony_ci 8851cb0ef41Sopenharmony_ci BIND(&slow_compare); 8861cb0ef41Sopenharmony_ci StringBuiltinsAssembler string_asm(state()); 8871cb0ef41Sopenharmony_ci string_asm.StringEqual_Core(search_element_string, search_type, 8881cb0ef41Sopenharmony_ci CAST(element_k), element_k_type, search_length, 8891cb0ef41Sopenharmony_ci &return_found, &continue_loop, &runtime); 8901cb0ef41Sopenharmony_ci BIND(&runtime); 8911cb0ef41Sopenharmony_ci TNode<Object> result = CallRuntime(Runtime::kStringEqual, context, 8921cb0ef41Sopenharmony_ci search_element_string, element_k); 8931cb0ef41Sopenharmony_ci Branch(TaggedEqual(result, TrueConstant()), &return_found, &continue_loop); 8941cb0ef41Sopenharmony_ci 8951cb0ef41Sopenharmony_ci BIND(&continue_loop); 8961cb0ef41Sopenharmony_ci Increment(&index_var); 8971cb0ef41Sopenharmony_ci Goto(&next_iteration); 8981cb0ef41Sopenharmony_ci } 8991cb0ef41Sopenharmony_ci 9001cb0ef41Sopenharmony_ci BIND(&bigint_loop); 9011cb0ef41Sopenharmony_ci { 9021cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 9031cb0ef41Sopenharmony_ci &return_not_found); 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ci TNode<Object> element_k = 9061cb0ef41Sopenharmony_ci UnsafeLoadFixedArrayElement(elements, index_var.value()); 9071cb0ef41Sopenharmony_ci Label continue_loop(this); 9081cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(element_k), &continue_loop); 9091cb0ef41Sopenharmony_ci GotoIfNot(IsBigInt(CAST(element_k)), &continue_loop); 9101cb0ef41Sopenharmony_ci TNode<Object> result = CallRuntime(Runtime::kBigIntEqualToBigInt, context, 9111cb0ef41Sopenharmony_ci search_element, element_k); 9121cb0ef41Sopenharmony_ci Branch(TaggedEqual(result, TrueConstant()), &return_found, &continue_loop); 9131cb0ef41Sopenharmony_ci 9141cb0ef41Sopenharmony_ci BIND(&continue_loop); 9151cb0ef41Sopenharmony_ci Increment(&index_var); 9161cb0ef41Sopenharmony_ci Goto(&bigint_loop); 9171cb0ef41Sopenharmony_ci } 9181cb0ef41Sopenharmony_ci BIND(&return_found); 9191cb0ef41Sopenharmony_ci if (variant == kIncludes) { 9201cb0ef41Sopenharmony_ci Return(TrueConstant()); 9211cb0ef41Sopenharmony_ci } else { 9221cb0ef41Sopenharmony_ci Return(SmiTag(index_var.value())); 9231cb0ef41Sopenharmony_ci } 9241cb0ef41Sopenharmony_ci 9251cb0ef41Sopenharmony_ci BIND(&return_not_found); 9261cb0ef41Sopenharmony_ci if (variant == kIncludes) { 9271cb0ef41Sopenharmony_ci Return(FalseConstant()); 9281cb0ef41Sopenharmony_ci } else { 9291cb0ef41Sopenharmony_ci Return(NumberConstant(-1)); 9301cb0ef41Sopenharmony_ci } 9311cb0ef41Sopenharmony_ci} 9321cb0ef41Sopenharmony_ci 9331cb0ef41Sopenharmony_civoid ArrayIncludesIndexofAssembler::GeneratePackedDoubles( 9341cb0ef41Sopenharmony_ci SearchVariant variant, TNode<FixedDoubleArray> elements, 9351cb0ef41Sopenharmony_ci TNode<Object> search_element, TNode<Smi> array_length, 9361cb0ef41Sopenharmony_ci TNode<Smi> from_index) { 9371cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, index_var, SmiUntag(from_index)); 9381cb0ef41Sopenharmony_ci TNode<IntPtrT> array_length_untagged = SmiUntag(array_length); 9391cb0ef41Sopenharmony_ci 9401cb0ef41Sopenharmony_ci Label nan_loop(this, &index_var), not_nan_loop(this, &index_var), 9411cb0ef41Sopenharmony_ci hole_loop(this, &index_var), search_notnan(this), return_found(this), 9421cb0ef41Sopenharmony_ci return_not_found(this); 9431cb0ef41Sopenharmony_ci TVARIABLE(Float64T, search_num); 9441cb0ef41Sopenharmony_ci search_num = Float64Constant(0); 9451cb0ef41Sopenharmony_ci 9461cb0ef41Sopenharmony_ci GotoIfNot(TaggedIsSmi(search_element), &search_notnan); 9471cb0ef41Sopenharmony_ci search_num = SmiToFloat64(CAST(search_element)); 9481cb0ef41Sopenharmony_ci Goto(¬_nan_loop); 9491cb0ef41Sopenharmony_ci 9501cb0ef41Sopenharmony_ci BIND(&search_notnan); 9511cb0ef41Sopenharmony_ci GotoIfNot(IsHeapNumber(CAST(search_element)), &return_not_found); 9521cb0ef41Sopenharmony_ci 9531cb0ef41Sopenharmony_ci search_num = LoadHeapNumberValue(CAST(search_element)); 9541cb0ef41Sopenharmony_ci 9551cb0ef41Sopenharmony_ci Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found; 9561cb0ef41Sopenharmony_ci BranchIfFloat64IsNaN(search_num.value(), nan_handling, ¬_nan_loop); 9571cb0ef41Sopenharmony_ci 9581cb0ef41Sopenharmony_ci BIND(¬_nan_loop); 9591cb0ef41Sopenharmony_ci { 9601cb0ef41Sopenharmony_ci Label continue_loop(this); 9611cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 9621cb0ef41Sopenharmony_ci &return_not_found); 9631cb0ef41Sopenharmony_ci TNode<Float64T> element_k = 9641cb0ef41Sopenharmony_ci LoadFixedDoubleArrayElement(elements, index_var.value()); 9651cb0ef41Sopenharmony_ci Branch(Float64Equal(element_k, search_num.value()), &return_found, 9661cb0ef41Sopenharmony_ci &continue_loop); 9671cb0ef41Sopenharmony_ci BIND(&continue_loop); 9681cb0ef41Sopenharmony_ci Increment(&index_var); 9691cb0ef41Sopenharmony_ci Goto(¬_nan_loop); 9701cb0ef41Sopenharmony_ci } 9711cb0ef41Sopenharmony_ci 9721cb0ef41Sopenharmony_ci // Array.p.includes uses SameValueZero comparisons, where NaN == NaN. 9731cb0ef41Sopenharmony_ci if (variant == kIncludes) { 9741cb0ef41Sopenharmony_ci BIND(&nan_loop); 9751cb0ef41Sopenharmony_ci Label continue_loop(this); 9761cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 9771cb0ef41Sopenharmony_ci &return_not_found); 9781cb0ef41Sopenharmony_ci TNode<Float64T> element_k = 9791cb0ef41Sopenharmony_ci LoadFixedDoubleArrayElement(elements, index_var.value()); 9801cb0ef41Sopenharmony_ci BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop); 9811cb0ef41Sopenharmony_ci BIND(&continue_loop); 9821cb0ef41Sopenharmony_ci Increment(&index_var); 9831cb0ef41Sopenharmony_ci Goto(&nan_loop); 9841cb0ef41Sopenharmony_ci } 9851cb0ef41Sopenharmony_ci 9861cb0ef41Sopenharmony_ci BIND(&return_found); 9871cb0ef41Sopenharmony_ci if (variant == kIncludes) { 9881cb0ef41Sopenharmony_ci Return(TrueConstant()); 9891cb0ef41Sopenharmony_ci } else { 9901cb0ef41Sopenharmony_ci Return(SmiTag(index_var.value())); 9911cb0ef41Sopenharmony_ci } 9921cb0ef41Sopenharmony_ci 9931cb0ef41Sopenharmony_ci BIND(&return_not_found); 9941cb0ef41Sopenharmony_ci if (variant == kIncludes) { 9951cb0ef41Sopenharmony_ci Return(FalseConstant()); 9961cb0ef41Sopenharmony_ci } else { 9971cb0ef41Sopenharmony_ci Return(NumberConstant(-1)); 9981cb0ef41Sopenharmony_ci } 9991cb0ef41Sopenharmony_ci} 10001cb0ef41Sopenharmony_ci 10011cb0ef41Sopenharmony_civoid ArrayIncludesIndexofAssembler::GenerateHoleyDoubles( 10021cb0ef41Sopenharmony_ci SearchVariant variant, TNode<FixedDoubleArray> elements, 10031cb0ef41Sopenharmony_ci TNode<Object> search_element, TNode<Smi> array_length, 10041cb0ef41Sopenharmony_ci TNode<Smi> from_index) { 10051cb0ef41Sopenharmony_ci TVARIABLE(IntPtrT, index_var, SmiUntag(from_index)); 10061cb0ef41Sopenharmony_ci TNode<IntPtrT> array_length_untagged = SmiUntag(array_length); 10071cb0ef41Sopenharmony_ci 10081cb0ef41Sopenharmony_ci Label nan_loop(this, &index_var), not_nan_loop(this, &index_var), 10091cb0ef41Sopenharmony_ci hole_loop(this, &index_var), search_notnan(this), return_found(this), 10101cb0ef41Sopenharmony_ci return_not_found(this); 10111cb0ef41Sopenharmony_ci TVARIABLE(Float64T, search_num); 10121cb0ef41Sopenharmony_ci search_num = Float64Constant(0); 10131cb0ef41Sopenharmony_ci 10141cb0ef41Sopenharmony_ci GotoIfNot(TaggedIsSmi(search_element), &search_notnan); 10151cb0ef41Sopenharmony_ci search_num = SmiToFloat64(CAST(search_element)); 10161cb0ef41Sopenharmony_ci Goto(¬_nan_loop); 10171cb0ef41Sopenharmony_ci 10181cb0ef41Sopenharmony_ci BIND(&search_notnan); 10191cb0ef41Sopenharmony_ci if (variant == kIncludes) { 10201cb0ef41Sopenharmony_ci GotoIf(IsUndefined(search_element), &hole_loop); 10211cb0ef41Sopenharmony_ci } 10221cb0ef41Sopenharmony_ci GotoIfNot(IsHeapNumber(CAST(search_element)), &return_not_found); 10231cb0ef41Sopenharmony_ci 10241cb0ef41Sopenharmony_ci search_num = LoadHeapNumberValue(CAST(search_element)); 10251cb0ef41Sopenharmony_ci 10261cb0ef41Sopenharmony_ci Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found; 10271cb0ef41Sopenharmony_ci BranchIfFloat64IsNaN(search_num.value(), nan_handling, ¬_nan_loop); 10281cb0ef41Sopenharmony_ci 10291cb0ef41Sopenharmony_ci BIND(¬_nan_loop); 10301cb0ef41Sopenharmony_ci { 10311cb0ef41Sopenharmony_ci Label continue_loop(this); 10321cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 10331cb0ef41Sopenharmony_ci &return_not_found); 10341cb0ef41Sopenharmony_ci 10351cb0ef41Sopenharmony_ci // No need for hole checking here; the following Float64Equal will 10361cb0ef41Sopenharmony_ci // return 'not equal' for holes anyway. 10371cb0ef41Sopenharmony_ci TNode<Float64T> element_k = 10381cb0ef41Sopenharmony_ci LoadFixedDoubleArrayElement(elements, index_var.value()); 10391cb0ef41Sopenharmony_ci 10401cb0ef41Sopenharmony_ci Branch(Float64Equal(element_k, search_num.value()), &return_found, 10411cb0ef41Sopenharmony_ci &continue_loop); 10421cb0ef41Sopenharmony_ci BIND(&continue_loop); 10431cb0ef41Sopenharmony_ci Increment(&index_var); 10441cb0ef41Sopenharmony_ci Goto(¬_nan_loop); 10451cb0ef41Sopenharmony_ci } 10461cb0ef41Sopenharmony_ci 10471cb0ef41Sopenharmony_ci // Array.p.includes uses SameValueZero comparisons, where NaN == NaN. 10481cb0ef41Sopenharmony_ci if (variant == kIncludes) { 10491cb0ef41Sopenharmony_ci BIND(&nan_loop); 10501cb0ef41Sopenharmony_ci Label continue_loop(this); 10511cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 10521cb0ef41Sopenharmony_ci &return_not_found); 10531cb0ef41Sopenharmony_ci 10541cb0ef41Sopenharmony_ci // Load double value or continue if it's the hole NaN. 10551cb0ef41Sopenharmony_ci TNode<Float64T> element_k = LoadFixedDoubleArrayElement( 10561cb0ef41Sopenharmony_ci elements, index_var.value(), &continue_loop); 10571cb0ef41Sopenharmony_ci 10581cb0ef41Sopenharmony_ci BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop); 10591cb0ef41Sopenharmony_ci BIND(&continue_loop); 10601cb0ef41Sopenharmony_ci Increment(&index_var); 10611cb0ef41Sopenharmony_ci Goto(&nan_loop); 10621cb0ef41Sopenharmony_ci } 10631cb0ef41Sopenharmony_ci 10641cb0ef41Sopenharmony_ci // Array.p.includes treats the hole as undefined. 10651cb0ef41Sopenharmony_ci if (variant == kIncludes) { 10661cb0ef41Sopenharmony_ci BIND(&hole_loop); 10671cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged), 10681cb0ef41Sopenharmony_ci &return_not_found); 10691cb0ef41Sopenharmony_ci 10701cb0ef41Sopenharmony_ci // Check if the element is a double hole, but don't load it. 10711cb0ef41Sopenharmony_ci LoadFixedDoubleArrayElement(elements, index_var.value(), &return_found, 10721cb0ef41Sopenharmony_ci MachineType::None()); 10731cb0ef41Sopenharmony_ci 10741cb0ef41Sopenharmony_ci Increment(&index_var); 10751cb0ef41Sopenharmony_ci Goto(&hole_loop); 10761cb0ef41Sopenharmony_ci } 10771cb0ef41Sopenharmony_ci 10781cb0ef41Sopenharmony_ci BIND(&return_found); 10791cb0ef41Sopenharmony_ci if (variant == kIncludes) { 10801cb0ef41Sopenharmony_ci Return(TrueConstant()); 10811cb0ef41Sopenharmony_ci } else { 10821cb0ef41Sopenharmony_ci Return(SmiTag(index_var.value())); 10831cb0ef41Sopenharmony_ci } 10841cb0ef41Sopenharmony_ci 10851cb0ef41Sopenharmony_ci BIND(&return_not_found); 10861cb0ef41Sopenharmony_ci if (variant == kIncludes) { 10871cb0ef41Sopenharmony_ci Return(FalseConstant()); 10881cb0ef41Sopenharmony_ci } else { 10891cb0ef41Sopenharmony_ci Return(NumberConstant(-1)); 10901cb0ef41Sopenharmony_ci } 10911cb0ef41Sopenharmony_ci} 10921cb0ef41Sopenharmony_ci 10931cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIncludes, ArrayIncludesIndexofAssembler) { 10941cb0ef41Sopenharmony_ci TNode<IntPtrT> argc = ChangeInt32ToIntPtr( 10951cb0ef41Sopenharmony_ci UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount)); 10961cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 10971cb0ef41Sopenharmony_ci 10981cb0ef41Sopenharmony_ci Generate(kIncludes, argc, context); 10991cb0ef41Sopenharmony_ci} 11001cb0ef41Sopenharmony_ci 11011cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIncludesSmiOrObject, ArrayIncludesIndexofAssembler) { 11021cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 11031cb0ef41Sopenharmony_ci auto elements = Parameter<FixedArray>(Descriptor::kElements); 11041cb0ef41Sopenharmony_ci auto search_element = Parameter<Object>(Descriptor::kSearchElement); 11051cb0ef41Sopenharmony_ci auto array_length = Parameter<Smi>(Descriptor::kLength); 11061cb0ef41Sopenharmony_ci auto from_index = Parameter<Smi>(Descriptor::kFromIndex); 11071cb0ef41Sopenharmony_ci 11081cb0ef41Sopenharmony_ci GenerateSmiOrObject(kIncludes, context, elements, search_element, 11091cb0ef41Sopenharmony_ci array_length, from_index); 11101cb0ef41Sopenharmony_ci} 11111cb0ef41Sopenharmony_ci 11121cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIncludesPackedDoubles, ArrayIncludesIndexofAssembler) { 11131cb0ef41Sopenharmony_ci auto elements = Parameter<FixedArrayBase>(Descriptor::kElements); 11141cb0ef41Sopenharmony_ci auto search_element = Parameter<Object>(Descriptor::kSearchElement); 11151cb0ef41Sopenharmony_ci auto array_length = Parameter<Smi>(Descriptor::kLength); 11161cb0ef41Sopenharmony_ci auto from_index = Parameter<Smi>(Descriptor::kFromIndex); 11171cb0ef41Sopenharmony_ci 11181cb0ef41Sopenharmony_ci ReturnIfEmpty(array_length, FalseConstant()); 11191cb0ef41Sopenharmony_ci GeneratePackedDoubles(kIncludes, CAST(elements), search_element, array_length, 11201cb0ef41Sopenharmony_ci from_index); 11211cb0ef41Sopenharmony_ci} 11221cb0ef41Sopenharmony_ci 11231cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIncludesHoleyDoubles, ArrayIncludesIndexofAssembler) { 11241cb0ef41Sopenharmony_ci auto elements = Parameter<FixedArrayBase>(Descriptor::kElements); 11251cb0ef41Sopenharmony_ci auto search_element = Parameter<Object>(Descriptor::kSearchElement); 11261cb0ef41Sopenharmony_ci auto array_length = Parameter<Smi>(Descriptor::kLength); 11271cb0ef41Sopenharmony_ci auto from_index = Parameter<Smi>(Descriptor::kFromIndex); 11281cb0ef41Sopenharmony_ci 11291cb0ef41Sopenharmony_ci ReturnIfEmpty(array_length, FalseConstant()); 11301cb0ef41Sopenharmony_ci GenerateHoleyDoubles(kIncludes, CAST(elements), search_element, array_length, 11311cb0ef41Sopenharmony_ci from_index); 11321cb0ef41Sopenharmony_ci} 11331cb0ef41Sopenharmony_ci 11341cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIndexOf, ArrayIncludesIndexofAssembler) { 11351cb0ef41Sopenharmony_ci TNode<IntPtrT> argc = ChangeInt32ToIntPtr( 11361cb0ef41Sopenharmony_ci UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount)); 11371cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 11381cb0ef41Sopenharmony_ci 11391cb0ef41Sopenharmony_ci Generate(kIndexOf, argc, context); 11401cb0ef41Sopenharmony_ci} 11411cb0ef41Sopenharmony_ci 11421cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIndexOfSmiOrObject, ArrayIncludesIndexofAssembler) { 11431cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 11441cb0ef41Sopenharmony_ci auto elements = Parameter<FixedArray>(Descriptor::kElements); 11451cb0ef41Sopenharmony_ci auto search_element = Parameter<Object>(Descriptor::kSearchElement); 11461cb0ef41Sopenharmony_ci auto array_length = Parameter<Smi>(Descriptor::kLength); 11471cb0ef41Sopenharmony_ci auto from_index = Parameter<Smi>(Descriptor::kFromIndex); 11481cb0ef41Sopenharmony_ci 11491cb0ef41Sopenharmony_ci GenerateSmiOrObject(kIndexOf, context, elements, search_element, array_length, 11501cb0ef41Sopenharmony_ci from_index); 11511cb0ef41Sopenharmony_ci} 11521cb0ef41Sopenharmony_ci 11531cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIndexOfPackedDoubles, ArrayIncludesIndexofAssembler) { 11541cb0ef41Sopenharmony_ci auto elements = Parameter<FixedArrayBase>(Descriptor::kElements); 11551cb0ef41Sopenharmony_ci auto search_element = Parameter<Object>(Descriptor::kSearchElement); 11561cb0ef41Sopenharmony_ci auto array_length = Parameter<Smi>(Descriptor::kLength); 11571cb0ef41Sopenharmony_ci auto from_index = Parameter<Smi>(Descriptor::kFromIndex); 11581cb0ef41Sopenharmony_ci 11591cb0ef41Sopenharmony_ci ReturnIfEmpty(array_length, NumberConstant(-1)); 11601cb0ef41Sopenharmony_ci GeneratePackedDoubles(kIndexOf, CAST(elements), search_element, array_length, 11611cb0ef41Sopenharmony_ci from_index); 11621cb0ef41Sopenharmony_ci} 11631cb0ef41Sopenharmony_ci 11641cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIndexOfHoleyDoubles, ArrayIncludesIndexofAssembler) { 11651cb0ef41Sopenharmony_ci auto elements = Parameter<FixedArrayBase>(Descriptor::kElements); 11661cb0ef41Sopenharmony_ci auto search_element = Parameter<Object>(Descriptor::kSearchElement); 11671cb0ef41Sopenharmony_ci auto array_length = Parameter<Smi>(Descriptor::kLength); 11681cb0ef41Sopenharmony_ci auto from_index = Parameter<Smi>(Descriptor::kFromIndex); 11691cb0ef41Sopenharmony_ci 11701cb0ef41Sopenharmony_ci ReturnIfEmpty(array_length, NumberConstant(-1)); 11711cb0ef41Sopenharmony_ci GenerateHoleyDoubles(kIndexOf, CAST(elements), search_element, array_length, 11721cb0ef41Sopenharmony_ci from_index); 11731cb0ef41Sopenharmony_ci} 11741cb0ef41Sopenharmony_ci 11751cb0ef41Sopenharmony_ci// ES #sec-array.prototype.values 11761cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayPrototypeValues, CodeStubAssembler) { 11771cb0ef41Sopenharmony_ci auto context = Parameter<NativeContext>(Descriptor::kContext); 11781cb0ef41Sopenharmony_ci auto receiver = Parameter<Object>(Descriptor::kReceiver); 11791cb0ef41Sopenharmony_ci Return(CreateArrayIterator(context, ToObject_Inline(context, receiver), 11801cb0ef41Sopenharmony_ci IterationKind::kValues)); 11811cb0ef41Sopenharmony_ci} 11821cb0ef41Sopenharmony_ci 11831cb0ef41Sopenharmony_ci// ES #sec-array.prototype.entries 11841cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayPrototypeEntries, CodeStubAssembler) { 11851cb0ef41Sopenharmony_ci auto context = Parameter<NativeContext>(Descriptor::kContext); 11861cb0ef41Sopenharmony_ci auto receiver = Parameter<Object>(Descriptor::kReceiver); 11871cb0ef41Sopenharmony_ci Return(CreateArrayIterator(context, ToObject_Inline(context, receiver), 11881cb0ef41Sopenharmony_ci IterationKind::kEntries)); 11891cb0ef41Sopenharmony_ci} 11901cb0ef41Sopenharmony_ci 11911cb0ef41Sopenharmony_ci// ES #sec-array.prototype.keys 11921cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayPrototypeKeys, CodeStubAssembler) { 11931cb0ef41Sopenharmony_ci auto context = Parameter<NativeContext>(Descriptor::kContext); 11941cb0ef41Sopenharmony_ci auto receiver = Parameter<Object>(Descriptor::kReceiver); 11951cb0ef41Sopenharmony_ci Return(CreateArrayIterator(context, ToObject_Inline(context, receiver), 11961cb0ef41Sopenharmony_ci IterationKind::kKeys)); 11971cb0ef41Sopenharmony_ci} 11981cb0ef41Sopenharmony_ci 11991cb0ef41Sopenharmony_ci// ES #sec-%arrayiteratorprototype%.next 12001cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) { 12011cb0ef41Sopenharmony_ci const char* method_name = "Array Iterator.prototype.next"; 12021cb0ef41Sopenharmony_ci 12031cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 12041cb0ef41Sopenharmony_ci auto maybe_iterator = Parameter<Object>(Descriptor::kReceiver); 12051cb0ef41Sopenharmony_ci 12061cb0ef41Sopenharmony_ci TVARIABLE(Oddball, var_done, TrueConstant()); 12071cb0ef41Sopenharmony_ci TVARIABLE(Object, var_value, UndefinedConstant()); 12081cb0ef41Sopenharmony_ci 12091cb0ef41Sopenharmony_ci Label allocate_entry_if_needed(this); 12101cb0ef41Sopenharmony_ci Label allocate_iterator_result(this); 12111cb0ef41Sopenharmony_ci Label if_typedarray(this), if_other(this, Label::kDeferred), if_array(this), 12121cb0ef41Sopenharmony_ci if_generic(this, Label::kDeferred); 12131cb0ef41Sopenharmony_ci Label set_done(this, Label::kDeferred); 12141cb0ef41Sopenharmony_ci 12151cb0ef41Sopenharmony_ci // If O does not have all of the internal slots of an Array Iterator Instance 12161cb0ef41Sopenharmony_ci // (22.1.5.3), throw a TypeError exception 12171cb0ef41Sopenharmony_ci ThrowIfNotInstanceType(context, maybe_iterator, JS_ARRAY_ITERATOR_TYPE, 12181cb0ef41Sopenharmony_ci method_name); 12191cb0ef41Sopenharmony_ci 12201cb0ef41Sopenharmony_ci TNode<JSArrayIterator> iterator = CAST(maybe_iterator); 12211cb0ef41Sopenharmony_ci 12221cb0ef41Sopenharmony_ci // Let a be O.[[IteratedObject]]. 12231cb0ef41Sopenharmony_ci TNode<JSReceiver> array = LoadJSArrayIteratorIteratedObject(iterator); 12241cb0ef41Sopenharmony_ci 12251cb0ef41Sopenharmony_ci // Let index be O.[[ArrayIteratorNextIndex]]. 12261cb0ef41Sopenharmony_ci TNode<Number> index = LoadJSArrayIteratorNextIndex(iterator); 12271cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberNonNegativeSafeInteger(index)); 12281cb0ef41Sopenharmony_ci 12291cb0ef41Sopenharmony_ci // Dispatch based on the type of the {array}. 12301cb0ef41Sopenharmony_ci TNode<Map> array_map = LoadMap(array); 12311cb0ef41Sopenharmony_ci TNode<Uint16T> array_type = LoadMapInstanceType(array_map); 12321cb0ef41Sopenharmony_ci GotoIf(InstanceTypeEqual(array_type, JS_ARRAY_TYPE), &if_array); 12331cb0ef41Sopenharmony_ci Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_typedarray, 12341cb0ef41Sopenharmony_ci &if_other); 12351cb0ef41Sopenharmony_ci 12361cb0ef41Sopenharmony_ci BIND(&if_array); 12371cb0ef41Sopenharmony_ci { 12381cb0ef41Sopenharmony_ci // If {array} is a JSArray, then the {index} must be in Unsigned32 range. 12391cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberArrayIndex(index)); 12401cb0ef41Sopenharmony_ci 12411cb0ef41Sopenharmony_ci // Check that the {index} is within range for the {array}. We handle all 12421cb0ef41Sopenharmony_ci // kinds of JSArray's here, so we do the computation on Uint32. 12431cb0ef41Sopenharmony_ci TNode<Uint32T> index32 = ChangeNumberToUint32(index); 12441cb0ef41Sopenharmony_ci TNode<Uint32T> length32 = 12451cb0ef41Sopenharmony_ci ChangeNumberToUint32(LoadJSArrayLength(CAST(array))); 12461cb0ef41Sopenharmony_ci GotoIfNot(Uint32LessThan(index32, length32), &set_done); 12471cb0ef41Sopenharmony_ci StoreJSArrayIteratorNextIndex( 12481cb0ef41Sopenharmony_ci iterator, ChangeUint32ToTagged(Uint32Add(index32, Uint32Constant(1)))); 12491cb0ef41Sopenharmony_ci 12501cb0ef41Sopenharmony_ci var_done = FalseConstant(); 12511cb0ef41Sopenharmony_ci var_value = index; 12521cb0ef41Sopenharmony_ci 12531cb0ef41Sopenharmony_ci GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField( 12541cb0ef41Sopenharmony_ci iterator, JSArrayIterator::kKindOffset), 12551cb0ef41Sopenharmony_ci Int32Constant(static_cast<int>(IterationKind::kKeys))), 12561cb0ef41Sopenharmony_ci &allocate_iterator_result); 12571cb0ef41Sopenharmony_ci 12581cb0ef41Sopenharmony_ci Label if_hole(this, Label::kDeferred); 12591cb0ef41Sopenharmony_ci TNode<Int32T> elements_kind = LoadMapElementsKind(array_map); 12601cb0ef41Sopenharmony_ci TNode<FixedArrayBase> elements = LoadElements(CAST(array)); 12611cb0ef41Sopenharmony_ci GotoIfForceSlowPath(&if_generic); 12621cb0ef41Sopenharmony_ci var_value = LoadFixedArrayBaseElementAsTagged( 12631cb0ef41Sopenharmony_ci elements, Signed(ChangeUint32ToWord(index32)), elements_kind, 12641cb0ef41Sopenharmony_ci &if_generic, &if_hole); 12651cb0ef41Sopenharmony_ci Goto(&allocate_entry_if_needed); 12661cb0ef41Sopenharmony_ci 12671cb0ef41Sopenharmony_ci BIND(&if_hole); 12681cb0ef41Sopenharmony_ci { 12691cb0ef41Sopenharmony_ci GotoIf(IsNoElementsProtectorCellInvalid(), &if_generic); 12701cb0ef41Sopenharmony_ci GotoIfNot(IsPrototypeInitialArrayPrototype(context, array_map), 12711cb0ef41Sopenharmony_ci &if_generic); 12721cb0ef41Sopenharmony_ci var_value = UndefinedConstant(); 12731cb0ef41Sopenharmony_ci Goto(&allocate_entry_if_needed); 12741cb0ef41Sopenharmony_ci } 12751cb0ef41Sopenharmony_ci } 12761cb0ef41Sopenharmony_ci 12771cb0ef41Sopenharmony_ci BIND(&if_other); 12781cb0ef41Sopenharmony_ci { 12791cb0ef41Sopenharmony_ci // We cannot enter here with either JSArray's or JSTypedArray's. 12801cb0ef41Sopenharmony_ci CSA_DCHECK(this, Word32BinaryNot(IsJSArray(array))); 12811cb0ef41Sopenharmony_ci CSA_DCHECK(this, Word32BinaryNot(IsJSTypedArray(array))); 12821cb0ef41Sopenharmony_ci 12831cb0ef41Sopenharmony_ci // Check that the {index} is within the bounds of the {array}s "length". 12841cb0ef41Sopenharmony_ci TNode<Number> length = CAST( 12851cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kToLength, context, 12861cb0ef41Sopenharmony_ci GetProperty(context, array, factory()->length_string()))); 12871cb0ef41Sopenharmony_ci GotoIfNumberGreaterThanOrEqual(index, length, &set_done); 12881cb0ef41Sopenharmony_ci StoreJSArrayIteratorNextIndex(iterator, NumberInc(index)); 12891cb0ef41Sopenharmony_ci 12901cb0ef41Sopenharmony_ci var_done = FalseConstant(); 12911cb0ef41Sopenharmony_ci var_value = index; 12921cb0ef41Sopenharmony_ci 12931cb0ef41Sopenharmony_ci Branch(Word32Equal(LoadAndUntagToWord32ObjectField( 12941cb0ef41Sopenharmony_ci iterator, JSArrayIterator::kKindOffset), 12951cb0ef41Sopenharmony_ci Int32Constant(static_cast<int>(IterationKind::kKeys))), 12961cb0ef41Sopenharmony_ci &allocate_iterator_result, &if_generic); 12971cb0ef41Sopenharmony_ci } 12981cb0ef41Sopenharmony_ci 12991cb0ef41Sopenharmony_ci BIND(&set_done); 13001cb0ef41Sopenharmony_ci { 13011cb0ef41Sopenharmony_ci // Change the [[ArrayIteratorNextIndex]] such that the {iterator} will 13021cb0ef41Sopenharmony_ci // never produce values anymore, because it will always fail the bounds 13031cb0ef41Sopenharmony_ci // check. Note that this is different from what the specification does, 13041cb0ef41Sopenharmony_ci // which is changing the [[IteratedObject]] to undefined, because leaving 13051cb0ef41Sopenharmony_ci // [[IteratedObject]] alone helps TurboFan to generate better code with 13061cb0ef41Sopenharmony_ci // the inlining in JSCallReducer::ReduceArrayIteratorPrototypeNext(). 13071cb0ef41Sopenharmony_ci // 13081cb0ef41Sopenharmony_ci // The terminal value we chose here depends on the type of the {array}, 13091cb0ef41Sopenharmony_ci // for JSArray's we use kMaxUInt32 so that TurboFan can always use 13101cb0ef41Sopenharmony_ci // Word32 representation for fast-path indices (and this is safe since 13111cb0ef41Sopenharmony_ci // the "length" of JSArray's is limited to Unsigned32 range). For other 13121cb0ef41Sopenharmony_ci // JSReceiver's we have to use kMaxSafeInteger, since the "length" can 13131cb0ef41Sopenharmony_ci // be any arbitrary value in the safe integer range. 13141cb0ef41Sopenharmony_ci // 13151cb0ef41Sopenharmony_ci // Note specifically that JSTypedArray's will never take this path, so 13161cb0ef41Sopenharmony_ci // we don't need to worry about their maximum value. 13171cb0ef41Sopenharmony_ci CSA_DCHECK(this, Word32BinaryNot(IsJSTypedArray(array))); 13181cb0ef41Sopenharmony_ci TNode<Number> max_length = 13191cb0ef41Sopenharmony_ci SelectConstant(IsJSArray(array), NumberConstant(kMaxUInt32), 13201cb0ef41Sopenharmony_ci NumberConstant(kMaxSafeInteger)); 13211cb0ef41Sopenharmony_ci StoreJSArrayIteratorNextIndex(iterator, max_length); 13221cb0ef41Sopenharmony_ci Goto(&allocate_iterator_result); 13231cb0ef41Sopenharmony_ci } 13241cb0ef41Sopenharmony_ci 13251cb0ef41Sopenharmony_ci BIND(&if_generic); 13261cb0ef41Sopenharmony_ci { 13271cb0ef41Sopenharmony_ci var_value = GetProperty(context, array, index); 13281cb0ef41Sopenharmony_ci Goto(&allocate_entry_if_needed); 13291cb0ef41Sopenharmony_ci } 13301cb0ef41Sopenharmony_ci 13311cb0ef41Sopenharmony_ci BIND(&if_typedarray); 13321cb0ef41Sopenharmony_ci { 13331cb0ef41Sopenharmony_ci // Overflowing uintptr range also means end of iteration. 13341cb0ef41Sopenharmony_ci TNode<UintPtrT> index_uintptr = 13351cb0ef41Sopenharmony_ci ChangeSafeIntegerNumberToUintPtr(index, &allocate_iterator_result); 13361cb0ef41Sopenharmony_ci 13371cb0ef41Sopenharmony_ci // If we go outside of the {length}, we don't need to update the 13381cb0ef41Sopenharmony_ci // [[ArrayIteratorNextIndex]] anymore, since a JSTypedArray's 13391cb0ef41Sopenharmony_ci // length cannot change anymore, so this {iterator} will never 13401cb0ef41Sopenharmony_ci // produce values again anyways. 13411cb0ef41Sopenharmony_ci Label detached(this); 13421cb0ef41Sopenharmony_ci TNode<UintPtrT> length = 13431cb0ef41Sopenharmony_ci LoadJSTypedArrayLengthAndCheckDetached(CAST(array), &detached); 13441cb0ef41Sopenharmony_ci GotoIfNot(UintPtrLessThan(index_uintptr, length), 13451cb0ef41Sopenharmony_ci &allocate_iterator_result); 13461cb0ef41Sopenharmony_ci // TODO(v8:4153): Consider storing next index as uintptr. Update this and 13471cb0ef41Sopenharmony_ci // the relevant TurboFan code. 13481cb0ef41Sopenharmony_ci StoreJSArrayIteratorNextIndex( 13491cb0ef41Sopenharmony_ci iterator, 13501cb0ef41Sopenharmony_ci ChangeUintPtrToTagged(UintPtrAdd(index_uintptr, UintPtrConstant(1)))); 13511cb0ef41Sopenharmony_ci 13521cb0ef41Sopenharmony_ci var_done = FalseConstant(); 13531cb0ef41Sopenharmony_ci var_value = index; 13541cb0ef41Sopenharmony_ci 13551cb0ef41Sopenharmony_ci GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField( 13561cb0ef41Sopenharmony_ci iterator, JSArrayIterator::kKindOffset), 13571cb0ef41Sopenharmony_ci Int32Constant(static_cast<int>(IterationKind::kKeys))), 13581cb0ef41Sopenharmony_ci &allocate_iterator_result); 13591cb0ef41Sopenharmony_ci 13601cb0ef41Sopenharmony_ci TNode<Int32T> elements_kind = LoadMapElementsKind(array_map); 13611cb0ef41Sopenharmony_ci TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(CAST(array)); 13621cb0ef41Sopenharmony_ci var_value = LoadFixedTypedArrayElementAsTagged(data_ptr, index_uintptr, 13631cb0ef41Sopenharmony_ci elements_kind); 13641cb0ef41Sopenharmony_ci Goto(&allocate_entry_if_needed); 13651cb0ef41Sopenharmony_ci 13661cb0ef41Sopenharmony_ci BIND(&detached); 13671cb0ef41Sopenharmony_ci ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name); 13681cb0ef41Sopenharmony_ci } 13691cb0ef41Sopenharmony_ci 13701cb0ef41Sopenharmony_ci BIND(&allocate_entry_if_needed); 13711cb0ef41Sopenharmony_ci { 13721cb0ef41Sopenharmony_ci GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField( 13731cb0ef41Sopenharmony_ci iterator, JSArrayIterator::kKindOffset), 13741cb0ef41Sopenharmony_ci Int32Constant(static_cast<int>(IterationKind::kValues))), 13751cb0ef41Sopenharmony_ci &allocate_iterator_result); 13761cb0ef41Sopenharmony_ci 13771cb0ef41Sopenharmony_ci TNode<JSObject> result = 13781cb0ef41Sopenharmony_ci AllocateJSIteratorResultForEntry(context, index, var_value.value()); 13791cb0ef41Sopenharmony_ci Return(result); 13801cb0ef41Sopenharmony_ci } 13811cb0ef41Sopenharmony_ci 13821cb0ef41Sopenharmony_ci BIND(&allocate_iterator_result); 13831cb0ef41Sopenharmony_ci { 13841cb0ef41Sopenharmony_ci TNode<JSObject> result = 13851cb0ef41Sopenharmony_ci AllocateJSIteratorResult(context, var_value.value(), var_done.value()); 13861cb0ef41Sopenharmony_ci Return(result); 13871cb0ef41Sopenharmony_ci } 13881cb0ef41Sopenharmony_ci} 13891cb0ef41Sopenharmony_ci 13901cb0ef41Sopenharmony_ciclass ArrayFlattenAssembler : public CodeStubAssembler { 13911cb0ef41Sopenharmony_ci public: 13921cb0ef41Sopenharmony_ci explicit ArrayFlattenAssembler(compiler::CodeAssemblerState* state) 13931cb0ef41Sopenharmony_ci : CodeStubAssembler(state) {} 13941cb0ef41Sopenharmony_ci 13951cb0ef41Sopenharmony_ci // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray 13961cb0ef41Sopenharmony_ci TNode<Number> FlattenIntoArray( 13971cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSReceiver> target, 13981cb0ef41Sopenharmony_ci TNode<JSReceiver> source, TNode<Number> source_length, 13991cb0ef41Sopenharmony_ci TNode<Number> start, TNode<Number> depth, 14001cb0ef41Sopenharmony_ci base::Optional<TNode<HeapObject>> mapper_function = base::nullopt, 14011cb0ef41Sopenharmony_ci base::Optional<TNode<Object>> this_arg = base::nullopt) { 14021cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberPositive(source_length)); 14031cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNumberPositive(start)); 14041cb0ef41Sopenharmony_ci 14051cb0ef41Sopenharmony_ci // 1. Let targetIndex be start. 14061cb0ef41Sopenharmony_ci TVARIABLE(Number, var_target_index, start); 14071cb0ef41Sopenharmony_ci 14081cb0ef41Sopenharmony_ci // 2. Let sourceIndex be 0. 14091cb0ef41Sopenharmony_ci TVARIABLE(Number, var_source_index, SmiConstant(0)); 14101cb0ef41Sopenharmony_ci 14111cb0ef41Sopenharmony_ci // 3. Repeat... 14121cb0ef41Sopenharmony_ci Label loop(this, {&var_target_index, &var_source_index}), done_loop(this); 14131cb0ef41Sopenharmony_ci Goto(&loop); 14141cb0ef41Sopenharmony_ci BIND(&loop); 14151cb0ef41Sopenharmony_ci { 14161cb0ef41Sopenharmony_ci TNode<Number> source_index = var_source_index.value(); 14171cb0ef41Sopenharmony_ci TNode<Number> target_index = var_target_index.value(); 14181cb0ef41Sopenharmony_ci 14191cb0ef41Sopenharmony_ci // ...while sourceIndex < sourceLen 14201cb0ef41Sopenharmony_ci GotoIfNumberGreaterThanOrEqual(source_index, source_length, &done_loop); 14211cb0ef41Sopenharmony_ci 14221cb0ef41Sopenharmony_ci // a. Let P be ! ToString(sourceIndex). 14231cb0ef41Sopenharmony_ci // b. Let exists be ? HasProperty(source, P). 14241cb0ef41Sopenharmony_ci CSA_DCHECK(this, 14251cb0ef41Sopenharmony_ci SmiGreaterThanOrEqual(CAST(source_index), SmiConstant(0))); 14261cb0ef41Sopenharmony_ci const TNode<Oddball> exists = 14271cb0ef41Sopenharmony_ci HasProperty(context, source, source_index, kHasProperty); 14281cb0ef41Sopenharmony_ci 14291cb0ef41Sopenharmony_ci // c. If exists is true, then 14301cb0ef41Sopenharmony_ci Label next(this); 14311cb0ef41Sopenharmony_ci GotoIfNot(IsTrue(exists), &next); 14321cb0ef41Sopenharmony_ci { 14331cb0ef41Sopenharmony_ci // i. Let element be ? Get(source, P). 14341cb0ef41Sopenharmony_ci TNode<Object> element_maybe_smi = 14351cb0ef41Sopenharmony_ci GetProperty(context, source, source_index); 14361cb0ef41Sopenharmony_ci 14371cb0ef41Sopenharmony_ci // ii. If mapperFunction is present, then 14381cb0ef41Sopenharmony_ci if (mapper_function) { 14391cb0ef41Sopenharmony_ci CSA_DCHECK(this, Word32Or(IsUndefined(mapper_function.value()), 14401cb0ef41Sopenharmony_ci IsCallable(mapper_function.value()))); 14411cb0ef41Sopenharmony_ci DCHECK(this_arg.has_value()); 14421cb0ef41Sopenharmony_ci 14431cb0ef41Sopenharmony_ci // 1. Set element to ? Call(mapperFunction, thisArg , « element, 14441cb0ef41Sopenharmony_ci // sourceIndex, source »). 14451cb0ef41Sopenharmony_ci element_maybe_smi = 14461cb0ef41Sopenharmony_ci Call(context, mapper_function.value(), this_arg.value(), 14471cb0ef41Sopenharmony_ci element_maybe_smi, source_index, source); 14481cb0ef41Sopenharmony_ci } 14491cb0ef41Sopenharmony_ci 14501cb0ef41Sopenharmony_ci // iii. Let shouldFlatten be false. 14511cb0ef41Sopenharmony_ci Label if_flatten_array(this), if_flatten_proxy(this, Label::kDeferred), 14521cb0ef41Sopenharmony_ci if_noflatten(this); 14531cb0ef41Sopenharmony_ci // iv. If depth > 0, then 14541cb0ef41Sopenharmony_ci GotoIfNumberGreaterThanOrEqual(SmiConstant(0), depth, &if_noflatten); 14551cb0ef41Sopenharmony_ci // 1. Set shouldFlatten to ? IsArray(element). 14561cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(element_maybe_smi), &if_noflatten); 14571cb0ef41Sopenharmony_ci TNode<HeapObject> element = CAST(element_maybe_smi); 14581cb0ef41Sopenharmony_ci GotoIf(IsJSArray(element), &if_flatten_array); 14591cb0ef41Sopenharmony_ci GotoIfNot(IsJSProxy(element), &if_noflatten); 14601cb0ef41Sopenharmony_ci Branch(IsTrue(CallRuntime(Runtime::kArrayIsArray, context, element)), 14611cb0ef41Sopenharmony_ci &if_flatten_proxy, &if_noflatten); 14621cb0ef41Sopenharmony_ci 14631cb0ef41Sopenharmony_ci BIND(&if_flatten_array); 14641cb0ef41Sopenharmony_ci { 14651cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsJSArray(element)); 14661cb0ef41Sopenharmony_ci 14671cb0ef41Sopenharmony_ci // 1. Let elementLen be ? ToLength(? Get(element, "length")). 14681cb0ef41Sopenharmony_ci const TNode<Object> element_length = 14691cb0ef41Sopenharmony_ci LoadObjectField(element, JSArray::kLengthOffset); 14701cb0ef41Sopenharmony_ci 14711cb0ef41Sopenharmony_ci // 2. Set targetIndex to ? FlattenIntoArray(target, element, 14721cb0ef41Sopenharmony_ci // elementLen, targetIndex, 14731cb0ef41Sopenharmony_ci // depth - 1). 14741cb0ef41Sopenharmony_ci var_target_index = CAST( 14751cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kFlattenIntoArray, context, target, element, 14761cb0ef41Sopenharmony_ci element_length, target_index, NumberDec(depth))); 14771cb0ef41Sopenharmony_ci Goto(&next); 14781cb0ef41Sopenharmony_ci } 14791cb0ef41Sopenharmony_ci 14801cb0ef41Sopenharmony_ci BIND(&if_flatten_proxy); 14811cb0ef41Sopenharmony_ci { 14821cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsJSProxy(element)); 14831cb0ef41Sopenharmony_ci 14841cb0ef41Sopenharmony_ci // 1. Let elementLen be ? ToLength(? Get(element, "length")). 14851cb0ef41Sopenharmony_ci const TNode<Number> element_length = ToLength_Inline( 14861cb0ef41Sopenharmony_ci context, GetProperty(context, element, LengthStringConstant())); 14871cb0ef41Sopenharmony_ci 14881cb0ef41Sopenharmony_ci // 2. Set targetIndex to ? FlattenIntoArray(target, element, 14891cb0ef41Sopenharmony_ci // elementLen, targetIndex, 14901cb0ef41Sopenharmony_ci // depth - 1). 14911cb0ef41Sopenharmony_ci var_target_index = CAST( 14921cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kFlattenIntoArray, context, target, element, 14931cb0ef41Sopenharmony_ci element_length, target_index, NumberDec(depth))); 14941cb0ef41Sopenharmony_ci Goto(&next); 14951cb0ef41Sopenharmony_ci } 14961cb0ef41Sopenharmony_ci 14971cb0ef41Sopenharmony_ci BIND(&if_noflatten); 14981cb0ef41Sopenharmony_ci { 14991cb0ef41Sopenharmony_ci // 1. If targetIndex >= 2^53-1, throw a TypeError exception. 15001cb0ef41Sopenharmony_ci Label throw_error(this, Label::kDeferred); 15011cb0ef41Sopenharmony_ci GotoIfNumberGreaterThanOrEqual( 15021cb0ef41Sopenharmony_ci target_index, NumberConstant(kMaxSafeInteger), &throw_error); 15031cb0ef41Sopenharmony_ci 15041cb0ef41Sopenharmony_ci // 2. Perform ? CreateDataPropertyOrThrow(target, 15051cb0ef41Sopenharmony_ci // ! ToString(targetIndex), 15061cb0ef41Sopenharmony_ci // element). 15071cb0ef41Sopenharmony_ci CallRuntime(Runtime::kCreateDataProperty, context, target, 15081cb0ef41Sopenharmony_ci target_index, element); 15091cb0ef41Sopenharmony_ci 15101cb0ef41Sopenharmony_ci // 3. Increase targetIndex by 1. 15111cb0ef41Sopenharmony_ci var_target_index = NumberInc(target_index); 15121cb0ef41Sopenharmony_ci Goto(&next); 15131cb0ef41Sopenharmony_ci 15141cb0ef41Sopenharmony_ci BIND(&throw_error); 15151cb0ef41Sopenharmony_ci ThrowTypeError(context, MessageTemplate::kFlattenPastSafeLength, 15161cb0ef41Sopenharmony_ci source_length, target_index); 15171cb0ef41Sopenharmony_ci } 15181cb0ef41Sopenharmony_ci } 15191cb0ef41Sopenharmony_ci BIND(&next); 15201cb0ef41Sopenharmony_ci 15211cb0ef41Sopenharmony_ci // d. Increase sourceIndex by 1. 15221cb0ef41Sopenharmony_ci var_source_index = NumberInc(source_index); 15231cb0ef41Sopenharmony_ci Goto(&loop); 15241cb0ef41Sopenharmony_ci } 15251cb0ef41Sopenharmony_ci 15261cb0ef41Sopenharmony_ci BIND(&done_loop); 15271cb0ef41Sopenharmony_ci return var_target_index.value(); 15281cb0ef41Sopenharmony_ci } 15291cb0ef41Sopenharmony_ci}; 15301cb0ef41Sopenharmony_ci 15311cb0ef41Sopenharmony_ci// https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray 15321cb0ef41Sopenharmony_ciTF_BUILTIN(FlattenIntoArray, ArrayFlattenAssembler) { 15331cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 15341cb0ef41Sopenharmony_ci auto target = Parameter<JSReceiver>(Descriptor::kTarget); 15351cb0ef41Sopenharmony_ci auto source = Parameter<JSReceiver>(Descriptor::kSource); 15361cb0ef41Sopenharmony_ci auto source_length = Parameter<Number>(Descriptor::kSourceLength); 15371cb0ef41Sopenharmony_ci auto start = Parameter<Number>(Descriptor::kStart); 15381cb0ef41Sopenharmony_ci auto depth = Parameter<Number>(Descriptor::kDepth); 15391cb0ef41Sopenharmony_ci 15401cb0ef41Sopenharmony_ci // FlattenIntoArray might get called recursively, check stack for overflow 15411cb0ef41Sopenharmony_ci // manually as it has stub linkage. 15421cb0ef41Sopenharmony_ci PerformStackCheck(context); 15431cb0ef41Sopenharmony_ci 15441cb0ef41Sopenharmony_ci Return( 15451cb0ef41Sopenharmony_ci FlattenIntoArray(context, target, source, source_length, start, depth)); 15461cb0ef41Sopenharmony_ci} 15471cb0ef41Sopenharmony_ci 15481cb0ef41Sopenharmony_ci// https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray 15491cb0ef41Sopenharmony_ciTF_BUILTIN(FlatMapIntoArray, ArrayFlattenAssembler) { 15501cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 15511cb0ef41Sopenharmony_ci auto target = Parameter<JSReceiver>(Descriptor::kTarget); 15521cb0ef41Sopenharmony_ci auto source = Parameter<JSReceiver>(Descriptor::kSource); 15531cb0ef41Sopenharmony_ci auto source_length = Parameter<Number>(Descriptor::kSourceLength); 15541cb0ef41Sopenharmony_ci auto start = Parameter<Number>(Descriptor::kStart); 15551cb0ef41Sopenharmony_ci auto depth = Parameter<Number>(Descriptor::kDepth); 15561cb0ef41Sopenharmony_ci auto mapper_function = Parameter<HeapObject>(Descriptor::kMapperFunction); 15571cb0ef41Sopenharmony_ci auto this_arg = Parameter<Object>(Descriptor::kThisArg); 15581cb0ef41Sopenharmony_ci 15591cb0ef41Sopenharmony_ci Return(FlattenIntoArray(context, target, source, source_length, start, depth, 15601cb0ef41Sopenharmony_ci mapper_function, this_arg)); 15611cb0ef41Sopenharmony_ci} 15621cb0ef41Sopenharmony_ci 15631cb0ef41Sopenharmony_ci// https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flat 15641cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayPrototypeFlat, CodeStubAssembler) { 15651cb0ef41Sopenharmony_ci const TNode<IntPtrT> argc = ChangeInt32ToIntPtr( 15661cb0ef41Sopenharmony_ci UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount)); 15671cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc); 15681cb0ef41Sopenharmony_ci const auto context = Parameter<Context>(Descriptor::kContext); 15691cb0ef41Sopenharmony_ci const TNode<Object> receiver = args.GetReceiver(); 15701cb0ef41Sopenharmony_ci const TNode<Object> depth = args.GetOptionalArgumentValue(0); 15711cb0ef41Sopenharmony_ci 15721cb0ef41Sopenharmony_ci // 1. Let O be ? ToObject(this value). 15731cb0ef41Sopenharmony_ci const TNode<JSReceiver> o = ToObject_Inline(context, receiver); 15741cb0ef41Sopenharmony_ci 15751cb0ef41Sopenharmony_ci // 2. Let sourceLen be ? ToLength(? Get(O, "length")). 15761cb0ef41Sopenharmony_ci const TNode<Number> source_length = 15771cb0ef41Sopenharmony_ci ToLength_Inline(context, GetProperty(context, o, LengthStringConstant())); 15781cb0ef41Sopenharmony_ci 15791cb0ef41Sopenharmony_ci // 3. Let depthNum be 1. 15801cb0ef41Sopenharmony_ci TVARIABLE(Number, var_depth_num, SmiConstant(1)); 15811cb0ef41Sopenharmony_ci 15821cb0ef41Sopenharmony_ci // 4. If depth is not undefined, then 15831cb0ef41Sopenharmony_ci Label done(this); 15841cb0ef41Sopenharmony_ci GotoIf(IsUndefined(depth), &done); 15851cb0ef41Sopenharmony_ci { 15861cb0ef41Sopenharmony_ci // a. Set depthNum to ? ToInteger(depth). 15871cb0ef41Sopenharmony_ci var_depth_num = ToInteger_Inline(context, depth); 15881cb0ef41Sopenharmony_ci Goto(&done); 15891cb0ef41Sopenharmony_ci } 15901cb0ef41Sopenharmony_ci BIND(&done); 15911cb0ef41Sopenharmony_ci 15921cb0ef41Sopenharmony_ci // 5. Let A be ? ArraySpeciesCreate(O, 0). 15931cb0ef41Sopenharmony_ci const TNode<JSReceiver> constructor = 15941cb0ef41Sopenharmony_ci CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context, o)); 15951cb0ef41Sopenharmony_ci const TNode<JSReceiver> a = Construct(context, constructor, SmiConstant(0)); 15961cb0ef41Sopenharmony_ci 15971cb0ef41Sopenharmony_ci // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum). 15981cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kFlattenIntoArray, context, a, o, source_length, 15991cb0ef41Sopenharmony_ci SmiConstant(0), var_depth_num.value()); 16001cb0ef41Sopenharmony_ci 16011cb0ef41Sopenharmony_ci // 7. Return A. 16021cb0ef41Sopenharmony_ci args.PopAndReturn(a); 16031cb0ef41Sopenharmony_ci} 16041cb0ef41Sopenharmony_ci 16051cb0ef41Sopenharmony_ci// https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap 16061cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayPrototypeFlatMap, CodeStubAssembler) { 16071cb0ef41Sopenharmony_ci const TNode<IntPtrT> argc = ChangeInt32ToIntPtr( 16081cb0ef41Sopenharmony_ci UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount)); 16091cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc); 16101cb0ef41Sopenharmony_ci const auto context = Parameter<Context>(Descriptor::kContext); 16111cb0ef41Sopenharmony_ci const TNode<Object> receiver = args.GetReceiver(); 16121cb0ef41Sopenharmony_ci const TNode<Object> mapper_function = args.GetOptionalArgumentValue(0); 16131cb0ef41Sopenharmony_ci 16141cb0ef41Sopenharmony_ci // 1. Let O be ? ToObject(this value). 16151cb0ef41Sopenharmony_ci const TNode<JSReceiver> o = ToObject_Inline(context, receiver); 16161cb0ef41Sopenharmony_ci 16171cb0ef41Sopenharmony_ci // 2. Let sourceLen be ? ToLength(? Get(O, "length")). 16181cb0ef41Sopenharmony_ci const TNode<Number> source_length = 16191cb0ef41Sopenharmony_ci ToLength_Inline(context, GetProperty(context, o, LengthStringConstant())); 16201cb0ef41Sopenharmony_ci 16211cb0ef41Sopenharmony_ci // 3. If IsCallable(mapperFunction) is false, throw a TypeError exception. 16221cb0ef41Sopenharmony_ci Label if_not_callable(this, Label::kDeferred); 16231cb0ef41Sopenharmony_ci GotoIf(TaggedIsSmi(mapper_function), &if_not_callable); 16241cb0ef41Sopenharmony_ci GotoIfNot(IsCallable(CAST(mapper_function)), &if_not_callable); 16251cb0ef41Sopenharmony_ci 16261cb0ef41Sopenharmony_ci // 4. If thisArg is present, let T be thisArg; else let T be undefined. 16271cb0ef41Sopenharmony_ci const TNode<Object> t = args.GetOptionalArgumentValue(1); 16281cb0ef41Sopenharmony_ci 16291cb0ef41Sopenharmony_ci // 5. Let A be ? ArraySpeciesCreate(O, 0). 16301cb0ef41Sopenharmony_ci const TNode<JSReceiver> constructor = 16311cb0ef41Sopenharmony_ci CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context, o)); 16321cb0ef41Sopenharmony_ci const TNode<JSReceiver> a = Construct(context, constructor, SmiConstant(0)); 16331cb0ef41Sopenharmony_ci 16341cb0ef41Sopenharmony_ci // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T). 16351cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kFlatMapIntoArray, context, a, o, source_length, 16361cb0ef41Sopenharmony_ci SmiConstant(0), SmiConstant(1), mapper_function, t); 16371cb0ef41Sopenharmony_ci 16381cb0ef41Sopenharmony_ci // 7. Return A. 16391cb0ef41Sopenharmony_ci args.PopAndReturn(a); 16401cb0ef41Sopenharmony_ci 16411cb0ef41Sopenharmony_ci BIND(&if_not_callable); 16421cb0ef41Sopenharmony_ci { ThrowTypeError(context, MessageTemplate::kMapperFunctionNonCallable); } 16431cb0ef41Sopenharmony_ci} 16441cb0ef41Sopenharmony_ci 16451cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayConstructor, ArrayBuiltinsAssembler) { 16461cb0ef41Sopenharmony_ci // This is a trampoline to ArrayConstructorImpl which just adds 16471cb0ef41Sopenharmony_ci // allocation_site parameter value and sets new_target if necessary. 16481cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 16491cb0ef41Sopenharmony_ci auto function = Parameter<JSFunction>(Descriptor::kTarget); 16501cb0ef41Sopenharmony_ci auto new_target = Parameter<Object>(Descriptor::kNewTarget); 16511cb0ef41Sopenharmony_ci auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount); 16521cb0ef41Sopenharmony_ci 16531cb0ef41Sopenharmony_ci // If new_target is undefined, then this is the 'Call' case, so set new_target 16541cb0ef41Sopenharmony_ci // to function. 16551cb0ef41Sopenharmony_ci new_target = 16561cb0ef41Sopenharmony_ci SelectConstant<Object>(IsUndefined(new_target), function, new_target); 16571cb0ef41Sopenharmony_ci 16581cb0ef41Sopenharmony_ci // Run the native code for the Array function called as a normal function. 16591cb0ef41Sopenharmony_ci TNode<Oddball> no_gc_site = UndefinedConstant(); 16601cb0ef41Sopenharmony_ci TailCallBuiltin(Builtin::kArrayConstructorImpl, context, function, new_target, 16611cb0ef41Sopenharmony_ci argc, no_gc_site); 16621cb0ef41Sopenharmony_ci} 16631cb0ef41Sopenharmony_ci 16641cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::TailCallArrayConstructorStub( 16651cb0ef41Sopenharmony_ci const Callable& callable, TNode<Context> context, TNode<JSFunction> target, 16661cb0ef41Sopenharmony_ci TNode<HeapObject> allocation_site_or_undefined, TNode<Int32T> argc) { 16671cb0ef41Sopenharmony_ci TNode<CodeT> code = HeapConstant(callable.code()); 16681cb0ef41Sopenharmony_ci 16691cb0ef41Sopenharmony_ci // We are going to call here ArrayNoArgumentsConstructor or 16701cb0ef41Sopenharmony_ci // ArraySingleArgumentsConstructor which in addition to the register arguments 16711cb0ef41Sopenharmony_ci // also expect some number of arguments on the expression stack. 16721cb0ef41Sopenharmony_ci // Since 16731cb0ef41Sopenharmony_ci // 1) incoming JS arguments are still on the stack, 16741cb0ef41Sopenharmony_ci // 2) the ArrayNoArgumentsConstructor, ArraySingleArgumentsConstructor and 16751cb0ef41Sopenharmony_ci // ArrayNArgumentsConstructor are defined so that the register arguments 16761cb0ef41Sopenharmony_ci // are passed on the same registers, 16771cb0ef41Sopenharmony_ci // in order to be able to generate a tail call to those builtins we do the 16781cb0ef41Sopenharmony_ci // following trick here: we tail call to the constructor builtin using 16791cb0ef41Sopenharmony_ci // ArrayNArgumentsConstructorDescriptor, so the tail call instruction 16801cb0ef41Sopenharmony_ci // pops the current frame but leaves all the incoming JS arguments on the 16811cb0ef41Sopenharmony_ci // expression stack so that the target builtin can still find them where it 16821cb0ef41Sopenharmony_ci // expects. 16831cb0ef41Sopenharmony_ci TailCallStub(ArrayNArgumentsConstructorDescriptor{}, code, context, target, 16841cb0ef41Sopenharmony_ci allocation_site_or_undefined, argc); 16851cb0ef41Sopenharmony_ci} 16861cb0ef41Sopenharmony_ci 16871cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument( 16881cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, 16891cb0ef41Sopenharmony_ci AllocationSiteOverrideMode mode, 16901cb0ef41Sopenharmony_ci base::Optional<TNode<AllocationSite>> allocation_site) { 16911cb0ef41Sopenharmony_ci if (mode == DISABLE_ALLOCATION_SITES) { 16921cb0ef41Sopenharmony_ci Callable callable = CodeFactory::ArrayNoArgumentConstructor( 16931cb0ef41Sopenharmony_ci isolate(), GetInitialFastElementsKind(), mode); 16941cb0ef41Sopenharmony_ci 16951cb0ef41Sopenharmony_ci TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(), 16961cb0ef41Sopenharmony_ci argc); 16971cb0ef41Sopenharmony_ci } else { 16981cb0ef41Sopenharmony_ci DCHECK_EQ(mode, DONT_OVERRIDE); 16991cb0ef41Sopenharmony_ci DCHECK(allocation_site); 17001cb0ef41Sopenharmony_ci TNode<Int32T> elements_kind = LoadElementsKind(*allocation_site); 17011cb0ef41Sopenharmony_ci 17021cb0ef41Sopenharmony_ci // TODO(ishell): Compute the builtin index dynamically instead of 17031cb0ef41Sopenharmony_ci // iterating over all expected elements kinds. 17041cb0ef41Sopenharmony_ci int last_index = 17051cb0ef41Sopenharmony_ci GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); 17061cb0ef41Sopenharmony_ci for (int i = 0; i <= last_index; ++i) { 17071cb0ef41Sopenharmony_ci Label next(this); 17081cb0ef41Sopenharmony_ci ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); 17091cb0ef41Sopenharmony_ci GotoIfNot(Word32Equal(elements_kind, Int32Constant(kind)), &next); 17101cb0ef41Sopenharmony_ci 17111cb0ef41Sopenharmony_ci Callable callable = 17121cb0ef41Sopenharmony_ci CodeFactory::ArrayNoArgumentConstructor(isolate(), kind, mode); 17131cb0ef41Sopenharmony_ci 17141cb0ef41Sopenharmony_ci TailCallArrayConstructorStub(callable, context, target, *allocation_site, 17151cb0ef41Sopenharmony_ci argc); 17161cb0ef41Sopenharmony_ci 17171cb0ef41Sopenharmony_ci BIND(&next); 17181cb0ef41Sopenharmony_ci } 17191cb0ef41Sopenharmony_ci 17201cb0ef41Sopenharmony_ci // If we reached this point there is a problem. 17211cb0ef41Sopenharmony_ci Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor); 17221cb0ef41Sopenharmony_ci } 17231cb0ef41Sopenharmony_ci} 17241cb0ef41Sopenharmony_ci 17251cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument( 17261cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, 17271cb0ef41Sopenharmony_ci AllocationSiteOverrideMode mode, 17281cb0ef41Sopenharmony_ci base::Optional<TNode<AllocationSite>> allocation_site) { 17291cb0ef41Sopenharmony_ci if (mode == DISABLE_ALLOCATION_SITES) { 17301cb0ef41Sopenharmony_ci ElementsKind initial = GetInitialFastElementsKind(); 17311cb0ef41Sopenharmony_ci ElementsKind holey_initial = GetHoleyElementsKind(initial); 17321cb0ef41Sopenharmony_ci Callable callable = CodeFactory::ArraySingleArgumentConstructor( 17331cb0ef41Sopenharmony_ci isolate(), holey_initial, mode); 17341cb0ef41Sopenharmony_ci 17351cb0ef41Sopenharmony_ci TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(), 17361cb0ef41Sopenharmony_ci argc); 17371cb0ef41Sopenharmony_ci } else { 17381cb0ef41Sopenharmony_ci DCHECK_EQ(mode, DONT_OVERRIDE); 17391cb0ef41Sopenharmony_ci DCHECK(allocation_site); 17401cb0ef41Sopenharmony_ci TNode<Smi> transition_info = LoadTransitionInfo(*allocation_site); 17411cb0ef41Sopenharmony_ci 17421cb0ef41Sopenharmony_ci // Least significant bit in fast array elements kind means holeyness. 17431cb0ef41Sopenharmony_ci STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0); 17441cb0ef41Sopenharmony_ci STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1); 17451cb0ef41Sopenharmony_ci STATIC_ASSERT(PACKED_ELEMENTS == 2); 17461cb0ef41Sopenharmony_ci STATIC_ASSERT(HOLEY_ELEMENTS == 3); 17471cb0ef41Sopenharmony_ci STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4); 17481cb0ef41Sopenharmony_ci STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5); 17491cb0ef41Sopenharmony_ci 17501cb0ef41Sopenharmony_ci Label normal_sequence(this); 17511cb0ef41Sopenharmony_ci TVARIABLE(Int32T, var_elements_kind, 17521cb0ef41Sopenharmony_ci Signed(DecodeWord32<AllocationSite::ElementsKindBits>( 17531cb0ef41Sopenharmony_ci SmiToInt32(transition_info)))); 17541cb0ef41Sopenharmony_ci // Is the low bit set? If so, we are holey and that is good. 17551cb0ef41Sopenharmony_ci int fast_elements_kind_holey_mask = 17561cb0ef41Sopenharmony_ci AllocationSite::ElementsKindBits::encode(static_cast<ElementsKind>(1)); 17571cb0ef41Sopenharmony_ci GotoIf(IsSetSmi(transition_info, fast_elements_kind_holey_mask), 17581cb0ef41Sopenharmony_ci &normal_sequence); 17591cb0ef41Sopenharmony_ci { 17601cb0ef41Sopenharmony_ci // Make elements kind holey and update elements kind in the type info. 17611cb0ef41Sopenharmony_ci var_elements_kind = Word32Or(var_elements_kind.value(), Int32Constant(1)); 17621cb0ef41Sopenharmony_ci StoreObjectFieldNoWriteBarrier( 17631cb0ef41Sopenharmony_ci *allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset, 17641cb0ef41Sopenharmony_ci SmiOr(transition_info, SmiConstant(fast_elements_kind_holey_mask))); 17651cb0ef41Sopenharmony_ci Goto(&normal_sequence); 17661cb0ef41Sopenharmony_ci } 17671cb0ef41Sopenharmony_ci BIND(&normal_sequence); 17681cb0ef41Sopenharmony_ci 17691cb0ef41Sopenharmony_ci // TODO(ishell): Compute the builtin index dynamically instead of 17701cb0ef41Sopenharmony_ci // iterating over all expected elements kinds. 17711cb0ef41Sopenharmony_ci // TODO(ishell): Given that the code above ensures that the elements kind 17721cb0ef41Sopenharmony_ci // is holey we can skip checking with non-holey elements kinds. 17731cb0ef41Sopenharmony_ci int last_index = 17741cb0ef41Sopenharmony_ci GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND); 17751cb0ef41Sopenharmony_ci for (int i = 0; i <= last_index; ++i) { 17761cb0ef41Sopenharmony_ci Label next(this); 17771cb0ef41Sopenharmony_ci ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); 17781cb0ef41Sopenharmony_ci GotoIfNot(Word32Equal(var_elements_kind.value(), Int32Constant(kind)), 17791cb0ef41Sopenharmony_ci &next); 17801cb0ef41Sopenharmony_ci 17811cb0ef41Sopenharmony_ci Callable callable = 17821cb0ef41Sopenharmony_ci CodeFactory::ArraySingleArgumentConstructor(isolate(), kind, mode); 17831cb0ef41Sopenharmony_ci 17841cb0ef41Sopenharmony_ci TailCallArrayConstructorStub(callable, context, target, *allocation_site, 17851cb0ef41Sopenharmony_ci argc); 17861cb0ef41Sopenharmony_ci 17871cb0ef41Sopenharmony_ci BIND(&next); 17881cb0ef41Sopenharmony_ci } 17891cb0ef41Sopenharmony_ci 17901cb0ef41Sopenharmony_ci // If we reached this point there is a problem. 17911cb0ef41Sopenharmony_ci Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor); 17921cb0ef41Sopenharmony_ci } 17931cb0ef41Sopenharmony_ci} 17941cb0ef41Sopenharmony_ci 17951cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::GenerateDispatchToArrayStub( 17961cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc, 17971cb0ef41Sopenharmony_ci AllocationSiteOverrideMode mode, 17981cb0ef41Sopenharmony_ci base::Optional<TNode<AllocationSite>> allocation_site) { 17991cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc); 18001cb0ef41Sopenharmony_ci Label check_one_case(this), fallthrough(this); 18011cb0ef41Sopenharmony_ci GotoIfNot(IntPtrEqual(args.GetLengthWithoutReceiver(), IntPtrConstant(0)), 18021cb0ef41Sopenharmony_ci &check_one_case); 18031cb0ef41Sopenharmony_ci CreateArrayDispatchNoArgument(context, target, argc, mode, allocation_site); 18041cb0ef41Sopenharmony_ci 18051cb0ef41Sopenharmony_ci BIND(&check_one_case); 18061cb0ef41Sopenharmony_ci GotoIfNot(IntPtrEqual(args.GetLengthWithoutReceiver(), IntPtrConstant(1)), 18071cb0ef41Sopenharmony_ci &fallthrough); 18081cb0ef41Sopenharmony_ci CreateArrayDispatchSingleArgument(context, target, argc, mode, 18091cb0ef41Sopenharmony_ci allocation_site); 18101cb0ef41Sopenharmony_ci 18111cb0ef41Sopenharmony_ci BIND(&fallthrough); 18121cb0ef41Sopenharmony_ci} 18131cb0ef41Sopenharmony_ci 18141cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayConstructorImpl, ArrayBuiltinsAssembler) { 18151cb0ef41Sopenharmony_ci auto target = Parameter<JSFunction>(Descriptor::kTarget); 18161cb0ef41Sopenharmony_ci auto new_target = Parameter<Object>(Descriptor::kNewTarget); 18171cb0ef41Sopenharmony_ci auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount); 18181cb0ef41Sopenharmony_ci auto maybe_allocation_site = 18191cb0ef41Sopenharmony_ci Parameter<HeapObject>(Descriptor::kAllocationSite); 18201cb0ef41Sopenharmony_ci 18211cb0ef41Sopenharmony_ci // Initial map for the builtin Array functions should be Map. 18221cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsMap(CAST(LoadObjectField( 18231cb0ef41Sopenharmony_ci target, JSFunction::kPrototypeOrInitialMapOffset)))); 18241cb0ef41Sopenharmony_ci 18251cb0ef41Sopenharmony_ci // We should either have undefined or a valid AllocationSite 18261cb0ef41Sopenharmony_ci CSA_DCHECK(this, Word32Or(IsUndefined(maybe_allocation_site), 18271cb0ef41Sopenharmony_ci IsAllocationSite(maybe_allocation_site))); 18281cb0ef41Sopenharmony_ci 18291cb0ef41Sopenharmony_ci // "Enter" the context of the Array function. 18301cb0ef41Sopenharmony_ci TNode<Context> context = 18311cb0ef41Sopenharmony_ci CAST(LoadObjectField(target, JSFunction::kContextOffset)); 18321cb0ef41Sopenharmony_ci 18331cb0ef41Sopenharmony_ci Label runtime(this, Label::kDeferred); 18341cb0ef41Sopenharmony_ci GotoIf(TaggedNotEqual(target, new_target), &runtime); 18351cb0ef41Sopenharmony_ci 18361cb0ef41Sopenharmony_ci Label no_info(this); 18371cb0ef41Sopenharmony_ci // If the feedback vector is the undefined value call an array constructor 18381cb0ef41Sopenharmony_ci // that doesn't use AllocationSites. 18391cb0ef41Sopenharmony_ci GotoIf(IsUndefined(maybe_allocation_site), &no_info); 18401cb0ef41Sopenharmony_ci 18411cb0ef41Sopenharmony_ci GenerateDispatchToArrayStub(context, target, argc, DONT_OVERRIDE, 18421cb0ef41Sopenharmony_ci CAST(maybe_allocation_site)); 18431cb0ef41Sopenharmony_ci Goto(&runtime); 18441cb0ef41Sopenharmony_ci 18451cb0ef41Sopenharmony_ci BIND(&no_info); 18461cb0ef41Sopenharmony_ci GenerateDispatchToArrayStub(context, target, argc, DISABLE_ALLOCATION_SITES); 18471cb0ef41Sopenharmony_ci Goto(&runtime); 18481cb0ef41Sopenharmony_ci 18491cb0ef41Sopenharmony_ci BIND(&runtime); 18501cb0ef41Sopenharmony_ci GenerateArrayNArgumentsConstructor(context, target, new_target, argc, 18511cb0ef41Sopenharmony_ci maybe_allocation_site); 18521cb0ef41Sopenharmony_ci} 18531cb0ef41Sopenharmony_ci 18541cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::GenerateConstructor( 18551cb0ef41Sopenharmony_ci TNode<Context> context, TNode<HeapObject> array_function, 18561cb0ef41Sopenharmony_ci TNode<Map> array_map, TNode<Object> array_size, 18571cb0ef41Sopenharmony_ci TNode<HeapObject> allocation_site, ElementsKind elements_kind, 18581cb0ef41Sopenharmony_ci AllocationSiteMode mode) { 18591cb0ef41Sopenharmony_ci Label ok(this); 18601cb0ef41Sopenharmony_ci Label smi_size(this); 18611cb0ef41Sopenharmony_ci Label small_smi_size(this); 18621cb0ef41Sopenharmony_ci Label call_runtime(this, Label::kDeferred); 18631cb0ef41Sopenharmony_ci 18641cb0ef41Sopenharmony_ci Branch(TaggedIsSmi(array_size), &smi_size, &call_runtime); 18651cb0ef41Sopenharmony_ci 18661cb0ef41Sopenharmony_ci BIND(&smi_size); 18671cb0ef41Sopenharmony_ci { 18681cb0ef41Sopenharmony_ci TNode<Smi> array_size_smi = CAST(array_size); 18691cb0ef41Sopenharmony_ci 18701cb0ef41Sopenharmony_ci if (IsFastPackedElementsKind(elements_kind)) { 18711cb0ef41Sopenharmony_ci Label abort(this, Label::kDeferred); 18721cb0ef41Sopenharmony_ci Branch(SmiEqual(array_size_smi, SmiConstant(0)), &small_smi_size, &abort); 18731cb0ef41Sopenharmony_ci 18741cb0ef41Sopenharmony_ci BIND(&abort); 18751cb0ef41Sopenharmony_ci TNode<Smi> reason = 18761cb0ef41Sopenharmony_ci SmiConstant(AbortReason::kAllocatingNonEmptyPackedArray); 18771cb0ef41Sopenharmony_ci TailCallRuntime(Runtime::kAbort, context, reason); 18781cb0ef41Sopenharmony_ci } else { 18791cb0ef41Sopenharmony_ci Branch(SmiAboveOrEqual(array_size_smi, 18801cb0ef41Sopenharmony_ci SmiConstant(JSArray::kInitialMaxFastElementArray)), 18811cb0ef41Sopenharmony_ci &call_runtime, &small_smi_size); 18821cb0ef41Sopenharmony_ci } 18831cb0ef41Sopenharmony_ci 18841cb0ef41Sopenharmony_ci BIND(&small_smi_size); 18851cb0ef41Sopenharmony_ci { 18861cb0ef41Sopenharmony_ci TNode<JSArray> array = AllocateJSArray( 18871cb0ef41Sopenharmony_ci elements_kind, array_map, array_size_smi, array_size_smi, 18881cb0ef41Sopenharmony_ci mode == DONT_TRACK_ALLOCATION_SITE 18891cb0ef41Sopenharmony_ci ? base::Optional<TNode<AllocationSite>>(base::nullopt) 18901cb0ef41Sopenharmony_ci : CAST(allocation_site)); 18911cb0ef41Sopenharmony_ci Return(array); 18921cb0ef41Sopenharmony_ci } 18931cb0ef41Sopenharmony_ci } 18941cb0ef41Sopenharmony_ci 18951cb0ef41Sopenharmony_ci BIND(&call_runtime); 18961cb0ef41Sopenharmony_ci { 18971cb0ef41Sopenharmony_ci TailCallRuntimeNewArray(context, array_function, array_size, array_function, 18981cb0ef41Sopenharmony_ci allocation_site); 18991cb0ef41Sopenharmony_ci } 19001cb0ef41Sopenharmony_ci} 19011cb0ef41Sopenharmony_ci 19021cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::GenerateArrayNoArgumentConstructor( 19031cb0ef41Sopenharmony_ci ElementsKind kind, AllocationSiteOverrideMode mode) { 19041cb0ef41Sopenharmony_ci using Descriptor = ArrayNoArgumentConstructorDescriptor; 19051cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadObjectField<NativeContext>( 19061cb0ef41Sopenharmony_ci Parameter<HeapObject>(Descriptor::kFunction), JSFunction::kContextOffset); 19071cb0ef41Sopenharmony_ci bool track_allocation_site = 19081cb0ef41Sopenharmony_ci AllocationSite::ShouldTrack(kind) && mode != DISABLE_ALLOCATION_SITES; 19091cb0ef41Sopenharmony_ci base::Optional<TNode<AllocationSite>> allocation_site = 19101cb0ef41Sopenharmony_ci track_allocation_site 19111cb0ef41Sopenharmony_ci ? Parameter<AllocationSite>(Descriptor::kAllocationSite) 19121cb0ef41Sopenharmony_ci : base::Optional<TNode<AllocationSite>>(base::nullopt); 19131cb0ef41Sopenharmony_ci TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context); 19141cb0ef41Sopenharmony_ci TNode<JSArray> array = AllocateJSArray( 19151cb0ef41Sopenharmony_ci kind, array_map, IntPtrConstant(JSArray::kPreallocatedArrayElements), 19161cb0ef41Sopenharmony_ci SmiConstant(0), allocation_site); 19171cb0ef41Sopenharmony_ci Return(array); 19181cb0ef41Sopenharmony_ci} 19191cb0ef41Sopenharmony_ci 19201cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::GenerateArraySingleArgumentConstructor( 19211cb0ef41Sopenharmony_ci ElementsKind kind, AllocationSiteOverrideMode mode) { 19221cb0ef41Sopenharmony_ci using Descriptor = ArraySingleArgumentConstructorDescriptor; 19231cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 19241cb0ef41Sopenharmony_ci auto function = Parameter<HeapObject>(Descriptor::kFunction); 19251cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = 19261cb0ef41Sopenharmony_ci CAST(LoadObjectField(function, JSFunction::kContextOffset)); 19271cb0ef41Sopenharmony_ci TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context); 19281cb0ef41Sopenharmony_ci 19291cb0ef41Sopenharmony_ci AllocationSiteMode allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; 19301cb0ef41Sopenharmony_ci if (mode == DONT_OVERRIDE) { 19311cb0ef41Sopenharmony_ci allocation_site_mode = AllocationSite::ShouldTrack(kind) 19321cb0ef41Sopenharmony_ci ? TRACK_ALLOCATION_SITE 19331cb0ef41Sopenharmony_ci : DONT_TRACK_ALLOCATION_SITE; 19341cb0ef41Sopenharmony_ci } 19351cb0ef41Sopenharmony_ci 19361cb0ef41Sopenharmony_ci auto array_size = Parameter<Object>(Descriptor::kArraySizeSmiParameter); 19371cb0ef41Sopenharmony_ci // allocation_site can be Undefined or an AllocationSite 19381cb0ef41Sopenharmony_ci auto allocation_site = Parameter<HeapObject>(Descriptor::kAllocationSite); 19391cb0ef41Sopenharmony_ci 19401cb0ef41Sopenharmony_ci GenerateConstructor(context, function, array_map, array_size, allocation_site, 19411cb0ef41Sopenharmony_ci kind, allocation_site_mode); 19421cb0ef41Sopenharmony_ci} 19431cb0ef41Sopenharmony_ci 19441cb0ef41Sopenharmony_civoid ArrayBuiltinsAssembler::GenerateArrayNArgumentsConstructor( 19451cb0ef41Sopenharmony_ci TNode<Context> context, TNode<JSFunction> target, TNode<Object> new_target, 19461cb0ef41Sopenharmony_ci TNode<Int32T> argc, TNode<HeapObject> maybe_allocation_site) { 19471cb0ef41Sopenharmony_ci // Replace incoming JS receiver argument with the target. 19481cb0ef41Sopenharmony_ci // TODO(ishell): Avoid replacing the target on the stack and just add it 19491cb0ef41Sopenharmony_ci // as another additional parameter for Runtime::kNewArray. 19501cb0ef41Sopenharmony_ci CodeStubArguments args(this, argc); 19511cb0ef41Sopenharmony_ci args.SetReceiver(target); 19521cb0ef41Sopenharmony_ci 19531cb0ef41Sopenharmony_ci // Adjust arguments count for the runtime call: 19541cb0ef41Sopenharmony_ci // +2 for new_target and maybe_allocation_site. 19551cb0ef41Sopenharmony_ci argc = Int32Add(TruncateIntPtrToInt32(args.GetLengthWithReceiver()), 19561cb0ef41Sopenharmony_ci Int32Constant(2)); 19571cb0ef41Sopenharmony_ci TailCallRuntime(Runtime::kNewArray, argc, context, new_target, 19581cb0ef41Sopenharmony_ci maybe_allocation_site); 19591cb0ef41Sopenharmony_ci} 19601cb0ef41Sopenharmony_ci 19611cb0ef41Sopenharmony_ciTF_BUILTIN(ArrayNArgumentsConstructor, ArrayBuiltinsAssembler) { 19621cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 19631cb0ef41Sopenharmony_ci auto target = Parameter<JSFunction>(Descriptor::kFunction); 19641cb0ef41Sopenharmony_ci auto argc = UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount); 19651cb0ef41Sopenharmony_ci auto maybe_allocation_site = 19661cb0ef41Sopenharmony_ci Parameter<HeapObject>(Descriptor::kAllocationSite); 19671cb0ef41Sopenharmony_ci 19681cb0ef41Sopenharmony_ci GenerateArrayNArgumentsConstructor(context, target, target, argc, 19691cb0ef41Sopenharmony_ci maybe_allocation_site); 19701cb0ef41Sopenharmony_ci} 19711cb0ef41Sopenharmony_ci 19721cb0ef41Sopenharmony_ci#define GENERATE_ARRAY_CTOR(name, kind_camel, kind_caps, mode_camel, \ 19731cb0ef41Sopenharmony_ci mode_caps) \ 19741cb0ef41Sopenharmony_ci TF_BUILTIN(Array##name##Constructor_##kind_camel##_##mode_camel, \ 19751cb0ef41Sopenharmony_ci ArrayBuiltinsAssembler) { \ 19761cb0ef41Sopenharmony_ci GenerateArray##name##Constructor(kind_caps, mode_caps); \ 19771cb0ef41Sopenharmony_ci } 19781cb0ef41Sopenharmony_ci 19791cb0ef41Sopenharmony_ci// The ArrayNoArgumentConstructor builtin family. 19801cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS, DontOverride, 19811cb0ef41Sopenharmony_ci DONT_OVERRIDE) 19821cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride, 19831cb0ef41Sopenharmony_ci DONT_OVERRIDE) 19841cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS, 19851cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 19861cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS, 19871cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 19881cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(NoArgument, Packed, PACKED_ELEMENTS, DisableAllocationSites, 19891cb0ef41Sopenharmony_ci DISABLE_ALLOCATION_SITES) 19901cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(NoArgument, Holey, HOLEY_ELEMENTS, DisableAllocationSites, 19911cb0ef41Sopenharmony_ci DISABLE_ALLOCATION_SITES) 19921cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(NoArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS, 19931cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 19941cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(NoArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS, 19951cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 19961cb0ef41Sopenharmony_ci 19971cb0ef41Sopenharmony_ci// The ArraySingleArgumentConstructor builtin family. 19981cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS, 19991cb0ef41Sopenharmony_ci DontOverride, DONT_OVERRIDE) 20001cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride, 20011cb0ef41Sopenharmony_ci DONT_OVERRIDE) 20021cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS, 20031cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 20041cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS, 20051cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 20061cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(SingleArgument, Packed, PACKED_ELEMENTS, 20071cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 20081cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(SingleArgument, Holey, HOLEY_ELEMENTS, 20091cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 20101cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(SingleArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS, 20111cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 20121cb0ef41Sopenharmony_ciGENERATE_ARRAY_CTOR(SingleArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS, 20131cb0ef41Sopenharmony_ci DisableAllocationSites, DISABLE_ALLOCATION_SITES) 20141cb0ef41Sopenharmony_ci 20151cb0ef41Sopenharmony_ci#undef GENERATE_ARRAY_CTOR 20161cb0ef41Sopenharmony_ci 20171cb0ef41Sopenharmony_ci} // namespace internal 20181cb0ef41Sopenharmony_ci} // namespace v8 2019