OLD | NEW |
---|---|
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 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 | 420 |
421 if (JSArray::HasReadOnlyLength(array)) { | 421 if (JSArray::HasReadOnlyLength(array)) { |
422 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); | 422 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
423 } | 423 } |
424 | 424 |
425 ElementsAccessor* accessor = array->GetElementsAccessor(); | 425 ElementsAccessor* accessor = array->GetElementsAccessor(); |
426 int new_length = accessor->Unshift(array, &args, to_add); | 426 int new_length = accessor->Unshift(array, &args, to_add); |
427 return Smi::FromInt(new_length); | 427 return Smi::FromInt(new_length); |
428 } | 428 } |
429 | 429 |
430 class ForEachCodeStubAssembler : public CodeStubAssembler { | 430 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
431 public: | 431 public: |
432 explicit ForEachCodeStubAssembler(compiler::CodeAssemblerState* state) | 432 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) |
433 : CodeStubAssembler(state) {} | 433 : CodeStubAssembler(state) {} |
434 | 434 |
435 void VisitOneElement(Node* context, Node* this_arg, Node* o, Node* k, | 435 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator; |
436 Node* callbackfn) { | 436 typedef std::function<void(Node* a, Node* pK, Node* value)> |
437 Comment("begin VisitOneElement"); | 437 CallResultProcessor; |
438 | 438 |
439 // a. Let Pk be ToString(k). | 439 void GenerateArrayIteratingBuiltinBody(const char* name, Node* receiver, |
440 Node* p_k = ToString(context, k); | 440 Node* callbackfn, Node* this_arg, |
441 Node* context, | |
442 BuiltinResultGenerator generator, | |
Igor Sheludko
2017/03/10 14:14:44
const X&
danno
2017/03/13 07:22:06
Done.
| |
443 CallResultProcessor processor) { | |
Igor Sheludko
2017/03/10 14:14:45
Same here.
danno
2017/03/13 07:22:06
Done.
| |
444 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); | |
445 Label non_array(this), slow(this, &k), array_changes(this, &k); | |
441 | 446 |
442 // b. Let kPresent be HasProperty(O, Pk). | 447 // TODO(danno): Seriously? Do we really need to throw the exact error |
443 // c. ReturnIfAbrupt(kPresent). | 448 // message on null and undefined so that the webkit tests pass? |
444 Node* k_present = | 449 Label throw_null_undefined_exception(this, Label::kDeferred); |
445 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); | 450 GotoIf(WordEqual(receiver, NullConstant()), |
451 &throw_null_undefined_exception); | |
452 GotoIf(WordEqual(receiver, UndefinedConstant()), | |
453 &throw_null_undefined_exception); | |
446 | 454 |
447 // d. If kPresent is true, then | 455 // By the book: taken directly from the ECMAScript 2015 specification |
448 Label not_present(this); | |
449 GotoIf(WordNotEqual(k_present, TrueConstant()), ¬_present); | |
450 | 456 |
451 // i. Let kValue be Get(O, Pk). | 457 // 1. Let O be ToObject(this value). |
452 // ii. ReturnIfAbrupt(kValue). | 458 // 2. ReturnIfAbrupt(O) |
453 Node* k_value = | 459 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); |
454 CallStub(CodeFactory::GetProperty(isolate()), context, o, k); | |
455 | 460 |
456 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | 461 // 3. Let len be ToLength(Get(O, "length")). |
457 // iv. ReturnIfAbrupt(funcResult). | 462 // 4. ReturnIfAbrupt(len). |
458 CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, k_value, | 463 Variable merged_length(this, MachineRepresentation::kTagged); |
459 k, o); | 464 Label has_length(this, &merged_length), not_js_array(this); |
465 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), ¬_js_array); | |
466 merged_length.Bind(LoadJSArrayLength(o)); | |
467 Goto(&has_length); | |
468 Bind(¬_js_array); | |
469 Node* len_property = | |
470 CallStub(CodeFactory::GetProperty(isolate()), context, o, | |
471 HeapConstant(isolate()->factory()->length_string())); | |
472 merged_length.Bind( | |
473 CallStub(CodeFactory::ToLength(isolate()), context, len_property)); | |
474 Goto(&has_length); | |
475 Bind(&has_length); | |
476 Node* len = merged_length.value(); | |
460 | 477 |
461 Goto(¬_present); | 478 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. |
462 Bind(¬_present); | 479 Label type_exception(this, Label::kDeferred); |
463 Comment("end VisitOneElement"); | 480 Label done(this); |
481 GotoIf(TaggedIsSmi(callbackfn), &type_exception); | |
482 Branch(IsCallableMap(LoadMap(callbackfn)), &done, &type_exception); | |
483 | |
484 Bind(&throw_null_undefined_exception); | |
485 { | |
486 std::string s("Array.prototype."); | |
487 s += name; | |
Igor Sheludko
2017/03/10 14:14:45
name could just be a "Array.prototype.smth" for si
danno
2017/03/13 07:22:06
Unfortunately, these must match the method name ex
Igor Sheludko
2017/03/13 08:21:20
I meant to pass full method name as a parameter in
| |
488 CallRuntime(Runtime::kThrowTypeError, context, | |
489 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), | |
490 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked( | |
491 s.c_str()))); | |
492 Unreachable(); | |
493 } | |
494 | |
495 Bind(&type_exception); | |
496 { | |
497 CallRuntime(Runtime::kThrowTypeError, context, | |
498 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); | |
499 Unreachable(); | |
500 } | |
501 | |
502 Bind(&done); | |
503 | |
504 Node* a = generator(o, len); | |
505 | |
506 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | |
507 // [Already done by the arguments adapter] | |
508 | |
509 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, | |
510 &slow); | |
511 | |
512 // 7. Let k be 0. | |
513 // Already done above in initialization of the Variable k | |
514 | |
515 Bind(&slow); | |
516 { | |
517 // 8. Repeat, while k < len | |
518 Label loop(this, &k); | |
519 Label after_loop(this); | |
520 Goto(&loop); | |
521 Bind(&loop); | |
522 { | |
523 GotoUnlessNumberLessThan(k.value(), len, &after_loop); | |
524 | |
525 Label done_element(this); | |
526 // a. Let Pk be ToString(k). | |
527 Node* p_k = ToString(context, k.value()); | |
528 | |
529 // b. Let kPresent be HasProperty(O, Pk). | |
530 // c. ReturnIfAbrupt(kPresent). | |
531 Node* k_present = | |
532 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); | |
533 | |
534 // d. If kPresent is true, then | |
535 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | |
536 | |
537 // i. Let kValue be Get(O, Pk). | |
538 // ii. ReturnIfAbrupt(kValue). | |
539 Node* k_value = CallStub(CodeFactory::GetProperty(isolate()), context, | |
540 o, k.value()); | |
541 | |
542 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | |
543 // iv. ReturnIfAbrupt(funcResult). | |
544 Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn, | |
545 this_arg, k_value, k.value(), o); | |
546 | |
547 processor(a, p_k, result); | |
548 Goto(&done_element); | |
549 Bind(&done_element); | |
550 | |
551 // e. Increase k by 1. | |
552 k.Bind(NumberInc(k.value())); | |
553 Goto(&loop); | |
554 } | |
555 Bind(&after_loop); | |
556 Return(a); | |
557 } | |
464 } | 558 } |
465 | 559 |
466 void VisitAllFastElements(Node* context, ElementsKind kind, Node* this_arg, | 560 private: |
467 Node* o, Node* len, Node* callbackfn, | 561 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, |
468 ParameterMode mode) { | 562 Node* this_arg, Node* o, Node* len, |
469 Comment("begin VisitAllFastElements"); | 563 Node* callbackfn, |
564 CallResultProcessor processor, Node* a, | |
Igor Sheludko
2017/03/10 14:14:45
Same here.
danno
2017/03/13 07:22:06
Done.
| |
565 Label* array_changed, ParameterMode mode) { | |
566 Comment("begin VisitAllFastElementsOneKind"); | |
470 Variable original_map(this, MachineRepresentation::kTagged); | 567 Variable original_map(this, MachineRepresentation::kTagged); |
471 original_map.Bind(LoadMap(o)); | 568 original_map.Bind(LoadMap(o)); |
472 VariableList list({&original_map}, zone()); | 569 VariableList list({&original_map}, zone()); |
570 Node* last_index = nullptr; | |
473 BuildFastLoop( | 571 BuildFastLoop( |
474 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), | 572 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), |
475 [context, kind, this, o, &original_map, callbackfn, this_arg, | 573 [context, kind, this, o, &original_map, callbackfn, this_arg, processor, |
Igor Sheludko
2017/03/10 14:14:44
I think these long capture lists do not contribute
danno
2017/03/13 07:22:06
Done.
| |
476 mode](Node* index) { | 574 a, array_changed, &last_index, mode](Node* index) { |
477 Label one_element_done(this), array_changed(this, Label::kDeferred), | 575 last_index = index; |
478 hole_element(this); | 576 Label one_element_done(this), hole_element(this); |
479 | 577 |
480 // Check if o's map has changed during the callback. If so, we have to | 578 // Check if o's map has changed during the callback. If so, we have to |
481 // fall back to the slower spec implementation for the rest of the | 579 // fall back to the slower spec implementation for the rest of the |
482 // iteration. | 580 // iteration. |
483 Node* o_map = LoadMap(o); | 581 Node* o_map = LoadMap(o); |
484 GotoIf(WordNotEqual(o_map, original_map.value()), &array_changed); | 582 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); |
485 | 583 |
486 // Check if o's length has changed during the callback and if the | 584 // Check if o's length has changed during the callback and if the |
487 // index is now out of range of the new length. | 585 // index is now out of range of the new length. |
488 Node* tagged_index = ParameterToTagged(index, mode); | 586 Node* tagged_index = ParameterToTagged(index, mode); |
489 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), | 587 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), |
490 &array_changed); | 588 array_changed); |
491 | 589 |
492 // Re-load the elements array. If may have been resized. | 590 // Re-load the elements array. If may have been resized. |
493 Node* elements = LoadElements(o); | 591 Node* elements = LoadElements(o); |
494 | 592 |
495 // Fast case: load the element directly from the elements FixedArray | 593 // Fast case: load the element directly from the elements FixedArray |
496 // and call the callback if the element is not the hole. | 594 // and call the callback if the element is not the hole. |
497 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); | 595 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); |
498 int base_size = kind == FAST_ELEMENTS | 596 int base_size = kind == FAST_ELEMENTS |
499 ? FixedArray::kHeaderSize | 597 ? FixedArray::kHeaderSize |
500 : (FixedArray::kHeaderSize - kHeapObjectTag); | 598 : (FixedArray::kHeaderSize - kHeapObjectTag); |
501 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); | 599 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); |
502 Node* value = nullptr; | 600 Node* value = nullptr; |
503 if (kind == FAST_ELEMENTS) { | 601 if (kind == FAST_ELEMENTS) { |
504 value = LoadObjectField(elements, offset); | 602 value = LoadObjectField(elements, offset); |
505 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); | 603 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); |
506 } else { | 604 } else { |
507 Node* double_value = | 605 Node* double_value = |
508 LoadDoubleWithHoleCheck(elements, offset, &hole_element); | 606 LoadDoubleWithHoleCheck(elements, offset, &hole_element); |
509 value = AllocateHeapNumberWithValue(double_value); | 607 value = AllocateHeapNumberWithValue(double_value); |
510 } | 608 } |
511 CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, | 609 Node* result = CallJS(CodeFactory::Call(isolate()), context, |
512 value, tagged_index, o); | 610 callbackfn, this_arg, value, tagged_index, o); |
611 processor(a, tagged_index, result); | |
513 Goto(&one_element_done); | 612 Goto(&one_element_done); |
514 | 613 |
515 Bind(&hole_element); | 614 Bind(&hole_element); |
615 // Check if o's prototype change unexpectedly has elements after the | |
616 // callback in the case of a hole. | |
516 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, | 617 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, |
517 &array_changed); | 618 array_changed); |
518 | |
519 // O's changed during the forEach. Use the implementation precisely | |
520 // specified in the spec for the rest of the iteration, also making | |
521 // the failed original_map sticky in case of a subseuent change that | |
522 // goes back to the original map. | |
523 Bind(&array_changed); | |
524 VisitOneElement(context, this_arg, o, ParameterToTagged(index, mode), | |
525 callbackfn); | |
526 original_map.Bind(UndefinedConstant()); | |
527 Goto(&one_element_done); | |
528 | 619 |
529 Bind(&one_element_done); | 620 Bind(&one_element_done); |
530 }, | 621 }, |
531 1, mode, IndexAdvanceMode::kPost); | 622 1, mode, IndexAdvanceMode::kPost); |
532 Comment("end VisitAllFastElements"); | 623 Comment("end VisitAllFastElementsOneKind"); |
624 return last_index; | |
625 } | |
626 | |
627 void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len, | |
628 Node* callbackfn, CallResultProcessor processor, | |
629 Node* a, Variable& k, Label* slow) { | |
630 Label switch_on_elements_kind(this), fast_elements(this), | |
631 maybe_double_elements(this), fast_double_elements(this); | |
632 | |
633 Comment("begin HandleFastElements"); | |
634 // Non-smi lengths must use the slow path. | |
635 GotoIf(TaggedIsNotSmi(len), slow); | |
636 | |
637 BranchIfFastJSArray(o, context, | |
638 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | |
639 &switch_on_elements_kind, slow); | |
640 | |
641 Bind(&switch_on_elements_kind); | |
642 // Select by ElementsKind | |
643 Node* o_map = LoadMap(o); | |
644 Node* bit_field2 = LoadMapBitField2(o_map); | |
645 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
646 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
647 &maybe_double_elements, &fast_elements); | |
648 | |
649 ParameterMode mode = OptimalParameterMode(); | |
650 Bind(&fast_elements); | |
651 { | |
652 Label array_changed(this, Label::kDeferred); | |
653 Node* last_index = VisitAllFastElementsOneKind( | |
654 context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a, | |
655 &array_changed, mode); | |
656 | |
657 // No exception, return success | |
658 Return(a); | |
659 | |
660 Bind(&array_changed); | |
661 k.Bind(ParameterToTagged(last_index, mode)); | |
662 Goto(slow); | |
663 } | |
664 | |
665 Bind(&maybe_double_elements); | |
666 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), | |
667 slow, &fast_double_elements); | |
668 | |
669 Bind(&fast_double_elements); | |
670 { | |
671 Label array_changed(this, Label::kDeferred); | |
672 Node* last_index = VisitAllFastElementsOneKind( | |
673 context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn, | |
674 processor, a, &array_changed, mode); | |
675 | |
676 // No exception, return success | |
677 Return(a); | |
678 | |
679 Bind(&array_changed); | |
680 k.Bind(ParameterToTagged(last_index, mode)); | |
681 Goto(slow); | |
682 } | |
533 } | 683 } |
534 }; | 684 }; |
535 | 685 |
536 TF_BUILTIN(ArrayForEach, ForEachCodeStubAssembler) { | 686 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { |
537 Label non_array(this), examine_elements(this), fast_elements(this), | |
538 slow(this), maybe_double_elements(this), fast_double_elements(this); | |
539 | |
540 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | 687 Node* receiver = Parameter(ForEachDescriptor::kReceiver); |
541 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | 688 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); |
542 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | 689 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); |
543 Node* context = Parameter(ForEachDescriptor::kContext); | 690 Node* context = Parameter(ForEachDescriptor::kContext); |
544 | 691 |
545 // TODO(danno): Seriously? Do we really need to throw the exact error message | 692 GenerateArrayIteratingBuiltinBody( |
546 // on null and undefined so that the webkit tests pass? | 693 "forEach", receiver, callbackfn, this_arg, context, |
547 Label throw_null_undefined_exception(this, Label::kDeferred); | 694 [this](Node*, Node*) { return UndefinedConstant(); }, |
Igor Sheludko
2017/03/10 14:14:44
[=]
danno
2017/03/13 07:22:06
Done.
| |
548 GotoIf(WordEqual(receiver, NullConstant()), &throw_null_undefined_exception); | 695 [](Node* a, Node* p_k, Node* value) {}); |
549 GotoIf(WordEqual(receiver, UndefinedConstant()), | 696 } |
550 &throw_null_undefined_exception); | |
551 | 697 |
552 // By the book: taken directly from the ECMAScript 2015 specification | 698 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { |
699 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | |
700 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | |
701 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | |
702 Node* context = Parameter(ForEachDescriptor::kContext); | |
553 | 703 |
554 // 1. Let O be ToObject(this value). | 704 GenerateArrayIteratingBuiltinBody( |
555 // 2. ReturnIfAbrupt(O) | 705 "every", receiver, callbackfn, this_arg, context, |
556 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); | 706 [this](Node*, Node*) { return TrueConstant(); }, |
Igor Sheludko
2017/03/10 14:14:44
[=]
danno
2017/03/13 07:22:06
Done.
| |
707 [this](Node* a, Node* p_k, Node* value) { | |
Igor Sheludko
2017/03/10 14:14:44
Same here.
danno
2017/03/13 07:22:06
Done.
| |
708 Label true_continue(this), return_false(this); | |
709 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); | |
710 Bind(&return_false); | |
711 Return(FalseConstant()); | |
712 Bind(&true_continue); | |
713 }); | |
714 } | |
557 | 715 |
558 // 3. Let len be ToLength(Get(O, "length")). | 716 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { |
559 // 4. ReturnIfAbrupt(len). | 717 Node* receiver = Parameter(ForEachDescriptor::kReceiver); |
560 Variable merged_length(this, MachineRepresentation::kTagged); | 718 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); |
561 Label has_length(this, &merged_length), not_js_array(this); | 719 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); |
562 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), ¬_js_array); | 720 Node* context = Parameter(ForEachDescriptor::kContext); |
563 merged_length.Bind(LoadJSArrayLength(o)); | |
564 Goto(&has_length); | |
565 Bind(¬_js_array); | |
566 Node* len_property = | |
567 CallStub(CodeFactory::GetProperty(isolate()), context, o, | |
568 HeapConstant(isolate()->factory()->length_string())); | |
569 merged_length.Bind( | |
570 CallStub(CodeFactory::ToLength(isolate()), context, len_property)); | |
571 Goto(&has_length); | |
572 Bind(&has_length); | |
573 Node* len = merged_length.value(); | |
574 | 721 |
575 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. | 722 GenerateArrayIteratingBuiltinBody( |
576 Label type_exception(this, Label::kDeferred); | 723 "some", receiver, callbackfn, this_arg, context, |
577 GotoIf(TaggedIsSmi(callbackfn), &type_exception); | 724 [this](Node*, Node*) { return FalseConstant(); }, |
Igor Sheludko
2017/03/10 14:14:44
[=]
danno
2017/03/13 07:22:06
Done.
| |
578 GotoIfNot(IsCallableMap(LoadMap(callbackfn)), &type_exception); | 725 [this](Node* a, Node* p_k, Node* value) { |
Igor Sheludko
2017/03/10 14:14:44
Same here.
danno
2017/03/13 07:22:06
Done.
| |
579 | 726 Label false_continue(this), return_true(this); |
580 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | 727 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
581 // [Already done by the arguments adapter] | 728 Bind(&return_true); |
582 | 729 Return(TrueConstant()); |
583 // Non-smi lengths must use the slow path. | 730 Bind(&false_continue); |
584 GotoIf(TaggedIsNotSmi(len), &slow); | 731 }); |
585 | |
586 BranchIfFastJSArray(o, context, | |
587 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | |
588 &examine_elements, &slow); | |
589 | |
590 Bind(&examine_elements); | |
591 | |
592 ParameterMode mode = OptimalParameterMode(); | |
593 | |
594 // Select by ElementsKind | |
595 Node* o_map = LoadMap(o); | |
596 Node* bit_field2 = LoadMapBitField2(o_map); | |
597 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
598 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
599 &maybe_double_elements, &fast_elements); | |
600 | |
601 Bind(&fast_elements); | |
602 { | |
603 VisitAllFastElements(context, FAST_ELEMENTS, this_arg, o, len, callbackfn, | |
604 mode); | |
605 | |
606 // No exception, return success | |
607 Return(UndefinedConstant()); | |
608 } | |
609 | |
610 Bind(&maybe_double_elements); | |
611 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), | |
612 &slow, &fast_double_elements); | |
613 | |
614 Bind(&fast_double_elements); | |
615 { | |
616 VisitAllFastElements(context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, | |
617 callbackfn, mode); | |
618 | |
619 // No exception, return success | |
620 Return(UndefinedConstant()); | |
621 } | |
622 | |
623 Bind(&slow); | |
624 { | |
625 // By the book: taken from the ECMAScript 2015 specification (cont.) | |
626 | |
627 // 7. Let k be 0. | |
628 Variable k(this, MachineRepresentation::kTagged); | |
629 k.Bind(SmiConstant(0)); | |
630 | |
631 // 8. Repeat, while k < len | |
632 Label loop(this, &k); | |
633 Label after_loop(this); | |
634 Goto(&loop); | |
635 Bind(&loop); | |
636 { | |
637 GotoUnlessNumberLessThan(k.value(), len, &after_loop); | |
638 | |
639 VisitOneElement(context, this_arg, o, k.value(), callbackfn); | |
640 | |
641 // e. Increase k by 1. | |
642 k.Bind(NumberInc(k.value())); | |
643 Goto(&loop); | |
644 } | |
645 Bind(&after_loop); | |
646 Return(UndefinedConstant()); | |
647 } | |
648 | |
649 Bind(&throw_null_undefined_exception); | |
650 { | |
651 CallRuntime(Runtime::kThrowTypeError, context, | |
652 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), | |
653 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked( | |
654 "Array.prototype.forEach"))); | |
655 Unreachable(); | |
656 } | |
657 | |
658 Bind(&type_exception); | |
659 { | |
660 CallRuntime(Runtime::kThrowTypeError, context, | |
661 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); | |
662 Unreachable(); | |
663 } | |
664 } | 732 } |
665 | 733 |
666 BUILTIN(ArraySlice) { | 734 BUILTIN(ArraySlice) { |
667 HandleScope scope(isolate); | 735 HandleScope scope(isolate); |
668 Handle<Object> receiver = args.receiver(); | 736 Handle<Object> receiver = args.receiver(); |
669 int len = -1; | 737 int len = -1; |
670 int relative_start = 0; | 738 int relative_start = 0; |
671 int relative_end = 0; | 739 int relative_end = 0; |
672 | 740 |
673 if (receiver->IsJSArray()) { | 741 if (receiver->IsJSArray()) { |
(...skipping 2171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2845 { | 2913 { |
2846 Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation); | 2914 Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation); |
2847 assembler.CallRuntime(Runtime::kThrowTypeError, context, message, | 2915 assembler.CallRuntime(Runtime::kThrowTypeError, context, message, |
2848 assembler.HeapConstant(operation)); | 2916 assembler.HeapConstant(operation)); |
2849 assembler.Unreachable(); | 2917 assembler.Unreachable(); |
2850 } | 2918 } |
2851 } | 2919 } |
2852 | 2920 |
2853 } // namespace internal | 2921 } // namespace internal |
2854 } // namespace v8 | 2922 } // namespace v8 |
OLD | NEW |