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