LCOV - code coverage report
Current view: top level - src/builtins - builtins-array-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1671 1705 98.0 %
Date: 2019-02-19 Functions: 399 402 99.3 %

          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             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : 
      22             : using Node = compiler::Node;
      23             : using IteratorRecord = IteratorBuiltinsFromDSLAssembler::IteratorRecord;
      24             : 
      25        3080 : ArrayBuiltinsAssembler::ArrayBuiltinsAssembler(
      26             :     compiler::CodeAssemblerState* state)
      27             :     : CodeStubAssembler(state),
      28             :       k_(this, MachineRepresentation::kTagged),
      29             :       a_(this, MachineRepresentation::kTagged),
      30        3080 :       to_(this, MachineRepresentation::kTagged, SmiConstant(0)),
      31        6160 :       fully_spec_compliant_(this, {&k_, &a_, &to_}) {}
      32             : 
      33         112 : void ArrayBuiltinsAssembler::FindResultGenerator() {
      34         112 :   a_.Bind(UndefinedConstant());
      35         112 : }
      36             : 
      37         784 : Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
      38             :   Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
      39         784 :                        this_arg(), k_value, k, o());
      40        1568 :   Label false_continue(this), return_true(this);
      41         784 :   BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
      42         784 :   BIND(&return_true);
      43         784 :   ReturnFromBuiltin(k_value);
      44         784 :   BIND(&false_continue);
      45        1568 :   return a();
      46             :   }
      47             : 
      48         112 :   void ArrayBuiltinsAssembler::FindIndexResultGenerator() {
      49         112 :     a_.Bind(SmiConstant(-1));
      50         112 :   }
      51             : 
      52         784 :   Node* ArrayBuiltinsAssembler::FindIndexProcessor(Node* k_value, Node* k) {
      53             :     Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
      54         784 :                          this_arg(), k_value, k, o());
      55        1568 :     Label false_continue(this), return_true(this);
      56         784 :     BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
      57         784 :     BIND(&return_true);
      58         784 :     ReturnFromBuiltin(k);
      59         784 :     BIND(&false_continue);
      60        1568 :     return a();
      61             :   }
      62             : 
      63          56 :   void ArrayBuiltinsAssembler::ForEachResultGenerator() {
      64          56 :     a_.Bind(UndefinedConstant());
      65          56 :   }
      66             : 
      67         616 :   Node* ArrayBuiltinsAssembler::ForEachProcessor(Node* k_value, Node* k) {
      68             :     CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(),
      69         616 :            k_value, k, o());
      70         616 :     return a();
      71             :   }
      72             : 
      73          56 :   void ArrayBuiltinsAssembler::SomeResultGenerator() {
      74          56 :     a_.Bind(FalseConstant());
      75          56 :   }
      76             : 
      77         616 :   Node* ArrayBuiltinsAssembler::SomeProcessor(Node* k_value, Node* k) {
      78             :     Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
      79         616 :                          this_arg(), k_value, k, o());
      80        1232 :     Label false_continue(this), return_true(this);
      81         616 :     BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
      82         616 :     BIND(&return_true);
      83         616 :     ReturnFromBuiltin(TrueConstant());
      84         616 :     BIND(&false_continue);
      85        1232 :     return a();
      86             :   }
      87             : 
      88          56 :   void ArrayBuiltinsAssembler::EveryResultGenerator() {
      89          56 :     a_.Bind(TrueConstant());
      90          56 :   }
      91             : 
      92         616 :   Node* ArrayBuiltinsAssembler::EveryProcessor(Node* k_value, Node* k) {
      93             :     Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
      94         616 :                          this_arg(), k_value, k, o());
      95        1232 :     Label true_continue(this), return_false(this);
      96         616 :     BranchIfToBooleanIsTrue(value, &true_continue, &return_false);
      97         616 :     BIND(&return_false);
      98         616 :     ReturnFromBuiltin(FalseConstant());
      99         616 :     BIND(&true_continue);
     100        1232 :     return a();
     101             :   }
     102             : 
     103         224 :   void ArrayBuiltinsAssembler::ReduceResultGenerator() {
     104         224 :     return a_.Bind(this_arg());
     105             :   }
     106             : 
     107        1568 :   Node* ArrayBuiltinsAssembler::ReduceProcessor(Node* k_value, Node* k) {
     108        1568 :     VARIABLE(result, MachineRepresentation::kTagged);
     109        3136 :     Label done(this, {&result}), initial(this);
     110        1568 :     GotoIf(WordEqual(a(), TheHoleConstant()), &initial);
     111             :     result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
     112        1568 :                        UndefinedConstant(), a(), k_value, k, o()));
     113        1568 :     Goto(&done);
     114             : 
     115        1568 :     BIND(&initial);
     116        1568 :     result.Bind(k_value);
     117        1568 :     Goto(&done);
     118             : 
     119        1568 :     BIND(&done);
     120        3136 :     return result.value();
     121             :   }
     122             : 
     123        1568 :   void ArrayBuiltinsAssembler::ReducePostLoopAction() {
     124        1568 :     Label ok(this);
     125        1568 :     GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok);
     126        1568 :     ThrowTypeError(context(), MessageTemplate::kReduceNoInitial);
     127        1568 :     BIND(&ok);
     128        1568 :   }
     129             : 
     130          56 :   void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() {
     131             :     // 6. Let A be ? TypedArraySpeciesCreate(O, len).
     132          56 :     TNode<JSTypedArray> original_array = CAST(o());
     133          56 :     TNode<Smi> length = CAST(len_);
     134          56 :     const char* method_name = "%TypedArray%.prototype.map";
     135             : 
     136          56 :     TypedArrayBuiltinsAssembler typedarray_asm(state());
     137             :     TNode<JSTypedArray> a = typedarray_asm.TypedArraySpeciesCreateByLength(
     138          56 :         context(), original_array, length, method_name);
     139             :     // In the Spec and our current implementation, the length check is already
     140             :     // performed in TypedArraySpeciesCreate.
     141             :     CSA_ASSERT(this, SmiLessThanOrEqual(CAST(len_), LoadJSTypedArrayLength(a)));
     142         112 :     fast_typed_array_target_ =
     143         112 :         Word32Equal(LoadInstanceType(LoadElements(original_array)),
     144         280 :                     LoadInstanceType(LoadElements(a)));
     145          56 :     a_.Bind(a);
     146          56 :   }
     147             : 
     148             :   // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map.
     149         616 :   Node* ArrayBuiltinsAssembler::TypedArrayMapProcessor(Node* k_value, Node* k) {
     150             :     // 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »).
     151             :     Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
     152         616 :                                 callbackfn(), this_arg(), k_value, k, o());
     153        1232 :     Label fast(this), slow(this), done(this), detached(this, Label::kDeferred);
     154             : 
     155             :     // 8. d. Perform ? Set(A, Pk, mapped_value, true).
     156             :     // Since we know that A is a TypedArray, this always ends up in
     157             :     // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then
     158             :     // tc39.github.io/ecma262/#sec-integerindexedelementset .
     159         616 :     Branch(fast_typed_array_target_, &fast, &slow);
     160             : 
     161         616 :     BIND(&fast);
     162             :     // #sec-integerindexedelementset
     163             :     // 5. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let
     164             :     // numValue be ? ToBigInt(v).
     165             :     // 6. Otherwise, let numValue be ? ToNumber(value).
     166             :     Node* num_value;
     167        1176 :     if (source_elements_kind_ == BIGINT64_ELEMENTS ||
     168         560 :         source_elements_kind_ == BIGUINT64_ELEMENTS) {
     169         112 :       num_value = ToBigInt(context(), mapped_value);
     170             :     } else {
     171         504 :       num_value = ToNumber_Inline(context(), mapped_value);
     172             :     }
     173             :     // The only way how this can bailout is because of a detached buffer.
     174             :     EmitElementStore(a(), k, num_value, source_elements_kind_,
     175             :                      KeyedAccessStoreMode::STANDARD_STORE, &detached,
     176         616 :                      context());
     177         616 :     Goto(&done);
     178             : 
     179         616 :     BIND(&slow);
     180         616 :     SetPropertyStrict(context(), CAST(a()), CAST(k), CAST(mapped_value));
     181         616 :     Goto(&done);
     182             : 
     183         616 :     BIND(&detached);
     184             :     // tc39.github.io/ecma262/#sec-integerindexedelementset
     185             :     // 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
     186         616 :     ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
     187             : 
     188         616 :     BIND(&done);
     189        1232 :     return a();
     190             :   }
     191             : 
     192        4032 :   void ArrayBuiltinsAssembler::NullPostLoopAction() {}
     193             : 
     194           0 :   void ArrayBuiltinsAssembler::FillFixedArrayWithSmiZero(
     195             :       TNode<FixedArray> array, TNode<Smi> smi_length) {
     196             :     CSA_ASSERT(this, Word32BinaryNot(IsFixedDoubleArray(array)));
     197             : 
     198           0 :     TNode<IntPtrT> length = SmiToIntPtr(smi_length);
     199           0 :     TNode<WordT> byte_length = TimesTaggedSize(length);
     200             :     CSA_ASSERT(this, UintPtrLessThan(length, byte_length));
     201             : 
     202             :     static const int32_t fa_base_data_offset =
     203             :         FixedArray::kHeaderSize - kHeapObjectTag;
     204             :     TNode<IntPtrT> backing_store = IntPtrAdd(
     205           0 :         BitcastTaggedToWord(array), IntPtrConstant(fa_base_data_offset));
     206             : 
     207             :     // Call out to memset to perform initialization.
     208             :     TNode<ExternalReference> memset =
     209           0 :         ExternalConstant(ExternalReference::libc_memset_function());
     210             :     STATIC_ASSERT(kSizetSize == kIntptrSize);
     211             :     CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
     212             :                    MachineType::IntPtr(), MachineType::UintPtr(), memset,
     213           0 :                    backing_store, IntPtrConstant(0), byte_length);
     214           0 :   }
     215             : 
     216        8400 :   void ArrayBuiltinsAssembler::ReturnFromBuiltin(Node* value) {
     217        8400 :     if (argc_ == nullptr) {
     218         112 :       Return(value);
     219             :     } else {
     220             :       // argc_ doesn't include the receiver, so it has to be added back in
     221             :       // manually.
     222        8288 :       PopAndReturn(IntPtrAdd(argc_, IntPtrConstant(1)), value);
     223             :     }
     224        8400 :   }
     225             : 
     226         672 :   void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinBody(
     227             :       TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
     228             :       Node* this_arg, TNode<IntPtrT> argc) {
     229         672 :     context_ = context;
     230         672 :     receiver_ = receiver;
     231         672 :     callbackfn_ = callbackfn;
     232         672 :     this_arg_ = this_arg;
     233         672 :     argc_ = argc;
     234         672 :   }
     235             : 
     236         224 :   void ArrayBuiltinsAssembler::GenerateIteratingArrayBuiltinBody(
     237             :       const char* name, const BuiltinResultGenerator& generator,
     238             :       const CallResultProcessor& processor, const PostLoopAction& action,
     239             :       const Callable& slow_case_continuation,
     240             :       MissingPropertyMode missing_property_mode, ForEachDirection direction) {
     241         448 :     Label non_array(this), array_changes(this, {&k_, &a_, &to_});
     242             : 
     243             :     // TODO(danno): Seriously? Do we really need to throw the exact error
     244             :     // message on null and undefined so that the webkit tests pass?
     245         448 :     Label throw_null_undefined_exception(this, Label::kDeferred);
     246         224 :     GotoIf(IsNullOrUndefined(receiver()), &throw_null_undefined_exception);
     247             : 
     248             :     // By the book: taken directly from the ECMAScript 2015 specification
     249             : 
     250             :     // 1. Let O be ToObject(this value).
     251             :     // 2. ReturnIfAbrupt(O)
     252         224 :     o_ = ToObject_Inline(context(), receiver());
     253             : 
     254             :     // 3. Let len be ToLength(Get(O, "length")).
     255             :     // 4. ReturnIfAbrupt(len).
     256         448 :     TVARIABLE(Number, merged_length);
     257         448 :     Label has_length(this, &merged_length), not_js_array(this);
     258         224 :     GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), &not_js_array);
     259         224 :     merged_length = LoadJSArrayLength(CAST(o()));
     260         224 :     Goto(&has_length);
     261             : 
     262         224 :     BIND(&not_js_array);
     263             :     {
     264             :       Node* len_property =
     265         448 :           GetProperty(context(), o(), isolate()->factory()->length_string());
     266         224 :       merged_length = ToLength_Inline(context(), len_property);
     267         224 :       Goto(&has_length);
     268             :     }
     269         224 :     BIND(&has_length);
     270             :     {
     271         224 :       len_ = merged_length.value();
     272             : 
     273             :       // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
     274         224 :       Label type_exception(this, Label::kDeferred);
     275         448 :       Label done(this);
     276         224 :       GotoIf(TaggedIsSmi(callbackfn()), &type_exception);
     277         224 :       Branch(IsCallableMap(LoadMap(callbackfn())), &done, &type_exception);
     278             : 
     279         224 :       BIND(&throw_null_undefined_exception);
     280             :       ThrowTypeError(context(), MessageTemplate::kCalledOnNullOrUndefined,
     281         224 :                      name);
     282             : 
     283         224 :       BIND(&type_exception);
     284             :       ThrowTypeError(context(), MessageTemplate::kCalledNonCallable,
     285         224 :                      callbackfn());
     286             : 
     287         448 :       BIND(&done);
     288             :     }
     289             : 
     290             :     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
     291             :     // [Already done by the arguments adapter]
     292             : 
     293         224 :     if (direction == ForEachDirection::kForward) {
     294             :       // 7. Let k be 0.
     295         168 :       k_.Bind(SmiConstant(0));
     296             :     } else {
     297          56 :       k_.Bind(NumberDec(len()));
     298             :     }
     299             : 
     300         224 :     generator(this);
     301             : 
     302             :     HandleFastElements(processor, action, &fully_spec_compliant_, direction,
     303         224 :                        missing_property_mode);
     304             : 
     305         224 :     BIND(&fully_spec_compliant_);
     306             : 
     307             :     Node* result =
     308             :         CallStub(slow_case_continuation, context(), receiver(), callbackfn(),
     309         224 :                  this_arg(), a_.value(), o(), k_.value(), len(), to_.value());
     310         448 :     ReturnFromBuiltin(result);
     311         224 :   }
     312             : 
     313         224 :   void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinLoopContinuation(
     314             :       TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
     315             :       Node* this_arg, Node* a, TNode<JSReceiver> o, Node* initial_k,
     316             :       TNode<Number> len, Node* to) {
     317         224 :     context_ = context;
     318         224 :     this_arg_ = this_arg;
     319         224 :     callbackfn_ = callbackfn;
     320         224 :     a_.Bind(a);
     321         224 :     k_.Bind(initial_k);
     322         224 :     o_ = o;
     323         224 :     len_ = len;
     324         224 :     to_.Bind(to);
     325         224 :   }
     326             : 
     327         448 :   void ArrayBuiltinsAssembler::GenerateIteratingTypedArrayBuiltinBody(
     328             :       const char* name, const BuiltinResultGenerator& generator,
     329             :       const CallResultProcessor& processor, const PostLoopAction& action,
     330             :       ForEachDirection direction) {
     331         448 :     name_ = name;
     332             : 
     333             :     // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray
     334             : 
     335         448 :     Label throw_not_typed_array(this, Label::kDeferred);
     336             : 
     337         448 :     GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
     338         896 :     GotoIfNot(HasInstanceType(CAST(receiver_), JS_TYPED_ARRAY_TYPE),
     339         448 :               &throw_not_typed_array);
     340             : 
     341         448 :     TNode<JSTypedArray> typed_array = CAST(receiver_);
     342         448 :     o_ = typed_array;
     343             : 
     344             :     TNode<JSArrayBuffer> array_buffer =
     345         448 :         LoadJSArrayBufferViewBuffer(typed_array);
     346         448 :     ThrowIfArrayBufferIsDetached(context_, array_buffer, name_);
     347             : 
     348         448 :     len_ = LoadJSTypedArrayLength(typed_array);
     349             : 
     350         896 :     Label throw_not_callable(this, Label::kDeferred);
     351         896 :     Label distinguish_types(this);
     352         448 :     GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable);
     353         896 :     Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types,
     354         448 :            &throw_not_callable);
     355             : 
     356         448 :     BIND(&throw_not_typed_array);
     357         448 :     ThrowTypeError(context_, MessageTemplate::kNotTypedArray);
     358             : 
     359         448 :     BIND(&throw_not_callable);
     360         448 :     ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_);
     361             : 
     362         896 :     Label unexpected_instance_type(this);
     363         448 :     BIND(&unexpected_instance_type);
     364         448 :     Unreachable();
     365             : 
     366             :     std::vector<int32_t> instance_types = {
     367             : #define INSTANCE_TYPE(Type, type, TYPE, ctype) FIXED_##TYPE##_ARRAY_TYPE,
     368             :         TYPED_ARRAYS(INSTANCE_TYPE)
     369             : #undef INSTANCE_TYPE
     370         896 :     };
     371         896 :     std::list<Label> labels;
     372        5376 :     for (size_t i = 0; i < instance_types.size(); ++i) {
     373        4928 :       labels.emplace_back(this);
     374             :     }
     375         896 :     std::vector<Label*> label_ptrs;
     376        5376 :     for (Label& label : labels) {
     377        4928 :       label_ptrs.push_back(&label);
     378             :     }
     379             : 
     380         448 :     BIND(&distinguish_types);
     381             : 
     382         448 :     generator(this);
     383             : 
     384         448 :     if (direction == ForEachDirection::kForward) {
     385         392 :       k_.Bind(SmiConstant(0));
     386             :     } else {
     387          56 :       k_.Bind(NumberDec(len()));
     388             :     }
     389             :     CSA_ASSERT(this, IsSafeInteger(k()));
     390         448 :     Node* instance_type = LoadInstanceType(LoadElements(typed_array));
     391         448 :     Switch(instance_type, &unexpected_instance_type, instance_types.data(),
     392         896 :            label_ptrs.data(), labels.size());
     393             : 
     394         448 :     size_t i = 0;
     395        5376 :     for (auto it = labels.begin(); it != labels.end(); ++i, ++it) {
     396        4928 :       BIND(&*it);
     397        4928 :       Label done(this);
     398             :       source_elements_kind_ = ElementsKindForInstanceType(
     399        4928 :           static_cast<InstanceType>(instance_types[i]));
     400             :       // TODO(tebbi): Silently cancelling the loop on buffer detachment is a
     401             :       // spec violation. Should go to &throw_detached and throw a TypeError
     402             :       // instead.
     403             :       VisitAllTypedArrayElements(array_buffer, processor, &done, direction,
     404        4928 :                                  typed_array);
     405        4928 :       Goto(&done);
     406             :       // No exception, return success
     407        4928 :       BIND(&done);
     408        4928 :       action(this);
     409        4928 :       ReturnFromBuiltin(a_.value());
     410        5376 :     }
     411         448 :   }
     412             : 
     413         224 :   void ArrayBuiltinsAssembler::GenerateIteratingArrayBuiltinLoopContinuation(
     414             :       const CallResultProcessor& processor, const PostLoopAction& action,
     415             :       MissingPropertyMode missing_property_mode, ForEachDirection direction) {
     416         224 :     Label loop(this, {&k_, &a_, &to_});
     417         448 :     Label after_loop(this);
     418         224 :     Goto(&loop);
     419         224 :     BIND(&loop);
     420             :     {
     421         224 :       if (direction == ForEachDirection::kForward) {
     422             :         // 8. Repeat, while k < len
     423         168 :         GotoIfNumberGreaterThanOrEqual(k(), len_, &after_loop);
     424             :       } else {
     425             :         // OR
     426             :         // 10. Repeat, while k >= 0
     427          56 :         GotoIfNumberGreaterThanOrEqual(SmiConstant(-1), k(), &after_loop);
     428             :       }
     429             : 
     430         224 :       Label done_element(this, &to_);
     431             :       // a. Let Pk be ToString(k).
     432             :       // k() is guaranteed to be a positive integer, hence ToString is
     433             :       // side-effect free and HasProperty/GetProperty do the conversion inline.
     434             :       CSA_ASSERT(this, IsSafeInteger(k()));
     435             : 
     436         224 :       if (missing_property_mode == MissingPropertyMode::kSkip) {
     437             :         // b. Let kPresent be HasProperty(O, Pk).
     438             :         // c. ReturnIfAbrupt(kPresent).
     439             :         TNode<Oddball> k_present =
     440         112 :             HasProperty(context(), o(), k(), kHasProperty);
     441             : 
     442             :         // d. If kPresent is true, then
     443         112 :         GotoIf(IsFalse(k_present), &done_element);
     444             :       }
     445             : 
     446             :       // i. Let kValue be Get(O, Pk).
     447             :       // ii. ReturnIfAbrupt(kValue).
     448         224 :       Node* k_value = GetProperty(context(), o(), k());
     449             : 
     450             :       // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
     451             :       // iv. ReturnIfAbrupt(funcResult).
     452         224 :       a_.Bind(processor(this, k_value, k()));
     453         224 :       Goto(&done_element);
     454             : 
     455         224 :       BIND(&done_element);
     456             : 
     457         224 :       if (direction == ForEachDirection::kForward) {
     458             :         // e. Increase k by 1.
     459         168 :         k_.Bind(NumberInc(k()));
     460             :       } else {
     461             :         // e. Decrease k by 1.
     462          56 :         k_.Bind(NumberDec(k()));
     463             :       }
     464         224 :       Goto(&loop);
     465             :     }
     466         224 :     BIND(&after_loop);
     467             : 
     468         224 :     action(this);
     469         448 :     Return(a_.value());
     470         224 :   }
     471             : 
     472        4928 :   ElementsKind ArrayBuiltinsAssembler::ElementsKindForInstanceType(
     473             :       InstanceType type) {
     474        4928 :     switch (type) {
     475             : #define INSTANCE_TYPE_TO_ELEMENTS_KIND(Type, type, TYPE, ctype) \
     476             :   case FIXED_##TYPE##_ARRAY_TYPE:                               \
     477             :     return TYPE##_ELEMENTS;
     478             : 
     479         448 :       TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND)
     480             : #undef INSTANCE_TYPE_TO_ELEMENTS_KIND
     481             : 
     482             :       default:
     483           0 :         UNREACHABLE();
     484             :     }
     485             :   }
     486             : 
     487        4928 :   void ArrayBuiltinsAssembler::VisitAllTypedArrayElements(
     488             :       Node* array_buffer, const CallResultProcessor& processor, Label* detached,
     489             :       ForEachDirection direction, TNode<JSTypedArray> typed_array) {
     490        4928 :     VariableList list({&a_, &k_, &to_}, zone());
     491             : 
     492        4928 :     FastLoopBody body = [&](Node* index) {
     493        4928 :       GotoIf(IsDetachedBuffer(array_buffer), detached);
     494        4928 :       Node* elements = LoadElements(typed_array);
     495             :       Node* base_ptr =
     496        4928 :           LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
     497             :       Node* external_ptr =
     498             :           LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
     499        4928 :                           MachineType::Pointer());
     500        4928 :       Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
     501             :       Node* value = LoadFixedTypedArrayElementAsTagged(
     502        4928 :           data_ptr, index, source_elements_kind_, SMI_PARAMETERS);
     503        4928 :       k_.Bind(index);
     504        4928 :       a_.Bind(processor(this, value, index));
     505       14784 :     };
     506        4928 :     Node* start = SmiConstant(0);
     507        4928 :     Node* end = len_;
     508        4928 :     IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost;
     509        4928 :     int incr = 1;
     510        4928 :     if (direction == ForEachDirection::kReverse) {
     511         616 :       std::swap(start, end);
     512         616 :       advance_mode = IndexAdvanceMode::kPre;
     513         616 :       incr = -1;
     514             :     }
     515             :     BuildFastLoop(list, start, end, body, incr, ParameterMode::SMI_PARAMETERS,
     516        9856 :                   advance_mode);
     517        4928 :   }
     518             : 
     519         448 :   void ArrayBuiltinsAssembler::VisitAllFastElementsOneKind(
     520             :       ElementsKind kind, const CallResultProcessor& processor,
     521             :       Label* array_changed, ParameterMode mode, ForEachDirection direction,
     522             :       MissingPropertyMode missing_property_mode, TNode<Smi> length) {
     523         448 :     Comment("begin VisitAllFastElementsOneKind");
     524             :     // We only use this kind of processing if the no-elements protector is
     525             :     // in place at the start. We'll continue checking during array iteration.
     526             :     CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid()));
     527         448 :     VARIABLE(original_map, MachineRepresentation::kTagged);
     528         448 :     original_map.Bind(LoadMap(o()));
     529         896 :     VariableList list({&original_map, &a_, &k_, &to_}, zone());
     530         448 :     Node* start = IntPtrOrSmiConstant(0, mode);
     531         448 :     Node* end = TaggedToParameter(length, mode);
     532             :     IndexAdvanceMode advance_mode = direction == ForEachDirection::kReverse
     533             :                                         ? IndexAdvanceMode::kPre
     534         448 :                                         : IndexAdvanceMode::kPost;
     535         448 :     if (direction == ForEachDirection::kReverse) std::swap(start, end);
     536             :     BuildFastLoop(
     537             :         list, start, end,
     538        1792 :         [=, &original_map](Node* index) {
     539         448 :           k_.Bind(ParameterToTagged(index, mode));
     540         896 :           Label one_element_done(this), hole_element(this),
     541         896 :               process_element(this);
     542             : 
     543             :           // Check if o's map has changed during the callback. If so, we have to
     544             :           // fall back to the slower spec implementation for the rest of the
     545             :           // iteration.
     546         448 :           Node* o_map = LoadMap(o());
     547         448 :           GotoIf(WordNotEqual(o_map, original_map.value()), array_changed);
     548             : 
     549         448 :           TNode<JSArray> o_array = CAST(o());
     550             :           // Check if o's length has changed during the callback and if the
     551             :           // index is now out of range of the new length.
     552         448 :           GotoIf(SmiGreaterThanOrEqual(CAST(k_.value()),
     553        1344 :                                        CAST(LoadJSArrayLength(o_array))),
     554         896 :                  array_changed);
     555             : 
     556             :           // Re-load the elements array. If may have been resized.
     557         448 :           Node* elements = LoadElements(o_array);
     558             : 
     559             :           // Fast case: load the element directly from the elements FixedArray
     560             :           // and call the callback if the element is not the hole.
     561             :           DCHECK(kind == PACKED_ELEMENTS || kind == PACKED_DOUBLE_ELEMENTS);
     562         448 :           int base_size = kind == PACKED_ELEMENTS
     563             :                               ? FixedArray::kHeaderSize
     564         448 :                               : (FixedArray::kHeaderSize - kHeapObjectTag);
     565         448 :           Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size);
     566         896 :           VARIABLE(value, MachineRepresentation::kTagged);
     567         448 :           if (kind == PACKED_ELEMENTS) {
     568         224 :             value.Bind(LoadObjectField(elements, offset));
     569         224 :             GotoIf(WordEqual(value.value(), TheHoleConstant()), &hole_element);
     570             :           } else {
     571             :             Node* double_value =
     572         224 :                 LoadDoubleWithHoleCheck(elements, offset, &hole_element);
     573         224 :             value.Bind(AllocateHeapNumberWithValue(double_value));
     574             :           }
     575         448 :           Goto(&process_element);
     576             : 
     577         448 :           BIND(&hole_element);
     578         448 :           if (missing_property_mode == MissingPropertyMode::kSkip) {
     579             :             // The NoElementsProtectorCell could go invalid during callbacks.
     580         224 :             Branch(IsNoElementsProtectorCellInvalid(), array_changed,
     581         448 :                    &one_element_done);
     582             :           } else {
     583         224 :             value.Bind(UndefinedConstant());
     584         224 :             Goto(&process_element);
     585             :           }
     586         448 :           BIND(&process_element);
     587             :           {
     588         448 :             a_.Bind(processor(this, value.value(), k()));
     589         448 :             Goto(&one_element_done);
     590             :           }
     591         448 :           BIND(&one_element_done);
     592         448 :         },
     593         448 :         1, mode, advance_mode);
     594         896 :     Comment("end VisitAllFastElementsOneKind");
     595         448 :   }
     596             : 
     597         224 :   void ArrayBuiltinsAssembler::HandleFastElements(
     598             :       const CallResultProcessor& processor, const PostLoopAction& action,
     599             :       Label* slow, ForEachDirection direction,
     600             :       MissingPropertyMode missing_property_mode) {
     601         448 :     Label switch_on_elements_kind(this), fast_elements(this),
     602         448 :         maybe_double_elements(this), fast_double_elements(this);
     603             : 
     604         224 :     Comment("begin HandleFastElements");
     605             :     // Non-smi lengths must use the slow path.
     606         224 :     GotoIf(TaggedIsNotSmi(len()), slow);
     607             : 
     608             :     BranchIfFastJSArray(o(), context(),
     609         224 :                         &switch_on_elements_kind, slow);
     610             : 
     611         224 :     BIND(&switch_on_elements_kind);
     612         224 :     TNode<Smi> smi_len = CAST(len());
     613             :     // Select by ElementsKind
     614         224 :     Node* kind = LoadElementsKind(o());
     615             :     Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
     616         224 :            &maybe_double_elements, &fast_elements);
     617             : 
     618         224 :     ParameterMode mode = OptimalParameterMode();
     619         224 :     BIND(&fast_elements);
     620             :     {
     621             :       VisitAllFastElementsOneKind(PACKED_ELEMENTS, processor, slow, mode,
     622         224 :                                   direction, missing_property_mode, smi_len);
     623             : 
     624         224 :       action(this);
     625             : 
     626             :       // No exception, return success
     627         224 :       ReturnFromBuiltin(a_.value());
     628             :     }
     629             : 
     630         224 :     BIND(&maybe_double_elements);
     631             :     Branch(IsElementsKindGreaterThan(kind, HOLEY_DOUBLE_ELEMENTS), slow,
     632         224 :            &fast_double_elements);
     633             : 
     634         224 :     BIND(&fast_double_elements);
     635             :     {
     636             :       VisitAllFastElementsOneKind(PACKED_DOUBLE_ELEMENTS, processor, slow, mode,
     637         224 :                                   direction, missing_property_mode, smi_len);
     638             : 
     639         224 :       action(this);
     640             : 
     641             :       // No exception, return success
     642         224 :       ReturnFromBuiltin(a_.value());
     643         224 :     }
     644         224 :   }
     645             : 
     646             :   // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
     647           0 :   void ArrayBuiltinsAssembler::GenerateArraySpeciesCreate(TNode<Number> len) {
     648           0 :     Label runtime(this, Label::kDeferred), done(this);
     649             : 
     650           0 :     Node* const original_map = LoadMap(o());
     651             :     GotoIfNot(
     652           0 :         InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
     653           0 :         &runtime);
     654             : 
     655           0 :     GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
     656           0 :               &runtime);
     657             : 
     658           0 :     Node* species_protector = ArraySpeciesProtectorConstant();
     659             :     Node* value =
     660           0 :         LoadObjectField(species_protector, PropertyCell::kValueOffset);
     661           0 :     Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
     662           0 :     GotoIf(WordEqual(value, protector_invalid), &runtime);
     663             : 
     664           0 :     GotoIfNot(TaggedIsPositiveSmi(len), &runtime);
     665             :     GotoIfNot(
     666           0 :         IsValidFastJSArrayCapacity(len, CodeStubAssembler::SMI_PARAMETERS),
     667           0 :         &runtime);
     668             : 
     669             :     // We need to be conservative and start with holey because the builtins
     670             :     // that create output arrays aren't guaranteed to be called for every
     671             :     // element in the input array (maybe the callback deletes an element).
     672             :     const ElementsKind elements_kind =
     673           0 :         GetHoleyElementsKind(GetInitialFastElementsKind());
     674           0 :     TNode<Context> native_context = LoadNativeContext(context());
     675             :     TNode<Map> array_map =
     676           0 :         LoadJSArrayElementsMap(elements_kind, native_context);
     677           0 :     a_.Bind(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, len, CAST(len),
     678             :                             nullptr, CodeStubAssembler::SMI_PARAMETERS,
     679           0 :                             kAllowLargeObjectAllocation));
     680             : 
     681           0 :     Goto(&done);
     682             : 
     683           0 :     BIND(&runtime);
     684             :     {
     685             :       // 5. Let A be ? ArraySpeciesCreate(O, len).
     686             :       TNode<JSReceiver> constructor =
     687           0 :           CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context(), o()));
     688           0 :       a_.Bind(Construct(context(), constructor, len));
     689           0 :       Goto(&fully_spec_compliant_);
     690             :     }
     691             : 
     692           0 :     BIND(&done);
     693           0 :   }
     694             : 
     695         336 : TF_BUILTIN(ArrayPrototypePop, CodeStubAssembler) {
     696             :   TNode<Int32T> argc =
     697          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
     698          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     699             :   CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
     700             : 
     701          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
     702          56 :   TNode<Object> receiver = args.GetReceiver();
     703             : 
     704          56 :   Label runtime(this, Label::kDeferred);
     705         112 :   Label fast(this);
     706             : 
     707             :   // Only pop in this stub if
     708             :   // 1) the array has fast elements
     709             :   // 2) the length is writable,
     710             :   // 3) the elements backing store isn't copy-on-write,
     711             :   // 4) we aren't supposed to shrink the backing store.
     712             : 
     713             :   // 1) Check that the array has fast elements.
     714          56 :   BranchIfFastJSArray(receiver, context, &fast, &runtime);
     715             : 
     716          56 :   BIND(&fast);
     717             :   {
     718          56 :     TNode<JSArray> array_receiver = CAST(receiver);
     719             :     CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver)));
     720             :     TNode<IntPtrT> length =
     721          56 :         LoadAndUntagObjectField(array_receiver, JSArray::kLengthOffset);
     722         112 :     Label return_undefined(this), fast_elements(this);
     723          56 :     GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
     724             : 
     725             :     // 2) Ensure that the length is writable.
     726          56 :     EnsureArrayLengthWritable(LoadMap(array_receiver), &runtime);
     727             : 
     728             :     // 3) Check that the elements backing store isn't copy-on-write.
     729          56 :     TNode<FixedArrayBase> elements = LoadElements(array_receiver);
     730         112 :     GotoIf(WordEqual(LoadMap(elements), LoadRoot(RootIndex::kFixedCOWArrayMap)),
     731          56 :            &runtime);
     732             : 
     733          56 :     TNode<IntPtrT> new_length = IntPtrSub(length, IntPtrConstant(1));
     734             : 
     735             :     // 4) Check that we're not supposed to shrink the backing store, as
     736             :     //    implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
     737          56 :     TNode<IntPtrT> capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
     738             :     GotoIf(IntPtrLessThan(
     739             :                IntPtrAdd(IntPtrAdd(new_length, new_length),
     740          56 :                          IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
     741         168 :                capacity),
     742          56 :            &runtime);
     743             : 
     744             :     StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset,
     745          56 :                                    SmiTag(new_length));
     746             : 
     747          56 :     TNode<Int32T> elements_kind = LoadElementsKind(array_receiver);
     748             :     GotoIf(Int32LessThanOrEqual(elements_kind,
     749         112 :                                 Int32Constant(TERMINAL_FAST_ELEMENTS_KIND)),
     750          56 :            &fast_elements);
     751             : 
     752          56 :     Node* value = LoadFixedDoubleArrayElement(CAST(elements), new_length,
     753          56 :                                               &return_undefined);
     754             : 
     755          56 :     StoreFixedDoubleArrayHole(CAST(elements), new_length);
     756          56 :     args.PopAndReturn(AllocateHeapNumberWithValue(value));
     757             : 
     758          56 :     BIND(&fast_elements);
     759             :     {
     760          56 :       Node* value = LoadFixedArrayElement(CAST(elements), new_length);
     761          56 :       StoreFixedArrayElement(CAST(elements), new_length, TheHoleConstant());
     762          56 :       GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
     763          56 :       args.PopAndReturn(value);
     764             :     }
     765             : 
     766          56 :     BIND(&return_undefined);
     767         112 :     { args.PopAndReturn(UndefinedConstant()); }
     768             :   }
     769             : 
     770          56 :   BIND(&runtime);
     771             :   {
     772             :     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
     773             :     // from the current frame here in order to reduce register pressure on the
     774             :     // fast path.
     775          56 :     TNode<JSFunction> target = LoadTargetFromFrame();
     776             :     TailCallBuiltin(Builtins::kArrayPop, context, target, UndefinedConstant(),
     777          56 :                     argc);
     778          56 :   }
     779          56 : }
     780             : 
     781         336 : TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
     782          56 :   TVARIABLE(IntPtrT, arg_index);
     783         112 :   Label default_label(this, &arg_index);
     784         112 :   Label smi_transition(this);
     785         112 :   Label object_push_pre(this);
     786         112 :   Label object_push(this, &arg_index);
     787         112 :   Label double_push(this, &arg_index);
     788         112 :   Label double_transition(this);
     789         112 :   Label runtime(this, Label::kDeferred);
     790             : 
     791             :   // TODO(ishell): use constants from Descriptor once the JSFunction linkage
     792             :   // arguments are reordered.
     793             :   TNode<Int32T> argc =
     794          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
     795          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     796             :   CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
     797             : 
     798          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
     799          56 :   TNode<Object> receiver = args.GetReceiver();
     800          56 :   TNode<JSArray> array_receiver;
     801          56 :   Node* kind = nullptr;
     802             : 
     803         112 :   Label fast(this);
     804          56 :   BranchIfFastJSArray(receiver, context, &fast, &runtime);
     805             : 
     806          56 :   BIND(&fast);
     807             :   {
     808          56 :     array_receiver = CAST(receiver);
     809          56 :     arg_index = IntPtrConstant(0);
     810          56 :     kind = EnsureArrayPushable(LoadMap(array_receiver), &runtime);
     811             :     GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
     812          56 :            &object_push_pre);
     813             : 
     814             :     Node* new_length = BuildAppendJSArray(PACKED_SMI_ELEMENTS, array_receiver,
     815          56 :                                           &args, &arg_index, &smi_transition);
     816          56 :     args.PopAndReturn(new_length);
     817             :   }
     818             : 
     819             :   // If the argument is not a smi, then use a heavyweight SetProperty to
     820             :   // transition the array for only the single next element. If the argument is
     821             :   // a smi, the failure is due to some other reason and we should fall back on
     822             :   // the most generic implementation for the rest of the array.
     823          56 :   BIND(&smi_transition);
     824             :   {
     825          56 :     Node* arg = args.AtIndex(arg_index.value());
     826          56 :     GotoIf(TaggedIsSmi(arg), &default_label);
     827          56 :     Node* length = LoadJSArrayLength(array_receiver);
     828             :     // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
     829             :     // calling into the runtime to do the elements transition is overkill.
     830          56 :     SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
     831          56 :     Increment(&arg_index);
     832             :     // The runtime SetProperty call could have converted the array to dictionary
     833             :     // mode, which must be detected to abort the fast-path.
     834          56 :     Node* kind = LoadElementsKind(array_receiver);
     835         112 :     GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
     836          56 :            &default_label);
     837             : 
     838          56 :     GotoIfNotNumber(arg, &object_push);
     839          56 :     Goto(&double_push);
     840             :   }
     841             : 
     842          56 :   BIND(&object_push_pre);
     843             :   {
     844             :     Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push,
     845          56 :            &object_push);
     846             :   }
     847             : 
     848          56 :   BIND(&object_push);
     849             :   {
     850             :     Node* new_length = BuildAppendJSArray(PACKED_ELEMENTS, array_receiver,
     851          56 :                                           &args, &arg_index, &default_label);
     852          56 :     args.PopAndReturn(new_length);
     853             :   }
     854             : 
     855          56 :   BIND(&double_push);
     856             :   {
     857             :     Node* new_length =
     858             :         BuildAppendJSArray(PACKED_DOUBLE_ELEMENTS, array_receiver, &args,
     859          56 :                            &arg_index, &double_transition);
     860          56 :     args.PopAndReturn(new_length);
     861             :   }
     862             : 
     863             :   // If the argument is not a double, then use a heavyweight SetProperty to
     864             :   // transition the array for only the single next element. If the argument is
     865             :   // a double, the failure is due to some other reason and we should fall back
     866             :   // on the most generic implementation for the rest of the array.
     867          56 :   BIND(&double_transition);
     868             :   {
     869          56 :     Node* arg = args.AtIndex(arg_index.value());
     870          56 :     GotoIfNumber(arg, &default_label);
     871          56 :     Node* length = LoadJSArrayLength(array_receiver);
     872             :     // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
     873             :     // calling into the runtime to do the elements transition is overkill.
     874          56 :     SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
     875          56 :     Increment(&arg_index);
     876             :     // The runtime SetProperty call could have converted the array to dictionary
     877             :     // mode, which must be detected to abort the fast-path.
     878          56 :     Node* kind = LoadElementsKind(array_receiver);
     879         112 :     GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
     880          56 :            &default_label);
     881          56 :     Goto(&object_push);
     882             :   }
     883             : 
     884             :   // Fallback that stores un-processed arguments using the full, heavyweight
     885             :   // SetProperty machinery.
     886          56 :   BIND(&default_label);
     887             :   {
     888             :     args.ForEach(
     889          56 :         [this, array_receiver, context](Node* arg) {
     890          56 :           Node* length = LoadJSArrayLength(array_receiver);
     891          56 :           SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
     892          56 :         },
     893          56 :         arg_index.value());
     894          56 :     args.PopAndReturn(LoadJSArrayLength(array_receiver));
     895             :   }
     896             : 
     897          56 :   BIND(&runtime);
     898             :   {
     899             :     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
     900             :     // from the current frame here in order to reduce register pressure on the
     901             :     // fast path.
     902          56 :     TNode<JSFunction> target = LoadTargetFromFrame();
     903             :     TailCallBuiltin(Builtins::kArrayPush, context, target, UndefinedConstant(),
     904          56 :                     argc);
     905          56 :   }
     906          56 : }
     907             : 
     908         336 : TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
     909             :   TNode<Int32T> argc =
     910          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
     911          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
     912             :   CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
     913             : 
     914          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
     915          56 :   TNode<Object> receiver = args.GetReceiver();
     916             : 
     917          56 :   Label runtime(this, Label::kDeferred);
     918         112 :   Label fast(this);
     919             : 
     920             :   // Only shift in this stub if
     921             :   // 1) the array has fast elements
     922             :   // 2) the length is writable,
     923             :   // 3) the elements backing store isn't copy-on-write,
     924             :   // 4) we aren't supposed to shrink the backing store,
     925             :   // 5) we aren't supposed to left-trim the backing store.
     926             : 
     927             :   // 1) Check that the array has fast elements.
     928          56 :   BranchIfFastJSArray(receiver, context, &fast, &runtime);
     929             : 
     930          56 :   BIND(&fast);
     931             :   {
     932          56 :     TNode<JSArray> array_receiver = CAST(receiver);
     933             :     CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver)));
     934             : 
     935             :     // 2) Ensure that the length is writable.
     936             :     //    This check needs to happen before the check for length zero.
     937             :     //    The spec requires a "SetProperty(array, 'length', 0)" call when
     938             :     //    the length is zero. This must throw an exception in the case of a
     939             :     //    read-only length.
     940          56 :     EnsureArrayLengthWritable(LoadMap(array_receiver), &runtime);
     941             : 
     942             :     TNode<IntPtrT> length =
     943          56 :         LoadAndUntagObjectField(array_receiver, JSArray::kLengthOffset);
     944         112 :     Label return_undefined(this), fast_elements_tagged(this),
     945         112 :         fast_elements_smi(this);
     946          56 :     GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
     947             : 
     948             :     // 3) Check that the elements backing store isn't copy-on-write.
     949          56 :     TNode<FixedArrayBase> elements = LoadElements(array_receiver);
     950         112 :     GotoIf(WordEqual(LoadMap(elements), LoadRoot(RootIndex::kFixedCOWArrayMap)),
     951          56 :            &runtime);
     952             : 
     953          56 :     TNode<IntPtrT> new_length = IntPtrSub(length, IntPtrConstant(1));
     954             : 
     955             :     // 4) Check that we're not supposed to right-trim the backing store, as
     956             :     //    implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
     957          56 :     Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
     958             :     GotoIf(IntPtrLessThan(
     959             :                IntPtrAdd(IntPtrAdd(new_length, new_length),
     960          56 :                          IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
     961         168 :                capacity),
     962          56 :            &runtime);
     963             : 
     964             :     // 5) Check that we're not supposed to left-trim the backing store, as
     965             :     //    implemented in elements.cc:FastElementsAccessor::MoveElements.
     966             :     GotoIf(IntPtrGreaterThan(new_length,
     967         112 :                              IntPtrConstant(JSArray::kMaxCopyElements)),
     968          56 :            &runtime);
     969             : 
     970             :     StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset,
     971          56 :                                    SmiTag(new_length));
     972             : 
     973          56 :     TNode<IntPtrT> element_zero = IntPtrConstant(0);
     974          56 :     TNode<IntPtrT> element_one = IntPtrConstant(1);
     975          56 :     TNode<Int32T> elements_kind = LoadElementsKind(array_receiver);
     976             :     GotoIf(
     977         112 :         Int32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_SMI_ELEMENTS)),
     978          56 :         &fast_elements_smi);
     979         112 :     GotoIf(Int32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
     980          56 :            &fast_elements_tagged);
     981             : 
     982             :     // Fast double elements kind:
     983             :     {
     984             :       CSA_ASSERT(this,
     985             :                  Int32LessThanOrEqual(elements_kind,
     986             :                                       Int32Constant(HOLEY_DOUBLE_ELEMENTS)));
     987             : 
     988          56 :       VARIABLE(result, MachineRepresentation::kTagged, UndefinedConstant());
     989             : 
     990         112 :       Label move_elements(this);
     991             :       result.Bind(AllocateHeapNumberWithValue(LoadFixedDoubleArrayElement(
     992          56 :           CAST(elements), element_zero, &move_elements)));
     993          56 :       Goto(&move_elements);
     994          56 :       BIND(&move_elements);
     995             : 
     996             :       MoveElements(HOLEY_DOUBLE_ELEMENTS, elements, element_zero, element_one,
     997          56 :                    new_length);
     998          56 :       StoreFixedDoubleArrayHole(CAST(elements), new_length);
     999         112 :       args.PopAndReturn(result.value());
    1000             :     }
    1001             : 
    1002          56 :     BIND(&fast_elements_tagged);
    1003             :     {
    1004          56 :       TNode<FixedArray> elements_fixed_array = CAST(elements);
    1005          56 :       Node* value = LoadFixedArrayElement(elements_fixed_array, 0);
    1006             :       MoveElements(HOLEY_ELEMENTS, elements, element_zero, element_one,
    1007          56 :                    new_length);
    1008             :       StoreFixedArrayElement(elements_fixed_array, new_length,
    1009          56 :                              TheHoleConstant());
    1010          56 :       GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
    1011          56 :       args.PopAndReturn(value);
    1012             :     }
    1013             : 
    1014          56 :     BIND(&fast_elements_smi);
    1015             :     {
    1016          56 :       TNode<FixedArray> elements_fixed_array = CAST(elements);
    1017          56 :       Node* value = LoadFixedArrayElement(elements_fixed_array, 0);
    1018             :       MoveElements(HOLEY_SMI_ELEMENTS, elements, element_zero, element_one,
    1019          56 :                    new_length);
    1020             :       StoreFixedArrayElement(elements_fixed_array, new_length,
    1021          56 :                              TheHoleConstant());
    1022          56 :       GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
    1023          56 :       args.PopAndReturn(value);
    1024             :     }
    1025             : 
    1026          56 :     BIND(&return_undefined);
    1027         112 :     { args.PopAndReturn(UndefinedConstant()); }
    1028             :   }
    1029             : 
    1030          56 :   BIND(&runtime);
    1031             :   {
    1032             :     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
    1033             :     // from the current frame here in order to reduce register pressure on the
    1034             :     // fast path.
    1035          56 :     TNode<JSFunction> target = LoadTargetFromFrame();
    1036             :     TailCallBuiltin(Builtins::kArrayShift, context, target, UndefinedConstant(),
    1037          56 :                     argc);
    1038          56 :   }
    1039          56 : }
    1040             : 
    1041         448 : TF_BUILTIN(ExtractFastJSArray, ArrayBuiltinsAssembler) {
    1042          56 :   ParameterMode mode = OptimalParameterMode();
    1043          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1044          56 :   Node* array = Parameter(Descriptor::kSource);
    1045          56 :   Node* begin = TaggedToParameter(Parameter(Descriptor::kBegin), mode);
    1046          56 :   Node* count = TaggedToParameter(Parameter(Descriptor::kCount), mode);
    1047             : 
    1048             :   CSA_ASSERT(this, IsJSArray(array));
    1049             :   CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid()));
    1050             : 
    1051          56 :   Return(ExtractFastJSArray(context, array, begin, count, mode));
    1052          56 : }
    1053             : 
    1054         336 : TF_BUILTIN(CloneFastJSArray, ArrayBuiltinsAssembler) {
    1055          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1056          56 :   TNode<JSArray> array = CAST(Parameter(Descriptor::kSource));
    1057             : 
    1058             :   CSA_ASSERT(this,
    1059             :              Word32Or(Word32BinaryNot(
    1060             :                           IsHoleyFastElementsKind(LoadElementsKind(array))),
    1061             :                       Word32BinaryNot(IsNoElementsProtectorCellInvalid())));
    1062             : 
    1063          56 :   ParameterMode mode = OptimalParameterMode();
    1064          56 :   Return(CloneFastJSArray(context, array, mode));
    1065          56 : }
    1066             : 
    1067             : // This builtin copies the backing store of fast arrays, while converting any
    1068             : // holes to undefined.
    1069             : // - If there are no holes in the source, its ElementsKind will be preserved. In
    1070             : // that case, this builtin should perform as fast as CloneFastJSArray. (In fact,
    1071             : // for fast packed arrays, the behavior is equivalent to CloneFastJSArray.)
    1072             : // - If there are holes in the source, the ElementsKind of the "copy" will be
    1073             : // PACKED_ELEMENTS (such that undefined can be stored).
    1074         336 : TF_BUILTIN(CloneFastJSArrayFillingHoles, ArrayBuiltinsAssembler) {
    1075          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1076          56 :   TNode<JSArray> array = CAST(Parameter(Descriptor::kSource));
    1077             : 
    1078             :   CSA_ASSERT(this,
    1079             :              Word32Or(Word32BinaryNot(
    1080             :                           IsHoleyFastElementsKind(LoadElementsKind(array))),
    1081             :                       Word32BinaryNot(IsNoElementsProtectorCellInvalid())));
    1082             : 
    1083          56 :   ParameterMode mode = OptimalParameterMode();
    1084             :   Return(CloneFastJSArray(context, array, mode, nullptr,
    1085          56 :                           HoleConversionMode::kConvertToUndefined));
    1086          56 : }
    1087             : 
    1088         728 : TF_BUILTIN(ArrayFindLoopContinuation, ArrayBuiltinsAssembler) {
    1089          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1090          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1091          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1092          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1093          56 :   Node* array = Parameter(Descriptor::kArray);
    1094          56 :   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
    1095          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1096          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1097          56 :   Node* to = Parameter(Descriptor::kTo);
    1098             : 
    1099             :   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
    1100             :                                             this_arg, array, object, initial_k,
    1101          56 :                                             len, to);
    1102             : 
    1103             :   GenerateIteratingArrayBuiltinLoopContinuation(
    1104             :       &ArrayBuiltinsAssembler::FindProcessor,
    1105             :       &ArrayBuiltinsAssembler::NullPostLoopAction,
    1106          56 :       MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
    1107          56 : }
    1108             : 
    1109             : // Continuation that is called after an eager deoptimization from TF (ex. the
    1110             : // array changes during iteration).
    1111         560 : TF_BUILTIN(ArrayFindLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
    1112          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1113          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1114          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1115          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1116          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1117          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1118             : 
    1119             :   Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
    1120             :                      callbackfn, this_arg, UndefinedConstant(), receiver,
    1121          56 :                      initial_k, len, UndefinedConstant()));
    1122          56 : }
    1123             : 
    1124             : // Continuation that is called after a lazy deoptimization from TF (ex. the
    1125             : // callback function is no longer callable).
    1126         560 : TF_BUILTIN(ArrayFindLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
    1127          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1128          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1129          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1130          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1131          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1132          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1133             : 
    1134             :   Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
    1135             :                      callbackfn, this_arg, UndefinedConstant(), receiver,
    1136          56 :                      initial_k, len, UndefinedConstant()));
    1137          56 : }
    1138             : 
    1139             : // Continuation that is called after a lazy deoptimization from TF that happens
    1140             : // right after the callback and it's returned value must be handled before
    1141             : // iteration continues.
    1142         672 : TF_BUILTIN(ArrayFindLoopAfterCallbackLazyDeoptContinuation,
    1143             :            ArrayBuiltinsAssembler) {
    1144          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1145          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1146          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1147          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1148          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1149          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1150          56 :   Node* found_value = Parameter(Descriptor::kFoundValue);
    1151          56 :   Node* is_found = Parameter(Descriptor::kIsFound);
    1152             : 
    1153             :   // This custom lazy deopt point is right after the callback. find() needs
    1154             :   // to pick up at the next step, which is returning the element if the callback
    1155             :   // value is truthy.  Otherwise, continue the search by calling the
    1156             :   // continuation.
    1157         112 :   Label if_true(this), if_false(this);
    1158          56 :   BranchIfToBooleanIsTrue(is_found, &if_true, &if_false);
    1159          56 :   BIND(&if_true);
    1160          56 :   Return(found_value);
    1161          56 :   BIND(&if_false);
    1162             :   Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
    1163             :                      callbackfn, this_arg, UndefinedConstant(), receiver,
    1164         112 :                      initial_k, len, UndefinedConstant()));
    1165          56 : }
    1166             : 
    1167             : // ES #sec-get-%typedarray%.prototype.find
    1168         336 : TF_BUILTIN(ArrayPrototypeFind, ArrayBuiltinsAssembler) {
    1169             :   TNode<IntPtrT> argc =
    1170          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1171          56 :   CodeStubArguments args(this, argc);
    1172          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1173          56 :   TNode<Object> receiver = args.GetReceiver();
    1174          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1175          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
    1176             : 
    1177          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
    1178             : 
    1179             :   GenerateIteratingArrayBuiltinBody(
    1180             :       "Array.prototype.find", &ArrayBuiltinsAssembler::FindResultGenerator,
    1181             :       &ArrayBuiltinsAssembler::FindProcessor,
    1182             :       &ArrayBuiltinsAssembler::NullPostLoopAction,
    1183             :       Builtins::CallableFor(isolate(), Builtins::kArrayFindLoopContinuation),
    1184          56 :       MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
    1185          56 : }
    1186             : 
    1187         728 : TF_BUILTIN(ArrayFindIndexLoopContinuation, ArrayBuiltinsAssembler) {
    1188          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1189          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1190          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1191          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1192          56 :   Node* array = Parameter(Descriptor::kArray);
    1193          56 :   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
    1194          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1195          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1196          56 :   Node* to = Parameter(Descriptor::kTo);
    1197             : 
    1198             :   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
    1199             :                                             this_arg, array, object, initial_k,
    1200          56 :                                             len, to);
    1201             : 
    1202             :   GenerateIteratingArrayBuiltinLoopContinuation(
    1203             :       &ArrayBuiltinsAssembler::FindIndexProcessor,
    1204             :       &ArrayBuiltinsAssembler::NullPostLoopAction,
    1205          56 :       MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
    1206          56 : }
    1207             : 
    1208         560 : TF_BUILTIN(ArrayFindIndexLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
    1209          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1210          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1211          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1212          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1213          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1214          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1215             : 
    1216             :   Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
    1217             :                      receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
    1218          56 :                      initial_k, len, UndefinedConstant()));
    1219          56 : }
    1220             : 
    1221         560 : TF_BUILTIN(ArrayFindIndexLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
    1222          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1223          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1224          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1225          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1226          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1227          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1228             : 
    1229             :   Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
    1230             :                      receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
    1231          56 :                      initial_k, len, UndefinedConstant()));
    1232          56 : }
    1233             : 
    1234         672 : TF_BUILTIN(ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation,
    1235             :            ArrayBuiltinsAssembler) {
    1236          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1237          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1238          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1239          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1240          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1241          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1242          56 :   Node* found_value = Parameter(Descriptor::kFoundValue);
    1243          56 :   Node* is_found = Parameter(Descriptor::kIsFound);
    1244             : 
    1245             :   // This custom lazy deopt point is right after the callback. find() needs
    1246             :   // to pick up at the next step, which is returning the element if the callback
    1247             :   // value is truthy.  Otherwise, continue the search by calling the
    1248             :   // continuation.
    1249         112 :   Label if_true(this), if_false(this);
    1250          56 :   BranchIfToBooleanIsTrue(is_found, &if_true, &if_false);
    1251          56 :   BIND(&if_true);
    1252          56 :   Return(found_value);
    1253          56 :   BIND(&if_false);
    1254             :   Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
    1255             :                      receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
    1256         112 :                      initial_k, len, UndefinedConstant()));
    1257          56 : }
    1258             : 
    1259             : // ES #sec-get-%typedarray%.prototype.findIndex
    1260         336 : TF_BUILTIN(ArrayPrototypeFindIndex, ArrayBuiltinsAssembler) {
    1261             :   TNode<IntPtrT> argc =
    1262          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1263          56 :   CodeStubArguments args(this, argc);
    1264          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1265          56 :   TNode<Object> receiver = args.GetReceiver();
    1266          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1267          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
    1268             : 
    1269          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
    1270             : 
    1271             :   GenerateIteratingArrayBuiltinBody(
    1272             :       "Array.prototype.findIndex",
    1273             :       &ArrayBuiltinsAssembler::FindIndexResultGenerator,
    1274             :       &ArrayBuiltinsAssembler::FindIndexProcessor,
    1275             :       &ArrayBuiltinsAssembler::NullPostLoopAction,
    1276             :       Builtins::CallableFor(isolate(),
    1277             :                             Builtins::kArrayFindIndexLoopContinuation),
    1278          56 :       MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
    1279          56 : }
    1280             : 
    1281          56 : class ArrayPopulatorAssembler : public CodeStubAssembler {
    1282             :  public:
    1283          56 :   explicit ArrayPopulatorAssembler(compiler::CodeAssemblerState* state)
    1284          56 :       : CodeStubAssembler(state) {}
    1285             : 
    1286          56 :   TNode<Object> ConstructArrayLike(TNode<Context> context,
    1287             :                                    TNode<Object> receiver) {
    1288          56 :     TVARIABLE(Object, array);
    1289         112 :     Label is_constructor(this), is_not_constructor(this), done(this);
    1290          56 :     GotoIf(TaggedIsSmi(receiver), &is_not_constructor);
    1291          56 :     Branch(IsConstructor(CAST(receiver)), &is_constructor, &is_not_constructor);
    1292             : 
    1293          56 :     BIND(&is_constructor);
    1294             :     {
    1295          56 :       array = Construct(context, CAST(receiver));
    1296          56 :       Goto(&done);
    1297             :     }
    1298             : 
    1299          56 :     BIND(&is_not_constructor);
    1300             :     {
    1301          56 :       Label allocate_js_array(this);
    1302             : 
    1303          56 :       TNode<Map> array_map = CAST(LoadContextElement(
    1304             :           context, Context::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX));
    1305             : 
    1306         168 :       array = AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, SmiConstant(0),
    1307             :                               SmiConstant(0), nullptr,
    1308         224 :                               ParameterMode::SMI_PARAMETERS);
    1309          56 :       Goto(&done);
    1310             :     }
    1311             : 
    1312          56 :     BIND(&done);
    1313         112 :     return array.value();
    1314             :   }
    1315             : 
    1316          56 :   TNode<Object> ConstructArrayLike(TNode<Context> context,
    1317             :                                    TNode<Object> receiver,
    1318             :                                    TNode<Number> length) {
    1319          56 :     TVARIABLE(Object, array);
    1320         112 :     Label is_constructor(this), is_not_constructor(this), done(this);
    1321             :     CSA_ASSERT(this, IsNumberNormalized(length));
    1322          56 :     GotoIf(TaggedIsSmi(receiver), &is_not_constructor);
    1323          56 :     Branch(IsConstructor(CAST(receiver)), &is_constructor, &is_not_constructor);
    1324             : 
    1325          56 :     BIND(&is_constructor);
    1326             :     {
    1327          56 :       array = Construct(context, CAST(receiver), length);
    1328          56 :       Goto(&done);
    1329             :     }
    1330             : 
    1331          56 :     BIND(&is_not_constructor);
    1332             :     {
    1333          56 :       array = ArrayCreate(context, length);
    1334          56 :       Goto(&done);
    1335             :     }
    1336             : 
    1337          56 :     BIND(&done);
    1338         112 :     return array.value();
    1339             :   }
    1340             : };
    1341             : 
    1342             : // ES #sec-array.from
    1343         336 : TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
    1344          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1345             :   TNode<Int32T> argc =
    1346          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
    1347             : 
    1348          56 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
    1349          56 :   TNode<Object> items = args.GetOptionalArgumentValue(0);
    1350          56 :   TNode<Object> receiver = args.GetReceiver();
    1351             : 
    1352         112 :   Label fast_iterate(this), normal_iterate(this);
    1353             : 
    1354             :   // Use fast path if:
    1355             :   // * |items| is the only argument, and
    1356             :   // * the receiver is the Array function.
    1357          56 :   GotoIfNot(Word32Equal(argc, Int32Constant(1)), &normal_iterate);
    1358             :   TNode<Object> array_function = LoadContextElement(
    1359          56 :       LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
    1360          56 :   Branch(WordEqual(array_function, receiver), &fast_iterate, &normal_iterate);
    1361             : 
    1362          56 :   BIND(&fast_iterate);
    1363             :   {
    1364          56 :     IteratorBuiltinsAssembler iterator_assembler(state());
    1365         112 :     TVARIABLE(Object, var_fast_result);
    1366             :     iterator_assembler.FastIterableToList(context, items, &var_fast_result,
    1367          56 :                                           &normal_iterate);
    1368         112 :     args.PopAndReturn(var_fast_result.value());
    1369             :   }
    1370             : 
    1371          56 :   BIND(&normal_iterate);
    1372          56 :   TNode<Object> map_function = args.GetOptionalArgumentValue(1);
    1373             : 
    1374             :   // If map_function is not undefined, then ensure it's callable else throw.
    1375             :   {
    1376         112 :     Label no_error(this), error(this);
    1377          56 :     GotoIf(IsUndefined(map_function), &no_error);
    1378          56 :     GotoIf(TaggedIsSmi(map_function), &error);
    1379          56 :     Branch(IsCallable(CAST(map_function)), &no_error, &error);
    1380             : 
    1381          56 :     BIND(&error);
    1382          56 :     ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_function);
    1383             : 
    1384         112 :     BIND(&no_error);
    1385             :   }
    1386             : 
    1387         112 :   Label iterable(this), not_iterable(this), finished(this), if_exception(this);
    1388             : 
    1389          56 :   TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
    1390             :   // The spec doesn't require ToObject to be called directly on the iterable
    1391             :   // branch, but it's part of GetMethod that is in the spec.
    1392          56 :   TNode<JSReceiver> array_like = ToObject_Inline(context, items);
    1393             : 
    1394         112 :   TVARIABLE(Object, array);
    1395         112 :   TVARIABLE(Number, length);
    1396             : 
    1397             :   // Determine whether items[Symbol.iterator] is defined:
    1398         112 :   IteratorBuiltinsAssembler iterator_assembler(state());
    1399             :   Node* iterator_method =
    1400          56 :       iterator_assembler.GetIteratorMethod(context, array_like);
    1401          56 :   Branch(IsNullOrUndefined(iterator_method), &not_iterable, &iterable);
    1402             : 
    1403          56 :   BIND(&iterable);
    1404             :   {
    1405          56 :     TVARIABLE(Number, index, SmiConstant(0));
    1406         112 :     TVARIABLE(Object, var_exception);
    1407         112 :     Label loop(this, &index), loop_done(this),
    1408         112 :         on_exception(this, Label::kDeferred),
    1409         112 :         index_overflow(this, Label::kDeferred);
    1410             : 
    1411             :     // Check that the method is callable.
    1412             :     {
    1413         112 :       Label get_method_not_callable(this, Label::kDeferred), next(this);
    1414          56 :       GotoIf(TaggedIsSmi(iterator_method), &get_method_not_callable);
    1415          56 :       GotoIfNot(IsCallable(CAST(iterator_method)), &get_method_not_callable);
    1416          56 :       Goto(&next);
    1417             : 
    1418          56 :       BIND(&get_method_not_callable);
    1419             :       ThrowTypeError(context, MessageTemplate::kCalledNonCallable,
    1420          56 :                      iterator_method);
    1421             : 
    1422         112 :       BIND(&next);
    1423             :     }
    1424             : 
    1425             :     // Construct the output array with empty length.
    1426          56 :     array = ConstructArrayLike(context, receiver);
    1427             : 
    1428             :     // Actually get the iterator and throw if the iterator method does not yield
    1429             :     // one.
    1430             :     IteratorRecord iterator_record =
    1431          56 :         iterator_assembler.GetIterator(context, items, iterator_method);
    1432             : 
    1433          56 :     TNode<Context> native_context = LoadNativeContext(context);
    1434             :     TNode<Object> fast_iterator_result_map =
    1435          56 :         LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
    1436             : 
    1437          56 :     Goto(&loop);
    1438             : 
    1439          56 :     BIND(&loop);
    1440             :     {
    1441             :       // Loop while iterator is not done.
    1442             :       TNode<Object> next = iterator_assembler.IteratorStep(
    1443          56 :           context, iterator_record, &loop_done, fast_iterator_result_map);
    1444          56 :       TVARIABLE(Object, value,
    1445             :                 CAST(iterator_assembler.IteratorValue(
    1446             :                     context, next, fast_iterator_result_map)));
    1447             : 
    1448             :       // If a map_function is supplied then call it (using this_arg as
    1449             :       // receiver), on the value returned from the iterator. Exceptions are
    1450             :       // caught so the iterator can be closed.
    1451             :       {
    1452          56 :         Label next(this);
    1453          56 :         GotoIf(IsUndefined(map_function), &next);
    1454             : 
    1455             :         CSA_ASSERT(this, IsCallable(CAST(map_function)));
    1456             :         Node* v = CallJS(CodeFactory::Call(isolate()), context, map_function,
    1457          56 :                          this_arg, value.value(), index.value());
    1458          56 :         GotoIfException(v, &on_exception, &var_exception);
    1459          56 :         value = CAST(v);
    1460          56 :         Goto(&next);
    1461          56 :         BIND(&next);
    1462             :       }
    1463             : 
    1464             :       // Store the result in the output object (catching any exceptions so the
    1465             :       // iterator can be closed).
    1466             :       Node* define_status =
    1467             :           CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
    1468          56 :                       index.value(), value.value());
    1469          56 :       GotoIfException(define_status, &on_exception, &var_exception);
    1470             : 
    1471          56 :       index = NumberInc(index.value());
    1472             : 
    1473             :       // The spec requires that we throw an exception if index reaches 2^53-1,
    1474             :       // but an empty loop would take >100 days to do this many iterations. To
    1475             :       // actually run for that long would require an iterator that never set
    1476             :       // done to true and a target array which somehow never ran out of memory,
    1477             :       // e.g. a proxy that discarded the values. Ignoring this case just means
    1478             :       // we would repeatedly call CreateDataProperty with index = 2^53.
    1479             :       CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
    1480             :         BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
    1481             :                                            NumberConstant(kMaxSafeInteger), ok,
    1482             :                                            not_ok);
    1483             :       });
    1484          56 :       Goto(&loop);
    1485             :     }
    1486             : 
    1487          56 :     BIND(&loop_done);
    1488             :     {
    1489          56 :       length = index;
    1490          56 :       Goto(&finished);
    1491             :     }
    1492             : 
    1493          56 :     BIND(&on_exception);
    1494             :     {
    1495             :       // Close the iterator, rethrowing either the passed exception or
    1496             :       // exceptions thrown during the close.
    1497             :       iterator_assembler.IteratorCloseOnException(context, iterator_record,
    1498          56 :                                                   var_exception.value());
    1499          56 :     }
    1500             :   }
    1501             : 
    1502          56 :   BIND(&not_iterable);
    1503             :   {
    1504             :     // Treat array_like as an array and try to get its length.
    1505         112 :     length = ToLength_Inline(
    1506         224 :         context, GetProperty(context, array_like, factory()->length_string()));
    1507             : 
    1508             :     // Construct an array using the receiver as constructor with the same length
    1509             :     // as the input array.
    1510          56 :     array = ConstructArrayLike(context, receiver, length.value());
    1511             : 
    1512          56 :     TVARIABLE(Number, index, SmiConstant(0));
    1513             : 
    1514             :     // TODO(ishell): remove <Object, Object>
    1515         112 :     GotoIf(WordEqual<Object, Object>(length.value(), SmiConstant(0)),
    1516          56 :            &finished);
    1517             : 
    1518             :     // Loop from 0 to length-1.
    1519             :     {
    1520          56 :       Label loop(this, &index);
    1521          56 :       Goto(&loop);
    1522          56 :       BIND(&loop);
    1523         112 :       TVARIABLE(Object, value);
    1524             : 
    1525          56 :       value = GetProperty(context, array_like, index.value());
    1526             : 
    1527             :       // If a map_function is supplied then call it (using this_arg as
    1528             :       // receiver), on the value retrieved from the array.
    1529             :       {
    1530          56 :         Label next(this);
    1531          56 :         GotoIf(IsUndefined(map_function), &next);
    1532             : 
    1533             :         CSA_ASSERT(this, IsCallable(CAST(map_function)));
    1534         112 :         value = CAST(CallJS(CodeFactory::Call(isolate()), context, map_function,
    1535          56 :                             this_arg, value.value(), index.value()));
    1536          56 :         Goto(&next);
    1537          56 :         BIND(&next);
    1538             :       }
    1539             : 
    1540             :       // Store the result in the output object.
    1541             :       CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
    1542          56 :                   index.value(), value.value());
    1543          56 :       index = NumberInc(index.value());
    1544             :       BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
    1545         112 :                                          length.value(), &loop, &finished);
    1546          56 :     }
    1547             :   }
    1548             : 
    1549          56 :   BIND(&finished);
    1550             : 
    1551             :   // Finally set the length on the output and return it.
    1552          56 :   SetPropertyLength(context, array.value(), length.value());
    1553         112 :   args.PopAndReturn(array.value());
    1554          56 : }
    1555             : 
    1556             : // ES #sec-get-%typedarray%.prototype.find
    1557         336 : TF_BUILTIN(TypedArrayPrototypeFind, ArrayBuiltinsAssembler) {
    1558             :   TNode<IntPtrT> argc =
    1559          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1560          56 :   CodeStubArguments args(this, argc);
    1561          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1562          56 :   TNode<Object> receiver = args.GetReceiver();
    1563          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1564          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
    1565             : 
    1566          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
    1567             : 
    1568             :   GenerateIteratingTypedArrayBuiltinBody(
    1569             :       "%TypedArray%.prototype.find",
    1570             :       &ArrayBuiltinsAssembler::FindResultGenerator,
    1571             :       &ArrayBuiltinsAssembler::FindProcessor,
    1572          56 :       &ArrayBuiltinsAssembler::NullPostLoopAction);
    1573          56 : }
    1574             : 
    1575             : // ES #sec-get-%typedarray%.prototype.findIndex
    1576         336 : TF_BUILTIN(TypedArrayPrototypeFindIndex, ArrayBuiltinsAssembler) {
    1577             :   TNode<IntPtrT> argc =
    1578          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1579          56 :   CodeStubArguments args(this, argc);
    1580          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1581          56 :   TNode<Object> receiver = args.GetReceiver();
    1582          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1583          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
    1584             : 
    1585          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
    1586             : 
    1587             :   GenerateIteratingTypedArrayBuiltinBody(
    1588             :       "%TypedArray%.prototype.findIndex",
    1589             :       &ArrayBuiltinsAssembler::FindIndexResultGenerator,
    1590             :       &ArrayBuiltinsAssembler::FindIndexProcessor,
    1591          56 :       &ArrayBuiltinsAssembler::NullPostLoopAction);
    1592          56 : }
    1593             : 
    1594         336 : TF_BUILTIN(TypedArrayPrototypeForEach, ArrayBuiltinsAssembler) {
    1595             :   TNode<IntPtrT> argc =
    1596          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1597          56 :   CodeStubArguments args(this, argc);
    1598          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1599          56 :   TNode<Object> receiver = args.GetReceiver();
    1600          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1601          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
    1602             : 
    1603          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
    1604             : 
    1605             :   GenerateIteratingTypedArrayBuiltinBody(
    1606             :       "%TypedArray%.prototype.forEach",
    1607             :       &ArrayBuiltinsAssembler::ForEachResultGenerator,
    1608             :       &ArrayBuiltinsAssembler::ForEachProcessor,
    1609          56 :       &ArrayBuiltinsAssembler::NullPostLoopAction);
    1610          56 : }
    1611             : 
    1612         336 : TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinsAssembler) {
    1613             :   TNode<IntPtrT> argc =
    1614          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1615          56 :   CodeStubArguments args(this, argc);
    1616          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1617          56 :   TNode<Object> receiver = args.GetReceiver();
    1618          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1619          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
    1620             : 
    1621          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
    1622             : 
    1623             :   GenerateIteratingTypedArrayBuiltinBody(
    1624             :       "%TypedArray%.prototype.some",
    1625             :       &ArrayBuiltinsAssembler::SomeResultGenerator,
    1626             :       &ArrayBuiltinsAssembler::SomeProcessor,
    1627          56 :       &ArrayBuiltinsAssembler::NullPostLoopAction);
    1628          56 : }
    1629             : 
    1630         336 : TF_BUILTIN(TypedArrayPrototypeEvery, ArrayBuiltinsAssembler) {
    1631             :   TNode<IntPtrT> argc =
    1632          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1633          56 :   CodeStubArguments args(this, argc);
    1634          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1635          56 :   TNode<Object> receiver = args.GetReceiver();
    1636          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1637          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
    1638             : 
    1639          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
    1640             : 
    1641             :   GenerateIteratingTypedArrayBuiltinBody(
    1642             :       "%TypedArray%.prototype.every",
    1643             :       &ArrayBuiltinsAssembler::EveryResultGenerator,
    1644             :       &ArrayBuiltinsAssembler::EveryProcessor,
    1645          56 :       &ArrayBuiltinsAssembler::NullPostLoopAction);
    1646          56 : }
    1647             : 
    1648         728 : TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinsAssembler) {
    1649          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1650          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1651          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1652          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1653          56 :   Node* accumulator = Parameter(Descriptor::kAccumulator);
    1654          56 :   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
    1655          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1656          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1657          56 :   Node* to = Parameter(Descriptor::kTo);
    1658             : 
    1659             :   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
    1660             :                                             this_arg, accumulator, object,
    1661          56 :                                             initial_k, len, to);
    1662             : 
    1663             :   GenerateIteratingArrayBuiltinLoopContinuation(
    1664             :       &ArrayBuiltinsAssembler::ReduceProcessor,
    1665             :       &ArrayBuiltinsAssembler::ReducePostLoopAction,
    1666          56 :       MissingPropertyMode::kSkip);
    1667          56 : }
    1668             : 
    1669         448 : TF_BUILTIN(ArrayReducePreLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
    1670          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1671          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1672          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1673          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1674             : 
    1675             :   // Simulate starting the loop at 0, but ensuring that the accumulator is
    1676             :   // the hole. The continuation stub will search for the initial non-hole
    1677             :   // element, rightly throwing an exception if not found.
    1678             :   Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
    1679             :                      callbackfn, UndefinedConstant(), TheHoleConstant(),
    1680          56 :                      receiver, SmiConstant(0), len, UndefinedConstant()));
    1681          56 : }
    1682             : 
    1683         560 : TF_BUILTIN(ArrayReduceLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
    1684          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1685          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1686          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1687          56 :   Node* accumulator = Parameter(Descriptor::kAccumulator);
    1688          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1689          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1690             : 
    1691             :   Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
    1692             :                      callbackfn, UndefinedConstant(), accumulator, receiver,
    1693          56 :                      initial_k, len, UndefinedConstant()));
    1694          56 : }
    1695             : 
    1696         560 : TF_BUILTIN(ArrayReduceLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
    1697          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1698          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1699          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1700          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1701          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1702          56 :   Node* result = Parameter(Descriptor::kResult);
    1703             : 
    1704             :   Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
    1705             :                      callbackfn, UndefinedConstant(), result, receiver,
    1706          56 :                      initial_k, len, UndefinedConstant()));
    1707          56 : }
    1708             : 
    1709         336 : TF_BUILTIN(ArrayReduce, ArrayBuiltinsAssembler) {
    1710             :   TNode<IntPtrT> argc =
    1711          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1712          56 :   CodeStubArguments args(this, argc);
    1713          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1714          56 :   TNode<Object> receiver = args.GetReceiver();
    1715          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1716          56 :   Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
    1717             : 
    1718             :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
    1719          56 :                                 argc);
    1720             : 
    1721             :   GenerateIteratingArrayBuiltinBody(
    1722             :       "Array.prototype.reduce", &ArrayBuiltinsAssembler::ReduceResultGenerator,
    1723             :       &ArrayBuiltinsAssembler::ReduceProcessor,
    1724             :       &ArrayBuiltinsAssembler::ReducePostLoopAction,
    1725             :       Builtins::CallableFor(isolate(), Builtins::kArrayReduceLoopContinuation),
    1726          56 :       MissingPropertyMode::kSkip);
    1727          56 : }
    1728             : 
    1729         336 : TF_BUILTIN(TypedArrayPrototypeReduce, ArrayBuiltinsAssembler) {
    1730             :   TNode<IntPtrT> argc =
    1731          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1732          56 :   CodeStubArguments args(this, argc);
    1733          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1734          56 :   TNode<Object> receiver = args.GetReceiver();
    1735          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1736          56 :   Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
    1737             : 
    1738             :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
    1739          56 :                                 argc);
    1740             : 
    1741             :   GenerateIteratingTypedArrayBuiltinBody(
    1742             :       "%TypedArray%.prototype.reduce",
    1743             :       &ArrayBuiltinsAssembler::ReduceResultGenerator,
    1744             :       &ArrayBuiltinsAssembler::ReduceProcessor,
    1745          56 :       &ArrayBuiltinsAssembler::ReducePostLoopAction);
    1746          56 : }
    1747             : 
    1748         728 : TF_BUILTIN(ArrayReduceRightLoopContinuation, ArrayBuiltinsAssembler) {
    1749          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1750          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1751          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1752          56 :   Node* this_arg = Parameter(Descriptor::kThisArg);
    1753          56 :   Node* accumulator = Parameter(Descriptor::kAccumulator);
    1754          56 :   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
    1755          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1756          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1757          56 :   Node* to = Parameter(Descriptor::kTo);
    1758             : 
    1759             :   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
    1760             :                                             this_arg, accumulator, object,
    1761          56 :                                             initial_k, len, to);
    1762             : 
    1763             :   GenerateIteratingArrayBuiltinLoopContinuation(
    1764             :       &ArrayBuiltinsAssembler::ReduceProcessor,
    1765             :       &ArrayBuiltinsAssembler::ReducePostLoopAction, MissingPropertyMode::kSkip,
    1766          56 :       ForEachDirection::kReverse);
    1767          56 : }
    1768             : 
    1769         448 : TF_BUILTIN(ArrayReduceRightPreLoopEagerDeoptContinuation,
    1770             :            ArrayBuiltinsAssembler) {
    1771          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1772          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1773          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1774          56 :   TNode<Smi> len = CAST(Parameter(Descriptor::kLength));
    1775             : 
    1776             :   // Simulate starting the loop at 0, but ensuring that the accumulator is
    1777             :   // the hole. The continuation stub will search for the initial non-hole
    1778             :   // element, rightly throwing an exception if not found.
    1779             :   Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
    1780             :                      receiver, callbackfn, UndefinedConstant(),
    1781             :                      TheHoleConstant(), receiver, SmiSub(len, SmiConstant(1)),
    1782          56 :                      len, UndefinedConstant()));
    1783          56 : }
    1784             : 
    1785         560 : TF_BUILTIN(ArrayReduceRightLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
    1786          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1787          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1788          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1789          56 :   Node* accumulator = Parameter(Descriptor::kAccumulator);
    1790          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1791          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1792             : 
    1793             :   Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
    1794             :                      receiver, callbackfn, UndefinedConstant(), accumulator,
    1795          56 :                      receiver, initial_k, len, UndefinedConstant()));
    1796          56 : }
    1797             : 
    1798         560 : TF_BUILTIN(ArrayReduceRightLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
    1799          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1800          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1801          56 :   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
    1802          56 :   Node* initial_k = Parameter(Descriptor::kInitialK);
    1803          56 :   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
    1804          56 :   Node* result = Parameter(Descriptor::kResult);
    1805             : 
    1806             :   Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
    1807             :                      receiver, callbackfn, UndefinedConstant(), result,
    1808          56 :                      receiver, initial_k, len, UndefinedConstant()));
    1809          56 : }
    1810             : 
    1811         336 : TF_BUILTIN(ArrayReduceRight, ArrayBuiltinsAssembler) {
    1812             :   TNode<IntPtrT> argc =
    1813          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1814          56 :   CodeStubArguments args(this, argc);
    1815          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1816          56 :   TNode<Object> receiver = args.GetReceiver();
    1817          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1818          56 :   Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
    1819             : 
    1820             :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
    1821          56 :                                 argc);
    1822             : 
    1823             :   GenerateIteratingArrayBuiltinBody(
    1824             :       "Array.prototype.reduceRight",
    1825             :       &ArrayBuiltinsAssembler::ReduceResultGenerator,
    1826             :       &ArrayBuiltinsAssembler::ReduceProcessor,
    1827             :       &ArrayBuiltinsAssembler::ReducePostLoopAction,
    1828             :       Builtins::CallableFor(isolate(),
    1829             :                             Builtins::kArrayReduceRightLoopContinuation),
    1830          56 :       MissingPropertyMode::kSkip, ForEachDirection::kReverse);
    1831          56 : }
    1832             : 
    1833         336 : TF_BUILTIN(TypedArrayPrototypeReduceRight, ArrayBuiltinsAssembler) {
    1834             :   TNode<IntPtrT> argc =
    1835          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1836          56 :   CodeStubArguments args(this, argc);
    1837          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1838          56 :   TNode<Object> receiver = args.GetReceiver();
    1839          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1840          56 :   Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
    1841             : 
    1842             :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
    1843          56 :                                 argc);
    1844             : 
    1845             :   GenerateIteratingTypedArrayBuiltinBody(
    1846             :       "%TypedArray%.prototype.reduceRight",
    1847             :       &ArrayBuiltinsAssembler::ReduceResultGenerator,
    1848             :       &ArrayBuiltinsAssembler::ReduceProcessor,
    1849             :       &ArrayBuiltinsAssembler::ReducePostLoopAction,
    1850          56 :       ForEachDirection::kReverse);
    1851          56 : }
    1852             : 
    1853         336 : TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
    1854             :   TNode<IntPtrT> argc =
    1855          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    1856          56 :   CodeStubArguments args(this, argc);
    1857          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1858          56 :   TNode<Object> receiver = args.GetReceiver();
    1859          56 :   Node* callbackfn = args.GetOptionalArgumentValue(0);
    1860          56 :   Node* this_arg = args.GetOptionalArgumentValue(1);
    1861             : 
    1862          56 :   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
    1863             : 
    1864             :   GenerateIteratingTypedArrayBuiltinBody(
    1865             :       "%TypedArray%.prototype.map",
    1866             :       &ArrayBuiltinsAssembler::TypedArrayMapResultGenerator,
    1867             :       &ArrayBuiltinsAssembler::TypedArrayMapProcessor,
    1868          56 :       &ArrayBuiltinsAssembler::NullPostLoopAction);
    1869          56 : }
    1870             : 
    1871         336 : TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
    1872          56 :   TNode<Object> object = CAST(Parameter(Descriptor::kArg));
    1873          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1874             : 
    1875         112 :   Label call_runtime(this), return_true(this), return_false(this);
    1876             : 
    1877          56 :   GotoIf(TaggedIsSmi(object), &return_false);
    1878          56 :   TNode<Int32T> instance_type = LoadInstanceType(CAST(object));
    1879             : 
    1880          56 :   GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &return_true);
    1881             : 
    1882             :   // TODO(verwaest): Handle proxies in-place.
    1883         112 :   Branch(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), &call_runtime,
    1884          56 :          &return_false);
    1885             : 
    1886          56 :   BIND(&return_true);
    1887          56 :   Return(TrueConstant());
    1888             : 
    1889          56 :   BIND(&return_false);
    1890          56 :   Return(FalseConstant());
    1891             : 
    1892          56 :   BIND(&call_runtime);
    1893         112 :   Return(CallRuntime(Runtime::kArrayIsArray, context, object));
    1894          56 : }
    1895             : 
    1896         448 : class ArrayIncludesIndexofAssembler : public CodeStubAssembler {
    1897             :  public:
    1898         448 :   explicit ArrayIncludesIndexofAssembler(compiler::CodeAssemblerState* state)
    1899         448 :       : CodeStubAssembler(state) {}
    1900             : 
    1901             :   enum SearchVariant { kIncludes, kIndexOf };
    1902             : 
    1903             :   void Generate(SearchVariant variant, TNode<IntPtrT> argc,
    1904             :                 TNode<Context> context);
    1905             :   void GenerateSmiOrObject(SearchVariant variant, Node* context, Node* elements,
    1906             :                            Node* search_element, Node* array_length,
    1907             :                            Node* from_index);
    1908             :   void GeneratePackedDoubles(SearchVariant variant, Node* elements,
    1909             :                              Node* search_element, Node* array_length,
    1910             :                              Node* from_index);
    1911             :   void GenerateHoleyDoubles(SearchVariant variant, Node* elements,
    1912             :                             Node* search_element, Node* array_length,
    1913             :                             Node* from_index);
    1914             : };
    1915             : 
    1916         112 : void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
    1917             :                                              TNode<IntPtrT> argc,
    1918             :                                              TNode<Context> context) {
    1919         112 :   const int kSearchElementArg = 0;
    1920         112 :   const int kFromIndexArg = 1;
    1921             : 
    1922         112 :   CodeStubArguments args(this, argc);
    1923             : 
    1924         112 :   TNode<Object> receiver = args.GetReceiver();
    1925             :   TNode<Object> search_element =
    1926         112 :       args.GetOptionalArgumentValue(kSearchElementArg);
    1927             : 
    1928         112 :   Node* intptr_zero = IntPtrConstant(0);
    1929             : 
    1930         224 :   Label init_index(this), return_not_found(this), call_runtime(this);
    1931             : 
    1932             :   // Take slow path if not a JSArray, if retrieving elements requires
    1933             :   // traversing prototype, or if access checks are required.
    1934         112 :   BranchIfFastJSArray(receiver, context, &init_index, &call_runtime);
    1935             : 
    1936         112 :   BIND(&init_index);
    1937         224 :   VARIABLE(index_var, MachineType::PointerRepresentation(), intptr_zero);
    1938         112 :   TNode<JSArray> array = CAST(receiver);
    1939             : 
    1940             :   // JSArray length is always a positive Smi for fast arrays.
    1941             :   CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array)));
    1942         112 :   Node* array_length = LoadFastJSArrayLength(array);
    1943         112 :   Node* array_length_untagged = SmiUntag(array_length);
    1944             : 
    1945             :   {
    1946             :     // Initialize fromIndex.
    1947         224 :     Label is_smi(this), is_nonsmi(this), done(this);
    1948             : 
    1949             :     // If no fromIndex was passed, default to 0.
    1950         112 :     GotoIf(IntPtrLessThanOrEqual(argc, IntPtrConstant(kFromIndexArg)), &done);
    1951             : 
    1952         112 :     Node* start_from = args.AtIndex(kFromIndexArg);
    1953             :     // Handle Smis and undefined here and everything else in runtime.
    1954             :     // We must be very careful with side effects from the ToInteger conversion,
    1955             :     // as the side effects might render previously checked assumptions about
    1956             :     // the receiver being a fast JSArray and its length invalid.
    1957         112 :     Branch(TaggedIsSmi(start_from), &is_smi, &is_nonsmi);
    1958             : 
    1959         112 :     BIND(&is_nonsmi);
    1960             :     {
    1961         112 :       GotoIfNot(IsUndefined(start_from), &call_runtime);
    1962         112 :       Goto(&done);
    1963             :     }
    1964         112 :     BIND(&is_smi);
    1965             :     {
    1966         112 :       Node* intptr_start_from = SmiUntag(start_from);
    1967         112 :       index_var.Bind(intptr_start_from);
    1968             : 
    1969         112 :       GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
    1970             :       // The fromIndex is negative: add it to the array's length.
    1971         112 :       index_var.Bind(IntPtrAdd(array_length_untagged, index_var.value()));
    1972             :       // Clamp negative results at zero.
    1973         112 :       GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
    1974         112 :       index_var.Bind(intptr_zero);
    1975         112 :       Goto(&done);
    1976             :     }
    1977         224 :     BIND(&done);
    1978             :   }
    1979             : 
    1980             :   // Fail early if startIndex >= array.length.
    1981         224 :   GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), array_length_untagged),
    1982         112 :          &return_not_found);
    1983             : 
    1984         224 :   Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
    1985             : 
    1986         112 :   TNode<Int32T> elements_kind = LoadElementsKind(array);
    1987         112 :   Node* elements = LoadElements(array);
    1988             :   STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
    1989             :   STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
    1990             :   STATIC_ASSERT(PACKED_ELEMENTS == 2);
    1991             :   STATIC_ASSERT(HOLEY_ELEMENTS == 3);
    1992         224 :   GotoIf(Uint32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
    1993         112 :          &if_smiorobjects);
    1994         224 :   GotoIf(Word32Equal(elements_kind, Int32Constant(PACKED_DOUBLE_ELEMENTS)),
    1995         112 :          &if_packed_doubles);
    1996         224 :   GotoIf(Word32Equal(elements_kind, Int32Constant(HOLEY_DOUBLE_ELEMENTS)),
    1997         112 :          &if_holey_doubles);
    1998         112 :   Goto(&return_not_found);
    1999             : 
    2000         112 :   BIND(&if_smiorobjects);
    2001             :   {
    2002             :     Callable callable =
    2003             :         (variant == kIncludes)
    2004             :             ? Builtins::CallableFor(isolate(),
    2005             :                                     Builtins::kArrayIncludesSmiOrObject)
    2006             :             : Builtins::CallableFor(isolate(),
    2007         112 :                                     Builtins::kArrayIndexOfSmiOrObject);
    2008             :     Node* result = CallStub(callable, context, elements, search_element,
    2009         112 :                             array_length, SmiTag(index_var.value()));
    2010         112 :     args.PopAndReturn(result);
    2011             :   }
    2012             : 
    2013         112 :   BIND(&if_packed_doubles);
    2014             :   {
    2015             :     Callable callable =
    2016             :         (variant == kIncludes)
    2017             :             ? Builtins::CallableFor(isolate(),
    2018             :                                     Builtins::kArrayIncludesPackedDoubles)
    2019             :             : Builtins::CallableFor(isolate(),
    2020         112 :                                     Builtins::kArrayIndexOfPackedDoubles);
    2021             :     Node* result = CallStub(callable, context, elements, search_element,
    2022         112 :                             array_length, SmiTag(index_var.value()));
    2023         112 :     args.PopAndReturn(result);
    2024             :   }
    2025             : 
    2026         112 :   BIND(&if_holey_doubles);
    2027             :   {
    2028             :     Callable callable =
    2029             :         (variant == kIncludes)
    2030             :             ? Builtins::CallableFor(isolate(),
    2031             :                                     Builtins::kArrayIncludesHoleyDoubles)
    2032             :             : Builtins::CallableFor(isolate(),
    2033         112 :                                     Builtins::kArrayIndexOfHoleyDoubles);
    2034             :     Node* result = CallStub(callable, context, elements, search_element,
    2035         112 :                             array_length, SmiTag(index_var.value()));
    2036         112 :     args.PopAndReturn(result);
    2037             :   }
    2038             : 
    2039         112 :   BIND(&return_not_found);
    2040         112 :   if (variant == kIncludes) {
    2041          56 :     args.PopAndReturn(FalseConstant());
    2042             :   } else {
    2043          56 :     args.PopAndReturn(NumberConstant(-1));
    2044             :   }
    2045             : 
    2046         112 :   BIND(&call_runtime);
    2047             :   {
    2048             :     Node* start_from =
    2049         112 :         args.GetOptionalArgumentValue(kFromIndexArg, UndefinedConstant());
    2050             :     Runtime::FunctionId function = variant == kIncludes
    2051             :                                        ? Runtime::kArrayIncludes_Slow
    2052         112 :                                        : Runtime::kArrayIndexOf;
    2053             :     args.PopAndReturn(
    2054         112 :         CallRuntime(function, context, array, search_element, start_from));
    2055         112 :   }
    2056         112 : }
    2057             : 
    2058         112 : void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
    2059             :     SearchVariant variant, Node* context, Node* elements, Node* search_element,
    2060             :     Node* array_length, Node* from_index) {
    2061         112 :   VARIABLE(index_var, MachineType::PointerRepresentation(),
    2062             :            SmiUntag(from_index));
    2063         224 :   VARIABLE(search_num, MachineRepresentation::kFloat64);
    2064         112 :   Node* array_length_untagged = SmiUntag(array_length);
    2065             : 
    2066         224 :   Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
    2067         224 :       string_loop(this), bigint_loop(this, &index_var),
    2068         224 :       undef_loop(this, &index_var), not_smi(this), not_heap_num(this),
    2069         224 :       return_found(this), return_not_found(this);
    2070             : 
    2071         112 :   GotoIfNot(TaggedIsSmi(search_element), &not_smi);
    2072         112 :   search_num.Bind(SmiToFloat64(search_element));
    2073         112 :   Goto(&heap_num_loop);
    2074             : 
    2075         112 :   BIND(&not_smi);
    2076         112 :   if (variant == kIncludes) {
    2077          56 :     GotoIf(IsUndefined(search_element), &undef_loop);
    2078             :   }
    2079         112 :   Node* map = LoadMap(search_element);
    2080         112 :   GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
    2081         112 :   search_num.Bind(LoadHeapNumberValue(search_element));
    2082         112 :   Goto(&heap_num_loop);
    2083             : 
    2084         112 :   BIND(&not_heap_num);
    2085         112 :   Node* search_type = LoadMapInstanceType(map);
    2086         112 :   GotoIf(IsStringInstanceType(search_type), &string_loop);
    2087         112 :   GotoIf(IsBigIntInstanceType(search_type), &bigint_loop);
    2088         112 :   Goto(&ident_loop);
    2089             : 
    2090         112 :   BIND(&ident_loop);
    2091             :   {
    2092         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2093         112 :               &return_not_found);
    2094             :     Node* element_k =
    2095         112 :         UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    2096         112 :     GotoIf(WordEqual(element_k, search_element), &return_found);
    2097             : 
    2098         112 :     Increment(&index_var);
    2099         112 :     Goto(&ident_loop);
    2100             :   }
    2101             : 
    2102         112 :   if (variant == kIncludes) {
    2103          56 :     BIND(&undef_loop);
    2104             : 
    2105         112 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2106          56 :               &return_not_found);
    2107             :     Node* element_k =
    2108          56 :         UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    2109          56 :     GotoIf(IsUndefined(element_k), &return_found);
    2110          56 :     GotoIf(IsTheHole(element_k), &return_found);
    2111             : 
    2112          56 :     Increment(&index_var);
    2113          56 :     Goto(&undef_loop);
    2114             :   }
    2115             : 
    2116         112 :   BIND(&heap_num_loop);
    2117             :   {
    2118         224 :     Label nan_loop(this, &index_var), not_nan_loop(this, &index_var);
    2119         112 :     Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
    2120         112 :     BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
    2121             : 
    2122         112 :     BIND(&not_nan_loop);
    2123             :     {
    2124         224 :       Label continue_loop(this), not_smi(this);
    2125         224 :       GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2126         112 :                 &return_not_found);
    2127             :       Node* element_k =
    2128         112 :           UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    2129         112 :       GotoIfNot(TaggedIsSmi(element_k), &not_smi);
    2130         224 :       Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
    2131         112 :              &return_found, &continue_loop);
    2132             : 
    2133         112 :       BIND(&not_smi);
    2134         112 :       GotoIfNot(IsHeapNumber(element_k), &continue_loop);
    2135         224 :       Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
    2136         112 :              &return_found, &continue_loop);
    2137             : 
    2138         112 :       BIND(&continue_loop);
    2139         112 :       Increment(&index_var);
    2140         224 :       Goto(&not_nan_loop);
    2141             :     }
    2142             : 
    2143             :     // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
    2144         112 :     if (variant == kIncludes) {
    2145          56 :       BIND(&nan_loop);
    2146          56 :       Label continue_loop(this);
    2147         112 :       GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2148          56 :                 &return_not_found);
    2149             :       Node* element_k =
    2150          56 :           UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    2151          56 :       GotoIf(TaggedIsSmi(element_k), &continue_loop);
    2152          56 :       GotoIfNot(IsHeapNumber(CAST(element_k)), &continue_loop);
    2153         112 :       BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_found,
    2154          56 :                            &continue_loop);
    2155             : 
    2156          56 :       BIND(&continue_loop);
    2157          56 :       Increment(&index_var);
    2158          56 :       Goto(&nan_loop);
    2159         112 :     }
    2160             :   }
    2161             : 
    2162         112 :   BIND(&string_loop);
    2163             :   {
    2164         112 :     TNode<String> search_element_string = CAST(search_element);
    2165         224 :     Label continue_loop(this), next_iteration(this, &index_var),
    2166         224 :         slow_compare(this), runtime(this, Label::kDeferred);
    2167             :     TNode<IntPtrT> search_length =
    2168         112 :         LoadStringLengthAsWord(search_element_string);
    2169         112 :     Goto(&next_iteration);
    2170         112 :     BIND(&next_iteration);
    2171         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2172         112 :               &return_not_found);
    2173             :     Node* element_k =
    2174         112 :         UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    2175         112 :     GotoIf(TaggedIsSmi(element_k), &continue_loop);
    2176         112 :     GotoIf(WordEqual(search_element_string, element_k), &return_found);
    2177         112 :     Node* element_k_type = LoadInstanceType(element_k);
    2178         112 :     GotoIfNot(IsStringInstanceType(element_k_type), &continue_loop);
    2179         224 :     Branch(WordEqual(search_length, LoadStringLengthAsWord(element_k)),
    2180         112 :            &slow_compare, &continue_loop);
    2181             : 
    2182         112 :     BIND(&slow_compare);
    2183         224 :     StringBuiltinsAssembler string_asm(state());
    2184             :     string_asm.StringEqual_Core(context, search_element_string, search_type,
    2185             :                                 element_k, element_k_type, search_length,
    2186         112 :                                 &return_found, &continue_loop, &runtime);
    2187         112 :     BIND(&runtime);
    2188             :     TNode<Object> result = CallRuntime(Runtime::kStringEqual, context,
    2189         112 :                                        search_element_string, element_k);
    2190         112 :     Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
    2191             : 
    2192         112 :     BIND(&continue_loop);
    2193         112 :     Increment(&index_var);
    2194         224 :     Goto(&next_iteration);
    2195             :   }
    2196             : 
    2197         112 :   BIND(&bigint_loop);
    2198             :   {
    2199         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2200         112 :               &return_not_found);
    2201             : 
    2202             :     Node* element_k =
    2203         112 :         UnsafeLoadFixedArrayElement(CAST(elements), index_var.value());
    2204         112 :     Label continue_loop(this);
    2205         112 :     GotoIf(TaggedIsSmi(element_k), &continue_loop);
    2206         112 :     GotoIfNot(IsBigInt(CAST(element_k)), &continue_loop);
    2207             :     TNode<Object> result = CallRuntime(Runtime::kBigIntEqualToBigInt, context,
    2208         112 :                                        search_element, element_k);
    2209         112 :     Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
    2210             : 
    2211         112 :     BIND(&continue_loop);
    2212         112 :     Increment(&index_var);
    2213         112 :     Goto(&bigint_loop);
    2214             :   }
    2215         112 :   BIND(&return_found);
    2216         112 :   if (variant == kIncludes) {
    2217          56 :     Return(TrueConstant());
    2218             :   } else {
    2219          56 :     Return(SmiTag(index_var.value()));
    2220             :   }
    2221             : 
    2222         112 :   BIND(&return_not_found);
    2223         112 :   if (variant == kIncludes) {
    2224          56 :     Return(FalseConstant());
    2225             :   } else {
    2226          56 :     Return(NumberConstant(-1));
    2227         112 :   }
    2228         112 : }
    2229             : 
    2230         112 : void ArrayIncludesIndexofAssembler::GeneratePackedDoubles(SearchVariant variant,
    2231             :                                                           Node* elements,
    2232             :                                                           Node* search_element,
    2233             :                                                           Node* array_length,
    2234             :                                                           Node* from_index) {
    2235         112 :   VARIABLE(index_var, MachineType::PointerRepresentation(),
    2236             :            SmiUntag(from_index));
    2237         112 :   Node* array_length_untagged = SmiUntag(array_length);
    2238             : 
    2239         224 :   Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
    2240         224 :       hole_loop(this, &index_var), search_notnan(this), return_found(this),
    2241         224 :       return_not_found(this);
    2242         224 :   VARIABLE(search_num, MachineRepresentation::kFloat64);
    2243         112 :   search_num.Bind(Float64Constant(0));
    2244             : 
    2245         112 :   GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
    2246         112 :   search_num.Bind(SmiToFloat64(search_element));
    2247         112 :   Goto(&not_nan_loop);
    2248             : 
    2249         112 :   BIND(&search_notnan);
    2250         112 :   GotoIfNot(IsHeapNumber(search_element), &return_not_found);
    2251             : 
    2252         112 :   search_num.Bind(LoadHeapNumberValue(search_element));
    2253             : 
    2254         112 :   Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
    2255         112 :   BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
    2256             : 
    2257         112 :   BIND(&not_nan_loop);
    2258             :   {
    2259         112 :     Label continue_loop(this);
    2260         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2261         112 :               &return_not_found);
    2262             :     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
    2263         112 :                                                   MachineType::Float64());
    2264         224 :     Branch(Float64Equal(element_k, search_num.value()), &return_found,
    2265         112 :            &continue_loop);
    2266         112 :     BIND(&continue_loop);
    2267         112 :     Increment(&index_var);
    2268         112 :     Goto(&not_nan_loop);
    2269             :   }
    2270             : 
    2271             :   // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
    2272         112 :   if (variant == kIncludes) {
    2273          56 :     BIND(&nan_loop);
    2274          56 :     Label continue_loop(this);
    2275         112 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2276          56 :               &return_not_found);
    2277             :     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
    2278          56 :                                                   MachineType::Float64());
    2279          56 :     BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
    2280          56 :     BIND(&continue_loop);
    2281          56 :     Increment(&index_var);
    2282          56 :     Goto(&nan_loop);
    2283             :   }
    2284             : 
    2285         112 :   BIND(&return_found);
    2286         112 :   if (variant == kIncludes) {
    2287          56 :     Return(TrueConstant());
    2288             :   } else {
    2289          56 :     Return(SmiTag(index_var.value()));
    2290             :   }
    2291             : 
    2292         112 :   BIND(&return_not_found);
    2293         112 :   if (variant == kIncludes) {
    2294          56 :     Return(FalseConstant());
    2295             :   } else {
    2296          56 :     Return(NumberConstant(-1));
    2297         112 :   }
    2298         112 : }
    2299             : 
    2300         112 : void ArrayIncludesIndexofAssembler::GenerateHoleyDoubles(SearchVariant variant,
    2301             :                                                          Node* elements,
    2302             :                                                          Node* search_element,
    2303             :                                                          Node* array_length,
    2304             :                                                          Node* from_index) {
    2305         112 :   VARIABLE(index_var, MachineType::PointerRepresentation(),
    2306             :            SmiUntag(from_index));
    2307         112 :   Node* array_length_untagged = SmiUntag(array_length);
    2308             : 
    2309         224 :   Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
    2310         224 :       hole_loop(this, &index_var), search_notnan(this), return_found(this),
    2311         224 :       return_not_found(this);
    2312         224 :   VARIABLE(search_num, MachineRepresentation::kFloat64);
    2313         112 :   search_num.Bind(Float64Constant(0));
    2314             : 
    2315         112 :   GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
    2316         112 :   search_num.Bind(SmiToFloat64(search_element));
    2317         112 :   Goto(&not_nan_loop);
    2318             : 
    2319         112 :   BIND(&search_notnan);
    2320         112 :   if (variant == kIncludes) {
    2321          56 :     GotoIf(IsUndefined(search_element), &hole_loop);
    2322             :   }
    2323         112 :   GotoIfNot(IsHeapNumber(search_element), &return_not_found);
    2324             : 
    2325         112 :   search_num.Bind(LoadHeapNumberValue(search_element));
    2326             : 
    2327         112 :   Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
    2328         112 :   BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
    2329             : 
    2330         112 :   BIND(&not_nan_loop);
    2331             :   {
    2332         112 :     Label continue_loop(this);
    2333         224 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2334         112 :               &return_not_found);
    2335             : 
    2336             :     // No need for hole checking here; the following Float64Equal will
    2337             :     // return 'not equal' for holes anyway.
    2338             :     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
    2339         112 :                                                   MachineType::Float64());
    2340             : 
    2341         224 :     Branch(Float64Equal(element_k, search_num.value()), &return_found,
    2342         112 :            &continue_loop);
    2343         112 :     BIND(&continue_loop);
    2344         112 :     Increment(&index_var);
    2345         112 :     Goto(&not_nan_loop);
    2346             :   }
    2347             : 
    2348             :   // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
    2349         112 :   if (variant == kIncludes) {
    2350          56 :     BIND(&nan_loop);
    2351          56 :     Label continue_loop(this);
    2352         112 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2353          56 :               &return_not_found);
    2354             : 
    2355             :     // Load double value or continue if it's the hole NaN.
    2356             :     Node* element_k = LoadFixedDoubleArrayElement(
    2357             :         elements, index_var.value(), MachineType::Float64(), 0,
    2358          56 :         INTPTR_PARAMETERS, &continue_loop);
    2359             : 
    2360          56 :     BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
    2361          56 :     BIND(&continue_loop);
    2362          56 :     Increment(&index_var);
    2363          56 :     Goto(&nan_loop);
    2364             :   }
    2365             : 
    2366             :   // Array.p.includes treats the hole as undefined.
    2367         112 :   if (variant == kIncludes) {
    2368          56 :     BIND(&hole_loop);
    2369         112 :     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
    2370          56 :               &return_not_found);
    2371             : 
    2372             :     // Check if the element is a double hole, but don't load it.
    2373             :     LoadFixedDoubleArrayElement(elements, index_var.value(),
    2374             :                                 MachineType::None(), 0, INTPTR_PARAMETERS,
    2375          56 :                                 &return_found);
    2376             : 
    2377          56 :     Increment(&index_var);
    2378          56 :     Goto(&hole_loop);
    2379             :   }
    2380             : 
    2381         112 :   BIND(&return_found);
    2382         112 :   if (variant == kIncludes) {
    2383          56 :     Return(TrueConstant());
    2384             :   } else {
    2385          56 :     Return(SmiTag(index_var.value()));
    2386             :   }
    2387             : 
    2388         112 :   BIND(&return_not_found);
    2389         112 :   if (variant == kIncludes) {
    2390          56 :     Return(FalseConstant());
    2391             :   } else {
    2392          56 :     Return(NumberConstant(-1));
    2393         112 :   }
    2394         112 : }
    2395             : 
    2396         336 : TF_BUILTIN(ArrayIncludes, ArrayIncludesIndexofAssembler) {
    2397             :   TNode<IntPtrT> argc =
    2398          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    2399          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2400             : 
    2401          56 :   Generate(kIncludes, argc, context);
    2402          56 : }
    2403             : 
    2404         504 : TF_BUILTIN(ArrayIncludesSmiOrObject, ArrayIncludesIndexofAssembler) {
    2405          56 :   Node* context = Parameter(Descriptor::kContext);
    2406          56 :   Node* elements = Parameter(Descriptor::kElements);
    2407          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    2408          56 :   Node* array_length = Parameter(Descriptor::kLength);
    2409          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    2410             : 
    2411             :   GenerateSmiOrObject(kIncludes, context, elements, search_element,
    2412          56 :                       array_length, from_index);
    2413          56 : }
    2414             : 
    2415         448 : TF_BUILTIN(ArrayIncludesPackedDoubles, ArrayIncludesIndexofAssembler) {
    2416          56 :   Node* elements = Parameter(Descriptor::kElements);
    2417          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    2418          56 :   Node* array_length = Parameter(Descriptor::kLength);
    2419          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    2420             : 
    2421             :   GeneratePackedDoubles(kIncludes, elements, search_element, array_length,
    2422          56 :                         from_index);
    2423          56 : }
    2424             : 
    2425         448 : TF_BUILTIN(ArrayIncludesHoleyDoubles, ArrayIncludesIndexofAssembler) {
    2426          56 :   Node* elements = Parameter(Descriptor::kElements);
    2427          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    2428          56 :   Node* array_length = Parameter(Descriptor::kLength);
    2429          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    2430             : 
    2431             :   GenerateHoleyDoubles(kIncludes, elements, search_element, array_length,
    2432          56 :                        from_index);
    2433          56 : }
    2434             : 
    2435         336 : TF_BUILTIN(ArrayIndexOf, ArrayIncludesIndexofAssembler) {
    2436             :   TNode<IntPtrT> argc =
    2437          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    2438          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2439             : 
    2440          56 :   Generate(kIndexOf, argc, context);
    2441          56 : }
    2442             : 
    2443         504 : TF_BUILTIN(ArrayIndexOfSmiOrObject, ArrayIncludesIndexofAssembler) {
    2444          56 :   Node* context = Parameter(Descriptor::kContext);
    2445          56 :   Node* elements = Parameter(Descriptor::kElements);
    2446          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    2447          56 :   Node* array_length = Parameter(Descriptor::kLength);
    2448          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    2449             : 
    2450             :   GenerateSmiOrObject(kIndexOf, context, elements, search_element, array_length,
    2451          56 :                       from_index);
    2452          56 : }
    2453             : 
    2454         448 : TF_BUILTIN(ArrayIndexOfPackedDoubles, ArrayIncludesIndexofAssembler) {
    2455          56 :   Node* elements = Parameter(Descriptor::kElements);
    2456          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    2457          56 :   Node* array_length = Parameter(Descriptor::kLength);
    2458          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    2459             : 
    2460             :   GeneratePackedDoubles(kIndexOf, elements, search_element, array_length,
    2461          56 :                         from_index);
    2462          56 : }
    2463             : 
    2464         448 : TF_BUILTIN(ArrayIndexOfHoleyDoubles, ArrayIncludesIndexofAssembler) {
    2465          56 :   Node* elements = Parameter(Descriptor::kElements);
    2466          56 :   Node* search_element = Parameter(Descriptor::kSearchElement);
    2467          56 :   Node* array_length = Parameter(Descriptor::kLength);
    2468          56 :   Node* from_index = Parameter(Descriptor::kFromIndex);
    2469             : 
    2470             :   GenerateHoleyDoubles(kIndexOf, elements, search_element, array_length,
    2471          56 :                        from_index);
    2472          56 : }
    2473             : 
    2474             : // ES #sec-array.prototype.values
    2475         336 : TF_BUILTIN(ArrayPrototypeValues, CodeStubAssembler) {
    2476          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2477          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    2478          56 :   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
    2479          56 :                              IterationKind::kValues));
    2480          56 : }
    2481             : 
    2482             : // ES #sec-array.prototype.entries
    2483         336 : TF_BUILTIN(ArrayPrototypeEntries, CodeStubAssembler) {
    2484          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2485          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    2486          56 :   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
    2487          56 :                              IterationKind::kEntries));
    2488          56 : }
    2489             : 
    2490             : // ES #sec-array.prototype.keys
    2491         336 : TF_BUILTIN(ArrayPrototypeKeys, CodeStubAssembler) {
    2492          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2493          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    2494          56 :   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
    2495          56 :                              IterationKind::kKeys));
    2496          56 : }
    2497             : 
    2498             : // ES #sec-%arrayiteratorprototype%.next
    2499         336 : TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
    2500          56 :   const char* method_name = "Array Iterator.prototype.next";
    2501             : 
    2502          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2503          56 :   Node* iterator = Parameter(Descriptor::kReceiver);
    2504             : 
    2505          56 :   VARIABLE(var_done, MachineRepresentation::kTagged, TrueConstant());
    2506         112 :   VARIABLE(var_value, MachineRepresentation::kTagged, UndefinedConstant());
    2507             : 
    2508         112 :   Label allocate_entry_if_needed(this);
    2509         112 :   Label allocate_iterator_result(this);
    2510         112 :   Label if_typedarray(this), if_other(this, Label::kDeferred), if_array(this),
    2511         112 :       if_generic(this, Label::kDeferred);
    2512         112 :   Label set_done(this, Label::kDeferred);
    2513             : 
    2514             :   // If O does not have all of the internal slots of an Array Iterator Instance
    2515             :   // (22.1.5.3), throw a TypeError exception
    2516             :   ThrowIfNotInstanceType(context, iterator, JS_ARRAY_ITERATOR_TYPE,
    2517          56 :                          method_name);
    2518             : 
    2519             :   // Let a be O.[[IteratedObject]].
    2520             :   TNode<JSReceiver> array =
    2521          56 :       CAST(LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset));
    2522             : 
    2523             :   // Let index be O.[[ArrayIteratorNextIndex]].
    2524             :   TNode<Number> index =
    2525          56 :       CAST(LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset));
    2526             :   CSA_ASSERT(this, IsNumberNonNegativeSafeInteger(index));
    2527             : 
    2528             :   // Dispatch based on the type of the {array}.
    2529          56 :   TNode<Map> array_map = LoadMap(array);
    2530          56 :   TNode<Int32T> array_type = LoadMapInstanceType(array_map);
    2531          56 :   GotoIf(InstanceTypeEqual(array_type, JS_ARRAY_TYPE), &if_array);
    2532         112 :   Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_typedarray,
    2533          56 :          &if_other);
    2534             : 
    2535          56 :   BIND(&if_array);
    2536             :   {
    2537             :     // If {array} is a JSArray, then the {index} must be in Unsigned32 range.
    2538             :     CSA_ASSERT(this, IsNumberArrayIndex(index));
    2539             : 
    2540             :     // Check that the {index} is within range for the {array}. We handle all
    2541             :     // kinds of JSArray's here, so we do the computation on Uint32.
    2542          56 :     TNode<Uint32T> index32 = ChangeNumberToUint32(index);
    2543             :     TNode<Uint32T> length32 =
    2544          56 :         ChangeNumberToUint32(LoadJSArrayLength(CAST(array)));
    2545          56 :     GotoIfNot(Uint32LessThan(index32, length32), &set_done);
    2546             :     StoreObjectField(
    2547             :         iterator, JSArrayIterator::kNextIndexOffset,
    2548          56 :         ChangeUint32ToTagged(Unsigned(Int32Add(index32, Int32Constant(1)))));
    2549             : 
    2550          56 :     var_done.Bind(FalseConstant());
    2551          56 :     var_value.Bind(index);
    2552             : 
    2553             :     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
    2554          56 :                            iterator, JSArrayIterator::kKindOffset),
    2555         168 :                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
    2556          56 :            &allocate_iterator_result);
    2557             : 
    2558          56 :     Label if_hole(this, Label::kDeferred);
    2559          56 :     TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
    2560          56 :     TNode<FixedArrayBase> elements = LoadElements(CAST(array));
    2561          56 :     GotoIfForceSlowPath(&if_generic);
    2562             :     var_value.Bind(LoadFixedArrayBaseElementAsTagged(
    2563         112 :         elements, Signed(ChangeUint32ToWord(index32)), elements_kind,
    2564          56 :         &if_generic, &if_hole));
    2565          56 :     Goto(&allocate_entry_if_needed);
    2566             : 
    2567          56 :     BIND(&if_hole);
    2568             :     {
    2569          56 :       GotoIf(IsNoElementsProtectorCellInvalid(), &if_generic);
    2570         112 :       GotoIfNot(IsPrototypeInitialArrayPrototype(context, array_map),
    2571          56 :                 &if_generic);
    2572          56 :       var_value.Bind(UndefinedConstant());
    2573          56 :       Goto(&allocate_entry_if_needed);
    2574          56 :     }
    2575             :   }
    2576             : 
    2577          56 :   BIND(&if_other);
    2578             :   {
    2579             :     // We cannot enter here with either JSArray's or JSTypedArray's.
    2580             :     CSA_ASSERT(this, Word32BinaryNot(IsJSArray(array)));
    2581             :     CSA_ASSERT(this, Word32BinaryNot(IsJSTypedArray(array)));
    2582             : 
    2583             :     // Check that the {index} is within the bounds of the {array}s "length".
    2584         112 :     TNode<Number> length = CAST(
    2585             :         CallBuiltin(Builtins::kToLength, context,
    2586             :                     GetProperty(context, array, factory()->length_string())));
    2587          56 :     GotoIfNumberGreaterThanOrEqual(index, length, &set_done);
    2588             :     StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset,
    2589          56 :                      NumberInc(index));
    2590             : 
    2591          56 :     var_done.Bind(FalseConstant());
    2592          56 :     var_value.Bind(index);
    2593             : 
    2594             :     Branch(Word32Equal(LoadAndUntagToWord32ObjectField(
    2595          56 :                            iterator, JSArrayIterator::kKindOffset),
    2596         168 :                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
    2597          56 :            &allocate_iterator_result, &if_generic);
    2598             :   }
    2599             : 
    2600          56 :   BIND(&set_done);
    2601             :   {
    2602             :     // Change the [[ArrayIteratorNextIndex]] such that the {iterator} will
    2603             :     // never produce values anymore, because it will always fail the bounds
    2604             :     // check. Note that this is different from what the specification does,
    2605             :     // which is changing the [[IteratedObject]] to undefined, because leaving
    2606             :     // [[IteratedObject]] alone helps TurboFan to generate better code with
    2607             :     // the inlining in JSCallReducer::ReduceArrayIteratorPrototypeNext().
    2608             :     //
    2609             :     // The terminal value we chose here depends on the type of the {array},
    2610             :     // for JSArray's we use kMaxUInt32 so that TurboFan can always use
    2611             :     // Word32 representation for fast-path indices (and this is safe since
    2612             :     // the "length" of JSArray's is limited to Unsigned32 range). For other
    2613             :     // JSReceiver's we have to use kMaxSafeInteger, since the "length" can
    2614             :     // be any arbitrary value in the safe integer range.
    2615             :     //
    2616             :     // Note specifically that JSTypedArray's will never take this path, so
    2617             :     // we don't need to worry about their maximum value.
    2618             :     CSA_ASSERT(this, Word32BinaryNot(IsJSTypedArray(array)));
    2619             :     TNode<Number> max_length =
    2620             :         SelectConstant(IsJSArray(array), NumberConstant(kMaxUInt32),
    2621          56 :                        NumberConstant(kMaxSafeInteger));
    2622          56 :     StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, max_length);
    2623          56 :     Goto(&allocate_iterator_result);
    2624             :   }
    2625             : 
    2626          56 :   BIND(&if_generic);
    2627             :   {
    2628          56 :     var_value.Bind(GetProperty(context, array, index));
    2629          56 :     Goto(&allocate_entry_if_needed);
    2630             :   }
    2631             : 
    2632          56 :   BIND(&if_typedarray);
    2633             :   {
    2634             :     // If {array} is a JSTypedArray, the {index} must always be a Smi.
    2635             :     CSA_ASSERT(this, TaggedIsSmi(index));
    2636             : 
    2637             :     // Check that the {array}s buffer wasn't detached.
    2638          56 :     ThrowIfArrayBufferViewBufferIsDetached(context, CAST(array), method_name);
    2639             : 
    2640             :     // If we go outside of the {length}, we don't need to update the
    2641             :     // [[ArrayIteratorNextIndex]] anymore, since a JSTypedArray's
    2642             :     // length cannot change anymore, so this {iterator} will never
    2643             :     // produce values again anyways.
    2644          56 :     TNode<Smi> length = LoadJSTypedArrayLength(CAST(array));
    2645          56 :     GotoIfNot(SmiBelow(CAST(index), length), &allocate_iterator_result);
    2646             :     StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
    2647          56 :                                    SmiInc(CAST(index)));
    2648             : 
    2649          56 :     var_done.Bind(FalseConstant());
    2650          56 :     var_value.Bind(index);
    2651             : 
    2652             :     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
    2653          56 :                            iterator, JSArrayIterator::kKindOffset),
    2654         168 :                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
    2655          56 :            &allocate_iterator_result);
    2656             : 
    2657          56 :     TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
    2658          56 :     Node* elements = LoadElements(CAST(array));
    2659             :     Node* base_ptr =
    2660          56 :         LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
    2661             :     Node* external_ptr =
    2662             :         LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
    2663          56 :                         MachineType::Pointer());
    2664             :     TNode<WordT> data_ptr =
    2665          56 :         IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
    2666          56 :     var_value.Bind(LoadFixedTypedArrayElementAsTagged(data_ptr, CAST(index),
    2667          56 :                                                       elements_kind));
    2668          56 :     Goto(&allocate_entry_if_needed);
    2669             :   }
    2670             : 
    2671          56 :   BIND(&allocate_entry_if_needed);
    2672             :   {
    2673             :     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
    2674          56 :                            iterator, JSArrayIterator::kKindOffset),
    2675         168 :                        Int32Constant(static_cast<int>(IterationKind::kValues))),
    2676          56 :            &allocate_iterator_result);
    2677             : 
    2678             :     Node* result =
    2679          56 :         AllocateJSIteratorResultForEntry(context, index, var_value.value());
    2680          56 :     Return(result);
    2681             :   }
    2682             : 
    2683          56 :   BIND(&allocate_iterator_result);
    2684             :   {
    2685             :     Node* result =
    2686          56 :         AllocateJSIteratorResult(context, var_value.value(), var_done.value());
    2687          56 :     Return(result);
    2688          56 :   }
    2689          56 : }
    2690             : 
    2691         112 : class ArrayFlattenAssembler : public CodeStubAssembler {
    2692             :  public:
    2693         112 :   explicit ArrayFlattenAssembler(compiler::CodeAssemblerState* state)
    2694         112 :       : CodeStubAssembler(state) {}
    2695             : 
    2696             :   // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
    2697         112 :   Node* FlattenIntoArray(Node* context, Node* target, Node* source,
    2698             :                          Node* source_length, Node* start, Node* depth,
    2699             :                          Node* mapper_function = nullptr,
    2700             :                          Node* this_arg = nullptr) {
    2701             :     CSA_ASSERT(this, IsJSReceiver(target));
    2702             :     CSA_ASSERT(this, IsJSReceiver(source));
    2703             :     CSA_ASSERT(this, IsNumberPositive(source_length));
    2704             :     CSA_ASSERT(this, IsNumberPositive(start));
    2705             :     CSA_ASSERT(this, IsNumber(depth));
    2706             : 
    2707             :     // 1. Let targetIndex be start.
    2708         112 :     VARIABLE(var_target_index, MachineRepresentation::kTagged, start);
    2709             : 
    2710             :     // 2. Let sourceIndex be 0.
    2711         224 :     VARIABLE(var_source_index, MachineRepresentation::kTagged, SmiConstant(0));
    2712             : 
    2713             :     // 3. Repeat...
    2714         224 :     Label loop(this, {&var_target_index, &var_source_index}), done_loop(this);
    2715         112 :     Goto(&loop);
    2716         112 :     BIND(&loop);
    2717             :     {
    2718         112 :       Node* const source_index = var_source_index.value();
    2719         112 :       Node* const target_index = var_target_index.value();
    2720             : 
    2721             :       // ...while sourceIndex < sourceLen
    2722         112 :       GotoIfNumberGreaterThanOrEqual(source_index, source_length, &done_loop);
    2723             : 
    2724             :       // a. Let P be ! ToString(sourceIndex).
    2725             :       // b. Let exists be ? HasProperty(source, P).
    2726             :       CSA_ASSERT(this,
    2727             :                  SmiGreaterThanOrEqual(CAST(source_index), SmiConstant(0)));
    2728             :       Node* const exists =
    2729         112 :           HasProperty(context, source, source_index, kHasProperty);
    2730             : 
    2731             :       // c. If exists is true, then
    2732         112 :       Label next(this);
    2733         112 :       GotoIfNot(IsTrue(exists), &next);
    2734             :       {
    2735             :         // i. Let element be ? Get(source, P).
    2736         112 :         Node* element = GetProperty(context, source, source_index);
    2737             : 
    2738             :         // ii. If mapperFunction is present, then
    2739         112 :         if (mapper_function != nullptr) {
    2740             :           CSA_ASSERT(this, Word32Or(IsUndefined(mapper_function),
    2741             :                                     IsCallable(mapper_function)));
    2742             :           DCHECK_NOT_NULL(this_arg);
    2743             : 
    2744             :           // 1. Set element to ? Call(mapperFunction, thisArg , « element,
    2745             :           //                          sourceIndex, source »).
    2746             :           element =
    2747             :               CallJS(CodeFactory::Call(isolate()), context, mapper_function,
    2748          56 :                      this_arg, element, source_index, source);
    2749             :         }
    2750             : 
    2751             :         // iii. Let shouldFlatten be false.
    2752         224 :         Label if_flatten_array(this), if_flatten_proxy(this, Label::kDeferred),
    2753         224 :             if_noflatten(this);
    2754             :         // iv. If depth > 0, then
    2755         112 :         GotoIfNumberGreaterThanOrEqual(SmiConstant(0), depth, &if_noflatten);
    2756             :         // 1. Set shouldFlatten to ? IsArray(element).
    2757         112 :         GotoIf(TaggedIsSmi(element), &if_noflatten);
    2758         112 :         GotoIf(IsJSArray(element), &if_flatten_array);
    2759         112 :         GotoIfNot(IsJSProxy(element), &if_noflatten);
    2760         224 :         Branch(IsTrue(CallRuntime(Runtime::kArrayIsArray, context, element)),
    2761         112 :                &if_flatten_proxy, &if_noflatten);
    2762             : 
    2763         112 :         BIND(&if_flatten_array);
    2764             :         {
    2765             :           CSA_ASSERT(this, IsJSArray(element));
    2766             : 
    2767             :           // 1. Let elementLen be ? ToLength(? Get(element, "length")).
    2768             :           Node* const element_length =
    2769         112 :               LoadObjectField(element, JSArray::kLengthOffset);
    2770             : 
    2771             :           // 2. Set targetIndex to ? FlattenIntoArray(target, element,
    2772             :           //                                          elementLen, targetIndex,
    2773             :           //                                          depth - 1).
    2774             :           var_target_index.Bind(
    2775             :               CallBuiltin(Builtins::kFlattenIntoArray, context, target, element,
    2776         112 :                           element_length, target_index, NumberDec(depth)));
    2777         112 :           Goto(&next);
    2778             :         }
    2779             : 
    2780         112 :         BIND(&if_flatten_proxy);
    2781             :         {
    2782             :           CSA_ASSERT(this, IsJSProxy(element));
    2783             : 
    2784             :           // 1. Let elementLen be ? ToLength(? Get(element, "length")).
    2785             :           Node* const element_length = ToLength_Inline(
    2786         112 :               context, GetProperty(context, element, LengthStringConstant()));
    2787             : 
    2788             :           // 2. Set targetIndex to ? FlattenIntoArray(target, element,
    2789             :           //                                          elementLen, targetIndex,
    2790             :           //                                          depth - 1).
    2791             :           var_target_index.Bind(
    2792             :               CallBuiltin(Builtins::kFlattenIntoArray, context, target, element,
    2793         112 :                           element_length, target_index, NumberDec(depth)));
    2794         112 :           Goto(&next);
    2795             :         }
    2796             : 
    2797         112 :         BIND(&if_noflatten);
    2798             :         {
    2799             :           // 1. If targetIndex >= 2^53-1, throw a TypeError exception.
    2800         112 :           Label throw_error(this, Label::kDeferred);
    2801             :           GotoIfNumberGreaterThanOrEqual(
    2802         112 :               target_index, NumberConstant(kMaxSafeInteger), &throw_error);
    2803             : 
    2804             :           // 2. Perform ? CreateDataPropertyOrThrow(target,
    2805             :           //                                        ! ToString(targetIndex),
    2806             :           //                                        element).
    2807             :           CallRuntime(Runtime::kCreateDataProperty, context, target,
    2808         112 :                       target_index, element);
    2809             : 
    2810             :           // 3. Increase targetIndex by 1.
    2811         112 :           var_target_index.Bind(NumberInc(target_index));
    2812         112 :           Goto(&next);
    2813             : 
    2814         112 :           BIND(&throw_error);
    2815             :           ThrowTypeError(context, MessageTemplate::kFlattenPastSafeLength,
    2816         112 :                          source_length, target_index);
    2817         112 :         }
    2818             :       }
    2819         112 :       BIND(&next);
    2820             : 
    2821             :       // d. Increase sourceIndex by 1.
    2822         112 :       var_source_index.Bind(NumberInc(source_index));
    2823         112 :       Goto(&loop);
    2824             :     }
    2825             : 
    2826         112 :     BIND(&done_loop);
    2827         224 :     return var_target_index.value();
    2828             :   }
    2829             : };
    2830             : 
    2831             : // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
    2832         560 : TF_BUILTIN(FlattenIntoArray, ArrayFlattenAssembler) {
    2833          56 :   Node* const context = Parameter(Descriptor::kContext);
    2834          56 :   Node* const target = Parameter(Descriptor::kTarget);
    2835          56 :   Node* const source = Parameter(Descriptor::kSource);
    2836          56 :   Node* const source_length = Parameter(Descriptor::kSourceLength);
    2837          56 :   Node* const start = Parameter(Descriptor::kStart);
    2838          56 :   Node* const depth = Parameter(Descriptor::kDepth);
    2839             : 
    2840             :   // FlattenIntoArray might get called recursively, check stack for overflow
    2841             :   // manually as it has stub linkage.
    2842          56 :   PerformStackCheck(CAST(context));
    2843             : 
    2844             :   Return(
    2845          56 :       FlattenIntoArray(context, target, source, source_length, start, depth));
    2846          56 : }
    2847             : 
    2848             : // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
    2849         672 : TF_BUILTIN(FlatMapIntoArray, ArrayFlattenAssembler) {
    2850          56 :   Node* const context = Parameter(Descriptor::kContext);
    2851          56 :   Node* const target = Parameter(Descriptor::kTarget);
    2852          56 :   Node* const source = Parameter(Descriptor::kSource);
    2853          56 :   Node* const source_length = Parameter(Descriptor::kSourceLength);
    2854          56 :   Node* const start = Parameter(Descriptor::kStart);
    2855          56 :   Node* const depth = Parameter(Descriptor::kDepth);
    2856          56 :   Node* const mapper_function = Parameter(Descriptor::kMapperFunction);
    2857          56 :   Node* const this_arg = Parameter(Descriptor::kThisArg);
    2858             : 
    2859             :   Return(FlattenIntoArray(context, target, source, source_length, start, depth,
    2860          56 :                           mapper_function, this_arg));
    2861          56 : }
    2862             : 
    2863             : // https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flat
    2864         336 : TF_BUILTIN(ArrayPrototypeFlat, CodeStubAssembler) {
    2865             :   TNode<IntPtrT> const argc =
    2866          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    2867          56 :   CodeStubArguments args(this, argc);
    2868          56 :   TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
    2869          56 :   TNode<Object> const receiver = args.GetReceiver();
    2870          56 :   TNode<Object> const depth = args.GetOptionalArgumentValue(0);
    2871             : 
    2872             :   // 1. Let O be ? ToObject(this value).
    2873          56 :   TNode<JSReceiver> const o = ToObject_Inline(context, receiver);
    2874             : 
    2875             :   // 2. Let sourceLen be ? ToLength(? Get(O, "length")).
    2876             :   TNode<Number> const source_length =
    2877          56 :       ToLength_Inline(context, GetProperty(context, o, LengthStringConstant()));
    2878             : 
    2879             :   // 3. Let depthNum be 1.
    2880          56 :   TVARIABLE(Number, var_depth_num, SmiConstant(1));
    2881             : 
    2882             :   // 4. If depth is not undefined, then
    2883         112 :   Label done(this);
    2884          56 :   GotoIf(IsUndefined(depth), &done);
    2885             :   {
    2886             :     // a. Set depthNum to ? ToInteger(depth).
    2887          56 :     var_depth_num = ToInteger_Inline(context, depth);
    2888          56 :     Goto(&done);
    2889             :   }
    2890          56 :   BIND(&done);
    2891             : 
    2892             :   // 5. Let A be ? ArraySpeciesCreate(O, 0).
    2893             :   TNode<JSReceiver> const constructor =
    2894          56 :       CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context, o));
    2895          56 :   Node* const a = Construct(context, constructor, SmiConstant(0));
    2896             : 
    2897             :   // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
    2898             :   CallBuiltin(Builtins::kFlattenIntoArray, context, a, o, source_length,
    2899          56 :               SmiConstant(0), var_depth_num.value());
    2900             : 
    2901             :   // 7. Return A.
    2902         112 :   args.PopAndReturn(a);
    2903          56 : }
    2904             : 
    2905             : // https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap
    2906         336 : TF_BUILTIN(ArrayPrototypeFlatMap, CodeStubAssembler) {
    2907             :   TNode<IntPtrT> const argc =
    2908          56 :       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
    2909          56 :   CodeStubArguments args(this, argc);
    2910          56 :   TNode<Context> const context = CAST(Parameter(Descriptor::kContext));
    2911          56 :   TNode<Object> const receiver = args.GetReceiver();
    2912          56 :   TNode<Object> const mapper_function = args.GetOptionalArgumentValue(0);
    2913             : 
    2914             :   // 1. Let O be ? ToObject(this value).
    2915          56 :   TNode<JSReceiver> const o = ToObject_Inline(context, receiver);
    2916             : 
    2917             :   // 2. Let sourceLen be ? ToLength(? Get(O, "length")).
    2918             :   TNode<Number> const source_length =
    2919          56 :       ToLength_Inline(context, GetProperty(context, o, LengthStringConstant()));
    2920             : 
    2921             :   // 3. If IsCallable(mapperFunction) is false, throw a TypeError exception.
    2922          56 :   Label if_not_callable(this, Label::kDeferred);
    2923          56 :   GotoIf(TaggedIsSmi(mapper_function), &if_not_callable);
    2924          56 :   GotoIfNot(IsCallable(CAST(mapper_function)), &if_not_callable);
    2925             : 
    2926             :   // 4. If thisArg is present, let T be thisArg; else let T be undefined.
    2927          56 :   TNode<Object> const t = args.GetOptionalArgumentValue(1);
    2928             : 
    2929             :   // 5. Let A be ? ArraySpeciesCreate(O, 0).
    2930             :   TNode<JSReceiver> const constructor =
    2931          56 :       CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context, o));
    2932          56 :   TNode<JSReceiver> const a = Construct(context, constructor, SmiConstant(0));
    2933             : 
    2934             :   // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
    2935             :   CallBuiltin(Builtins::kFlatMapIntoArray, context, a, o, source_length,
    2936          56 :               SmiConstant(0), SmiConstant(1), mapper_function, t);
    2937             : 
    2938             :   // 7. Return A.
    2939          56 :   args.PopAndReturn(a);
    2940             : 
    2941          56 :   BIND(&if_not_callable);
    2942          56 :   { ThrowTypeError(context, MessageTemplate::kMapperFunctionNonCallable); }
    2943          56 : }
    2944             : 
    2945         448 : TF_BUILTIN(ArrayConstructor, ArrayBuiltinsAssembler) {
    2946             :   // This is a trampoline to ArrayConstructorImpl which just adds
    2947             :   // allocation_site parameter value and sets new_target if necessary.
    2948          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    2949          56 :   TNode<JSFunction> function = CAST(Parameter(Descriptor::kTarget));
    2950          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
    2951             :   TNode<Int32T> argc =
    2952          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
    2953             : 
    2954             :   // If new_target is undefined, then this is the 'Call' case, so set new_target
    2955             :   // to function.
    2956         112 :   new_target =
    2957          56 :       SelectConstant<Object>(IsUndefined(new_target), function, new_target);
    2958             : 
    2959             :   // Run the native code for the Array function called as a normal function.
    2960          56 :   TNode<Object> no_allocation_site = UndefinedConstant();
    2961             :   TailCallBuiltin(Builtins::kArrayConstructorImpl, context, function,
    2962          56 :                   new_target, argc, no_allocation_site);
    2963          56 : }
    2964             : 
    2965         784 : void ArrayBuiltinsAssembler::TailCallArrayConstructorStub(
    2966             :     const Callable& callable, TNode<Context> context, TNode<JSFunction> target,
    2967             :     TNode<HeapObject> allocation_site_or_undefined, TNode<Int32T> argc) {
    2968         784 :   TNode<Code> code = HeapConstant(callable.code());
    2969             : 
    2970             :   // We are going to call here ArrayNoArgumentsConstructor or
    2971             :   // ArraySingleArgumentsConstructor which in addition to the register arguments
    2972             :   // also expect some number of arguments on the expression stack.
    2973             :   // Since
    2974             :   // 1) incoming JS arguments are still on the stack,
    2975             :   // 2) the ArrayNoArgumentsConstructor, ArraySingleArgumentsConstructor and
    2976             :   //    ArrayNArgumentsConstructor are defined so that the register arguments
    2977             :   //    are passed on the same registers,
    2978             :   // in order to be able to generate a tail call to those builtins we do the
    2979             :   // following trick here: we tail call to the constructor builtin using
    2980             :   // ArrayNArgumentsConstructorDescriptor, so the tail call instruction
    2981             :   // pops the current frame but leaves all the incoming JS arguments on the
    2982             :   // expression stack so that the target builtin can still find them where it
    2983             :   // expects.
    2984             :   TailCallStub(ArrayNArgumentsConstructorDescriptor{}, code, context, target,
    2985         784 :                allocation_site_or_undefined, argc);
    2986         784 : }
    2987             : 
    2988         112 : void ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument(
    2989             :     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
    2990             :     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
    2991         112 :   if (mode == DISABLE_ALLOCATION_SITES) {
    2992             :     Callable callable = CodeFactory::ArrayNoArgumentConstructor(
    2993          56 :         isolate(), GetInitialFastElementsKind(), mode);
    2994             : 
    2995          56 :     TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(),
    2996          56 :                                  argc);
    2997             :   } else {
    2998             :     DCHECK_EQ(mode, DONT_OVERRIDE);
    2999          56 :     TNode<Int32T> elements_kind = LoadElementsKind(allocation_site);
    3000             : 
    3001             :     // TODO(ishell): Compute the builtin index dynamically instead of
    3002             :     // iterating over all expected elements kinds.
    3003             :     int last_index =
    3004          56 :         GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
    3005         392 :     for (int i = 0; i <= last_index; ++i) {
    3006         336 :       Label next(this);
    3007         336 :       ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
    3008         336 :       GotoIfNot(Word32Equal(elements_kind, Int32Constant(kind)), &next);
    3009             : 
    3010             :       Callable callable =
    3011         672 :           CodeFactory::ArrayNoArgumentConstructor(isolate(), kind, mode);
    3012             : 
    3013             :       TailCallArrayConstructorStub(callable, context, target, allocation_site,
    3014         336 :                                    argc);
    3015             : 
    3016         336 :       BIND(&next);
    3017         336 :     }
    3018             : 
    3019             :     // If we reached this point there is a problem.
    3020          56 :     Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
    3021             :   }
    3022         112 : }
    3023             : 
    3024         112 : void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument(
    3025             :     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
    3026             :     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
    3027         112 :   if (mode == DISABLE_ALLOCATION_SITES) {
    3028          56 :     ElementsKind initial = GetInitialFastElementsKind();
    3029          56 :     ElementsKind holey_initial = GetHoleyElementsKind(initial);
    3030             :     Callable callable = CodeFactory::ArraySingleArgumentConstructor(
    3031          56 :         isolate(), holey_initial, mode);
    3032             : 
    3033          56 :     TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(),
    3034          56 :                                  argc);
    3035             :   } else {
    3036             :     DCHECK_EQ(mode, DONT_OVERRIDE);
    3037          56 :     TNode<Smi> transition_info = LoadTransitionInfo(allocation_site);
    3038             : 
    3039             :     // Least significant bit in fast array elements kind means holeyness.
    3040             :     STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
    3041             :     STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
    3042             :     STATIC_ASSERT(PACKED_ELEMENTS == 2);
    3043             :     STATIC_ASSERT(HOLEY_ELEMENTS == 3);
    3044             :     STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
    3045             :     STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
    3046             : 
    3047          56 :     Label normal_sequence(this);
    3048         112 :     TVARIABLE(Int32T, var_elements_kind,
    3049             :               Signed(DecodeWord32<AllocationSite::ElementsKindBits>(
    3050             :                   SmiToInt32(transition_info))));
    3051             :     // Is the low bit set? If so, we are holey and that is good.
    3052             :     int fast_elements_kind_holey_mask =
    3053          56 :         AllocationSite::ElementsKindBits::encode(static_cast<ElementsKind>(1));
    3054         112 :     GotoIf(IsSetSmi(transition_info, fast_elements_kind_holey_mask),
    3055          56 :            &normal_sequence);
    3056             :     {
    3057             :       // Make elements kind holey and update elements kind in the type info.
    3058         112 :       var_elements_kind =
    3059         112 :           Signed(Word32Or(var_elements_kind.value(), Int32Constant(1)));
    3060             :       StoreObjectFieldNoWriteBarrier(
    3061             :           allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset,
    3062          56 :           SmiOr(transition_info, SmiConstant(fast_elements_kind_holey_mask)));
    3063          56 :       Goto(&normal_sequence);
    3064             :     }
    3065          56 :     BIND(&normal_sequence);
    3066             : 
    3067             :     // TODO(ishell): Compute the builtin index dynamically instead of
    3068             :     // iterating over all expected elements kinds.
    3069             :     // TODO(ishell): Given that the code above ensures that the elements kind
    3070             :     // is holey we can skip checking with non-holey elements kinds.
    3071             :     int last_index =
    3072          56 :         GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
    3073         392 :     for (int i = 0; i <= last_index; ++i) {
    3074         336 :       Label next(this);
    3075         336 :       ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
    3076         672 :       GotoIfNot(Word32Equal(var_elements_kind.value(), Int32Constant(kind)),
    3077         336 :                 &next);
    3078             : 
    3079             :       Callable callable =
    3080         672 :           CodeFactory::ArraySingleArgumentConstructor(isolate(), kind, mode);
    3081             : 
    3082             :       TailCallArrayConstructorStub(callable, context, target, allocation_site,
    3083         336 :                                    argc);
    3084             : 
    3085         336 :       BIND(&next);
    3086         336 :     }
    3087             : 
    3088             :     // If we reached this point there is a problem.
    3089         112 :     Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
    3090             :   }
    3091         112 : }
    3092             : 
    3093         112 : void ArrayBuiltinsAssembler::GenerateDispatchToArrayStub(
    3094             :     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
    3095             :     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
    3096         224 :   Label check_one_case(this), fallthrough(this);
    3097         112 :   GotoIfNot(Word32Equal(argc, Int32Constant(0)), &check_one_case);
    3098         112 :   CreateArrayDispatchNoArgument(context, target, argc, mode, allocation_site);
    3099             : 
    3100         112 :   BIND(&check_one_case);
    3101         112 :   GotoIfNot(Word32Equal(argc, Int32Constant(1)), &fallthrough);
    3102             :   CreateArrayDispatchSingleArgument(context, target, argc, mode,
    3103         112 :                                     allocation_site);
    3104             : 
    3105         224 :   BIND(&fallthrough);
    3106         112 : }
    3107             : 
    3108         448 : TF_BUILTIN(ArrayConstructorImpl, ArrayBuiltinsAssembler) {
    3109          56 :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
    3110          56 :   TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
    3111             :   TNode<Int32T> argc =
    3112          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
    3113             :   TNode<HeapObject> maybe_allocation_site =
    3114          56 :       CAST(Parameter(Descriptor::kAllocationSite));
    3115             : 
    3116             :   // Initial map for the builtin Array functions should be Map.
    3117             :   CSA_ASSERT(this, IsMap(CAST(LoadObjectField(
    3118             :                        target, JSFunction::kPrototypeOrInitialMapOffset))));
    3119             : 
    3120             :   // We should either have undefined or a valid AllocationSite
    3121             :   CSA_ASSERT(this, Word32Or(IsUndefined(maybe_allocation_site),
    3122             :                             IsAllocationSite(maybe_allocation_site)));
    3123             : 
    3124             :   // "Enter" the context of the Array function.
    3125             :   TNode<Context> context =
    3126          56 :       CAST(LoadObjectField(target, JSFunction::kContextOffset));
    3127             : 
    3128          56 :   Label runtime(this, Label::kDeferred);
    3129          56 :   GotoIf(WordNotEqual(target, new_target), &runtime);
    3130             : 
    3131         112 :   Label no_info(this);
    3132             :   // If the feedback vector is the undefined value call an array constructor
    3133             :   // that doesn't use AllocationSites.
    3134          56 :   GotoIf(IsUndefined(maybe_allocation_site), &no_info);
    3135             : 
    3136             :   GenerateDispatchToArrayStub(context, target, argc, DONT_OVERRIDE,
    3137          56 :                               CAST(maybe_allocation_site));
    3138          56 :   Goto(&runtime);
    3139             : 
    3140          56 :   BIND(&no_info);
    3141          56 :   GenerateDispatchToArrayStub(context, target, argc, DISABLE_ALLOCATION_SITES);
    3142          56 :   Goto(&runtime);
    3143             : 
    3144          56 :   BIND(&runtime);
    3145             :   GenerateArrayNArgumentsConstructor(context, target, new_target, argc,
    3146         112 :                                      maybe_allocation_site);
    3147          56 : }
    3148             : 
    3149         448 : void ArrayBuiltinsAssembler::GenerateConstructor(
    3150             :     Node* context, Node* array_function, Node* array_map, Node* array_size,
    3151             :     Node* allocation_site, ElementsKind elements_kind,
    3152             :     AllocationSiteMode mode) {
    3153         448 :   Label ok(this);
    3154         896 :   Label smi_size(this);
    3155         896 :   Label small_smi_size(this);
    3156         896 :   Label call_runtime(this, Label::kDeferred);
    3157             : 
    3158         448 :   Branch(TaggedIsSmi(array_size), &smi_size, &call_runtime);
    3159             : 
    3160         448 :   BIND(&smi_size);
    3161             : 
    3162         448 :   if (IsFastPackedElementsKind(elements_kind)) {
    3163         224 :     Label abort(this, Label::kDeferred);
    3164         224 :     Branch(SmiEqual(CAST(array_size), SmiConstant(0)), &small_smi_size, &abort);
    3165             : 
    3166         224 :     BIND(&abort);
    3167         224 :     Node* reason = SmiConstant(AbortReason::kAllocatingNonEmptyPackedArray);
    3168         224 :     TailCallRuntime(Runtime::kAbort, context, reason);
    3169             :   } else {
    3170             :     int element_size =
    3171         224 :         IsDoubleElementsKind(elements_kind) ? kDoubleSize : kTaggedSize;
    3172             :     int max_fast_elements =
    3173             :         (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize -
    3174             :          AllocationMemento::kSize) /
    3175         224 :         element_size;
    3176         448 :     Branch(SmiAboveOrEqual(CAST(array_size), SmiConstant(max_fast_elements)),
    3177         224 :            &call_runtime, &small_smi_size);
    3178             :   }
    3179             : 
    3180         448 :   BIND(&small_smi_size);
    3181             :   {
    3182             :     TNode<JSArray> array = AllocateJSArray(
    3183         896 :         elements_kind, CAST(array_map), array_size, CAST(array_size),
    3184             :         mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site,
    3185        1344 :         CodeStubAssembler::SMI_PARAMETERS);
    3186         448 :     Return(array);
    3187             :   }
    3188             : 
    3189         448 :   BIND(&call_runtime);
    3190             :   {
    3191             :     TailCallRuntime(Runtime::kNewArray, context, array_function, array_size,
    3192         448 :                     array_function, allocation_site);
    3193         448 :   }
    3194         448 : }
    3195             : 
    3196         448 : void ArrayBuiltinsAssembler::GenerateArrayNoArgumentConstructor(
    3197             :     ElementsKind kind, AllocationSiteOverrideMode mode) {
    3198             :   typedef ArrayNoArgumentConstructorDescriptor Descriptor;
    3199             :   Node* native_context = LoadObjectField(Parameter(Descriptor::kFunction),
    3200         448 :                                          JSFunction::kContextOffset);
    3201             :   bool track_allocation_site =
    3202         448 :       AllocationSite::ShouldTrack(kind) && mode != DISABLE_ALLOCATION_SITES;
    3203             :   Node* allocation_site =
    3204         448 :       track_allocation_site ? Parameter(Descriptor::kAllocationSite) : nullptr;
    3205         448 :   TNode<Map> array_map = LoadJSArrayElementsMap(kind, native_context);
    3206             :   TNode<JSArray> array = AllocateJSArray(
    3207         448 :       kind, array_map, IntPtrConstant(JSArray::kPreallocatedArrayElements),
    3208         896 :       SmiConstant(0), allocation_site);
    3209         448 :   Return(array);
    3210         448 : }
    3211             : 
    3212         448 : void ArrayBuiltinsAssembler::GenerateArraySingleArgumentConstructor(
    3213             :     ElementsKind kind, AllocationSiteOverrideMode mode) {
    3214             :   typedef ArraySingleArgumentConstructorDescriptor Descriptor;
    3215         448 :   Node* context = Parameter(Descriptor::kContext);
    3216         448 :   Node* function = Parameter(Descriptor::kFunction);
    3217         448 :   Node* native_context = LoadObjectField(function, JSFunction::kContextOffset);
    3218         448 :   Node* array_map = LoadJSArrayElementsMap(kind, native_context);
    3219             : 
    3220         448 :   AllocationSiteMode allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
    3221         448 :   if (mode == DONT_OVERRIDE) {
    3222         112 :     allocation_site_mode = AllocationSite::ShouldTrack(kind)
    3223             :                                ? TRACK_ALLOCATION_SITE
    3224         112 :                                : DONT_TRACK_ALLOCATION_SITE;
    3225             :   }
    3226             : 
    3227         448 :   Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
    3228         448 :   Node* allocation_site = Parameter(Descriptor::kAllocationSite);
    3229             : 
    3230             :   GenerateConstructor(context, function, array_map, array_size, allocation_site,
    3231         448 :                       kind, allocation_site_mode);
    3232         448 : }
    3233             : 
    3234         112 : void ArrayBuiltinsAssembler::GenerateArrayNArgumentsConstructor(
    3235             :     TNode<Context> context, TNode<JSFunction> target, TNode<Object> new_target,
    3236             :     TNode<Int32T> argc, TNode<HeapObject> maybe_allocation_site) {
    3237             :   // Replace incoming JS receiver argument with the target.
    3238             :   // TODO(ishell): Avoid replacing the target on the stack and just add it
    3239             :   // as another additional parameter for Runtime::kNewArray.
    3240         112 :   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
    3241         112 :   args.SetReceiver(target);
    3242             : 
    3243             :   // Adjust arguments count for the runtime call: +1 for implicit receiver
    3244             :   // and +2 for new_target and maybe_allocation_site.
    3245         112 :   argc = Int32Add(argc, Int32Constant(3));
    3246             :   TailCallRuntime(Runtime::kNewArray, argc, context, new_target,
    3247         112 :                   maybe_allocation_site);
    3248         112 : }
    3249             : 
    3250         448 : TF_BUILTIN(ArrayNArgumentsConstructor, ArrayBuiltinsAssembler) {
    3251          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    3252          56 :   TNode<JSFunction> target = CAST(Parameter(Descriptor::kFunction));
    3253             :   TNode<Int32T> argc =
    3254          56 :       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
    3255             :   TNode<HeapObject> maybe_allocation_site =
    3256          56 :       CAST(Parameter(Descriptor::kAllocationSite));
    3257             : 
    3258             :   GenerateArrayNArgumentsConstructor(context, target, target, argc,
    3259          56 :                                      maybe_allocation_site);
    3260          56 : }
    3261             : 
    3262             : #define GENERATE_ARRAY_CTOR(name, kind_camel, kind_caps, mode_camel, \
    3263             :                             mode_caps)                               \
    3264             :   TF_BUILTIN(Array##name##Constructor_##kind_camel##_##mode_camel,   \
    3265             :              ArrayBuiltinsAssembler) {                               \
    3266             :     GenerateArray##name##Constructor(kind_caps, mode_caps);          \
    3267             :   }
    3268             : 
    3269             : // The ArrayNoArgumentConstructor builtin family.
    3270         224 : GENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS, DontOverride,
    3271             :                     DONT_OVERRIDE)
    3272         224 : GENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride,
    3273             :                     DONT_OVERRIDE)
    3274         224 : GENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS,
    3275             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3276         224 : GENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS,
    3277             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3278         224 : GENERATE_ARRAY_CTOR(NoArgument, Packed, PACKED_ELEMENTS, DisableAllocationSites,
    3279             :                     DISABLE_ALLOCATION_SITES)
    3280         224 : GENERATE_ARRAY_CTOR(NoArgument, Holey, HOLEY_ELEMENTS, DisableAllocationSites,
    3281             :                     DISABLE_ALLOCATION_SITES)
    3282         224 : GENERATE_ARRAY_CTOR(NoArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS,
    3283             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3284         224 : GENERATE_ARRAY_CTOR(NoArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS,
    3285             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3286             : 
    3287             : // The ArraySingleArgumentConstructor builtin family.
    3288         224 : GENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS,
    3289             :                     DontOverride, DONT_OVERRIDE)
    3290         224 : GENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride,
    3291             :                     DONT_OVERRIDE)
    3292         224 : GENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS,
    3293             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3294         224 : GENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS,
    3295             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3296         224 : GENERATE_ARRAY_CTOR(SingleArgument, Packed, PACKED_ELEMENTS,
    3297             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3298         224 : GENERATE_ARRAY_CTOR(SingleArgument, Holey, HOLEY_ELEMENTS,
    3299             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3300         224 : GENERATE_ARRAY_CTOR(SingleArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS,
    3301             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3302         224 : GENERATE_ARRAY_CTOR(SingleArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS,
    3303             :                     DisableAllocationSites, DISABLE_ALLOCATION_SITES)
    3304             : 
    3305             : #undef GENERATE_ARRAY_CTOR
    3306             : 
    3307         280 : TF_BUILTIN(InternalArrayNoArgumentConstructor_Packed, ArrayBuiltinsAssembler) {
    3308             :   typedef ArrayNoArgumentConstructorDescriptor Descriptor;
    3309             :   TNode<Map> array_map =
    3310          56 :       CAST(LoadObjectField(Parameter(Descriptor::kFunction),
    3311             :                            JSFunction::kPrototypeOrInitialMapOffset));
    3312             :   TNode<JSArray> array = AllocateJSArray(
    3313             :       PACKED_ELEMENTS, array_map,
    3314          56 :       IntPtrConstant(JSArray::kPreallocatedArrayElements), SmiConstant(0));
    3315          56 :   Return(array);
    3316          56 : }
    3317             : 
    3318             : }  // namespace internal
    3319       86739 : }  // namespace v8

Generated by: LCOV version 1.10