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/arguments-inl.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 using Node = compiler::Node;
21 
ArrayBuiltinsAssembler(compiler::CodeAssemblerState * state)22 ArrayBuiltinsAssembler::ArrayBuiltinsAssembler(
23     compiler::CodeAssemblerState* state)
24     : BaseBuiltinsFromDSLAssembler(state),
25       k_(this, MachineRepresentation::kTagged),
26       a_(this, MachineRepresentation::kTagged),
27       to_(this, MachineRepresentation::kTagged, SmiConstant(0)),
28       fully_spec_compliant_(this, {&k_, &a_, &to_}) {}
29 
FindResultGenerator()30 void ArrayBuiltinsAssembler::FindResultGenerator() {
31   a_.Bind(UndefinedConstant());
32 }
33 
FindProcessor(Node * k_value,Node * k)34 Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
35   Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
36                        this_arg(), k_value, k, o());
37   Label false_continue(this), return_true(this);
38   BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
39   BIND(&return_true);
40   ReturnFromBuiltin(k_value);
41   BIND(&false_continue);
42   return a();
43   }
44 
FindIndexResultGenerator()45   void ArrayBuiltinsAssembler::FindIndexResultGenerator() {
46     a_.Bind(SmiConstant(-1));
47   }
48 
FindIndexProcessor(Node * k_value,Node * k)49   Node* ArrayBuiltinsAssembler::FindIndexProcessor(Node* k_value, Node* k) {
50     Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
51                          this_arg(), k_value, k, o());
52     Label false_continue(this), return_true(this);
53     BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
54     BIND(&return_true);
55     ReturnFromBuiltin(k);
56     BIND(&false_continue);
57     return a();
58   }
59 
ForEachResultGenerator()60   void ArrayBuiltinsAssembler::ForEachResultGenerator() {
61     a_.Bind(UndefinedConstant());
62   }
63 
ForEachProcessor(Node * k_value,Node * k)64   Node* ArrayBuiltinsAssembler::ForEachProcessor(Node* k_value, Node* k) {
65     CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(),
66            k_value, k, o());
67     return a();
68   }
69 
SomeResultGenerator()70   void ArrayBuiltinsAssembler::SomeResultGenerator() {
71     a_.Bind(FalseConstant());
72   }
73 
SomeProcessor(Node * k_value,Node * k)74   Node* ArrayBuiltinsAssembler::SomeProcessor(Node* k_value, Node* k) {
75     Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
76                          this_arg(), k_value, k, o());
77     Label false_continue(this), return_true(this);
78     BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
79     BIND(&return_true);
80     ReturnFromBuiltin(TrueConstant());
81     BIND(&false_continue);
82     return a();
83   }
84 
EveryResultGenerator()85   void ArrayBuiltinsAssembler::EveryResultGenerator() {
86     a_.Bind(TrueConstant());
87   }
88 
EveryProcessor(Node * k_value,Node * k)89   Node* ArrayBuiltinsAssembler::EveryProcessor(Node* k_value, Node* k) {
90     Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
91                          this_arg(), k_value, k, o());
92     Label true_continue(this), return_false(this);
93     BranchIfToBooleanIsTrue(value, &true_continue, &return_false);
94     BIND(&return_false);
95     ReturnFromBuiltin(FalseConstant());
96     BIND(&true_continue);
97     return a();
98   }
99 
ReduceResultGenerator()100   void ArrayBuiltinsAssembler::ReduceResultGenerator() {
101     return a_.Bind(this_arg());
102   }
103 
ReduceProcessor(Node * k_value,Node * k)104   Node* ArrayBuiltinsAssembler::ReduceProcessor(Node* k_value, Node* k) {
105     VARIABLE(result, MachineRepresentation::kTagged);
106     Label done(this, {&result}), initial(this);
107     GotoIf(WordEqual(a(), TheHoleConstant()), &initial);
108     result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
109                        UndefinedConstant(), a(), k_value, k, o()));
110     Goto(&done);
111 
112     BIND(&initial);
113     result.Bind(k_value);
114     Goto(&done);
115 
116     BIND(&done);
117     return result.value();
118   }
119 
ReducePostLoopAction()120   void ArrayBuiltinsAssembler::ReducePostLoopAction() {
121     Label ok(this);
122     GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok);
123     ThrowTypeError(context(), MessageTemplate::kReduceNoInitial);
124     BIND(&ok);
125   }
126 
FilterResultGenerator()127   void ArrayBuiltinsAssembler::FilterResultGenerator() {
128     // 7. Let A be ArraySpeciesCreate(O, 0).
129     // This version of ArraySpeciesCreate will create with the correct
130     // ElementsKind in the fast case.
131     GenerateArraySpeciesCreate();
132   }
133 
FilterProcessor(Node * k_value,Node * k)134   Node* ArrayBuiltinsAssembler::FilterProcessor(Node* k_value, Node* k) {
135     // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)).
136     Node* selected = CallJS(CodeFactory::Call(isolate()), context(),
137                             callbackfn(), this_arg(), k_value, k, o());
138     Label true_continue(this, &to_), false_continue(this);
139     BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue);
140     BIND(&true_continue);
141     // iii. If selected is true, then...
142     {
143       Label after_work(this, &to_);
144       Node* kind = nullptr;
145 
146       // If a() is a JSArray, we can have a fast path.
147       Label fast(this);
148       Label runtime(this);
149       Label object_push_pre(this), object_push(this), double_push(this);
150       BranchIfFastJSArray(a(), context(), &fast, &runtime);
151 
152       BIND(&fast);
153       {
154         GotoIf(WordNotEqual(LoadJSArrayLength(a()), to_.value()), &runtime);
155         kind = EnsureArrayPushable(LoadMap(a()), &runtime);
156         GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
157                &object_push_pre);
158 
159         BuildAppendJSArray(HOLEY_SMI_ELEMENTS, a(), k_value, &runtime);
160         Goto(&after_work);
161       }
162 
163       BIND(&object_push_pre);
164       {
165         Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push,
166                &object_push);
167       }
168 
169       BIND(&object_push);
170       {
171         BuildAppendJSArray(HOLEY_ELEMENTS, a(), k_value, &runtime);
172         Goto(&after_work);
173       }
174 
175       BIND(&double_push);
176       {
177         BuildAppendJSArray(HOLEY_DOUBLE_ELEMENTS, a(), k_value, &runtime);
178         Goto(&after_work);
179       }
180 
181       BIND(&runtime);
182       {
183         // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
184         CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(),
185                     k_value);
186         Goto(&after_work);
187       }
188 
189       BIND(&after_work);
190       {
191         // 2. Increase to by 1.
192         to_.Bind(NumberInc(to_.value()));
193         Goto(&false_continue);
194       }
195     }
196     BIND(&false_continue);
197     return a();
198   }
199 
MapResultGenerator()200   void ArrayBuiltinsAssembler::MapResultGenerator() {
201     GenerateArraySpeciesCreate(len_);
202   }
203 
TypedArrayMapResultGenerator()204   void ArrayBuiltinsAssembler::TypedArrayMapResultGenerator() {
205     // 6. Let A be ? TypedArraySpeciesCreate(O, len).
206     TNode<JSTypedArray> original_array = CAST(o());
207     TNode<Smi> length = CAST(len_);
208     const char* method_name = "%TypedArray%.prototype.map";
209 
210     TypedArrayBuiltinsAssembler typedarray_asm(state());
211     TNode<JSTypedArray> a = typedarray_asm.SpeciesCreateByLength(
212         context(), original_array, length, method_name);
213     // In the Spec and our current implementation, the length check is already
214     // performed in TypedArraySpeciesCreate.
215     CSA_ASSERT(this, SmiLessThanOrEqual(CAST(len_), LoadTypedArrayLength(a)));
216     fast_typed_array_target_ =
217         Word32Equal(LoadInstanceType(LoadElements(original_array)),
218                     LoadInstanceType(LoadElements(a)));
219     a_.Bind(a);
220   }
221 
SpecCompliantMapProcessor(Node * k_value,Node * k)222   Node* ArrayBuiltinsAssembler::SpecCompliantMapProcessor(Node* k_value,
223                                                           Node* k) {
224     //  i. Let kValue be ? Get(O, Pk). Performed by the caller of
225     //  SpecCompliantMapProcessor.
226     // ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
227     Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
228                                 callbackfn(), this_arg(), k_value, k, o());
229 
230     // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
231     CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mapped_value);
232     return a();
233   }
234 
FastMapProcessor(Node * k_value,Node * k)235   Node* ArrayBuiltinsAssembler::FastMapProcessor(Node* k_value, Node* k) {
236     //  i. Let kValue be ? Get(O, Pk). Performed by the caller of
237     //  FastMapProcessor.
238     // ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
239     Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
240                                 callbackfn(), this_arg(), k_value, k, o());
241 
242     // mode is SMI_PARAMETERS because k has tagged representation.
243     ParameterMode mode = SMI_PARAMETERS;
244     Label runtime(this), finished(this);
245     Label transition_pre(this), transition_smi_fast(this),
246         transition_smi_double(this);
247     Label array_not_smi(this), array_fast(this), array_double(this);
248 
249     TNode<Int32T> kind = LoadElementsKind(a());
250     Node* elements = LoadElements(a());
251     GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS), &array_not_smi);
252     TryStoreArrayElement(HOLEY_SMI_ELEMENTS, mode, &transition_pre, elements, k,
253                          mapped_value);
254     Goto(&finished);
255 
256     BIND(&transition_pre);
257     {
258       // array is smi. Value is either tagged or a heap number.
259       CSA_ASSERT(this, TaggedIsNotSmi(mapped_value));
260       GotoIf(IsHeapNumberMap(LoadMap(mapped_value)), &transition_smi_double);
261       Goto(&transition_smi_fast);
262     }
263 
264     BIND(&array_not_smi);
265     {
266       Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &array_double,
267              &array_fast);
268     }
269 
270     BIND(&transition_smi_fast);
271     {
272       // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
273       Node* const native_context = LoadNativeContext(context());
274       Node* const fast_map = LoadContextElement(
275           native_context, Context::JS_ARRAY_HOLEY_ELEMENTS_MAP_INDEX);
276 
277       // Since this transition is only a map change, just do it right here.
278       // Since a() doesn't have an allocation site, it's safe to do the
279       // map store directly, otherwise I'd call TransitionElementsKind().
280       StoreMap(a(), fast_map);
281       Goto(&array_fast);
282     }
283 
284     BIND(&array_fast);
285     {
286       TryStoreArrayElement(HOLEY_ELEMENTS, mode, &runtime, elements, k,
287                            mapped_value);
288       Goto(&finished);
289     }
290 
291     BIND(&transition_smi_double);
292     {
293       // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
294       Node* const native_context = LoadNativeContext(context());
295       Node* const double_map = LoadContextElement(
296           native_context, Context::JS_ARRAY_HOLEY_DOUBLE_ELEMENTS_MAP_INDEX);
297 
298       const ElementsKind kFromKind = HOLEY_SMI_ELEMENTS;
299       const ElementsKind kToKind = HOLEY_DOUBLE_ELEMENTS;
300       const bool kIsJSArray = true;
301 
302       Label transition_in_runtime(this, Label::kDeferred);
303       TransitionElementsKind(a(), double_map, kFromKind, kToKind, kIsJSArray,
304                              &transition_in_runtime);
305       Goto(&array_double);
306 
307       BIND(&transition_in_runtime);
308       CallRuntime(Runtime::kTransitionElementsKind, context(), a(), double_map);
309       Goto(&array_double);
310     }
311 
312     BIND(&array_double);
313     {
314       // TODO(mvstanton): If we use a variable for elements and bind it
315       // appropriately, we can avoid an extra load of elements by binding the
316       // value only after a transition from smi to double.
317       elements = LoadElements(a());
318       // If the mapped_value isn't a number, this will bail out to the runtime
319       // to make the transition.
320       TryStoreArrayElement(HOLEY_DOUBLE_ELEMENTS, mode, &runtime, elements, k,
321                            mapped_value);
322       Goto(&finished);
323     }
324 
325     BIND(&runtime);
326     {
327       // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
328       CallRuntime(Runtime::kCreateDataProperty, context(), a(), k,
329                   mapped_value);
330       Goto(&finished);
331     }
332 
333     BIND(&finished);
334     return a();
335   }
336 
337   // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map.
TypedArrayMapProcessor(Node * k_value,Node * k)338   Node* ArrayBuiltinsAssembler::TypedArrayMapProcessor(Node* k_value, Node* k) {
339     // 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »).
340     Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
341                                 callbackfn(), this_arg(), k_value, k, o());
342     Label fast(this), slow(this), done(this), detached(this, Label::kDeferred);
343 
344     // 8. d. Perform ? Set(A, Pk, mapped_value, true).
345     // Since we know that A is a TypedArray, this always ends up in
346     // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then
347     // tc39.github.io/ecma262/#sec-integerindexedelementset .
348     Branch(fast_typed_array_target_, &fast, &slow);
349 
350     BIND(&fast);
351     // #sec-integerindexedelementset
352     // 5. If arrayTypeName is "BigUint64Array" or "BigInt64Array", let
353     // numValue be ? ToBigInt(v).
354     // 6. Otherwise, let numValue be ? ToNumber(value).
355     Node* num_value;
356     if (source_elements_kind_ == BIGINT64_ELEMENTS ||
357         source_elements_kind_ == BIGUINT64_ELEMENTS) {
358       num_value = ToBigInt(context(), mapped_value);
359     } else {
360       num_value = ToNumber_Inline(context(), mapped_value);
361     }
362     // The only way how this can bailout is because of a detached buffer.
363     EmitElementStore(a(), k, num_value, false, source_elements_kind_,
364                      KeyedAccessStoreMode::STANDARD_STORE, &detached,
365                      context());
366     Goto(&done);
367 
368     BIND(&slow);
369     SetPropertyStrict(context(), CAST(a()), CAST(k), CAST(mapped_value));
370     Goto(&done);
371 
372     BIND(&detached);
373     // tc39.github.io/ecma262/#sec-integerindexedelementset
374     // 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
375     ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
376 
377     BIND(&done);
378     return a();
379   }
380 
NullPostLoopAction()381   void ArrayBuiltinsAssembler::NullPostLoopAction() {}
382 
FillFixedArrayWithSmiZero(TNode<FixedArray> array,TNode<Smi> smi_length)383   void ArrayBuiltinsAssembler::FillFixedArrayWithSmiZero(
384       TNode<FixedArray> array, TNode<Smi> smi_length) {
385     CSA_ASSERT(this, Word32BinaryNot(IsFixedDoubleArray(array)));
386 
387     TNode<IntPtrT> length = SmiToIntPtr(smi_length);
388     TNode<WordT> byte_length = TimesPointerSize(length);
389     CSA_ASSERT(this, UintPtrLessThan(length, byte_length));
390 
391     static const int32_t fa_base_data_offset =
392         FixedArray::kHeaderSize - kHeapObjectTag;
393     TNode<IntPtrT> backing_store = IntPtrAdd(
394         BitcastTaggedToWord(array), IntPtrConstant(fa_base_data_offset));
395 
396     // Call out to memset to perform initialization.
397     TNode<ExternalReference> memset =
398         ExternalConstant(ExternalReference::libc_memset_function());
399     STATIC_ASSERT(kSizetSize == kIntptrSize);
400     CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
401                    MachineType::IntPtr(), MachineType::UintPtr(), memset,
402                    backing_store, IntPtrConstant(0), byte_length);
403   }
404 
ReturnFromBuiltin(Node * value)405   void ArrayBuiltinsAssembler::ReturnFromBuiltin(Node* value) {
406     if (argc_ == nullptr) {
407       Return(value);
408     } else {
409       // argc_ doesn't include the receiver, so it has to be added back in
410       // manually.
411       PopAndReturn(IntPtrAdd(argc_, IntPtrConstant(1)), value);
412     }
413   }
414 
InitIteratingArrayBuiltinBody(TNode<Context> context,TNode<Object> receiver,Node * callbackfn,Node * this_arg,TNode<IntPtrT> argc)415   void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinBody(
416       TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
417       Node* this_arg, TNode<IntPtrT> argc) {
418     context_ = context;
419     receiver_ = receiver;
420     callbackfn_ = callbackfn;
421     this_arg_ = this_arg;
422     argc_ = argc;
423   }
424 
GenerateIteratingArrayBuiltinBody(const char * name,const BuiltinResultGenerator & generator,const CallResultProcessor & processor,const PostLoopAction & action,const Callable & slow_case_continuation,MissingPropertyMode missing_property_mode,ForEachDirection direction)425   void ArrayBuiltinsAssembler::GenerateIteratingArrayBuiltinBody(
426       const char* name, const BuiltinResultGenerator& generator,
427       const CallResultProcessor& processor, const PostLoopAction& action,
428       const Callable& slow_case_continuation,
429       MissingPropertyMode missing_property_mode, ForEachDirection direction) {
430     Label non_array(this), array_changes(this, {&k_, &a_, &to_});
431 
432     // TODO(danno): Seriously? Do we really need to throw the exact error
433     // message on null and undefined so that the webkit tests pass?
434     Label throw_null_undefined_exception(this, Label::kDeferred);
435     GotoIf(IsNullOrUndefined(receiver()), &throw_null_undefined_exception);
436 
437     // By the book: taken directly from the ECMAScript 2015 specification
438 
439     // 1. Let O be ToObject(this value).
440     // 2. ReturnIfAbrupt(O)
441     o_ = ToObject_Inline(context(), receiver());
442 
443     // 3. Let len be ToLength(Get(O, "length")).
444     // 4. ReturnIfAbrupt(len).
445     TVARIABLE(Number, merged_length);
446     Label has_length(this, &merged_length), not_js_array(this);
447     GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), &not_js_array);
448     merged_length = LoadJSArrayLength(CAST(o()));
449     Goto(&has_length);
450 
451     BIND(&not_js_array);
452     {
453       Node* len_property =
454           GetProperty(context(), o(), isolate()->factory()->length_string());
455       merged_length = ToLength_Inline(context(), len_property);
456       Goto(&has_length);
457     }
458     BIND(&has_length);
459     {
460       len_ = merged_length.value();
461 
462       // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
463       Label type_exception(this, Label::kDeferred);
464       Label done(this);
465       GotoIf(TaggedIsSmi(callbackfn()), &type_exception);
466       Branch(IsCallableMap(LoadMap(callbackfn())), &done, &type_exception);
467 
468       BIND(&throw_null_undefined_exception);
469       ThrowTypeError(context(), MessageTemplate::kCalledOnNullOrUndefined,
470                      name);
471 
472       BIND(&type_exception);
473       ThrowTypeError(context(), MessageTemplate::kCalledNonCallable,
474                      callbackfn());
475 
476       BIND(&done);
477     }
478 
479     // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
480     // [Already done by the arguments adapter]
481 
482     if (direction == ForEachDirection::kForward) {
483       // 7. Let k be 0.
484       k_.Bind(SmiConstant(0));
485     } else {
486       k_.Bind(NumberDec(len()));
487     }
488 
489     generator(this);
490 
491     HandleFastElements(processor, action, &fully_spec_compliant_, direction,
492                        missing_property_mode);
493 
494     BIND(&fully_spec_compliant_);
495 
496     Node* result =
497         CallStub(slow_case_continuation, context(), receiver(), callbackfn(),
498                  this_arg(), a_.value(), o(), k_.value(), len(), to_.value());
499     ReturnFromBuiltin(result);
500   }
501 
InitIteratingArrayBuiltinLoopContinuation(TNode<Context> context,TNode<Object> receiver,Node * callbackfn,Node * this_arg,Node * a,TNode<JSReceiver> o,Node * initial_k,TNode<Number> len,Node * to)502   void ArrayBuiltinsAssembler::InitIteratingArrayBuiltinLoopContinuation(
503       TNode<Context> context, TNode<Object> receiver, Node* callbackfn,
504       Node* this_arg, Node* a, TNode<JSReceiver> o, Node* initial_k,
505       TNode<Number> len, Node* to) {
506     context_ = context;
507     this_arg_ = this_arg;
508     callbackfn_ = callbackfn;
509     a_.Bind(a);
510     k_.Bind(initial_k);
511     o_ = o;
512     len_ = len;
513     to_.Bind(to);
514   }
515 
GenerateIteratingTypedArrayBuiltinBody(const char * name,const BuiltinResultGenerator & generator,const CallResultProcessor & processor,const PostLoopAction & action,ForEachDirection direction)516   void ArrayBuiltinsAssembler::GenerateIteratingTypedArrayBuiltinBody(
517       const char* name, const BuiltinResultGenerator& generator,
518       const CallResultProcessor& processor, const PostLoopAction& action,
519       ForEachDirection direction) {
520     name_ = name;
521 
522     // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray
523 
524     Label throw_not_typed_array(this, Label::kDeferred);
525 
526     GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
527     GotoIfNot(HasInstanceType(CAST(receiver_), JS_TYPED_ARRAY_TYPE),
528               &throw_not_typed_array);
529 
530     TNode<JSTypedArray> typed_array = CAST(receiver_);
531     o_ = typed_array;
532 
533     TNode<JSArrayBuffer> array_buffer = LoadArrayBufferViewBuffer(typed_array);
534     ThrowIfArrayBufferIsDetached(context_, array_buffer, name_);
535 
536     len_ = LoadTypedArrayLength(typed_array);
537 
538     Label throw_not_callable(this, Label::kDeferred);
539     Label distinguish_types(this);
540     GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable);
541     Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types,
542            &throw_not_callable);
543 
544     BIND(&throw_not_typed_array);
545     ThrowTypeError(context_, MessageTemplate::kNotTypedArray);
546 
547     BIND(&throw_not_callable);
548     ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_);
549 
550     Label unexpected_instance_type(this);
551     BIND(&unexpected_instance_type);
552     Unreachable();
553 
554     std::vector<int32_t> instance_types = {
555 #define INSTANCE_TYPE(Type, type, TYPE, ctype) FIXED_##TYPE##_ARRAY_TYPE,
556         TYPED_ARRAYS(INSTANCE_TYPE)
557 #undef INSTANCE_TYPE
558     };
559     std::vector<Label> labels;
560     for (size_t i = 0; i < instance_types.size(); ++i) {
561       labels.push_back(Label(this));
562     }
563     std::vector<Label*> label_ptrs;
564     for (Label& label : labels) {
565       label_ptrs.push_back(&label);
566     }
567 
568     BIND(&distinguish_types);
569 
570     generator(this);
571 
572     if (direction == ForEachDirection::kForward) {
573       k_.Bind(SmiConstant(0));
574     } else {
575       k_.Bind(NumberDec(len()));
576     }
577     CSA_ASSERT(this, IsSafeInteger(k()));
578     Node* instance_type = LoadInstanceType(LoadElements(typed_array));
579     Switch(instance_type, &unexpected_instance_type, instance_types.data(),
580            label_ptrs.data(), labels.size());
581 
582     for (size_t i = 0; i < labels.size(); ++i) {
583       BIND(&labels[i]);
584       Label done(this);
585       source_elements_kind_ = ElementsKindForInstanceType(
586           static_cast<InstanceType>(instance_types[i]));
587       // TODO(tebbi): Silently cancelling the loop on buffer detachment is a
588       // spec violation. Should go to &throw_detached and throw a TypeError
589       // instead.
590       VisitAllTypedArrayElements(array_buffer, processor, &done, direction,
591                                  typed_array);
592       Goto(&done);
593       // No exception, return success
594       BIND(&done);
595       action(this);
596       ReturnFromBuiltin(a_.value());
597     }
598   }
599 
GenerateIteratingArrayBuiltinLoopContinuation(const CallResultProcessor & processor,const PostLoopAction & action,MissingPropertyMode missing_property_mode,ForEachDirection direction)600   void ArrayBuiltinsAssembler::GenerateIteratingArrayBuiltinLoopContinuation(
601       const CallResultProcessor& processor, const PostLoopAction& action,
602       MissingPropertyMode missing_property_mode, ForEachDirection direction) {
603     Label loop(this, {&k_, &a_, &to_});
604     Label after_loop(this);
605     Goto(&loop);
606     BIND(&loop);
607     {
608       if (direction == ForEachDirection::kForward) {
609         // 8. Repeat, while k < len
610         GotoIfNumberGreaterThanOrEqual(k(), len_, &after_loop);
611       } else {
612         // OR
613         // 10. Repeat, while k >= 0
614         GotoIfNumberGreaterThanOrEqual(SmiConstant(-1), k(), &after_loop);
615       }
616 
617       Label done_element(this, &to_);
618       // a. Let Pk be ToString(k).
619       // k() is guaranteed to be a positive integer, hence ToString is
620       // side-effect free and HasProperty/GetProperty do the conversion inline.
621       CSA_ASSERT(this, IsSafeInteger(k()));
622 
623       if (missing_property_mode == MissingPropertyMode::kSkip) {
624         // b. Let kPresent be HasProperty(O, Pk).
625         // c. ReturnIfAbrupt(kPresent).
626         TNode<Oddball> k_present =
627             HasProperty(context(), o(), k(), kHasProperty);
628 
629         // d. If kPresent is true, then
630         GotoIf(IsFalse(k_present), &done_element);
631       }
632 
633       // i. Let kValue be Get(O, Pk).
634       // ii. ReturnIfAbrupt(kValue).
635       Node* k_value = GetProperty(context(), o(), k());
636 
637       // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
638       // iv. ReturnIfAbrupt(funcResult).
639       a_.Bind(processor(this, k_value, k()));
640       Goto(&done_element);
641 
642       BIND(&done_element);
643 
644       if (direction == ForEachDirection::kForward) {
645         // e. Increase k by 1.
646         k_.Bind(NumberInc(k()));
647       } else {
648         // e. Decrease k by 1.
649         k_.Bind(NumberDec(k()));
650       }
651       Goto(&loop);
652     }
653     BIND(&after_loop);
654 
655     action(this);
656     Return(a_.value());
657   }
658 
ElementsKindForInstanceType(InstanceType type)659   ElementsKind ArrayBuiltinsAssembler::ElementsKindForInstanceType(
660       InstanceType type) {
661     switch (type) {
662 #define INSTANCE_TYPE_TO_ELEMENTS_KIND(Type, type, TYPE, ctype) \
663   case FIXED_##TYPE##_ARRAY_TYPE:                               \
664     return TYPE##_ELEMENTS;
665 
666       TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND)
667 #undef INSTANCE_TYPE_TO_ELEMENTS_KIND
668 
669       default:
670         UNREACHABLE();
671     }
672   }
673 
VisitAllTypedArrayElements(Node * array_buffer,const CallResultProcessor & processor,Label * detached,ForEachDirection direction,TNode<JSTypedArray> typed_array)674   void ArrayBuiltinsAssembler::VisitAllTypedArrayElements(
675       Node* array_buffer, const CallResultProcessor& processor, Label* detached,
676       ForEachDirection direction, TNode<JSTypedArray> typed_array) {
677     VariableList list({&a_, &k_, &to_}, zone());
678 
679     FastLoopBody body = [&](Node* index) {
680       GotoIf(IsDetachedBuffer(array_buffer), detached);
681       Node* elements = LoadElements(typed_array);
682       Node* base_ptr =
683           LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
684       Node* external_ptr =
685           LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
686                           MachineType::Pointer());
687       Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
688       Node* value = LoadFixedTypedArrayElementAsTagged(
689           data_ptr, index, source_elements_kind_, SMI_PARAMETERS);
690       k_.Bind(index);
691       a_.Bind(processor(this, value, index));
692     };
693     Node* start = SmiConstant(0);
694     Node* end = len_;
695     IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost;
696     int incr = 1;
697     if (direction == ForEachDirection::kReverse) {
698       std::swap(start, end);
699       advance_mode = IndexAdvanceMode::kPre;
700       incr = -1;
701     }
702     BuildFastLoop(list, start, end, body, incr, ParameterMode::SMI_PARAMETERS,
703                   advance_mode);
704   }
705 
VisitAllFastElementsOneKind(ElementsKind kind,const CallResultProcessor & processor,Label * array_changed,ParameterMode mode,ForEachDirection direction,MissingPropertyMode missing_property_mode,TNode<Smi> length)706   void ArrayBuiltinsAssembler::VisitAllFastElementsOneKind(
707       ElementsKind kind, const CallResultProcessor& processor,
708       Label* array_changed, ParameterMode mode, ForEachDirection direction,
709       MissingPropertyMode missing_property_mode, TNode<Smi> length) {
710     Comment("begin VisitAllFastElementsOneKind");
711     // We only use this kind of processing if the no-elements protector is
712     // in place at the start. We'll continue checking during array iteration.
713     CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid()));
714     VARIABLE(original_map, MachineRepresentation::kTagged);
715     original_map.Bind(LoadMap(o()));
716     VariableList list({&original_map, &a_, &k_, &to_}, zone());
717     Node* start = IntPtrOrSmiConstant(0, mode);
718     Node* end = TaggedToParameter(length, mode);
719     IndexAdvanceMode advance_mode = direction == ForEachDirection::kReverse
720                                         ? IndexAdvanceMode::kPre
721                                         : IndexAdvanceMode::kPost;
722     if (direction == ForEachDirection::kReverse) std::swap(start, end);
723     BuildFastLoop(
724         list, start, end,
725         [=, &original_map](Node* index) {
726           k_.Bind(ParameterToTagged(index, mode));
727           Label one_element_done(this), hole_element(this),
728               process_element(this);
729 
730           // Check if o's map has changed during the callback. If so, we have to
731           // fall back to the slower spec implementation for the rest of the
732           // iteration.
733           Node* o_map = LoadMap(o());
734           GotoIf(WordNotEqual(o_map, original_map.value()), array_changed);
735 
736           TNode<JSArray> o_array = CAST(o());
737           // Check if o's length has changed during the callback and if the
738           // index is now out of range of the new length.
739           GotoIf(SmiGreaterThanOrEqual(CAST(k_.value()),
740                                        CAST(LoadJSArrayLength(o_array))),
741                  array_changed);
742 
743           // Re-load the elements array. If may have been resized.
744           Node* elements = LoadElements(o_array);
745 
746           // Fast case: load the element directly from the elements FixedArray
747           // and call the callback if the element is not the hole.
748           DCHECK(kind == PACKED_ELEMENTS || kind == PACKED_DOUBLE_ELEMENTS);
749           int base_size = kind == PACKED_ELEMENTS
750                               ? FixedArray::kHeaderSize
751                               : (FixedArray::kHeaderSize - kHeapObjectTag);
752           Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size);
753           VARIABLE(value, MachineRepresentation::kTagged);
754           if (kind == PACKED_ELEMENTS) {
755             value.Bind(LoadObjectField(elements, offset));
756             GotoIf(WordEqual(value.value(), TheHoleConstant()), &hole_element);
757           } else {
758             Node* double_value =
759                 LoadDoubleWithHoleCheck(elements, offset, &hole_element);
760             value.Bind(AllocateHeapNumberWithValue(double_value));
761           }
762           Goto(&process_element);
763 
764           BIND(&hole_element);
765           if (missing_property_mode == MissingPropertyMode::kSkip) {
766             // The NoElementsProtectorCell could go invalid during callbacks.
767             Branch(IsNoElementsProtectorCellInvalid(), array_changed,
768                    &one_element_done);
769           } else {
770             value.Bind(UndefinedConstant());
771             Goto(&process_element);
772           }
773           BIND(&process_element);
774           {
775             a_.Bind(processor(this, value.value(), k()));
776             Goto(&one_element_done);
777           }
778           BIND(&one_element_done);
779         },
780         1, mode, advance_mode);
781     Comment("end VisitAllFastElementsOneKind");
782   }
783 
HandleFastElements(const CallResultProcessor & processor,const PostLoopAction & action,Label * slow,ForEachDirection direction,MissingPropertyMode missing_property_mode)784   void ArrayBuiltinsAssembler::HandleFastElements(
785       const CallResultProcessor& processor, const PostLoopAction& action,
786       Label* slow, ForEachDirection direction,
787       MissingPropertyMode missing_property_mode) {
788     Label switch_on_elements_kind(this), fast_elements(this),
789         maybe_double_elements(this), fast_double_elements(this);
790 
791     Comment("begin HandleFastElements");
792     // Non-smi lengths must use the slow path.
793     GotoIf(TaggedIsNotSmi(len()), slow);
794 
795     BranchIfFastJSArray(o(), context(),
796                         &switch_on_elements_kind, slow);
797 
798     BIND(&switch_on_elements_kind);
799     TNode<Smi> smi_len = CAST(len());
800     // Select by ElementsKind
801     Node* o_map = LoadMap(o());
802     Node* bit_field2 = LoadMapBitField2(o_map);
803     Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
804     Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
805            &maybe_double_elements, &fast_elements);
806 
807     ParameterMode mode = OptimalParameterMode();
808     BIND(&fast_elements);
809     {
810       VisitAllFastElementsOneKind(PACKED_ELEMENTS, processor, slow, mode,
811                                   direction, missing_property_mode, smi_len);
812 
813       action(this);
814 
815       // No exception, return success
816       ReturnFromBuiltin(a_.value());
817     }
818 
819     BIND(&maybe_double_elements);
820     Branch(IsElementsKindGreaterThan(kind, HOLEY_DOUBLE_ELEMENTS), slow,
821            &fast_double_elements);
822 
823     BIND(&fast_double_elements);
824     {
825       VisitAllFastElementsOneKind(PACKED_DOUBLE_ELEMENTS, processor, slow, mode,
826                                   direction, missing_property_mode, smi_len);
827 
828       action(this);
829 
830       // No exception, return success
831       ReturnFromBuiltin(a_.value());
832     }
833   }
834 
835   // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
836   // This version is specialized to create a zero length array
837   // of the elements kind of the input array.
GenerateArraySpeciesCreate()838   void ArrayBuiltinsAssembler::GenerateArraySpeciesCreate() {
839     Label runtime(this, Label::kDeferred), done(this);
840 
841     TNode<Smi> len = SmiConstant(0);
842     TNode<Map> original_map = LoadMap(o());
843     GotoIfNot(
844         InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
845         &runtime);
846 
847     GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
848               &runtime);
849 
850     Node* species_protector = ArraySpeciesProtectorConstant();
851     Node* value =
852         LoadObjectField(species_protector, PropertyCell::kValueOffset);
853     TNode<Smi> const protector_invalid =
854         SmiConstant(Isolate::kProtectorInvalid);
855     GotoIf(WordEqual(value, protector_invalid), &runtime);
856 
857     // Respect the ElementsKind of the input array.
858     TNode<Int32T> elements_kind = LoadMapElementsKind(original_map);
859     GotoIfNot(IsFastElementsKind(elements_kind), &runtime);
860     TNode<Context> native_context = LoadNativeContext(context());
861     TNode<Map> array_map =
862         LoadJSArrayElementsMap(elements_kind, native_context);
863     TNode<JSArray> array =
864         CAST(AllocateJSArray(GetInitialFastElementsKind(), array_map, len, len,
865                              nullptr, CodeStubAssembler::SMI_PARAMETERS));
866     a_.Bind(array);
867 
868     Goto(&done);
869 
870     BIND(&runtime);
871     {
872       // 5. Let A be ? ArraySpeciesCreate(O, len).
873       Node* constructor =
874           CallRuntime(Runtime::kArraySpeciesConstructor, context(), o());
875       a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(),
876                           constructor, len));
877       Goto(&fully_spec_compliant_);
878     }
879 
880     BIND(&done);
881   }
882 
883   // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
GenerateArraySpeciesCreate(TNode<Number> len)884   void ArrayBuiltinsAssembler::GenerateArraySpeciesCreate(TNode<Number> len) {
885     Label runtime(this, Label::kDeferred), done(this);
886 
887     Node* const original_map = LoadMap(o());
888     GotoIfNot(
889         InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
890         &runtime);
891 
892     GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
893               &runtime);
894 
895     Node* species_protector = ArraySpeciesProtectorConstant();
896     Node* value =
897         LoadObjectField(species_protector, PropertyCell::kValueOffset);
898     Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
899     GotoIf(WordEqual(value, protector_invalid), &runtime);
900 
901     GotoIfNot(TaggedIsPositiveSmi(len), &runtime);
902     GotoIf(
903         SmiAbove(CAST(len), SmiConstant(JSArray::kInitialMaxFastElementArray)),
904         &runtime);
905 
906     // We need to be conservative and start with holey because the builtins
907     // that create output arrays aren't guaranteed to be called for every
908     // element in the input array (maybe the callback deletes an element).
909     const ElementsKind elements_kind =
910         GetHoleyElementsKind(GetInitialFastElementsKind());
911     TNode<Context> native_context = LoadNativeContext(context());
912     TNode<Map> array_map =
913         LoadJSArrayElementsMap(elements_kind, native_context);
914     a_.Bind(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, len, len, nullptr,
915                             CodeStubAssembler::SMI_PARAMETERS));
916 
917     Goto(&done);
918 
919     BIND(&runtime);
920     {
921       // 5. Let A be ? ArraySpeciesCreate(O, len).
922       Node* constructor =
923           CallRuntime(Runtime::kArraySpeciesConstructor, context(), o());
924       a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(),
925                           constructor, len));
926       Goto(&fully_spec_compliant_);
927     }
928 
929     BIND(&done);
930   }
931 
TF_BUILTIN(ArrayPrototypePop,CodeStubAssembler)932 TF_BUILTIN(ArrayPrototypePop, CodeStubAssembler) {
933   TNode<Int32T> argc =
934       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
935   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
936   CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
937 
938   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
939   TNode<Object> receiver = args.GetReceiver();
940 
941   Label runtime(this, Label::kDeferred);
942   Label fast(this);
943 
944   // Only pop in this stub if
945   // 1) the array has fast elements
946   // 2) the length is writable,
947   // 3) the elements backing store isn't copy-on-write,
948   // 4) we aren't supposed to shrink the backing store.
949 
950   // 1) Check that the array has fast elements.
951   BranchIfFastJSArray(receiver, context, &fast, &runtime);
952 
953   BIND(&fast);
954   {
955     TNode<JSArray> array_receiver = CAST(receiver);
956     CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver)));
957     Node* length =
958         LoadAndUntagObjectField(array_receiver, JSArray::kLengthOffset);
959     Label return_undefined(this), fast_elements(this);
960     GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
961 
962     // 2) Ensure that the length is writable.
963     EnsureArrayLengthWritable(LoadMap(array_receiver), &runtime);
964 
965     // 3) Check that the elements backing store isn't copy-on-write.
966     Node* elements = LoadElements(array_receiver);
967     GotoIf(WordEqual(LoadMap(elements),
968                      LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
969            &runtime);
970 
971     Node* new_length = IntPtrSub(length, IntPtrConstant(1));
972 
973     // 4) Check that we're not supposed to shrink the backing store, as
974     //    implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
975     Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
976     GotoIf(IntPtrLessThan(
977                IntPtrAdd(IntPtrAdd(new_length, new_length),
978                          IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
979                capacity),
980            &runtime);
981 
982     StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset,
983                                    SmiTag(new_length));
984 
985     TNode<Int32T> elements_kind = LoadElementsKind(array_receiver);
986     GotoIf(Int32LessThanOrEqual(elements_kind,
987                                 Int32Constant(TERMINAL_FAST_ELEMENTS_KIND)),
988            &fast_elements);
989 
990     Node* value = LoadFixedDoubleArrayElement(
991         elements, new_length, MachineType::Float64(), 0, INTPTR_PARAMETERS,
992         &return_undefined);
993 
994     int32_t header_size = FixedDoubleArray::kHeaderSize - kHeapObjectTag;
995     Node* offset = ElementOffsetFromIndex(new_length, HOLEY_DOUBLE_ELEMENTS,
996                                           INTPTR_PARAMETERS, header_size);
997     if (Is64()) {
998       Node* double_hole = Int64Constant(kHoleNanInt64);
999       StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset,
1000                           double_hole);
1001     } else {
1002       STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32);
1003       Node* double_hole = Int32Constant(kHoleNanLower32);
1004       StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
1005                           double_hole);
1006       StoreNoWriteBarrier(MachineRepresentation::kWord32, elements,
1007                           IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
1008                           double_hole);
1009     }
1010     args.PopAndReturn(AllocateHeapNumberWithValue(value));
1011 
1012     BIND(&fast_elements);
1013     {
1014       Node* value = LoadFixedArrayElement(CAST(elements), new_length);
1015       StoreFixedArrayElement(CAST(elements), new_length, TheHoleConstant());
1016       GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
1017       args.PopAndReturn(value);
1018     }
1019 
1020     BIND(&return_undefined);
1021     { args.PopAndReturn(UndefinedConstant()); }
1022   }
1023 
1024   BIND(&runtime);
1025   {
1026     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
1027     // from the current frame here in order to reduce register pressure on the
1028     // fast path.
1029     TNode<JSFunction> target = LoadTargetFromFrame();
1030     TailCallBuiltin(Builtins::kArrayPop, context, target, UndefinedConstant(),
1031                     argc);
1032   }
1033 }
1034 
TF_BUILTIN(ArrayPrototypePush,CodeStubAssembler)1035 TF_BUILTIN(ArrayPrototypePush, CodeStubAssembler) {
1036   TVARIABLE(IntPtrT, arg_index);
1037   Label default_label(this, &arg_index);
1038   Label smi_transition(this);
1039   Label object_push_pre(this);
1040   Label object_push(this, &arg_index);
1041   Label double_push(this, &arg_index);
1042   Label double_transition(this);
1043   Label runtime(this, Label::kDeferred);
1044 
1045   // TODO(ishell): use constants from Descriptor once the JSFunction linkage
1046   // arguments are reordered.
1047   TNode<Int32T> argc =
1048       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
1049   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1050   CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
1051 
1052   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
1053   TNode<Object> receiver = args.GetReceiver();
1054   TNode<JSArray> array_receiver;
1055   Node* kind = nullptr;
1056 
1057   Label fast(this);
1058   BranchIfFastJSArray(receiver, context, &fast, &runtime);
1059 
1060   BIND(&fast);
1061   {
1062     array_receiver = CAST(receiver);
1063     arg_index = IntPtrConstant(0);
1064     kind = EnsureArrayPushable(LoadMap(array_receiver), &runtime);
1065     GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
1066            &object_push_pre);
1067 
1068     Node* new_length = BuildAppendJSArray(PACKED_SMI_ELEMENTS, array_receiver,
1069                                           &args, &arg_index, &smi_transition);
1070     args.PopAndReturn(new_length);
1071   }
1072 
1073   // If the argument is not a smi, then use a heavyweight SetProperty to
1074   // transition the array for only the single next element. If the argument is
1075   // a smi, the failure is due to some other reason and we should fall back on
1076   // the most generic implementation for the rest of the array.
1077   BIND(&smi_transition);
1078   {
1079     Node* arg = args.AtIndex(arg_index.value());
1080     GotoIf(TaggedIsSmi(arg), &default_label);
1081     Node* length = LoadJSArrayLength(array_receiver);
1082     // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
1083     // calling into the runtime to do the elements transition is overkill.
1084     SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
1085     Increment(&arg_index);
1086     // The runtime SetProperty call could have converted the array to dictionary
1087     // mode, which must be detected to abort the fast-path.
1088     Node* map = LoadMap(array_receiver);
1089     Node* bit_field2 = LoadMapBitField2(map);
1090     Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
1091     GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
1092            &default_label);
1093 
1094     GotoIfNotNumber(arg, &object_push);
1095     Goto(&double_push);
1096   }
1097 
1098   BIND(&object_push_pre);
1099   {
1100     Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push,
1101            &object_push);
1102   }
1103 
1104   BIND(&object_push);
1105   {
1106     Node* new_length = BuildAppendJSArray(PACKED_ELEMENTS, array_receiver,
1107                                           &args, &arg_index, &default_label);
1108     args.PopAndReturn(new_length);
1109   }
1110 
1111   BIND(&double_push);
1112   {
1113     Node* new_length =
1114         BuildAppendJSArray(PACKED_DOUBLE_ELEMENTS, array_receiver, &args,
1115                            &arg_index, &double_transition);
1116     args.PopAndReturn(new_length);
1117   }
1118 
1119   // If the argument is not a double, then use a heavyweight SetProperty to
1120   // transition the array for only the single next element. If the argument is
1121   // a double, the failure is due to some other reason and we should fall back
1122   // on the most generic implementation for the rest of the array.
1123   BIND(&double_transition);
1124   {
1125     Node* arg = args.AtIndex(arg_index.value());
1126     GotoIfNumber(arg, &default_label);
1127     Node* length = LoadJSArrayLength(array_receiver);
1128     // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
1129     // calling into the runtime to do the elements transition is overkill.
1130     SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
1131     Increment(&arg_index);
1132     // The runtime SetProperty call could have converted the array to dictionary
1133     // mode, which must be detected to abort the fast-path.
1134     Node* map = LoadMap(array_receiver);
1135     Node* bit_field2 = LoadMapBitField2(map);
1136     Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
1137     GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
1138            &default_label);
1139     Goto(&object_push);
1140   }
1141 
1142   // Fallback that stores un-processed arguments using the full, heavyweight
1143   // SetProperty machinery.
1144   BIND(&default_label);
1145   {
1146     args.ForEach(
1147         [this, array_receiver, context](Node* arg) {
1148           Node* length = LoadJSArrayLength(array_receiver);
1149           SetPropertyStrict(context, array_receiver, CAST(length), CAST(arg));
1150         },
1151         arg_index.value());
1152     args.PopAndReturn(LoadJSArrayLength(array_receiver));
1153   }
1154 
1155   BIND(&runtime);
1156   {
1157     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
1158     // from the current frame here in order to reduce register pressure on the
1159     // fast path.
1160     TNode<JSFunction> target = LoadTargetFromFrame();
1161     TailCallBuiltin(Builtins::kArrayPush, context, target, UndefinedConstant(),
1162                     argc);
1163   }
1164 }
1165 
1166 class ArrayPrototypeSliceCodeStubAssembler : public CodeStubAssembler {
1167  public:
ArrayPrototypeSliceCodeStubAssembler(compiler::CodeAssemblerState * state)1168   explicit ArrayPrototypeSliceCodeStubAssembler(
1169       compiler::CodeAssemblerState* state)
1170       : CodeStubAssembler(state) {}
1171 
HandleFastSlice(TNode<Context> context,Node * array,Node * from,Node * count,Label * slow)1172   Node* HandleFastSlice(TNode<Context> context, Node* array, Node* from,
1173                         Node* count, Label* slow) {
1174     VARIABLE(result, MachineRepresentation::kTagged);
1175     Label done(this);
1176 
1177     GotoIf(TaggedIsNotSmi(from), slow);
1178     GotoIf(TaggedIsNotSmi(count), slow);
1179 
1180     Label try_fast_arguments(this), try_simple_slice(this);
1181 
1182     Node* map = LoadMap(array);
1183     GotoIfNot(IsJSArrayMap(map), &try_fast_arguments);
1184 
1185     // Check prototype chain if receiver does not have packed elements
1186     GotoIfNot(IsPrototypeInitialArrayPrototype(context, map), slow);
1187 
1188     GotoIf(IsNoElementsProtectorCellInvalid(), slow);
1189 
1190     GotoIf(IsArraySpeciesProtectorCellInvalid(), slow);
1191 
1192     // Bailout if receiver has slow elements.
1193     Node* elements_kind = LoadMapElementsKind(map);
1194     GotoIfNot(IsFastElementsKind(elements_kind), &try_simple_slice);
1195 
1196     // Make sure that the length hasn't been changed by side-effect.
1197     Node* array_length = LoadJSArrayLength(array);
1198     GotoIf(TaggedIsNotSmi(array_length), slow);
1199     GotoIf(SmiAbove(SmiAdd(CAST(from), CAST(count)), CAST(array_length)), slow);
1200 
1201     CSA_ASSERT(this, SmiGreaterThanOrEqual(CAST(from), SmiConstant(0)));
1202 
1203     result.Bind(CallBuiltin(Builtins::kExtractFastJSArray, context, array, from,
1204                             count));
1205     Goto(&done);
1206 
1207     BIND(&try_fast_arguments);
1208 
1209     Node* const native_context = LoadNativeContext(context);
1210     Node* const fast_aliasted_arguments_map = LoadContextElement(
1211         native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
1212     GotoIf(WordNotEqual(map, fast_aliasted_arguments_map), &try_simple_slice);
1213 
1214     TNode<SloppyArgumentsElements> sloppy_elements = CAST(LoadElements(array));
1215     TNode<Smi> sloppy_elements_length =
1216         LoadFixedArrayBaseLength(sloppy_elements);
1217     TNode<Smi> parameter_map_length =
1218         SmiSub(sloppy_elements_length,
1219                SmiConstant(SloppyArgumentsElements::kParameterMapStart));
1220     VARIABLE(index_out, MachineType::PointerRepresentation());
1221 
1222     int max_fast_elements =
1223         (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize -
1224          AllocationMemento::kSize) /
1225         kPointerSize;
1226     GotoIf(SmiAboveOrEqual(CAST(count), SmiConstant(max_fast_elements)),
1227            &try_simple_slice);
1228 
1229     GotoIf(SmiLessThan(CAST(from), SmiConstant(0)), slow);
1230 
1231     TNode<Smi> end = SmiAdd(CAST(from), CAST(count));
1232 
1233     TNode<FixedArray> unmapped_elements = CAST(LoadFixedArrayElement(
1234         sloppy_elements, SloppyArgumentsElements::kArgumentsIndex));
1235     TNode<Smi> unmapped_elements_length =
1236         LoadFixedArrayBaseLength(unmapped_elements);
1237 
1238     GotoIf(SmiAbove(end, unmapped_elements_length), slow);
1239 
1240     Node* array_map = LoadJSArrayElementsMap(HOLEY_ELEMENTS, native_context);
1241     result.Bind(AllocateJSArray(HOLEY_ELEMENTS, array_map, count, count,
1242                                 nullptr, SMI_PARAMETERS));
1243 
1244     index_out.Bind(IntPtrConstant(0));
1245     TNode<FixedArray> result_elements = CAST(LoadElements(result.value()));
1246     TNode<Smi> from_mapped = SmiMin(parameter_map_length, CAST(from));
1247     TNode<Smi> to = SmiMin(parameter_map_length, end);
1248     Node* arguments_context = LoadFixedArrayElement(
1249         sloppy_elements, SloppyArgumentsElements::kContextIndex);
1250     VariableList var_list({&index_out}, zone());
1251     BuildFastLoop(
1252         var_list, from_mapped, to,
1253         [this, result_elements, arguments_context, sloppy_elements,
1254          unmapped_elements, &index_out](Node* current) {
1255           Node* context_index = LoadFixedArrayElement(
1256               sloppy_elements, current,
1257               kPointerSize * SloppyArgumentsElements::kParameterMapStart,
1258               SMI_PARAMETERS);
1259           Label is_the_hole(this), done(this);
1260           GotoIf(IsTheHole(context_index), &is_the_hole);
1261           Node* mapped_argument =
1262               LoadContextElement(arguments_context, SmiUntag(context_index));
1263           StoreFixedArrayElement(result_elements, index_out.value(),
1264                                  mapped_argument, SKIP_WRITE_BARRIER);
1265           Goto(&done);
1266           BIND(&is_the_hole);
1267           Node* argument = LoadFixedArrayElement(unmapped_elements, current, 0,
1268                                                  SMI_PARAMETERS);
1269           StoreFixedArrayElement(result_elements, index_out.value(), argument,
1270                                  SKIP_WRITE_BARRIER);
1271           Goto(&done);
1272           BIND(&done);
1273           index_out.Bind(IntPtrAdd(index_out.value(), IntPtrConstant(1)));
1274         },
1275         1, SMI_PARAMETERS, IndexAdvanceMode::kPost);
1276 
1277     TNode<Smi> unmapped_from =
1278         SmiMin(SmiMax(parameter_map_length, CAST(from)), end);
1279 
1280     BuildFastLoop(
1281         var_list, unmapped_from, end,
1282         [this, unmapped_elements, result_elements, &index_out](Node* current) {
1283           Node* argument = LoadFixedArrayElement(unmapped_elements, current, 0,
1284                                                  SMI_PARAMETERS);
1285           StoreFixedArrayElement(result_elements, index_out.value(), argument,
1286                                  SKIP_WRITE_BARRIER);
1287           index_out.Bind(IntPtrAdd(index_out.value(), IntPtrConstant(1)));
1288         },
1289         1, SMI_PARAMETERS, IndexAdvanceMode::kPost);
1290 
1291     Goto(&done);
1292 
1293     BIND(&try_simple_slice);
1294     Node* simple_result = CallRuntime(Runtime::kTrySliceSimpleNonFastElements,
1295                                       context, array, from, count);
1296     GotoIfNumber(simple_result, slow);
1297     result.Bind(simple_result);
1298 
1299     Goto(&done);
1300 
1301     BIND(&done);
1302     return result.value();
1303   }
1304 
CopyOneElement(TNode<Context> context,Node * o,Node * a,Node * p_k,Variable & n)1305   void CopyOneElement(TNode<Context> context, Node* o, Node* a, Node* p_k,
1306                       Variable& n) {
1307     // b. Let kPresent be HasProperty(O, Pk).
1308     // c. ReturnIfAbrupt(kPresent).
1309     TNode<Oddball> k_present = HasProperty(context, o, p_k, kHasProperty);
1310 
1311     // d. If kPresent is true, then
1312     Label done_element(this);
1313     GotoIf(IsFalse(k_present), &done_element);
1314 
1315     // i. Let kValue be Get(O, Pk).
1316     // ii. ReturnIfAbrupt(kValue).
1317     Node* k_value = GetProperty(context, o, p_k);
1318 
1319     // iii. Let status be CreateDataPropertyOrThrow(A, ToString(n), kValue).
1320     // iv. ReturnIfAbrupt(status).
1321     CallRuntime(Runtime::kCreateDataProperty, context, a, n.value(), k_value);
1322 
1323     Goto(&done_element);
1324     BIND(&done_element);
1325   }
1326 };
1327 
TF_BUILTIN(ArrayPrototypeSlice,ArrayPrototypeSliceCodeStubAssembler)1328 TF_BUILTIN(ArrayPrototypeSlice, ArrayPrototypeSliceCodeStubAssembler) {
1329   Node* const argc =
1330       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
1331   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1332   Label slow(this, Label::kDeferred), fast_elements_kind(this);
1333 
1334   CodeStubArguments args(this, argc);
1335   TNode<Object> receiver = args.GetReceiver();
1336 
1337   TVARIABLE(JSReceiver, o);
1338   VARIABLE(len, MachineRepresentation::kTagged);
1339   Label length_done(this), generic_length(this), check_arguments_length(this),
1340       load_arguments_length(this);
1341 
1342   GotoIf(TaggedIsSmi(receiver), &generic_length);
1343   GotoIfNot(IsJSArray(CAST(receiver)), &check_arguments_length);
1344 
1345   TNode<JSArray> array_receiver = CAST(receiver);
1346   o = array_receiver;
1347   len.Bind(LoadJSArrayLength(array_receiver));
1348 
1349   // Check for the array clone case. There can be no arguments to slice, the
1350   // array prototype chain must be intact and have no elements, the array has to
1351   // have fast elements.
1352   GotoIf(WordNotEqual(argc, IntPtrConstant(0)), &length_done);
1353 
1354   Label clone(this);
1355   BranchIfFastJSArrayForCopy(receiver, context, &clone, &length_done);
1356   BIND(&clone);
1357 
1358   args.PopAndReturn(
1359       CallBuiltin(Builtins::kCloneFastJSArray, context, receiver));
1360 
1361   BIND(&check_arguments_length);
1362 
1363   Node* map = LoadMap(array_receiver);
1364   Node* native_context = LoadNativeContext(context);
1365   GotoIfContextElementEqual(map, native_context,
1366                             Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX,
1367                             &load_arguments_length);
1368   GotoIfContextElementEqual(map, native_context,
1369                             Context::SLOW_ALIASED_ARGUMENTS_MAP_INDEX,
1370                             &load_arguments_length);
1371   GotoIfContextElementEqual(map, native_context,
1372                             Context::STRICT_ARGUMENTS_MAP_INDEX,
1373                             &load_arguments_length);
1374   GotoIfContextElementEqual(map, native_context,
1375                             Context::SLOPPY_ARGUMENTS_MAP_INDEX,
1376                             &load_arguments_length);
1377 
1378   Goto(&generic_length);
1379 
1380   BIND(&load_arguments_length);
1381   Node* arguments_length =
1382       LoadObjectField(array_receiver, JSArgumentsObject::kLengthOffset);
1383   GotoIf(TaggedIsNotSmi(arguments_length), &generic_length);
1384   o = CAST(receiver);
1385   len.Bind(arguments_length);
1386   Goto(&length_done);
1387 
1388   BIND(&generic_length);
1389   // 1. Let O be ToObject(this value).
1390   // 2. ReturnIfAbrupt(O).
1391   o = ToObject_Inline(context, receiver);
1392 
1393   // 3. Let len be ToLength(Get(O, "length")).
1394   // 4. ReturnIfAbrupt(len).
1395   len.Bind(ToLength_Inline(
1396       context,
1397       GetProperty(context, o.value(), isolate()->factory()->length_string())));
1398   Goto(&length_done);
1399 
1400   BIND(&length_done);
1401 
1402   // 5. Let relativeStart be ToInteger(start).
1403   // 6. ReturnIfAbrupt(relativeStart).
1404   TNode<Object> arg0 = args.GetOptionalArgumentValue(0, SmiConstant(0));
1405   Node* relative_start = ToInteger_Inline(context, arg0);
1406 
1407   // 7. If relativeStart < 0, let k be max((len + relativeStart),0);
1408   //    else let k be min(relativeStart, len.value()).
1409   VARIABLE(k, MachineRepresentation::kTagged);
1410   Label relative_start_positive(this), relative_start_done(this);
1411   GotoIfNumberGreaterThanOrEqual(relative_start, SmiConstant(0),
1412                                  &relative_start_positive);
1413   k.Bind(NumberMax(NumberAdd(len.value(), relative_start), NumberConstant(0)));
1414   Goto(&relative_start_done);
1415   BIND(&relative_start_positive);
1416   k.Bind(NumberMin(relative_start, len.value()));
1417   Goto(&relative_start_done);
1418   BIND(&relative_start_done);
1419 
1420   // 8. If end is undefined, let relativeEnd be len;
1421   //    else let relativeEnd be ToInteger(end).
1422   // 9. ReturnIfAbrupt(relativeEnd).
1423   TNode<Object> end = args.GetOptionalArgumentValue(1, UndefinedConstant());
1424   Label end_undefined(this), end_done(this);
1425   VARIABLE(relative_end, MachineRepresentation::kTagged);
1426   GotoIf(WordEqual(end, UndefinedConstant()), &end_undefined);
1427   relative_end.Bind(ToInteger_Inline(context, end));
1428   Goto(&end_done);
1429   BIND(&end_undefined);
1430   relative_end.Bind(len.value());
1431   Goto(&end_done);
1432   BIND(&end_done);
1433 
1434   // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0);
1435   //     else let final be min(relativeEnd, len).
1436   VARIABLE(final, MachineRepresentation::kTagged);
1437   Label relative_end_positive(this), relative_end_done(this);
1438   GotoIfNumberGreaterThanOrEqual(relative_end.value(), NumberConstant(0),
1439                                  &relative_end_positive);
1440   final.Bind(NumberMax(NumberAdd(len.value(), relative_end.value()),
1441                        NumberConstant(0)));
1442   Goto(&relative_end_done);
1443   BIND(&relative_end_positive);
1444   final.Bind(NumberMin(relative_end.value(), len.value()));
1445   Goto(&relative_end_done);
1446   BIND(&relative_end_done);
1447 
1448   // 11. Let count be max(final – k, 0).
1449   Node* count =
1450       NumberMax(NumberSub(final.value(), k.value()), NumberConstant(0));
1451 
1452   // Handle FAST_ELEMENTS
1453   Label non_fast(this);
1454   Node* fast_result =
1455       HandleFastSlice(context, o.value(), k.value(), count, &non_fast);
1456   args.PopAndReturn(fast_result);
1457 
1458   // 12. Let A be ArraySpeciesCreate(O, count).
1459   // 13. ReturnIfAbrupt(A).
1460   BIND(&non_fast);
1461 
1462   Node* constructor =
1463       CallRuntime(Runtime::kArraySpeciesConstructor, context, o.value());
1464   Node* a = ConstructJS(CodeFactory::Construct(isolate()), context, constructor,
1465                         count);
1466 
1467   // 14. Let n be 0.
1468   VARIABLE(n, MachineRepresentation::kTagged);
1469   n.Bind(SmiConstant(0));
1470 
1471   Label loop(this, {&k, &n});
1472   Label after_loop(this);
1473   Goto(&loop);
1474   BIND(&loop);
1475   {
1476     // 15. Repeat, while k < final
1477     GotoIfNumberGreaterThanOrEqual(k.value(), final.value(), &after_loop);
1478 
1479     Node* p_k = k.value();  //  ToString(context, k.value()) is no-op
1480 
1481     CopyOneElement(context, o.value(), a, p_k, n);
1482 
1483     // e. Increase k by 1.
1484     k.Bind(NumberInc(k.value()));
1485 
1486     // f. Increase n by 1.
1487     n.Bind(NumberInc(n.value()));
1488 
1489     Goto(&loop);
1490   }
1491 
1492   BIND(&after_loop);
1493 
1494   // 16. Let setStatus be Set(A, "length", n, true).
1495   // 17. ReturnIfAbrupt(setStatus).
1496   SetPropertyStrict(context, CAST(a), CodeStubAssembler::LengthStringConstant(),
1497                     CAST(n.value()));
1498   args.PopAndReturn(a);
1499 }
1500 
TF_BUILTIN(ArrayPrototypeShift,CodeStubAssembler)1501 TF_BUILTIN(ArrayPrototypeShift, CodeStubAssembler) {
1502   TNode<Int32T> argc =
1503       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
1504   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1505   CSA_ASSERT(this, IsUndefined(Parameter(Descriptor::kJSNewTarget)));
1506 
1507   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
1508   TNode<Object> receiver = args.GetReceiver();
1509 
1510   Label runtime(this, Label::kDeferred);
1511   Label fast(this);
1512 
1513   // Only shift in this stub if
1514   // 1) the array has fast elements
1515   // 2) the length is writable,
1516   // 3) the elements backing store isn't copy-on-write,
1517   // 4) we aren't supposed to shrink the backing store,
1518   // 5) we aren't supposed to left-trim the backing store.
1519 
1520   // 1) Check that the array has fast elements.
1521   BranchIfFastJSArray(receiver, context, &fast, &runtime);
1522 
1523   BIND(&fast);
1524   {
1525     TNode<JSArray> array_receiver = CAST(receiver);
1526     CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array_receiver)));
1527     Node* length =
1528         LoadAndUntagObjectField(array_receiver, JSArray::kLengthOffset);
1529     Label return_undefined(this), fast_elements_tagged(this),
1530         fast_elements_smi(this);
1531     GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
1532 
1533     // 2) Ensure that the length is writable.
1534     EnsureArrayLengthWritable(LoadMap(array_receiver), &runtime);
1535 
1536     // 3) Check that the elements backing store isn't copy-on-write.
1537     Node* elements = LoadElements(array_receiver);
1538     GotoIf(WordEqual(LoadMap(elements),
1539                      LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
1540            &runtime);
1541 
1542     Node* new_length = IntPtrSub(length, IntPtrConstant(1));
1543 
1544     // 4) Check that we're not supposed to right-trim the backing store, as
1545     //    implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
1546     Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
1547     GotoIf(IntPtrLessThan(
1548                IntPtrAdd(IntPtrAdd(new_length, new_length),
1549                          IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
1550                capacity),
1551            &runtime);
1552 
1553     // 5) Check that we're not supposed to left-trim the backing store, as
1554     //    implemented in elements.cc:FastElementsAccessor::MoveElements.
1555     GotoIf(IntPtrGreaterThan(new_length,
1556                              IntPtrConstant(JSArray::kMaxCopyElements)),
1557            &runtime);
1558 
1559     StoreObjectFieldNoWriteBarrier(array_receiver, JSArray::kLengthOffset,
1560                                    SmiTag(new_length));
1561 
1562     TNode<Int32T> elements_kind = LoadElementsKind(array_receiver);
1563     GotoIf(
1564         Int32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_SMI_ELEMENTS)),
1565         &fast_elements_smi);
1566     GotoIf(Int32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
1567            &fast_elements_tagged);
1568 
1569     // Fast double elements kind:
1570     {
1571       CSA_ASSERT(this,
1572                  Int32LessThanOrEqual(elements_kind,
1573                                       Int32Constant(HOLEY_DOUBLE_ELEMENTS)));
1574 
1575       VARIABLE(result, MachineRepresentation::kTagged, UndefinedConstant());
1576 
1577       Label move_elements(this);
1578       result.Bind(AllocateHeapNumberWithValue(LoadFixedDoubleArrayElement(
1579           elements, IntPtrConstant(0), MachineType::Float64(), 0,
1580           INTPTR_PARAMETERS, &move_elements)));
1581       Goto(&move_elements);
1582       BIND(&move_elements);
1583 
1584       int32_t header_size = FixedDoubleArray::kHeaderSize - kHeapObjectTag;
1585       Node* memmove =
1586           ExternalConstant(ExternalReference::libc_memmove_function());
1587       Node* start = IntPtrAdd(
1588           BitcastTaggedToWord(elements),
1589           ElementOffsetFromIndex(IntPtrConstant(0), HOLEY_DOUBLE_ELEMENTS,
1590                                  INTPTR_PARAMETERS, header_size));
1591       CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
1592                      MachineType::Pointer(), MachineType::UintPtr(), memmove,
1593                      start, IntPtrAdd(start, IntPtrConstant(kDoubleSize)),
1594                      IntPtrMul(new_length, IntPtrConstant(kDoubleSize)));
1595       Node* offset = ElementOffsetFromIndex(new_length, HOLEY_DOUBLE_ELEMENTS,
1596                                             INTPTR_PARAMETERS, header_size);
1597       if (Is64()) {
1598         Node* double_hole = Int64Constant(kHoleNanInt64);
1599         StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset,
1600                             double_hole);
1601       } else {
1602         STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32);
1603         Node* double_hole = Int32Constant(kHoleNanLower32);
1604         StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
1605                             double_hole);
1606         StoreNoWriteBarrier(MachineRepresentation::kWord32, elements,
1607                             IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
1608                             double_hole);
1609       }
1610       args.PopAndReturn(result.value());
1611     }
1612 
1613     BIND(&fast_elements_tagged);
1614     {
1615       TNode<FixedArray> elements_fixed_array = CAST(elements);
1616       Node* value = LoadFixedArrayElement(elements_fixed_array, 0);
1617       BuildFastLoop(
1618           IntPtrConstant(0), new_length,
1619           [&](Node* index) {
1620             StoreFixedArrayElement(
1621                 elements_fixed_array, index,
1622                 LoadFixedArrayElement(elements_fixed_array,
1623                                       IntPtrAdd(index, IntPtrConstant(1))));
1624           },
1625           1, ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
1626       StoreFixedArrayElement(elements_fixed_array, new_length,
1627                              TheHoleConstant());
1628       GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
1629       args.PopAndReturn(value);
1630     }
1631 
1632     BIND(&fast_elements_smi);
1633     {
1634       TNode<FixedArray> elements_fixed_array = CAST(elements);
1635       Node* value = LoadFixedArrayElement(elements_fixed_array, 0);
1636       BuildFastLoop(
1637           IntPtrConstant(0), new_length,
1638           [&](Node* index) {
1639             StoreFixedArrayElement(
1640                 elements_fixed_array, index,
1641                 LoadFixedArrayElement(elements_fixed_array,
1642                                       IntPtrAdd(index, IntPtrConstant(1))),
1643                 SKIP_WRITE_BARRIER);
1644           },
1645           1, ParameterMode::INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
1646       StoreFixedArrayElement(elements_fixed_array, new_length,
1647                              TheHoleConstant());
1648       GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
1649       args.PopAndReturn(value);
1650     }
1651 
1652     BIND(&return_undefined);
1653     { args.PopAndReturn(UndefinedConstant()); }
1654   }
1655 
1656   BIND(&runtime);
1657   {
1658     // We are not using Parameter(Descriptor::kJSTarget) and loading the value
1659     // from the current frame here in order to reduce register pressure on the
1660     // fast path.
1661     TNode<JSFunction> target = LoadTargetFromFrame();
1662     TailCallBuiltin(Builtins::kArrayShift, context, target, UndefinedConstant(),
1663                     argc);
1664   }
1665 }
1666 
TF_BUILTIN(ExtractFastJSArray,ArrayBuiltinsAssembler)1667 TF_BUILTIN(ExtractFastJSArray, ArrayBuiltinsAssembler) {
1668   ParameterMode mode = OptimalParameterMode();
1669   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1670   Node* array = Parameter(Descriptor::kSource);
1671   Node* begin = TaggedToParameter(Parameter(Descriptor::kBegin), mode);
1672   Node* count = TaggedToParameter(Parameter(Descriptor::kCount), mode);
1673 
1674   CSA_ASSERT(this, IsJSArray(array));
1675   CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid()));
1676 
1677   Return(ExtractFastJSArray(context, array, begin, count, mode));
1678 }
1679 
TF_BUILTIN(CloneFastJSArray,ArrayBuiltinsAssembler)1680 TF_BUILTIN(CloneFastJSArray, ArrayBuiltinsAssembler) {
1681   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1682   Node* array = Parameter(Descriptor::kSource);
1683 
1684   CSA_ASSERT(this, IsJSArray(array));
1685   CSA_ASSERT(this, Word32BinaryNot(IsNoElementsProtectorCellInvalid()));
1686 
1687   ParameterMode mode = OptimalParameterMode();
1688   Return(CloneFastJSArray(context, array, mode));
1689 }
1690 
TF_BUILTIN(ArrayFindLoopContinuation,ArrayBuiltinsAssembler)1691 TF_BUILTIN(ArrayFindLoopContinuation, ArrayBuiltinsAssembler) {
1692   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1693   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1694   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1695   Node* this_arg = Parameter(Descriptor::kThisArg);
1696   Node* array = Parameter(Descriptor::kArray);
1697   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
1698   Node* initial_k = Parameter(Descriptor::kInitialK);
1699   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1700   Node* to = Parameter(Descriptor::kTo);
1701 
1702   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1703                                             this_arg, array, object, initial_k,
1704                                             len, to);
1705 
1706   GenerateIteratingArrayBuiltinLoopContinuation(
1707       &ArrayBuiltinsAssembler::FindProcessor,
1708       &ArrayBuiltinsAssembler::NullPostLoopAction,
1709       MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
1710 }
1711 
1712 // Continuation that is called after an eager deoptimization from TF (ex. the
1713 // array changes during iteration).
TF_BUILTIN(ArrayFindLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)1714 TF_BUILTIN(ArrayFindLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
1715   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1716   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1717   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1718   Node* this_arg = Parameter(Descriptor::kThisArg);
1719   Node* initial_k = Parameter(Descriptor::kInitialK);
1720   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1721 
1722   Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
1723                      callbackfn, this_arg, UndefinedConstant(), receiver,
1724                      initial_k, len, UndefinedConstant()));
1725 }
1726 
1727 // Continuation that is called after a lazy deoptimization from TF (ex. the
1728 // callback function is no longer callable).
TF_BUILTIN(ArrayFindLoopLazyDeoptContinuation,ArrayBuiltinsAssembler)1729 TF_BUILTIN(ArrayFindLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
1730   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1731   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1732   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1733   Node* this_arg = Parameter(Descriptor::kThisArg);
1734   Node* initial_k = Parameter(Descriptor::kInitialK);
1735   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1736 
1737   Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
1738                      callbackfn, this_arg, UndefinedConstant(), receiver,
1739                      initial_k, len, UndefinedConstant()));
1740 }
1741 
1742 // Continuation that is called after a lazy deoptimization from TF that happens
1743 // right after the callback and it's returned value must be handled before
1744 // iteration continues.
TF_BUILTIN(ArrayFindLoopAfterCallbackLazyDeoptContinuation,ArrayBuiltinsAssembler)1745 TF_BUILTIN(ArrayFindLoopAfterCallbackLazyDeoptContinuation,
1746            ArrayBuiltinsAssembler) {
1747   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1748   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1749   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1750   Node* this_arg = Parameter(Descriptor::kThisArg);
1751   Node* initial_k = Parameter(Descriptor::kInitialK);
1752   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1753   Node* found_value = Parameter(Descriptor::kFoundValue);
1754   Node* is_found = Parameter(Descriptor::kIsFound);
1755 
1756   // This custom lazy deopt point is right after the callback. find() needs
1757   // to pick up at the next step, which is returning the element if the callback
1758   // value is truthy.  Otherwise, continue the search by calling the
1759   // continuation.
1760   Label if_true(this), if_false(this);
1761   BranchIfToBooleanIsTrue(is_found, &if_true, &if_false);
1762   BIND(&if_true);
1763   Return(found_value);
1764   BIND(&if_false);
1765   Return(CallBuiltin(Builtins::kArrayFindLoopContinuation, context, receiver,
1766                      callbackfn, this_arg, UndefinedConstant(), receiver,
1767                      initial_k, len, UndefinedConstant()));
1768 }
1769 
1770 // ES #sec-get-%typedarray%.prototype.find
TF_BUILTIN(ArrayPrototypeFind,ArrayBuiltinsAssembler)1771 TF_BUILTIN(ArrayPrototypeFind, ArrayBuiltinsAssembler) {
1772   TNode<IntPtrT> argc =
1773       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
1774   CodeStubArguments args(this, argc);
1775   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1776   TNode<Object> receiver = args.GetReceiver();
1777   Node* callbackfn = args.GetOptionalArgumentValue(0);
1778   Node* this_arg = args.GetOptionalArgumentValue(1);
1779 
1780   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
1781 
1782   GenerateIteratingArrayBuiltinBody(
1783       "Array.prototype.find", &ArrayBuiltinsAssembler::FindResultGenerator,
1784       &ArrayBuiltinsAssembler::FindProcessor,
1785       &ArrayBuiltinsAssembler::NullPostLoopAction,
1786       Builtins::CallableFor(isolate(), Builtins::kArrayFindLoopContinuation),
1787       MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
1788 }
1789 
TF_BUILTIN(ArrayFindIndexLoopContinuation,ArrayBuiltinsAssembler)1790 TF_BUILTIN(ArrayFindIndexLoopContinuation, ArrayBuiltinsAssembler) {
1791   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1792   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1793   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1794   Node* this_arg = Parameter(Descriptor::kThisArg);
1795   Node* array = Parameter(Descriptor::kArray);
1796   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
1797   Node* initial_k = Parameter(Descriptor::kInitialK);
1798   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1799   Node* to = Parameter(Descriptor::kTo);
1800 
1801   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1802                                             this_arg, array, object, initial_k,
1803                                             len, to);
1804 
1805   GenerateIteratingArrayBuiltinLoopContinuation(
1806       &ArrayBuiltinsAssembler::FindIndexProcessor,
1807       &ArrayBuiltinsAssembler::NullPostLoopAction,
1808       MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
1809 }
1810 
TF_BUILTIN(ArrayFindIndexLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)1811 TF_BUILTIN(ArrayFindIndexLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
1812   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1813   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1814   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1815   Node* this_arg = Parameter(Descriptor::kThisArg);
1816   Node* initial_k = Parameter(Descriptor::kInitialK);
1817   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1818 
1819   Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
1820                      receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
1821                      initial_k, len, UndefinedConstant()));
1822 }
1823 
TF_BUILTIN(ArrayFindIndexLoopLazyDeoptContinuation,ArrayBuiltinsAssembler)1824 TF_BUILTIN(ArrayFindIndexLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
1825   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1826   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1827   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1828   Node* this_arg = Parameter(Descriptor::kThisArg);
1829   Node* initial_k = Parameter(Descriptor::kInitialK);
1830   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1831 
1832   Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
1833                      receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
1834                      initial_k, len, UndefinedConstant()));
1835 }
1836 
TF_BUILTIN(ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation,ArrayBuiltinsAssembler)1837 TF_BUILTIN(ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation,
1838            ArrayBuiltinsAssembler) {
1839   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1840   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1841   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1842   Node* this_arg = Parameter(Descriptor::kThisArg);
1843   Node* initial_k = Parameter(Descriptor::kInitialK);
1844   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
1845   Node* found_value = Parameter(Descriptor::kFoundValue);
1846   Node* is_found = Parameter(Descriptor::kIsFound);
1847 
1848   // This custom lazy deopt point is right after the callback. find() needs
1849   // to pick up at the next step, which is returning the element if the callback
1850   // value is truthy.  Otherwise, continue the search by calling the
1851   // continuation.
1852   Label if_true(this), if_false(this);
1853   BranchIfToBooleanIsTrue(is_found, &if_true, &if_false);
1854   BIND(&if_true);
1855   Return(found_value);
1856   BIND(&if_false);
1857   Return(CallBuiltin(Builtins::kArrayFindIndexLoopContinuation, context,
1858                      receiver, callbackfn, this_arg, SmiConstant(-1), receiver,
1859                      initial_k, len, UndefinedConstant()));
1860 }
1861 
1862 // ES #sec-get-%typedarray%.prototype.findIndex
TF_BUILTIN(ArrayPrototypeFindIndex,ArrayBuiltinsAssembler)1863 TF_BUILTIN(ArrayPrototypeFindIndex, ArrayBuiltinsAssembler) {
1864   TNode<IntPtrT> argc =
1865       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
1866   CodeStubArguments args(this, argc);
1867   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1868   TNode<Object> receiver = args.GetReceiver();
1869   Node* callbackfn = args.GetOptionalArgumentValue(0);
1870   Node* this_arg = args.GetOptionalArgumentValue(1);
1871 
1872   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
1873 
1874   GenerateIteratingArrayBuiltinBody(
1875       "Array.prototype.findIndex",
1876       &ArrayBuiltinsAssembler::FindIndexResultGenerator,
1877       &ArrayBuiltinsAssembler::FindIndexProcessor,
1878       &ArrayBuiltinsAssembler::NullPostLoopAction,
1879       Builtins::CallableFor(isolate(),
1880                             Builtins::kArrayFindIndexLoopContinuation),
1881       MissingPropertyMode::kUseUndefined, ForEachDirection::kForward);
1882 }
1883 
1884 class ArrayPopulatorAssembler : public CodeStubAssembler {
1885  public:
ArrayPopulatorAssembler(compiler::CodeAssemblerState * state)1886   explicit ArrayPopulatorAssembler(compiler::CodeAssemblerState* state)
1887       : CodeStubAssembler(state) {}
1888 
ConstructArrayLike(TNode<Context> context,TNode<Object> receiver)1889   TNode<Object> ConstructArrayLike(TNode<Context> context,
1890                                    TNode<Object> receiver) {
1891     TVARIABLE(Object, array);
1892     Label is_constructor(this), is_not_constructor(this), done(this);
1893     GotoIf(TaggedIsSmi(receiver), &is_not_constructor);
1894     Branch(IsConstructor(CAST(receiver)), &is_constructor, &is_not_constructor);
1895 
1896     BIND(&is_constructor);
1897     {
1898       array = CAST(
1899           ConstructJS(CodeFactory::Construct(isolate()), context, receiver));
1900       Goto(&done);
1901     }
1902 
1903     BIND(&is_not_constructor);
1904     {
1905       Label allocate_js_array(this);
1906 
1907       TNode<Map> array_map = CAST(LoadContextElement(
1908           context, Context::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX));
1909 
1910       array = CAST(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map,
1911                                    SmiConstant(0), SmiConstant(0), nullptr,
1912                                    ParameterMode::SMI_PARAMETERS));
1913       Goto(&done);
1914     }
1915 
1916     BIND(&done);
1917     return array.value();
1918   }
1919 
ConstructArrayLike(TNode<Context> context,TNode<Object> receiver,TNode<Number> length)1920   TNode<Object> ConstructArrayLike(TNode<Context> context,
1921                                    TNode<Object> receiver,
1922                                    TNode<Number> length) {
1923     TVARIABLE(Object, array);
1924     Label is_constructor(this), is_not_constructor(this), done(this);
1925     CSA_ASSERT(this, IsNumberNormalized(length));
1926     GotoIf(TaggedIsSmi(receiver), &is_not_constructor);
1927     Branch(IsConstructor(CAST(receiver)), &is_constructor, &is_not_constructor);
1928 
1929     BIND(&is_constructor);
1930     {
1931       array = CAST(ConstructJS(CodeFactory::Construct(isolate()), context,
1932                                receiver, length));
1933       Goto(&done);
1934     }
1935 
1936     BIND(&is_not_constructor);
1937     {
1938       Label allocate_js_array(this);
1939 
1940       Label next(this), runtime(this, Label::kDeferred);
1941       TNode<Smi> limit = SmiConstant(JSArray::kInitialMaxFastElementArray);
1942       CSA_ASSERT_BRANCH(this, [=](Label* ok, Label* not_ok) {
1943         BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual,
1944                                            length, SmiConstant(0), ok, not_ok);
1945       });
1946       // This check also transitively covers the case where length is too big
1947       // to be representable by a SMI and so is not usable with
1948       // AllocateJSArray.
1949       BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, length,
1950                                          limit, &runtime, &next);
1951 
1952       BIND(&runtime);
1953       {
1954         TNode<Context> native_context = LoadNativeContext(context);
1955         TNode<JSFunction> array_function = CAST(
1956             LoadContextElement(native_context, Context::ARRAY_FUNCTION_INDEX));
1957         array = CallRuntime(Runtime::kNewArray, context, array_function, length,
1958                             array_function, UndefinedConstant());
1959         Goto(&done);
1960       }
1961 
1962       BIND(&next);
1963       CSA_ASSERT(this, TaggedIsSmi(length));
1964 
1965       TNode<Map> array_map = CAST(LoadContextElement(
1966           context, Context::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX));
1967 
1968       // TODO(delphick): Consider using
1969       // AllocateUninitializedJSArrayWithElements to avoid initializing an
1970       // array and then writing over it.
1971       array = CAST(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, length,
1972                                    SmiConstant(0), nullptr,
1973                                    ParameterMode::SMI_PARAMETERS));
1974       Goto(&done);
1975     }
1976 
1977     BIND(&done);
1978     return array.value();
1979   }
1980 
GenerateSetLength(TNode<Context> context,TNode<Object> array,TNode<Number> length)1981   void GenerateSetLength(TNode<Context> context, TNode<Object> array,
1982                          TNode<Number> length) {
1983     Label fast(this), runtime(this), done(this);
1984     // There's no need to set the length, if
1985     // 1) the array is a fast JS array and
1986     // 2) the new length is equal to the old length.
1987     // as the set is not observable. Otherwise fall back to the run-time.
1988 
1989     // 1) Check that the array has fast elements.
1990     // TODO(delphick): Consider changing this since it does an an unnecessary
1991     // check for SMIs.
1992     // TODO(delphick): Also we could hoist this to after the array construction
1993     // and copy the args into array in the same way as the Array constructor.
1994     BranchIfFastJSArray(array, context, &fast, &runtime);
1995 
1996     BIND(&fast);
1997     {
1998       TNode<JSArray> fast_array = CAST(array);
1999 
2000       TNode<Smi> length_smi = CAST(length);
2001       TNode<Smi> old_length = LoadFastJSArrayLength(fast_array);
2002       CSA_ASSERT(this, TaggedIsPositiveSmi(old_length));
2003 
2004       // 2) If the created array's length matches the required length, then
2005       //    there's nothing else to do. Otherwise use the runtime to set the
2006       //    property as that will insert holes into excess elements or shrink
2007       //    the backing store as appropriate.
2008       Branch(SmiNotEqual(length_smi, old_length), &runtime, &done);
2009     }
2010 
2011     BIND(&runtime);
2012     {
2013       SetPropertyStrict(context, array,
2014                         CodeStubAssembler::LengthStringConstant(), length);
2015       Goto(&done);
2016     }
2017 
2018     BIND(&done);
2019   }
2020 };
2021 
2022 // ES #sec-array.from
TF_BUILTIN(ArrayFrom,ArrayPopulatorAssembler)2023 TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
2024   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2025   TNode<Int32T> argc =
2026       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
2027 
2028   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
2029 
2030   TNode<Object> map_function = args.GetOptionalArgumentValue(1);
2031 
2032   // If map_function is not undefined, then ensure it's callable else throw.
2033   {
2034     Label no_error(this), error(this);
2035     GotoIf(IsUndefined(map_function), &no_error);
2036     GotoIf(TaggedIsSmi(map_function), &error);
2037     Branch(IsCallable(CAST(map_function)), &no_error, &error);
2038 
2039     BIND(&error);
2040     ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_function);
2041 
2042     BIND(&no_error);
2043   }
2044 
2045   Label iterable(this), not_iterable(this), finished(this), if_exception(this);
2046 
2047   TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
2048   TNode<Object> items = args.GetOptionalArgumentValue(0);
2049   // The spec doesn't require ToObject to be called directly on the iterable
2050   // branch, but it's part of GetMethod that is in the spec.
2051   TNode<JSReceiver> array_like = ToObject_Inline(context, items);
2052 
2053   TVARIABLE(Object, array);
2054   TVARIABLE(Number, length);
2055 
2056   // Determine whether items[Symbol.iterator] is defined:
2057   IteratorBuiltinsAssembler iterator_assembler(state());
2058   Node* iterator_method =
2059       iterator_assembler.GetIteratorMethod(context, array_like);
2060   Branch(IsNullOrUndefined(iterator_method), &not_iterable, &iterable);
2061 
2062   BIND(&iterable);
2063   {
2064     TVARIABLE(Number, index, SmiConstant(0));
2065     TVARIABLE(Object, var_exception);
2066     Label loop(this, &index), loop_done(this),
2067         on_exception(this, Label::kDeferred),
2068         index_overflow(this, Label::kDeferred);
2069 
2070     // Check that the method is callable.
2071     {
2072       Label get_method_not_callable(this, Label::kDeferred), next(this);
2073       GotoIf(TaggedIsSmi(iterator_method), &get_method_not_callable);
2074       GotoIfNot(IsCallable(CAST(iterator_method)), &get_method_not_callable);
2075       Goto(&next);
2076 
2077       BIND(&get_method_not_callable);
2078       ThrowTypeError(context, MessageTemplate::kCalledNonCallable,
2079                      iterator_method);
2080 
2081       BIND(&next);
2082     }
2083 
2084     // Construct the output array with empty length.
2085     array = ConstructArrayLike(context, args.GetReceiver());
2086 
2087     // Actually get the iterator and throw if the iterator method does not yield
2088     // one.
2089     IteratorRecord iterator_record =
2090         iterator_assembler.GetIterator(context, items, iterator_method);
2091 
2092     TNode<Context> native_context = LoadNativeContext(context);
2093     TNode<Object> fast_iterator_result_map =
2094         LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
2095 
2096     Goto(&loop);
2097 
2098     BIND(&loop);
2099     {
2100       // Loop while iterator is not done.
2101       TNode<Object> next = CAST(iterator_assembler.IteratorStep(
2102           context, iterator_record, &loop_done, fast_iterator_result_map));
2103       TVARIABLE(Object, value,
2104                 CAST(iterator_assembler.IteratorValue(
2105                     context, next, fast_iterator_result_map)));
2106 
2107       // If a map_function is supplied then call it (using this_arg as
2108       // receiver), on the value returned from the iterator. Exceptions are
2109       // caught so the iterator can be closed.
2110       {
2111         Label next(this);
2112         GotoIf(IsUndefined(map_function), &next);
2113 
2114         CSA_ASSERT(this, IsCallable(CAST(map_function)));
2115         Node* v = CallJS(CodeFactory::Call(isolate()), context, map_function,
2116                          this_arg, value.value(), index.value());
2117         GotoIfException(v, &on_exception, &var_exception);
2118         value = CAST(v);
2119         Goto(&next);
2120         BIND(&next);
2121       }
2122 
2123       // Store the result in the output object (catching any exceptions so the
2124       // iterator can be closed).
2125       Node* define_status =
2126           CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
2127                       index.value(), value.value());
2128       GotoIfException(define_status, &on_exception, &var_exception);
2129 
2130       index = NumberInc(index.value());
2131 
2132       // The spec requires that we throw an exception if index reaches 2^53-1,
2133       // but an empty loop would take >100 days to do this many iterations. To
2134       // actually run for that long would require an iterator that never set
2135       // done to true and a target array which somehow never ran out of memory,
2136       // e.g. a proxy that discarded the values. Ignoring this case just means
2137       // we would repeatedly call CreateDataProperty with index = 2^53.
2138       CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
2139         BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
2140                                            NumberConstant(kMaxSafeInteger), ok,
2141                                            not_ok);
2142       });
2143       Goto(&loop);
2144     }
2145 
2146     BIND(&loop_done);
2147     {
2148       length = index;
2149       Goto(&finished);
2150     }
2151 
2152     BIND(&on_exception);
2153     {
2154       // Close the iterator, rethrowing either the passed exception or
2155       // exceptions thrown during the close.
2156       iterator_assembler.IteratorCloseOnException(context, iterator_record,
2157                                                   &var_exception);
2158     }
2159   }
2160 
2161   BIND(&not_iterable);
2162   {
2163     // Treat array_like as an array and try to get its length.
2164     length = ToLength_Inline(
2165         context, GetProperty(context, array_like, factory()->length_string()));
2166 
2167     // Construct an array using the receiver as constructor with the same length
2168     // as the input array.
2169     array = ConstructArrayLike(context, args.GetReceiver(), length.value());
2170 
2171     TVARIABLE(Number, index, SmiConstant(0));
2172 
2173     // TODO(ishell): remove <Object, Object>
2174     GotoIf(WordEqual<Object, Object>(length.value(), SmiConstant(0)),
2175            &finished);
2176 
2177     // Loop from 0 to length-1.
2178     {
2179       Label loop(this, &index);
2180       Goto(&loop);
2181       BIND(&loop);
2182       TVARIABLE(Object, value);
2183 
2184       value = GetProperty(context, array_like, index.value());
2185 
2186       // If a map_function is supplied then call it (using this_arg as
2187       // receiver), on the value retrieved from the array.
2188       {
2189         Label next(this);
2190         GotoIf(IsUndefined(map_function), &next);
2191 
2192         CSA_ASSERT(this, IsCallable(CAST(map_function)));
2193         value = CAST(CallJS(CodeFactory::Call(isolate()), context, map_function,
2194                             this_arg, value.value(), index.value()));
2195         Goto(&next);
2196         BIND(&next);
2197       }
2198 
2199       // Store the result in the output object.
2200       CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
2201                   index.value(), value.value());
2202       index = NumberInc(index.value());
2203       BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
2204                                          length.value(), &loop, &finished);
2205     }
2206   }
2207 
2208   BIND(&finished);
2209 
2210   // Finally set the length on the output and return it.
2211   GenerateSetLength(context, array.value(), length.value());
2212   args.PopAndReturn(array.value());
2213 }
2214 
2215 // ES #sec-array.of
TF_BUILTIN(ArrayOf,ArrayPopulatorAssembler)2216 TF_BUILTIN(ArrayOf, ArrayPopulatorAssembler) {
2217   TNode<Int32T> argc =
2218       UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
2219   TNode<Smi> length = SmiFromInt32(argc);
2220 
2221   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2222 
2223   CodeStubArguments args(this, length, nullptr, ParameterMode::SMI_PARAMETERS);
2224 
2225   TNode<Object> array = ConstructArrayLike(context, args.GetReceiver(), length);
2226 
2227   // TODO(delphick): Avoid using CreateDataProperty on the fast path.
2228   BuildFastLoop(SmiConstant(0), length,
2229                 [=](Node* index) {
2230                   CallRuntime(
2231                       Runtime::kCreateDataProperty, context,
2232                       static_cast<Node*>(array), index,
2233                       args.AtIndex(index, ParameterMode::SMI_PARAMETERS));
2234                 },
2235                 1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
2236 
2237   GenerateSetLength(context, array, length);
2238   args.PopAndReturn(array);
2239 }
2240 
2241 // ES #sec-get-%typedarray%.prototype.find
TF_BUILTIN(TypedArrayPrototypeFind,ArrayBuiltinsAssembler)2242 TF_BUILTIN(TypedArrayPrototypeFind, ArrayBuiltinsAssembler) {
2243   TNode<IntPtrT> argc =
2244       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2245   CodeStubArguments args(this, argc);
2246   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2247   TNode<Object> receiver = args.GetReceiver();
2248   Node* callbackfn = args.GetOptionalArgumentValue(0);
2249   Node* this_arg = args.GetOptionalArgumentValue(1);
2250 
2251   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2252 
2253   GenerateIteratingTypedArrayBuiltinBody(
2254       "%TypedArray%.prototype.find",
2255       &ArrayBuiltinsAssembler::FindResultGenerator,
2256       &ArrayBuiltinsAssembler::FindProcessor,
2257       &ArrayBuiltinsAssembler::NullPostLoopAction);
2258 }
2259 
2260 // ES #sec-get-%typedarray%.prototype.findIndex
TF_BUILTIN(TypedArrayPrototypeFindIndex,ArrayBuiltinsAssembler)2261 TF_BUILTIN(TypedArrayPrototypeFindIndex, ArrayBuiltinsAssembler) {
2262   TNode<IntPtrT> argc =
2263       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2264   CodeStubArguments args(this, argc);
2265   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2266   TNode<Object> receiver = args.GetReceiver();
2267   Node* callbackfn = args.GetOptionalArgumentValue(0);
2268   Node* this_arg = args.GetOptionalArgumentValue(1);
2269 
2270   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2271 
2272   GenerateIteratingTypedArrayBuiltinBody(
2273       "%TypedArray%.prototype.findIndex",
2274       &ArrayBuiltinsAssembler::FindIndexResultGenerator,
2275       &ArrayBuiltinsAssembler::FindIndexProcessor,
2276       &ArrayBuiltinsAssembler::NullPostLoopAction);
2277 }
2278 
TF_BUILTIN(TypedArrayPrototypeForEach,ArrayBuiltinsAssembler)2279 TF_BUILTIN(TypedArrayPrototypeForEach, ArrayBuiltinsAssembler) {
2280   TNode<IntPtrT> argc =
2281       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2282   CodeStubArguments args(this, argc);
2283   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2284   TNode<Object> receiver = args.GetReceiver();
2285   Node* callbackfn = args.GetOptionalArgumentValue(0);
2286   Node* this_arg = args.GetOptionalArgumentValue(1);
2287 
2288   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2289 
2290   GenerateIteratingTypedArrayBuiltinBody(
2291       "%TypedArray%.prototype.forEach",
2292       &ArrayBuiltinsAssembler::ForEachResultGenerator,
2293       &ArrayBuiltinsAssembler::ForEachProcessor,
2294       &ArrayBuiltinsAssembler::NullPostLoopAction);
2295 }
2296 
TF_BUILTIN(ArraySomeLoopLazyDeoptContinuation,ArrayBuiltinsAssembler)2297 TF_BUILTIN(ArraySomeLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2298   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2299   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2300   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2301   Node* this_arg = Parameter(Descriptor::kThisArg);
2302   Node* initial_k = Parameter(Descriptor::kInitialK);
2303   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2304   Node* result = Parameter(Descriptor::kResult);
2305 
2306   // This custom lazy deopt point is right after the callback. every() needs
2307   // to pick up at the next step, which is either continuing to the next
2308   // array element or returning false if {result} is false.
2309   Label true_continue(this), false_continue(this);
2310 
2311   // iii. If selected is true, then...
2312   BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
2313   BIND(&true_continue);
2314   { Return(TrueConstant()); }
2315   BIND(&false_continue);
2316   {
2317     // Increment k.
2318     initial_k = NumberInc(initial_k);
2319 
2320     Return(CallBuiltin(Builtins::kArraySomeLoopContinuation, context, receiver,
2321                        callbackfn, this_arg, FalseConstant(), receiver,
2322                        initial_k, len, UndefinedConstant()));
2323   }
2324 }
2325 
TF_BUILTIN(ArraySomeLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)2326 TF_BUILTIN(ArraySomeLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2327   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2328   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2329   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2330   Node* this_arg = Parameter(Descriptor::kThisArg);
2331   Node* initial_k = Parameter(Descriptor::kInitialK);
2332   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2333 
2334   Return(CallBuiltin(Builtins::kArraySomeLoopContinuation, context, receiver,
2335                      callbackfn, this_arg, FalseConstant(), receiver, initial_k,
2336                      len, UndefinedConstant()));
2337 }
2338 
TF_BUILTIN(ArraySomeLoopContinuation,ArrayBuiltinsAssembler)2339 TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinsAssembler) {
2340   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2341   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2342   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2343   Node* this_arg = Parameter(Descriptor::kThisArg);
2344   Node* array = Parameter(Descriptor::kArray);
2345   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2346   Node* initial_k = Parameter(Descriptor::kInitialK);
2347   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2348   Node* to = Parameter(Descriptor::kTo);
2349 
2350   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
2351                                             this_arg, array, object, initial_k,
2352                                             len, to);
2353 
2354   GenerateIteratingArrayBuiltinLoopContinuation(
2355       &ArrayBuiltinsAssembler::SomeProcessor,
2356       &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2357 }
2358 
TF_BUILTIN(ArraySome,ArrayBuiltinsAssembler)2359 TF_BUILTIN(ArraySome, ArrayBuiltinsAssembler) {
2360   TNode<IntPtrT> argc =
2361       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2362   CodeStubArguments args(this, argc);
2363   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2364   TNode<Object> receiver = args.GetReceiver();
2365   Node* callbackfn = args.GetOptionalArgumentValue(0);
2366   Node* this_arg = args.GetOptionalArgumentValue(1);
2367 
2368   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2369 
2370   GenerateIteratingArrayBuiltinBody(
2371       "Array.prototype.some", &ArrayBuiltinsAssembler::SomeResultGenerator,
2372       &ArrayBuiltinsAssembler::SomeProcessor,
2373       &ArrayBuiltinsAssembler::NullPostLoopAction,
2374       Builtins::CallableFor(isolate(), Builtins::kArraySomeLoopContinuation),
2375       MissingPropertyMode::kSkip);
2376 }
2377 
TF_BUILTIN(TypedArrayPrototypeSome,ArrayBuiltinsAssembler)2378 TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinsAssembler) {
2379   TNode<IntPtrT> argc =
2380       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2381   CodeStubArguments args(this, argc);
2382   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2383   TNode<Object> receiver = args.GetReceiver();
2384   Node* callbackfn = args.GetOptionalArgumentValue(0);
2385   Node* this_arg = args.GetOptionalArgumentValue(1);
2386 
2387   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2388 
2389   GenerateIteratingTypedArrayBuiltinBody(
2390       "%TypedArray%.prototype.some",
2391       &ArrayBuiltinsAssembler::SomeResultGenerator,
2392       &ArrayBuiltinsAssembler::SomeProcessor,
2393       &ArrayBuiltinsAssembler::NullPostLoopAction);
2394 }
2395 
TF_BUILTIN(ArrayEveryLoopLazyDeoptContinuation,ArrayBuiltinsAssembler)2396 TF_BUILTIN(ArrayEveryLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2397   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2398   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2399   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2400   Node* this_arg = Parameter(Descriptor::kThisArg);
2401   Node* initial_k = Parameter(Descriptor::kInitialK);
2402   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2403   Node* result = Parameter(Descriptor::kResult);
2404 
2405   // This custom lazy deopt point is right after the callback. every() needs
2406   // to pick up at the next step, which is either continuing to the next
2407   // array element or returning false if {result} is false.
2408   Label true_continue(this), false_continue(this);
2409 
2410   // iii. If selected is true, then...
2411   BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
2412   BIND(&true_continue);
2413   {
2414     // Increment k.
2415     initial_k = NumberInc(initial_k);
2416 
2417     Return(CallBuiltin(Builtins::kArrayEveryLoopContinuation, context, receiver,
2418                        callbackfn, this_arg, TrueConstant(), receiver,
2419                        initial_k, len, UndefinedConstant()));
2420   }
2421   BIND(&false_continue);
2422   { Return(FalseConstant()); }
2423 }
2424 
TF_BUILTIN(ArrayEveryLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)2425 TF_BUILTIN(ArrayEveryLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2426   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2427   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2428   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2429   Node* this_arg = Parameter(Descriptor::kThisArg);
2430   Node* initial_k = Parameter(Descriptor::kInitialK);
2431   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2432 
2433   Return(CallBuiltin(Builtins::kArrayEveryLoopContinuation, context, receiver,
2434                      callbackfn, this_arg, TrueConstant(), receiver, initial_k,
2435                      len, UndefinedConstant()));
2436 }
2437 
TF_BUILTIN(ArrayEveryLoopContinuation,ArrayBuiltinsAssembler)2438 TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinsAssembler) {
2439   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2440   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2441   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2442   Node* this_arg = Parameter(Descriptor::kThisArg);
2443   Node* array = Parameter(Descriptor::kArray);
2444   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2445   Node* initial_k = Parameter(Descriptor::kInitialK);
2446   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2447   Node* to = Parameter(Descriptor::kTo);
2448 
2449   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
2450                                             this_arg, array, object, initial_k,
2451                                             len, to);
2452 
2453   GenerateIteratingArrayBuiltinLoopContinuation(
2454       &ArrayBuiltinsAssembler::EveryProcessor,
2455       &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2456 }
2457 
TF_BUILTIN(ArrayEvery,ArrayBuiltinsAssembler)2458 TF_BUILTIN(ArrayEvery, ArrayBuiltinsAssembler) {
2459   TNode<IntPtrT> argc =
2460       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2461   CodeStubArguments args(this, argc);
2462   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2463   TNode<Object> receiver = args.GetReceiver();
2464   Node* callbackfn = args.GetOptionalArgumentValue(0);
2465   Node* this_arg = args.GetOptionalArgumentValue(1);
2466 
2467   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2468 
2469   GenerateIteratingArrayBuiltinBody(
2470       "Array.prototype.every", &ArrayBuiltinsAssembler::EveryResultGenerator,
2471       &ArrayBuiltinsAssembler::EveryProcessor,
2472       &ArrayBuiltinsAssembler::NullPostLoopAction,
2473       Builtins::CallableFor(isolate(), Builtins::kArrayEveryLoopContinuation),
2474       MissingPropertyMode::kSkip);
2475 }
2476 
TF_BUILTIN(TypedArrayPrototypeEvery,ArrayBuiltinsAssembler)2477 TF_BUILTIN(TypedArrayPrototypeEvery, ArrayBuiltinsAssembler) {
2478   TNode<IntPtrT> argc =
2479       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2480   CodeStubArguments args(this, argc);
2481   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2482   TNode<Object> receiver = args.GetReceiver();
2483   Node* callbackfn = args.GetOptionalArgumentValue(0);
2484   Node* this_arg = args.GetOptionalArgumentValue(1);
2485 
2486   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2487 
2488   GenerateIteratingTypedArrayBuiltinBody(
2489       "%TypedArray%.prototype.every",
2490       &ArrayBuiltinsAssembler::EveryResultGenerator,
2491       &ArrayBuiltinsAssembler::EveryProcessor,
2492       &ArrayBuiltinsAssembler::NullPostLoopAction);
2493 }
2494 
TF_BUILTIN(ArrayReduceLoopContinuation,ArrayBuiltinsAssembler)2495 TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinsAssembler) {
2496   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2497   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2498   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2499   Node* this_arg = Parameter(Descriptor::kThisArg);
2500   Node* accumulator = Parameter(Descriptor::kAccumulator);
2501   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2502   Node* initial_k = Parameter(Descriptor::kInitialK);
2503   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2504   Node* to = Parameter(Descriptor::kTo);
2505 
2506   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
2507                                             this_arg, accumulator, object,
2508                                             initial_k, len, to);
2509 
2510   GenerateIteratingArrayBuiltinLoopContinuation(
2511       &ArrayBuiltinsAssembler::ReduceProcessor,
2512       &ArrayBuiltinsAssembler::ReducePostLoopAction,
2513       MissingPropertyMode::kSkip);
2514 }
2515 
TF_BUILTIN(ArrayReducePreLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)2516 TF_BUILTIN(ArrayReducePreLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2517   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2518   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2519   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2520   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2521 
2522   // Simulate starting the loop at 0, but ensuring that the accumulator is
2523   // the hole. The continuation stub will search for the initial non-hole
2524   // element, rightly throwing an exception if not found.
2525   Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
2526                      callbackfn, UndefinedConstant(), TheHoleConstant(),
2527                      receiver, SmiConstant(0), len, UndefinedConstant()));
2528 }
2529 
TF_BUILTIN(ArrayReduceLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)2530 TF_BUILTIN(ArrayReduceLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2531   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2532   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2533   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2534   Node* accumulator = Parameter(Descriptor::kAccumulator);
2535   Node* initial_k = Parameter(Descriptor::kInitialK);
2536   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2537 
2538   Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
2539                      callbackfn, UndefinedConstant(), accumulator, receiver,
2540                      initial_k, len, UndefinedConstant()));
2541 }
2542 
TF_BUILTIN(ArrayReduceLoopLazyDeoptContinuation,ArrayBuiltinsAssembler)2543 TF_BUILTIN(ArrayReduceLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2544   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2545   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2546   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2547   Node* initial_k = Parameter(Descriptor::kInitialK);
2548   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2549   Node* result = Parameter(Descriptor::kResult);
2550 
2551   Return(CallBuiltin(Builtins::kArrayReduceLoopContinuation, context, receiver,
2552                      callbackfn, UndefinedConstant(), result, receiver,
2553                      initial_k, len, UndefinedConstant()));
2554 }
2555 
TF_BUILTIN(ArrayReduce,ArrayBuiltinsAssembler)2556 TF_BUILTIN(ArrayReduce, ArrayBuiltinsAssembler) {
2557   TNode<IntPtrT> argc =
2558       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2559   CodeStubArguments args(this, argc);
2560   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2561   TNode<Object> receiver = args.GetReceiver();
2562   Node* callbackfn = args.GetOptionalArgumentValue(0);
2563   Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
2564 
2565   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
2566                                 argc);
2567 
2568   GenerateIteratingArrayBuiltinBody(
2569       "Array.prototype.reduce", &ArrayBuiltinsAssembler::ReduceResultGenerator,
2570       &ArrayBuiltinsAssembler::ReduceProcessor,
2571       &ArrayBuiltinsAssembler::ReducePostLoopAction,
2572       Builtins::CallableFor(isolate(), Builtins::kArrayReduceLoopContinuation),
2573       MissingPropertyMode::kSkip);
2574 }
2575 
TF_BUILTIN(TypedArrayPrototypeReduce,ArrayBuiltinsAssembler)2576 TF_BUILTIN(TypedArrayPrototypeReduce, ArrayBuiltinsAssembler) {
2577   TNode<IntPtrT> argc =
2578       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2579   CodeStubArguments args(this, argc);
2580   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2581   TNode<Object> receiver = args.GetReceiver();
2582   Node* callbackfn = args.GetOptionalArgumentValue(0);
2583   Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
2584 
2585   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
2586                                 argc);
2587 
2588   GenerateIteratingTypedArrayBuiltinBody(
2589       "%TypedArray%.prototype.reduce",
2590       &ArrayBuiltinsAssembler::ReduceResultGenerator,
2591       &ArrayBuiltinsAssembler::ReduceProcessor,
2592       &ArrayBuiltinsAssembler::ReducePostLoopAction);
2593 }
2594 
TF_BUILTIN(ArrayReduceRightLoopContinuation,ArrayBuiltinsAssembler)2595 TF_BUILTIN(ArrayReduceRightLoopContinuation, ArrayBuiltinsAssembler) {
2596   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2597   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2598   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2599   Node* this_arg = Parameter(Descriptor::kThisArg);
2600   Node* accumulator = Parameter(Descriptor::kAccumulator);
2601   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2602   Node* initial_k = Parameter(Descriptor::kInitialK);
2603   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2604   Node* to = Parameter(Descriptor::kTo);
2605 
2606   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
2607                                             this_arg, accumulator, object,
2608                                             initial_k, len, to);
2609 
2610   GenerateIteratingArrayBuiltinLoopContinuation(
2611       &ArrayBuiltinsAssembler::ReduceProcessor,
2612       &ArrayBuiltinsAssembler::ReducePostLoopAction, MissingPropertyMode::kSkip,
2613       ForEachDirection::kReverse);
2614 }
2615 
TF_BUILTIN(ArrayReduceRightPreLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)2616 TF_BUILTIN(ArrayReduceRightPreLoopEagerDeoptContinuation,
2617            ArrayBuiltinsAssembler) {
2618   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2619   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2620   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2621   TNode<Smi> len = CAST(Parameter(Descriptor::kLength));
2622 
2623   // Simulate starting the loop at 0, but ensuring that the accumulator is
2624   // the hole. The continuation stub will search for the initial non-hole
2625   // element, rightly throwing an exception if not found.
2626   Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
2627                      receiver, callbackfn, UndefinedConstant(),
2628                      TheHoleConstant(), receiver, SmiSub(len, SmiConstant(1)),
2629                      len, UndefinedConstant()));
2630 }
2631 
TF_BUILTIN(ArrayReduceRightLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)2632 TF_BUILTIN(ArrayReduceRightLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2633   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2634   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2635   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2636   Node* accumulator = Parameter(Descriptor::kAccumulator);
2637   Node* initial_k = Parameter(Descriptor::kInitialK);
2638   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2639 
2640   Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
2641                      receiver, callbackfn, UndefinedConstant(), accumulator,
2642                      receiver, initial_k, len, UndefinedConstant()));
2643 }
2644 
TF_BUILTIN(ArrayReduceRightLoopLazyDeoptContinuation,ArrayBuiltinsAssembler)2645 TF_BUILTIN(ArrayReduceRightLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2646   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2647   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2648   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2649   Node* initial_k = Parameter(Descriptor::kInitialK);
2650   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2651   Node* result = Parameter(Descriptor::kResult);
2652 
2653   Return(CallBuiltin(Builtins::kArrayReduceRightLoopContinuation, context,
2654                      receiver, callbackfn, UndefinedConstant(), result,
2655                      receiver, initial_k, len, UndefinedConstant()));
2656 }
2657 
TF_BUILTIN(ArrayReduceRight,ArrayBuiltinsAssembler)2658 TF_BUILTIN(ArrayReduceRight, ArrayBuiltinsAssembler) {
2659   TNode<IntPtrT> argc =
2660       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2661   CodeStubArguments args(this, argc);
2662   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2663   TNode<Object> receiver = args.GetReceiver();
2664   Node* callbackfn = args.GetOptionalArgumentValue(0);
2665   Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
2666 
2667   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
2668                                 argc);
2669 
2670   GenerateIteratingArrayBuiltinBody(
2671       "Array.prototype.reduceRight",
2672       &ArrayBuiltinsAssembler::ReduceResultGenerator,
2673       &ArrayBuiltinsAssembler::ReduceProcessor,
2674       &ArrayBuiltinsAssembler::ReducePostLoopAction,
2675       Builtins::CallableFor(isolate(),
2676                             Builtins::kArrayReduceRightLoopContinuation),
2677       MissingPropertyMode::kSkip, ForEachDirection::kReverse);
2678 }
2679 
TF_BUILTIN(TypedArrayPrototypeReduceRight,ArrayBuiltinsAssembler)2680 TF_BUILTIN(TypedArrayPrototypeReduceRight, ArrayBuiltinsAssembler) {
2681   TNode<IntPtrT> argc =
2682       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2683   CodeStubArguments args(this, argc);
2684   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2685   TNode<Object> receiver = args.GetReceiver();
2686   Node* callbackfn = args.GetOptionalArgumentValue(0);
2687   Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
2688 
2689   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
2690                                 argc);
2691 
2692   GenerateIteratingTypedArrayBuiltinBody(
2693       "%TypedArray%.prototype.reduceRight",
2694       &ArrayBuiltinsAssembler::ReduceResultGenerator,
2695       &ArrayBuiltinsAssembler::ReduceProcessor,
2696       &ArrayBuiltinsAssembler::ReducePostLoopAction,
2697       ForEachDirection::kReverse);
2698 }
2699 
TF_BUILTIN(ArrayFilterLoopContinuation,ArrayBuiltinsAssembler)2700 TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinsAssembler) {
2701   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2702   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2703   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2704   Node* this_arg = Parameter(Descriptor::kThisArg);
2705   Node* array = Parameter(Descriptor::kArray);
2706   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2707   Node* initial_k = Parameter(Descriptor::kInitialK);
2708   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2709   Node* to = Parameter(Descriptor::kTo);
2710 
2711   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
2712                                             this_arg, array, object, initial_k,
2713                                             len, to);
2714 
2715   GenerateIteratingArrayBuiltinLoopContinuation(
2716       &ArrayBuiltinsAssembler::FilterProcessor,
2717       &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2718 }
2719 
TF_BUILTIN(ArrayFilterLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)2720 TF_BUILTIN(ArrayFilterLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2721   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2722   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2723   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2724   Node* this_arg = Parameter(Descriptor::kThisArg);
2725   Node* array = Parameter(Descriptor::kArray);
2726   Node* initial_k = Parameter(Descriptor::kInitialK);
2727   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2728   Node* to = Parameter(Descriptor::kTo);
2729 
2730   Return(CallBuiltin(Builtins::kArrayFilterLoopContinuation, context, receiver,
2731                      callbackfn, this_arg, array, receiver, initial_k, len,
2732                      to));
2733 }
2734 
TF_BUILTIN(ArrayFilterLoopLazyDeoptContinuation,ArrayBuiltinsAssembler)2735 TF_BUILTIN(ArrayFilterLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2736   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2737   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2738   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2739   Node* this_arg = Parameter(Descriptor::kThisArg);
2740   Node* array = Parameter(Descriptor::kArray);
2741   Node* initial_k = Parameter(Descriptor::kInitialK);
2742   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2743   Node* value_k = Parameter(Descriptor::kValueK);
2744   Node* result = Parameter(Descriptor::kResult);
2745 
2746   VARIABLE(to, MachineRepresentation::kTagged, Parameter(Descriptor::kTo));
2747 
2748   // This custom lazy deopt point is right after the callback. filter() needs
2749   // to pick up at the next step, which is setting the callback result in
2750   // the output array. After incrementing k and to, we can glide into the loop
2751   // continuation builtin.
2752 
2753   Label true_continue(this, &to), false_continue(this);
2754 
2755   // iii. If selected is true, then...
2756   BranchIfToBooleanIsTrue(result, &true_continue, &false_continue);
2757   BIND(&true_continue);
2758   {
2759     // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
2760     CallRuntime(Runtime::kCreateDataProperty, context, array, to.value(),
2761                 value_k);
2762     // 2. Increase to by 1.
2763     to.Bind(NumberInc(to.value()));
2764     Goto(&false_continue);
2765   }
2766   BIND(&false_continue);
2767 
2768   // Increment k.
2769   initial_k = NumberInc(initial_k);
2770 
2771   Return(CallBuiltin(Builtins::kArrayFilterLoopContinuation, context, receiver,
2772                      callbackfn, this_arg, array, receiver, initial_k, len,
2773                      to.value()));
2774 }
2775 
TF_BUILTIN(ArrayFilter,ArrayBuiltinsAssembler)2776 TF_BUILTIN(ArrayFilter, ArrayBuiltinsAssembler) {
2777   TNode<IntPtrT> argc =
2778       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2779   CodeStubArguments args(this, argc);
2780   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2781   TNode<Object> receiver = args.GetReceiver();
2782   Node* callbackfn = args.GetOptionalArgumentValue(0);
2783   Node* this_arg = args.GetOptionalArgumentValue(1);
2784 
2785   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2786 
2787   GenerateIteratingArrayBuiltinBody(
2788       "Array.prototype.filter", &ArrayBuiltinsAssembler::FilterResultGenerator,
2789       &ArrayBuiltinsAssembler::FilterProcessor,
2790       &ArrayBuiltinsAssembler::NullPostLoopAction,
2791       Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation),
2792       MissingPropertyMode::kSkip);
2793 }
2794 
TF_BUILTIN(ArrayMapLoopContinuation,ArrayBuiltinsAssembler)2795 TF_BUILTIN(ArrayMapLoopContinuation, ArrayBuiltinsAssembler) {
2796   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2797   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2798   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2799   Node* this_arg = Parameter(Descriptor::kThisArg);
2800   Node* array = Parameter(Descriptor::kArray);
2801   TNode<JSReceiver> object = CAST(Parameter(Descriptor::kObject));
2802   Node* initial_k = Parameter(Descriptor::kInitialK);
2803   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2804   Node* to = Parameter(Descriptor::kTo);
2805 
2806   InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
2807                                             this_arg, array, object, initial_k,
2808                                             len, to);
2809 
2810   GenerateIteratingArrayBuiltinLoopContinuation(
2811       &ArrayBuiltinsAssembler::SpecCompliantMapProcessor,
2812       &ArrayBuiltinsAssembler::NullPostLoopAction, MissingPropertyMode::kSkip);
2813 }
2814 
TF_BUILTIN(ArrayMapLoopEagerDeoptContinuation,ArrayBuiltinsAssembler)2815 TF_BUILTIN(ArrayMapLoopEagerDeoptContinuation, ArrayBuiltinsAssembler) {
2816   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2817   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2818   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2819   Node* this_arg = Parameter(Descriptor::kThisArg);
2820   Node* array = Parameter(Descriptor::kArray);
2821   Node* initial_k = Parameter(Descriptor::kInitialK);
2822   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2823 
2824   Return(CallBuiltin(Builtins::kArrayMapLoopContinuation, context, receiver,
2825                      callbackfn, this_arg, array, receiver, initial_k, len,
2826                      UndefinedConstant()));
2827 }
2828 
TF_BUILTIN(ArrayMapLoopLazyDeoptContinuation,ArrayBuiltinsAssembler)2829 TF_BUILTIN(ArrayMapLoopLazyDeoptContinuation, ArrayBuiltinsAssembler) {
2830   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2831   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
2832   Node* callbackfn = Parameter(Descriptor::kCallbackFn);
2833   Node* this_arg = Parameter(Descriptor::kThisArg);
2834   Node* array = Parameter(Descriptor::kArray);
2835   Node* initial_k = Parameter(Descriptor::kInitialK);
2836   TNode<Number> len = CAST(Parameter(Descriptor::kLength));
2837   Node* result = Parameter(Descriptor::kResult);
2838 
2839   // This custom lazy deopt point is right after the callback. map() needs
2840   // to pick up at the next step, which is setting the callback result in
2841   // the output array. After incrementing k, we can glide into the loop
2842   // continuation builtin.
2843 
2844   // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
2845   CallRuntime(Runtime::kCreateDataProperty, context, array, initial_k, result);
2846   // Then we have to increment k before going on.
2847   initial_k = NumberInc(initial_k);
2848 
2849   Return(CallBuiltin(Builtins::kArrayMapLoopContinuation, context, receiver,
2850                      callbackfn, this_arg, array, receiver, initial_k, len,
2851                      UndefinedConstant()));
2852 }
2853 
TF_BUILTIN(ArrayMap,ArrayBuiltinsAssembler)2854 TF_BUILTIN(ArrayMap, ArrayBuiltinsAssembler) {
2855   TNode<IntPtrT> argc =
2856       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2857   CodeStubArguments args(this, argc);
2858   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2859   TNode<Object> receiver = args.GetReceiver();
2860   Node* callbackfn = args.GetOptionalArgumentValue(0);
2861   Node* this_arg = args.GetOptionalArgumentValue(1);
2862 
2863   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2864 
2865   GenerateIteratingArrayBuiltinBody(
2866       "Array.prototype.map", &ArrayBuiltinsAssembler::MapResultGenerator,
2867       &ArrayBuiltinsAssembler::FastMapProcessor,
2868       &ArrayBuiltinsAssembler::NullPostLoopAction,
2869       Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation),
2870       MissingPropertyMode::kSkip);
2871 }
2872 
TF_BUILTIN(TypedArrayPrototypeMap,ArrayBuiltinsAssembler)2873 TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
2874   TNode<IntPtrT> argc =
2875       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
2876   CodeStubArguments args(this, argc);
2877   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2878   TNode<Object> receiver = args.GetReceiver();
2879   Node* callbackfn = args.GetOptionalArgumentValue(0);
2880   Node* this_arg = args.GetOptionalArgumentValue(1);
2881 
2882   InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, argc);
2883 
2884   GenerateIteratingTypedArrayBuiltinBody(
2885       "%TypedArray%.prototype.map",
2886       &ArrayBuiltinsAssembler::TypedArrayMapResultGenerator,
2887       &ArrayBuiltinsAssembler::TypedArrayMapProcessor,
2888       &ArrayBuiltinsAssembler::NullPostLoopAction);
2889 }
2890 
TF_BUILTIN(ArrayIsArray,CodeStubAssembler)2891 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
2892   TNode<Object> object = CAST(Parameter(Descriptor::kArg));
2893   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
2894 
2895   Label call_runtime(this), return_true(this), return_false(this);
2896 
2897   GotoIf(TaggedIsSmi(object), &return_false);
2898   TNode<Int32T> instance_type = LoadInstanceType(CAST(object));
2899 
2900   GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &return_true);
2901 
2902   // TODO(verwaest): Handle proxies in-place.
2903   Branch(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), &call_runtime,
2904          &return_false);
2905 
2906   BIND(&return_true);
2907   Return(TrueConstant());
2908 
2909   BIND(&return_false);
2910   Return(FalseConstant());
2911 
2912   BIND(&call_runtime);
2913   Return(CallRuntime(Runtime::kArrayIsArray, context, object));
2914 }
2915 
2916 class ArrayIncludesIndexofAssembler : public CodeStubAssembler {
2917  public:
ArrayIncludesIndexofAssembler(compiler::CodeAssemblerState * state)2918   explicit ArrayIncludesIndexofAssembler(compiler::CodeAssemblerState* state)
2919       : CodeStubAssembler(state) {}
2920 
2921   enum SearchVariant { kIncludes, kIndexOf };
2922 
2923   void Generate(SearchVariant variant, TNode<IntPtrT> argc,
2924                 TNode<Context> context);
2925   void GenerateSmiOrObject(SearchVariant variant, Node* context, Node* elements,
2926                            Node* search_element, Node* array_length,
2927                            Node* from_index);
2928   void GeneratePackedDoubles(SearchVariant variant, Node* elements,
2929                              Node* search_element, Node* array_length,
2930                              Node* from_index);
2931   void GenerateHoleyDoubles(SearchVariant variant, Node* elements,
2932                             Node* search_element, Node* array_length,
2933                             Node* from_index);
2934 };
2935 
Generate(SearchVariant variant,TNode<IntPtrT> argc,TNode<Context> context)2936 void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant,
2937                                              TNode<IntPtrT> argc,
2938                                              TNode<Context> context) {
2939   const int kSearchElementArg = 0;
2940   const int kFromIndexArg = 1;
2941 
2942   CodeStubArguments args(this, argc);
2943 
2944   TNode<Object> receiver = args.GetReceiver();
2945   TNode<Object> search_element =
2946       args.GetOptionalArgumentValue(kSearchElementArg);
2947 
2948   Node* intptr_zero = IntPtrConstant(0);
2949 
2950   Label init_index(this), return_not_found(this), call_runtime(this);
2951 
2952   // Take slow path if not a JSArray, if retrieving elements requires
2953   // traversing prototype, or if access checks are required.
2954   BranchIfFastJSArray(receiver, context, &init_index, &call_runtime);
2955 
2956   BIND(&init_index);
2957   VARIABLE(index_var, MachineType::PointerRepresentation(), intptr_zero);
2958   TNode<JSArray> array = CAST(receiver);
2959 
2960   // JSArray length is always a positive Smi for fast arrays.
2961   CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array)));
2962   Node* array_length = LoadFastJSArrayLength(array);
2963   Node* array_length_untagged = SmiUntag(array_length);
2964 
2965   {
2966     // Initialize fromIndex.
2967     Label is_smi(this), is_nonsmi(this), done(this);
2968 
2969     // If no fromIndex was passed, default to 0.
2970     GotoIf(IntPtrLessThanOrEqual(argc, IntPtrConstant(kFromIndexArg)), &done);
2971 
2972     Node* start_from = args.AtIndex(kFromIndexArg);
2973     // Handle Smis and undefined here and everything else in runtime.
2974     // We must be very careful with side effects from the ToInteger conversion,
2975     // as the side effects might render previously checked assumptions about
2976     // the receiver being a fast JSArray and its length invalid.
2977     Branch(TaggedIsSmi(start_from), &is_smi, &is_nonsmi);
2978 
2979     BIND(&is_nonsmi);
2980     {
2981       GotoIfNot(IsUndefined(start_from), &call_runtime);
2982       Goto(&done);
2983     }
2984     BIND(&is_smi);
2985     {
2986       Node* intptr_start_from = SmiUntag(start_from);
2987       index_var.Bind(intptr_start_from);
2988 
2989       GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
2990       // The fromIndex is negative: add it to the array's length.
2991       index_var.Bind(IntPtrAdd(array_length_untagged, index_var.value()));
2992       // Clamp negative results at zero.
2993       GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
2994       index_var.Bind(intptr_zero);
2995       Goto(&done);
2996     }
2997     BIND(&done);
2998   }
2999 
3000   // Fail early if startIndex >= array.length.
3001   GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), array_length_untagged),
3002          &return_not_found);
3003 
3004   Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
3005 
3006   TNode<Int32T> elements_kind = LoadElementsKind(array);
3007   Node* elements = LoadElements(array);
3008   STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
3009   STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
3010   STATIC_ASSERT(PACKED_ELEMENTS == 2);
3011   STATIC_ASSERT(HOLEY_ELEMENTS == 3);
3012   GotoIf(Uint32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
3013          &if_smiorobjects);
3014   GotoIf(Word32Equal(elements_kind, Int32Constant(PACKED_DOUBLE_ELEMENTS)),
3015          &if_packed_doubles);
3016   GotoIf(Word32Equal(elements_kind, Int32Constant(HOLEY_DOUBLE_ELEMENTS)),
3017          &if_holey_doubles);
3018   Goto(&return_not_found);
3019 
3020   BIND(&if_smiorobjects);
3021   {
3022     Callable callable =
3023         (variant == kIncludes)
3024             ? Builtins::CallableFor(isolate(),
3025                                     Builtins::kArrayIncludesSmiOrObject)
3026             : Builtins::CallableFor(isolate(),
3027                                     Builtins::kArrayIndexOfSmiOrObject);
3028     Node* result = CallStub(callable, context, elements, search_element,
3029                             array_length, SmiTag(index_var.value()));
3030     args.PopAndReturn(result);
3031   }
3032 
3033   BIND(&if_packed_doubles);
3034   {
3035     Callable callable =
3036         (variant == kIncludes)
3037             ? Builtins::CallableFor(isolate(),
3038                                     Builtins::kArrayIncludesPackedDoubles)
3039             : Builtins::CallableFor(isolate(),
3040                                     Builtins::kArrayIndexOfPackedDoubles);
3041     Node* result = CallStub(callable, context, elements, search_element,
3042                             array_length, SmiTag(index_var.value()));
3043     args.PopAndReturn(result);
3044   }
3045 
3046   BIND(&if_holey_doubles);
3047   {
3048     Callable callable =
3049         (variant == kIncludes)
3050             ? Builtins::CallableFor(isolate(),
3051                                     Builtins::kArrayIncludesHoleyDoubles)
3052             : Builtins::CallableFor(isolate(),
3053                                     Builtins::kArrayIndexOfHoleyDoubles);
3054     Node* result = CallStub(callable, context, elements, search_element,
3055                             array_length, SmiTag(index_var.value()));
3056     args.PopAndReturn(result);
3057   }
3058 
3059   BIND(&return_not_found);
3060   if (variant == kIncludes) {
3061     args.PopAndReturn(FalseConstant());
3062   } else {
3063     args.PopAndReturn(NumberConstant(-1));
3064   }
3065 
3066   BIND(&call_runtime);
3067   {
3068     Node* start_from =
3069         args.GetOptionalArgumentValue(kFromIndexArg, UndefinedConstant());
3070     Runtime::FunctionId function = variant == kIncludes
3071                                        ? Runtime::kArrayIncludes_Slow
3072                                        : Runtime::kArrayIndexOf;
3073     args.PopAndReturn(
3074         CallRuntime(function, context, array, search_element, start_from));
3075   }
3076 }
3077 
GenerateSmiOrObject(SearchVariant variant,Node * context,Node * elements,Node * search_element,Node * array_length,Node * from_index)3078 void ArrayIncludesIndexofAssembler::GenerateSmiOrObject(
3079     SearchVariant variant, Node* context, Node* elements, Node* search_element,
3080     Node* array_length, Node* from_index) {
3081   VARIABLE(index_var, MachineType::PointerRepresentation(),
3082            SmiUntag(from_index));
3083   VARIABLE(search_num, MachineRepresentation::kFloat64);
3084   Node* array_length_untagged = SmiUntag(array_length);
3085 
3086   Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
3087       string_loop(this), bigint_loop(this, &index_var),
3088       undef_loop(this, &index_var), not_smi(this), not_heap_num(this),
3089       return_found(this), return_not_found(this);
3090 
3091   GotoIfNot(TaggedIsSmi(search_element), &not_smi);
3092   search_num.Bind(SmiToFloat64(search_element));
3093   Goto(&heap_num_loop);
3094 
3095   BIND(&not_smi);
3096   if (variant == kIncludes) {
3097     GotoIf(IsUndefined(search_element), &undef_loop);
3098   }
3099   Node* map = LoadMap(search_element);
3100   GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
3101   search_num.Bind(LoadHeapNumberValue(search_element));
3102   Goto(&heap_num_loop);
3103 
3104   BIND(&not_heap_num);
3105   Node* search_type = LoadMapInstanceType(map);
3106   GotoIf(IsStringInstanceType(search_type), &string_loop);
3107   GotoIf(IsBigIntInstanceType(search_type), &bigint_loop);
3108   Goto(&ident_loop);
3109 
3110   BIND(&ident_loop);
3111   {
3112     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3113               &return_not_found);
3114     Node* element_k = LoadFixedArrayElement(CAST(elements), index_var.value());
3115     GotoIf(WordEqual(element_k, search_element), &return_found);
3116 
3117     Increment(&index_var);
3118     Goto(&ident_loop);
3119   }
3120 
3121   if (variant == kIncludes) {
3122     BIND(&undef_loop);
3123 
3124     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3125               &return_not_found);
3126     Node* element_k = LoadFixedArrayElement(CAST(elements), index_var.value());
3127     GotoIf(IsUndefined(element_k), &return_found);
3128     GotoIf(IsTheHole(element_k), &return_found);
3129 
3130     Increment(&index_var);
3131     Goto(&undef_loop);
3132   }
3133 
3134   BIND(&heap_num_loop);
3135   {
3136     Label nan_loop(this, &index_var), not_nan_loop(this, &index_var);
3137     Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
3138     BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
3139 
3140     BIND(&not_nan_loop);
3141     {
3142       Label continue_loop(this), not_smi(this);
3143       GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3144                 &return_not_found);
3145       Node* element_k =
3146           LoadFixedArrayElement(CAST(elements), index_var.value());
3147       GotoIfNot(TaggedIsSmi(element_k), &not_smi);
3148       Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
3149              &return_found, &continue_loop);
3150 
3151       BIND(&not_smi);
3152       GotoIfNot(IsHeapNumber(element_k), &continue_loop);
3153       Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
3154              &return_found, &continue_loop);
3155 
3156       BIND(&continue_loop);
3157       Increment(&index_var);
3158       Goto(&not_nan_loop);
3159     }
3160 
3161     // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
3162     if (variant == kIncludes) {
3163       BIND(&nan_loop);
3164       Label continue_loop(this);
3165       GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3166                 &return_not_found);
3167       Node* element_k =
3168           LoadFixedArrayElement(CAST(elements), index_var.value());
3169       GotoIf(TaggedIsSmi(element_k), &continue_loop);
3170       GotoIfNot(IsHeapNumber(CAST(element_k)), &continue_loop);
3171       BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_found,
3172                            &continue_loop);
3173 
3174       BIND(&continue_loop);
3175       Increment(&index_var);
3176       Goto(&nan_loop);
3177     }
3178   }
3179 
3180   BIND(&string_loop);
3181   {
3182     TNode<String> search_element_string = CAST(search_element);
3183     Label continue_loop(this), next_iteration(this, &index_var),
3184         slow_compare(this), runtime(this, Label::kDeferred);
3185     TNode<IntPtrT> search_length =
3186         LoadStringLengthAsWord(search_element_string);
3187     Goto(&next_iteration);
3188     BIND(&next_iteration);
3189     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3190               &return_not_found);
3191     Node* element_k = LoadFixedArrayElement(CAST(elements), index_var.value());
3192     GotoIf(TaggedIsSmi(element_k), &continue_loop);
3193     GotoIf(WordEqual(search_element_string, element_k), &return_found);
3194     Node* element_k_type = LoadInstanceType(element_k);
3195     GotoIfNot(IsStringInstanceType(element_k_type), &continue_loop);
3196     Branch(WordEqual(search_length, LoadStringLengthAsWord(element_k)),
3197            &slow_compare, &continue_loop);
3198 
3199     BIND(&slow_compare);
3200     StringBuiltinsAssembler string_asm(state());
3201     string_asm.StringEqual_Core(context, search_element_string, search_type,
3202                                 element_k, element_k_type, search_length,
3203                                 &return_found, &continue_loop, &runtime);
3204     BIND(&runtime);
3205     TNode<Object> result = CallRuntime(Runtime::kStringEqual, context,
3206                                        search_element_string, element_k);
3207     Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
3208 
3209     BIND(&continue_loop);
3210     Increment(&index_var);
3211     Goto(&next_iteration);
3212   }
3213 
3214   BIND(&bigint_loop);
3215   {
3216     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3217               &return_not_found);
3218 
3219     Node* element_k = LoadFixedArrayElement(CAST(elements), index_var.value());
3220     Label continue_loop(this);
3221     GotoIf(TaggedIsSmi(element_k), &continue_loop);
3222     GotoIfNot(IsBigInt(CAST(element_k)), &continue_loop);
3223     TNode<Object> result = CallRuntime(Runtime::kBigIntEqualToBigInt, context,
3224                                        search_element, element_k);
3225     Branch(WordEqual(result, TrueConstant()), &return_found, &continue_loop);
3226 
3227     BIND(&continue_loop);
3228     Increment(&index_var);
3229     Goto(&bigint_loop);
3230   }
3231   BIND(&return_found);
3232   if (variant == kIncludes) {
3233     Return(TrueConstant());
3234   } else {
3235     Return(SmiTag(index_var.value()));
3236   }
3237 
3238   BIND(&return_not_found);
3239   if (variant == kIncludes) {
3240     Return(FalseConstant());
3241   } else {
3242     Return(NumberConstant(-1));
3243   }
3244 }
3245 
GeneratePackedDoubles(SearchVariant variant,Node * elements,Node * search_element,Node * array_length,Node * from_index)3246 void ArrayIncludesIndexofAssembler::GeneratePackedDoubles(SearchVariant variant,
3247                                                           Node* elements,
3248                                                           Node* search_element,
3249                                                           Node* array_length,
3250                                                           Node* from_index) {
3251   VARIABLE(index_var, MachineType::PointerRepresentation(),
3252            SmiUntag(from_index));
3253   Node* array_length_untagged = SmiUntag(array_length);
3254 
3255   Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
3256       hole_loop(this, &index_var), search_notnan(this), return_found(this),
3257       return_not_found(this);
3258   VARIABLE(search_num, MachineRepresentation::kFloat64);
3259   search_num.Bind(Float64Constant(0));
3260 
3261   GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
3262   search_num.Bind(SmiToFloat64(search_element));
3263   Goto(&not_nan_loop);
3264 
3265   BIND(&search_notnan);
3266   GotoIfNot(IsHeapNumber(search_element), &return_not_found);
3267 
3268   search_num.Bind(LoadHeapNumberValue(search_element));
3269 
3270   Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
3271   BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
3272 
3273   BIND(&not_nan_loop);
3274   {
3275     Label continue_loop(this);
3276     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3277               &return_not_found);
3278     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
3279                                                   MachineType::Float64());
3280     Branch(Float64Equal(element_k, search_num.value()), &return_found,
3281            &continue_loop);
3282     BIND(&continue_loop);
3283     Increment(&index_var);
3284     Goto(&not_nan_loop);
3285   }
3286 
3287   // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
3288   if (variant == kIncludes) {
3289     BIND(&nan_loop);
3290     Label continue_loop(this);
3291     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3292               &return_not_found);
3293     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
3294                                                   MachineType::Float64());
3295     BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
3296     BIND(&continue_loop);
3297     Increment(&index_var);
3298     Goto(&nan_loop);
3299   }
3300 
3301   BIND(&return_found);
3302   if (variant == kIncludes) {
3303     Return(TrueConstant());
3304   } else {
3305     Return(SmiTag(index_var.value()));
3306   }
3307 
3308   BIND(&return_not_found);
3309   if (variant == kIncludes) {
3310     Return(FalseConstant());
3311   } else {
3312     Return(NumberConstant(-1));
3313   }
3314 }
3315 
GenerateHoleyDoubles(SearchVariant variant,Node * elements,Node * search_element,Node * array_length,Node * from_index)3316 void ArrayIncludesIndexofAssembler::GenerateHoleyDoubles(SearchVariant variant,
3317                                                          Node* elements,
3318                                                          Node* search_element,
3319                                                          Node* array_length,
3320                                                          Node* from_index) {
3321   VARIABLE(index_var, MachineType::PointerRepresentation(),
3322            SmiUntag(from_index));
3323   Node* array_length_untagged = SmiUntag(array_length);
3324 
3325   Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
3326       hole_loop(this, &index_var), search_notnan(this), return_found(this),
3327       return_not_found(this);
3328   VARIABLE(search_num, MachineRepresentation::kFloat64);
3329   search_num.Bind(Float64Constant(0));
3330 
3331   GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
3332   search_num.Bind(SmiToFloat64(search_element));
3333   Goto(&not_nan_loop);
3334 
3335   BIND(&search_notnan);
3336   if (variant == kIncludes) {
3337     GotoIf(IsUndefined(search_element), &hole_loop);
3338   }
3339   GotoIfNot(IsHeapNumber(search_element), &return_not_found);
3340 
3341   search_num.Bind(LoadHeapNumberValue(search_element));
3342 
3343   Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
3344   BranchIfFloat64IsNaN(search_num.value(), nan_handling, &not_nan_loop);
3345 
3346   BIND(&not_nan_loop);
3347   {
3348     Label continue_loop(this);
3349     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3350               &return_not_found);
3351 
3352     // No need for hole checking here; the following Float64Equal will
3353     // return 'not equal' for holes anyway.
3354     Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
3355                                                   MachineType::Float64());
3356 
3357     Branch(Float64Equal(element_k, search_num.value()), &return_found,
3358            &continue_loop);
3359     BIND(&continue_loop);
3360     Increment(&index_var);
3361     Goto(&not_nan_loop);
3362   }
3363 
3364   // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
3365   if (variant == kIncludes) {
3366     BIND(&nan_loop);
3367     Label continue_loop(this);
3368     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3369               &return_not_found);
3370 
3371     // Load double value or continue if it's the hole NaN.
3372     Node* element_k = LoadFixedDoubleArrayElement(
3373         elements, index_var.value(), MachineType::Float64(), 0,
3374         INTPTR_PARAMETERS, &continue_loop);
3375 
3376     BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
3377     BIND(&continue_loop);
3378     Increment(&index_var);
3379     Goto(&nan_loop);
3380   }
3381 
3382   // Array.p.includes treats the hole as undefined.
3383   if (variant == kIncludes) {
3384     BIND(&hole_loop);
3385     GotoIfNot(UintPtrLessThan(index_var.value(), array_length_untagged),
3386               &return_not_found);
3387 
3388     // Check if the element is a double hole, but don't load it.
3389     LoadFixedDoubleArrayElement(elements, index_var.value(),
3390                                 MachineType::None(), 0, INTPTR_PARAMETERS,
3391                                 &return_found);
3392 
3393     Increment(&index_var);
3394     Goto(&hole_loop);
3395   }
3396 
3397   BIND(&return_found);
3398   if (variant == kIncludes) {
3399     Return(TrueConstant());
3400   } else {
3401     Return(SmiTag(index_var.value()));
3402   }
3403 
3404   BIND(&return_not_found);
3405   if (variant == kIncludes) {
3406     Return(FalseConstant());
3407   } else {
3408     Return(NumberConstant(-1));
3409   }
3410 }
3411 
TF_BUILTIN(ArrayIncludes,ArrayIncludesIndexofAssembler)3412 TF_BUILTIN(ArrayIncludes, ArrayIncludesIndexofAssembler) {
3413   TNode<IntPtrT> argc =
3414       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
3415   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3416 
3417   Generate(kIncludes, argc, context);
3418 }
3419 
TF_BUILTIN(ArrayIncludesSmiOrObject,ArrayIncludesIndexofAssembler)3420 TF_BUILTIN(ArrayIncludesSmiOrObject, ArrayIncludesIndexofAssembler) {
3421   Node* context = Parameter(Descriptor::kContext);
3422   Node* elements = Parameter(Descriptor::kElements);
3423   Node* search_element = Parameter(Descriptor::kSearchElement);
3424   Node* array_length = Parameter(Descriptor::kLength);
3425   Node* from_index = Parameter(Descriptor::kFromIndex);
3426 
3427   GenerateSmiOrObject(kIncludes, context, elements, search_element,
3428                       array_length, from_index);
3429 }
3430 
TF_BUILTIN(ArrayIncludesPackedDoubles,ArrayIncludesIndexofAssembler)3431 TF_BUILTIN(ArrayIncludesPackedDoubles, ArrayIncludesIndexofAssembler) {
3432   Node* elements = Parameter(Descriptor::kElements);
3433   Node* search_element = Parameter(Descriptor::kSearchElement);
3434   Node* array_length = Parameter(Descriptor::kLength);
3435   Node* from_index = Parameter(Descriptor::kFromIndex);
3436 
3437   GeneratePackedDoubles(kIncludes, elements, search_element, array_length,
3438                         from_index);
3439 }
3440 
TF_BUILTIN(ArrayIncludesHoleyDoubles,ArrayIncludesIndexofAssembler)3441 TF_BUILTIN(ArrayIncludesHoleyDoubles, ArrayIncludesIndexofAssembler) {
3442   Node* elements = Parameter(Descriptor::kElements);
3443   Node* search_element = Parameter(Descriptor::kSearchElement);
3444   Node* array_length = Parameter(Descriptor::kLength);
3445   Node* from_index = Parameter(Descriptor::kFromIndex);
3446 
3447   GenerateHoleyDoubles(kIncludes, elements, search_element, array_length,
3448                        from_index);
3449 }
3450 
TF_BUILTIN(ArrayIndexOf,ArrayIncludesIndexofAssembler)3451 TF_BUILTIN(ArrayIndexOf, ArrayIncludesIndexofAssembler) {
3452   TNode<IntPtrT> argc =
3453       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
3454   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3455 
3456   Generate(kIndexOf, argc, context);
3457 }
3458 
TF_BUILTIN(ArrayIndexOfSmiOrObject,ArrayIncludesIndexofAssembler)3459 TF_BUILTIN(ArrayIndexOfSmiOrObject, ArrayIncludesIndexofAssembler) {
3460   Node* context = Parameter(Descriptor::kContext);
3461   Node* elements = Parameter(Descriptor::kElements);
3462   Node* search_element = Parameter(Descriptor::kSearchElement);
3463   Node* array_length = Parameter(Descriptor::kLength);
3464   Node* from_index = Parameter(Descriptor::kFromIndex);
3465 
3466   GenerateSmiOrObject(kIndexOf, context, elements, search_element, array_length,
3467                       from_index);
3468 }
3469 
TF_BUILTIN(ArrayIndexOfPackedDoubles,ArrayIncludesIndexofAssembler)3470 TF_BUILTIN(ArrayIndexOfPackedDoubles, ArrayIncludesIndexofAssembler) {
3471   Node* elements = Parameter(Descriptor::kElements);
3472   Node* search_element = Parameter(Descriptor::kSearchElement);
3473   Node* array_length = Parameter(Descriptor::kLength);
3474   Node* from_index = Parameter(Descriptor::kFromIndex);
3475 
3476   GeneratePackedDoubles(kIndexOf, elements, search_element, array_length,
3477                         from_index);
3478 }
3479 
TF_BUILTIN(ArrayIndexOfHoleyDoubles,ArrayIncludesIndexofAssembler)3480 TF_BUILTIN(ArrayIndexOfHoleyDoubles, ArrayIncludesIndexofAssembler) {
3481   Node* elements = Parameter(Descriptor::kElements);
3482   Node* search_element = Parameter(Descriptor::kSearchElement);
3483   Node* array_length = Parameter(Descriptor::kLength);
3484   Node* from_index = Parameter(Descriptor::kFromIndex);
3485 
3486   GenerateHoleyDoubles(kIndexOf, elements, search_element, array_length,
3487                        from_index);
3488 }
3489 
3490 // ES #sec-array.prototype.values
TF_BUILTIN(ArrayPrototypeValues,CodeStubAssembler)3491 TF_BUILTIN(ArrayPrototypeValues, CodeStubAssembler) {
3492   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3493   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
3494   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
3495                              IterationKind::kValues));
3496 }
3497 
3498 // ES #sec-array.prototype.entries
TF_BUILTIN(ArrayPrototypeEntries,CodeStubAssembler)3499 TF_BUILTIN(ArrayPrototypeEntries, CodeStubAssembler) {
3500   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3501   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
3502   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
3503                              IterationKind::kEntries));
3504 }
3505 
3506 // ES #sec-array.prototype.keys
TF_BUILTIN(ArrayPrototypeKeys,CodeStubAssembler)3507 TF_BUILTIN(ArrayPrototypeKeys, CodeStubAssembler) {
3508   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3509   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
3510   Return(CreateArrayIterator(context, ToObject_Inline(context, receiver),
3511                              IterationKind::kKeys));
3512 }
3513 
3514 // ES #sec-%arrayiteratorprototype%.next
TF_BUILTIN(ArrayIteratorPrototypeNext,CodeStubAssembler)3515 TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
3516   const char* method_name = "Array Iterator.prototype.next";
3517 
3518   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3519   Node* iterator = Parameter(Descriptor::kReceiver);
3520 
3521   VARIABLE(var_done, MachineRepresentation::kTagged, TrueConstant());
3522   VARIABLE(var_value, MachineRepresentation::kTagged, UndefinedConstant());
3523 
3524   Label allocate_entry_if_needed(this);
3525   Label allocate_iterator_result(this);
3526   Label if_typedarray(this), if_other(this, Label::kDeferred), if_array(this),
3527       if_generic(this, Label::kDeferred);
3528   Label set_done(this, Label::kDeferred);
3529 
3530   // If O does not have all of the internal slots of an Array Iterator Instance
3531   // (22.1.5.3), throw a TypeError exception
3532   ThrowIfNotInstanceType(context, iterator, JS_ARRAY_ITERATOR_TYPE,
3533                          method_name);
3534 
3535   // Let a be O.[[IteratedObject]].
3536   TNode<JSReceiver> array =
3537       CAST(LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset));
3538 
3539   // Let index be O.[[ArrayIteratorNextIndex]].
3540   TNode<Number> index =
3541       CAST(LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset));
3542   CSA_ASSERT(this, IsNumberNonNegativeSafeInteger(index));
3543 
3544   // Dispatch based on the type of the {array}.
3545   TNode<Map> array_map = LoadMap(array);
3546   TNode<Int32T> array_type = LoadMapInstanceType(array_map);
3547   GotoIf(InstanceTypeEqual(array_type, JS_ARRAY_TYPE), &if_array);
3548   Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_typedarray,
3549          &if_other);
3550 
3551   BIND(&if_array);
3552   {
3553     // If {array} is a JSArray, then the {index} must be in Unsigned32 range.
3554     CSA_ASSERT(this, IsNumberArrayIndex(index));
3555 
3556     // Check that the {index} is within range for the {array}. We handle all
3557     // kinds of JSArray's here, so we do the computation on Uint32.
3558     TNode<Uint32T> index32 = ChangeNumberToUint32(index);
3559     TNode<Uint32T> length32 =
3560         ChangeNumberToUint32(LoadJSArrayLength(CAST(array)));
3561     GotoIfNot(Uint32LessThan(index32, length32), &set_done);
3562     StoreObjectField(
3563         iterator, JSArrayIterator::kNextIndexOffset,
3564         ChangeUint32ToTagged(Unsigned(Int32Add(index32, Int32Constant(1)))));
3565 
3566     var_done.Bind(FalseConstant());
3567     var_value.Bind(index);
3568 
3569     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
3570                            iterator, JSArrayIterator::kKindOffset),
3571                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
3572            &allocate_iterator_result);
3573 
3574     Label if_hole(this, Label::kDeferred);
3575     TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
3576     TNode<FixedArrayBase> elements = LoadElements(CAST(array));
3577     var_value.Bind(LoadFixedArrayBaseElementAsTagged(
3578         elements, Signed(ChangeUint32ToWord(index32)), elements_kind,
3579         &if_generic, &if_hole));
3580     Goto(&allocate_entry_if_needed);
3581 
3582     BIND(&if_hole);
3583     {
3584       GotoIf(IsNoElementsProtectorCellInvalid(), &if_generic);
3585       var_value.Bind(UndefinedConstant());
3586       Goto(&allocate_entry_if_needed);
3587     }
3588   }
3589 
3590   BIND(&if_other);
3591   {
3592     // We cannot enter here with either JSArray's or JSTypedArray's.
3593     CSA_ASSERT(this, Word32BinaryNot(IsJSArray(array)));
3594     CSA_ASSERT(this, Word32BinaryNot(IsJSTypedArray(array)));
3595 
3596     // Check that the {index} is within the bounds of the {array}s "length".
3597     TNode<Number> length = CAST(
3598         CallBuiltin(Builtins::kToLength, context,
3599                     GetProperty(context, array, factory()->length_string())));
3600     GotoIfNumberGreaterThanOrEqual(index, length, &set_done);
3601     StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset,
3602                      NumberInc(index));
3603 
3604     var_done.Bind(FalseConstant());
3605     var_value.Bind(index);
3606 
3607     Branch(Word32Equal(LoadAndUntagToWord32ObjectField(
3608                            iterator, JSArrayIterator::kKindOffset),
3609                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
3610            &allocate_iterator_result, &if_generic);
3611   }
3612 
3613   BIND(&set_done);
3614   {
3615     // Change the [[ArrayIteratorNextIndex]] such that the {iterator} will
3616     // never produce values anymore, because it will always fail the bounds
3617     // check. Note that this is different from what the specification does,
3618     // which is changing the [[IteratedObject]] to undefined, because leaving
3619     // [[IteratedObject]] alone helps TurboFan to generate better code with
3620     // the inlining in JSCallReducer::ReduceArrayIteratorPrototypeNext().
3621     //
3622     // The terminal value we chose here depends on the type of the {array},
3623     // for JSArray's we use kMaxUInt32 so that TurboFan can always use
3624     // Word32 representation for fast-path indices (and this is safe since
3625     // the "length" of JSArray's is limited to Unsigned32 range). For other
3626     // JSReceiver's we have to use kMaxSafeInteger, since the "length" can
3627     // be any arbitrary value in the safe integer range.
3628     //
3629     // Note specifically that JSTypedArray's will never take this path, so
3630     // we don't need to worry about their maximum value.
3631     CSA_ASSERT(this, Word32BinaryNot(IsJSTypedArray(array)));
3632     TNode<Number> max_length =
3633         SelectConstant(IsJSArray(array), NumberConstant(kMaxUInt32),
3634                        NumberConstant(kMaxSafeInteger));
3635     StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset, max_length);
3636     Goto(&allocate_iterator_result);
3637   }
3638 
3639   BIND(&if_generic);
3640   {
3641     var_value.Bind(GetProperty(context, array, index));
3642     Goto(&allocate_entry_if_needed);
3643   }
3644 
3645   BIND(&if_typedarray);
3646   {
3647     // If {array} is a JSTypedArray, the {index} must always be a Smi.
3648     CSA_ASSERT(this, TaggedIsSmi(index));
3649 
3650     // Check that the {array}s buffer wasn't neutered.
3651     ThrowIfArrayBufferViewBufferIsDetached(context, CAST(array), method_name);
3652 
3653     // If we go outside of the {length}, we don't need to update the
3654     // [[ArrayIteratorNextIndex]] anymore, since a JSTypedArray's
3655     // length cannot change anymore, so this {iterator} will never
3656     // produce values again anyways.
3657     TNode<Smi> length = LoadTypedArrayLength(CAST(array));
3658     GotoIfNot(SmiBelow(CAST(index), length), &allocate_iterator_result);
3659     StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
3660                                    SmiInc(CAST(index)));
3661 
3662     var_done.Bind(FalseConstant());
3663     var_value.Bind(index);
3664 
3665     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
3666                            iterator, JSArrayIterator::kKindOffset),
3667                        Int32Constant(static_cast<int>(IterationKind::kKeys))),
3668            &allocate_iterator_result);
3669 
3670     TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
3671     Node* elements = LoadElements(CAST(array));
3672     Node* base_ptr =
3673         LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
3674     Node* external_ptr =
3675         LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
3676                         MachineType::Pointer());
3677     TNode<WordT> data_ptr =
3678         IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
3679     var_value.Bind(LoadFixedTypedArrayElementAsTagged(data_ptr, CAST(index),
3680                                                       elements_kind));
3681     Goto(&allocate_entry_if_needed);
3682   }
3683 
3684   BIND(&allocate_entry_if_needed);
3685   {
3686     GotoIf(Word32Equal(LoadAndUntagToWord32ObjectField(
3687                            iterator, JSArrayIterator::kKindOffset),
3688                        Int32Constant(static_cast<int>(IterationKind::kValues))),
3689            &allocate_iterator_result);
3690 
3691     Node* result =
3692         AllocateJSIteratorResultForEntry(context, index, var_value.value());
3693     Return(result);
3694   }
3695 
3696   BIND(&allocate_iterator_result);
3697   {
3698     Node* result =
3699         AllocateJSIteratorResult(context, var_value.value(), var_done.value());
3700     Return(result);
3701   }
3702 }
3703 
3704 namespace {
3705 
3706 class ArrayFlattenAssembler : public CodeStubAssembler {
3707  public:
ArrayFlattenAssembler(compiler::CodeAssemblerState * state)3708   explicit ArrayFlattenAssembler(compiler::CodeAssemblerState* state)
3709       : CodeStubAssembler(state) {}
3710 
3711   // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
FlattenIntoArray(Node * context,Node * target,Node * source,Node * source_length,Node * start,Node * depth,Node * mapper_function=nullptr,Node * this_arg=nullptr)3712   Node* FlattenIntoArray(Node* context, Node* target, Node* source,
3713                          Node* source_length, Node* start, Node* depth,
3714                          Node* mapper_function = nullptr,
3715                          Node* this_arg = nullptr) {
3716     CSA_ASSERT(this, IsJSReceiver(target));
3717     CSA_ASSERT(this, IsJSReceiver(source));
3718     CSA_ASSERT(this, IsNumberPositive(source_length));
3719     CSA_ASSERT(this, IsNumberPositive(start));
3720     CSA_ASSERT(this, IsNumber(depth));
3721 
3722     // 1. Let targetIndex be start.
3723     VARIABLE(var_target_index, MachineRepresentation::kTagged, start);
3724 
3725     // 2. Let sourceIndex be 0.
3726     VARIABLE(var_source_index, MachineRepresentation::kTagged, SmiConstant(0));
3727 
3728     // 3. Repeat...
3729     Label loop(this, {&var_target_index, &var_source_index}), done_loop(this);
3730     Goto(&loop);
3731     BIND(&loop);
3732     {
3733       Node* const source_index = var_source_index.value();
3734       Node* const target_index = var_target_index.value();
3735 
3736       // ...while sourceIndex < sourceLen
3737       GotoIfNumberGreaterThanOrEqual(source_index, source_length, &done_loop);
3738 
3739       // a. Let P be ! ToString(sourceIndex).
3740       // b. Let exists be ? HasProperty(source, P).
3741       CSA_ASSERT(this,
3742                  SmiGreaterThanOrEqual(CAST(source_index), SmiConstant(0)));
3743       Node* const exists =
3744           HasProperty(context, source, source_index, kHasProperty);
3745 
3746       // c. If exists is true, then
3747       Label next(this);
3748       GotoIfNot(IsTrue(exists), &next);
3749       {
3750         // i. Let element be ? Get(source, P).
3751         Node* element = GetProperty(context, source, source_index);
3752 
3753         // ii. If mapperFunction is present, then
3754         if (mapper_function != nullptr) {
3755           CSA_ASSERT(this, Word32Or(IsUndefined(mapper_function),
3756                                     IsCallable(mapper_function)));
3757           DCHECK_NOT_NULL(this_arg);
3758 
3759           // 1. Set element to ? Call(mapperFunction, thisArg , « element,
3760           //                          sourceIndex, source »).
3761           element =
3762               CallJS(CodeFactory::Call(isolate()), context, mapper_function,
3763                      this_arg, element, source_index, source);
3764         }
3765 
3766         // iii. Let shouldFlatten be false.
3767         Label if_flatten_array(this), if_flatten_proxy(this, Label::kDeferred),
3768             if_noflatten(this);
3769         // iv. If depth > 0, then
3770         GotoIfNumberGreaterThanOrEqual(SmiConstant(0), depth, &if_noflatten);
3771         // 1. Set shouldFlatten to ? IsArray(element).
3772         GotoIf(TaggedIsSmi(element), &if_noflatten);
3773         GotoIf(IsJSArray(element), &if_flatten_array);
3774         GotoIfNot(IsJSProxy(element), &if_noflatten);
3775         Branch(IsTrue(CallRuntime(Runtime::kArrayIsArray, context, element)),
3776                &if_flatten_proxy, &if_noflatten);
3777 
3778         BIND(&if_flatten_array);
3779         {
3780           CSA_ASSERT(this, IsJSArray(element));
3781 
3782           // 1. Let elementLen be ? ToLength(? Get(element, "length")).
3783           Node* const element_length =
3784               LoadObjectField(element, JSArray::kLengthOffset);
3785 
3786           // 2. Set targetIndex to ? FlattenIntoArray(target, element,
3787           //                                          elementLen, targetIndex,
3788           //                                          depth - 1).
3789           var_target_index.Bind(
3790               CallBuiltin(Builtins::kFlattenIntoArray, context, target, element,
3791                           element_length, target_index, NumberDec(depth)));
3792           Goto(&next);
3793         }
3794 
3795         BIND(&if_flatten_proxy);
3796         {
3797           CSA_ASSERT(this, IsJSProxy(element));
3798 
3799           // 1. Let elementLen be ? ToLength(? Get(element, "length")).
3800           Node* const element_length = ToLength_Inline(
3801               context, GetProperty(context, element, LengthStringConstant()));
3802 
3803           // 2. Set targetIndex to ? FlattenIntoArray(target, element,
3804           //                                          elementLen, targetIndex,
3805           //                                          depth - 1).
3806           var_target_index.Bind(
3807               CallBuiltin(Builtins::kFlattenIntoArray, context, target, element,
3808                           element_length, target_index, NumberDec(depth)));
3809           Goto(&next);
3810         }
3811 
3812         BIND(&if_noflatten);
3813         {
3814           // 1. If targetIndex >= 2^53-1, throw a TypeError exception.
3815           Label throw_error(this, Label::kDeferred);
3816           GotoIfNumberGreaterThanOrEqual(
3817               target_index, NumberConstant(kMaxSafeInteger), &throw_error);
3818 
3819           // 2. Perform ? CreateDataPropertyOrThrow(target,
3820           //                                        ! ToString(targetIndex),
3821           //                                        element).
3822           CallRuntime(Runtime::kCreateDataProperty, context, target,
3823                       target_index, element);
3824 
3825           // 3. Increase targetIndex by 1.
3826           var_target_index.Bind(NumberInc(target_index));
3827           Goto(&next);
3828 
3829           BIND(&throw_error);
3830           ThrowTypeError(context, MessageTemplate::kFlattenPastSafeLength,
3831                          source_length, target_index);
3832         }
3833       }
3834       BIND(&next);
3835 
3836       // d. Increase sourceIndex by 1.
3837       var_source_index.Bind(NumberInc(source_index));
3838       Goto(&loop);
3839     }
3840 
3841     BIND(&done_loop);
3842     return var_target_index.value();
3843   }
3844 };
3845 
3846 }  // namespace
3847 
3848 // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
TF_BUILTIN(FlattenIntoArray,ArrayFlattenAssembler)3849 TF_BUILTIN(FlattenIntoArray, ArrayFlattenAssembler) {
3850   Node* const context = Parameter(Descriptor::kContext);
3851   Node* const target = Parameter(Descriptor::kTarget);
3852   Node* const source = Parameter(Descriptor::kSource);
3853   Node* const source_length = Parameter(Descriptor::kSourceLength);
3854   Node* const start = Parameter(Descriptor::kStart);
3855   Node* const depth = Parameter(Descriptor::kDepth);
3856 
3857   Return(
3858       FlattenIntoArray(context, target, source, source_length, start, depth));
3859 }
3860 
3861 // https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
TF_BUILTIN(FlatMapIntoArray,ArrayFlattenAssembler)3862 TF_BUILTIN(FlatMapIntoArray, ArrayFlattenAssembler) {
3863   Node* const context = Parameter(Descriptor::kContext);
3864   Node* const target = Parameter(Descriptor::kTarget);
3865   Node* const source = Parameter(Descriptor::kSource);
3866   Node* const source_length = Parameter(Descriptor::kSourceLength);
3867   Node* const start = Parameter(Descriptor::kStart);
3868   Node* const depth = Parameter(Descriptor::kDepth);
3869   Node* const mapper_function = Parameter(Descriptor::kMapperFunction);
3870   Node* const this_arg = Parameter(Descriptor::kThisArg);
3871 
3872   Return(FlattenIntoArray(context, target, source, source_length, start, depth,
3873                           mapper_function, this_arg));
3874 }
3875 
3876 // https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flat
TF_BUILTIN(ArrayPrototypeFlat,CodeStubAssembler)3877 TF_BUILTIN(ArrayPrototypeFlat, CodeStubAssembler) {
3878   Node* const argc =
3879       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
3880   CodeStubArguments args(this, argc);
3881   Node* const context = Parameter(Descriptor::kContext);
3882   Node* const receiver = args.GetReceiver();
3883   Node* const depth = args.GetOptionalArgumentValue(0);
3884 
3885   // 1. Let O be ? ToObject(this value).
3886   Node* const o = ToObject_Inline(CAST(context), CAST(receiver));
3887 
3888   // 2. Let sourceLen be ? ToLength(? Get(O, "length")).
3889   Node* const source_length =
3890       ToLength_Inline(context, GetProperty(context, o, LengthStringConstant()));
3891 
3892   // 3. Let depthNum be 1.
3893   VARIABLE(var_depth_num, MachineRepresentation::kTagged, SmiConstant(1));
3894 
3895   // 4. If depth is not undefined, then
3896   Label done(this);
3897   GotoIf(IsUndefined(depth), &done);
3898   {
3899     // a. Set depthNum to ? ToInteger(depth).
3900     var_depth_num.Bind(ToInteger_Inline(context, depth));
3901     Goto(&done);
3902   }
3903   BIND(&done);
3904 
3905   // 5. Let A be ? ArraySpeciesCreate(O, 0).
3906   Node* const constructor =
3907       CallRuntime(Runtime::kArraySpeciesConstructor, context, o);
3908   Node* const a = ConstructJS(CodeFactory::Construct(isolate()), context,
3909                               constructor, SmiConstant(0));
3910 
3911   // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
3912   CallBuiltin(Builtins::kFlattenIntoArray, context, a, o, source_length,
3913               SmiConstant(0), var_depth_num.value());
3914 
3915   // 7. Return A.
3916   args.PopAndReturn(a);
3917 }
3918 
3919 // https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap
TF_BUILTIN(ArrayPrototypeFlatMap,CodeStubAssembler)3920 TF_BUILTIN(ArrayPrototypeFlatMap, CodeStubAssembler) {
3921   Node* const argc =
3922       ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
3923   CodeStubArguments args(this, argc);
3924   Node* const context = Parameter(Descriptor::kContext);
3925   Node* const receiver = args.GetReceiver();
3926   Node* const mapper_function = args.GetOptionalArgumentValue(0);
3927 
3928   // 1. Let O be ? ToObject(this value).
3929   Node* const o = ToObject_Inline(CAST(context), CAST(receiver));
3930 
3931   // 2. Let sourceLen be ? ToLength(? Get(O, "length")).
3932   Node* const source_length =
3933       ToLength_Inline(context, GetProperty(context, o, LengthStringConstant()));
3934 
3935   // 3. If IsCallable(mapperFunction) is false, throw a TypeError exception.
3936   Label if_not_callable(this, Label::kDeferred);
3937   GotoIf(TaggedIsSmi(mapper_function), &if_not_callable);
3938   GotoIfNot(IsCallable(mapper_function), &if_not_callable);
3939 
3940   // 4. If thisArg is present, let T be thisArg; else let T be undefined.
3941   Node* const t = args.GetOptionalArgumentValue(1);
3942 
3943   // 5. Let A be ? ArraySpeciesCreate(O, 0).
3944   Node* const constructor =
3945       CallRuntime(Runtime::kArraySpeciesConstructor, context, o);
3946   Node* const a = ConstructJS(CodeFactory::Construct(isolate()), context,
3947                               constructor, SmiConstant(0));
3948 
3949   // 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
3950   CallBuiltin(Builtins::kFlatMapIntoArray, context, a, o, source_length,
3951               SmiConstant(0), SmiConstant(1), mapper_function, t);
3952 
3953   // 7. Return A.
3954   args.PopAndReturn(a);
3955 
3956   BIND(&if_not_callable);
3957   { ThrowTypeError(context, MessageTemplate::kMapperFunctionNonCallable); }
3958 }
3959 
TF_BUILTIN(ArrayConstructor,ArrayBuiltinsAssembler)3960 TF_BUILTIN(ArrayConstructor, ArrayBuiltinsAssembler) {
3961   // This is a trampoline to ArrayConstructorImpl which just adds
3962   // allocation_site parameter value and sets new_target if necessary.
3963   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
3964   TNode<JSFunction> function = CAST(Parameter(Descriptor::kTarget));
3965   TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
3966   TNode<Int32T> argc =
3967       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
3968 
3969   // If new_target is undefined, then this is the 'Call' case, so set new_target
3970   // to function.
3971   new_target =
3972       SelectConstant<Object>(IsUndefined(new_target), function, new_target);
3973 
3974   // Run the native code for the Array function called as a normal function.
3975   TNode<Object> no_allocation_site = UndefinedConstant();
3976   TailCallBuiltin(Builtins::kArrayConstructorImpl, context, function,
3977                   new_target, argc, no_allocation_site);
3978 }
3979 
TailCallArrayConstructorStub(const Callable & callable,TNode<Context> context,TNode<JSFunction> target,TNode<HeapObject> allocation_site_or_undefined,TNode<Int32T> argc)3980 void ArrayBuiltinsAssembler::TailCallArrayConstructorStub(
3981     const Callable& callable, TNode<Context> context, TNode<JSFunction> target,
3982     TNode<HeapObject> allocation_site_or_undefined, TNode<Int32T> argc) {
3983   TNode<Code> code = HeapConstant(callable.code());
3984 
3985   // We are going to call here ArrayNoArgumentsConstructor or
3986   // ArraySingleArgumentsConstructor which in addition to the register arguments
3987   // also expect some number of arguments on the expression stack.
3988   // Since
3989   // 1) incoming JS arguments are still on the stack,
3990   // 2) the ArrayNoArgumentsConstructor, ArraySingleArgumentsConstructor and
3991   //    ArrayNArgumentsConstructor are defined so that the register arguments
3992   //    are passed on the same registers,
3993   // in order to be able to generate a tail call to those builtins we do the
3994   // following trick here: we tail call to the constructor builtin using
3995   // ArrayNArgumentsConstructorDescriptor, so the tail call instruction
3996   // pops the current frame but leaves all the incoming JS arguments on the
3997   // expression stack so that the target builtin can still find them where it
3998   // expects.
3999   TailCallStub(ArrayNArgumentsConstructorDescriptor{}, code, context, target,
4000                allocation_site_or_undefined, argc);
4001 }
4002 
CreateArrayDispatchNoArgument(TNode<Context> context,TNode<JSFunction> target,TNode<Int32T> argc,AllocationSiteOverrideMode mode,TNode<AllocationSite> allocation_site)4003 void ArrayBuiltinsAssembler::CreateArrayDispatchNoArgument(
4004     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
4005     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
4006   if (mode == DISABLE_ALLOCATION_SITES) {
4007     Callable callable = CodeFactory::ArrayNoArgumentConstructor(
4008         isolate(), GetInitialFastElementsKind(), mode);
4009 
4010     TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(),
4011                                  argc);
4012   } else {
4013     DCHECK_EQ(mode, DONT_OVERRIDE);
4014     TNode<Int32T> elements_kind = LoadElementsKind(allocation_site);
4015 
4016     // TODO(ishell): Compute the builtin index dynamically instead of
4017     // iterating over all expected elements kinds.
4018     int last_index =
4019         GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
4020     for (int i = 0; i <= last_index; ++i) {
4021       Label next(this);
4022       ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4023       GotoIfNot(Word32Equal(elements_kind, Int32Constant(kind)), &next);
4024 
4025       Callable callable =
4026           CodeFactory::ArrayNoArgumentConstructor(isolate(), kind, mode);
4027 
4028       TailCallArrayConstructorStub(callable, context, target, allocation_site,
4029                                    argc);
4030 
4031       BIND(&next);
4032     }
4033 
4034     // If we reached this point there is a problem.
4035     Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
4036   }
4037 }
4038 
CreateArrayDispatchSingleArgument(TNode<Context> context,TNode<JSFunction> target,TNode<Int32T> argc,AllocationSiteOverrideMode mode,TNode<AllocationSite> allocation_site)4039 void ArrayBuiltinsAssembler::CreateArrayDispatchSingleArgument(
4040     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
4041     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
4042   if (mode == DISABLE_ALLOCATION_SITES) {
4043     ElementsKind initial = GetInitialFastElementsKind();
4044     ElementsKind holey_initial = GetHoleyElementsKind(initial);
4045     Callable callable = CodeFactory::ArraySingleArgumentConstructor(
4046         isolate(), holey_initial, mode);
4047 
4048     TailCallArrayConstructorStub(callable, context, target, UndefinedConstant(),
4049                                  argc);
4050   } else {
4051     DCHECK_EQ(mode, DONT_OVERRIDE);
4052     TNode<Smi> transition_info = LoadTransitionInfo(allocation_site);
4053 
4054     // Least significant bit in fast array elements kind means holeyness.
4055     STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
4056     STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
4057     STATIC_ASSERT(PACKED_ELEMENTS == 2);
4058     STATIC_ASSERT(HOLEY_ELEMENTS == 3);
4059     STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS == 4);
4060     STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == 5);
4061 
4062     Label normal_sequence(this);
4063     TVARIABLE(Int32T, var_elements_kind,
4064               Signed(DecodeWord32<AllocationSite::ElementsKindBits>(
4065                   SmiToInt32(transition_info))));
4066     // Is the low bit set? If so, we are holey and that is good.
4067     int fast_elements_kind_holey_mask =
4068         AllocationSite::ElementsKindBits::encode(static_cast<ElementsKind>(1));
4069     GotoIf(IsSetSmi(transition_info, fast_elements_kind_holey_mask),
4070            &normal_sequence);
4071     {
4072       // Make elements kind holey and update elements kind in the type info.
4073       var_elements_kind =
4074           Signed(Word32Or(var_elements_kind.value(), Int32Constant(1)));
4075       StoreObjectFieldNoWriteBarrier(
4076           allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset,
4077           SmiOr(transition_info, SmiConstant(fast_elements_kind_holey_mask)));
4078       Goto(&normal_sequence);
4079     }
4080     BIND(&normal_sequence);
4081 
4082     // TODO(ishell): Compute the builtin index dynamically instead of
4083     // iterating over all expected elements kinds.
4084     // TODO(ishell): Given that the code above ensures that the elements kind
4085     // is holey we can skip checking with non-holey elements kinds.
4086     int last_index =
4087         GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
4088     for (int i = 0; i <= last_index; ++i) {
4089       Label next(this);
4090       ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4091       GotoIfNot(Word32Equal(var_elements_kind.value(), Int32Constant(kind)),
4092                 &next);
4093 
4094       Callable callable =
4095           CodeFactory::ArraySingleArgumentConstructor(isolate(), kind, mode);
4096 
4097       TailCallArrayConstructorStub(callable, context, target, allocation_site,
4098                                    argc);
4099 
4100       BIND(&next);
4101     }
4102 
4103     // If we reached this point there is a problem.
4104     Abort(AbortReason::kUnexpectedElementsKindInArrayConstructor);
4105   }
4106 }
4107 
GenerateDispatchToArrayStub(TNode<Context> context,TNode<JSFunction> target,TNode<Int32T> argc,AllocationSiteOverrideMode mode,TNode<AllocationSite> allocation_site)4108 void ArrayBuiltinsAssembler::GenerateDispatchToArrayStub(
4109     TNode<Context> context, TNode<JSFunction> target, TNode<Int32T> argc,
4110     AllocationSiteOverrideMode mode, TNode<AllocationSite> allocation_site) {
4111   Label check_one_case(this), fallthrough(this);
4112   GotoIfNot(Word32Equal(argc, Int32Constant(0)), &check_one_case);
4113   CreateArrayDispatchNoArgument(context, target, argc, mode, allocation_site);
4114 
4115   BIND(&check_one_case);
4116   GotoIfNot(Word32Equal(argc, Int32Constant(1)), &fallthrough);
4117   CreateArrayDispatchSingleArgument(context, target, argc, mode,
4118                                     allocation_site);
4119 
4120   BIND(&fallthrough);
4121 }
4122 
TF_BUILTIN(ArrayConstructorImpl,ArrayBuiltinsAssembler)4123 TF_BUILTIN(ArrayConstructorImpl, ArrayBuiltinsAssembler) {
4124   TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
4125   TNode<Object> new_target = CAST(Parameter(Descriptor::kNewTarget));
4126   TNode<Int32T> argc =
4127       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
4128   TNode<HeapObject> maybe_allocation_site =
4129       CAST(Parameter(Descriptor::kAllocationSite));
4130 
4131   // Initial map for the builtin Array functions should be Map.
4132   CSA_ASSERT(this, IsMap(CAST(LoadObjectField(
4133                        target, JSFunction::kPrototypeOrInitialMapOffset))));
4134 
4135   // We should either have undefined or a valid AllocationSite
4136   CSA_ASSERT(this, Word32Or(IsUndefined(maybe_allocation_site),
4137                             IsAllocationSite(maybe_allocation_site)));
4138 
4139   // "Enter" the context of the Array function.
4140   TNode<Context> context =
4141       CAST(LoadObjectField(target, JSFunction::kContextOffset));
4142 
4143   Label runtime(this, Label::kDeferred);
4144   GotoIf(WordNotEqual(target, new_target), &runtime);
4145 
4146   Label no_info(this);
4147   // If the feedback vector is the undefined value call an array constructor
4148   // that doesn't use AllocationSites.
4149   GotoIf(IsUndefined(maybe_allocation_site), &no_info);
4150 
4151   GenerateDispatchToArrayStub(context, target, argc, DONT_OVERRIDE,
4152                               CAST(maybe_allocation_site));
4153   Goto(&runtime);
4154 
4155   BIND(&no_info);
4156   GenerateDispatchToArrayStub(context, target, argc, DISABLE_ALLOCATION_SITES);
4157   Goto(&runtime);
4158 
4159   BIND(&runtime);
4160   GenerateArrayNArgumentsConstructor(context, target, new_target, argc,
4161                                      maybe_allocation_site);
4162 }
4163 
GenerateConstructor(Node * context,Node * array_function,Node * array_map,Node * array_size,Node * allocation_site,ElementsKind elements_kind,AllocationSiteMode mode)4164 void ArrayBuiltinsAssembler::GenerateConstructor(
4165     Node* context, Node* array_function, Node* array_map, Node* array_size,
4166     Node* allocation_site, ElementsKind elements_kind,
4167     AllocationSiteMode mode) {
4168   Label ok(this);
4169   Label smi_size(this);
4170   Label small_smi_size(this);
4171   Label call_runtime(this, Label::kDeferred);
4172 
4173   Branch(TaggedIsSmi(array_size), &smi_size, &call_runtime);
4174 
4175   BIND(&smi_size);
4176 
4177   if (IsFastPackedElementsKind(elements_kind)) {
4178     Label abort(this, Label::kDeferred);
4179     Branch(SmiEqual(CAST(array_size), SmiConstant(0)), &small_smi_size, &abort);
4180 
4181     BIND(&abort);
4182     Node* reason = SmiConstant(AbortReason::kAllocatingNonEmptyPackedArray);
4183     TailCallRuntime(Runtime::kAbort, context, reason);
4184   } else {
4185     int element_size =
4186         IsDoubleElementsKind(elements_kind) ? kDoubleSize : kPointerSize;
4187     int max_fast_elements =
4188         (kMaxRegularHeapObjectSize - FixedArray::kHeaderSize - JSArray::kSize -
4189          AllocationMemento::kSize) /
4190         element_size;
4191     Branch(SmiAboveOrEqual(CAST(array_size), SmiConstant(max_fast_elements)),
4192            &call_runtime, &small_smi_size);
4193   }
4194 
4195   BIND(&small_smi_size);
4196   {
4197     Node* array = AllocateJSArray(
4198         elements_kind, array_map, array_size, array_size,
4199         mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site,
4200         CodeStubAssembler::SMI_PARAMETERS);
4201     Return(array);
4202   }
4203 
4204   BIND(&call_runtime);
4205   {
4206     TailCallRuntime(Runtime::kNewArray, context, array_function, array_size,
4207                     array_function, allocation_site);
4208   }
4209 }
4210 
GenerateArrayNoArgumentConstructor(ElementsKind kind,AllocationSiteOverrideMode mode)4211 void ArrayBuiltinsAssembler::GenerateArrayNoArgumentConstructor(
4212     ElementsKind kind, AllocationSiteOverrideMode mode) {
4213   typedef ArrayNoArgumentConstructorDescriptor Descriptor;
4214   Node* native_context = LoadObjectField(Parameter(Descriptor::kFunction),
4215                                          JSFunction::kContextOffset);
4216   bool track_allocation_site =
4217       AllocationSite::ShouldTrack(kind) && mode != DISABLE_ALLOCATION_SITES;
4218   Node* allocation_site =
4219       track_allocation_site ? Parameter(Descriptor::kAllocationSite) : nullptr;
4220   Node* array_map = LoadJSArrayElementsMap(kind, native_context);
4221   Node* array = AllocateJSArray(
4222       kind, array_map, IntPtrConstant(JSArray::kPreallocatedArrayElements),
4223       SmiConstant(0), allocation_site);
4224   Return(array);
4225 }
4226 
GenerateArraySingleArgumentConstructor(ElementsKind kind,AllocationSiteOverrideMode mode)4227 void ArrayBuiltinsAssembler::GenerateArraySingleArgumentConstructor(
4228     ElementsKind kind, AllocationSiteOverrideMode mode) {
4229   typedef ArraySingleArgumentConstructorDescriptor Descriptor;
4230   Node* context = Parameter(Descriptor::kContext);
4231   Node* function = Parameter(Descriptor::kFunction);
4232   Node* native_context = LoadObjectField(function, JSFunction::kContextOffset);
4233   Node* array_map = LoadJSArrayElementsMap(kind, native_context);
4234 
4235   AllocationSiteMode allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
4236   if (mode == DONT_OVERRIDE) {
4237     allocation_site_mode = AllocationSite::ShouldTrack(kind)
4238                                ? TRACK_ALLOCATION_SITE
4239                                : DONT_TRACK_ALLOCATION_SITE;
4240   }
4241 
4242   Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
4243   Node* allocation_site = Parameter(Descriptor::kAllocationSite);
4244 
4245   GenerateConstructor(context, function, array_map, array_size, allocation_site,
4246                       kind, allocation_site_mode);
4247 }
4248 
GenerateArrayNArgumentsConstructor(TNode<Context> context,TNode<JSFunction> target,TNode<Object> new_target,TNode<Int32T> argc,TNode<HeapObject> maybe_allocation_site)4249 void ArrayBuiltinsAssembler::GenerateArrayNArgumentsConstructor(
4250     TNode<Context> context, TNode<JSFunction> target, TNode<Object> new_target,
4251     TNode<Int32T> argc, TNode<HeapObject> maybe_allocation_site) {
4252   // Replace incoming JS receiver argument with the target.
4253   // TODO(ishell): Avoid replacing the target on the stack and just add it
4254   // as another additional parameter for Runtime::kNewArray.
4255   CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
4256   args.SetReceiver(target);
4257 
4258   // Adjust arguments count for the runtime call: +1 for implicit receiver
4259   // and +2 for new_target and maybe_allocation_site.
4260   argc = Int32Add(argc, Int32Constant(3));
4261   TailCallRuntime(Runtime::kNewArray, argc, context, new_target,
4262                   maybe_allocation_site);
4263 }
4264 
TF_BUILTIN(ArrayNArgumentsConstructor,ArrayBuiltinsAssembler)4265 TF_BUILTIN(ArrayNArgumentsConstructor, ArrayBuiltinsAssembler) {
4266   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
4267   TNode<JSFunction> target = CAST(Parameter(Descriptor::kFunction));
4268   TNode<Int32T> argc =
4269       UncheckedCast<Int32T>(Parameter(Descriptor::kActualArgumentsCount));
4270   TNode<HeapObject> maybe_allocation_site =
4271       CAST(Parameter(Descriptor::kAllocationSite));
4272 
4273   GenerateArrayNArgumentsConstructor(context, target, target, argc,
4274                                      maybe_allocation_site);
4275 }
4276 
GenerateInternalArrayNoArgumentConstructor(ElementsKind kind)4277 void ArrayBuiltinsAssembler::GenerateInternalArrayNoArgumentConstructor(
4278     ElementsKind kind) {
4279   typedef ArrayNoArgumentConstructorDescriptor Descriptor;
4280   Node* array_map = LoadObjectField(Parameter(Descriptor::kFunction),
4281                                     JSFunction::kPrototypeOrInitialMapOffset);
4282   Node* array = AllocateJSArray(
4283       kind, array_map, IntPtrConstant(JSArray::kPreallocatedArrayElements),
4284       SmiConstant(0));
4285   Return(array);
4286 }
4287 
GenerateInternalArraySingleArgumentConstructor(ElementsKind kind)4288 void ArrayBuiltinsAssembler::GenerateInternalArraySingleArgumentConstructor(
4289     ElementsKind kind) {
4290   typedef ArraySingleArgumentConstructorDescriptor Descriptor;
4291   Node* context = Parameter(Descriptor::kContext);
4292   Node* function = Parameter(Descriptor::kFunction);
4293   Node* array_map =
4294       LoadObjectField(function, JSFunction::kPrototypeOrInitialMapOffset);
4295   Node* array_size = Parameter(Descriptor::kArraySizeSmiParameter);
4296   Node* allocation_site = UndefinedConstant();
4297 
4298   GenerateConstructor(context, function, array_map, array_size, allocation_site,
4299                       kind, DONT_TRACK_ALLOCATION_SITE);
4300 }
4301 
4302 #define GENERATE_ARRAY_CTOR(name, kind_camel, kind_caps, mode_camel, \
4303                             mode_caps)                               \
4304   TF_BUILTIN(Array##name##Constructor_##kind_camel##_##mode_camel,   \
4305              ArrayBuiltinsAssembler) {                               \
4306     GenerateArray##name##Constructor(kind_caps, mode_caps);          \
4307   }
4308 
4309 // The ArrayNoArgumentConstructor builtin family.
4310 GENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS, DontOverride,
4311                     DONT_OVERRIDE);
4312 GENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride,
4313                     DONT_OVERRIDE);
4314 GENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS,
4315                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4316 GENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS,
4317                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4318 GENERATE_ARRAY_CTOR(NoArgument, Packed, PACKED_ELEMENTS, DisableAllocationSites,
4319                     DISABLE_ALLOCATION_SITES);
4320 GENERATE_ARRAY_CTOR(NoArgument, Holey, HOLEY_ELEMENTS, DisableAllocationSites,
4321                     DISABLE_ALLOCATION_SITES);
4322 GENERATE_ARRAY_CTOR(NoArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS,
4323                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4324 GENERATE_ARRAY_CTOR(NoArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS,
4325                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4326 
4327 // The ArraySingleArgumentConstructor builtin family.
4328 GENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS,
4329                     DontOverride, DONT_OVERRIDE);
4330 GENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride,
4331                     DONT_OVERRIDE);
4332 GENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS,
4333                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4334 GENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS,
4335                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4336 GENERATE_ARRAY_CTOR(SingleArgument, Packed, PACKED_ELEMENTS,
4337                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4338 GENERATE_ARRAY_CTOR(SingleArgument, Holey, HOLEY_ELEMENTS,
4339                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4340 GENERATE_ARRAY_CTOR(SingleArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS,
4341                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4342 GENERATE_ARRAY_CTOR(SingleArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS,
4343                     DisableAllocationSites, DISABLE_ALLOCATION_SITES);
4344 
4345 #undef GENERATE_ARRAY_CTOR
4346 
4347 #define GENERATE_INTERNAL_ARRAY_CTOR(name, kind_camel, kind_caps) \
4348   TF_BUILTIN(InternalArray##name##Constructor_##kind_camel,       \
4349              ArrayBuiltinsAssembler) {                            \
4350     GenerateInternalArray##name##Constructor(kind_caps);          \
4351   }
4352 
4353 GENERATE_INTERNAL_ARRAY_CTOR(NoArgument, Packed, PACKED_ELEMENTS);
4354 GENERATE_INTERNAL_ARRAY_CTOR(NoArgument, Holey, HOLEY_ELEMENTS);
4355 GENERATE_INTERNAL_ARRAY_CTOR(SingleArgument, Packed, PACKED_ELEMENTS);
4356 GENERATE_INTERNAL_ARRAY_CTOR(SingleArgument, Holey, HOLEY_ELEMENTS);
4357 
4358 #undef GENERATE_INTERNAL_ARRAY_CTOR
4359 
4360 }  // namespace internal
4361 }  // namespace v8
4362