LCOV - code coverage report
Current view: top level - src/builtins - builtins-array-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1177 1219 96.6 %
Date: 2019-03-21 Functions: 238 240 99.2 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-array-gen.h"
       6             : 
       7             : #include "src/builtins/builtins-iterator-gen.h"
       8             : #include "src/builtins/builtins-string-gen.h"
       9             : #include "src/builtins/builtins-typed-array-gen.h"
      10             : #include "src/builtins/builtins-utils-gen.h"
      11             : #include "src/builtins/builtins.h"
      12             : #include "src/code-stub-assembler.h"
      13             : #include "src/frame-constants.h"
      14             : #include "src/heap/factory-inl.h"
      15             : #include "src/objects/allocation-site-inl.h"
      16             : #include "src/objects/arguments-inl.h"
      17             : #include "src/objects/property-cell.h"
      18             : #include "torque-generated/builtins-typed-array-createtypedarray-from-dsl-gen.h"
      19             : 
      20             : namespace v8 {
      21             : namespace internal {
      22             : 
      23             : using Node = compiler::Node;
      24             : using IteratorRecord = IteratorBuiltinsFromDSLAssembler::IteratorRecord;
      25             : 
      26        1568 : ArrayBuiltinsAssembler::ArrayBuiltinsAssembler(
      27             :     compiler::CodeAssemblerState* state)
      28             :     : CodeStubAssembler(state),
      29             :       k_(this, MachineRepresentation::kTagged),
      30             :       a_(this, MachineRepresentation::kTagged),
      31        3136 :       to_(this, MachineRepresentation::kTagged, SmiConstant(0)),
      32        4704 :       fully_spec_compliant_(this, {&k_, &a_, &to_}) {}
      33             : 
      34          56 :   void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() {
      35             :     // 6. Let A be ? TypedArraySpeciesCreate(O, len).
      36          56 :     TNode<JSTypedArray> original_array = CAST(o());
      37          56 :     TNode<Smi> length = CAST(len_);
      38          56 :     const char* method_name = "%TypedArray%.prototype.map";
      39             : 
      40         112 :     TypedArrayCreatetypedarrayBuiltinsFromDSLAssembler typedarray_asm(state());
      41             :     TNode<JSTypedArray> a = typedarray_asm.TypedArraySpeciesCreateByLength(
      42          56 :         context(), method_name, original_array, length);
      43             :     // In the Spec and our current implementation, the length check is already
      44             :     // performed in TypedArraySpeciesCreate.
      45             :     CSA_ASSERT(this, SmiLessThanOrEqual(CAST(len_), LoadJSTypedArrayLength(a)));
      46          56 :     fast_typed_array_target_ =
      47         224 :         Word32Equal(LoadInstanceType(LoadElements(original_array)),
      48         280 :                     LoadInstanceType(LoadElements(a)));
      49          56 :     a_.Bind(a);
      50          56 :   }
      51             : 
      52             :   // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map.
      53         616 :   Node* ArrayBuiltinsAssembler::TypedArrayMapProcessor(Node* k_value, Node* k) {
      54             :     // 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »).
      55        1232 :     Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
      56         616 :                                 callbackfn(), this_arg(), k_value, k, o());
      57        1232 :     Label fast(this), slow(this), done(this), detached(this, Label::kDeferred);
      58             : 
      59             :     // 8. d. Perform ? Set(A, Pk, mapped_value, true).
      60             :     // Since we know that A is a TypedArray, this always ends up in
      61             :     // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then
      62             :     // tc39.github.io/ecma262/#sec-integerindexedelementset .
      63         616 :     Branch(fast_typed_array_target_, &fast, &slow);
      64             : 
      65         616 :     BIND(&fast);
      66             :     // #sec-integerindexedelementset
      67             :     // 5. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let
      68             :     // numValue be ? ToBigInt(v).
      69             :     // 6. Otherwise, let numValue be ? ToNumber(value).
      70             :     Node* num_value;
      71        1176 :     if (source_elements_kind_ == BIGINT64_ELEMENTS ||
      72         560 :         source_elements_kind_ == BIGUINT64_ELEMENTS) {
      73         112 :       num_value = ToBigInt(context(), mapped_value);
      74             :     } else {
      75         504 :       num_value = ToNumber_Inline(context(), mapped_value);
      76             :     }
      77             :     // The only way how this can bailout is because of a detached buffer.
      78         616 :     EmitElementStore(a(), k, num_value, source_elements_kind_,
      79             :                      KeyedAccessStoreMode::STANDARD_STORE, &detached,
      80        1232 :                      context());
      81         616 :     Goto(&done);
      82             : 
      83         616 :     BIND(&slow);
      84         616 :     SetPropertyStrict(context(), CAST(a()), CAST(k), CAST(mapped_value));
      85         616 :     Goto(&done);
      86             : 
      87         616 :     BIND(&detached);
      88             :     // tc39.github.io/ecma262/#sec-integerindexedelementset
      89             :     // 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
      90         616 :     ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
      91             : 
      92         616 :     BIND(&done);
      93        1232 :     return a();
      94             :   }
      95             : 
      96         616 :   void ArrayBuiltinsAssembler::NullPostLoopAction() {}
      97             : 
      98           0 :   void ArrayBuiltinsAssembler::FillFixedArrayWithSmiZero(
      99             :       TNode<FixedArray> array, TNode<Smi> smi_length) {
     100             :     CSA_ASSERT(this, Word32BinaryNot(IsFixedDoubleArray(array)));
     101             : 
     102           0 :     TNode<IntPtrT> length = SmiToIntPtr(smi_length);
     103           0 :     TNode<WordT> byte_length = TimesTaggedSize(length);
     104             :     CSA_ASSERT(this, UintPtrLessThan(length, byte_length));
     105             : 
     106             :     static const int32_t fa_base_data_offset =
     107             :         FixedArray::kHeaderSize - kHeapObjectTag;
     108             :     TNode<IntPtrT> backing_store = IntPtrAdd(
     109           0 :         BitcastTaggedToWord(array), IntPtrConstant(fa_base_data_offset));
     110             : 
     111             :     // Call out to memset to perform initialization.
     112             :     TNode<ExternalReference> memset =
     113           0 :         ExternalConstant(ExternalReference::libc_memset_function());
     114             :     STATIC_ASSERT(kSizetSize == kIntptrSize);
     115           0 :     CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
     116             :                    MachineType::IntPtr(), MachineType::UintPtr(), memset,
     117           0 :                    backing_store, IntPtrConstant(0), byte_length);
     118           0 :   }
     119             : 
     120         616 :   void ArrayBuiltinsAssembler::ReturnFromBuiltin(Node* value) {
     121         616 :     if (argc_ == nullptr) {
     122           0 :       Return(value);
     123             :     } else {
     124             :       // argc_ doesn't include the receiver, so it has to be added back in
     125             :       // manually.
     126         616 :       PopAndReturn(IntPtrAdd(argc_, IntPtrConstant(1)), value);
     127             :     }
     128         616 :   }
     129             : 
     130          56 :   void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinBody(
     131             :       TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
     132             :       Node* this_arg, TNode<IntPtrT> argc) {
     133          56 :     context_ = context;
     134          56 :     receiver_ = receiver;
     135          56 :     callbackfn_ = callbackfn;
     136          56 :     this_arg_ = this_arg;
     137          56 :     argc_ = argc;
     138          56 :   }
     139             : 
     140          56 :   void ArrayBuiltinsAssembler::GenerateIteratingTypedArrayBuiltinBody(
     141             :       const char* name, const BuiltinResultGenerator& generator,
     142             :       const CallResultProcessor& processor, const PostLoopAction& action,
     143             :       ForEachDirection direction) {
     144          56 :     name_ = name;
     145             : 
     146             :     // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray
     147             : 
     148         112 :     Label throw_not_typed_array(this, Label::kDeferred);
     149             : 
     150          56 :     GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
     151         112 :     GotoIfNot(HasInstanceType(CAST(receiver_), JS_TYPED_ARRAY_TYPE),
     152          56 :               &throw_not_typed_array);
     153             : 
     154          56 :     TNode<JSTypedArray> typed_array = CAST(receiver_);
     155          56 :     o_ = typed_array;
     156             : 
     157             :     TNode<JSArrayBuffer> array_buffer =
     158          56 :         LoadJSArrayBufferViewBuffer(typed_array);
     159          56 :     ThrowIfArrayBufferIsDetached(context_, array_buffer, name_);
     160             : 
     161          56 :     len_ = LoadJSTypedArrayLength(typed_array);
     162             : 
     163         112 :     Label throw_not_callable(this, Label::kDeferred);
     164         112 :     Label distinguish_types(this);
     165          56 :     GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable);
     166         112 :     Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types,
     167          56 :            &throw_not_callable);
     168             : 
     169          56 :     BIND(&throw_not_typed_array);
     170          56 :     ThrowTypeError(context_, MessageTemplate::kNotTypedArray);
     171             : 
     172          56 :     BIND(&throw_not_callable);
     173          56 :     ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_);
     174             : 
     175         112 :     Label unexpected_instance_type(this);
     176          56 :     BIND(&unexpected_instance_type);
     177          56 :     Unreachable();
     178             : 
     179             :     std::vector<int32_t> instance_types = {
     180             : #define INSTANCE_TYPE(Type, type, TYPE, ctype) FIXED_##TYPE##_ARRAY_TYPE,
     181             :         TYPED_ARRAYS(INSTANCE_TYPE)
     182             : #undef INSTANCE_TYPE
     183         112 :     };
     184         112 :     std::list<Label> labels;
     185         672 :     for (size_t i = 0; i < instance_types.size(); ++i) {
     186         616 :       labels.emplace_back(this);
     187             :     }
     188         112 :     std::vector<Label*> label_ptrs;
     189         672 :     for (Label& label : labels) {
     190         616 :       label_ptrs.push_back(&label);
     191             :     }
     192             : 
     193          56 :     BIND(&distinguish_types);
     194             : 
     195          56 :     generator(this);
     196             : 
     197          56 :     if (direction == ForEachDirection::kForward) {
     198          56 :       k_.Bind(SmiConstant(0));
     199             :     } else {
     200           0 :       k_.Bind(NumberDec(len()));
     201             :     }
     202             :     CSA_ASSERT(this, IsSafeInteger(k()));
     203          56 :     Node* instance_type = LoadInstanceType(LoadElements(typed_array));
     204          56 :     Switch(instance_type, &unexpected_instance_type, instance_types.data(),
     205          56 :            label_ptrs.data(), labels.size());
     206             : 
     207          56 :     size_t i = 0;
     208         672 :     for (auto it = labels.begin(); it != labels.end(); ++i, ++it) {
     209         616 :       BIND(&*it);
     210        1232 :       Label done(this);
     211         616 :       source_elements_kind_ = ElementsKindForInstanceType(
     212        1232 :           static_cast<InstanceType>(instance_types[i]));
     213             :       // TODO(tebbi): Silently cancelling the loop on buffer detachment is a
     214             :       // spec violation. Should go to &throw_detached and throw a TypeError
     215             :       // instead.
     216         616 :       VisitAllTypedArrayElements(array_buffer, processor, &done, direction,
     217         616 :                                  typed_array);
     218         616 :       Goto(&done);
     219             :       // No exception, return success
     220         616 :       BIND(&done);
     221         616 :       action(this);
     222         616 :       ReturnFromBuiltin(a_.value());
     223             :     }
     224          56 :   }
     225             : 
     226         616 :   ElementsKind ArrayBuiltinsAssembler::ElementsKindForInstanceType(
     227             :       InstanceType type) {
     228         616 :     switch (type) {
     229             : #define INSTANCE_TYPE_TO_ELEMENTS_KIND(Type, type, TYPE, ctype) \
     230             :   case FIXED_##TYPE##_ARRAY_TYPE:                               \
     231             :     return TYPE##_ELEMENTS;
     232             : 
     233          56 :       TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND)
     234             : #undef INSTANCE_TYPE_TO_ELEMENTS_KIND
     235             : 
     236             :       default:
     237           0 :         UNREACHABLE();
     238             :     }
     239             :   }
     240             : 
     241         616 :   void ArrayBuiltinsAssembler::VisitAllTypedArrayElements(
     242             :       Node* array_buffer, const CallResultProcessor& processor, Label* detached,
     243             :       ForEachDirection direction, TNode<JSTypedArray> typed_array) {
     244        1232 :     VariableList list({&a_, &k_, &to_}, zone());
     245             : 
     246         616 :     FastLoopBody body = [&](Node* index) {
     247        6776 :       GotoIf(IsDetachedBuffer(array_buffer), detached);
     248        1232 :       Node* elements = LoadElements(typed_array);
     249             :       Node* base_ptr =
     250        1232 :           LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
     251             :       Node* external_ptr =
     252        1848 :           LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
     253         616 :                           MachineType::Pointer());
     254        1848 :       Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
     255        1232 :       Node* value = LoadFixedTypedArrayElementAsTagged(
     256        1232 :           data_ptr, index, source_elements_kind_, SMI_PARAMETERS);
     257         616 :       k_.Bind(index);
     258        1232 :       a_.Bind(processor(this, value, index));
     259        1848 :     };
     260         616 :     Node* start = SmiConstant(0);
     261         616 :     Node* end = len_;
     262         616 :     IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost;
     263         616 :     int incr = 1;
     264         616 :     if (direction == ForEachDirection::kReverse) {
     265           0 :       std::swap(start, end);
     266           0 :       advance_mode = IndexAdvanceMode::kPre;
     267           0 :       incr = -1;
     268             :     }
     269         616 :     BuildFastLoop(list, start, end, body, incr, ParameterMode::SMI_PARAMETERS,
     270        1232 :                   advance_mode);
     271         616 :   }
     272             : 
     273             :   // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
     274           0 :   void ArrayBuiltinsAssembler::GenerateArraySpeciesCreate(TNode<Number> len) {
     275           0 :     Label runtime(this, Label::kDeferred), done(this);
     276             : 
     277           0 :     Node* const original_map = LoadMap(o());
     278           0 :     GotoIfNot(
     279           0 :         InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
     280           0 :         &runtime);
     281             : 
     282           0 :     GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
     283           0 :               &runtime);
     284             : 
     285           0 :     Node* species_protector = ArraySpeciesProtectorConstant();
     286             :     Node* value =
     287           0 :         LoadObjectField(species_protector, PropertyCell::kValueOffset);
     288           0 :     Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
     289           0 :     GotoIf(WordEqual(value, protector_invalid), &runtime);
     290             : 
     291           0 :     GotoIfNot(TaggedIsPositiveSmi(len), &runtime);
     292           0 :     GotoIfNot(
     293           0 :         IsValidFastJSArrayCapacity(len, CodeStubAssembler::SMI_PARAMETERS),
     294           0 :         &runtime);
     295             : 
     296             :     // We need to be conservative and start with holey because the builtins
     297             :     // that create output arrays aren't guaranteed to be called for every
     298             :     // element in the input array (maybe the callback deletes an element).
     299             :     const ElementsKind elements_kind =
     300           0 :         GetHoleyElementsKind(GetInitialFastElementsKind());
     301           0 :     TNode<Context> native_context = LoadNativeContext(context());
     302             :     TNode<Map> array_map =
     303           0 :         LoadJSArrayElementsMap(elements_kind, native_context);
     304           0 :     a_.Bind(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, len, CAST(len),
     305             :                             nullptr, CodeStubAssembler::SMI_PARAMETERS,
     306           0 :                             kAllowLargeObjectAllocation));
     307             : 
     308           0 :     Goto(&done);
     309             : 
     310           0 :     BIND(&runtime);
     311             :     {
     312             :       // 5. Let A be ? ArraySpeciesCreate(O, len).
     313             :       TNode<JSReceiver> constructor =
     314           0 :           CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context(), o()));
     315           0 :       a_.Bind(Construct(context(), constructor, len));
     316           0 :       Goto(&fully_spec_compliant_);
     317             :     }
     318             : 
     319           0 :     BIND(&done);
     320           0 :   }
     321             : 
     322         336 : TF_BUILTIN(ArrayPrototypePop, CodeStubAssembler) {
     323             :   TNode<Int32T> argc =
     324          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
     325          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     326             :   CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
     327             : 
     328          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
     329          56 :   TNode<Object> receiver = args.GetReceiver();
     330             : 
     331         112 :   Label runtime(this, Label::kDeferred);
     332         112 :   Label fast(this);
     333             : 
     334             :   // Only pop in this stub if
     335             :   // 1) the array has fast elements
     336             :   // 2) the length is writable,
     337             :   // 3) the elements backing store isn't copy-on-write,
     338             :   // 4) we aren't supposed to shrink the backing store.
     339             : 
     340             :   // 1) Check that the array has fast elements.
     341          56 :   BranchIfFastJSArray(receiver, context, &fast, &runtime);
     342             : 
     343          56 :   BIND(&fast);
     344             :   {
     345          56 :     TNode<JSArray> array_receiver = CAST(receiver);
     346             :     CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver)));
     347             :     TNode<IntPtrT> length =
     348          56 :         LoadAndUntagObjectField(array_receiver, JSArray::kLengthOffset);
     349         112 :     Label return_undefined(this), fast_elements(this);
     350          56 :     GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
     351             : 
     352             :     // 2) Ensure that the length is writable.
     353          56 :     EnsureArrayLengthWritable(LoadMap(array_receiver), &runtime);
     354             : 
     355             :     // 3) Check that the elements backing store isn't copy-on-write.
     356          56 :     TNode<FixedArrayBase> elements = LoadElements(array_receiver);
     357         112 :     GotoIf(WordEqual(LoadMap(elements), LoadRoot(RootIndex::kFixedCOWArrayMap)),
     358          56 :            &runtime);
     359             : 
     360          56 :     TNode<IntPtrT> new_length = IntPtrSub(length, IntPtrConstant(1));
     361             : 
     362             :     // 4) Check that we're not supposed to shrink the backing store, as
     363             :     //    implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
     364          56 :     TNode<IntPtrT> capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
     365         112 :     GotoIf(IntPtrLessThan(
     366         112 :                IntPtrAdd(IntPtrAdd(new_length, new_length),
     367          56 :                          IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
     368         224 :                capacity),
     369          56 :            &runtime);
     370             : 
     371         112 :     StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset,
     372          56 :                                    SmiTag(new_length));
     373             : 
     374          56 :     TNode<Int32T> elements_kind = LoadElementsKind(array_receiver);
     375         112 :     GotoIf(Int32LessThanOrEqual(elements_kind,
     376         112 :                                 Int32Constant(TERMINAL_FAST_ELEMENTS_KIND)),
     377          56 :            &fast_elements);
     378             : 
     379         112 :     Node* value = LoadFixedDoubleArrayElement(CAST(elements), new_length,
     380          56 :                                               &return_undefined);
     381             : 
     382          56 :     StoreFixedDoubleArrayHole(CAST(elements), new_length);
     383          56 :     args.PopAndReturn(AllocateHeapNumberWithValue(value));
     384             : 
     385          56 :     BIND(&fast_elements);
     386             :     {
     387          56 :       Node* value = LoadFixedArrayElement(CAST(elements), new_length);
     388          56 :       StoreFixedArrayElement(CAST(elements), new_length, TheHoleConstant());
     389          56 :       GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
     390          56 :       args.PopAndReturn(value);
     391             :     }
     392             : 
     393          56 :     BIND(&return_undefined);
     394          56 :     { args.PopAndReturn(UndefinedConstant()); }
     395             :   }
     396             : 
     397          56 :   BIND(&runtime);
     398             :   {
     399             :     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
     400             :     // from the current frame here in order to reduce register pressure on the
     401             :     // fast path.
     402          56 :     TNode<JSFunction> target = LoadTargetFromFrame();
     403         112 :     TailCallBuiltin(Builtins::kArrayPop, context, target, UndefinedConstant(),
     404          56 :                     argc);
     405             :   }
     406          56 : }
     407             : 
     408         336 : TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
     409         112 :   TVARIABLE(IntPtrT, arg_index);
     410         112 :   Label default_label(this, &arg_index);
     411         112 :   Label smi_transition(this);
     412         112 :   Label object_push_pre(this);
     413         112 :   Label object_push(this, &arg_index);
     414         112 :   Label double_push(this, &arg_index);
     415         112 :   Label double_transition(this);
     416         112 :   Label runtime(this, Label::kDeferred);
     417             : 
     418             :   // TODO(ishell): use constants from Descriptor once the JSFunction linkage
     419             :   // arguments are reordered.
     420             :   TNode<Int32T> argc =
     421          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
     422          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     423             :   CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
     424             : 
     425          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
     426          56 :   TNode<Object> receiver = args.GetReceiver();
     427          56 :   TNode<JSArray> array_receiver;
     428          56 :   Node* kind = nullptr;
     429             : 
     430         112 :   Label fast(this);
     431          56 :   BranchIfFastJSArray(receiver, context, &fast, &runtime);
     432             : 
     433          56 :   BIND(&fast);
     434             :   {
     435          56 :     array_receiver = CAST(receiver);
     436          56 :     arg_index = IntPtrConstant(0);
     437          56 :     kind = EnsureArrayPushable(LoadMap(array_receiver), &runtime);
     438         112 :     GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
     439          56 :            &object_push_pre);
     440             : 
     441         112 :     Node* new_length = BuildAppendJSArray(PACKED_SMI_ELEMENTS, array_receiver,
     442         168 :                                           &args, &arg_index, &smi_transition);
     443          56 :     args.PopAndReturn(new_length);
     444             :   }
     445             : 
     446             :   // If the argument is not a smi, then use a heavyweight SetProperty to
     447             :   // transition the array for only the single next element. If the argument is
     448             :   // a smi, the failure is due to some other reason and we should fall back on
     449             :   // the most generic implementation for the rest of the array.
     450          56 :   BIND(&smi_transition);
     451             :   {
     452          56 :     Node* arg = args.AtIndex(arg_index.value());
     453          56 :     GotoIf(TaggedIsSmi(arg), &default_label);
     454          56 :     Node* length = LoadJSArrayLength(array_receiver);
     455             :     // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
     456             :     // calling into the runtime to do the elements transition is overkill.
     457          56 :     SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
     458          56 :     Increment(&arg_index);
     459             :     // The runtime SetProperty call could have converted the array to dictionary
     460             :     // mode, which must be detected to abort the fast-path.
     461          56 :     Node* kind = LoadElementsKind(array_receiver);
     462         112 :     GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
     463          56 :            &default_label);
     464             : 
     465          56 :     GotoIfNotNumber(arg, &object_push);
     466          56 :     Goto(&double_push);
     467             :   }
     468             : 
     469          56 :   BIND(&object_push_pre);
     470             :   {
     471         112 :     Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push,
     472          56 :            &object_push);
     473             :   }
     474             : 
     475          56 :   BIND(&object_push);
     476             :   {
     477         112 :     Node* new_length = BuildAppendJSArray(PACKED_ELEMENTS, array_receiver,
     478         168 :                                           &args, &arg_index, &default_label);
     479          56 :     args.PopAndReturn(new_length);
     480             :   }
     481             : 
     482          56 :   BIND(&double_push);
     483             :   {
     484             :     Node* new_length =
     485         112 :         BuildAppendJSArray(PACKED_DOUBLE_ELEMENTS, array_receiver, &args,
     486         168 :                            &arg_index, &double_transition);
     487          56 :     args.PopAndReturn(new_length);
     488             :   }
     489             : 
     490             :   // If the argument is not a double, then use a heavyweight SetProperty to
     491             :   // transition the array for only the single next element. If the argument is
     492             :   // a double, the failure is due to some other reason and we should fall back
     493             :   // on the most generic implementation for the rest of the array.
     494          56 :   BIND(&double_transition);
     495             :   {
     496          56 :     Node* arg = args.AtIndex(arg_index.value());
     497          56 :     GotoIfNumber(arg, &default_label);
     498          56 :     Node* length = LoadJSArrayLength(array_receiver);
     499             :     // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
     500             :     // calling into the runtime to do the elements transition is overkill.
     501          56 :     SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
     502          56 :     Increment(&arg_index);
     503             :     // The runtime SetProperty call could have converted the array to dictionary
     504             :     // mode, which must be detected to abort the fast-path.
     505          56 :     Node* kind = LoadElementsKind(array_receiver);
     506         112 :     GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
     507          56 :            &default_label);
     508          56 :     Goto(&object_push);
     509             :   }
     510             : 
     511             :   // Fallback that stores un-processed arguments using the full, heavyweight
     512             :   // SetProperty machinery.
     513          56 :   BIND(&default_label);
     514             :   {
     515         112 :     args.ForEach(
     516         280 :         [this, array_receiver, context](Node* arg) {
     517         112 :           Node* length = LoadJSArrayLength(array_receiver);
     518         168 :           SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
     519          56 :         },
     520         168 :         arg_index.value());
     521          56 :     args.PopAndReturn(LoadJSArrayLength(array_receiver));
     522             :   }
     523             : 
     524          56 :   BIND(&runtime);
     525             :   {
     526             :     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
     527             :     // from the current frame here in order to reduce register pressure on the
     528             :     // fast path.
     529          56 :     TNode<JSFunction> target = LoadTargetFromFrame();
     530         112 :     TailCallBuiltin(Builtins::kArrayPush, context, target, UndefinedConstant(),
     531          56 :                     argc);
     532             :   }
     533          56 : }
     534             : 
     535         448 : TF_BUILTIN(ExtractFastJSArray, ArrayBuiltinsAssembler) {
     536          56 :   ParameterMode mode = OptimalParameterMode();
     537          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     538          56 :   Node* array = Parameter(Descriptor::kSource);
     539          56 :   Node* begin = TaggedToParameter(Parameter(Descriptor::kBegin), mode);
     540          56 :   Node* count = TaggedToParameter(Parameter(Descriptor::kCount), mode);
     541             : 
     542             :   CSA_ASSERT(this, IsJSArray(array));
     543             :   CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid()));
     544             : 
     545          56 :   Return(ExtractFastJSArray(context, array, begin, count, mode));
     546          56 : }
     547             : 
     548         336 : TF_BUILTIN(CloneFastJSArray, ArrayBuiltinsAssembler) {
     549          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     550          56 :   TNode<JSArray> array = CAST(Parameter(Descriptor::kSource));
     551             : 
     552             :   CSA_ASSERT(this,
     553             :              Word32Or(Word32BinaryNot(
     554             :                           IsHoleyFastElementsKind(LoadElementsKind(array))),
     555             :                       Word32BinaryNot(IsNoElementsProtectorCellInvalid())));
     556             : 
     557          56 :   ParameterMode mode = OptimalParameterMode();
     558          56 :   Return(CloneFastJSArray(context, array, mode));
     559          56 : }
     560             : 
     561             : // This builtin copies the backing store of fast arrays, while converting any
     562             : // holes to undefined.
     563             : // - If there are no holes in the source, its ElementsKind will be preserved. In
     564             : // that case, this builtin should perform as fast as CloneFastJSArray. (In fact,
     565             : // for fast packed arrays, the behavior is equivalent to CloneFastJSArray.)
     566             : // - If there are holes in the source, the ElementsKind of the "copy" will be
     567             : // PACKED_ELEMENTS (such that undefined can be stored).
     568         336 : TF_BUILTIN(CloneFastJSArrayFillingHoles, ArrayBuiltinsAssembler) {
     569          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     570          56 :   TNode<JSArray> array = CAST(Parameter(Descriptor::kSource));
     571             : 
     572             :   CSA_ASSERT(this,
     573             :              Word32Or(Word32BinaryNot(
     574             :                           IsHoleyFastElementsKind(LoadElementsKind(array))),
     575             :                       Word32BinaryNot(IsNoElementsProtectorCellInvalid())));
     576             : 
     577          56 :   ParameterMode mode = OptimalParameterMode();
     578         112 :   Return(CloneFastJSArray(context, array, mode, nullptr,
     579          56 :                           HoleConversionMode::kConvertToUndefined));
     580          56 : }
     581             : 
     582          56 : class ArrayPopulatorAssembler : public CodeStubAssembler {
     583             :  public:
     584          56 :   explicit ArrayPopulatorAssembler(compiler::CodeAssemblerState* state)
     585          56 :       : CodeStubAssembler(state) {}
     586             : 
     587          56 :   TNode<Object> ConstructArrayLike(TNode<Context> context,
     588             :                                    TNode<Object> receiver) {
     589         112 :     TVARIABLE(Object, array);
     590         112 :     Label is_constructor(this), is_not_constructor(this), done(this);
     591          56 :     GotoIf(TaggedIsSmi(receiver), &is_not_constructor);
     592          56 :     Branch(IsConstructor(CAST(receiver)), &is_constructor, &is_not_constructor);
     593             : 
     594          56 :     BIND(&is_constructor);
     595             :     {
     596          56 :       array = Construct(context, CAST(receiver));
     597          56 :       Goto(&done);
     598             :     }
     599             : 
     600          56 :     BIND(&is_not_constructor);
     601             :     {
     602         112 :       Label allocate_js_array(this);
     603             : 
     604          56 :       TNode<Map> array_map = CAST(LoadContextElement(
     605             :           context, Context::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX));
     606             : 
     607         168 :       array = AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, SmiConstant(0),
     608             :                               SmiConstant(0), nullptr,
     609         224 :                               ParameterMode::SMI_PARAMETERS);
     610          56 :       Goto(&done);
     611             :     }
     612             : 
     613          56 :     BIND(&done);
     614         112 :     return array.value();
     615             :   }
     616             : 
     617          56 :   TNode<Object> ConstructArrayLike(TNode<Context> context,
     618             :                                    TNode<Object> receiver,
     619             :                                    TNode<Number> length) {
     620         112 :     TVARIABLE(Object, array);
     621         112 :     Label is_constructor(this), is_not_constructor(this), done(this);
     622             :     CSA_ASSERT(this, IsNumberNormalized(length));
     623          56 :     GotoIf(TaggedIsSmi(receiver), &is_not_constructor);
     624          56 :     Branch(IsConstructor(CAST(receiver)), &is_constructor, &is_not_constructor);
     625             : 
     626          56 :     BIND(&is_constructor);
     627             :     {
     628          56 :       array = Construct(context, CAST(receiver), length);
     629          56 :       Goto(&done);
     630             :     }
     631             : 
     632          56 :     BIND(&is_not_constructor);
     633             :     {
     634          56 :       array = ArrayCreate(context, length);
     635          56 :       Goto(&done);
     636             :     }
     637             : 
     638          56 :     BIND(&done);
     639         112 :     return array.value();
     640             :   }
     641             : };
     642             : 
     643             : // ES #sec-array.from
     644         336 : TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
     645          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     646             :   TNode<Int32T> argc =
     647          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
     648             : 
     649          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
     650          56 :   TNode<Object> items = args.GetOptionalArgumentValue(0);
     651          56 :   TNode<Object> receiver = args.GetReceiver();
     652             : 
     653         112 :   Label fast_iterate(this), normal_iterate(this);
     654             : 
     655             :   // Use fast path if:
     656             :   // * |items| is the only argument, and
     657             :   // * the receiver is the Array function.
     658          56 :   GotoIfNot(Word32Equal(argc, Int32Constant(1)), &normal_iterate);
     659             :   TNode<Object> array_function = LoadContextElement(
     660          56 :       LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
     661          56 :   Branch(WordEqual(array_function, receiver), &fast_iterate, &normal_iterate);
     662             : 
     663          56 :   BIND(&fast_iterate);
     664             :   {
     665         112 :     IteratorBuiltinsAssembler iterator_assembler(state());
     666         112 :     TVARIABLE(Object, var_fast_result);
     667             :     iterator_assembler.FastIterableToList(context, items, &var_fast_result,
     668          56 :                                           &normal_iterate);
     669          56 :     args.PopAndReturn(var_fast_result.value());
     670             :   }
     671             : 
     672          56 :   BIND(&normal_iterate);
     673          56 :   TNode<Object> map_function = args.GetOptionalArgumentValue(1);
     674             : 
     675             :   // If map_function is not undefined, then ensure it's callable else throw.
     676             :   {
     677         112 :     Label no_error(this), error(this);
     678          56 :     GotoIf(IsUndefined(map_function), &no_error);
     679          56 :     GotoIf(TaggedIsSmi(map_function), &error);
     680          56 :     Branch(IsCallable(CAST(map_function)), &no_error, &error);
     681             : 
     682          56 :     BIND(&error);
     683          56 :     ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_function);
     684             : 
     685          56 :     BIND(&no_error);
     686             :   }
     687             : 
     688         112 :   Label iterable(this), not_iterable(this), finished(this), if_exception(this);
     689             : 
     690          56 :   TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
     691             :   // The spec doesn't require ToObject to be called directly on the iterable
     692             :   // branch, but it's part of GetMethod that is in the spec.
     693          56 :   TNode<JSReceiver> array_like = ToObject_Inline(context, items);
     694             : 
     695         112 :   TVARIABLE(Object, array);
     696         112 :   TVARIABLE(Number, length);
     697             : 
     698             :   // Determine whether items[Symbol.iterator] is defined:
     699         112 :   IteratorBuiltinsAssembler iterator_assembler(state());
     700             :   Node* iterator_method =
     701          56 :       iterator_assembler.GetIteratorMethod(context, array_like);
     702          56 :   Branch(IsNullOrUndefined(iterator_method), &not_iterable, &iterable);
     703             : 
     704          56 :   BIND(&iterable);
     705             :   {
     706         112 :     TVARIABLE(Number, index, SmiConstant(0));
     707         112 :     TVARIABLE(Object, var_exception);
     708         112 :     Label loop(this, &index), loop_done(this),
     709         112 :         on_exception(this, Label::kDeferred),
     710         112 :         index_overflow(this, Label::kDeferred);
     711             : 
     712             :     // Check that the method is callable.
     713             :     {
     714         112 :       Label get_method_not_callable(this, Label::kDeferred), next(this);
     715          56 :       GotoIf(TaggedIsSmi(iterator_method), &get_method_not_callable);
     716          56 :       GotoIfNot(IsCallable(CAST(iterator_method)), &get_method_not_callable);
     717          56 :       Goto(&next);
     718             : 
     719          56 :       BIND(&get_method_not_callable);
     720          56 :       ThrowTypeError(context, MessageTemplate::kCalledNonCallable,
     721          56 :                      iterator_method);
     722             : 
     723          56 :       BIND(&next);
     724             :     }
     725             : 
     726             :     // Construct the output array with empty length.
     727          56 :     array = ConstructArrayLike(context, receiver);
     728             : 
     729             :     // Actually get the iterator and throw if the iterator method does not yield
     730             :     // one.
     731             :     IteratorRecord iterator_record =
     732          56 :         iterator_assembler.GetIterator(context, items, iterator_method);
     733             : 
     734          56 :     TNode<Context> native_context = LoadNativeContext(context);
     735             :     TNode<Object> fast_iterator_result_map =
     736          56 :         LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
     737             : 
     738          56 :     Goto(&loop);
     739             : 
     740          56 :     BIND(&loop);
     741             :     {
     742             :       // Loop while iterator is not done.
     743             :       TNode<Object> next = iterator_assembler.IteratorStep(
     744          56 :           context, iterator_record, &loop_done, fast_iterator_result_map);
     745         112 :       TVARIABLE(Object, value,
     746             :                 CAST(iterator_assembler.IteratorValue(
     747             :                     context, next, fast_iterator_result_map)));
     748             : 
     749             :       // If a map_function is supplied then call it (using this_arg as
     750             :       // receiver), on the value returned from the iterator. Exceptions are
     751             :       // caught so the iterator can be closed.
     752             :       {
     753         112 :         Label next(this);
     754          56 :         GotoIf(IsUndefined(map_function), &next);
     755             : 
     756             :         CSA_ASSERT(this, IsCallable(CAST(map_function)));
     757         112 :         Node* v = CallJS(CodeFactory::Call(isolate()), context, map_function,
     758          56 :                          this_arg, value.value(), index.value());
     759          56 :         GotoIfException(v, &on_exception, &var_exception);
     760          56 :         value = CAST(v);
     761          56 :         Goto(&next);
     762          56 :         BIND(&next);
     763             :       }
     764             : 
     765             :       // Store the result in the output object (catching any exceptions so the
     766             :       // iterator can be closed).
     767             :       Node* define_status =
     768         112 :           CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
     769         168 :                       index.value(), value.value());
     770          56 :       GotoIfException(define_status, &on_exception, &var_exception);
     771             : 
     772          56 :       index = NumberInc(index.value());
     773             : 
     774             :       // The spec requires that we throw an exception if index reaches 2^53-1,
     775             :       // but an empty loop would take >100 days to do this many iterations. To
     776             :       // actually run for that long would require an iterator that never set
     777             :       // done to true and a target array which somehow never ran out of memory,
     778             :       // e.g. a proxy that discarded the values. Ignoring this case just means
     779             :       // we would repeatedly call CreateDataProperty with index = 2^53.
     780             :       CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
     781             :         BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
     782             :                                            NumberConstant(kMaxSafeInteger), ok,
     783             :                                            not_ok);
     784             :       });
     785          56 :       Goto(&loop);
     786             :     }
     787             : 
     788          56 :     BIND(&loop_done);
     789             :     {
     790          56 :       length = index;
     791          56 :       Goto(&finished);
     792             :     }
     793             : 
     794          56 :     BIND(&on_exception);
     795             :     {
     796             :       // Close the iterator, rethrowing either the passed exception or
     797             :       // exceptions thrown during the close.
     798          56 :       iterator_assembler.IteratorCloseOnException(context, iterator_record,
     799          56 :                                                   var_exception.value());
     800             :     }
     801             :   }
     802             : 
     803          56 :   BIND(&not_iterable);
     804             :   {
     805             :     // Treat array_like as an array and try to get its length.
     806         112 :     length = ToLength_Inline(
     807         224 :         context, GetProperty(context, array_like, factory()->length_string()));
     808             : 
     809             :     // Construct an array using the receiver as constructor with the same length
     810             :     // as the input array.
     811          56 :     array = ConstructArrayLike(context, receiver, length.value());
     812             : 
     813         112 :     TVARIABLE(Number, index, SmiConstant(0));
     814             : 
     815             :     // TODO(ishell): remove <Object, Object>
     816         112 :     GotoIf(WordEqual<Object, Object>(length.value(), SmiConstant(0)),
     817          56 :            &finished);
     818             : 
     819             :     // Loop from 0 to length-1.
     820             :     {
     821         112 :       Label loop(this, &index);
     822          56 :       Goto(&loop);
     823          56 :       BIND(&loop);
     824         112 :       TVARIABLE(Object, value);
     825             : 
     826          56 :       value = GetProperty(context, array_like, index.value());
     827             : 
     828             :       // If a map_function is supplied then call it (using this_arg as
     829             :       // receiver), on the value retrieved from the array.
     830             :       {
     831         112 :         Label next(this);
     832          56 :         GotoIf(IsUndefined(map_function), &next);
     833             : 
     834             :         CSA_ASSERT(this, IsCallable(CAST(map_function)));
     835         112 :         value = CAST(CallJS(CodeFactory::Call(isolate()), context, map_function,
     836          56 :                             this_arg, value.value(), index.value()));
     837          56 :         Goto(&next);
     838          56 :         BIND(&next);
     839             :       }
     840             : 
     841             :       // Store the result in the output object.
     842             :       CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
     843          56 :                   index.value(), value.value());
     844          56 :       index = NumberInc(index.value());
     845         112 :       BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
     846         168 :                                          length.value(), &loop, &finished);
     847             :     }
     848             :   }
     849             : 
     850          56 :   BIND(&finished);
     851             : 
     852             :   // Finally set the length on the output and return it.
     853          56 :   SetPropertyLength(context, array.value(), length.value());
     854          56 :   args.PopAndReturn(array.value());
     855          56 : }
     856             : 
     857         336 : TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
     858             :   TNode<IntPtrT> argc =
     859          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
     860          56 :   CodeStubArguments args(this, argc);
     861          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     862          56 :   TNode<Object> receiver = args.GetReceiver();
     863          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
     864          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
     865             : 
     866          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
     867             : 
     868         112 :   GenerateIteratingTypedArrayBuiltinBody(
     869             :       "%TypedArray%.prototype.map",
     870             :       &ArrayBuiltinsAssembler::TypedArrayMapResultGenerator,
     871             :       &ArrayBuiltinsAssembler::TypedArrayMapProcessor,
     872          56 :       &ArrayBuiltinsAssembler::NullPostLoopAction);
     873          56 : }
     874             : 
     875         336 : TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
     876          56 :   TNode<Object> object = CAST(Parameter(Descriptor::kArg));
     877          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     878             : 
     879         112 :   Label call_runtime(this), return_true(this), return_false(this);
     880             : 
     881          56 :   GotoIf(TaggedIsSmi(object), &return_false);
     882          56 :   TNode<Int32T> instance_type = LoadInstanceType(CAST(object));
     883             : 
     884          56 :   GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &return_true);
     885             : 
     886             :   // TODO(verwaest): Handle proxies in-place.
     887         112 :   Branch(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), &call_runtime,
     888          56 :          &return_false);
     889             : 
     890          56 :   BIND(&return_true);
     891          56 :   Return(TrueConstant());
     892             : 
     893          56 :   BIND(&return_false);
     894          56 :   Return(FalseConstant());
     895             : 
     896          56 :   BIND(&call_runtime);
     897          56 :   Return(CallRuntime(Runtime::kArrayIsArray, context, object));
     898          56 : }
     899             : 
     900         448 : class ArrayIncludesIndexofAssembler : public CodeStubAssembler {
     901             :  public:
     902         448 :   explicit ArrayIncludesIndexofAssembler(compiler::CodeAssemblerState* state)
     903         448 :       : CodeStubAssembler(state) {}
     904             : 
     905             :   enum SearchVariant { kIncludes, kIndexOf };
     906             : 
     907             :   void Generate(SearchVariant variant, TNode<IntPtrT> argc,
     908             :                 TNode<Context> context);
     909             :   void GenerateSmiOrObject(SearchVariant variant, Node* context, Node* elements,
     910             :                            Node* search_element, Node* array_length,
     911             :                            Node* from_index);
     912             :   void GeneratePackedDoubles(SearchVariant variant, Node* elements,
     913             :                              Node* search_element, Node* array_length,
     914             :                              Node* from_index);
     915             :   void GenerateHoleyDoubles(SearchVariant variant, Node* elements,
     916             :                             Node* search_element, Node* array_length,
     917             :                             Node* from_index);
     918             : };
     919             : 
     920         112 : void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
     921             :                                              TNode<IntPtrT> argc,
     922             :                                              TNode<Context> context) {
     923         112 :   const int kSearchElementArg = 0;
     924         112 :   const int kFromIndexArg = 1;
     925             : 
     926         112 :   CodeStubArguments args(this, argc);
     927             : 
     928         112 :   TNode<Object> receiver = args.GetReceiver();
     929             :   TNode<Object> search_element =
     930         112 :       args.GetOptionalArgumentValue(kSearchElementArg);
     931             : 
     932         112 :   Node* intptr_zero = IntPtrConstant(0);
     933             : 
     934         224 :   Label init_index(this), return_not_found(this), call_runtime(this);
     935             : 
     936             :   // Take slow path if not a JSArray, if retrieving elements requires
     937             :   // traversing prototype, or if access checks are required.
     938         112 :   BranchIfFastJSArray(receiver, context, &init_index, &call_runtime);
     939             : 
     940         112 :   BIND(&init_index);
     941         224 :   VARIABLE(index_var, MachineType::PointerRepresentation(), intptr_zero);
     942         112 :   TNode<JSArray> array = CAST(receiver);
     943             : 
     944             :   // JSArray length is always a positive Smi for fast arrays.
     945             :   CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array)));
     946         112 :   Node* array_length = LoadFastJSArrayLength(array);
     947         112 :   Node* array_length_untagged = SmiUntag(array_length);
     948             : 
     949             :   {
     950             :     // Initialize fromIndex.
     951         224 :     Label is_smi(this), is_nonsmi(this), done(this);
     952             : 
     953             :     // If no fromIndex was passed, default to 0.
     954         112 :     GotoIf(IntPtrLessThanOrEqual(argc, IntPtrConstant(kFromIndexArg)), &done);
     955             : 
     956         112 :     Node* start_from = args.AtIndex(kFromIndexArg);
     957             :     // Handle Smis and undefined here and everything else in runtime.
     958             :     // We must be very careful with side effects from the ToInteger conversion,
     959             :     // as the side effects might render previously checked assumptions about
     960             :     // the receiver being a fast JSArray and its length invalid.
     961         112 :     Branch(TaggedIsSmi(start_from), &is_smi, &is_nonsmi);
     962             : 
     963         112 :     BIND(&is_nonsmi);
     964             :     {
     965         112 :       GotoIfNot(IsUndefined(start_from), &call_runtime);
     966         112 :       Goto(&done);
     967             :     }
     968         112 :     BIND(&is_smi);
     969             :     {
     970         112 :       Node* intptr_start_from = SmiUntag(start_from);
     971         112 :       index_var.Bind(intptr_start_from);
     972             : 
     973         112 :       GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
     974             :       // The fromIndex is negative: add it to the array's length.
     975         112 :       index_var.Bind(IntPtrAdd(array_length_untagged, index_var.value()));
     976             :       // Clamp negative results at zero.
     977         112 :       GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
     978         112 :       index_var.Bind(intptr_zero);
     979         112 :       Goto(&done);
     980             :     }
     981         112 :     BIND(&done);
     982             :   }
     983             : 
     984             :   // Fail early if startIndex >= array.length.
     985         224 :   GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), array_length_untagged),
     986         112 :          &return_not_found);
     987             : 
     988         224 :   Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
     989             : 
     990         112 :   TNode<Int32T> elements_kind = LoadElementsKind(array);
     991         112 :   Node* elements = LoadElements(array);
     992             :   STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
     993             :   STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
     994             :   STATIC_ASSERT(PACKED_ELEMENTS == 2);
     995             :   STATIC_ASSERT(HOLEY_ELEMENTS == 3);
     996         224 :   GotoIf(Uint32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
     997         112 :          &if_smiorobjects);
     998         224 :   GotoIf(Word32Equal(elements_kind, Int32Constant(PACKED_DOUBLE_ELEMENTS)),
     999         112 :          &if_packed_doubles);
    1000         224 :   GotoIf(Word32Equal(elements_kind, Int32Constant(HOLEY_DOUBLE_ELEMENTS)),
    1001         112 :          &if_holey_doubles);
    1002         112 :   Goto(&return_not_found);
    1003             : 
    1004         112 :   BIND(&if_smiorobjects);
    1005             :   {
    1006             :     Callable callable =
    1007             :         (variant == kIncludes)
    1008             :             ? Builtins::CallableFor(isolate(),
    1009             :                                     Builtins::kArrayIncludesSmiOrObject)
    1010             :             : Builtins::CallableFor(isolate(),
    1011         224 :                                     Builtins::kArrayIndexOfSmiOrObject);
    1012         224 :     Node* result = CallStub(callable, context, elements, search_element,
    1013         336 :                             array_length, SmiTag(index_var.value()));
    1014         112 :     args.PopAndReturn(result);
    1015             :   }
    1016             : 
    1017         112 :   BIND(&if_packed_doubles);
    1018             :   {
    1019             :     Callable callable =
    1020             :         (variant == kIncludes)
    1021             :             ? Builtins::CallableFor(isolate(),
    1022             :                                     Builtins::kArrayIncludesPackedDoubles)
    1023             :             : Builtins::CallableFor(isolate(),
    1024         224 :                                     Builtins::kArrayIndexOfPackedDoubles);
    1025         224 :     Node* result = CallStub(callable, context, elements, search_element,
    1026         336 :                             array_length, SmiTag(index_var.value()));
    1027         112 :     args.PopAndReturn(result);
    1028             :   }
    1029             : 
    1030         112 :   BIND(&if_holey_doubles);
    1031             :   {
    1032             :     Callable callable =
    1033             :         (variant == kIncludes)
    1034             :             ? Builtins::CallableFor(isolate(),
    1035             :                                     Builtins::kArrayIncludesHoleyDoubles)
    1036             :             : Builtins::CallableFor(isolate(),
    1037         224 :                                     Builtins::kArrayIndexOfHoleyDoubles);
    1038         224 :     Node* result = CallStub(callable, context, elements, search_element,
    1039         336 :                             array_length, SmiTag(index_var.value()));
    1040         112 :     args.PopAndReturn(result);
    1041             :   }
    1042             : 
    1043         112 :   BIND(&return_not_found);
    1044         112 :   if (variant == kIncludes) {
    1045          56 :     args.PopAndReturn(FalseConstant());
    1046             :   } else {
    1047          56 :     args.PopAndReturn(NumberConstant(-1));
    1048             :   }
    1049             : 
    1050         112 :   BIND(&call_runtime);
    1051             :   {
    1052             :     Node* start_from =
    1053         112 :         args.GetOptionalArgumentValue(kFromIndexArg, UndefinedConstant());
    1054             :     Runtime::FunctionId function = variant == kIncludes
    1055             :                                        ? Runtime::kArrayIncludes_Slow
    1056         112 :                                        : Runtime::kArrayIndexOf;
    1057         112 :     args.PopAndReturn(
    1058         224 :         CallRuntime(function, context, array, search_element, start_from));
    1059             :   }
    1060         112 : }
    1061             : 
    1062         112 : void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
    1063             :     SearchVariant variant, Node* context, Node* elements, Node* search_element,
    1064             :     Node* array_length, Node* from_index) {
    1065         224 :   VARIABLE(index_var, MachineType::PointerRepresentation(),
    1066             :            SmiUntag(from_index));
    1067         224 :   VARIABLE(search_num, MachineRepresentation::kFloat64);
    1068         112 :   Node* array_length_untagged = SmiUntag(array_length);
    1069             : 
    1070         224 :   Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
    1071         224 :       string_loop(this), bigint_loop(this, &index_var),
    1072         224 :       undef_loop(this, &index_var), not_smi(this), not_heap_num(this),
    1073         224 :       return_found(this), return_not_found(this);
    1074             : 
    1075         112 :   GotoIfNot(TaggedIsSmi(search_element), &not_smi);
    1076         112 :   search_num.Bind(SmiToFloat64(search_element));
    1077         112 :   Goto(&heap_num_loop);
    1078             : 
    1079         112 :   BIND(&not_smi);
    1080         112 :   if (variant == kIncludes) {
    1081          56 :     GotoIf(IsUndefined(search_element), &undef_loop);
    1082             :   }
    1083         112 :   Node* map = LoadMap(search_element);
    1084         112 :   GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
    1085         112 :   search_num.Bind(LoadHeapNumberValue(search_element));
    1086         112 :   Goto(&heap_num_loop);
    1087             : 
    1088         112 :   BIND(&not_heap_num);
    1089         112 :   Node* search_type = LoadMapInstanceType(map);
    1090         112 :   GotoIf(IsStringInstanceType(search_type), &string_loop);
    1091         112 :   GotoIf(IsBigIntInstanceType(search_type), &bigint_loop);
    1092         112 :   Goto(&ident_loop);
    1093             : 
    1094         112 :   BIND(&ident_loop);
    1095             :   {
    1096         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1097         112 :               &return_not_found);
    1098             :     Node* element_k =
    1099         112 :         UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    1100         112 :     GotoIf(WordEqual(element_k, search_element), &return_found);
    1101             : 
    1102         112 :     Increment(&index_var);
    1103         112 :     Goto(&ident_loop);
    1104             :   }
    1105             : 
    1106         112 :   if (variant == kIncludes) {
    1107          56 :     BIND(&undef_loop);
    1108             : 
    1109         112 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1110          56 :               &return_not_found);
    1111             :     Node* element_k =
    1112          56 :         UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    1113          56 :     GotoIf(IsUndefined(element_k), &return_found);
    1114          56 :     GotoIf(IsTheHole(element_k), &return_found);
    1115             : 
    1116          56 :     Increment(&index_var);
    1117          56 :     Goto(&undef_loop);
    1118             :   }
    1119             : 
    1120         112 :   BIND(&heap_num_loop);
    1121             :   {
    1122         224 :     Label nan_loop(this, &index_var), not_nan_loop(this, &index_var);
    1123         112 :     Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
    1124         112 :     BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
    1125             : 
    1126         112 :     BIND(&not_nan_loop);
    1127             :     {
    1128         224 :       Label continue_loop(this), not_smi(this);
    1129         224 :       GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1130         112 :                 &return_not_found);
    1131             :       Node* element_k =
    1132         112 :           UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    1133         112 :       GotoIfNot(TaggedIsSmi(element_k), &not_smi);
    1134         224 :       Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
    1135         112 :              &return_found, &continue_loop);
    1136             : 
    1137         112 :       BIND(&not_smi);
    1138         112 :       GotoIfNot(IsHeapNumber(element_k), &continue_loop);
    1139         224 :       Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
    1140         112 :              &return_found, &continue_loop);
    1141             : 
    1142         112 :       BIND(&continue_loop);
    1143         112 :       Increment(&index_var);
    1144         112 :       Goto(&not_nan_loop);
    1145             :     }
    1146             : 
    1147             :     // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
    1148         112 :     if (variant == kIncludes) {
    1149          56 :       BIND(&nan_loop);
    1150         112 :       Label continue_loop(this);
    1151         112 :       GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1152          56 :                 &return_not_found);
    1153             :       Node* element_k =
    1154          56 :           UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    1155          56 :       GotoIf(TaggedIsSmi(element_k), &continue_loop);
    1156          56 :       GotoIfNot(IsHeapNumber(CAST(element_k)), &continue_loop);
    1157         112 :       BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_found,
    1158          56 :                            &continue_loop);
    1159             : 
    1160          56 :       BIND(&continue_loop);
    1161          56 :       Increment(&index_var);
    1162          56 :       Goto(&nan_loop);
    1163             :     }
    1164             :   }
    1165             : 
    1166         112 :   BIND(&string_loop);
    1167             :   {
    1168         112 :     TNode<String> search_element_string = CAST(search_element);
    1169         224 :     Label continue_loop(this), next_iteration(this, &index_var),
    1170         224 :         slow_compare(this), runtime(this, Label::kDeferred);
    1171             :     TNode<IntPtrT> search_length =
    1172         112 :         LoadStringLengthAsWord(search_element_string);
    1173         112 :     Goto(&next_iteration);
    1174         112 :     BIND(&next_iteration);
    1175         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1176         112 :               &return_not_found);
    1177             :     Node* element_k =
    1178         112 :         UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    1179         112 :     GotoIf(TaggedIsSmi(element_k), &continue_loop);
    1180         112 :     GotoIf(WordEqual(search_element_string, element_k), &return_found);
    1181         112 :     Node* element_k_type = LoadInstanceType(element_k);
    1182         112 :     GotoIfNot(IsStringInstanceType(element_k_type), &continue_loop);
    1183         224 :     Branch(WordEqual(search_length, LoadStringLengthAsWord(element_k)),
    1184         112 :            &slow_compare, &continue_loop);
    1185             : 
    1186         112 :     BIND(&slow_compare);
    1187         224 :     StringBuiltinsAssembler string_asm(state());
    1188         112 :     string_asm.StringEqual_Core(context, search_element_string, search_type,
    1189             :                                 element_k, element_k_type, search_length,
    1190         112 :                                 &return_found, &continue_loop, &runtime);
    1191         112 :     BIND(&runtime);
    1192             :     TNode<Object> result = CallRuntime(Runtime::kStringEqual, context,
    1193         112 :                                        search_element_string, element_k);
    1194         112 :     Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
    1195             : 
    1196         112 :     BIND(&continue_loop);
    1197         112 :     Increment(&index_var);
    1198         112 :     Goto(&next_iteration);
    1199             :   }
    1200             : 
    1201         112 :   BIND(&bigint_loop);
    1202             :   {
    1203         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1204         112 :               &return_not_found);
    1205             : 
    1206             :     Node* element_k =
    1207         112 :         UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    1208         224 :     Label continue_loop(this);
    1209         112 :     GotoIf(TaggedIsSmi(element_k), &continue_loop);
    1210         112 :     GotoIfNot(IsBigInt(CAST(element_k)), &continue_loop);
    1211             :     TNode<Object> result = CallRuntime(Runtime::kBigIntEqualToBigInt, context,
    1212         112 :                                        search_element, element_k);
    1213         112 :     Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
    1214             : 
    1215         112 :     BIND(&continue_loop);
    1216         112 :     Increment(&index_var);
    1217         112 :     Goto(&bigint_loop);
    1218             :   }
    1219         112 :   BIND(&return_found);
    1220         112 :   if (variant == kIncludes) {
    1221          56 :     Return(TrueConstant());
    1222             :   } else {
    1223          56 :     Return(SmiTag(index_var.value()));
    1224             :   }
    1225             : 
    1226         112 :   BIND(&return_not_found);
    1227         112 :   if (variant == kIncludes) {
    1228          56 :     Return(FalseConstant());
    1229             :   } else {
    1230          56 :     Return(NumberConstant(-1));
    1231             :   }
    1232         112 : }
    1233             : 
    1234         112 : void ArrayIncludesIndexofAssembler::GeneratePackedDoubles(SearchVariant variant,
    1235             :                                                           Node* elements,
    1236             :                                                           Node* search_element,
    1237             :                                                           Node* array_length,
    1238             :                                                           Node* from_index) {
    1239         224 :   VARIABLE(index_var, MachineType::PointerRepresentation(),
    1240             :            SmiUntag(from_index));
    1241         112 :   Node* array_length_untagged = SmiUntag(array_length);
    1242             : 
    1243         224 :   Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
    1244         224 :       hole_loop(this, &index_var), search_notnan(this), return_found(this),
    1245         224 :       return_not_found(this);
    1246         224 :   VARIABLE(search_num, MachineRepresentation::kFloat64);
    1247         112 :   search_num.Bind(Float64Constant(0));
    1248             : 
    1249         112 :   GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
    1250         112 :   search_num.Bind(SmiToFloat64(search_element));
    1251         112 :   Goto(&not_nan_loop);
    1252             : 
    1253         112 :   BIND(&search_notnan);
    1254         112 :   GotoIfNot(IsHeapNumber(search_element), &return_not_found);
    1255             : 
    1256         112 :   search_num.Bind(LoadHeapNumberValue(search_element));
    1257             : 
    1258         112 :   Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
    1259         112 :   BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
    1260             : 
    1261         112 :   BIND(&not_nan_loop);
    1262             :   {
    1263         224 :     Label continue_loop(this);
    1264         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1265         112 :               &return_not_found);
    1266         224 :     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
    1267         336 :                                                   MachineType::Float64());
    1268         224 :     Branch(Float64Equal(element_k, search_num.value()), &return_found,
    1269         112 :            &continue_loop);
    1270         112 :     BIND(&continue_loop);
    1271         112 :     Increment(&index_var);
    1272         112 :     Goto(&not_nan_loop);
    1273             :   }
    1274             : 
    1275             :   // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
    1276         112 :   if (variant == kIncludes) {
    1277          56 :     BIND(&nan_loop);
    1278         112 :     Label continue_loop(this);
    1279         112 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1280          56 :               &return_not_found);
    1281         112 :     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
    1282         168 :                                                   MachineType::Float64());
    1283          56 :     BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
    1284          56 :     BIND(&continue_loop);
    1285          56 :     Increment(&index_var);
    1286          56 :     Goto(&nan_loop);
    1287             :   }
    1288             : 
    1289         112 :   BIND(&return_found);
    1290         112 :   if (variant == kIncludes) {
    1291          56 :     Return(TrueConstant());
    1292             :   } else {
    1293          56 :     Return(SmiTag(index_var.value()));
    1294             :   }
    1295             : 
    1296         112 :   BIND(&return_not_found);
    1297         112 :   if (variant == kIncludes) {
    1298          56 :     Return(FalseConstant());
    1299             :   } else {
    1300          56 :     Return(NumberConstant(-1));
    1301             :   }
    1302         112 : }
    1303             : 
    1304         112 : void ArrayIncludesIndexofAssembler::GenerateHoleyDoubles(SearchVariant variant,
    1305             :                                                          Node* elements,
    1306             :                                                          Node* search_element,
    1307             :                                                          Node* array_length,
    1308             :                                                          Node* from_index) {
    1309         224 :   VARIABLE(index_var, MachineType::PointerRepresentation(),
    1310             :            SmiUntag(from_index));
    1311         112 :   Node* array_length_untagged = SmiUntag(array_length);
    1312             : 
    1313         224 :   Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
    1314         224 :       hole_loop(this, &index_var), search_notnan(this), return_found(this),
    1315         224 :       return_not_found(this);
    1316         224 :   VARIABLE(search_num, MachineRepresentation::kFloat64);
    1317         112 :   search_num.Bind(Float64Constant(0));
    1318             : 
    1319         112 :   GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
    1320         112 :   search_num.Bind(SmiToFloat64(search_element));
    1321         112 :   Goto(&not_nan_loop);
    1322             : 
    1323         112 :   BIND(&search_notnan);
    1324         112 :   if (variant == kIncludes) {
    1325          56 :     GotoIf(IsUndefined(search_element), &hole_loop);
    1326             :   }
    1327         112 :   GotoIfNot(IsHeapNumber(search_element), &return_not_found);
    1328             : 
    1329         112 :   search_num.Bind(LoadHeapNumberValue(search_element));
    1330             : 
    1331         112 :   Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
    1332         112 :   BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
    1333             : 
    1334         112 :   BIND(&not_nan_loop);
    1335             :   {
    1336         224 :     Label continue_loop(this);
    1337         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1338         112 :               &return_not_found);
    1339             : 
    1340             :     // No need for hole checking here; the following Float64Equal will
    1341             :     // return 'not equal' for holes anyway.
    1342         224 :     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
    1343         336 :                                                   MachineType::Float64());
    1344             : 
    1345         224 :     Branch(Float64Equal(element_k, search_num.value()), &return_found,
    1346         112 :            &continue_loop);
    1347         112 :     BIND(&continue_loop);
    1348         112 :     Increment(&index_var);
    1349         112 :     Goto(&not_nan_loop);
    1350             :   }
    1351             : 
    1352             :   // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
    1353         112 :   if (variant == kIncludes) {
    1354          56 :     BIND(&nan_loop);
    1355         112 :     Label continue_loop(this);
    1356         112 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1357          56 :               &return_not_found);
    1358             : 
    1359             :     // Load double value or continue if it's the hole NaN.
    1360         112 :     Node* element_k = LoadFixedDoubleArrayElement(
    1361             :         elements, index_var.value(), MachineType::Float64(), 0,
    1362         168 :         INTPTR_PARAMETERS, &continue_loop);
    1363             : 
    1364          56 :     BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
    1365          56 :     BIND(&continue_loop);
    1366          56 :     Increment(&index_var);
    1367          56 :     Goto(&nan_loop);
    1368             :   }
    1369             : 
    1370             :   // Array.p.includes treats the hole as undefined.
    1371         112 :   if (variant == kIncludes) {
    1372          56 :     BIND(&hole_loop);
    1373         112 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    1374          56 :               &return_not_found);
    1375             : 
    1376             :     // Check if the element is a double hole, but don't load it.
    1377             :     LoadFixedDoubleArrayElement(elements, index_var.value(),
    1378             :                                 MachineType::None(), 0, INTPTR_PARAMETERS,
    1379          56 :                                 &return_found);
    1380             : 
    1381          56 :     Increment(&index_var);
    1382          56 :     Goto(&hole_loop);
    1383             :   }
    1384             : 
    1385         112 :   BIND(&return_found);
    1386         112 :   if (variant == kIncludes) {
    1387          56 :     Return(TrueConstant());
    1388             :   } else {
    1389          56 :     Return(SmiTag(index_var.value()));
    1390             :   }
    1391             : 
    1392         112 :   BIND(&return_not_found);
    1393         112 :   if (variant == kIncludes) {
    1394          56 :     Return(FalseConstant());
    1395             :   } else {
    1396          56 :     Return(NumberConstant(-1));
    1397             :   }
    1398         112 : }
    1399             : 
    1400         336 : TF_BUILTIN(ArrayIncludes, ArrayIncludesIndexofAssembler) {
    1401             :   TNode<IntPtrT> argc =
    1402          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1403          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1404             : 
    1405          56 :   Generate(kIncludes, argc, context);
    1406          56 : }
    1407             : 
    1408         504 : TF_BUILTIN(ArrayIncludesSmiOrObject, ArrayIncludesIndexofAssembler) {
    1409          56 :   Node* context = Parameter(Descriptor::kContext);
    1410          56 :   Node* elements = Parameter(Descriptor::kElements);
    1411          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    1412          56 :   Node* array_length = Parameter(Descriptor::kLength);
    1413          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    1414             : 
    1415          56 :   GenerateSmiOrObject(kIncludes, context, elements, search_element,
    1416          56 :                       array_length, from_index);
    1417          56 : }
    1418             : 
    1419         448 : TF_BUILTIN(ArrayIncludesPackedDoubles, ArrayIncludesIndexofAssembler) {
    1420          56 :   Node* elements = Parameter(Descriptor::kElements);
    1421          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    1422          56 :   Node* array_length = Parameter(Descriptor::kLength);
    1423          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    1424             : 
    1425          56 :   GeneratePackedDoubles(kIncludes, elements, search_element, array_length,
    1426          56 :                         from_index);
    1427          56 : }
    1428             : 
    1429         448 : TF_BUILTIN(ArrayIncludesHoleyDoubles, ArrayIncludesIndexofAssembler) {
    1430          56 :   Node* elements = Parameter(Descriptor::kElements);
    1431          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    1432          56 :   Node* array_length = Parameter(Descriptor::kLength);
    1433          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    1434             : 
    1435          56 :   GenerateHoleyDoubles(kIncludes, elements, search_element, array_length,
    1436          56 :                        from_index);
    1437          56 : }
    1438             : 
    1439         336 : TF_BUILTIN(ArrayIndexOf, ArrayIncludesIndexofAssembler) {
    1440             :   TNode<IntPtrT> argc =
    1441          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1442          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1443             : 
    1444          56 :   Generate(kIndexOf, argc, context);
    1445          56 : }
    1446             : 
    1447         504 : TF_BUILTIN(ArrayIndexOfSmiOrObject, ArrayIncludesIndexofAssembler) {
    1448          56 :   Node* context = Parameter(Descriptor::kContext);
    1449          56 :   Node* elements = Parameter(Descriptor::kElements);
    1450          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    1451          56 :   Node* array_length = Parameter(Descriptor::kLength);
    1452          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    1453             : 
    1454          56 :   GenerateSmiOrObject(kIndexOf, context, elements, search_element, array_length,
    1455          56 :                       from_index);
    1456          56 : }
    1457             : 
    1458         448 : TF_BUILTIN(ArrayIndexOfPackedDoubles, ArrayIncludesIndexofAssembler) {
    1459          56 :   Node* elements = Parameter(Descriptor::kElements);
    1460          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    1461          56 :   Node* array_length = Parameter(Descriptor::kLength);
    1462          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    1463             : 
    1464          56 :   GeneratePackedDoubles(kIndexOf, elements, search_element, array_length,
    1465          56 :                         from_index);
    1466          56 : }
    1467             : 
    1468         448 : TF_BUILTIN(ArrayIndexOfHoleyDoubles, ArrayIncludesIndexofAssembler) {
    1469          56 :   Node* elements = Parameter(Descriptor::kElements);
    1470          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    1471          56 :   Node* array_length = Parameter(Descriptor::kLength);
    1472          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    1473             : 
    1474          56 :   GenerateHoleyDoubles(kIndexOf, elements, search_element, array_length,
    1475          56 :                        from_index);
    1476          56 : }
    1477             : 
    1478             : // ES #sec-array.prototype.values
    1479         336 : TF_BUILTIN(ArrayPrototypeValues, CodeStubAssembler) {
    1480          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1481          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1482         224 :   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
    1483         168 :                              IterationKind::kValues));
    1484          56 : }
    1485             : 
    1486             : // ES #sec-array.prototype.entries
    1487         336 : TF_BUILTIN(ArrayPrototypeEntries, CodeStubAssembler) {
    1488          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1489          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1490         224 :   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
    1491         168 :                              IterationKind::kEntries));
    1492          56 : }
    1493             : 
    1494             : // ES #sec-array.prototype.keys
    1495         336 : TF_BUILTIN(ArrayPrototypeKeys, CodeStubAssembler) {
    1496          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1497          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1498         224 :   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
    1499         168 :                              IterationKind::kKeys));
    1500          56 : }
    1501             : 
    1502             : // ES #sec-%arrayiteratorprototype%.next
    1503         336 : TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
    1504          56 :   const char* method_name = "Array Iterator.prototype.next";
    1505             : 
    1506          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1507          56 :   Node* iterator = Parameter(Descriptor::kReceiver);
    1508             : 
    1509         112 :   VARIABLE(var_done, MachineRepresentation::kTagged, TrueConstant());
    1510         112 :   VARIABLE(var_value, MachineRepresentation::kTagged, UndefinedConstant());
    1511             : 
    1512         112 :   Label allocate_entry_if_needed(this);
    1513         112 :   Label allocate_iterator_result(this);
    1514         112 :   Label if_typedarray(this), if_other(this, Label::kDeferred), if_array(this),
    1515         112 :       if_generic(this, Label::kDeferred);
    1516         112 :   Label set_done(this, Label::kDeferred);
    1517             : 
    1518             :   // If O does not have all of the internal slots of an Array Iterator Instance
    1519             :   // (22.1.5.3), throw a TypeError exception
    1520          56 :   ThrowIfNotInstanceType(context, iterator, JS_ARRAY_ITERATOR_TYPE,
    1521          56 :                          method_name);
    1522             : 
    1523             :   // Let a be O.[[IteratedObject]].
    1524             :   TNode<JSReceiver> array =
    1525          56 :       CAST(LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset));
    1526             : 
    1527             :   // Let index be O.[[ArrayIteratorNextIndex]].
    1528             :   TNode<Number> index =
    1529          56 :       CAST(LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset));
    1530             :   CSA_ASSERT(this, IsNumberNonNegativeSafeInteger(index));
    1531             : 
    1532             :   // Dispatch based on the type of the {array}.
    1533          56 :   TNode<Map> array_map = LoadMap(array);
    1534          56 :   TNode<Int32T> array_type = LoadMapInstanceType(array_map);
    1535          56 :   GotoIf(InstanceTypeEqual(array_type, JS_ARRAY_TYPE), &if_array);
    1536         112 :   Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_typedarray,
    1537          56 :          &if_other);
    1538             : 
    1539          56 :   BIND(&if_array);
    1540             :   {
    1541             :     // If {array} is a JSArray, then the {index} must be in Unsigned32 range.
    1542             :     CSA_ASSERT(this, IsNumberArrayIndex(index));
    1543             : 
    1544             :     // Check that the {index} is within range for the {array}. We handle all
    1545             :     // kinds of JSArray's here, so we do the computation on Uint32.
    1546          56 :     TNode<Uint32T> index32 = ChangeNumberToUint32(index);
    1547             :     TNode<Uint32T> length32 =
    1548          56 :         ChangeNumberToUint32(LoadJSArrayLength(CAST(array)));
    1549          56 :     GotoIfNot(Uint32LessThan(index32, length32), &set_done);
    1550          56 :     StoreObjectField(
    1551             :         iterator, JSArrayIterator::kNextIndexOffset,
    1552         112 :         ChangeUint32ToTagged(Unsigned(Int32Add(index32, Int32Constant(1)))));
    1553             : 
    1554          56 :     var_done.Bind(FalseConstant());
    1555          56 :     var_value.Bind(index);
    1556             : 
    1557         224 :     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
    1558          56 :                            iterator, JSArrayIterator::kKindOffset),
    1559         224 :                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
    1560          56 :            &allocate_iterator_result);
    1561             : 
    1562         112 :     Label if_hole(this, Label::kDeferred);
    1563          56 :     TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
    1564          56 :     TNode<FixedArrayBase> elements = LoadElements(CAST(array));
    1565          56 :     GotoIfForceSlowPath(&if_generic);
    1566         112 :     var_value.Bind(LoadFixedArrayBaseElementAsTagged(
    1567         112 :         elements, Signed(ChangeUint32ToWord(index32)), elements_kind,
    1568         168 :         &if_generic, &if_hole));
    1569          56 :     Goto(&allocate_entry_if_needed);
    1570             : 
    1571          56 :     BIND(&if_hole);
    1572             :     {
    1573          56 :       GotoIf(IsNoElementsProtectorCellInvalid(), &if_generic);
    1574         112 :       GotoIfNot(IsPrototypeInitialArrayPrototype(context, array_map),
    1575          56 :                 &if_generic);
    1576          56 :       var_value.Bind(UndefinedConstant());
    1577          56 :       Goto(&allocate_entry_if_needed);
    1578             :     }
    1579             :   }
    1580             : 
    1581          56 :   BIND(&if_other);
    1582             :   {
    1583             :     // We cannot enter here with either JSArray's or JSTypedArray's.
    1584             :     CSA_ASSERT(this, Word32BinaryNot(IsJSArray(array)));
    1585             :     CSA_ASSERT(this, Word32BinaryNot(IsJSTypedArray(array)));
    1586             : 
    1587             :     // Check that the {index} is within the bounds of the {array}s "length".
    1588         112 :     TNode<Number> length = CAST(
    1589             :         CallBuiltin(Builtins::kToLength, context,
    1590             :                     GetProperty(context, array, factory()->length_string())));
    1591          56 :     GotoIfNumberGreaterThanOrEqual(index, length, &set_done);
    1592          56 :     StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset,
    1593         112 :                      NumberInc(index));
    1594             : 
    1595          56 :     var_done.Bind(FalseConstant());
    1596          56 :     var_value.Bind(index);
    1597             : 
    1598         224 :     Branch(Word32Equal(LoadAndUntagToWord32ObjectField(
    1599          56 :                            iterator, JSArrayIterator::kKindOffset),
    1600         224 :                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
    1601          56 :            &allocate_iterator_result, &if_generic);
    1602             :   }
    1603             : 
    1604          56 :   BIND(&set_done);
    1605             :   {
    1606             :     // Change the [[ArrayIteratorNextIndex]] such that the {iterator} will
    1607             :     // never produce values anymore, because it will always fail the bounds
    1608             :     // check. Note that this is different from what the specification does,
    1609             :     // which is changing the [[IteratedObject]] to undefined, because leaving
    1610             :     // [[IteratedObject]] alone helps TurboFan to generate better code with
    1611             :     // the inlining in JSCallReducer::ReduceArrayIteratorPrototypeNext().
    1612             :     //
    1613             :     // The terminal value we chose here depends on the type of the {array},
    1614             :     // for JSArray's we use kMaxUInt32 so that TurboFan can always use
    1615             :     // Word32 representation for fast-path indices (and this is safe since
    1616             :     // the "length" of JSArray's is limited to Unsigned32 range). For other
    1617             :     // JSReceiver's we have to use kMaxSafeInteger, since the "length" can
    1618             :     // be any arbitrary value in the safe integer range.
    1619             :     //
    1620             :     // Note specifically that JSTypedArray's will never take this path, so
    1621             :     // we don't need to worry about their maximum value.
    1622             :     CSA_ASSERT(this, Word32BinaryNot(IsJSTypedArray(array)));
    1623             :     TNode<Number> max_length =
    1624             :         SelectConstant(IsJSArray(array), NumberConstant(kMaxUInt32),
    1625          56 :                        NumberConstant(kMaxSafeInteger));
    1626          56 :     StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, max_length);
    1627          56 :     Goto(&allocate_iterator_result);
    1628             :   }
    1629             : 
    1630          56 :   BIND(&if_generic);
    1631             :   {
    1632          56 :     var_value.Bind(GetProperty(context, array, index));
    1633          56 :     Goto(&allocate_entry_if_needed);
    1634             :   }
    1635             : 
    1636          56 :   BIND(&if_typedarray);
    1637             :   {
    1638             :     // If {array} is a JSTypedArray, the {index} must always be a Smi.
    1639             :     CSA_ASSERT(this, TaggedIsSmi(index));
    1640             : 
    1641             :     // Check that the {array}s buffer wasn't detached.
    1642          56 :     ThrowIfArrayBufferViewBufferIsDetached(context, CAST(array), method_name);
    1643             : 
    1644             :     // If we go outside of the {length}, we don't need to update the
    1645             :     // [[ArrayIteratorNextIndex]] anymore, since a JSTypedArray's
    1646             :     // length cannot change anymore, so this {iterator} will never
    1647             :     // produce values again anyways.
    1648          56 :     TNode<Smi> length = LoadJSTypedArrayLength(CAST(array));
    1649          56 :     GotoIfNot(SmiBelow(CAST(index), length), &allocate_iterator_result);
    1650          56 :     StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
    1651         112 :                                    SmiInc(CAST(index)));
    1652             : 
    1653          56 :     var_done.Bind(FalseConstant());
    1654          56 :     var_value.Bind(index);
    1655             : 
    1656         224 :     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
    1657          56 :                            iterator, JSArrayIterator::kKindOffset),
    1658         224 :                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
    1659          56 :            &allocate_iterator_result);
    1660             : 
    1661          56 :     TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
    1662          56 :     Node* elements = LoadElements(CAST(array));
    1663             :     Node* base_ptr =
    1664          56 :         LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
    1665             :     Node* external_ptr =
    1666         112 :         LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
    1667          56 :                         MachineType::Pointer());
    1668             :     TNode<WordT> data_ptr =
    1669          56 :         IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
    1670         168 :     var_value.Bind(LoadFixedTypedArrayElementAsTagged(data_ptr, CAST(index),
    1671         112 :                                                       elements_kind));
    1672          56 :     Goto(&allocate_entry_if_needed);
    1673             :   }
    1674             : 
    1675          56 :   BIND(&allocate_entry_if_needed);
    1676             :   {
    1677         224 :     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
    1678          56 :                            iterator, JSArrayIterator::kKindOffset),
    1679         224 :                        Int32Constant(static_cast<int>(IterationKind::kValues))),
    1680          56 :            &allocate_iterator_result);
    1681             : 
    1682             :     Node* result =
    1683          56 :         AllocateJSIteratorResultForEntry(context, index, var_value.value());
    1684          56 :     Return(result);
    1685             :   }
    1686             : 
    1687          56 :   BIND(&allocate_iterator_result);
    1688             :   {
    1689             :     Node* result =
    1690          56 :         AllocateJSIteratorResult(context, var_value.value(), var_done.value());
    1691          56 :     Return(result);
    1692             :   }
    1693          56 : }
    1694             : 
    1695         112 : class ArrayFlattenAssembler : public CodeStubAssembler {
    1696             :  public:
    1697         112 :   explicit ArrayFlattenAssembler(compiler::CodeAssemblerState* state)
    1698         112 :       : CodeStubAssembler(state) {}
    1699             : 
    1700             :   // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
    1701         112 :   Node* FlattenIntoArray(Node* context, Node* target, Node* source,
    1702             :                          Node* source_length, Node* start, Node* depth,
    1703             :                          Node* mapper_function = nullptr,
    1704             :                          Node* this_arg = nullptr) {
    1705             :     CSA_ASSERT(this, IsJSReceiver(target));
    1706             :     CSA_ASSERT(this, IsJSReceiver(source));
    1707             :     CSA_ASSERT(this, IsNumberPositive(source_length));
    1708             :     CSA_ASSERT(this, IsNumberPositive(start));
    1709             :     CSA_ASSERT(this, IsNumber(depth));
    1710             : 
    1711             :     // 1. Let targetIndex be start.
    1712         224 :     VARIABLE(var_target_index, MachineRepresentation::kTagged, start);
    1713             : 
    1714             :     // 2. Let sourceIndex be 0.
    1715         224 :     VARIABLE(var_source_index, MachineRepresentation::kTagged, SmiConstant(0));
    1716             : 
    1717             :     // 3. Repeat...
    1718         224 :     Label loop(this, {&var_target_index, &var_source_index}), done_loop(this);
    1719         112 :     Goto(&loop);
    1720         112 :     BIND(&loop);
    1721             :     {
    1722         112 :       Node* const source_index = var_source_index.value();
    1723         112 :       Node* const target_index = var_target_index.value();
    1724             : 
    1725             :       // ...while sourceIndex < sourceLen
    1726         112 :       GotoIfNumberGreaterThanOrEqual(source_index, source_length, &done_loop);
    1727             : 
    1728             :       // a. Let P be ! ToString(sourceIndex).
    1729             :       // b. Let exists be ? HasProperty(source, P).
    1730             :       CSA_ASSERT(this,
    1731             :                  SmiGreaterThanOrEqual(CAST(source_index), SmiConstant(0)));
    1732             :       Node* const exists =
    1733         112 :           HasProperty(context, source, source_index, kHasProperty);
    1734             : 
    1735             :       // c. If exists is true, then
    1736         224 :       Label next(this);
    1737         112 :       GotoIfNot(IsTrue(exists), &next);
    1738             :       {
    1739             :         // i. Let element be ? Get(source, P).
    1740         112 :         Node* element = GetProperty(context, source, source_index);
    1741             : 
    1742             :         // ii. If mapperFunction is present, then
    1743         112 :         if (mapper_function != nullptr) {
    1744             :           CSA_ASSERT(this, Word32Or(IsUndefined(mapper_function),
    1745             :                                     IsCallable(mapper_function)));
    1746             :           DCHECK_NOT_NULL(this_arg);
    1747             : 
    1748             :           // 1. Set element to ? Call(mapperFunction, thisArg , « element,
    1749             :           //                          sourceIndex, source »).
    1750             :           element =
    1751         112 :               CallJS(CodeFactory::Call(isolate()), context, mapper_function,
    1752          56 :                      this_arg, element, source_index, source);
    1753             :         }
    1754             : 
    1755             :         // iii. Let shouldFlatten be false.
    1756         224 :         Label if_flatten_array(this), if_flatten_proxy(this, Label::kDeferred),
    1757         224 :             if_noflatten(this);
    1758             :         // iv. If depth > 0, then
    1759         112 :         GotoIfNumberGreaterThanOrEqual(SmiConstant(0), depth, &if_noflatten);
    1760             :         // 1. Set shouldFlatten to ? IsArray(element).
    1761         112 :         GotoIf(TaggedIsSmi(element), &if_noflatten);
    1762         112 :         GotoIf(IsJSArray(element), &if_flatten_array);
    1763         112 :         GotoIfNot(IsJSProxy(element), &if_noflatten);
    1764         224 :         Branch(IsTrue(CallRuntime(Runtime::kArrayIsArray, context, element)),
    1765         112 :                &if_flatten_proxy, &if_noflatten);
    1766             : 
    1767         112 :         BIND(&if_flatten_array);
    1768             :         {
    1769             :           CSA_ASSERT(this, IsJSArray(element));
    1770             : 
    1771             :           // 1. Let elementLen be ? ToLength(? Get(element, "length")).
    1772             :           Node* const element_length =
    1773         112 :               LoadObjectField(element, JSArray::kLengthOffset);
    1774             : 
    1775             :           // 2. Set targetIndex to ? FlattenIntoArray(target, element,
    1776             :           //                                          elementLen, targetIndex,
    1777             :           //                                          depth - 1).
    1778         112 :           var_target_index.Bind(
    1779         224 :               CallBuiltin(Builtins::kFlattenIntoArray, context, target, element,
    1780         336 :                           element_length, target_index, NumberDec(depth)));
    1781         112 :           Goto(&next);
    1782             :         }
    1783             : 
    1784         112 :         BIND(&if_flatten_proxy);
    1785             :         {
    1786             :           CSA_ASSERT(this, IsJSProxy(element));
    1787             : 
    1788             :           // 1. Let elementLen be ? ToLength(? Get(element, "length")).
    1789         224 :           Node* const element_length = ToLength_Inline(
    1790         336 :               context, GetProperty(context, element, LengthStringConstant()));
    1791             : 
    1792             :           // 2. Set targetIndex to ? FlattenIntoArray(target, element,
    1793             :           //                                          elementLen, targetIndex,
    1794             :           //                                          depth - 1).
    1795         112 :           var_target_index.Bind(
    1796         224 :               CallBuiltin(Builtins::kFlattenIntoArray, context, target, element,
    1797         336 :                           element_length, target_index, NumberDec(depth)));
    1798         112 :           Goto(&next);
    1799             :         }
    1800             : 
    1801         112 :         BIND(&if_noflatten);
    1802             :         {
    1803             :           // 1. If targetIndex >= 2^53-1, throw a TypeError exception.
    1804         224 :           Label throw_error(this, Label::kDeferred);
    1805         112 :           GotoIfNumberGreaterThanOrEqual(
    1806         224 :               target_index, NumberConstant(kMaxSafeInteger), &throw_error);
    1807             : 
    1808             :           // 2. Perform ? CreateDataPropertyOrThrow(target,
    1809             :           //                                        ! ToString(targetIndex),
    1810             :           //                                        element).
    1811             :           CallRuntime(Runtime::kCreateDataProperty, context, target,
    1812         112 :                       target_index, element);
    1813             : 
    1814             :           // 3. Increase targetIndex by 1.
    1815         112 :           var_target_index.Bind(NumberInc(target_index));
    1816         112 :           Goto(&next);
    1817             : 
    1818         112 :           BIND(&throw_error);
    1819         112 :           ThrowTypeError(context, MessageTemplate::kFlattenPastSafeLength,
    1820         112 :                          source_length, target_index);
    1821             :         }
    1822             :       }
    1823         112 :       BIND(&next);
    1824             : 
    1825             :       // d. Increase sourceIndex by 1.
    1826         112 :       var_source_index.Bind(NumberInc(source_index));
    1827         112 :       Goto(&loop);
    1828             :     }
    1829             : 
    1830         112 :     BIND(&done_loop);
    1831         224 :     return var_target_index.value();
    1832             :   }
    1833             : };
    1834             : 
    1835             : // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
    1836         560 : TF_BUILTIN(FlattenIntoArray, ArrayFlattenAssembler) {
    1837          56 :   Node* const context = Parameter(Descriptor::kContext);
    1838          56 :   Node* const target = Parameter(Descriptor::kTarget);
    1839          56 :   Node* const source = Parameter(Descriptor::kSource);
    1840          56 :   Node* const source_length = Parameter(Descriptor::kSourceLength);
    1841          56 :   Node* const start = Parameter(Descriptor::kStart);
    1842          56 :   Node* const depth = Parameter(Descriptor::kDepth);
    1843             : 
    1844             :   // FlattenIntoArray might get called recursively, check stack for overflow
    1845             :   // manually as it has stub linkage.
    1846          56 :   PerformStackCheck(CAST(context));
    1847             : 
    1848         112 :   Return(
    1849          56 :       FlattenIntoArray(context, target, source, source_length, start, depth));
    1850          56 : }
    1851             : 
    1852             : // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
    1853         672 : TF_BUILTIN(FlatMapIntoArray, ArrayFlattenAssembler) {
    1854          56 :   Node* const context = Parameter(Descriptor::kContext);
    1855          56 :   Node* const target = Parameter(Descriptor::kTarget);
    1856          56 :   Node* const source = Parameter(Descriptor::kSource);
    1857          56 :   Node* const source_length = Parameter(Descriptor::kSourceLength);
    1858          56 :   Node* const start = Parameter(Descriptor::kStart);
    1859          56 :   Node* const depth = Parameter(Descriptor::kDepth);
    1860          56 :   Node* const mapper_function = Parameter(Descriptor::kMapperFunction);
    1861          56 :   Node* const this_arg = Parameter(Descriptor::kThisArg);
    1862             : 
    1863         112 :   Return(FlattenIntoArray(context, target, source, source_length, start, depth,
    1864          56 :                           mapper_function, this_arg));
    1865          56 : }
    1866             : 
    1867             : // https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flat
    1868         336 : TF_BUILTIN(ArrayPrototypeFlat, CodeStubAssembler) {
    1869             :   TNode<IntPtrT> const argc =
    1870          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1871          56 :   CodeStubArguments args(this, argc);
    1872          56 :   TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
    1873          56 :   TNode<Object> const receiver = args.GetReceiver();
    1874          56 :   TNode<Object> const depth = args.GetOptionalArgumentValue(0);
    1875             : 
    1876             :   // 1. Let O be ? ToObject(this value).
    1877          56 :   TNode<JSReceiver> const o = ToObject_Inline(context, receiver);
    1878             : 
    1879             :   // 2. Let sourceLen be ? ToLength(? Get(O, "length")).
    1880             :   TNode<Number> const source_length =
    1881          56 :       ToLength_Inline(context, GetProperty(context, o, LengthStringConstant()));
    1882             : 
    1883             :   // 3. Let depthNum be 1.
    1884         112 :   TVARIABLE(Number, var_depth_num, SmiConstant(1));
    1885             : 
    1886             :   // 4. If depth is not undefined, then
    1887         112 :   Label done(this);
    1888          56 :   GotoIf(IsUndefined(depth), &done);
    1889             :   {
    1890             :     // a. Set depthNum to ? ToInteger(depth).
    1891          56 :     var_depth_num = ToInteger_Inline(context, depth);
    1892          56 :     Goto(&done);
    1893             :   }
    1894          56 :   BIND(&done);
    1895             : 
    1896             :   // 5. Let A be ? ArraySpeciesCreate(O, 0).
    1897             :   TNode<JSReceiver> const constructor =
    1898          56 :       CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context, o));
    1899          56 :   Node* const a = Construct(context, constructor, SmiConstant(0));
    1900             : 
    1901             :   // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
    1902             :   CallBuiltin(Builtins::kFlattenIntoArray, context, a, o, source_length,
    1903          56 :               SmiConstant(0), var_depth_num.value());
    1904             : 
    1905             :   // 7. Return A.
    1906          56 :   args.PopAndReturn(a);
    1907          56 : }
    1908             : 
    1909             : // https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap
    1910         336 : TF_BUILTIN(ArrayPrototypeFlatMap, CodeStubAssembler) {
    1911             :   TNode<IntPtrT> const argc =
    1912          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1913          56 :   CodeStubArguments args(this, argc);
    1914          56 :   TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
    1915          56 :   TNode<Object> const receiver = args.GetReceiver();
    1916          56 :   TNode<Object> const mapper_function = args.GetOptionalArgumentValue(0);
    1917             : 
    1918             :   // 1. Let O be ? ToObject(this value).
    1919          56 :   TNode<JSReceiver> const o = ToObject_Inline(context, receiver);
    1920             : 
    1921             :   // 2. Let sourceLen be ? ToLength(? Get(O, "length")).
    1922             :   TNode<Number> const source_length =
    1923          56 :       ToLength_Inline(context, GetProperty(context, o, LengthStringConstant()));
    1924             : 
    1925             :   // 3. If IsCallable(mapperFunction) is false, throw a TypeError exception.
    1926         112 :   Label if_not_callable(this, Label::kDeferred);
    1927          56 :   GotoIf(TaggedIsSmi(mapper_function), &if_not_callable);
    1928          56 :   GotoIfNot(IsCallable(CAST(mapper_function)), &if_not_callable);
    1929             : 
    1930             :   // 4. If thisArg is present, let T be thisArg; else let T be undefined.
    1931          56 :   TNode<Object> const t = args.GetOptionalArgumentValue(1);
    1932             : 
    1933             :   // 5. Let A be ? ArraySpeciesCreate(O, 0).
    1934             :   TNode<JSReceiver> const constructor =
    1935          56 :       CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context, o));
    1936          56 :   TNode<JSReceiver> const a = Construct(context, constructor, SmiConstant(0));
    1937             : 
    1938             :   // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
    1939             :   CallBuiltin(Builtins::kFlatMapIntoArray, context, a, o, source_length,
    1940          56 :               SmiConstant(0), SmiConstant(1), mapper_function, t);
    1941             : 
    1942             :   // 7. Return A.
    1943          56 :   args.PopAndReturn(a);
    1944             : 
    1945          56 :   BIND(&if_not_callable);
    1946          56 :   { ThrowTypeError(context, MessageTemplate::kMapperFunctionNonCallable); }
    1947          56 : }
    1948             : 
    1949         448 : TF_BUILTIN(ArrayConstructor, ArrayBuiltinsAssembler) {
    1950             :   // This is a trampoline to ArrayConstructorImpl which just adds
    1951             :   // allocation_site parameter value and sets new_target if necessary.
    1952          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1953          56 :   TNode<JSFunction> function = CAST(Parameter(Descriptor::kTarget));
    1954          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
    1955             :   TNode<Int32T> argc =
    1956          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
    1957             : 
    1958             :   // If new_target is undefined, then this is the 'Call' case, so set new_target
    1959             :   // to function.
    1960         112 :   new_target =
    1961          56 :       SelectConstant<Object>(IsUndefined(new_target), function, new_target);
    1962             : 
    1963             :   // Run the native code for the Array function called as a normal function.
    1964          56 :   TNode<Object> no_allocation_site = UndefinedConstant();
    1965         112 :   TailCallBuiltin(Builtins::kArrayConstructorImpl, context, function,
    1966          56 :                   new_target, argc, no_allocation_site);
    1967          56 : }
    1968             : 
    1969         784 : void ArrayBuiltinsAssembler::TailCallArrayConstructorStub(
    1970             :     const Callable& callable, TNode<Context> context, TNode<JSFunction> target,
    1971             :     TNode<HeapObject> allocation_site_or_undefined, TNode<Int32T> argc) {
    1972         784 :   TNode<Code> code = HeapConstant(callable.code());
    1973             : 
    1974             :   // We are going to call here ArrayNoArgumentsConstructor or
    1975             :   // ArraySingleArgumentsConstructor which in addition to the register arguments
    1976             :   // also expect some number of arguments on the expression stack.
    1977             :   // Since
    1978             :   // 1) incoming JS arguments are still on the stack,
    1979             :   // 2) the ArrayNoArgumentsConstructor, ArraySingleArgumentsConstructor and
    1980             :   //    ArrayNArgumentsConstructor are defined so that the register arguments
    1981             :   //    are passed on the same registers,
    1982             :   // in order to be able to generate a tail call to those builtins we do the
    1983             :   // following trick here: we tail call to the constructor builtin using
    1984             :   // ArrayNArgumentsConstructorDescriptor, so the tail call instruction
    1985             :   // pops the current frame but leaves all the incoming JS arguments on the
    1986             :   // expression stack so that the target builtin can still find them where it
    1987             :   // expects.
    1988        1568 :   TailCallStub(ArrayNArgumentsConstructorDescriptor{}, code, context, target,
    1989         784 :                allocation_site_or_undefined, argc);
    1990         784 : }
    1991             : 
    1992         112 : void ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument(
    1993             :     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
    1994             :     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
    1995         112 :   if (mode == DISABLE_ALLOCATION_SITES) {
    1996             :     Callable callable = CodeFactory::ArrayNoArgumentConstructor(
    1997         112 :         isolate(), GetInitialFastElementsKind(), mode);
    1998             : 
    1999         112 :     TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(),
    2000          56 :                                  argc);
    2001             :   } else {
    2002             :     DCHECK_EQ(mode, DONT_OVERRIDE);
    2003          56 :     TNode<Int32T> elements_kind = LoadElementsKind(allocation_site);
    2004             : 
    2005             :     // TODO(ishell): Compute the builtin index dynamically instead of
    2006             :     // iterating over all expected elements kinds.
    2007             :     int last_index =
    2008          56 :         GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
    2009         392 :     for (int i = 0; i <= last_index; ++i) {
    2010         672 :       Label next(this);
    2011         336 :       ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
    2012         336 :       GotoIfNot(Word32Equal(elements_kind, Int32Constant(kind)), &next);
    2013             : 
    2014             :       Callable callable =
    2015         672 :           CodeFactory::ArrayNoArgumentConstructor(isolate(), kind, mode);
    2016             : 
    2017         672 :       TailCallArrayConstructorStub(callable, context, target, allocation_site,
    2018         336 :                                    argc);
    2019             : 
    2020         336 :       BIND(&next);
    2021             :     }
    2022             : 
    2023             :     // If we reached this point there is a problem.
    2024          56 :     Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
    2025             :   }
    2026         112 : }
    2027             : 
    2028         112 : void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument(
    2029             :     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
    2030             :     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
    2031         112 :   if (mode == DISABLE_ALLOCATION_SITES) {
    2032          56 :     ElementsKind initial = GetInitialFastElementsKind();
    2033          56 :     ElementsKind holey_initial = GetHoleyElementsKind(initial);
    2034             :     Callable callable = CodeFactory::ArraySingleArgumentConstructor(
    2035         112 :         isolate(), holey_initial, mode);
    2036             : 
    2037         112 :     TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(),
    2038          56 :                                  argc);
    2039             :   } else {
    2040             :     DCHECK_EQ(mode, DONT_OVERRIDE);
    2041          56 :     TNode<Smi> transition_info = LoadTransitionInfo(allocation_site);
    2042             : 
    2043             :     // Least significant bit in fast array elements kind means holeyness.
    2044             :     STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
    2045             :     STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
    2046             :     STATIC_ASSERT(PACKED_ELEMENTS == 2);
    2047             :     STATIC_ASSERT(HOLEY_ELEMENTS == 3);
    2048             :     STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
    2049             :     STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
    2050             : 
    2051         112 :     Label normal_sequence(this);
    2052         112 :     TVARIABLE(Int32T, var_elements_kind,
    2053             :               Signed(DecodeWord32<AllocationSite::ElementsKindBits>(
    2054             :                   SmiToInt32(transition_info))));
    2055             :     // Is the low bit set? If so, we are holey and that is good.
    2056             :     int fast_elements_kind_holey_mask =
    2057          56 :         AllocationSite::ElementsKindBits::encode(static_cast<ElementsKind>(1));
    2058         112 :     GotoIf(IsSetSmi(transition_info, fast_elements_kind_holey_mask),
    2059          56 :            &normal_sequence);
    2060             :     {
    2061             :       // Make elements kind holey and update elements kind in the type info.
    2062         224 :       var_elements_kind =
    2063         280 :           Signed(Word32Or(var_elements_kind.value(), Int32Constant(1)));
    2064         112 :       StoreObjectFieldNoWriteBarrier(
    2065             :           allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset,
    2066          56 :           SmiOr(transition_info, SmiConstant(fast_elements_kind_holey_mask)));
    2067          56 :       Goto(&normal_sequence);
    2068             :     }
    2069          56 :     BIND(&normal_sequence);
    2070             : 
    2071             :     // TODO(ishell): Compute the builtin index dynamically instead of
    2072             :     // iterating over all expected elements kinds.
    2073             :     // TODO(ishell): Given that the code above ensures that the elements kind
    2074             :     // is holey we can skip checking with non-holey elements kinds.
    2075             :     int last_index =
    2076          56 :         GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
    2077         392 :     for (int i = 0; i <= last_index; ++i) {
    2078         672 :       Label next(this);
    2079         336 :       ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
    2080         672 :       GotoIfNot(Word32Equal(var_elements_kind.value(), Int32Constant(kind)),
    2081         336 :                 &next);
    2082             : 
    2083             :       Callable callable =
    2084         672 :           CodeFactory::ArraySingleArgumentConstructor(isolate(), kind, mode);
    2085             : 
    2086         672 :       TailCallArrayConstructorStub(callable, context, target, allocation_site,
    2087         336 :                                    argc);
    2088             : 
    2089         336 :       BIND(&next);
    2090             :     }
    2091             : 
    2092             :     // If we reached this point there is a problem.
    2093          56 :     Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
    2094             :   }
    2095         112 : }
    2096             : 
    2097         112 : void ArrayBuiltinsAssembler::GenerateDispatchToArrayStub(
    2098             :     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
    2099             :     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
    2100         224 :   Label check_one_case(this), fallthrough(this);
    2101         112 :   GotoIfNot(Word32Equal(argc, Int32Constant(0)), &check_one_case);
    2102         112 :   CreateArrayDispatchNoArgument(context, target, argc, mode, allocation_site);
    2103             : 
    2104         112 :   BIND(&check_one_case);
    2105         112 :   GotoIfNot(Word32Equal(argc, Int32Constant(1)), &fallthrough);
    2106             :   CreateArrayDispatchSingleArgument(context, target, argc, mode,
    2107         112 :                                     allocation_site);
    2108             : 
    2109         112 :   BIND(&fallthrough);
    2110         112 : }
    2111             : 
    2112         448 : TF_BUILTIN(ArrayConstructorImpl, ArrayBuiltinsAssembler) {
    2113          56 :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
    2114          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
    2115             :   TNode<Int32T> argc =
    2116          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
    2117             :   TNode<HeapObject> maybe_allocation_site =
    2118          56 :       CAST(Parameter(Descriptor::kAllocationSite));
    2119             : 
    2120             :   // Initial map for the builtin Array functions should be Map.
    2121             :   CSA_ASSERT(this, IsMap(CAST(LoadObjectField(
    2122             :                        target, JSFunction::kPrototypeOrInitialMapOffset))));
    2123             : 
    2124             :   // We should either have undefined or a valid AllocationSite
    2125             :   CSA_ASSERT(this, Word32Or(IsUndefined(maybe_allocation_site),
    2126             :                             IsAllocationSite(maybe_allocation_site)));
    2127             : 
    2128             :   // "Enter" the context of the Array function.
    2129             :   TNode<Context> context =
    2130          56 :       CAST(LoadObjectField(target, JSFunction::kContextOffset));
    2131             : 
    2132         112 :   Label runtime(this, Label::kDeferred);
    2133          56 :   GotoIf(WordNotEqual(target, new_target), &runtime);
    2134             : 
    2135         112 :   Label no_info(this);
    2136             :   // If the feedback vector is the undefined value call an array constructor
    2137             :   // that doesn't use AllocationSites.
    2138          56 :   GotoIf(IsUndefined(maybe_allocation_site), &no_info);
    2139             : 
    2140          56 :   GenerateDispatchToArrayStub(context, target, argc, DONT_OVERRIDE,
    2141         112 :                               CAST(maybe_allocation_site));
    2142          56 :   Goto(&runtime);
    2143             : 
    2144          56 :   BIND(&no_info);
    2145          56 :   GenerateDispatchToArrayStub(context, target, argc, DISABLE_ALLOCATION_SITES);
    2146          56 :   Goto(&runtime);
    2147             : 
    2148          56 :   BIND(&runtime);
    2149          56 :   GenerateArrayNArgumentsConstructor(context, target, new_target, argc,
    2150          56 :                                      maybe_allocation_site);
    2151          56 : }
    2152             : 
    2153         448 : void ArrayBuiltinsAssembler::GenerateConstructor(
    2154             :     Node* context, Node* array_function, Node* array_map, Node* array_size,
    2155             :     Node* allocation_site, ElementsKind elements_kind,
    2156             :     AllocationSiteMode mode) {
    2157         896 :   Label ok(this);
    2158         896 :   Label smi_size(this);
    2159         896 :   Label small_smi_size(this);
    2160         896 :   Label call_runtime(this, Label::kDeferred);
    2161             : 
    2162         448 :   Branch(TaggedIsSmi(array_size), &smi_size, &call_runtime);
    2163             : 
    2164         448 :   BIND(&smi_size);
    2165             : 
    2166         448 :   if (IsFastPackedElementsKind(elements_kind)) {
    2167         448 :     Label abort(this, Label::kDeferred);
    2168         224 :     Branch(SmiEqual(CAST(array_size), SmiConstant(0)), &small_smi_size, &abort);
    2169             : 
    2170         224 :     BIND(&abort);
    2171         224 :     Node* reason = SmiConstant(AbortReason::kAllocatingNonEmptyPackedArray);
    2172         224 :     TailCallRuntime(Runtime::kAbort, context, reason);
    2173             :   } else {
    2174             :     int element_size =
    2175         224 :         IsDoubleElementsKind(elements_kind) ? kDoubleSize : kTaggedSize;
    2176             :     int max_fast_elements =
    2177             :         (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize -
    2178             :          AllocationMemento::kSize) /
    2179         224 :         element_size;
    2180         448 :     Branch(SmiAboveOrEqual(CAST(array_size), SmiConstant(max_fast_elements)),
    2181         224 :            &call_runtime, &small_smi_size);
    2182             :   }
    2183             : 
    2184         448 :   BIND(&small_smi_size);
    2185             :   {
    2186             :     TNode<JSArray> array = AllocateJSArray(
    2187        1344 :         elements_kind, CAST(array_map), array_size, CAST(array_size),
    2188             :         mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site,
    2189        1792 :         CodeStubAssembler::SMI_PARAMETERS);
    2190         448 :     Return(array);
    2191             :   }
    2192             : 
    2193         448 :   BIND(&call_runtime);
    2194             :   {
    2195         896 :     TailCallRuntime(Runtime::kNewArray, context, array_function, array_size,
    2196         448 :                     array_function, allocation_site);
    2197             :   }
    2198         448 : }
    2199             : 
    2200         448 : void ArrayBuiltinsAssembler::GenerateArrayNoArgumentConstructor(
    2201             :     ElementsKind kind, AllocationSiteOverrideMode mode) {
    2202             :   typedef ArrayNoArgumentConstructorDescriptor Descriptor;
    2203         896 :   Node* native_context = LoadObjectField(Parameter(Descriptor::kFunction),
    2204        1344 :                                          JSFunction::kContextOffset);
    2205             :   bool track_allocation_site =
    2206         448 :       AllocationSite::ShouldTrack(kind) && mode != DISABLE_ALLOCATION_SITES;
    2207             :   Node* allocation_site =
    2208         448 :       track_allocation_site ? Parameter(Descriptor::kAllocationSite) : nullptr;
    2209         448 :   TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context);
    2210             :   TNode<JSArray> array = AllocateJSArray(
    2211         896 :       kind, array_map, IntPtrConstant(JSArray::kPreallocatedArrayElements),
    2212        1344 :       SmiConstant(0), allocation_site);
    2213         448 :   Return(array);
    2214         448 : }
    2215             : 
    2216         448 : void ArrayBuiltinsAssembler::GenerateArraySingleArgumentConstructor(
    2217             :     ElementsKind kind, AllocationSiteOverrideMode mode) {
    2218             :   typedef ArraySingleArgumentConstructorDescriptor Descriptor;
    2219         448 :   Node* context = Parameter(Descriptor::kContext);
    2220         448 :   Node* function = Parameter(Descriptor::kFunction);
    2221         448 :   Node* native_context = LoadObjectField(function, JSFunction::kContextOffset);
    2222         448 :   Node* array_map = LoadJSArrayElementsMap(kind, native_context);
    2223             : 
    2224         448 :   AllocationSiteMode allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
    2225         448 :   if (mode == DONT_OVERRIDE) {
    2226         112 :     allocation_site_mode = AllocationSite::ShouldTrack(kind)
    2227             :                                ? TRACK_ALLOCATION_SITE
    2228         112 :                                : DONT_TRACK_ALLOCATION_SITE;
    2229             :   }
    2230             : 
    2231         448 :   Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
    2232         448 :   Node* allocation_site = Parameter(Descriptor::kAllocationSite);
    2233             : 
    2234         448 :   GenerateConstructor(context, function, array_map, array_size, allocation_site,
    2235         448 :                       kind, allocation_site_mode);
    2236         448 : }
    2237             : 
    2238         112 : void ArrayBuiltinsAssembler::GenerateArrayNArgumentsConstructor(
    2239             :     TNode<Context> context, TNode<JSFunction> target, TNode<Object> new_target,
    2240             :     TNode<Int32T> argc, TNode<HeapObject> maybe_allocation_site) {
    2241             :   // Replace incoming JS receiver argument with the target.
    2242             :   // TODO(ishell): Avoid replacing the target on the stack and just add it
    2243             :   // as another additional parameter for Runtime::kNewArray.
    2244         112 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
    2245         112 :   args.SetReceiver(target);
    2246             : 
    2247             :   // Adjust arguments count for the runtime call: +1 for implicit receiver
    2248             :   // and +2 for new_target and maybe_allocation_site.
    2249         112 :   argc = Int32Add(argc, Int32Constant(3));
    2250         224 :   TailCallRuntime(Runtime::kNewArray, argc, context, new_target,
    2251         112 :                   maybe_allocation_site);
    2252         112 : }
    2253             : 
    2254         448 : TF_BUILTIN(ArrayNArgumentsConstructor, ArrayBuiltinsAssembler) {
    2255          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2256          56 :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kFunction));
    2257             :   TNode<Int32T> argc =
    2258          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
    2259             :   TNode<HeapObject> maybe_allocation_site =
    2260          56 :       CAST(Parameter(Descriptor::kAllocationSite));
    2261             : 
    2262         112 :   GenerateArrayNArgumentsConstructor(context, target, target, argc,
    2263          56 :                                      maybe_allocation_site);
    2264          56 : }
    2265             : 
    2266             : #define GENERATE_ARRAY_CTOR(name, kind_camel, kind_caps, mode_camel, \
    2267             :                             mode_caps)                               \
    2268             :   TF_BUILTIN(Array##name##Constructor_##kind_camel##_##mode_camel,   \
    2269             :              ArrayBuiltinsAssembler) {                               \
    2270             :     GenerateArray##name##Constructor(kind_caps, mode_caps);          \
    2271             :   }
    2272             : 
    2273             : // The ArrayNoArgumentConstructor builtin family.
    2274         224 : GENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS, DontOverride,
    2275             :                     DONT_OVERRIDE)
    2276         224 : GENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride,
    2277             :                     DONT_OVERRIDE)
    2278         224 : GENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS,
    2279             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2280         224 : GENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS,
    2281             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2282         224 : GENERATE_ARRAY_CTOR(NoArgument, Packed, PACKED_ELEMENTS, DisableAllocationSites,
    2283             :                     DISABLE_ALLOCATION_SITES)
    2284         224 : GENERATE_ARRAY_CTOR(NoArgument, Holey, HOLEY_ELEMENTS, DisableAllocationSites,
    2285             :                     DISABLE_ALLOCATION_SITES)
    2286         224 : GENERATE_ARRAY_CTOR(NoArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS,
    2287             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2288         224 : GENERATE_ARRAY_CTOR(NoArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS,
    2289             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2290             : 
    2291             : // The ArraySingleArgumentConstructor builtin family.
    2292         224 : GENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS,
    2293             :                     DontOverride, DONT_OVERRIDE)
    2294         224 : GENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride,
    2295             :                     DONT_OVERRIDE)
    2296         224 : GENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS,
    2297             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2298         224 : GENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS,
    2299             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2300         224 : GENERATE_ARRAY_CTOR(SingleArgument, Packed, PACKED_ELEMENTS,
    2301             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2302         224 : GENERATE_ARRAY_CTOR(SingleArgument, Holey, HOLEY_ELEMENTS,
    2303             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2304         224 : GENERATE_ARRAY_CTOR(SingleArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS,
    2305             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2306         224 : GENERATE_ARRAY_CTOR(SingleArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS,
    2307             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    2308             : 
    2309             : #undef GENERATE_ARRAY_CTOR
    2310             : 
    2311         280 : TF_BUILTIN(InternalArrayNoArgumentConstructor_Packed, ArrayBuiltinsAssembler) {
    2312             :   typedef ArrayNoArgumentConstructorDescriptor Descriptor;
    2313             :   TNode<Map> array_map =
    2314          56 :       CAST(LoadObjectField(Parameter(Descriptor::kFunction),
    2315             :                            JSFunction::kPrototypeOrInitialMapOffset));
    2316             :   TNode<JSArray> array = AllocateJSArray(
    2317             :       PACKED_ELEMENTS, array_map,
    2318          56 :       IntPtrConstant(JSArray::kPreallocatedArrayElements), SmiConstant(0));
    2319          56 :   Return(array);
    2320          56 : }
    2321             : 
    2322             : }  // namespace internal
    2323       87414 : }  // namespace v8

Generated by: LCOV version 1.10