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-string-gen.h"
6 : #include "src/builtins/builtins-utils-gen.h"
7 : #include "src/builtins/builtins.h"
8 : #include "src/code-stub-assembler.h"
9 : #include "src/factory-inl.h"
10 : #include "src/frame-constants.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 1488 : class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
16 : public:
17 744 : explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state)
18 : : CodeStubAssembler(state),
19 : k_(this, MachineRepresentation::kTagged),
20 : a_(this, MachineRepresentation::kTagged),
21 : to_(this, MachineRepresentation::kTagged, SmiConstant(0)),
22 2232 : fully_spec_compliant_(this, {&k_, &a_, &to_}) {}
23 :
24 : typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)>
25 : BuiltinResultGenerator;
26 :
27 : typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm,
28 : Node* k_value, Node* k)>
29 : CallResultProcessor;
30 :
31 : typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)>
32 : PostLoopAction;
33 :
34 620 : void ForEachResultGenerator() { a_.Bind(UndefinedConstant()); }
35 :
36 372 : Node* ForEachProcessor(Node* k_value, Node* k) {
37 : CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(),
38 744 : k_value, k, o());
39 372 : return a();
40 : }
41 :
42 620 : void SomeResultGenerator() { a_.Bind(FalseConstant()); }
43 :
44 372 : Node* SomeProcessor(Node* k_value, Node* k) {
45 : Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
46 744 : this_arg(), k_value, k, o());
47 372 : Label false_continue(this), return_true(this);
48 372 : BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
49 372 : BIND(&return_true);
50 744 : ReturnFromBuiltin(TrueConstant());
51 372 : BIND(&false_continue);
52 372 : return a();
53 : }
54 :
55 620 : void EveryResultGenerator() { a_.Bind(TrueConstant()); }
56 :
57 372 : Node* EveryProcessor(Node* k_value, Node* k) {
58 : Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
59 744 : this_arg(), k_value, k, o());
60 372 : Label true_continue(this), return_false(this);
61 372 : BranchIfToBooleanIsTrue(value, &true_continue, &return_false);
62 372 : BIND(&return_false);
63 744 : ReturnFromBuiltin(FalseConstant());
64 372 : BIND(&true_continue);
65 372 : return a();
66 : }
67 :
68 620 : void ReduceResultGenerator() { return a_.Bind(this_arg()); }
69 :
70 2232 : Node* ReduceProcessor(Node* k_value, Node* k) {
71 744 : VARIABLE(result, MachineRepresentation::kTagged);
72 2232 : Label done(this, {&result}), initial(this);
73 1488 : GotoIf(WordEqual(a(), TheHoleConstant()), &initial);
74 : result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
75 2232 : UndefinedConstant(), a(), k_value, k, o()));
76 744 : Goto(&done);
77 :
78 744 : BIND(&initial);
79 744 : result.Bind(k_value);
80 744 : Goto(&done);
81 :
82 744 : BIND(&done);
83 1488 : return result.value();
84 : }
85 :
86 1488 : void ReducePostLoopAction() {
87 744 : Label ok(this);
88 1488 : GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok);
89 744 : ThrowTypeError(context(), MessageTemplate::kReduceNoInitial);
90 744 : BIND(&ok);
91 744 : }
92 :
93 31 : void FilterResultGenerator() {
94 : // 7. Let A be ArraySpeciesCreate(O, 0).
95 : // This version of ArraySpeciesCreate will create with the correct
96 : // ElementsKind in the fast case.
97 31 : ArraySpeciesCreate();
98 31 : }
99 :
100 279 : Node* FilterProcessor(Node* k_value, Node* k) {
101 : // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)).
102 : Node* selected = CallJS(CodeFactory::Call(isolate()), context(),
103 186 : callbackfn(), this_arg(), k_value, k, o());
104 186 : Label true_continue(this, &to_), false_continue(this);
105 93 : BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue);
106 93 : BIND(&true_continue);
107 : // iii. If selected is true, then...
108 : {
109 : Label after_work(this, &to_);
110 : Node* kind = nullptr;
111 :
112 : // If a() is a JSArray, we can have a fast path.
113 93 : Label fast(this);
114 93 : Label runtime(this);
115 93 : Label object_push_pre(this), object_push(this), double_push(this);
116 93 : BranchIfFastJSArray(a(), context(), &fast, &runtime);
117 :
118 93 : BIND(&fast);
119 : {
120 372 : GotoIf(SmiNotEqual(LoadJSArrayLength(a()), to_.value()), &runtime);
121 93 : kind = EnsureArrayPushable(a(), &runtime);
122 : GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
123 186 : &object_push_pre);
124 :
125 93 : BuildAppendJSArray(HOLEY_SMI_ELEMENTS, a(), k_value, &runtime);
126 93 : Goto(&after_work);
127 : }
128 :
129 93 : BIND(&object_push_pre);
130 : {
131 : Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push,
132 186 : &object_push);
133 : }
134 :
135 93 : BIND(&object_push);
136 : {
137 93 : BuildAppendJSArray(HOLEY_ELEMENTS, a(), k_value, &runtime);
138 93 : Goto(&after_work);
139 : }
140 :
141 93 : BIND(&double_push);
142 : {
143 93 : BuildAppendJSArray(HOLEY_DOUBLE_ELEMENTS, a(), k_value, &runtime);
144 93 : Goto(&after_work);
145 : }
146 :
147 93 : BIND(&runtime);
148 : {
149 : // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
150 : CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(),
151 93 : k_value);
152 93 : Goto(&after_work);
153 : }
154 :
155 93 : BIND(&after_work);
156 : {
157 : // 2. Increase to by 1.
158 93 : to_.Bind(NumberInc(to_.value()));
159 93 : Goto(&false_continue);
160 93 : }
161 : }
162 93 : BIND(&false_continue);
163 93 : return a();
164 : }
165 :
166 62 : void MapResultGenerator() { ArraySpeciesCreate(len_); }
167 :
168 558 : void TypedArrayMapResultGenerator() {
169 : // 6. Let A be ? TypedArraySpeciesCreate(O, len).
170 558 : Node* a = TypedArraySpeciesCreateByLength(context(), o(), len_);
171 : // In the Spec and our current implementation, the length check is already
172 : // performed in TypedArraySpeciesCreate.
173 : CSA_ASSERT(this,
174 : SmiLessThanOrEqual(
175 : len_, LoadObjectField(a, JSTypedArray::kLengthOffset)));
176 1395 : fast_typed_array_target_ = Word32Equal(LoadInstanceType(LoadElements(o_)),
177 1953 : LoadInstanceType(LoadElements(a)));
178 279 : a_.Bind(a);
179 279 : }
180 :
181 62 : Node* SpecCompliantMapProcessor(Node* k_value, Node* k) {
182 : // i. Let kValue be ? Get(O, Pk). Performed by the caller of
183 : // SpecCompliantMapProcessor.
184 : // ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
185 : Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
186 62 : callbackfn(), this_arg(), k_value, k, o());
187 :
188 : // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
189 : CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mapped_value);
190 31 : return a();
191 : }
192 :
193 310 : Node* FastMapProcessor(Node* k_value, Node* k) {
194 : // i. Let kValue be ? Get(O, Pk). Performed by the caller of
195 : // FastMapProcessor.
196 : // ii. Let mapped_value be ? Call(callbackfn, T, kValue, k, O).
197 : Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
198 124 : callbackfn(), this_arg(), k_value, k, o());
199 :
200 : // mode is SMI_PARAMETERS because k has tagged representation.
201 : ParameterMode mode = SMI_PARAMETERS;
202 62 : Label runtime(this), finished(this);
203 62 : Label transition_pre(this), transition_smi_fast(this),
204 62 : transition_smi_double(this);
205 62 : Label array_not_smi(this), array_fast(this), array_double(this);
206 :
207 186 : Node* kind = LoadMapElementsKind(LoadMap(a()));
208 124 : Node* elements = LoadElements(a());
209 124 : GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS), &array_not_smi);
210 : TryStoreArrayElement(HOLEY_SMI_ELEMENTS, mode, &transition_pre, elements, k,
211 62 : mapped_value);
212 62 : Goto(&finished);
213 :
214 62 : BIND(&transition_pre);
215 : {
216 : // array is smi. Value is either tagged or a heap number.
217 : CSA_ASSERT(this, TaggedIsNotSmi(mapped_value));
218 186 : GotoIf(IsHeapNumberMap(LoadMap(mapped_value)), &transition_smi_double);
219 62 : Goto(&transition_smi_fast);
220 : }
221 :
222 62 : BIND(&array_not_smi);
223 : {
224 : Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &array_double,
225 124 : &array_fast);
226 : }
227 :
228 62 : BIND(&transition_smi_fast);
229 : {
230 : // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
231 124 : Node* const native_context = LoadNativeContext(context());
232 : Node* const fast_map = LoadContextElement(
233 124 : native_context, Context::JS_ARRAY_HOLEY_ELEMENTS_MAP_INDEX);
234 :
235 : // Since this transition is only a map change, just do it right here.
236 : // Since a() doesn't have an allocation site, it's safe to do the
237 : // map store directly, otherwise I'd call TransitionElementsKind().
238 62 : StoreMap(a(), fast_map);
239 62 : Goto(&array_fast);
240 : }
241 :
242 62 : BIND(&array_fast);
243 : {
244 : TryStoreArrayElement(HOLEY_ELEMENTS, mode, &runtime, elements, k,
245 62 : mapped_value);
246 62 : Goto(&finished);
247 : }
248 :
249 62 : BIND(&transition_smi_double);
250 : {
251 : // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
252 124 : Node* const native_context = LoadNativeContext(context());
253 : Node* const double_map = LoadContextElement(
254 124 : native_context, Context::JS_ARRAY_HOLEY_DOUBLE_ELEMENTS_MAP_INDEX);
255 : CallStub(CodeFactory::TransitionElementsKind(
256 : isolate(), HOLEY_SMI_ELEMENTS, HOLEY_DOUBLE_ELEMENTS, true),
257 124 : context(), a(), double_map);
258 62 : Goto(&array_double);
259 : }
260 :
261 62 : BIND(&array_double);
262 : {
263 : // TODO(mvstanton): If we use a variable for elements and bind it
264 : // appropriately, we can avoid an extra load of elements by binding the
265 : // value only after a transition from smi to double.
266 124 : elements = LoadElements(a());
267 : // If the mapped_value isn't a number, this will bail out to the runtime
268 : // to make the transition.
269 : TryStoreArrayElement(HOLEY_DOUBLE_ELEMENTS, mode, &runtime, elements, k,
270 62 : mapped_value);
271 62 : Goto(&finished);
272 : }
273 :
274 62 : BIND(&runtime);
275 : {
276 : // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mapped_value).
277 : CallRuntime(Runtime::kCreateDataProperty, context(), a(), k,
278 : mapped_value);
279 62 : Goto(&finished);
280 : }
281 :
282 62 : BIND(&finished);
283 62 : return a();
284 : }
285 :
286 : // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map.
287 837 : Node* TypedArrayMapProcessor(Node* k_value, Node* k) {
288 : // 8. c. Let mapped_value be ? Call(callbackfn, T, « kValue, k, O »).
289 : Node* mapped_value = CallJS(CodeFactory::Call(isolate()), context(),
290 558 : callbackfn(), this_arg(), k_value, k, o());
291 279 : Label fast(this), slow(this), done(this), detached(this, Label::kDeferred);
292 :
293 : // 8. d. Perform ? Set(A, Pk, mapped_value, true).
294 : // Since we know that A is a TypedArray, this always ends up in
295 : // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then
296 : // tc39.github.io/ecma262/#sec-integerindexedelementset .
297 558 : Branch(fast_typed_array_target_, &fast, &slow);
298 :
299 279 : BIND(&fast);
300 : // #sec-integerindexedelementset 3. Let numValue be ? ToNumber(value).
301 558 : Node* num_value = ToNumber(context(), mapped_value);
302 : // The only way how this can bailout is because of a detached buffer.
303 : EmitElementStore(a(), k, num_value, false, source_elements_kind_,
304 558 : KeyedAccessStoreMode::STANDARD_STORE, &detached);
305 279 : Goto(&done);
306 :
307 279 : BIND(&slow);
308 : CallRuntime(Runtime::kSetProperty, context(), a(), k, mapped_value,
309 279 : SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
310 279 : Goto(&done);
311 :
312 279 : BIND(&detached);
313 : // tc39.github.io/ecma262/#sec-integerindexedelementset
314 : // 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
315 279 : ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
316 :
317 279 : BIND(&done);
318 279 : return a();
319 : }
320 :
321 1581 : void NullPostLoopAction() {}
322 :
323 : protected:
324 : Node* context() { return context_; }
325 : Node* receiver() { return receiver_; }
326 : Node* new_target() { return new_target_; }
327 : Node* argc() { return argc_; }
328 : Node* o() { return o_; }
329 : Node* len() { return len_; }
330 : Node* callbackfn() { return callbackfn_; }
331 : Node* this_arg() { return this_arg_; }
332 1519 : Node* k() { return k_.value(); }
333 5425 : Node* a() { return a_.value(); }
334 :
335 3069 : void ReturnFromBuiltin(Node* value) {
336 3069 : if (argc_ == nullptr) {
337 62 : Return(value);
338 : } else {
339 : // argc_ doesn't include the receiver, so it has to be added back in
340 : // manually.
341 9021 : PopAndReturn(IntPtrAdd(argc_, IntPtrConstant(1)), value);
342 : }
343 3069 : }
344 :
345 : void InitIteratingArrayBuiltinBody(Node* context, Node* receiver,
346 : Node* callbackfn, Node* this_arg,
347 : Node* new_target, Node* argc) {
348 403 : context_ = context;
349 403 : receiver_ = receiver;
350 403 : new_target_ = new_target;
351 403 : callbackfn_ = callbackfn;
352 403 : this_arg_ = this_arg;
353 403 : argc_ = argc;
354 : }
355 :
356 217 : void GenerateIteratingArrayBuiltinBody(
357 : const char* name, const BuiltinResultGenerator& generator,
358 : const CallResultProcessor& processor, const PostLoopAction& action,
359 : const Callable& slow_case_continuation,
360 3069 : ForEachDirection direction = ForEachDirection::kForward) {
361 868 : Label non_array(this), array_changes(this, {&k_, &a_, &to_});
362 :
363 : // TODO(danno): Seriously? Do we really need to throw the exact error
364 : // message on null and undefined so that the webkit tests pass?
365 217 : Label throw_null_undefined_exception(this, Label::kDeferred);
366 434 : GotoIf(WordEqual(receiver(), NullConstant()),
367 217 : &throw_null_undefined_exception);
368 434 : GotoIf(WordEqual(receiver(), UndefinedConstant()),
369 217 : &throw_null_undefined_exception);
370 :
371 : // By the book: taken directly from the ECMAScript 2015 specification
372 :
373 : // 1. Let O be ToObject(this value).
374 : // 2. ReturnIfAbrupt(O)
375 217 : o_ = CallBuiltin(Builtins::kToObject, context(), receiver());
376 :
377 : // 3. Let len be ToLength(Get(O, "length")).
378 : // 4. ReturnIfAbrupt(len).
379 434 : VARIABLE(merged_length, MachineRepresentation::kTagged);
380 217 : Label has_length(this, &merged_length), not_js_array(this);
381 434 : GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), ¬_js_array);
382 434 : merged_length.Bind(LoadJSArrayLength(o()));
383 217 : Goto(&has_length);
384 217 : BIND(¬_js_array);
385 : Node* len_property =
386 434 : GetProperty(context(), o(), isolate()->factory()->length_string());
387 217 : merged_length.Bind(ToLength_Inline(context(), len_property));
388 217 : Goto(&has_length);
389 217 : BIND(&has_length);
390 217 : len_ = merged_length.value();
391 :
392 : // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
393 217 : Label type_exception(this, Label::kDeferred);
394 217 : Label done(this);
395 434 : GotoIf(TaggedIsSmi(callbackfn()), &type_exception);
396 651 : Branch(IsCallableMap(LoadMap(callbackfn())), &done, &type_exception);
397 :
398 217 : BIND(&throw_null_undefined_exception);
399 217 : ThrowTypeError(context(), MessageTemplate::kCalledOnNullOrUndefined, name);
400 :
401 217 : BIND(&type_exception);
402 : ThrowTypeError(context(), MessageTemplate::kCalledNonCallable,
403 217 : callbackfn());
404 :
405 217 : BIND(&done);
406 :
407 : // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
408 : // [Already done by the arguments adapter]
409 :
410 217 : if (direction == ForEachDirection::kForward) {
411 : // 7. Let k be 0.
412 372 : k_.Bind(SmiConstant(0));
413 : } else {
414 31 : k_.Bind(NumberDec(len()));
415 : }
416 :
417 217 : generator(this);
418 :
419 217 : HandleFastElements(processor, action, &fully_spec_compliant_, direction);
420 :
421 217 : BIND(&fully_spec_compliant_);
422 :
423 : Node* result =
424 : CallStub(slow_case_continuation, context(), receiver(), callbackfn(),
425 868 : this_arg(), a_.value(), o(), k_.value(), len(), to_.value());
426 434 : ReturnFromBuiltin(result);
427 217 : }
428 :
429 : void InitIteratingArrayBuiltinLoopContinuation(Node* context, Node* receiver,
430 : Node* callbackfn,
431 : Node* this_arg, Node* a,
432 : Node* o, Node* initial_k,
433 : Node* len, Node* to) {
434 217 : context_ = context;
435 217 : this_arg_ = this_arg;
436 217 : callbackfn_ = callbackfn;
437 217 : argc_ = nullptr;
438 217 : a_.Bind(a);
439 217 : k_.Bind(initial_k);
440 217 : o_ = o;
441 217 : len_ = len;
442 217 : to_.Bind(to);
443 : }
444 :
445 186 : void GenerateIteratingTypedArrayBuiltinBody(
446 : const char* name, const BuiltinResultGenerator& generator,
447 : const CallResultProcessor& processor, const PostLoopAction& action,
448 31 : ForEachDirection direction = ForEachDirection::kForward) {
449 186 : name_ = name;
450 :
451 : // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray
452 :
453 186 : Label throw_not_typed_array(this, Label::kDeferred),
454 186 : throw_detached(this, Label::kDeferred);
455 :
456 558 : GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
457 : GotoIfNot(HasInstanceType(receiver_, JS_TYPED_ARRAY_TYPE),
458 372 : &throw_not_typed_array);
459 :
460 186 : o_ = receiver_;
461 : Node* array_buffer = LoadObjectField(o_, JSTypedArray::kBufferOffset);
462 372 : GotoIf(IsDetachedBuffer(array_buffer), &throw_detached);
463 :
464 372 : len_ = LoadObjectField(o_, JSTypedArray::kLengthOffset);
465 :
466 186 : Label throw_not_callable(this, Label::kDeferred);
467 186 : Label distinguish_types(this);
468 558 : GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable);
469 372 : Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types,
470 558 : &throw_not_callable);
471 :
472 186 : BIND(&throw_not_typed_array);
473 186 : ThrowTypeError(context_, MessageTemplate::kNotTypedArray);
474 :
475 186 : BIND(&throw_detached);
476 186 : ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
477 :
478 186 : BIND(&throw_not_callable);
479 186 : ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_);
480 :
481 186 : Label unexpected_instance_type(this);
482 186 : BIND(&unexpected_instance_type);
483 186 : Unreachable();
484 :
485 : std::vector<int32_t> instance_types = {
486 : #define INSTANCE_TYPE(Type, type, TYPE, ctype, size) FIXED_##TYPE##_ARRAY_TYPE,
487 : TYPED_ARRAYS(INSTANCE_TYPE)
488 : #undef INSTANCE_TYPE
489 : };
490 186 : std::vector<Label> labels;
491 3720 : for (size_t i = 0; i < instance_types.size(); ++i) {
492 1674 : labels.push_back(Label(this));
493 : }
494 : std::vector<Label*> label_ptrs;
495 2046 : for (Label& label : labels) {
496 3348 : label_ptrs.push_back(&label);
497 : }
498 :
499 186 : BIND(&distinguish_types);
500 :
501 186 : if (direction == ForEachDirection::kForward) {
502 310 : k_.Bind(SmiConstant(0));
503 : } else {
504 31 : k_.Bind(NumberDec(len()));
505 : }
506 744 : Node* instance_type = LoadInstanceType(LoadElements(o_));
507 : Switch(instance_type, &unexpected_instance_type, instance_types.data(),
508 372 : label_ptrs.data(), labels.size());
509 :
510 3720 : for (size_t i = 0; i < labels.size(); ++i) {
511 1674 : BIND(&labels[i]);
512 : Label done(this);
513 : source_elements_kind_ = ElementsKindForInstanceType(
514 3348 : static_cast<InstanceType>(instance_types[i]));
515 1674 : generator(this);
516 : // TODO(tebbi): Silently cancelling the loop on buffer detachment is a
517 : // spec violation. Should go to &throw_detached and throw a TypeError
518 : // instead.
519 1674 : VisitAllTypedArrayElements(array_buffer, processor, &done, direction);
520 1674 : Goto(&done);
521 : // No exception, return success
522 1674 : BIND(&done);
523 1674 : action(this);
524 1674 : ReturnFromBuiltin(a_.value());
525 1860 : }
526 186 : }
527 :
528 217 : void GenerateIteratingArrayBuiltinLoopContinuation(
529 : const CallResultProcessor& processor, const PostLoopAction& action,
530 651 : ForEachDirection direction = ForEachDirection::kForward) {
531 434 : Label loop(this, {&k_, &a_, &to_});
532 217 : Label after_loop(this);
533 217 : Goto(&loop);
534 217 : BIND(&loop);
535 : {
536 217 : if (direction == ForEachDirection::kForward) {
537 : // 8. Repeat, while k < len
538 372 : GotoIfNumberGreaterThanOrEqual(k(), len_, &after_loop);
539 : } else {
540 : // OR
541 : // 10. Repeat, while k >= 0
542 62 : GotoIfNumberGreaterThanOrEqual(SmiConstant(-1), k(), &after_loop);
543 : }
544 :
545 : Label done_element(this, &to_);
546 : // a. Let Pk be ToString(k).
547 : // We never have to perform a ToString conversion as the above guards
548 : // guarantee that we have a positive {k} which also is a valid array
549 : // index in the range [0, 2^32-1).
550 : CSA_ASSERT(this, IsNumberArrayIndex(k()));
551 :
552 : // b. Let kPresent be HasProperty(O, Pk).
553 : // c. ReturnIfAbrupt(kPresent).
554 217 : Node* k_present = HasProperty(o(), k(), context(), kHasProperty);
555 :
556 : // d. If kPresent is true, then
557 434 : GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element);
558 :
559 : // i. Let kValue be Get(O, Pk).
560 : // ii. ReturnIfAbrupt(kValue).
561 217 : Node* k_value = GetProperty(context(), o(), k());
562 :
563 : // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
564 : // iv. ReturnIfAbrupt(funcResult).
565 217 : a_.Bind(processor(this, k_value, k()));
566 217 : Goto(&done_element);
567 :
568 217 : BIND(&done_element);
569 :
570 217 : if (direction == ForEachDirection::kForward) {
571 : // e. Increase k by 1.
572 186 : k_.Bind(NumberInc(k()));
573 : } else {
574 : // e. Decrease k by 1.
575 31 : k_.Bind(NumberDec(k()));
576 : }
577 217 : Goto(&loop);
578 : }
579 217 : BIND(&after_loop);
580 :
581 217 : action(this);
582 651 : Return(a_.value());
583 217 : }
584 :
585 : private:
586 1674 : static ElementsKind ElementsKindForInstanceType(InstanceType type) {
587 1674 : switch (type) {
588 : #define INSTANCE_TYPE_TO_ELEMENTS_KIND(Type, type, TYPE, ctype, size) \
589 : case FIXED_##TYPE##_ARRAY_TYPE: \
590 : return TYPE##_ELEMENTS;
591 :
592 186 : TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND)
593 : #undef INSTANCE_TYPE_TO_ELEMENTS_KIND
594 :
595 : default:
596 0 : UNREACHABLE();
597 : }
598 : }
599 :
600 1674 : void VisitAllTypedArrayElements(Node* array_buffer,
601 : const CallResultProcessor& processor,
602 : Label* detached, ForEachDirection direction) {
603 1674 : VariableList list({&a_, &k_, &to_}, zone());
604 :
605 1674 : FastLoopBody body = [&](Node* index) {
606 3348 : GotoIf(IsDetachedBuffer(array_buffer), detached);
607 5022 : Node* elements = LoadElements(o_);
608 : Node* base_ptr =
609 1674 : LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
610 : Node* external_ptr =
611 : LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
612 1674 : MachineType::Pointer());
613 5022 : Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
614 : Node* value = LoadFixedTypedArrayElementAsTagged(
615 1674 : data_ptr, index, source_elements_kind_, SMI_PARAMETERS);
616 1674 : k_.Bind(index);
617 1674 : a_.Bind(processor(this, value, index));
618 1674 : };
619 3348 : Node* start = SmiConstant(0);
620 1674 : Node* end = len_;
621 : IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost;
622 : int incr = 1;
623 1674 : if (direction == ForEachDirection::kReverse) {
624 : std::swap(start, end);
625 : advance_mode = IndexAdvanceMode::kPre;
626 : incr = -1;
627 : }
628 : BuildFastLoop(list, start, end, body, incr, ParameterMode::SMI_PARAMETERS,
629 1674 : advance_mode);
630 1674 : }
631 :
632 434 : void VisitAllFastElementsOneKind(ElementsKind kind,
633 : const CallResultProcessor& processor,
634 : Label* array_changed, ParameterMode mode,
635 868 : ForEachDirection direction) {
636 434 : Comment("begin VisitAllFastElementsOneKind");
637 434 : VARIABLE(original_map, MachineRepresentation::kTagged);
638 868 : original_map.Bind(LoadMap(o()));
639 434 : VariableList list({&original_map, &a_, &k_, &to_}, zone());
640 434 : Node* start = IntPtrOrSmiConstant(0, mode);
641 : Node* end = TaggedToParameter(len(), mode);
642 : IndexAdvanceMode advance_mode = direction == ForEachDirection::kReverse
643 : ? IndexAdvanceMode::kPre
644 434 : : IndexAdvanceMode::kPost;
645 434 : if (direction == ForEachDirection::kReverse) std::swap(start, end);
646 : BuildFastLoop(
647 : list, start, end,
648 1302 : [=, &original_map](Node* index) {
649 2170 : k_.Bind(ParameterToTagged(index, mode));
650 1302 : Label one_element_done(this), hole_element(this);
651 :
652 : // Check if o's map has changed during the callback. If so, we have to
653 : // fall back to the slower spec implementation for the rest of the
654 : // iteration.
655 1302 : Node* o_map = LoadMap(o());
656 1302 : GotoIf(WordNotEqual(o_map, original_map.value()), array_changed);
657 :
658 : // Check if o's length has changed during the callback and if the
659 : // index is now out of range of the new length.
660 1302 : GotoIf(SmiGreaterThanOrEqual(k_.value(), LoadJSArrayLength(o())),
661 1736 : array_changed);
662 :
663 : // Re-load the elements array. If may have been resized.
664 1302 : Node* elements = LoadElements(o());
665 :
666 : // Fast case: load the element directly from the elements FixedArray
667 : // and call the callback if the element is not the hole.
668 : DCHECK(kind == PACKED_ELEMENTS || kind == PACKED_DOUBLE_ELEMENTS);
669 434 : int base_size = kind == PACKED_ELEMENTS
670 : ? FixedArray::kHeaderSize
671 434 : : (FixedArray::kHeaderSize - kHeapObjectTag);
672 434 : Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size);
673 : Node* value = nullptr;
674 434 : if (kind == PACKED_ELEMENTS) {
675 217 : value = LoadObjectField(elements, offset);
676 651 : GotoIf(WordEqual(value, TheHoleConstant()), &hole_element);
677 : } else {
678 : Node* double_value =
679 217 : LoadDoubleWithHoleCheck(elements, offset, &hole_element);
680 434 : value = AllocateHeapNumberWithValue(double_value);
681 : }
682 868 : a_.Bind(processor(this, value, k()));
683 434 : Goto(&one_element_done);
684 :
685 434 : BIND(&hole_element);
686 : // Check if o's prototype change unexpectedly has elements after the
687 : // callback in the case of a hole.
688 : BranchIfPrototypesHaveNoElements(o_map, &one_element_done,
689 434 : array_changed);
690 :
691 434 : BIND(&one_element_done);
692 434 : },
693 1736 : 1, mode, advance_mode);
694 434 : Comment("end VisitAllFastElementsOneKind");
695 434 : }
696 :
697 217 : void HandleFastElements(const CallResultProcessor& processor,
698 : const PostLoopAction& action, Label* slow,
699 651 : ForEachDirection direction) {
700 434 : Label switch_on_elements_kind(this), fast_elements(this),
701 217 : maybe_double_elements(this), fast_double_elements(this);
702 :
703 217 : Comment("begin HandleFastElements");
704 : // Non-smi lengths must use the slow path.
705 434 : GotoIf(TaggedIsNotSmi(len()), slow);
706 :
707 : BranchIfFastJSArray(o(), context(),
708 217 : &switch_on_elements_kind, slow);
709 :
710 217 : BIND(&switch_on_elements_kind);
711 : // Select by ElementsKind
712 434 : Node* o_map = LoadMap(o());
713 434 : Node* bit_field2 = LoadMapBitField2(o_map);
714 : Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
715 : Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
716 434 : &maybe_double_elements, &fast_elements);
717 :
718 : ParameterMode mode = OptimalParameterMode();
719 217 : BIND(&fast_elements);
720 : {
721 : VisitAllFastElementsOneKind(PACKED_ELEMENTS, processor, slow, mode,
722 217 : direction);
723 :
724 217 : action(this);
725 :
726 : // No exception, return success
727 217 : ReturnFromBuiltin(a_.value());
728 : }
729 :
730 217 : BIND(&maybe_double_elements);
731 : Branch(IsElementsKindGreaterThan(kind, HOLEY_DOUBLE_ELEMENTS), slow,
732 434 : &fast_double_elements);
733 :
734 217 : BIND(&fast_double_elements);
735 : {
736 : VisitAllFastElementsOneKind(PACKED_DOUBLE_ELEMENTS, processor, slow, mode,
737 217 : direction);
738 :
739 217 : action(this);
740 :
741 : // No exception, return success
742 217 : ReturnFromBuiltin(a_.value());
743 217 : }
744 217 : }
745 :
746 : // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
747 : // This version is specialized to create a zero length array
748 : // of the elements kind of the input array.
749 186 : void ArraySpeciesCreate() {
750 62 : Label runtime(this, Label::kDeferred), done(this);
751 :
752 31 : TNode<Smi> len = SmiConstant(0);
753 31 : TNode<Map> original_map = LoadMap(o());
754 : GotoIfNot(
755 31 : InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
756 93 : &runtime);
757 :
758 : GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
759 62 : &runtime);
760 :
761 62 : Node* species_protector = SpeciesProtectorConstant();
762 : Node* value =
763 : LoadObjectField(species_protector, PropertyCell::kValueOffset);
764 : TNode<Smi> const protector_invalid =
765 31 : SmiConstant(Isolate::kProtectorInvalid);
766 31 : GotoIf(WordEqual(value, protector_invalid), &runtime);
767 :
768 : // Respect the ElementsKind of the input array.
769 31 : TNode<Int32T> elements_kind = LoadMapElementsKind(original_map);
770 62 : GotoIfNot(IsFastElementsKind(elements_kind), &runtime);
771 31 : TNode<Context> native_context = CAST(LoadNativeContext(context()));
772 : TNode<Map> array_map =
773 31 : CAST(LoadJSArrayElementsMap(elements_kind, native_context));
774 : TNode<JSArray> array =
775 31 : CAST(AllocateJSArray(GetInitialFastElementsKind(), array_map, len, len,
776 : nullptr, CodeStubAssembler::SMI_PARAMETERS));
777 31 : a_.Bind(array);
778 :
779 31 : Goto(&done);
780 :
781 31 : BIND(&runtime);
782 : {
783 : // 5. Let A be ? ArraySpeciesCreate(O, len).
784 : Node* constructor =
785 : CallRuntime(Runtime::kArraySpeciesConstructor, context(), o());
786 : a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(),
787 62 : constructor, len));
788 31 : Goto(&fully_spec_compliant_);
789 : }
790 :
791 62 : BIND(&done);
792 31 : }
793 :
794 : // Perform ArraySpeciesCreate (ES6 #sec-arrayspeciescreate).
795 186 : void ArraySpeciesCreate(SloppyTNode<Smi> len) {
796 62 : Label runtime(this, Label::kDeferred), done(this);
797 :
798 62 : Node* const original_map = LoadMap(o());
799 : GotoIfNot(
800 31 : InstanceTypeEqual(LoadMapInstanceType(original_map), JS_ARRAY_TYPE),
801 93 : &runtime);
802 :
803 : GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
804 62 : &runtime);
805 :
806 62 : Node* species_protector = SpeciesProtectorConstant();
807 : Node* value =
808 : LoadObjectField(species_protector, PropertyCell::kValueOffset);
809 62 : Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
810 62 : GotoIf(WordEqual(value, protector_invalid), &runtime);
811 :
812 62 : GotoIfNot(TaggedIsPositiveSmi(len), &runtime);
813 : GotoIf(SmiAbove(len, SmiConstant(JSArray::kInitialMaxFastElementArray)),
814 93 : &runtime);
815 :
816 : // We need to be conservative and start with holey because the builtins
817 : // that create output arrays aren't guaranteed to be called for every
818 : // element in the input array (maybe the callback deletes an element).
819 : const ElementsKind elements_kind =
820 : GetHoleyElementsKind(GetInitialFastElementsKind());
821 31 : TNode<Context> native_context = CAST(LoadNativeContext(context()));
822 : TNode<Map> array_map =
823 31 : CAST(LoadJSArrayElementsMap(elements_kind, native_context));
824 : a_.Bind(AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, len, len, nullptr,
825 31 : CodeStubAssembler::SMI_PARAMETERS));
826 :
827 31 : Goto(&done);
828 :
829 31 : BIND(&runtime);
830 : {
831 : // 5. Let A be ? ArraySpeciesCreate(O, len).
832 : Node* constructor =
833 : CallRuntime(Runtime::kArraySpeciesConstructor, context(), o());
834 : a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(),
835 62 : constructor, len));
836 31 : Goto(&fully_spec_compliant_);
837 : }
838 :
839 62 : BIND(&done);
840 31 : }
841 :
842 : Node* callbackfn_ = nullptr;
843 : Node* o_ = nullptr;
844 : Node* this_arg_ = nullptr;
845 : Node* len_ = nullptr;
846 : Node* context_ = nullptr;
847 : Node* receiver_ = nullptr;
848 : Node* new_target_ = nullptr;
849 : Node* argc_ = nullptr;
850 : Node* fast_typed_array_target_ = nullptr;
851 : const char* name_ = nullptr;
852 : Variable k_;
853 : Variable a_;
854 : Variable to_;
855 : Label fully_spec_compliant_;
856 : ElementsKind source_elements_kind_ = ElementsKind::NO_ELEMENTS;
857 : };
858 :
859 93 : TF_BUILTIN(FastArrayPop, CodeStubAssembler) {
860 : Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
861 : Node* context = Parameter(BuiltinDescriptor::kContext);
862 : CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
863 : UndefinedConstant()));
864 :
865 93 : CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
866 62 : Node* receiver = args.GetReceiver();
867 :
868 : Label runtime(this, Label::kDeferred);
869 31 : Label fast(this);
870 :
871 : // Only pop in this stub if
872 : // 1) the array has fast elements
873 : // 2) the length is writable,
874 : // 3) the elements backing store isn't copy-on-write,
875 : // 4) we aren't supposed to shrink the backing store.
876 :
877 : // 1) Check that the array has fast elements.
878 31 : BranchIfFastJSArray(receiver, context, &fast, &runtime);
879 :
880 31 : BIND(&fast);
881 : {
882 : CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(receiver)));
883 62 : Node* length = LoadAndUntagObjectField(receiver, JSArray::kLengthOffset);
884 31 : Label return_undefined(this), fast_elements(this);
885 93 : GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
886 :
887 : // 2) Ensure that the length is writable.
888 62 : EnsureArrayLengthWritable(LoadMap(receiver), &runtime);
889 :
890 : // 3) Check that the elements backing store isn't copy-on-write.
891 62 : Node* elements = LoadElements(receiver);
892 : GotoIf(WordEqual(LoadMap(elements),
893 93 : LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
894 31 : &runtime);
895 :
896 93 : Node* new_length = IntPtrSub(length, IntPtrConstant(1));
897 :
898 : // 4) Check that we're not supposed to shrink the backing store, as
899 : // implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
900 93 : Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
901 : GotoIf(IntPtrLessThan(
902 31 : IntPtrAdd(IntPtrAdd(new_length, new_length),
903 124 : IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
904 93 : capacity),
905 62 : &runtime);
906 :
907 : StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset,
908 62 : SmiTag(new_length));
909 :
910 93 : Node* elements_kind = LoadMapElementsKind(LoadMap(receiver));
911 : GotoIf(Int32LessThanOrEqual(elements_kind,
912 62 : Int32Constant(TERMINAL_FAST_ELEMENTS_KIND)),
913 62 : &fast_elements);
914 :
915 : Node* value = LoadFixedDoubleArrayElement(
916 : elements, new_length, MachineType::Float64(), 0, INTPTR_PARAMETERS,
917 31 : &return_undefined);
918 :
919 : int32_t header_size = FixedDoubleArray::kHeaderSize - kHeapObjectTag;
920 : Node* offset = ElementOffsetFromIndex(new_length, HOLEY_DOUBLE_ELEMENTS,
921 31 : INTPTR_PARAMETERS, header_size);
922 31 : if (Is64()) {
923 62 : Node* double_hole = Int64Constant(kHoleNanInt64);
924 : StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset,
925 31 : double_hole);
926 : } else {
927 : STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32);
928 0 : Node* double_hole = Int32Constant(kHoleNanLower32);
929 : StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
930 0 : double_hole);
931 : StoreNoWriteBarrier(MachineRepresentation::kWord32, elements,
932 0 : IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
933 0 : double_hole);
934 : }
935 62 : args.PopAndReturn(AllocateHeapNumberWithValue(value));
936 :
937 31 : BIND(&fast_elements);
938 : {
939 31 : Node* value = LoadFixedArrayElement(elements, new_length);
940 62 : StoreFixedArrayElement(elements, new_length, TheHoleConstant());
941 62 : GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
942 31 : args.PopAndReturn(value);
943 : }
944 :
945 31 : BIND(&return_undefined);
946 93 : { args.PopAndReturn(UndefinedConstant()); }
947 : }
948 :
949 31 : BIND(&runtime);
950 : {
951 : Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
952 31 : MachineType::TaggedPointer());
953 : TailCallStub(CodeFactory::ArrayPop(isolate()), context, target,
954 62 : UndefinedConstant(), argc);
955 31 : }
956 31 : }
957 :
958 124 : TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
959 31 : TVARIABLE(IntPtrT, arg_index);
960 31 : Label default_label(this, &arg_index);
961 31 : Label smi_transition(this);
962 31 : Label object_push_pre(this);
963 31 : Label object_push(this, &arg_index);
964 31 : Label double_push(this, &arg_index);
965 31 : Label double_transition(this);
966 31 : Label runtime(this, Label::kDeferred);
967 :
968 : // TODO(ishell): use constants from Descriptor once the JSFunction linkage
969 : // arguments are reordered.
970 : Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
971 : Node* context = Parameter(BuiltinDescriptor::kContext);
972 : CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
973 : UndefinedConstant()));
974 :
975 93 : CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
976 62 : Node* receiver = args.GetReceiver();
977 : Node* kind = nullptr;
978 :
979 31 : Label fast(this);
980 31 : BranchIfFastJSArray(receiver, context, &fast, &runtime);
981 :
982 31 : BIND(&fast);
983 : {
984 31 : arg_index = IntPtrConstant(0);
985 31 : kind = EnsureArrayPushable(receiver, &runtime);
986 : GotoIf(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
987 62 : &object_push_pre);
988 :
989 : Node* new_length = BuildAppendJSArray(PACKED_SMI_ELEMENTS, receiver, &args,
990 62 : &arg_index, &smi_transition);
991 31 : args.PopAndReturn(new_length);
992 : }
993 :
994 : // If the argument is not a smi, then use a heavyweight SetProperty to
995 : // transition the array for only the single next element. If the argument is
996 : // a smi, the failure is due to some other reason and we should fall back on
997 : // the most generic implementation for the rest of the array.
998 31 : BIND(&smi_transition);
999 : {
1000 62 : Node* arg = args.AtIndex(arg_index);
1001 62 : GotoIf(TaggedIsSmi(arg), &default_label);
1002 62 : Node* length = LoadJSArrayLength(receiver);
1003 : // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
1004 : // calling into the runtime to do the elements transition is overkill.
1005 : CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
1006 31 : SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
1007 31 : Increment(&arg_index);
1008 : // The runtime SetProperty call could have converted the array to dictionary
1009 : // mode, which must be detected to abort the fast-path.
1010 62 : Node* map = LoadMap(receiver);
1011 62 : Node* bit_field2 = LoadMapBitField2(map);
1012 : Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
1013 62 : GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
1014 62 : &default_label);
1015 :
1016 31 : GotoIfNotNumber(arg, &object_push);
1017 31 : Goto(&double_push);
1018 : }
1019 :
1020 31 : BIND(&object_push_pre);
1021 : {
1022 : Branch(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &double_push,
1023 62 : &object_push);
1024 : }
1025 :
1026 31 : BIND(&object_push);
1027 : {
1028 : Node* new_length = BuildAppendJSArray(PACKED_ELEMENTS, receiver, &args,
1029 62 : &arg_index, &default_label);
1030 31 : args.PopAndReturn(new_length);
1031 : }
1032 :
1033 31 : BIND(&double_push);
1034 : {
1035 : Node* new_length =
1036 : BuildAppendJSArray(PACKED_DOUBLE_ELEMENTS, receiver, &args, &arg_index,
1037 62 : &double_transition);
1038 31 : args.PopAndReturn(new_length);
1039 : }
1040 :
1041 : // If the argument is not a double, then use a heavyweight SetProperty to
1042 : // transition the array for only the single next element. If the argument is
1043 : // a double, the failure is due to some other reason and we should fall back
1044 : // on the most generic implementation for the rest of the array.
1045 31 : BIND(&double_transition);
1046 : {
1047 62 : Node* arg = args.AtIndex(arg_index);
1048 31 : GotoIfNumber(arg, &default_label);
1049 62 : Node* length = LoadJSArrayLength(receiver);
1050 : // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
1051 : // calling into the runtime to do the elements transition is overkill.
1052 : CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
1053 31 : SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
1054 31 : Increment(&arg_index);
1055 : // The runtime SetProperty call could have converted the array to dictionary
1056 : // mode, which must be detected to abort the fast-path.
1057 62 : Node* map = LoadMap(receiver);
1058 62 : Node* bit_field2 = LoadMapBitField2(map);
1059 : Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
1060 62 : GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
1061 62 : &default_label);
1062 31 : Goto(&object_push);
1063 : }
1064 :
1065 : // Fallback that stores un-processed arguments using the full, heavyweight
1066 : // SetProperty machinery.
1067 31 : BIND(&default_label);
1068 : {
1069 : args.ForEach(
1070 31 : [this, receiver, context](Node* arg) {
1071 93 : Node* length = LoadJSArrayLength(receiver);
1072 : CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
1073 31 : SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
1074 31 : },
1075 62 : arg_index);
1076 62 : args.PopAndReturn(LoadJSArrayLength(receiver));
1077 : }
1078 :
1079 31 : BIND(&runtime);
1080 : {
1081 : Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
1082 31 : MachineType::TaggedPointer());
1083 : TailCallStub(CodeFactory::ArrayPush(isolate()), context, target,
1084 62 : UndefinedConstant(), argc);
1085 : }
1086 31 : }
1087 :
1088 93 : TF_BUILTIN(FastArrayShift, CodeStubAssembler) {
1089 : Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
1090 : Node* context = Parameter(BuiltinDescriptor::kContext);
1091 : CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
1092 : UndefinedConstant()));
1093 :
1094 93 : CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
1095 62 : Node* receiver = args.GetReceiver();
1096 :
1097 : Label runtime(this, Label::kDeferred);
1098 31 : Label fast(this);
1099 :
1100 : // Only shift in this stub if
1101 : // 1) the array has fast elements
1102 : // 2) the length is writable,
1103 : // 3) the elements backing store isn't copy-on-write,
1104 : // 4) we aren't supposed to shrink the backing store,
1105 : // 5) we aren't supposed to left-trim the backing store.
1106 :
1107 : // 1) Check that the array has fast elements.
1108 31 : BranchIfFastJSArray(receiver, context, &fast, &runtime);
1109 :
1110 31 : BIND(&fast);
1111 : {
1112 : CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(receiver)));
1113 62 : Node* length = LoadAndUntagObjectField(receiver, JSArray::kLengthOffset);
1114 31 : Label return_undefined(this), fast_elements_tagged(this),
1115 31 : fast_elements_smi(this);
1116 93 : GotoIf(IntPtrEqual(length, IntPtrConstant(0)), &return_undefined);
1117 :
1118 : // 2) Ensure that the length is writable.
1119 62 : EnsureArrayLengthWritable(LoadMap(receiver), &runtime);
1120 :
1121 : // 3) Check that the elements backing store isn't copy-on-write.
1122 62 : Node* elements = LoadElements(receiver);
1123 : GotoIf(WordEqual(LoadMap(elements),
1124 93 : LoadRoot(Heap::kFixedCOWArrayMapRootIndex)),
1125 31 : &runtime);
1126 :
1127 93 : Node* new_length = IntPtrSub(length, IntPtrConstant(1));
1128 :
1129 : // 4) Check that we're not supposed to right-trim the backing store, as
1130 : // implemented in elements.cc:ElementsAccessorBase::SetLengthImpl.
1131 124 : Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
1132 : GotoIf(IntPtrLessThan(
1133 31 : IntPtrAdd(IntPtrAdd(new_length, new_length),
1134 124 : IntPtrConstant(JSObject::kMinAddedElementsCapacity)),
1135 93 : capacity),
1136 62 : &runtime);
1137 :
1138 : // 5) Check that we're not supposed to left-trim the backing store, as
1139 : // implemented in elements.cc:FastElementsAccessor::MoveElements.
1140 : GotoIf(IntPtrGreaterThan(new_length,
1141 62 : IntPtrConstant(JSArray::kMaxCopyElements)),
1142 62 : &runtime);
1143 :
1144 : StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset,
1145 62 : SmiTag(new_length));
1146 :
1147 93 : Node* elements_kind = LoadMapElementsKind(LoadMap(receiver));
1148 : GotoIf(
1149 62 : Int32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_SMI_ELEMENTS)),
1150 62 : &fast_elements_smi);
1151 62 : GotoIf(Int32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
1152 62 : &fast_elements_tagged);
1153 :
1154 : // Fast double elements kind:
1155 : {
1156 : CSA_ASSERT(this,
1157 : Int32LessThanOrEqual(elements_kind,
1158 : Int32Constant(HOLEY_DOUBLE_ELEMENTS)));
1159 :
1160 62 : VARIABLE(result, MachineRepresentation::kTagged, UndefinedConstant());
1161 :
1162 31 : Label move_elements(this);
1163 : result.Bind(AllocateHeapNumberWithValue(LoadFixedDoubleArrayElement(
1164 : elements, IntPtrConstant(0), MachineType::Float64(), 0,
1165 124 : INTPTR_PARAMETERS, &move_elements)));
1166 31 : Goto(&move_elements);
1167 31 : BIND(&move_elements);
1168 :
1169 : int32_t header_size = FixedDoubleArray::kHeaderSize - kHeapObjectTag;
1170 : Node* memmove =
1171 62 : ExternalConstant(ExternalReference::libc_memmove_function(isolate()));
1172 : Node* start = IntPtrAdd(
1173 62 : BitcastTaggedToWord(elements),
1174 : ElementOffsetFromIndex(IntPtrConstant(0), HOLEY_DOUBLE_ELEMENTS,
1175 186 : INTPTR_PARAMETERS, header_size));
1176 : CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
1177 : MachineType::Pointer(), MachineType::UintPtr(), memmove,
1178 62 : start, IntPtrAdd(start, IntPtrConstant(kDoubleSize)),
1179 155 : IntPtrMul(new_length, IntPtrConstant(kDoubleSize)));
1180 : Node* offset = ElementOffsetFromIndex(new_length, HOLEY_DOUBLE_ELEMENTS,
1181 31 : INTPTR_PARAMETERS, header_size);
1182 31 : if (Is64()) {
1183 62 : Node* double_hole = Int64Constant(kHoleNanInt64);
1184 : StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset,
1185 31 : double_hole);
1186 : } else {
1187 : STATIC_ASSERT(kHoleNanLower32 == kHoleNanUpper32);
1188 0 : Node* double_hole = Int32Constant(kHoleNanLower32);
1189 : StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset,
1190 0 : double_hole);
1191 : StoreNoWriteBarrier(MachineRepresentation::kWord32, elements,
1192 0 : IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
1193 0 : double_hole);
1194 : }
1195 62 : args.PopAndReturn(result.value());
1196 : }
1197 :
1198 31 : BIND(&fast_elements_tagged);
1199 : {
1200 31 : Node* value = LoadFixedArrayElement(elements, 0);
1201 : BuildFastLoop(IntPtrConstant(0), new_length,
1202 31 : [&](Node* index) {
1203 : StoreFixedArrayElement(
1204 : elements, index,
1205 : LoadFixedArrayElement(
1206 93 : elements, IntPtrAdd(index, IntPtrConstant(1))));
1207 31 : },
1208 : 1, ParameterMode::INTPTR_PARAMETERS,
1209 93 : IndexAdvanceMode::kPost);
1210 62 : StoreFixedArrayElement(elements, new_length, TheHoleConstant());
1211 62 : GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
1212 31 : args.PopAndReturn(value);
1213 : }
1214 :
1215 31 : BIND(&fast_elements_smi);
1216 : {
1217 31 : Node* value = LoadFixedArrayElement(elements, 0);
1218 : BuildFastLoop(IntPtrConstant(0), new_length,
1219 31 : [&](Node* index) {
1220 : StoreFixedArrayElement(
1221 : elements, index,
1222 : LoadFixedArrayElement(
1223 93 : elements, IntPtrAdd(index, IntPtrConstant(1))),
1224 62 : SKIP_WRITE_BARRIER);
1225 31 : },
1226 : 1, ParameterMode::INTPTR_PARAMETERS,
1227 93 : IndexAdvanceMode::kPost);
1228 62 : StoreFixedArrayElement(elements, new_length, TheHoleConstant());
1229 62 : GotoIf(WordEqual(value, TheHoleConstant()), &return_undefined);
1230 31 : args.PopAndReturn(value);
1231 : }
1232 :
1233 31 : BIND(&return_undefined);
1234 93 : { args.PopAndReturn(UndefinedConstant()); }
1235 : }
1236 :
1237 31 : BIND(&runtime);
1238 : {
1239 : Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
1240 31 : MachineType::TaggedPointer());
1241 : TailCallStub(CodeFactory::ArrayShift(isolate()), context, target,
1242 62 : UndefinedConstant(), argc);
1243 31 : }
1244 31 : }
1245 :
1246 62 : TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) {
1247 : Node* context = Parameter(Descriptor::kContext);
1248 : Node* receiver = Parameter(Descriptor::kReceiver);
1249 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1250 : Node* this_arg = Parameter(Descriptor::kThisArg);
1251 : Node* array = Parameter(Descriptor::kArray);
1252 : Node* object = Parameter(Descriptor::kObject);
1253 : Node* initial_k = Parameter(Descriptor::kInitialK);
1254 : Node* len = Parameter(Descriptor::kLength);
1255 : Node* to = Parameter(Descriptor::kTo);
1256 :
1257 : InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1258 : this_arg, array, object, initial_k,
1259 : len, to);
1260 :
1261 : GenerateIteratingArrayBuiltinLoopContinuation(
1262 : &ArrayBuiltinCodeStubAssembler::ForEachProcessor,
1263 93 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1264 31 : }
1265 :
1266 62 : TF_BUILTIN(ArrayForEachLoopEagerDeoptContinuation,
1267 : ArrayBuiltinCodeStubAssembler) {
1268 : Node* context = Parameter(Descriptor::kContext);
1269 : Node* receiver = Parameter(Descriptor::kReceiver);
1270 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1271 : Node* this_arg = Parameter(Descriptor::kThisArg);
1272 : Node* initial_k = Parameter(Descriptor::kInitialK);
1273 : Node* len = Parameter(Descriptor::kLength);
1274 :
1275 : Callable stub(Builtins::CallableFor(isolate(),
1276 31 : Builtins::kArrayForEachLoopContinuation));
1277 : Return(CallStub(stub, context, receiver, callbackfn, this_arg,
1278 : UndefinedConstant(), receiver, initial_k, len,
1279 62 : UndefinedConstant()));
1280 31 : }
1281 :
1282 62 : TF_BUILTIN(ArrayForEachLoopLazyDeoptContinuation,
1283 : ArrayBuiltinCodeStubAssembler) {
1284 : Node* context = Parameter(Descriptor::kContext);
1285 : Node* receiver = Parameter(Descriptor::kReceiver);
1286 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1287 : Node* this_arg = Parameter(Descriptor::kThisArg);
1288 : Node* initial_k = Parameter(Descriptor::kInitialK);
1289 : Node* len = Parameter(Descriptor::kLength);
1290 :
1291 : Callable stub(Builtins::CallableFor(isolate(),
1292 31 : Builtins::kArrayForEachLoopContinuation));
1293 : Return(CallStub(stub, context, receiver, callbackfn, this_arg,
1294 : UndefinedConstant(), receiver, initial_k, len,
1295 62 : UndefinedConstant()));
1296 31 : }
1297 :
1298 93 : TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) {
1299 : Node* argc =
1300 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1301 31 : CodeStubArguments args(this, argc);
1302 : Node* context = Parameter(BuiltinDescriptor::kContext);
1303 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1304 62 : Node* receiver = args.GetReceiver();
1305 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1306 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1307 :
1308 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1309 : new_target, argc);
1310 :
1311 : GenerateIteratingArrayBuiltinBody(
1312 : "Array.prototype.forEach",
1313 : &ArrayBuiltinCodeStubAssembler::ForEachResultGenerator,
1314 : &ArrayBuiltinCodeStubAssembler::ForEachProcessor,
1315 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
1316 : Builtins::CallableFor(isolate(),
1317 155 : Builtins::kArrayForEachLoopContinuation));
1318 31 : }
1319 :
1320 93 : TF_BUILTIN(TypedArrayPrototypeForEach, ArrayBuiltinCodeStubAssembler) {
1321 : Node* argc =
1322 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1323 31 : CodeStubArguments args(this, argc);
1324 : Node* context = Parameter(BuiltinDescriptor::kContext);
1325 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1326 62 : Node* receiver = args.GetReceiver();
1327 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1328 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1329 :
1330 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1331 : new_target, argc);
1332 :
1333 : GenerateIteratingTypedArrayBuiltinBody(
1334 : "%TypedArray%.prototype.forEach",
1335 : &ArrayBuiltinCodeStubAssembler::ForEachResultGenerator,
1336 : &ArrayBuiltinCodeStubAssembler::ForEachProcessor,
1337 124 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1338 31 : }
1339 :
1340 62 : TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) {
1341 : Node* context = Parameter(Descriptor::kContext);
1342 : Node* receiver = Parameter(Descriptor::kReceiver);
1343 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1344 : Node* this_arg = Parameter(Descriptor::kThisArg);
1345 : Node* array = Parameter(Descriptor::kArray);
1346 : Node* object = Parameter(Descriptor::kObject);
1347 : Node* initial_k = Parameter(Descriptor::kInitialK);
1348 : Node* len = Parameter(Descriptor::kLength);
1349 : Node* to = Parameter(Descriptor::kTo);
1350 :
1351 : InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1352 : this_arg, array, object, initial_k,
1353 : len, to);
1354 :
1355 : GenerateIteratingArrayBuiltinLoopContinuation(
1356 : &ArrayBuiltinCodeStubAssembler::SomeProcessor,
1357 93 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1358 31 : }
1359 :
1360 93 : TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) {
1361 : Node* argc =
1362 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1363 31 : CodeStubArguments args(this, argc);
1364 : Node* context = Parameter(BuiltinDescriptor::kContext);
1365 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1366 62 : Node* receiver = args.GetReceiver();
1367 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1368 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1369 :
1370 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1371 : new_target, argc);
1372 :
1373 : GenerateIteratingArrayBuiltinBody(
1374 : "Array.prototype.some",
1375 : &ArrayBuiltinCodeStubAssembler::SomeResultGenerator,
1376 : &ArrayBuiltinCodeStubAssembler::SomeProcessor,
1377 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
1378 155 : Builtins::CallableFor(isolate(), Builtins::kArraySomeLoopContinuation));
1379 31 : }
1380 :
1381 93 : TF_BUILTIN(TypedArrayPrototypeSome, ArrayBuiltinCodeStubAssembler) {
1382 : Node* argc =
1383 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1384 31 : CodeStubArguments args(this, argc);
1385 : Node* context = Parameter(BuiltinDescriptor::kContext);
1386 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1387 62 : Node* receiver = args.GetReceiver();
1388 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1389 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1390 :
1391 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1392 : new_target, argc);
1393 :
1394 : GenerateIteratingTypedArrayBuiltinBody(
1395 : "%TypedArray%.prototype.some",
1396 : &ArrayBuiltinCodeStubAssembler::SomeResultGenerator,
1397 : &ArrayBuiltinCodeStubAssembler::SomeProcessor,
1398 124 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1399 31 : }
1400 :
1401 62 : TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) {
1402 : Node* context = Parameter(Descriptor::kContext);
1403 : Node* receiver = Parameter(Descriptor::kReceiver);
1404 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1405 : Node* this_arg = Parameter(Descriptor::kThisArg);
1406 : Node* array = Parameter(Descriptor::kArray);
1407 : Node* object = Parameter(Descriptor::kObject);
1408 : Node* initial_k = Parameter(Descriptor::kInitialK);
1409 : Node* len = Parameter(Descriptor::kLength);
1410 : Node* to = Parameter(Descriptor::kTo);
1411 :
1412 : InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1413 : this_arg, array, object, initial_k,
1414 : len, to);
1415 :
1416 : GenerateIteratingArrayBuiltinLoopContinuation(
1417 : &ArrayBuiltinCodeStubAssembler::EveryProcessor,
1418 93 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1419 31 : }
1420 :
1421 93 : TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) {
1422 : Node* argc =
1423 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1424 31 : CodeStubArguments args(this, argc);
1425 : Node* context = Parameter(BuiltinDescriptor::kContext);
1426 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1427 62 : Node* receiver = args.GetReceiver();
1428 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1429 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1430 :
1431 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1432 : new_target, argc);
1433 :
1434 : GenerateIteratingArrayBuiltinBody(
1435 : "Array.prototype.every",
1436 : &ArrayBuiltinCodeStubAssembler::EveryResultGenerator,
1437 : &ArrayBuiltinCodeStubAssembler::EveryProcessor,
1438 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
1439 155 : Builtins::CallableFor(isolate(), Builtins::kArrayEveryLoopContinuation));
1440 31 : }
1441 :
1442 93 : TF_BUILTIN(TypedArrayPrototypeEvery, ArrayBuiltinCodeStubAssembler) {
1443 : Node* argc =
1444 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1445 31 : CodeStubArguments args(this, argc);
1446 : Node* context = Parameter(BuiltinDescriptor::kContext);
1447 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1448 62 : Node* receiver = args.GetReceiver();
1449 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1450 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1451 :
1452 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1453 : new_target, argc);
1454 :
1455 : GenerateIteratingTypedArrayBuiltinBody(
1456 : "%TypedArray%.prototype.every",
1457 : &ArrayBuiltinCodeStubAssembler::EveryResultGenerator,
1458 : &ArrayBuiltinCodeStubAssembler::EveryProcessor,
1459 124 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1460 31 : }
1461 :
1462 62 : TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinCodeStubAssembler) {
1463 : Node* context = Parameter(Descriptor::kContext);
1464 : Node* receiver = Parameter(Descriptor::kReceiver);
1465 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1466 : Node* this_arg = Parameter(Descriptor::kThisArg);
1467 : Node* accumulator = Parameter(Descriptor::kAccumulator);
1468 : Node* object = Parameter(Descriptor::kObject);
1469 : Node* initial_k = Parameter(Descriptor::kInitialK);
1470 : Node* len = Parameter(Descriptor::kLength);
1471 : Node* to = Parameter(Descriptor::kTo);
1472 :
1473 : InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1474 : this_arg, accumulator, object,
1475 : initial_k, len, to);
1476 :
1477 : GenerateIteratingArrayBuiltinLoopContinuation(
1478 : &ArrayBuiltinCodeStubAssembler::ReduceProcessor,
1479 93 : &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction);
1480 31 : }
1481 :
1482 93 : TF_BUILTIN(ArrayReduce, ArrayBuiltinCodeStubAssembler) {
1483 : Node* argc =
1484 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1485 31 : CodeStubArguments args(this, argc);
1486 : Node* context = Parameter(BuiltinDescriptor::kContext);
1487 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1488 62 : Node* receiver = args.GetReceiver();
1489 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1490 93 : Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
1491 :
1492 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
1493 : new_target, argc);
1494 :
1495 : GenerateIteratingArrayBuiltinBody(
1496 : "Array.prototype.reduce",
1497 : &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator,
1498 : &ArrayBuiltinCodeStubAssembler::ReduceProcessor,
1499 : &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
1500 155 : Builtins::CallableFor(isolate(), Builtins::kArrayReduceLoopContinuation));
1501 31 : }
1502 :
1503 93 : TF_BUILTIN(TypedArrayPrototypeReduce, ArrayBuiltinCodeStubAssembler) {
1504 : Node* argc =
1505 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1506 31 : CodeStubArguments args(this, argc);
1507 : Node* context = Parameter(BuiltinDescriptor::kContext);
1508 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1509 62 : Node* receiver = args.GetReceiver();
1510 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1511 93 : Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
1512 :
1513 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
1514 : new_target, argc);
1515 :
1516 : GenerateIteratingTypedArrayBuiltinBody(
1517 : "%TypedArray%.prototype.reduce",
1518 : &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator,
1519 : &ArrayBuiltinCodeStubAssembler::ReduceProcessor,
1520 124 : &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction);
1521 31 : }
1522 :
1523 62 : TF_BUILTIN(ArrayReduceRightLoopContinuation, ArrayBuiltinCodeStubAssembler) {
1524 : Node* context = Parameter(Descriptor::kContext);
1525 : Node* receiver = Parameter(Descriptor::kReceiver);
1526 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1527 : Node* this_arg = Parameter(Descriptor::kThisArg);
1528 : Node* accumulator = Parameter(Descriptor::kAccumulator);
1529 : Node* object = Parameter(Descriptor::kObject);
1530 : Node* initial_k = Parameter(Descriptor::kInitialK);
1531 : Node* len = Parameter(Descriptor::kLength);
1532 : Node* to = Parameter(Descriptor::kTo);
1533 :
1534 : InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1535 : this_arg, accumulator, object,
1536 : initial_k, len, to);
1537 :
1538 : GenerateIteratingArrayBuiltinLoopContinuation(
1539 : &ArrayBuiltinCodeStubAssembler::ReduceProcessor,
1540 : &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
1541 93 : ForEachDirection::kReverse);
1542 31 : }
1543 :
1544 93 : TF_BUILTIN(ArrayReduceRight, ArrayBuiltinCodeStubAssembler) {
1545 : Node* argc =
1546 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1547 31 : CodeStubArguments args(this, argc);
1548 : Node* context = Parameter(BuiltinDescriptor::kContext);
1549 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1550 62 : Node* receiver = args.GetReceiver();
1551 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1552 93 : Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
1553 :
1554 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
1555 : new_target, argc);
1556 :
1557 : GenerateIteratingArrayBuiltinBody(
1558 : "Array.prototype.reduceRight",
1559 : &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator,
1560 : &ArrayBuiltinCodeStubAssembler::ReduceProcessor,
1561 : &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
1562 : Builtins::CallableFor(isolate(),
1563 : Builtins::kArrayReduceRightLoopContinuation),
1564 155 : ForEachDirection::kReverse);
1565 31 : }
1566 :
1567 93 : TF_BUILTIN(TypedArrayPrototypeReduceRight, ArrayBuiltinCodeStubAssembler) {
1568 : Node* argc =
1569 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1570 31 : CodeStubArguments args(this, argc);
1571 : Node* context = Parameter(BuiltinDescriptor::kContext);
1572 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1573 62 : Node* receiver = args.GetReceiver();
1574 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1575 93 : Node* initial_value = args.GetOptionalArgumentValue(1, TheHoleConstant());
1576 :
1577 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value,
1578 : new_target, argc);
1579 :
1580 : GenerateIteratingTypedArrayBuiltinBody(
1581 : "%TypedArray%.prototype.reduceRight",
1582 : &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator,
1583 : &ArrayBuiltinCodeStubAssembler::ReduceProcessor,
1584 : &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction,
1585 124 : ForEachDirection::kReverse);
1586 31 : }
1587 :
1588 62 : TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) {
1589 : Node* context = Parameter(Descriptor::kContext);
1590 : Node* receiver = Parameter(Descriptor::kReceiver);
1591 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1592 : Node* this_arg = Parameter(Descriptor::kThisArg);
1593 : Node* array = Parameter(Descriptor::kArray);
1594 : Node* object = Parameter(Descriptor::kObject);
1595 : Node* initial_k = Parameter(Descriptor::kInitialK);
1596 : Node* len = Parameter(Descriptor::kLength);
1597 : Node* to = Parameter(Descriptor::kTo);
1598 :
1599 : InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1600 : this_arg, array, object, initial_k,
1601 : len, to);
1602 :
1603 : GenerateIteratingArrayBuiltinLoopContinuation(
1604 : &ArrayBuiltinCodeStubAssembler::FilterProcessor,
1605 93 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1606 31 : }
1607 :
1608 93 : TF_BUILTIN(ArrayFilter, ArrayBuiltinCodeStubAssembler) {
1609 : Node* argc =
1610 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1611 31 : CodeStubArguments args(this, argc);
1612 : Node* context = Parameter(BuiltinDescriptor::kContext);
1613 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1614 62 : Node* receiver = args.GetReceiver();
1615 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1616 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1617 :
1618 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1619 : new_target, argc);
1620 :
1621 : GenerateIteratingArrayBuiltinBody(
1622 : "Array.prototype.filter",
1623 : &ArrayBuiltinCodeStubAssembler::FilterResultGenerator,
1624 : &ArrayBuiltinCodeStubAssembler::FilterProcessor,
1625 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
1626 155 : Builtins::CallableFor(isolate(), Builtins::kArrayFilterLoopContinuation));
1627 31 : }
1628 :
1629 62 : TF_BUILTIN(ArrayMapLoopContinuation, ArrayBuiltinCodeStubAssembler) {
1630 : Node* context = Parameter(Descriptor::kContext);
1631 : Node* receiver = Parameter(Descriptor::kReceiver);
1632 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1633 : Node* this_arg = Parameter(Descriptor::kThisArg);
1634 : Node* array = Parameter(Descriptor::kArray);
1635 : Node* object = Parameter(Descriptor::kObject);
1636 : Node* initial_k = Parameter(Descriptor::kInitialK);
1637 : Node* len = Parameter(Descriptor::kLength);
1638 : Node* to = Parameter(Descriptor::kTo);
1639 :
1640 : InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn,
1641 : this_arg, array, object, initial_k,
1642 : len, to);
1643 :
1644 : GenerateIteratingArrayBuiltinLoopContinuation(
1645 : &ArrayBuiltinCodeStubAssembler::SpecCompliantMapProcessor,
1646 93 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1647 31 : }
1648 :
1649 62 : TF_BUILTIN(ArrayMapLoopEagerDeoptContinuation, ArrayBuiltinCodeStubAssembler) {
1650 : Node* context = Parameter(Descriptor::kContext);
1651 : Node* receiver = Parameter(Descriptor::kReceiver);
1652 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1653 : Node* this_arg = Parameter(Descriptor::kThisArg);
1654 : Node* array = Parameter(Descriptor::kArray);
1655 : Node* initial_k = Parameter(Descriptor::kInitialK);
1656 : Node* len = Parameter(Descriptor::kLength);
1657 :
1658 : Callable stub(
1659 31 : Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation));
1660 : Return(CallStub(stub, context, receiver, callbackfn, this_arg, array,
1661 62 : receiver, initial_k, len, UndefinedConstant()));
1662 31 : }
1663 :
1664 62 : TF_BUILTIN(ArrayMapLoopLazyDeoptContinuation, ArrayBuiltinCodeStubAssembler) {
1665 : Node* context = Parameter(Descriptor::kContext);
1666 : Node* receiver = Parameter(Descriptor::kReceiver);
1667 : Node* callbackfn = Parameter(Descriptor::kCallbackFn);
1668 : Node* this_arg = Parameter(Descriptor::kThisArg);
1669 : Node* array = Parameter(Descriptor::kArray);
1670 : Node* initial_k = Parameter(Descriptor::kInitialK);
1671 : Node* len = Parameter(Descriptor::kLength);
1672 : Node* result = Parameter(Descriptor::kResult);
1673 :
1674 : // This custom lazy deopt point is right after the callback. map() needs
1675 : // to pick up at the next step, which is setting the callback result in
1676 : // the output array. After incrementing k, we can glide into the loop
1677 : // continuation builtin.
1678 :
1679 : // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
1680 : CallRuntime(Runtime::kCreateDataProperty, context, array, initial_k, result);
1681 : // Then we have to increment k before going on.
1682 31 : initial_k = NumberInc(initial_k);
1683 :
1684 : Callable stub(
1685 31 : Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation));
1686 : Return(CallStub(stub, context, receiver, callbackfn, this_arg, array,
1687 62 : receiver, initial_k, len, UndefinedConstant()));
1688 31 : }
1689 :
1690 93 : TF_BUILTIN(ArrayMap, ArrayBuiltinCodeStubAssembler) {
1691 : Node* argc =
1692 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1693 31 : CodeStubArguments args(this, argc);
1694 : Node* context = Parameter(BuiltinDescriptor::kContext);
1695 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1696 62 : Node* receiver = args.GetReceiver();
1697 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1698 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1699 :
1700 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1701 : new_target, argc);
1702 :
1703 : GenerateIteratingArrayBuiltinBody(
1704 : "Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator,
1705 : &ArrayBuiltinCodeStubAssembler::FastMapProcessor,
1706 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
1707 155 : Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation));
1708 31 : }
1709 :
1710 93 : TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinCodeStubAssembler) {
1711 : Node* argc =
1712 62 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1713 31 : CodeStubArguments args(this, argc);
1714 : Node* context = Parameter(BuiltinDescriptor::kContext);
1715 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
1716 62 : Node* receiver = args.GetReceiver();
1717 62 : Node* callbackfn = args.GetOptionalArgumentValue(0);
1718 62 : Node* this_arg = args.GetOptionalArgumentValue(1);
1719 :
1720 : InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
1721 : new_target, argc);
1722 :
1723 : GenerateIteratingTypedArrayBuiltinBody(
1724 : "%TypedArray%.prototype.map",
1725 : &ArrayBuiltinCodeStubAssembler::TypedArrayMapResultGenerator,
1726 : &ArrayBuiltinCodeStubAssembler::TypedArrayMapProcessor,
1727 124 : &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
1728 31 : }
1729 :
1730 93 : TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
1731 : TNode<Object> object = CAST(Parameter(Descriptor::kArg));
1732 : TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1733 :
1734 31 : Label call_runtime(this), return_true(this), return_false(this);
1735 :
1736 62 : GotoIf(TaggedIsSmi(object), &return_false);
1737 62 : TNode<Word32T> instance_type = LoadInstanceType(CAST(object));
1738 :
1739 62 : GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &return_true);
1740 :
1741 : // TODO(verwaest): Handle proxies in-place.
1742 : Branch(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), &call_runtime,
1743 62 : &return_false);
1744 :
1745 31 : BIND(&return_true);
1746 62 : Return(BooleanConstant(true));
1747 :
1748 31 : BIND(&return_false);
1749 62 : Return(BooleanConstant(false));
1750 :
1751 31 : BIND(&call_runtime);
1752 62 : Return(CallRuntime(Runtime::kArrayIsArray, context, object));
1753 31 : }
1754 :
1755 : class ArrayIncludesIndexofAssembler : public CodeStubAssembler {
1756 : public:
1757 : explicit ArrayIncludesIndexofAssembler(compiler::CodeAssemblerState* state)
1758 62 : : CodeStubAssembler(state) {}
1759 :
1760 : enum SearchVariant { kIncludes, kIndexOf };
1761 :
1762 : void Generate(SearchVariant variant);
1763 : };
1764 :
1765 62 : void ArrayIncludesIndexofAssembler::Generate(SearchVariant variant) {
1766 : const int kSearchElementArg = 0;
1767 : const int kFromIndexArg = 1;
1768 :
1769 : TNode<IntPtrT> argc =
1770 124 : ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
1771 62 : CodeStubArguments args(this, argc);
1772 :
1773 62 : TNode<Object> receiver = args.GetReceiver();
1774 : TNode<Object> search_element =
1775 62 : args.GetOptionalArgumentValue(kSearchElementArg);
1776 62 : Node* context = Parameter(BuiltinDescriptor::kContext);
1777 :
1778 124 : Node* intptr_zero = IntPtrConstant(0);
1779 :
1780 62 : Label init_index(this), return_found(this), return_not_found(this),
1781 62 : call_runtime(this);
1782 :
1783 : // Take slow path if not a JSArray, if retrieving elements requires
1784 : // traversing prototype, or if access checks are required.
1785 62 : BranchIfFastJSArray(receiver, context, &init_index, &call_runtime);
1786 :
1787 62 : BIND(&init_index);
1788 124 : VARIABLE(index_var, MachineType::PointerRepresentation(), intptr_zero);
1789 : TNode<JSArray> array = CAST(receiver);
1790 :
1791 : // JSArray length is always a positive Smi for fast arrays.
1792 : CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array)));
1793 186 : Node* array_length = SmiUntag(LoadFastJSArrayLength(array));
1794 :
1795 : {
1796 : // Initialize fromIndex.
1797 62 : Label is_smi(this), is_nonsmi(this), done(this);
1798 :
1799 : // If no fromIndex was passed, default to 0.
1800 186 : GotoIf(IntPtrLessThanOrEqual(argc, IntPtrConstant(kFromIndexArg)), &done);
1801 :
1802 124 : Node* start_from = args.AtIndex(kFromIndexArg);
1803 : // Handle Smis and undefined here and everything else in runtime.
1804 : // We must be very careful with side effects from the ToInteger conversion,
1805 : // as the side effects might render previously checked assumptions about
1806 : // the receiver being a fast JSArray and its length invalid.
1807 124 : Branch(TaggedIsSmi(start_from), &is_smi, &is_nonsmi);
1808 :
1809 62 : BIND(&is_nonsmi);
1810 : {
1811 124 : GotoIfNot(IsUndefined(start_from), &call_runtime);
1812 62 : Goto(&done);
1813 : }
1814 62 : BIND(&is_smi);
1815 : {
1816 124 : Node* intptr_start_from = SmiUntag(start_from);
1817 62 : index_var.Bind(intptr_start_from);
1818 :
1819 186 : GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
1820 : // The fromIndex is negative: add it to the array's length.
1821 186 : index_var.Bind(IntPtrAdd(array_length, index_var.value()));
1822 : // Clamp negative results at zero.
1823 186 : GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), intptr_zero), &done);
1824 62 : index_var.Bind(intptr_zero);
1825 62 : Goto(&done);
1826 : }
1827 124 : BIND(&done);
1828 : }
1829 :
1830 : // Fail early if startIndex >= array.length.
1831 124 : GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), array_length),
1832 124 : &return_not_found);
1833 :
1834 62 : Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
1835 :
1836 186 : Node* elements_kind = LoadMapElementsKind(LoadMap(array));
1837 124 : Node* elements = LoadElements(array);
1838 : STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
1839 : STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
1840 : STATIC_ASSERT(PACKED_ELEMENTS == 2);
1841 : STATIC_ASSERT(HOLEY_ELEMENTS == 3);
1842 124 : GotoIf(Uint32LessThanOrEqual(elements_kind, Int32Constant(HOLEY_ELEMENTS)),
1843 124 : &if_smiorobjects);
1844 124 : GotoIf(Word32Equal(elements_kind, Int32Constant(PACKED_DOUBLE_ELEMENTS)),
1845 124 : &if_packed_doubles);
1846 124 : GotoIf(Word32Equal(elements_kind, Int32Constant(HOLEY_DOUBLE_ELEMENTS)),
1847 124 : &if_holey_doubles);
1848 62 : Goto(&return_not_found);
1849 :
1850 62 : BIND(&if_smiorobjects);
1851 : {
1852 62 : VARIABLE(search_num, MachineRepresentation::kFloat64);
1853 62 : Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
1854 62 : string_loop(this), bigint_loop(this, &index_var),
1855 62 : undef_loop(this, &index_var), not_smi(this), not_heap_num(this);
1856 :
1857 124 : GotoIfNot(TaggedIsSmi(search_element), ¬_smi);
1858 124 : search_num.Bind(SmiToFloat64(CAST(search_element)));
1859 62 : Goto(&heap_num_loop);
1860 :
1861 62 : BIND(¬_smi);
1862 62 : if (variant == kIncludes) {
1863 62 : GotoIf(IsUndefined(search_element), &undef_loop);
1864 : }
1865 124 : Node* map = LoadMap(CAST(search_element));
1866 124 : GotoIfNot(IsHeapNumberMap(map), ¬_heap_num);
1867 124 : search_num.Bind(LoadHeapNumberValue(CAST(search_element)));
1868 62 : Goto(&heap_num_loop);
1869 :
1870 62 : BIND(¬_heap_num);
1871 124 : Node* search_type = LoadMapInstanceType(map);
1872 124 : GotoIf(IsStringInstanceType(search_type), &string_loop);
1873 124 : GotoIf(IsBigIntInstanceType(search_type), &bigint_loop);
1874 62 : Goto(&ident_loop);
1875 :
1876 62 : BIND(&ident_loop);
1877 : {
1878 124 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
1879 124 : &return_not_found);
1880 62 : Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1881 62 : GotoIf(WordEqual(element_k, search_element), &return_found);
1882 :
1883 62 : Increment(&index_var);
1884 62 : Goto(&ident_loop);
1885 : }
1886 :
1887 62 : if (variant == kIncludes) {
1888 31 : BIND(&undef_loop);
1889 :
1890 62 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
1891 62 : &return_not_found);
1892 31 : Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1893 62 : GotoIf(IsUndefined(element_k), &return_found);
1894 62 : GotoIf(IsTheHole(element_k), &return_found);
1895 :
1896 31 : Increment(&index_var);
1897 31 : Goto(&undef_loop);
1898 : }
1899 :
1900 62 : BIND(&heap_num_loop);
1901 : {
1902 62 : Label nan_loop(this, &index_var), not_nan_loop(this, &index_var);
1903 : Label* nan_handling =
1904 62 : variant == kIncludes ? &nan_loop : &return_not_found;
1905 62 : BranchIfFloat64IsNaN(search_num.value(), nan_handling, ¬_nan_loop);
1906 :
1907 62 : BIND(¬_nan_loop);
1908 : {
1909 62 : Label continue_loop(this), not_smi(this);
1910 124 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
1911 124 : &return_not_found);
1912 62 : Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1913 124 : GotoIfNot(TaggedIsSmi(element_k), ¬_smi);
1914 186 : Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
1915 124 : &return_found, &continue_loop);
1916 :
1917 62 : BIND(¬_smi);
1918 124 : GotoIfNot(IsHeapNumber(element_k), &continue_loop);
1919 186 : Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
1920 124 : &return_found, &continue_loop);
1921 :
1922 62 : BIND(&continue_loop);
1923 62 : Increment(&index_var);
1924 124 : Goto(¬_nan_loop);
1925 : }
1926 :
1927 : // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
1928 62 : if (variant == kIncludes) {
1929 31 : BIND(&nan_loop);
1930 : Label continue_loop(this);
1931 62 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
1932 62 : &return_not_found);
1933 31 : Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1934 62 : GotoIf(TaggedIsSmi(element_k), &continue_loop);
1935 62 : GotoIfNot(IsHeapNumber(element_k), &continue_loop);
1936 31 : BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_found,
1937 62 : &continue_loop);
1938 :
1939 31 : BIND(&continue_loop);
1940 31 : Increment(&index_var);
1941 31 : Goto(&nan_loop);
1942 62 : }
1943 : }
1944 :
1945 62 : BIND(&string_loop);
1946 : {
1947 : TNode<String> search_element_string = CAST(search_element);
1948 62 : Label continue_loop(this), next_iteration(this, &index_var),
1949 62 : slow_compare(this), runtime(this, Label::kDeferred);
1950 124 : Node* search_length = LoadStringLength(search_element_string);
1951 62 : Goto(&next_iteration);
1952 62 : BIND(&next_iteration);
1953 124 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
1954 124 : &return_not_found);
1955 62 : Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1956 124 : GotoIf(TaggedIsSmi(element_k), &continue_loop);
1957 62 : GotoIf(WordEqual(search_element_string, element_k), &return_found);
1958 124 : Node* element_k_type = LoadInstanceType(element_k);
1959 124 : GotoIfNot(IsStringInstanceType(element_k_type), &continue_loop);
1960 124 : Branch(WordEqual(search_length, LoadStringLength(element_k)),
1961 62 : &slow_compare, &continue_loop);
1962 :
1963 62 : BIND(&slow_compare);
1964 : StringBuiltinsAssembler string_asm(state());
1965 : string_asm.StringEqual_Core(context, search_element_string, search_type,
1966 : search_length, element_k, element_k_type,
1967 62 : &return_found, &continue_loop, &runtime);
1968 62 : BIND(&runtime);
1969 : TNode<Object> result = CallRuntime(Runtime::kStringEqual, context,
1970 : search_element_string, element_k);
1971 62 : Branch(WordEqual(BooleanConstant(true), result), &return_found,
1972 62 : &continue_loop);
1973 :
1974 62 : BIND(&continue_loop);
1975 62 : Increment(&index_var);
1976 124 : Goto(&next_iteration);
1977 : }
1978 :
1979 62 : BIND(&bigint_loop);
1980 : {
1981 124 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
1982 124 : &return_not_found);
1983 62 : Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1984 : TNode<Object> result = CallRuntime(Runtime::kBigIntEqual, context,
1985 : search_element, element_k);
1986 124 : GotoIf(WordEqual(result, TrueConstant()), &return_found);
1987 62 : Increment(&index_var);
1988 62 : Goto(&bigint_loop);
1989 62 : }
1990 : }
1991 :
1992 62 : BIND(&if_packed_doubles);
1993 : {
1994 62 : Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
1995 62 : hole_loop(this, &index_var), search_notnan(this);
1996 124 : VARIABLE(search_num, MachineRepresentation::kFloat64);
1997 :
1998 124 : GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
1999 124 : search_num.Bind(SmiToFloat64(CAST(search_element)));
2000 62 : Goto(¬_nan_loop);
2001 :
2002 62 : BIND(&search_notnan);
2003 124 : GotoIfNot(IsHeapNumber(search_element), &return_not_found);
2004 :
2005 124 : search_num.Bind(LoadHeapNumberValue(CAST(search_element)));
2006 :
2007 62 : Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
2008 62 : BranchIfFloat64IsNaN(search_num.value(), nan_handling, ¬_nan_loop);
2009 :
2010 62 : BIND(¬_nan_loop);
2011 : {
2012 : Label continue_loop(this);
2013 124 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
2014 124 : &return_not_found);
2015 : Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
2016 62 : MachineType::Float64());
2017 124 : Branch(Float64Equal(element_k, search_num.value()), &return_found,
2018 124 : &continue_loop);
2019 62 : BIND(&continue_loop);
2020 62 : Increment(&index_var);
2021 62 : Goto(¬_nan_loop);
2022 : }
2023 :
2024 : // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
2025 62 : if (variant == kIncludes) {
2026 31 : BIND(&nan_loop);
2027 : Label continue_loop(this);
2028 62 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
2029 62 : &return_not_found);
2030 : Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
2031 31 : MachineType::Float64());
2032 31 : BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
2033 31 : BIND(&continue_loop);
2034 31 : Increment(&index_var);
2035 31 : Goto(&nan_loop);
2036 62 : }
2037 : }
2038 :
2039 62 : BIND(&if_holey_doubles);
2040 : {
2041 62 : Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
2042 62 : hole_loop(this, &index_var), search_notnan(this);
2043 124 : VARIABLE(search_num, MachineRepresentation::kFloat64);
2044 :
2045 124 : GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
2046 124 : search_num.Bind(SmiToFloat64(CAST(search_element)));
2047 62 : Goto(¬_nan_loop);
2048 :
2049 62 : BIND(&search_notnan);
2050 62 : if (variant == kIncludes) {
2051 62 : GotoIf(IsUndefined(search_element), &hole_loop);
2052 : }
2053 124 : GotoIfNot(IsHeapNumber(search_element), &return_not_found);
2054 :
2055 124 : search_num.Bind(LoadHeapNumberValue(CAST(search_element)));
2056 :
2057 62 : Label* nan_handling = variant == kIncludes ? &nan_loop : &return_not_found;
2058 62 : BranchIfFloat64IsNaN(search_num.value(), nan_handling, ¬_nan_loop);
2059 :
2060 62 : BIND(¬_nan_loop);
2061 : {
2062 : Label continue_loop(this);
2063 124 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
2064 124 : &return_not_found);
2065 :
2066 : // No need for hole checking here; the following Float64Equal will
2067 : // return 'not equal' for holes anyway.
2068 : Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
2069 62 : MachineType::Float64());
2070 :
2071 124 : Branch(Float64Equal(element_k, search_num.value()), &return_found,
2072 124 : &continue_loop);
2073 62 : BIND(&continue_loop);
2074 62 : Increment(&index_var);
2075 62 : Goto(¬_nan_loop);
2076 : }
2077 :
2078 : // Array.p.includes uses SameValueZero comparisons, where NaN == NaN.
2079 62 : if (variant == kIncludes) {
2080 31 : BIND(&nan_loop);
2081 : Label continue_loop(this);
2082 62 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
2083 62 : &return_not_found);
2084 :
2085 : // Load double value or continue if it's the hole NaN.
2086 : Node* element_k = LoadFixedDoubleArrayElement(
2087 : elements, index_var.value(), MachineType::Float64(), 0,
2088 31 : INTPTR_PARAMETERS, &continue_loop);
2089 :
2090 31 : BranchIfFloat64IsNaN(element_k, &return_found, &continue_loop);
2091 31 : BIND(&continue_loop);
2092 31 : Increment(&index_var);
2093 31 : Goto(&nan_loop);
2094 : }
2095 :
2096 : // Array.p.includes treats the hole as undefined.
2097 62 : if (variant == kIncludes) {
2098 31 : BIND(&hole_loop);
2099 62 : GotoIfNot(UintPtrLessThan(index_var.value(), array_length),
2100 62 : &return_not_found);
2101 :
2102 : // Check if the element is a double hole, but don't load it.
2103 : LoadFixedDoubleArrayElement(elements, index_var.value(),
2104 : MachineType::None(), 0, INTPTR_PARAMETERS,
2105 31 : &return_found);
2106 :
2107 31 : Increment(&index_var);
2108 31 : Goto(&hole_loop);
2109 62 : }
2110 : }
2111 :
2112 62 : BIND(&return_found);
2113 62 : if (variant == kIncludes) {
2114 62 : args.PopAndReturn(TrueConstant());
2115 : } else {
2116 93 : args.PopAndReturn(SmiTag(index_var.value()));
2117 : }
2118 :
2119 62 : BIND(&return_not_found);
2120 62 : if (variant == kIncludes) {
2121 62 : args.PopAndReturn(FalseConstant());
2122 : } else {
2123 62 : args.PopAndReturn(NumberConstant(-1));
2124 : }
2125 :
2126 62 : BIND(&call_runtime);
2127 : {
2128 124 : Node* start_from = args.GetOptionalArgumentValue(kFromIndexArg);
2129 : Runtime::FunctionId function = variant == kIncludes
2130 : ? Runtime::kArrayIncludes_Slow
2131 62 : : Runtime::kArrayIndexOf;
2132 : args.PopAndReturn(
2133 62 : CallRuntime(function, context, array, search_element, start_from));
2134 62 : }
2135 62 : }
2136 :
2137 93 : TF_BUILTIN(ArrayIncludes, ArrayIncludesIndexofAssembler) {
2138 31 : Generate(kIncludes);
2139 0 : }
2140 :
2141 93 : TF_BUILTIN(ArrayIndexOf, ArrayIncludesIndexofAssembler) { Generate(kIndexOf); }
2142 :
2143 : class ArrayPrototypeIterationAssembler : public CodeStubAssembler {
2144 : public:
2145 : explicit ArrayPrototypeIterationAssembler(compiler::CodeAssemblerState* state)
2146 93 : : CodeStubAssembler(state) {}
2147 :
2148 : protected:
2149 93 : void Generate_ArrayPrototypeIterationMethod(Node* context, Node* receiver,
2150 : IterationKind iteration_kind) {
2151 93 : VARIABLE(var_array, MachineRepresentation::kTagged);
2152 186 : VARIABLE(var_map, MachineRepresentation::kTagged);
2153 186 : VARIABLE(var_type, MachineRepresentation::kWord32);
2154 :
2155 93 : Label if_isnotobject(this, Label::kDeferred);
2156 93 : Label create_array_iterator(this);
2157 :
2158 186 : GotoIf(TaggedIsSmi(receiver), &if_isnotobject);
2159 93 : var_array.Bind(receiver);
2160 186 : var_map.Bind(LoadMap(receiver));
2161 279 : var_type.Bind(LoadMapInstanceType(var_map.value()));
2162 : Branch(IsJSReceiverInstanceType(var_type.value()), &create_array_iterator,
2163 186 : &if_isnotobject);
2164 :
2165 93 : BIND(&if_isnotobject);
2166 : {
2167 93 : Node* result = CallBuiltin(Builtins::kToObject, context, receiver);
2168 93 : var_array.Bind(result);
2169 186 : var_map.Bind(LoadMap(result));
2170 279 : var_type.Bind(LoadMapInstanceType(var_map.value()));
2171 93 : Goto(&create_array_iterator);
2172 : }
2173 :
2174 93 : BIND(&create_array_iterator);
2175 : Return(CreateArrayIterator(var_array.value(), var_map.value(),
2176 279 : var_type.value(), context, iteration_kind));
2177 93 : }
2178 : };
2179 :
2180 124 : TF_BUILTIN(ArrayPrototypeValues, ArrayPrototypeIterationAssembler) {
2181 : Node* context = Parameter(Descriptor::kContext);
2182 : Node* receiver = Parameter(Descriptor::kReceiver);
2183 : Generate_ArrayPrototypeIterationMethod(context, receiver,
2184 31 : IterationKind::kValues);
2185 31 : }
2186 :
2187 124 : TF_BUILTIN(ArrayPrototypeEntries, ArrayPrototypeIterationAssembler) {
2188 : Node* context = Parameter(Descriptor::kContext);
2189 : Node* receiver = Parameter(Descriptor::kReceiver);
2190 : Generate_ArrayPrototypeIterationMethod(context, receiver,
2191 31 : IterationKind::kEntries);
2192 31 : }
2193 :
2194 124 : TF_BUILTIN(ArrayPrototypeKeys, ArrayPrototypeIterationAssembler) {
2195 : Node* context = Parameter(Descriptor::kContext);
2196 : Node* receiver = Parameter(Descriptor::kReceiver);
2197 : Generate_ArrayPrototypeIterationMethod(context, receiver,
2198 31 : IterationKind::kKeys);
2199 31 : }
2200 :
2201 124 : TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
2202 : Handle<String> operation = factory()->NewStringFromAsciiChecked(
2203 31 : "Array Iterator.prototype.next", TENURED);
2204 :
2205 : Node* context = Parameter(Descriptor::kContext);
2206 : Node* iterator = Parameter(Descriptor::kReceiver);
2207 :
2208 31 : VARIABLE(var_value, MachineRepresentation::kTagged);
2209 62 : VARIABLE(var_done, MachineRepresentation::kTagged);
2210 :
2211 : // Required, or else `throw_bad_receiver` fails a DCHECK due to these
2212 : // variables not being bound along all paths, despite not being used.
2213 62 : var_done.Bind(TrueConstant());
2214 62 : var_value.Bind(UndefinedConstant());
2215 :
2216 31 : Label throw_bad_receiver(this, Label::kDeferred);
2217 31 : Label set_done(this);
2218 31 : Label allocate_key_result(this);
2219 31 : Label allocate_entry_if_needed(this);
2220 31 : Label allocate_iterator_result(this);
2221 31 : Label generic_values(this);
2222 :
2223 : // If O does not have all of the internal slots of an Array Iterator Instance
2224 : // (22.1.5.3), throw a TypeError exception
2225 62 : GotoIf(TaggedIsSmi(iterator), &throw_bad_receiver);
2226 31 : TNode<Int32T> instance_type = LoadInstanceType(iterator);
2227 62 : GotoIf(IsArrayIteratorInstanceType(instance_type), &throw_bad_receiver);
2228 :
2229 : // Let a be O.[[IteratedObject]].
2230 : Node* array =
2231 : LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset);
2232 :
2233 : // Let index be O.[[ArrayIteratorNextIndex]].
2234 : Node* index = LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset);
2235 : Node* orig_map =
2236 : LoadObjectField(iterator, JSArrayIterator::kIteratedObjectMapOffset);
2237 62 : Node* array_map = LoadMap(array);
2238 :
2239 31 : Label if_isfastarray(this), if_isnotfastarray(this),
2240 31 : if_isdetached(this, Label::kDeferred);
2241 :
2242 62 : Branch(WordEqual(orig_map, array_map), &if_isfastarray, &if_isnotfastarray);
2243 :
2244 31 : BIND(&if_isfastarray);
2245 : {
2246 : CSA_ASSERT(
2247 : this, InstanceTypeEqual(LoadMapInstanceType(array_map), JS_ARRAY_TYPE));
2248 :
2249 62 : Node* length = LoadJSArrayLength(array);
2250 :
2251 : CSA_ASSERT(this, TaggedIsSmi(length));
2252 : CSA_ASSERT(this, TaggedIsSmi(index));
2253 :
2254 62 : GotoIfNot(SmiBelow(index, length), &set_done);
2255 :
2256 62 : Node* one = SmiConstant(1);
2257 : StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
2258 62 : SmiAdd(index, one));
2259 :
2260 62 : var_done.Bind(FalseConstant());
2261 62 : Node* elements = LoadElements(array);
2262 :
2263 : static int32_t kInstanceType[] = {
2264 : JS_FAST_ARRAY_KEY_ITERATOR_TYPE,
2265 : JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2266 : JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2267 : JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2268 : JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2269 : JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2270 : JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2271 : JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE,
2272 : JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE,
2273 : JS_FAST_ARRAY_VALUE_ITERATOR_TYPE,
2274 : JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE,
2275 : JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE,
2276 : JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE,
2277 : };
2278 :
2279 31 : Label packed_object_values(this), holey_object_values(this),
2280 31 : packed_double_values(this), holey_double_values(this);
2281 : Label* kInstanceTypeHandlers[] = {
2282 : &allocate_key_result, &packed_object_values, &holey_object_values,
2283 : &packed_object_values, &holey_object_values, &packed_double_values,
2284 : &holey_double_values, &packed_object_values, &holey_object_values,
2285 : &packed_object_values, &holey_object_values, &packed_double_values,
2286 31 : &holey_double_values};
2287 :
2288 : Switch(instance_type, &throw_bad_receiver, kInstanceType,
2289 31 : kInstanceTypeHandlers, arraysize(kInstanceType));
2290 :
2291 31 : BIND(&packed_object_values);
2292 : {
2293 31 : var_value.Bind(LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS));
2294 31 : Goto(&allocate_entry_if_needed);
2295 : }
2296 :
2297 31 : BIND(&packed_double_values);
2298 : {
2299 : Node* value = LoadFixedDoubleArrayElement(
2300 31 : elements, index, MachineType::Float64(), 0, SMI_PARAMETERS);
2301 62 : var_value.Bind(AllocateHeapNumberWithValue(value));
2302 31 : Goto(&allocate_entry_if_needed);
2303 : }
2304 :
2305 31 : BIND(&holey_object_values);
2306 : {
2307 : // Check the array_protector cell, and take the slow path if it's invalid.
2308 62 : GotoIf(IsArrayProtectorCellInvalid(), &generic_values);
2309 :
2310 62 : var_value.Bind(UndefinedConstant());
2311 31 : Node* value = LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS);
2312 62 : GotoIf(WordEqual(value, TheHoleConstant()), &allocate_entry_if_needed);
2313 31 : var_value.Bind(value);
2314 31 : Goto(&allocate_entry_if_needed);
2315 : }
2316 :
2317 31 : BIND(&holey_double_values);
2318 : {
2319 : // Check the array_protector cell, and take the slow path if it's invalid.
2320 62 : GotoIf(IsArrayProtectorCellInvalid(), &generic_values);
2321 :
2322 62 : var_value.Bind(UndefinedConstant());
2323 : Node* value = LoadFixedDoubleArrayElement(
2324 : elements, index, MachineType::Float64(), 0, SMI_PARAMETERS,
2325 31 : &allocate_entry_if_needed);
2326 62 : var_value.Bind(AllocateHeapNumberWithValue(value));
2327 31 : Goto(&allocate_entry_if_needed);
2328 31 : }
2329 : }
2330 :
2331 31 : BIND(&if_isnotfastarray);
2332 : {
2333 31 : Label if_istypedarray(this), if_isgeneric(this);
2334 :
2335 : // If a is undefined, return CreateIterResultObject(undefined, true)
2336 62 : GotoIf(WordEqual(array, UndefinedConstant()), &allocate_iterator_result);
2337 :
2338 62 : Node* array_type = LoadInstanceType(array);
2339 : Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_istypedarray,
2340 62 : &if_isgeneric);
2341 :
2342 31 : BIND(&if_isgeneric);
2343 : {
2344 : Label if_wasfastarray(this);
2345 :
2346 : Node* length = nullptr;
2347 : {
2348 31 : VARIABLE(var_length, MachineRepresentation::kTagged);
2349 31 : Label if_isarray(this), if_isnotarray(this), done(this);
2350 : Branch(InstanceTypeEqual(array_type, JS_ARRAY_TYPE), &if_isarray,
2351 62 : &if_isnotarray);
2352 :
2353 31 : BIND(&if_isarray);
2354 : {
2355 62 : var_length.Bind(LoadJSArrayLength(array));
2356 :
2357 : // Invalidate protector cell if needed
2358 62 : Branch(WordNotEqual(orig_map, UndefinedConstant()), &if_wasfastarray,
2359 31 : &done);
2360 :
2361 31 : BIND(&if_wasfastarray);
2362 : {
2363 : Label if_invalid(this, Label::kDeferred);
2364 : // A fast array iterator transitioned to a slow iterator during
2365 : // iteration. Invalidate fast_array_iteration_prtoector cell to
2366 : // prevent potential deopt loops.
2367 : StoreObjectFieldNoWriteBarrier(
2368 : iterator, JSArrayIterator::kIteratedObjectMapOffset,
2369 62 : UndefinedConstant());
2370 : GotoIf(Uint32LessThanOrEqual(
2371 : instance_type,
2372 62 : Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
2373 62 : &done);
2374 :
2375 62 : Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
2376 62 : Node* cell = LoadRoot(Heap::kFastArrayIterationProtectorRootIndex);
2377 31 : StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, invalid);
2378 31 : Goto(&done);
2379 : }
2380 : }
2381 :
2382 31 : BIND(&if_isnotarray);
2383 : {
2384 : Node* length =
2385 62 : GetProperty(context, array, factory()->length_string());
2386 31 : var_length.Bind(ToLength_Inline(context, length));
2387 31 : Goto(&done);
2388 : }
2389 :
2390 31 : BIND(&done);
2391 62 : length = var_length.value();
2392 : }
2393 :
2394 31 : GotoIfNumberGreaterThanOrEqual(index, length, &set_done);
2395 :
2396 : StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset,
2397 31 : NumberInc(index));
2398 62 : var_done.Bind(FalseConstant());
2399 :
2400 : Branch(
2401 : Uint32LessThanOrEqual(
2402 62 : instance_type, Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
2403 62 : &allocate_key_result, &generic_values);
2404 :
2405 31 : BIND(&generic_values);
2406 : {
2407 31 : var_value.Bind(GetProperty(context, array, index));
2408 31 : Goto(&allocate_entry_if_needed);
2409 31 : }
2410 : }
2411 :
2412 31 : BIND(&if_istypedarray);
2413 : {
2414 : Node* buffer = LoadObjectField(array, JSTypedArray::kBufferOffset);
2415 62 : GotoIf(IsDetachedBuffer(buffer), &if_isdetached);
2416 :
2417 : Node* length = LoadObjectField(array, JSTypedArray::kLengthOffset);
2418 :
2419 : CSA_ASSERT(this, TaggedIsSmi(length));
2420 : CSA_ASSERT(this, TaggedIsSmi(index));
2421 :
2422 62 : GotoIfNot(SmiBelow(index, length), &set_done);
2423 :
2424 62 : Node* one = SmiConstant(1);
2425 : StoreObjectFieldNoWriteBarrier(
2426 62 : iterator, JSArrayIterator::kNextIndexOffset, SmiAdd(index, one));
2427 62 : var_done.Bind(FalseConstant());
2428 :
2429 62 : Node* elements = LoadElements(array);
2430 : Node* base_ptr =
2431 : LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
2432 : Node* external_ptr =
2433 : LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
2434 31 : MachineType::Pointer());
2435 93 : Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
2436 :
2437 : static int32_t kInstanceType[] = {
2438 : JS_TYPED_ARRAY_KEY_ITERATOR_TYPE,
2439 : JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2440 : JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2441 : JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2442 : JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2443 : JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2444 : JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2445 : JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2446 : JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2447 : JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2448 : JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE,
2449 : JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE,
2450 : JS_INT8_ARRAY_VALUE_ITERATOR_TYPE,
2451 : JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE,
2452 : JS_INT16_ARRAY_VALUE_ITERATOR_TYPE,
2453 : JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE,
2454 : JS_INT32_ARRAY_VALUE_ITERATOR_TYPE,
2455 : JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE,
2456 : JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE,
2457 : };
2458 :
2459 31 : Label uint8_values(this), int8_values(this), uint16_values(this),
2460 31 : int16_values(this), uint32_values(this), int32_values(this),
2461 31 : float32_values(this), float64_values(this);
2462 : Label* kInstanceTypeHandlers[] = {
2463 : &allocate_key_result, &uint8_values, &uint8_values,
2464 : &int8_values, &uint16_values, &int16_values,
2465 : &uint32_values, &int32_values, &float32_values,
2466 : &float64_values, &uint8_values, &uint8_values,
2467 : &int8_values, &uint16_values, &int16_values,
2468 : &uint32_values, &int32_values, &float32_values,
2469 : &float64_values,
2470 31 : };
2471 :
2472 62 : var_done.Bind(FalseConstant());
2473 : Switch(instance_type, &throw_bad_receiver, kInstanceType,
2474 31 : kInstanceTypeHandlers, arraysize(kInstanceType));
2475 :
2476 31 : BIND(&uint8_values);
2477 : {
2478 : Node* value_uint8 = LoadFixedTypedArrayElement(
2479 31 : data_ptr, index, UINT8_ELEMENTS, SMI_PARAMETERS);
2480 62 : var_value.Bind(SmiFromWord32(value_uint8));
2481 31 : Goto(&allocate_entry_if_needed);
2482 : }
2483 31 : BIND(&int8_values);
2484 : {
2485 : Node* value_int8 = LoadFixedTypedArrayElement(
2486 31 : data_ptr, index, INT8_ELEMENTS, SMI_PARAMETERS);
2487 62 : var_value.Bind(SmiFromWord32(value_int8));
2488 31 : Goto(&allocate_entry_if_needed);
2489 : }
2490 31 : BIND(&uint16_values);
2491 : {
2492 : Node* value_uint16 = LoadFixedTypedArrayElement(
2493 31 : data_ptr, index, UINT16_ELEMENTS, SMI_PARAMETERS);
2494 62 : var_value.Bind(SmiFromWord32(value_uint16));
2495 31 : Goto(&allocate_entry_if_needed);
2496 : }
2497 31 : BIND(&int16_values);
2498 : {
2499 : Node* value_int16 = LoadFixedTypedArrayElement(
2500 31 : data_ptr, index, INT16_ELEMENTS, SMI_PARAMETERS);
2501 62 : var_value.Bind(SmiFromWord32(value_int16));
2502 31 : Goto(&allocate_entry_if_needed);
2503 : }
2504 31 : BIND(&uint32_values);
2505 : {
2506 : Node* value_uint32 = LoadFixedTypedArrayElement(
2507 31 : data_ptr, index, UINT32_ELEMENTS, SMI_PARAMETERS);
2508 62 : var_value.Bind(ChangeUint32ToTagged(value_uint32));
2509 31 : Goto(&allocate_entry_if_needed);
2510 : }
2511 31 : BIND(&int32_values);
2512 : {
2513 : Node* value_int32 = LoadFixedTypedArrayElement(
2514 31 : data_ptr, index, INT32_ELEMENTS, SMI_PARAMETERS);
2515 62 : var_value.Bind(ChangeInt32ToTagged(value_int32));
2516 31 : Goto(&allocate_entry_if_needed);
2517 : }
2518 31 : BIND(&float32_values);
2519 : {
2520 : Node* value_float32 = LoadFixedTypedArrayElement(
2521 31 : data_ptr, index, FLOAT32_ELEMENTS, SMI_PARAMETERS);
2522 : var_value.Bind(
2523 93 : AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(value_float32)));
2524 31 : Goto(&allocate_entry_if_needed);
2525 : }
2526 31 : BIND(&float64_values);
2527 : {
2528 : Node* value_float64 = LoadFixedTypedArrayElement(
2529 31 : data_ptr, index, FLOAT64_ELEMENTS, SMI_PARAMETERS);
2530 62 : var_value.Bind(AllocateHeapNumberWithValue(value_float64));
2531 31 : Goto(&allocate_entry_if_needed);
2532 31 : }
2533 31 : }
2534 : }
2535 :
2536 31 : BIND(&set_done);
2537 : {
2538 : StoreObjectFieldNoWriteBarrier(
2539 62 : iterator, JSArrayIterator::kIteratedObjectOffset, UndefinedConstant());
2540 31 : Goto(&allocate_iterator_result);
2541 : }
2542 :
2543 31 : BIND(&allocate_key_result);
2544 : {
2545 31 : var_value.Bind(index);
2546 62 : var_done.Bind(FalseConstant());
2547 31 : Goto(&allocate_iterator_result);
2548 : }
2549 :
2550 31 : BIND(&allocate_entry_if_needed);
2551 : {
2552 : GotoIf(Uint32LessThan(Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE),
2553 62 : instance_type),
2554 62 : &allocate_iterator_result);
2555 :
2556 62 : Node* elements = AllocateFixedArray(PACKED_ELEMENTS, IntPtrConstant(2));
2557 31 : StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER);
2558 31 : StoreFixedArrayElement(elements, 1, var_value.value(), SKIP_WRITE_BARRIER);
2559 :
2560 31 : Node* entry = Allocate(JSArray::kSize);
2561 31 : Node* map = LoadContextElement(LoadNativeContext(context),
2562 93 : Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
2563 :
2564 31 : StoreMapNoWriteBarrier(entry, map);
2565 : StoreObjectFieldRoot(entry, JSArray::kPropertiesOrHashOffset,
2566 31 : Heap::kEmptyFixedArrayRootIndex);
2567 31 : StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset, elements);
2568 : StoreObjectFieldNoWriteBarrier(entry, JSArray::kLengthOffset,
2569 62 : SmiConstant(2));
2570 :
2571 31 : var_value.Bind(entry);
2572 31 : Goto(&allocate_iterator_result);
2573 : }
2574 :
2575 31 : BIND(&allocate_iterator_result);
2576 : {
2577 31 : Node* result = Allocate(JSIteratorResult::kSize);
2578 31 : Node* map = LoadContextElement(LoadNativeContext(context),
2579 93 : Context::ITERATOR_RESULT_MAP_INDEX);
2580 31 : StoreMapNoWriteBarrier(result, map);
2581 : StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOrHashOffset,
2582 31 : Heap::kEmptyFixedArrayRootIndex);
2583 : StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
2584 31 : Heap::kEmptyFixedArrayRootIndex);
2585 : StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset,
2586 31 : var_value.value());
2587 : StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset,
2588 31 : var_done.value());
2589 31 : Return(result);
2590 : }
2591 :
2592 31 : BIND(&throw_bad_receiver);
2593 : {
2594 : // The {receiver} is not a valid JSArrayIterator.
2595 : CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
2596 : HeapConstant(operation), iterator);
2597 31 : Unreachable();
2598 : }
2599 :
2600 31 : BIND(&if_isdetached);
2601 : ThrowTypeError(context, MessageTemplate::kDetachedOperation,
2602 62 : HeapConstant(operation));
2603 31 : }
2604 :
2605 : } // namespace internal
2606 : } // namespace v8
|