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