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