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