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