Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Side by Side Diff: src/builtins/builtins-array.cc

Issue 2752143004: [refactor] Separate generated builtins and C++ builtins into separate files (Closed)
Patch Set: tentative gcmole fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-arguments-gen.cc ('k') | src/builtins/builtins-array-gen.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/builtins/builtins.h" 5 #include "src/builtins/builtins.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h" 9 #include "src/code-stub-assembler.h"
10 #include "src/contexts.h" 10 #include "src/contexts.h"
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 181
182 if (JSArray::HasReadOnlyLength(array)) { 182 if (JSArray::HasReadOnlyLength(array)) {
183 return CallJsIntrinsic(isolate, isolate->array_push(), args); 183 return CallJsIntrinsic(isolate, isolate->array_push(), args);
184 } 184 }
185 185
186 ElementsAccessor* accessor = array->GetElementsAccessor(); 186 ElementsAccessor* accessor = array->GetElementsAccessor();
187 int new_length = accessor->Push(array, &args, to_add); 187 int new_length = accessor->Push(array, &args, to_add);
188 return Smi::FromInt(new_length); 188 return Smi::FromInt(new_length);
189 } 189 }
190 190
191 TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
192 Variable arg_index(this, MachineType::PointerRepresentation());
193 Label default_label(this, &arg_index);
194 Label smi_transition(this);
195 Label object_push_pre(this);
196 Label object_push(this, &arg_index);
197 Label double_push(this, &arg_index);
198 Label double_transition(this);
199 Label runtime(this, Label::kDeferred);
200
201 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
202 Node* context = Parameter(BuiltinDescriptor::kContext);
203 Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
204
205 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
206 Node* receiver = args.GetReceiver();
207 Node* kind = nullptr;
208
209 Label fast(this);
210 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS,
211 &fast, &runtime);
212
213 Bind(&fast);
214 {
215 // Disallow pushing onto prototypes. It might be the JSArray prototype.
216 // Disallow pushing onto non-extensible objects.
217 Comment("Disallow pushing onto prototypes");
218 Node* map = LoadMap(receiver);
219 Node* bit_field2 = LoadMapBitField2(map);
220 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
221 (1 << Map::kIsExtensible);
222 Node* test = Word32And(bit_field2, Int32Constant(mask));
223 GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)),
224 &runtime);
225
226 // Disallow pushing onto arrays in dictionary named property mode. We need
227 // to figure out whether the length property is still writable.
228 Comment("Disallow pushing onto arrays in dictionary named property mode");
229 GotoIf(IsDictionaryMap(map), &runtime);
230
231 // Check whether the length property is writable. The length property is the
232 // only default named property on arrays. It's nonconfigurable, hence is
233 // guaranteed to stay the first property.
234 Node* descriptors = LoadMapDescriptors(map);
235 Node* details =
236 LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
237 GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask),
238 &runtime);
239
240 arg_index.Bind(IntPtrConstant(0));
241 kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
242
243 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
244 &object_push_pre);
245
246 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver,
247 args, arg_index, &smi_transition);
248 args.PopAndReturn(new_length);
249 }
250
251 // If the argument is not a smi, then use a heavyweight SetProperty to
252 // transition the array for only the single next element. If the argument is
253 // a smi, the failure is due to some other reason and we should fall back on
254 // the most generic implementation for the rest of the array.
255 Bind(&smi_transition);
256 {
257 Node* arg = args.AtIndex(arg_index.value());
258 GotoIf(TaggedIsSmi(arg), &default_label);
259 Node* length = LoadJSArrayLength(receiver);
260 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
261 // calling into the runtime to do the elements transition is overkill.
262 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
263 SmiConstant(STRICT));
264 Increment(arg_index);
265 // The runtime SetProperty call could have converted the array to dictionary
266 // mode, which must be detected to abort the fast-path.
267 Node* map = LoadMap(receiver);
268 Node* bit_field2 = LoadMapBitField2(map);
269 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
270 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
271 &default_label);
272
273 GotoIfNotNumber(arg, &object_push);
274 Goto(&double_push);
275 }
276
277 Bind(&object_push_pre);
278 {
279 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
280 &double_push, &object_push);
281 }
282
283 Bind(&object_push);
284 {
285 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver,
286 args, arg_index, &default_label);
287 args.PopAndReturn(new_length);
288 }
289
290 Bind(&double_push);
291 {
292 Node* new_length =
293 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args,
294 arg_index, &double_transition);
295 args.PopAndReturn(new_length);
296 }
297
298 // If the argument is not a double, then use a heavyweight SetProperty to
299 // transition the array for only the single next element. If the argument is
300 // a double, the failure is due to some other reason and we should fall back
301 // on the most generic implementation for the rest of the array.
302 Bind(&double_transition);
303 {
304 Node* arg = args.AtIndex(arg_index.value());
305 GotoIfNumber(arg, &default_label);
306 Node* length = LoadJSArrayLength(receiver);
307 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
308 // calling into the runtime to do the elements transition is overkill.
309 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
310 SmiConstant(STRICT));
311 Increment(arg_index);
312 // The runtime SetProperty call could have converted the array to dictionary
313 // mode, which must be detected to abort the fast-path.
314 Node* map = LoadMap(receiver);
315 Node* bit_field2 = LoadMapBitField2(map);
316 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
317 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
318 &default_label);
319 Goto(&object_push);
320 }
321
322 // Fallback that stores un-processed arguments using the full, heavyweight
323 // SetProperty machinery.
324 Bind(&default_label);
325 {
326 args.ForEach(
327 [this, receiver, context](Node* arg) {
328 Node* length = LoadJSArrayLength(receiver);
329 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
330 SmiConstant(STRICT));
331 },
332 arg_index.value());
333 args.PopAndReturn(LoadJSArrayLength(receiver));
334 }
335
336 Bind(&runtime);
337 {
338 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
339 MachineType::TaggedPointer());
340 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target,
341 argc);
342 }
343 }
344
345 BUILTIN(ArrayPop) { 191 BUILTIN(ArrayPop) {
346 HandleScope scope(isolate); 192 HandleScope scope(isolate);
347 Handle<Object> receiver = args.receiver(); 193 Handle<Object> receiver = args.receiver();
348 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { 194 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) {
349 return CallJsIntrinsic(isolate, isolate->array_pop(), args); 195 return CallJsIntrinsic(isolate, isolate->array_pop(), args);
350 } 196 }
351 197
352 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 198 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
353 199
354 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value()); 200 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value());
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 254
409 if (JSArray::HasReadOnlyLength(array)) { 255 if (JSArray::HasReadOnlyLength(array)) {
410 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); 256 return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
411 } 257 }
412 258
413 ElementsAccessor* accessor = array->GetElementsAccessor(); 259 ElementsAccessor* accessor = array->GetElementsAccessor();
414 int new_length = accessor->Unshift(array, &args, to_add); 260 int new_length = accessor->Unshift(array, &args, to_add);
415 return Smi::FromInt(new_length); 261 return Smi::FromInt(new_length);
416 } 262 }
417 263
418 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
419 public:
420 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state)
421 : CodeStubAssembler(state) {}
422
423 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator;
424 typedef std::function<void(Node* a, Node* pK, Node* value)>
425 CallResultProcessor;
426
427 void GenerateArrayIteratingBuiltinBody(
428 const char* name, Node* receiver, Node* callbackfn, Node* this_arg,
429 Node* context, const BuiltinResultGenerator& generator,
430 const CallResultProcessor& processor) {
431 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0));
432 Label non_array(this), slow(this, &k), array_changes(this, &k);
433
434 // TODO(danno): Seriously? Do we really need to throw the exact error
435 // message on null and undefined so that the webkit tests pass?
436 Label throw_null_undefined_exception(this, Label::kDeferred);
437 GotoIf(WordEqual(receiver, NullConstant()),
438 &throw_null_undefined_exception);
439 GotoIf(WordEqual(receiver, UndefinedConstant()),
440 &throw_null_undefined_exception);
441
442 // By the book: taken directly from the ECMAScript 2015 specification
443
444 // 1. Let O be ToObject(this value).
445 // 2. ReturnIfAbrupt(O)
446 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver);
447
448 // 3. Let len be ToLength(Get(O, "length")).
449 // 4. ReturnIfAbrupt(len).
450 Variable merged_length(this, MachineRepresentation::kTagged);
451 Label has_length(this, &merged_length), not_js_array(this);
452 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), &not_js_array);
453 merged_length.Bind(LoadJSArrayLength(o));
454 Goto(&has_length);
455 Bind(&not_js_array);
456 Node* len_property =
457 GetProperty(context, o, isolate()->factory()->length_string());
458 merged_length.Bind(
459 CallStub(CodeFactory::ToLength(isolate()), context, len_property));
460 Goto(&has_length);
461 Bind(&has_length);
462 Node* len = merged_length.value();
463
464 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception.
465 Label type_exception(this, Label::kDeferred);
466 Label done(this);
467 GotoIf(TaggedIsSmi(callbackfn), &type_exception);
468 Branch(IsCallableMap(LoadMap(callbackfn)), &done, &type_exception);
469
470 Bind(&throw_null_undefined_exception);
471 {
472 CallRuntime(
473 Runtime::kThrowTypeError, context,
474 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined),
475 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name)));
476 Unreachable();
477 }
478
479 Bind(&type_exception);
480 {
481 CallRuntime(Runtime::kThrowTypeError, context,
482 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn);
483 Unreachable();
484 }
485
486 Bind(&done);
487
488 Node* a = generator(o, len);
489
490 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined.
491 // [Already done by the arguments adapter]
492
493 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k,
494 &slow);
495
496 // 7. Let k be 0.
497 // Already done above in initialization of the Variable k
498
499 Bind(&slow);
500 {
501 // 8. Repeat, while k < len
502 Label loop(this, &k);
503 Label after_loop(this);
504 Goto(&loop);
505 Bind(&loop);
506 {
507 GotoUnlessNumberLessThan(k.value(), len, &after_loop);
508
509 Label done_element(this);
510 // a. Let Pk be ToString(k).
511 Node* p_k = ToString(context, k.value());
512
513 // b. Let kPresent be HasProperty(O, Pk).
514 // c. ReturnIfAbrupt(kPresent).
515 Node* k_present =
516 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o);
517
518 // d. If kPresent is true, then
519 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element);
520
521 // i. Let kValue be Get(O, Pk).
522 // ii. ReturnIfAbrupt(kValue).
523 Node* k_value = GetProperty(context, o, k.value());
524
525 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»).
526 // iv. ReturnIfAbrupt(funcResult).
527 Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn,
528 this_arg, k_value, k.value(), o);
529
530 processor(a, p_k, result);
531 Goto(&done_element);
532 Bind(&done_element);
533
534 // e. Increase k by 1.
535 k.Bind(NumberInc(k.value()));
536 Goto(&loop);
537 }
538 Bind(&after_loop);
539 Return(a);
540 }
541 }
542
543 private:
544 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind,
545 Node* this_arg, Node* o, Node* len,
546 Node* callbackfn,
547 const CallResultProcessor& processor,
548 Node* a, Label* array_changed,
549 ParameterMode mode) {
550 Comment("begin VisitAllFastElementsOneKind");
551 Variable original_map(this, MachineRepresentation::kTagged);
552 original_map.Bind(LoadMap(o));
553 VariableList list({&original_map}, zone());
554 Node* last_index = nullptr;
555 BuildFastLoop(
556 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode),
557 [=, &original_map, &last_index](Node* index) {
558 last_index = index;
559 Label one_element_done(this), hole_element(this);
560
561 // Check if o's map has changed during the callback. If so, we have to
562 // fall back to the slower spec implementation for the rest of the
563 // iteration.
564 Node* o_map = LoadMap(o);
565 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed);
566
567 // Check if o's length has changed during the callback and if the
568 // index is now out of range of the new length.
569 Node* tagged_index = ParameterToTagged(index, mode);
570 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)),
571 array_changed);
572
573 // Re-load the elements array. If may have been resized.
574 Node* elements = LoadElements(o);
575
576 // Fast case: load the element directly from the elements FixedArray
577 // and call the callback if the element is not the hole.
578 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS);
579 int base_size = kind == FAST_ELEMENTS
580 ? FixedArray::kHeaderSize
581 : (FixedArray::kHeaderSize - kHeapObjectTag);
582 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size);
583 Node* value = nullptr;
584 if (kind == FAST_ELEMENTS) {
585 value = LoadObjectField(elements, offset);
586 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element);
587 } else {
588 Node* double_value =
589 LoadDoubleWithHoleCheck(elements, offset, &hole_element);
590 value = AllocateHeapNumberWithValue(double_value);
591 }
592 Node* result = CallJS(CodeFactory::Call(isolate()), context,
593 callbackfn, this_arg, value, tagged_index, o);
594 processor(a, tagged_index, result);
595 Goto(&one_element_done);
596
597 Bind(&hole_element);
598 // Check if o's prototype change unexpectedly has elements after the
599 // callback in the case of a hole.
600 BranchIfPrototypesHaveNoElements(o_map, &one_element_done,
601 array_changed);
602
603 Bind(&one_element_done);
604 },
605 1, mode, IndexAdvanceMode::kPost);
606 Comment("end VisitAllFastElementsOneKind");
607 return last_index;
608 }
609
610 void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len,
611 Node* callbackfn, CallResultProcessor processor,
612 Node* a, Variable& k, Label* slow) {
613 Label switch_on_elements_kind(this), fast_elements(this),
614 maybe_double_elements(this), fast_double_elements(this);
615
616 Comment("begin HandleFastElements");
617 // Non-smi lengths must use the slow path.
618 GotoIf(TaggedIsNotSmi(len), slow);
619
620 BranchIfFastJSArray(o, context,
621 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
622 &switch_on_elements_kind, slow);
623
624 Bind(&switch_on_elements_kind);
625 // Select by ElementsKind
626 Node* o_map = LoadMap(o);
627 Node* bit_field2 = LoadMapBitField2(o_map);
628 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
629 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
630 &maybe_double_elements, &fast_elements);
631
632 ParameterMode mode = OptimalParameterMode();
633 Bind(&fast_elements);
634 {
635 Label array_changed(this, Label::kDeferred);
636 Node* last_index = VisitAllFastElementsOneKind(
637 context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a,
638 &array_changed, mode);
639
640 // No exception, return success
641 Return(a);
642
643 Bind(&array_changed);
644 k.Bind(ParameterToTagged(last_index, mode));
645 Goto(slow);
646 }
647
648 Bind(&maybe_double_elements);
649 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)),
650 slow, &fast_double_elements);
651
652 Bind(&fast_double_elements);
653 {
654 Label array_changed(this, Label::kDeferred);
655 Node* last_index = VisitAllFastElementsOneKind(
656 context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn,
657 processor, a, &array_changed, mode);
658
659 // No exception, return success
660 Return(a);
661
662 Bind(&array_changed);
663 k.Bind(ParameterToTagged(last_index, mode));
664 Goto(slow);
665 }
666 }
667 };
668
669 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) {
670 Node* receiver = Parameter(ForEachDescriptor::kReceiver);
671 Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
672 Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
673 Node* context = Parameter(ForEachDescriptor::kContext);
674
675 GenerateArrayIteratingBuiltinBody(
676 "Array.prototype.forEach", receiver, callbackfn, this_arg, context,
677 [=](Node*, Node*) { return UndefinedConstant(); },
678 [](Node* a, Node* p_k, Node* value) {});
679 }
680
681 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) {
682 Node* receiver = Parameter(ForEachDescriptor::kReceiver);
683 Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
684 Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
685 Node* context = Parameter(ForEachDescriptor::kContext);
686
687 GenerateArrayIteratingBuiltinBody(
688 "Array.prototype.every", receiver, callbackfn, this_arg, context,
689 [=](Node*, Node*) { return TrueConstant(); },
690 [=](Node* a, Node* p_k, Node* value) {
691 Label true_continue(this), return_false(this);
692 BranchIfToBooleanIsTrue(value, &true_continue, &return_false);
693 Bind(&return_false);
694 Return(FalseConstant());
695 Bind(&true_continue);
696 });
697 }
698
699 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) {
700 Node* receiver = Parameter(ForEachDescriptor::kReceiver);
701 Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
702 Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
703 Node* context = Parameter(ForEachDescriptor::kContext);
704
705 GenerateArrayIteratingBuiltinBody(
706 "Array.prototype.some", receiver, callbackfn, this_arg, context,
707 [=](Node*, Node*) { return FalseConstant(); },
708 [=](Node* a, Node* p_k, Node* value) {
709 Label false_continue(this), return_true(this);
710 BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
711 Bind(&return_true);
712 Return(TrueConstant());
713 Bind(&false_continue);
714 });
715 }
716
717 BUILTIN(ArraySlice) { 264 BUILTIN(ArraySlice) {
718 HandleScope scope(isolate); 265 HandleScope scope(isolate);
719 Handle<Object> receiver = args.receiver(); 266 Handle<Object> receiver = args.receiver();
720 int len = -1; 267 int len = -1;
721 int relative_start = 0; 268 int relative_start = 0;
722 int relative_end = 0; 269 int relative_end = 0;
723 270
724 if (receiver->IsJSArray()) { 271 if (receiver->IsJSArray()) {
725 DisallowHeapAllocation no_gc; 272 DisallowHeapAllocation no_gc;
726 JSArray* array = JSArray::cast(*receiver); 273 JSArray* array = JSArray::cast(*receiver);
(...skipping 958 matching lines...) Expand 10 before | Expand all | Expand 10 after
1685 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); 1232 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver));
1686 if (*species == *isolate->array_function()) { 1233 if (*species == *isolate->array_function()) {
1687 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { 1234 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
1688 return *result_array; 1235 return *result_array;
1689 } 1236 }
1690 if (isolate->has_pending_exception()) return isolate->heap()->exception(); 1237 if (isolate->has_pending_exception()) return isolate->heap()->exception();
1691 } 1238 }
1692 return Slow_ArrayConcat(&args, species, isolate); 1239 return Slow_ArrayConcat(&args, species, isolate);
1693 } 1240 }
1694 1241
1695 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
1696 Node* object = Parameter(1);
1697 Node* context = Parameter(4);
1698
1699 Label call_runtime(this), return_true(this), return_false(this);
1700
1701 GotoIf(TaggedIsSmi(object), &return_false);
1702 Node* instance_type = LoadInstanceType(object);
1703
1704 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)),
1705 &return_true);
1706
1707 // TODO(verwaest): Handle proxies in-place.
1708 Branch(Word32Equal(instance_type, Int32Constant(JS_PROXY_TYPE)),
1709 &call_runtime, &return_false);
1710
1711 Bind(&return_true);
1712 Return(BooleanConstant(true));
1713
1714 Bind(&return_false);
1715 Return(BooleanConstant(false));
1716
1717 Bind(&call_runtime);
1718 Return(CallRuntime(Runtime::kArrayIsArray, context, object));
1719 }
1720
1721 TF_BUILTIN(ArrayIncludes, CodeStubAssembler) {
1722 Node* const array = Parameter(0);
1723 Node* const search_element = Parameter(1);
1724 Node* const start_from = Parameter(2);
1725 Node* const context = Parameter(3 + 2);
1726
1727 Variable index_var(this, MachineType::PointerRepresentation());
1728
1729 Label init_k(this), return_true(this), return_false(this), call_runtime(this);
1730 Label init_len(this), select_loop(this);
1731
1732 index_var.Bind(IntPtrConstant(0));
1733
1734 // Take slow path if not a JSArray, if retrieving elements requires
1735 // traversing prototype, or if access checks are required.
1736 BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ,
1737 &init_len, &call_runtime);
1738
1739 Bind(&init_len);
1740 // JSArray length is always an Smi for fast arrays.
1741 CSA_ASSERT(this, TaggedIsSmi(LoadObjectField(array, JSArray::kLengthOffset)));
1742 Node* const len = LoadAndUntagObjectField(array, JSArray::kLengthOffset);
1743
1744 GotoIf(IsUndefined(start_from), &select_loop);
1745
1746 // Bailout to slow path if startIndex is not an Smi.
1747 Branch(TaggedIsSmi(start_from), &init_k, &call_runtime);
1748
1749 Bind(&init_k);
1750 CSA_ASSERT(this, TaggedIsSmi(start_from));
1751 Node* const untagged_start_from = SmiToWord(start_from);
1752 index_var.Bind(Select(
1753 IntPtrGreaterThanOrEqual(untagged_start_from, IntPtrConstant(0)),
1754 [=]() { return untagged_start_from; },
1755 [=]() {
1756 Node* const index = IntPtrAdd(len, untagged_start_from);
1757 return SelectConstant(IntPtrLessThan(index, IntPtrConstant(0)),
1758 IntPtrConstant(0), index,
1759 MachineType::PointerRepresentation());
1760 },
1761 MachineType::PointerRepresentation()));
1762
1763 Goto(&select_loop);
1764 Bind(&select_loop);
1765 static int32_t kElementsKind[] = {
1766 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS,
1767 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS,
1768 };
1769
1770 Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
1771 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects,
1772 &if_smiorobjects, &if_smiorobjects,
1773 &if_packed_doubles, &if_holey_doubles};
1774
1775 Node* map = LoadMap(array);
1776 Node* elements_kind = LoadMapElementsKind(map);
1777 Node* elements = LoadElements(array);
1778 Switch(elements_kind, &return_false, kElementsKind, element_kind_handlers,
1779 arraysize(kElementsKind));
1780
1781 Bind(&if_smiorobjects);
1782 {
1783 Variable search_num(this, MachineRepresentation::kFloat64);
1784 Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
1785 string_loop(this, &index_var), undef_loop(this, &index_var),
1786 not_smi(this), not_heap_num(this);
1787
1788 GotoIfNot(TaggedIsSmi(search_element), &not_smi);
1789 search_num.Bind(SmiToFloat64(search_element));
1790 Goto(&heap_num_loop);
1791
1792 Bind(&not_smi);
1793 GotoIf(WordEqual(search_element, UndefinedConstant()), &undef_loop);
1794 Node* map = LoadMap(search_element);
1795 GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
1796 search_num.Bind(LoadHeapNumberValue(search_element));
1797 Goto(&heap_num_loop);
1798
1799 Bind(&not_heap_num);
1800 Node* search_type = LoadMapInstanceType(map);
1801 GotoIf(IsStringInstanceType(search_type), &string_loop);
1802 Goto(&ident_loop);
1803
1804 Bind(&ident_loop);
1805 {
1806 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1807 Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1808 GotoIf(WordEqual(element_k, search_element), &return_true);
1809
1810 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1811 Goto(&ident_loop);
1812 }
1813
1814 Bind(&undef_loop);
1815 {
1816 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1817 Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1818 GotoIf(WordEqual(element_k, UndefinedConstant()), &return_true);
1819 GotoIf(WordEqual(element_k, TheHoleConstant()), &return_true);
1820
1821 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1822 Goto(&undef_loop);
1823 }
1824
1825 Bind(&heap_num_loop);
1826 {
1827 Label nan_loop(this, &index_var), not_nan_loop(this, &index_var);
1828 BranchIfFloat64IsNaN(search_num.value(), &nan_loop, &not_nan_loop);
1829
1830 Bind(&not_nan_loop);
1831 {
1832 Label continue_loop(this), not_smi(this);
1833 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1834 Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1835 GotoIfNot(TaggedIsSmi(element_k), &not_smi);
1836 Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
1837 &return_true, &continue_loop);
1838
1839 Bind(&not_smi);
1840 GotoIfNot(IsHeapNumber(element_k), &continue_loop);
1841 Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
1842 &return_true, &continue_loop);
1843
1844 Bind(&continue_loop);
1845 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1846 Goto(&not_nan_loop);
1847 }
1848
1849 Bind(&nan_loop);
1850 {
1851 Label continue_loop(this);
1852 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1853 Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1854 GotoIf(TaggedIsSmi(element_k), &continue_loop);
1855 GotoIfNot(IsHeapNumber(element_k), &continue_loop);
1856 BranchIfFloat64IsNaN(LoadHeapNumberValue(element_k), &return_true,
1857 &continue_loop);
1858
1859 Bind(&continue_loop);
1860 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1861 Goto(&nan_loop);
1862 }
1863 }
1864
1865 Bind(&string_loop);
1866 {
1867 Label continue_loop(this);
1868 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1869 Node* element_k = LoadFixedArrayElement(elements, index_var.value());
1870 GotoIf(TaggedIsSmi(element_k), &continue_loop);
1871 GotoIfNot(IsStringInstanceType(LoadInstanceType(element_k)),
1872 &continue_loop);
1873
1874 // TODO(bmeurer): Consider inlining the StringEqual logic here.
1875 Node* result = CallStub(CodeFactory::StringEqual(isolate()), context,
1876 search_element, element_k);
1877 Branch(WordEqual(BooleanConstant(true), result), &return_true,
1878 &continue_loop);
1879
1880 Bind(&continue_loop);
1881 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1882 Goto(&string_loop);
1883 }
1884 }
1885
1886 Bind(&if_packed_doubles);
1887 {
1888 Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
1889 hole_loop(this, &index_var), search_notnan(this);
1890 Variable search_num(this, MachineRepresentation::kFloat64);
1891
1892 GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
1893 search_num.Bind(SmiToFloat64(search_element));
1894 Goto(&not_nan_loop);
1895
1896 Bind(&search_notnan);
1897 GotoIfNot(IsHeapNumber(search_element), &return_false);
1898
1899 search_num.Bind(LoadHeapNumberValue(search_element));
1900
1901 BranchIfFloat64IsNaN(search_num.value(), &nan_loop, &not_nan_loop);
1902
1903 // Search for HeapNumber
1904 Bind(&not_nan_loop);
1905 {
1906 Label continue_loop(this);
1907 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1908 Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
1909 MachineType::Float64());
1910 Branch(Float64Equal(element_k, search_num.value()), &return_true,
1911 &continue_loop);
1912 Bind(&continue_loop);
1913 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1914 Goto(&not_nan_loop);
1915 }
1916
1917 // Search for NaN
1918 Bind(&nan_loop);
1919 {
1920 Label continue_loop(this);
1921 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1922 Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
1923 MachineType::Float64());
1924 BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop);
1925 Bind(&continue_loop);
1926 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1927 Goto(&nan_loop);
1928 }
1929 }
1930
1931 Bind(&if_holey_doubles);
1932 {
1933 Label nan_loop(this, &index_var), not_nan_loop(this, &index_var),
1934 hole_loop(this, &index_var), search_notnan(this);
1935 Variable search_num(this, MachineRepresentation::kFloat64);
1936
1937 GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
1938 search_num.Bind(SmiToFloat64(search_element));
1939 Goto(&not_nan_loop);
1940
1941 Bind(&search_notnan);
1942 GotoIf(WordEqual(search_element, UndefinedConstant()), &hole_loop);
1943 GotoIfNot(IsHeapNumber(search_element), &return_false);
1944
1945 search_num.Bind(LoadHeapNumberValue(search_element));
1946
1947 BranchIfFloat64IsNaN(search_num.value(), &nan_loop, &not_nan_loop);
1948
1949 // Search for HeapNumber
1950 Bind(&not_nan_loop);
1951 {
1952 Label continue_loop(this);
1953 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1954
1955 // Load double value or continue if it contains a double hole.
1956 Node* element_k = LoadFixedDoubleArrayElement(
1957 elements, index_var.value(), MachineType::Float64(), 0,
1958 INTPTR_PARAMETERS, &continue_loop);
1959
1960 Branch(Float64Equal(element_k, search_num.value()), &return_true,
1961 &continue_loop);
1962 Bind(&continue_loop);
1963 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1964 Goto(&not_nan_loop);
1965 }
1966
1967 // Search for NaN
1968 Bind(&nan_loop);
1969 {
1970 Label continue_loop(this);
1971 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1972
1973 // Load double value or continue if it contains a double hole.
1974 Node* element_k = LoadFixedDoubleArrayElement(
1975 elements, index_var.value(), MachineType::Float64(), 0,
1976 INTPTR_PARAMETERS, &continue_loop);
1977
1978 BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop);
1979 Bind(&continue_loop);
1980 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1981 Goto(&nan_loop);
1982 }
1983
1984 // Search for the Hole
1985 Bind(&hole_loop);
1986 {
1987 GotoIfNot(UintPtrLessThan(index_var.value(), len), &return_false);
1988
1989 // Check if the element is a double hole, but don't load it.
1990 LoadFixedDoubleArrayElement(elements, index_var.value(),
1991 MachineType::None(), 0, INTPTR_PARAMETERS,
1992 &return_true);
1993
1994 index_var.Bind(IntPtrAdd(index_var.value(), IntPtrConstant(1)));
1995 Goto(&hole_loop);
1996 }
1997 }
1998
1999 Bind(&return_true);
2000 Return(TrueConstant());
2001
2002 Bind(&return_false);
2003 Return(FalseConstant());
2004
2005 Bind(&call_runtime);
2006 Return(CallRuntime(Runtime::kArrayIncludes_Slow, context, array,
2007 search_element, start_from));
2008 }
2009
2010 TF_BUILTIN(ArrayIndexOf, CodeStubAssembler) {
2011 Node* array = Parameter(0);
2012 Node* search_element = Parameter(1);
2013 Node* start_from = Parameter(2);
2014 Node* context = Parameter(3 + 2);
2015
2016 Node* intptr_zero = IntPtrConstant(0);
2017 Node* intptr_one = IntPtrConstant(1);
2018
2019 Variable len_var(this, MachineType::PointerRepresentation()),
2020 index_var(this, MachineType::PointerRepresentation()),
2021 start_from_var(this, MachineType::PointerRepresentation());
2022
2023 Label init_k(this), return_found(this), return_not_found(this),
2024 call_runtime(this);
2025
2026 Label init_len(this);
2027
2028 index_var.Bind(intptr_zero);
2029 len_var.Bind(intptr_zero);
2030
2031 // Take slow path if not a JSArray, if retrieving elements requires
2032 // traversing prototype, or if access checks are required.
2033 BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ,
2034 &init_len, &call_runtime);
2035
2036 Bind(&init_len);
2037 {
2038 // JSArray length is always an Smi for fast arrays.
2039 CSA_ASSERT(this,
2040 TaggedIsSmi(LoadObjectField(array, JSArray::kLengthOffset)));
2041 Node* len = LoadAndUntagObjectField(array, JSArray::kLengthOffset);
2042
2043 len_var.Bind(len);
2044 Branch(WordEqual(len_var.value(), intptr_zero), &return_not_found, &init_k);
2045 }
2046
2047 Bind(&init_k);
2048 {
2049 // For now only deal with undefined and Smis here; we must be really careful
2050 // with side-effects from the ToInteger conversion as the side-effects might
2051 // render our assumptions about the receiver being a fast JSArray and the
2052 // length invalid.
2053 Label done(this), init_k_smi(this), init_k_other(this), init_k_zero(this),
2054 init_k_n(this);
2055 Branch(TaggedIsSmi(start_from), &init_k_smi, &init_k_other);
2056
2057 Bind(&init_k_smi);
2058 {
2059 // The fromIndex is a Smi.
2060 start_from_var.Bind(SmiUntag(start_from));
2061 Goto(&init_k_n);
2062 }
2063
2064 Bind(&init_k_other);
2065 {
2066 // The fromIndex must be undefined then, otherwise bailout and let the
2067 // runtime deal with the full ToInteger conversion.
2068 GotoIfNot(IsUndefined(start_from), &call_runtime);
2069 start_from_var.Bind(intptr_zero);
2070 Goto(&init_k_n);
2071 }
2072
2073 Bind(&init_k_n);
2074 {
2075 Label if_positive(this), if_negative(this), done(this);
2076 Branch(IntPtrLessThan(start_from_var.value(), intptr_zero), &if_negative,
2077 &if_positive);
2078
2079 Bind(&if_positive);
2080 {
2081 index_var.Bind(start_from_var.value());
2082 Goto(&done);
2083 }
2084
2085 Bind(&if_negative);
2086 {
2087 index_var.Bind(IntPtrAdd(len_var.value(), start_from_var.value()));
2088 Branch(IntPtrLessThan(index_var.value(), intptr_zero), &init_k_zero,
2089 &done);
2090 }
2091
2092 Bind(&init_k_zero);
2093 {
2094 index_var.Bind(intptr_zero);
2095 Goto(&done);
2096 }
2097
2098 Bind(&done);
2099 }
2100 }
2101
2102 static int32_t kElementsKind[] = {
2103 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS,
2104 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS,
2105 };
2106
2107 Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
2108 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects,
2109 &if_smiorobjects, &if_smiorobjects,
2110 &if_packed_doubles, &if_holey_doubles};
2111
2112 Node* map = LoadMap(array);
2113 Node* elements_kind = LoadMapElementsKind(map);
2114 Node* elements = LoadElements(array);
2115 Switch(elements_kind, &return_not_found, kElementsKind, element_kind_handlers,
2116 arraysize(kElementsKind));
2117
2118 Bind(&if_smiorobjects);
2119 {
2120 Variable search_num(this, MachineRepresentation::kFloat64);
2121 Label ident_loop(this, &index_var), heap_num_loop(this, &search_num),
2122 string_loop(this, &index_var), not_smi(this), not_heap_num(this);
2123
2124 GotoIfNot(TaggedIsSmi(search_element), &not_smi);
2125 search_num.Bind(SmiToFloat64(search_element));
2126 Goto(&heap_num_loop);
2127
2128 Bind(&not_smi);
2129 Node* map = LoadMap(search_element);
2130 GotoIfNot(IsHeapNumberMap(map), &not_heap_num);
2131 search_num.Bind(LoadHeapNumberValue(search_element));
2132 Goto(&heap_num_loop);
2133
2134 Bind(&not_heap_num);
2135 Node* search_type = LoadMapInstanceType(map);
2136 GotoIf(IsStringInstanceType(search_type), &string_loop);
2137 Goto(&ident_loop);
2138
2139 Bind(&ident_loop);
2140 {
2141 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
2142 &return_not_found);
2143 Node* element_k = LoadFixedArrayElement(elements, index_var.value());
2144 GotoIf(WordEqual(element_k, search_element), &return_found);
2145
2146 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
2147 Goto(&ident_loop);
2148 }
2149
2150 Bind(&heap_num_loop);
2151 {
2152 Label not_nan_loop(this, &index_var);
2153 BranchIfFloat64IsNaN(search_num.value(), &return_not_found,
2154 &not_nan_loop);
2155
2156 Bind(&not_nan_loop);
2157 {
2158 Label continue_loop(this), not_smi(this);
2159 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
2160 &return_not_found);
2161 Node* element_k = LoadFixedArrayElement(elements, index_var.value());
2162 GotoIfNot(TaggedIsSmi(element_k), &not_smi);
2163 Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)),
2164 &return_found, &continue_loop);
2165
2166 Bind(&not_smi);
2167 GotoIfNot(IsHeapNumber(element_k), &continue_loop);
2168 Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)),
2169 &return_found, &continue_loop);
2170
2171 Bind(&continue_loop);
2172 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
2173 Goto(&not_nan_loop);
2174 }
2175 }
2176
2177 Bind(&string_loop);
2178 {
2179 Label continue_loop(this);
2180 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
2181 &return_not_found);
2182 Node* element_k = LoadFixedArrayElement(elements, index_var.value());
2183 GotoIf(TaggedIsSmi(element_k), &continue_loop);
2184 GotoIfNot(IsString(element_k), &continue_loop);
2185
2186 // TODO(bmeurer): Consider inlining the StringEqual logic here.
2187 Callable callable = CodeFactory::StringEqual(isolate());
2188 Node* result = CallStub(callable, context, search_element, element_k);
2189 Branch(WordEqual(BooleanConstant(true), result), &return_found,
2190 &continue_loop);
2191
2192 Bind(&continue_loop);
2193 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
2194 Goto(&string_loop);
2195 }
2196 }
2197
2198 Bind(&if_packed_doubles);
2199 {
2200 Label not_nan_loop(this, &index_var), search_notnan(this);
2201 Variable search_num(this, MachineRepresentation::kFloat64);
2202
2203 GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
2204 search_num.Bind(SmiToFloat64(search_element));
2205 Goto(&not_nan_loop);
2206
2207 Bind(&search_notnan);
2208 GotoIfNot(IsHeapNumber(search_element), &return_not_found);
2209
2210 search_num.Bind(LoadHeapNumberValue(search_element));
2211
2212 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, &not_nan_loop);
2213
2214 // Search for HeapNumber
2215 Bind(&not_nan_loop);
2216 {
2217 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
2218 &return_not_found);
2219 Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(),
2220 MachineType::Float64());
2221 GotoIf(Float64Equal(element_k, search_num.value()), &return_found);
2222
2223 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
2224 Goto(&not_nan_loop);
2225 }
2226 }
2227
2228 Bind(&if_holey_doubles);
2229 {
2230 Label not_nan_loop(this, &index_var), search_notnan(this);
2231 Variable search_num(this, MachineRepresentation::kFloat64);
2232
2233 GotoIfNot(TaggedIsSmi(search_element), &search_notnan);
2234 search_num.Bind(SmiToFloat64(search_element));
2235 Goto(&not_nan_loop);
2236
2237 Bind(&search_notnan);
2238 GotoIfNot(IsHeapNumber(search_element), &return_not_found);
2239
2240 search_num.Bind(LoadHeapNumberValue(search_element));
2241
2242 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, &not_nan_loop);
2243
2244 // Search for HeapNumber
2245 Bind(&not_nan_loop);
2246 {
2247 Label continue_loop(this);
2248 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()),
2249 &return_not_found);
2250
2251 // Load double value or continue if it contains a double hole.
2252 Node* element_k = LoadFixedDoubleArrayElement(
2253 elements, index_var.value(), MachineType::Float64(), 0,
2254 INTPTR_PARAMETERS, &continue_loop);
2255
2256 Branch(Float64Equal(element_k, search_num.value()), &return_found,
2257 &continue_loop);
2258 Bind(&continue_loop);
2259 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one));
2260 Goto(&not_nan_loop);
2261 }
2262 }
2263
2264 Bind(&return_found);
2265 Return(SmiTag(index_var.value()));
2266
2267 Bind(&return_not_found);
2268 Return(NumberConstant(-1));
2269
2270 Bind(&call_runtime);
2271 Return(CallRuntime(Runtime::kArrayIndexOf, context, array, search_element,
2272 start_from));
2273 }
2274
2275 class ArrayPrototypeIterationAssembler : public CodeStubAssembler {
2276 public:
2277 explicit ArrayPrototypeIterationAssembler(compiler::CodeAssemblerState* state)
2278 : CodeStubAssembler(state) {}
2279
2280 protected:
2281 void Generate_ArrayPrototypeIterationMethod(IterationKind iteration_kind) {
2282 Node* receiver = Parameter(0);
2283 Node* context = Parameter(3);
2284
2285 Variable var_array(this, MachineRepresentation::kTagged);
2286 Variable var_map(this, MachineRepresentation::kTagged);
2287 Variable var_type(this, MachineRepresentation::kWord32);
2288
2289 Label if_isnotobject(this, Label::kDeferred);
2290 Label create_array_iterator(this);
2291
2292 GotoIf(TaggedIsSmi(receiver), &if_isnotobject);
2293 var_array.Bind(receiver);
2294 var_map.Bind(LoadMap(receiver));
2295 var_type.Bind(LoadMapInstanceType(var_map.value()));
2296 Branch(IsJSReceiverInstanceType(var_type.value()), &create_array_iterator,
2297 &if_isnotobject);
2298
2299 Bind(&if_isnotobject);
2300 {
2301 Callable callable = CodeFactory::ToObject(isolate());
2302 Node* result = CallStub(callable, context, receiver);
2303 var_array.Bind(result);
2304 var_map.Bind(LoadMap(result));
2305 var_type.Bind(LoadMapInstanceType(var_map.value()));
2306 Goto(&create_array_iterator);
2307 }
2308
2309 Bind(&create_array_iterator);
2310 Return(CreateArrayIterator(var_array.value(), var_map.value(),
2311 var_type.value(), context, iteration_kind));
2312 }
2313 };
2314
2315 TF_BUILTIN(ArrayPrototypeValues, ArrayPrototypeIterationAssembler) {
2316 Generate_ArrayPrototypeIterationMethod(IterationKind::kValues);
2317 }
2318
2319 TF_BUILTIN(ArrayPrototypeEntries, ArrayPrototypeIterationAssembler) {
2320 Generate_ArrayPrototypeIterationMethod(IterationKind::kEntries);
2321 }
2322
2323 TF_BUILTIN(ArrayPrototypeKeys, ArrayPrototypeIterationAssembler) {
2324 Generate_ArrayPrototypeIterationMethod(IterationKind::kKeys);
2325 }
2326
2327 TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
2328 Handle<String> operation = factory()->NewStringFromAsciiChecked(
2329 "Array Iterator.prototype.next", TENURED);
2330
2331 Node* iterator = Parameter(0);
2332 Node* context = Parameter(3);
2333
2334 Variable var_value(this, MachineRepresentation::kTagged);
2335 Variable var_done(this, MachineRepresentation::kTagged);
2336
2337 // Required, or else `throw_bad_receiver` fails a DCHECK due to these
2338 // variables not being bound along all paths, despite not being used.
2339 var_done.Bind(TrueConstant());
2340 var_value.Bind(UndefinedConstant());
2341
2342 Label throw_bad_receiver(this, Label::kDeferred);
2343 Label set_done(this);
2344 Label allocate_key_result(this);
2345 Label allocate_entry_if_needed(this);
2346 Label allocate_iterator_result(this);
2347 Label generic_values(this);
2348
2349 // If O does not have all of the internal slots of an Array Iterator Instance
2350 // (22.1.5.3), throw a TypeError exception
2351 GotoIf(TaggedIsSmi(iterator), &throw_bad_receiver);
2352 Node* instance_type = LoadInstanceType(iterator);
2353 GotoIf(
2354 Uint32LessThan(
2355 Int32Constant(LAST_ARRAY_ITERATOR_TYPE - FIRST_ARRAY_ITERATOR_TYPE),
2356 Int32Sub(instance_type, Int32Constant(FIRST_ARRAY_ITERATOR_TYPE))),
2357 &throw_bad_receiver);
2358
2359 // Let a be O.[[IteratedObject]].
2360 Node* array =
2361 LoadObjectField(iterator, JSArrayIterator::kIteratedObjectOffset);
2362
2363 // Let index be O.[[ArrayIteratorNextIndex]].
2364 Node* index = LoadObjectField(iterator, JSArrayIterator::kNextIndexOffset);
2365 Node* orig_map =
2366 LoadObjectField(iterator, JSArrayIterator::kIteratedObjectMapOffset);
2367 Node* array_map = LoadMap(array);
2368
2369 Label if_isfastarray(this), if_isnotfastarray(this),
2370 if_isdetached(this, Label::kDeferred);
2371
2372 Branch(WordEqual(orig_map, array_map), &if_isfastarray, &if_isnotfastarray);
2373
2374 Bind(&if_isfastarray);
2375 {
2376 CSA_ASSERT(this, Word32Equal(LoadMapInstanceType(array_map),
2377 Int32Constant(JS_ARRAY_TYPE)));
2378
2379 Node* length = LoadObjectField(array, JSArray::kLengthOffset);
2380
2381 CSA_ASSERT(this, TaggedIsSmi(length));
2382 CSA_ASSERT(this, TaggedIsSmi(index));
2383
2384 GotoIfNot(SmiBelow(index, length), &set_done);
2385
2386 Node* one = SmiConstant(Smi::FromInt(1));
2387 StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
2388 SmiAdd(index, one));
2389
2390 var_done.Bind(FalseConstant());
2391 Node* elements = LoadElements(array);
2392
2393 static int32_t kInstanceType[] = {
2394 JS_FAST_ARRAY_KEY_ITERATOR_TYPE,
2395 JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2396 JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2397 JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2398 JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2399 JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2400 JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2401 JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE,
2402 JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE,
2403 JS_FAST_ARRAY_VALUE_ITERATOR_TYPE,
2404 JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE,
2405 JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE,
2406 JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE,
2407 };
2408
2409 Label packed_object_values(this), holey_object_values(this),
2410 packed_double_values(this), holey_double_values(this);
2411 Label* kInstanceTypeHandlers[] = {
2412 &allocate_key_result, &packed_object_values, &holey_object_values,
2413 &packed_object_values, &holey_object_values, &packed_double_values,
2414 &holey_double_values, &packed_object_values, &holey_object_values,
2415 &packed_object_values, &holey_object_values, &packed_double_values,
2416 &holey_double_values};
2417
2418 Switch(instance_type, &throw_bad_receiver, kInstanceType,
2419 kInstanceTypeHandlers, arraysize(kInstanceType));
2420
2421 Bind(&packed_object_values);
2422 {
2423 var_value.Bind(LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS));
2424 Goto(&allocate_entry_if_needed);
2425 }
2426
2427 Bind(&packed_double_values);
2428 {
2429 Node* value = LoadFixedDoubleArrayElement(
2430 elements, index, MachineType::Float64(), 0, SMI_PARAMETERS);
2431 var_value.Bind(AllocateHeapNumberWithValue(value));
2432 Goto(&allocate_entry_if_needed);
2433 }
2434
2435 Bind(&holey_object_values);
2436 {
2437 // Check the array_protector cell, and take the slow path if it's invalid.
2438 Node* invalid = SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
2439 Node* cell = LoadRoot(Heap::kArrayProtectorRootIndex);
2440 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
2441 GotoIf(WordEqual(cell_value, invalid), &generic_values);
2442
2443 var_value.Bind(UndefinedConstant());
2444 Node* value = LoadFixedArrayElement(elements, index, 0, SMI_PARAMETERS);
2445 GotoIf(WordEqual(value, TheHoleConstant()), &allocate_entry_if_needed);
2446 var_value.Bind(value);
2447 Goto(&allocate_entry_if_needed);
2448 }
2449
2450 Bind(&holey_double_values);
2451 {
2452 // Check the array_protector cell, and take the slow path if it's invalid.
2453 Node* invalid = SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
2454 Node* cell = LoadRoot(Heap::kArrayProtectorRootIndex);
2455 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
2456 GotoIf(WordEqual(cell_value, invalid), &generic_values);
2457
2458 var_value.Bind(UndefinedConstant());
2459 Node* value = LoadFixedDoubleArrayElement(
2460 elements, index, MachineType::Float64(), 0, SMI_PARAMETERS,
2461 &allocate_entry_if_needed);
2462 var_value.Bind(AllocateHeapNumberWithValue(value));
2463 Goto(&allocate_entry_if_needed);
2464 }
2465 }
2466
2467 Bind(&if_isnotfastarray);
2468 {
2469 Label if_istypedarray(this), if_isgeneric(this);
2470
2471 // If a is undefined, return CreateIterResultObject(undefined, true)
2472 GotoIf(WordEqual(array, UndefinedConstant()), &allocate_iterator_result);
2473
2474 Node* array_type = LoadInstanceType(array);
2475 Branch(Word32Equal(array_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
2476 &if_istypedarray, &if_isgeneric);
2477
2478 Bind(&if_isgeneric);
2479 {
2480 Label if_wasfastarray(this);
2481
2482 Node* length = nullptr;
2483 {
2484 Variable var_length(this, MachineRepresentation::kTagged);
2485 Label if_isarray(this), if_isnotarray(this), done(this);
2486 Branch(Word32Equal(array_type, Int32Constant(JS_ARRAY_TYPE)),
2487 &if_isarray, &if_isnotarray);
2488
2489 Bind(&if_isarray);
2490 {
2491 var_length.Bind(LoadObjectField(array, JSArray::kLengthOffset));
2492
2493 // Invalidate protector cell if needed
2494 Branch(WordNotEqual(orig_map, UndefinedConstant()), &if_wasfastarray,
2495 &done);
2496
2497 Bind(&if_wasfastarray);
2498 {
2499 Label if_invalid(this, Label::kDeferred);
2500 // A fast array iterator transitioned to a slow iterator during
2501 // iteration. Invalidate fast_array_iteration_prtoector cell to
2502 // prevent potential deopt loops.
2503 StoreObjectFieldNoWriteBarrier(
2504 iterator, JSArrayIterator::kIteratedObjectMapOffset,
2505 UndefinedConstant());
2506 GotoIf(Uint32LessThanOrEqual(
2507 instance_type,
2508 Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
2509 &done);
2510
2511 Node* invalid =
2512 SmiConstant(Smi::FromInt(Isolate::kProtectorInvalid));
2513 Node* cell = LoadRoot(Heap::kFastArrayIterationProtectorRootIndex);
2514 StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, invalid);
2515 Goto(&done);
2516 }
2517 }
2518
2519 Bind(&if_isnotarray);
2520 {
2521 Node* length =
2522 GetProperty(context, array, factory()->length_string());
2523 Callable to_length = CodeFactory::ToLength(isolate());
2524 var_length.Bind(CallStub(to_length, context, length));
2525 Goto(&done);
2526 }
2527
2528 Bind(&done);
2529 length = var_length.value();
2530 }
2531
2532 GotoUnlessNumberLessThan(index, length, &set_done);
2533
2534 StoreObjectField(iterator, JSArrayIterator::kNextIndexOffset,
2535 NumberInc(index));
2536 var_done.Bind(FalseConstant());
2537
2538 Branch(
2539 Uint32LessThanOrEqual(
2540 instance_type, Int32Constant(JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE)),
2541 &allocate_key_result, &generic_values);
2542
2543 Bind(&generic_values);
2544 {
2545 var_value.Bind(GetProperty(context, array, index));
2546 Goto(&allocate_entry_if_needed);
2547 }
2548 }
2549
2550 Bind(&if_istypedarray);
2551 {
2552 Node* buffer = LoadObjectField(array, JSTypedArray::kBufferOffset);
2553 GotoIf(IsDetachedBuffer(buffer), &if_isdetached);
2554
2555 Node* length = LoadObjectField(array, JSTypedArray::kLengthOffset);
2556
2557 CSA_ASSERT(this, TaggedIsSmi(length));
2558 CSA_ASSERT(this, TaggedIsSmi(index));
2559
2560 GotoIfNot(SmiBelow(index, length), &set_done);
2561
2562 Node* one = SmiConstant(1);
2563 StoreObjectFieldNoWriteBarrier(
2564 iterator, JSArrayIterator::kNextIndexOffset, SmiAdd(index, one));
2565 var_done.Bind(FalseConstant());
2566
2567 Node* elements = LoadElements(array);
2568 Node* base_ptr =
2569 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
2570 Node* external_ptr =
2571 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
2572 MachineType::Pointer());
2573 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
2574
2575 static int32_t kInstanceType[] = {
2576 JS_TYPED_ARRAY_KEY_ITERATOR_TYPE,
2577 JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2578 JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2579 JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2580 JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2581 JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2582 JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2583 JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2584 JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2585 JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE,
2586 JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE,
2587 JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE,
2588 JS_INT8_ARRAY_VALUE_ITERATOR_TYPE,
2589 JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE,
2590 JS_INT16_ARRAY_VALUE_ITERATOR_TYPE,
2591 JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE,
2592 JS_INT32_ARRAY_VALUE_ITERATOR_TYPE,
2593 JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE,
2594 JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE,
2595 };
2596
2597 Label uint8_values(this), int8_values(this), uint16_values(this),
2598 int16_values(this), uint32_values(this), int32_values(this),
2599 float32_values(this), float64_values(this);
2600 Label* kInstanceTypeHandlers[] = {
2601 &allocate_key_result, &uint8_values, &uint8_values,
2602 &int8_values, &uint16_values, &int16_values,
2603 &uint32_values, &int32_values, &float32_values,
2604 &float64_values, &uint8_values, &uint8_values,
2605 &int8_values, &uint16_values, &int16_values,
2606 &uint32_values, &int32_values, &float32_values,
2607 &float64_values,
2608 };
2609
2610 var_done.Bind(FalseConstant());
2611 Switch(instance_type, &throw_bad_receiver, kInstanceType,
2612 kInstanceTypeHandlers, arraysize(kInstanceType));
2613
2614 Bind(&uint8_values);
2615 {
2616 Node* value_uint8 = LoadFixedTypedArrayElement(
2617 data_ptr, index, UINT8_ELEMENTS, SMI_PARAMETERS);
2618 var_value.Bind(SmiFromWord32(value_uint8));
2619 Goto(&allocate_entry_if_needed);
2620 }
2621 Bind(&int8_values);
2622 {
2623 Node* value_int8 = LoadFixedTypedArrayElement(
2624 data_ptr, index, INT8_ELEMENTS, SMI_PARAMETERS);
2625 var_value.Bind(SmiFromWord32(value_int8));
2626 Goto(&allocate_entry_if_needed);
2627 }
2628 Bind(&uint16_values);
2629 {
2630 Node* value_uint16 = LoadFixedTypedArrayElement(
2631 data_ptr, index, UINT16_ELEMENTS, SMI_PARAMETERS);
2632 var_value.Bind(SmiFromWord32(value_uint16));
2633 Goto(&allocate_entry_if_needed);
2634 }
2635 Bind(&int16_values);
2636 {
2637 Node* value_int16 = LoadFixedTypedArrayElement(
2638 data_ptr, index, INT16_ELEMENTS, SMI_PARAMETERS);
2639 var_value.Bind(SmiFromWord32(value_int16));
2640 Goto(&allocate_entry_if_needed);
2641 }
2642 Bind(&uint32_values);
2643 {
2644 Node* value_uint32 = LoadFixedTypedArrayElement(
2645 data_ptr, index, UINT32_ELEMENTS, SMI_PARAMETERS);
2646 var_value.Bind(ChangeUint32ToTagged(value_uint32));
2647 Goto(&allocate_entry_if_needed);
2648 }
2649 Bind(&int32_values);
2650 {
2651 Node* value_int32 = LoadFixedTypedArrayElement(
2652 data_ptr, index, INT32_ELEMENTS, SMI_PARAMETERS);
2653 var_value.Bind(ChangeInt32ToTagged(value_int32));
2654 Goto(&allocate_entry_if_needed);
2655 }
2656 Bind(&float32_values);
2657 {
2658 Node* value_float32 = LoadFixedTypedArrayElement(
2659 data_ptr, index, FLOAT32_ELEMENTS, SMI_PARAMETERS);
2660 var_value.Bind(
2661 AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(value_float32)));
2662 Goto(&allocate_entry_if_needed);
2663 }
2664 Bind(&float64_values);
2665 {
2666 Node* value_float64 = LoadFixedTypedArrayElement(
2667 data_ptr, index, FLOAT64_ELEMENTS, SMI_PARAMETERS);
2668 var_value.Bind(AllocateHeapNumberWithValue(value_float64));
2669 Goto(&allocate_entry_if_needed);
2670 }
2671 }
2672 }
2673
2674 Bind(&set_done);
2675 {
2676 StoreObjectFieldNoWriteBarrier(
2677 iterator, JSArrayIterator::kIteratedObjectOffset, UndefinedConstant());
2678 Goto(&allocate_iterator_result);
2679 }
2680
2681 Bind(&allocate_key_result);
2682 {
2683 var_value.Bind(index);
2684 var_done.Bind(FalseConstant());
2685 Goto(&allocate_iterator_result);
2686 }
2687
2688 Bind(&allocate_entry_if_needed);
2689 {
2690 GotoIf(Int32GreaterThan(instance_type,
2691 Int32Constant(LAST_ARRAY_KEY_VALUE_ITERATOR_TYPE)),
2692 &allocate_iterator_result);
2693
2694 Node* elements = AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2));
2695 StoreFixedArrayElement(elements, 0, index, SKIP_WRITE_BARRIER);
2696 StoreFixedArrayElement(elements, 1, var_value.value(), SKIP_WRITE_BARRIER);
2697
2698 Node* entry = Allocate(JSArray::kSize);
2699 Node* map = LoadContextElement(LoadNativeContext(context),
2700 Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX);
2701
2702 StoreMapNoWriteBarrier(entry, map);
2703 StoreObjectFieldRoot(entry, JSArray::kPropertiesOffset,
2704 Heap::kEmptyFixedArrayRootIndex);
2705 StoreObjectFieldNoWriteBarrier(entry, JSArray::kElementsOffset, elements);
2706 StoreObjectFieldNoWriteBarrier(entry, JSArray::kLengthOffset,
2707 SmiConstant(Smi::FromInt(2)));
2708
2709 var_value.Bind(entry);
2710 Goto(&allocate_iterator_result);
2711 }
2712
2713 Bind(&allocate_iterator_result);
2714 {
2715 Node* result = Allocate(JSIteratorResult::kSize);
2716 Node* map = LoadContextElement(LoadNativeContext(context),
2717 Context::ITERATOR_RESULT_MAP_INDEX);
2718 StoreMapNoWriteBarrier(result, map);
2719 StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset,
2720 Heap::kEmptyFixedArrayRootIndex);
2721 StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
2722 Heap::kEmptyFixedArrayRootIndex);
2723 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset,
2724 var_value.value());
2725 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset,
2726 var_done.value());
2727 Return(result);
2728 }
2729
2730 Bind(&throw_bad_receiver);
2731 {
2732 // The {receiver} is not a valid JSArrayIterator.
2733 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
2734 HeapConstant(operation), iterator);
2735 Unreachable();
2736 }
2737
2738 Bind(&if_isdetached);
2739 {
2740 Node* message = SmiConstant(MessageTemplate::kDetachedOperation);
2741 CallRuntime(Runtime::kThrowTypeError, context, message,
2742 HeapConstant(operation));
2743 Unreachable();
2744 }
2745 }
2746
2747 } // namespace internal 1242 } // namespace internal
2748 } // namespace v8 1243 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-arguments-gen.cc ('k') | src/builtins/builtins-array-gen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698