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