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