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