| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/interpreter/interpreter-assembler.h" | 5 #include "src/interpreter/interpreter-assembler.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <ostream> | 8 #include <ostream> |
| 9 | 9 |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| (...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not | 539 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not |
| 540 // computed, meaning that it can't appear to be a pointer. If the low bit is | 540 // computed, meaning that it can't appear to be a pointer. If the low bit is |
| 541 // 0, then hash is computed, but the 0 bit prevents the field from appearing | 541 // 0, then hash is computed, but the 0 bit prevents the field from appearing |
| 542 // to be a pointer. | 542 // to be a pointer. |
| 543 STATIC_ASSERT(WeakCell::kSize >= kPointerSize); | 543 STATIC_ASSERT(WeakCell::kSize >= kPointerSize); |
| 544 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset == | 544 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset == |
| 545 WeakCell::kValueOffset && | 545 WeakCell::kValueOffset && |
| 546 WeakCell::kValueOffset == Symbol::kHashFieldSlot); | 546 WeakCell::kValueOffset == Symbol::kHashFieldSlot); |
| 547 | 547 |
| 548 Variable return_value(this, MachineRepresentation::kTagged); | 548 Variable return_value(this, MachineRepresentation::kTagged); |
| 549 Label handle_monomorphic(this), extra_checks(this), end(this), call(this), | 549 Label call_function(this), extra_checks(this, Label::kDeferred), call(this), |
| 550 call_function(this); | 550 end(this); |
| 551 | 551 |
| 552 // The checks. First, does function match the recorded monomorphic target? | 552 // The checks. First, does function match the recorded monomorphic target? |
| 553 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); | 553 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); |
| 554 Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element); | 554 Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element); |
| 555 Node* is_monomorphic = WordEqual(function, feedback_value); | 555 Node* is_monomorphic = WordEqual(function, feedback_value); |
| 556 Branch(is_monomorphic, &handle_monomorphic, &extra_checks); | 556 GotoUnless(is_monomorphic, &extra_checks); |
| 557 | 557 |
| 558 Bind(&handle_monomorphic); | 558 // The compare above could have been a SMI/SMI comparison. Guard against |
| 559 // this convincing us that we have a monomorphic JSFunction. |
| 560 Node* is_smi = TaggedIsSmi(function); |
| 561 Branch(is_smi, &extra_checks, &call_function); |
| 562 |
| 563 Bind(&call_function); |
| 559 { | 564 { |
| 560 // The compare above could have been a SMI/SMI comparison. Guard against | |
| 561 // this convincing us that we have a monomorphic JSFunction. | |
| 562 Node* is_smi = TaggedIsSmi(function); | |
| 563 GotoIf(is_smi, &extra_checks); | |
| 564 | |
| 565 // Increment the call count. | 565 // Increment the call count. |
| 566 IncrementCallCount(type_feedback_vector, slot_id); | 566 IncrementCallCount(type_feedback_vector, slot_id); |
| 567 | 567 |
| 568 // Call using call function builtin. | 568 // Call using call function builtin. |
| 569 Callable callable = CodeFactory::InterpreterPushArgsAndCall( | 569 Callable callable = CodeFactory::InterpreterPushArgsAndCall( |
| 570 isolate(), tail_call_mode, CallableType::kJSFunction); | 570 isolate(), tail_call_mode, CallableType::kJSFunction); |
| 571 Node* code_target = HeapConstant(callable.code()); | 571 Node* code_target = HeapConstant(callable.code()); |
| 572 Node* ret_value = CallStub(callable.descriptor(), code_target, context, | 572 Node* ret_value = CallStub(callable.descriptor(), code_target, context, |
| 573 arg_count, first_arg, function); | 573 arg_count, first_arg, function); |
| 574 return_value.Bind(ret_value); | 574 return_value.Bind(ret_value); |
| 575 Goto(&end); | 575 Goto(&end); |
| 576 } | 576 } |
| 577 | 577 |
| 578 Bind(&extra_checks); | 578 Bind(&extra_checks); |
| 579 { | 579 { |
| 580 Label check_initialized(this, Label::kDeferred), mark_megamorphic(this), | 580 Label check_initialized(this), mark_megamorphic(this), |
| 581 check_allocation_site(this), | 581 create_allocation_site(this); |
| 582 create_allocation_site(this, Label::kDeferred); | 582 |
| 583 // Check if it is a megamorphic target | 583 Comment("check if megamorphic"); |
| 584 // Check if it is a megamorphic target. |
| 584 Node* is_megamorphic = WordEqual( | 585 Node* is_megamorphic = WordEqual( |
| 585 feedback_element, | 586 feedback_element, |
| 586 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); | 587 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); |
| 587 Branch(is_megamorphic, &call, &check_allocation_site); | 588 GotoIf(is_megamorphic, &call); |
| 588 | 589 |
| 589 Bind(&check_allocation_site); | 590 Comment("check if it is an allocation site"); |
| 590 { | 591 Node* is_allocation_site = WordEqual( |
| 591 Node* is_allocation_site = | 592 LoadMap(feedback_element), LoadRoot(Heap::kAllocationSiteMapRootIndex)); |
| 592 WordEqual(LoadMap(feedback_element), | 593 GotoUnless(is_allocation_site, &check_initialized); |
| 593 LoadRoot(Heap::kAllocationSiteMapRootIndex)); | |
| 594 GotoUnless(is_allocation_site, &check_initialized); | |
| 595 | 594 |
| 596 // If it is not the Array() function, mark megamorphic. | 595 // If it is not the Array() function, mark megamorphic. |
| 597 Node* context_slot = | 596 Node* context_slot = |
| 598 LoadFixedArrayElement(LoadNativeContext(context), | 597 LoadFixedArrayElement(LoadNativeContext(context), |
| 599 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); | 598 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); |
| 600 Node* is_array_function = WordEqual(context_slot, function); | 599 Node* is_array_function = WordEqual(context_slot, function); |
| 601 GotoUnless(is_array_function, &mark_megamorphic); | 600 GotoUnless(is_array_function, &mark_megamorphic); |
| 602 | 601 |
| 603 // It is a monomorphic Array function. Increment the call count. | 602 // It is a monomorphic Array function. Increment the call count. |
| 604 IncrementCallCount(type_feedback_vector, slot_id); | 603 IncrementCallCount(type_feedback_vector, slot_id); |
| 605 | 604 |
| 606 // Call ArrayConstructorStub. | 605 // Call ArrayConstructorStub. |
| 607 Callable callable_call = | 606 Callable callable_call = |
| 608 CodeFactory::InterpreterPushArgsAndConstructArray(isolate()); | 607 CodeFactory::InterpreterPushArgsAndConstructArray(isolate()); |
| 609 Node* code_target_call = HeapConstant(callable_call.code()); | 608 Node* code_target_call = HeapConstant(callable_call.code()); |
| 610 Node* ret_value = | 609 Node* ret_value = |
| 611 CallStub(callable_call.descriptor(), code_target_call, context, | 610 CallStub(callable_call.descriptor(), code_target_call, context, |
| 612 arg_count, function, feedback_element, first_arg); | 611 arg_count, function, feedback_element, first_arg); |
| 613 return_value.Bind(ret_value); | 612 return_value.Bind(ret_value); |
| 614 Goto(&end); | 613 Goto(&end); |
| 615 } | |
| 616 | 614 |
| 617 Bind(&check_initialized); | 615 Bind(&check_initialized); |
| 618 { | 616 { |
| 619 Label possibly_monomorphic(this); | 617 Comment("check if uninitialized"); |
| 620 // Check if it is uninitialized. | 618 // Check if it is uninitialized target first. |
| 621 Node* is_uninitialized = WordEqual( | 619 Node* is_uninitialized = WordEqual( |
| 622 feedback_element, | 620 feedback_element, |
| 623 HeapConstant(TypeFeedbackVector::UninitializedSentinel(isolate()))); | 621 HeapConstant(TypeFeedbackVector::UninitializedSentinel(isolate()))); |
| 624 GotoUnless(is_uninitialized, &mark_megamorphic); | 622 GotoUnless(is_uninitialized, &mark_megamorphic); |
| 625 | 623 |
| 624 Comment("handle_unitinitialized"); |
| 625 // If it is not a JSFunction mark it as megamorphic. |
| 626 Node* is_smi = TaggedIsSmi(function); | 626 Node* is_smi = TaggedIsSmi(function); |
| 627 GotoIf(is_smi, &mark_megamorphic); | 627 GotoIf(is_smi, &mark_megamorphic); |
| 628 | 628 |
| 629 // Check if function is an object of JSFunction type | 629 // Check if function is an object of JSFunction type. |
| 630 Node* instance_type = LoadInstanceType(function); | 630 Node* instance_type = LoadInstanceType(function); |
| 631 Node* is_js_function = | 631 Node* is_js_function = |
| 632 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); | 632 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); |
| 633 GotoUnless(is_js_function, &mark_megamorphic); | 633 GotoUnless(is_js_function, &mark_megamorphic); |
| 634 | 634 |
| 635 // Check if it is the Array() function. | 635 // Check if it is the Array() function. |
| 636 Node* context_slot = | 636 Node* context_slot = |
| 637 LoadFixedArrayElement(LoadNativeContext(context), | 637 LoadFixedArrayElement(LoadNativeContext(context), |
| 638 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); | 638 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); |
| 639 Node* is_array_function = WordEqual(context_slot, function); | 639 Node* is_array_function = WordEqual(context_slot, function); |
| 640 GotoIf(is_array_function, &create_allocation_site); | 640 GotoIf(is_array_function, &create_allocation_site); |
| 641 | 641 |
| 642 // Check if the function belongs to the same native context | 642 // Check if the function belongs to the same native context. |
| 643 Node* native_context = LoadNativeContext( | 643 Node* native_context = LoadNativeContext( |
| 644 LoadObjectField(function, JSFunction::kContextOffset)); | 644 LoadObjectField(function, JSFunction::kContextOffset)); |
| 645 Node* is_same_native_context = | 645 Node* is_same_native_context = |
| 646 WordEqual(native_context, LoadNativeContext(context)); | 646 WordEqual(native_context, LoadNativeContext(context)); |
| 647 GotoUnless(is_same_native_context, &mark_megamorphic); | 647 GotoUnless(is_same_native_context, &mark_megamorphic); |
| 648 | 648 |
| 649 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), | 649 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), |
| 650 function); | 650 function); |
| 651 | 651 |
| 652 // Call using call function builtin. | 652 // Call using call function builtin. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 671 // and will not move during a GC. So it is safe to skip write barrier. | 671 // and will not move during a GC. So it is safe to skip write barrier. |
| 672 DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); | 672 DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); |
| 673 StoreFixedArrayElement( | 673 StoreFixedArrayElement( |
| 674 type_feedback_vector, slot_id, | 674 type_feedback_vector, slot_id, |
| 675 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), | 675 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), |
| 676 SKIP_WRITE_BARRIER); | 676 SKIP_WRITE_BARRIER); |
| 677 Goto(&call); | 677 Goto(&call); |
| 678 } | 678 } |
| 679 } | 679 } |
| 680 | 680 |
| 681 Bind(&call_function); | |
| 682 { | |
| 683 // Increment the call count. | |
| 684 IncrementCallCount(type_feedback_vector, slot_id); | |
| 685 | |
| 686 Callable callable_call = CodeFactory::InterpreterPushArgsAndCall( | |
| 687 isolate(), tail_call_mode, CallableType::kJSFunction); | |
| 688 Node* code_target_call = HeapConstant(callable_call.code()); | |
| 689 Node* ret_value = CallStub(callable_call.descriptor(), code_target_call, | |
| 690 context, arg_count, first_arg, function); | |
| 691 return_value.Bind(ret_value); | |
| 692 Goto(&end); | |
| 693 } | |
| 694 | |
| 695 Bind(&call); | 681 Bind(&call); |
| 696 { | 682 { |
| 683 Comment("Increment call count and call using Call builtin"); |
| 697 // Increment the call count. | 684 // Increment the call count. |
| 698 IncrementCallCount(type_feedback_vector, slot_id); | 685 IncrementCallCount(type_feedback_vector, slot_id); |
| 699 | 686 |
| 700 // Call using call builtin. | 687 // Call using call builtin. |
| 701 Callable callable_call = CodeFactory::InterpreterPushArgsAndCall( | 688 Callable callable_call = CodeFactory::InterpreterPushArgsAndCall( |
| 702 isolate(), tail_call_mode, CallableType::kAny); | 689 isolate(), tail_call_mode, CallableType::kAny); |
| 703 Node* code_target_call = HeapConstant(callable_call.code()); | 690 Node* code_target_call = HeapConstant(callable_call.code()); |
| 704 Node* ret_value = CallStub(callable_call.descriptor(), code_target_call, | 691 Node* ret_value = CallStub(callable_call.descriptor(), code_target_call, |
| 705 context, arg_count, first_arg, function); | 692 context, arg_count, first_arg, function); |
| 706 return_value.Bind(ret_value); | 693 return_value.Bind(ret_value); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 718 isolate(), tail_call_mode, CallableType::kAny); | 705 isolate(), tail_call_mode, CallableType::kAny); |
| 719 Node* code_target = HeapConstant(callable.code()); | 706 Node* code_target = HeapConstant(callable.code()); |
| 720 return CallStub(callable.descriptor(), code_target, context, arg_count, | 707 return CallStub(callable.descriptor(), code_target, context, arg_count, |
| 721 first_arg, function); | 708 first_arg, function); |
| 722 } | 709 } |
| 723 | 710 |
| 724 Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context, | 711 Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context, |
| 725 Node* new_target, Node* first_arg, | 712 Node* new_target, Node* first_arg, |
| 726 Node* arg_count, Node* slot_id, | 713 Node* arg_count, Node* slot_id, |
| 727 Node* type_feedback_vector) { | 714 Node* type_feedback_vector) { |
| 728 Label call_construct(this), js_function(this), end(this); | |
| 729 Variable return_value(this, MachineRepresentation::kTagged); | 715 Variable return_value(this, MachineRepresentation::kTagged); |
| 730 Variable allocation_feedback(this, MachineRepresentation::kTagged); | 716 Variable allocation_feedback(this, MachineRepresentation::kTagged); |
| 731 allocation_feedback.Bind(UndefinedConstant()); | 717 Label call_construct_function(this, &allocation_feedback), |
| 718 extra_checks(this, Label::kDeferred), call_construct(this), end(this); |
| 732 | 719 |
| 733 // Slot id of 0 is used to indicate no type feedback is available. | 720 // Slot id of 0 is used to indicate no type feedback is available. |
| 734 STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); | 721 STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); |
| 735 Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0)); | 722 Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0)); |
| 736 GotoIf(is_feedback_unavailable, &call_construct); | 723 GotoIf(is_feedback_unavailable, &call_construct); |
| 737 | 724 |
| 738 // Check that the constructor is not a smi. | 725 // Check that the constructor is not a smi. |
| 739 Node* is_smi = TaggedIsSmi(constructor); | 726 Node* is_smi = TaggedIsSmi(constructor); |
| 740 GotoIf(is_smi, &call_construct); | 727 GotoIf(is_smi, &call_construct); |
| 741 | 728 |
| 742 // Check that constructor is a JSFunction. | 729 // Check that constructor is a JSFunction. |
| 743 Node* instance_type = LoadInstanceType(constructor); | 730 Node* instance_type = LoadInstanceType(constructor); |
| 744 Node* is_js_function = | 731 Node* is_js_function = |
| 745 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); | 732 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); |
| 746 Branch(is_js_function, &js_function, &call_construct); | 733 GotoUnless(is_js_function, &call_construct); |
| 747 | 734 |
| 748 Bind(&js_function); | 735 // Check if it is a monomorphic constructor. |
| 736 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); |
| 737 Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element); |
| 738 Node* is_monomorphic = WordEqual(constructor, feedback_value); |
| 739 allocation_feedback.Bind(UndefinedConstant()); |
| 740 Branch(is_monomorphic, &call_construct_function, &extra_checks); |
| 741 |
| 742 Bind(&call_construct_function); |
| 749 { | 743 { |
| 750 // Cache the called function in a feedback vector slot. Cache states | 744 Comment("call using callConstructFunction"); |
| 751 // are uninitialized, monomorphic (indicated by a JSFunction), and | 745 IncrementCallCount(type_feedback_vector, slot_id); |
| 752 // megamorphic. | 746 Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct( |
| 753 // TODO(mythria/v8:5210): Check if it is better to mark extra_checks as a | 747 isolate(), CallableType::kJSFunction); |
| 754 // deferred block so that call_construct_function will be scheduled. | 748 return_value.Bind(CallStub(callable_function.descriptor(), |
| 755 Label extra_checks(this), call_construct_function(this); | 749 HeapConstant(callable_function.code()), context, |
| 750 arg_count, new_target, constructor, |
| 751 allocation_feedback.value(), first_arg)); |
| 752 Goto(&end); |
| 753 } |
| 756 | 754 |
| 757 Node* feedback_element = | 755 Bind(&extra_checks); |
| 758 LoadFixedArrayElement(type_feedback_vector, slot_id); | 756 { |
| 759 Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element); | 757 Label check_allocation_site(this), check_initialized(this), |
| 760 Node* is_monomorphic = WordEqual(constructor, feedback_value); | 758 initialize(this), mark_megamorphic(this); |
| 761 Branch(is_monomorphic, &call_construct_function, &extra_checks); | |
| 762 | 759 |
| 763 Bind(&extra_checks); | 760 // Check if it is a megamorphic target. |
| 761 Comment("check if megamorphic"); |
| 762 Node* is_megamorphic = WordEqual( |
| 763 feedback_element, |
| 764 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); |
| 765 GotoIf(is_megamorphic, &call_construct_function); |
| 766 |
| 767 Comment("check if weak cell"); |
| 768 Node* is_weak_cell = WordEqual(LoadMap(feedback_element), |
| 769 LoadRoot(Heap::kWeakCellMapRootIndex)); |
| 770 GotoUnless(is_weak_cell, &check_allocation_site); |
| 771 |
| 772 // If the weak cell is cleared, we have a new chance to become |
| 773 // monomorphic. |
| 774 Comment("check if weak cell is cleared"); |
| 775 Node* is_smi = TaggedIsSmi(feedback_value); |
| 776 Branch(is_smi, &initialize, &mark_megamorphic); |
| 777 |
| 778 Bind(&check_allocation_site); |
| 764 { | 779 { |
| 765 Label mark_megamorphic(this), initialize(this), | 780 Comment("check if it is an allocation site"); |
| 766 check_allocation_site(this), check_initialized(this), | 781 Node* is_allocation_site = |
| 767 set_alloc_feedback_and_call(this); | 782 WordEqual(LoadObjectField(feedback_element, 0), |
| 783 LoadRoot(Heap::kAllocationSiteMapRootIndex)); |
| 784 GotoUnless(is_allocation_site, &check_initialized); |
| 785 |
| 786 // Make sure the function is the Array() function. |
| 787 Node* context_slot = |
| 788 LoadFixedArrayElement(LoadNativeContext(context), |
| 789 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); |
| 790 Node* is_array_function = WordEqual(context_slot, constructor); |
| 791 GotoUnless(is_array_function, &mark_megamorphic); |
| 792 |
| 793 allocation_feedback.Bind(feedback_element); |
| 794 Goto(&call_construct_function); |
| 795 } |
| 796 |
| 797 Bind(&check_initialized); |
| 798 { |
| 799 // Check if it is uninitialized. |
| 800 Comment("check if uninitialized"); |
| 801 Node* is_uninitialized = WordEqual( |
| 802 feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex)); |
| 803 Branch(is_uninitialized, &initialize, &mark_megamorphic); |
| 804 } |
| 805 |
| 806 Bind(&initialize); |
| 807 { |
| 808 Label create_allocation_site(this), create_weak_cell(this); |
| 809 Comment("initialize the feedback element"); |
| 810 // Create an allocation site if the function is an array function, |
| 811 // otherwise create a weak cell. |
| 812 Node* context_slot = |
| 813 LoadFixedArrayElement(LoadNativeContext(context), |
| 814 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); |
| 815 Node* is_array_function = WordEqual(context_slot, constructor); |
| 816 Branch(is_array_function, &create_allocation_site, &create_weak_cell); |
| 817 |
| 818 Bind(&create_allocation_site); |
| 768 { | 819 { |
| 769 // Check if it is a megamorphic target | 820 Node* site = CreateAllocationSiteInFeedbackVector(type_feedback_vector, |
| 770 Comment("check if megamorphic"); | 821 SmiTag(slot_id)); |
| 771 Node* is_megamorphic = WordEqual( | 822 allocation_feedback.Bind(site); |
| 772 feedback_element, | |
| 773 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); | |
| 774 GotoIf(is_megamorphic, &call_construct_function); | |
| 775 | |
| 776 Comment("check if weak cell"); | |
| 777 Node* is_weak_cell = WordEqual(LoadMap(feedback_element), | |
| 778 LoadRoot(Heap::kWeakCellMapRootIndex)); | |
| 779 GotoUnless(is_weak_cell, &check_allocation_site); | |
| 780 // If the weak cell is cleared, we have a new chance to become | |
| 781 // monomorphic. | |
| 782 Comment("check if weak cell is cleared"); | |
| 783 Node* is_smi = TaggedIsSmi(feedback_value); | |
| 784 Branch(is_smi, &initialize, &mark_megamorphic); | |
| 785 } | |
| 786 | |
| 787 Bind(&check_allocation_site); | |
| 788 { | |
| 789 Comment("check if it is an allocation site"); | |
| 790 Node* is_allocation_site = | |
| 791 WordEqual(LoadObjectField(feedback_element, 0), | |
| 792 LoadRoot(Heap::kAllocationSiteMapRootIndex)); | |
| 793 GotoUnless(is_allocation_site, &check_initialized); | |
| 794 | |
| 795 // Make sure the function is the Array() function | |
| 796 Node* context_slot = | |
| 797 LoadFixedArrayElement(LoadNativeContext(context), | |
| 798 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); | |
| 799 Node* is_array_function = WordEqual(context_slot, constructor); | |
| 800 Branch(is_array_function, &set_alloc_feedback_and_call, | |
| 801 &mark_megamorphic); | |
| 802 } | |
| 803 | |
| 804 Bind(&set_alloc_feedback_and_call); | |
| 805 { | |
| 806 allocation_feedback.Bind(feedback_element); | |
| 807 Goto(&call_construct_function); | 823 Goto(&call_construct_function); |
| 808 } | 824 } |
| 809 | 825 |
| 810 Bind(&check_initialized); | 826 Bind(&create_weak_cell); |
| 811 { | 827 { |
| 812 // Check if it is uninitialized. | 828 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), |
| 813 Comment("check if uninitialized"); | 829 constructor); |
| 814 Node* is_uninitialized = WordEqual( | |
| 815 feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex)); | |
| 816 Branch(is_uninitialized, &initialize, &mark_megamorphic); | |
| 817 } | |
| 818 | |
| 819 Bind(&initialize); | |
| 820 { | |
| 821 Label create_weak_cell(this), create_allocation_site(this); | |
| 822 Comment("initialize the feedback element"); | |
| 823 // Check that it is the Array() function. | |
| 824 Node* context_slot = | |
| 825 LoadFixedArrayElement(LoadNativeContext(context), | |
| 826 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); | |
| 827 Node* is_array_function = WordEqual(context_slot, constructor); | |
| 828 Branch(is_array_function, &create_allocation_site, &create_weak_cell); | |
| 829 | |
| 830 Bind(&create_allocation_site); | |
| 831 { | |
| 832 Node* site = CreateAllocationSiteInFeedbackVector( | |
| 833 type_feedback_vector, SmiTag(slot_id)); | |
| 834 allocation_feedback.Bind(site); | |
| 835 Goto(&call_construct_function); | |
| 836 } | |
| 837 | |
| 838 Bind(&create_weak_cell); | |
| 839 { | |
| 840 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), | |
| 841 constructor); | |
| 842 Goto(&call_construct_function); | |
| 843 } | |
| 844 } | |
| 845 | |
| 846 Bind(&mark_megamorphic); | |
| 847 { | |
| 848 // MegamorphicSentinel is an immortal immovable object so | |
| 849 // write-barrier is not needed. | |
| 850 Comment("transition to megamorphic"); | |
| 851 DCHECK( | |
| 852 Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); | |
| 853 StoreFixedArrayElement( | |
| 854 type_feedback_vector, slot_id, | |
| 855 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), | |
| 856 SKIP_WRITE_BARRIER); | |
| 857 Goto(&call_construct_function); | 830 Goto(&call_construct_function); |
| 858 } | 831 } |
| 859 } | 832 } |
| 860 | 833 |
| 861 Bind(&call_construct_function); | 834 Bind(&mark_megamorphic); |
| 862 { | 835 { |
| 863 Comment("call using callConstructFunction"); | 836 // MegamorphicSentinel is an immortal immovable object so |
| 864 IncrementCallCount(type_feedback_vector, slot_id); | 837 // write-barrier is not needed. |
| 865 Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct( | 838 Comment("transition to megamorphic"); |
| 866 isolate(), CallableType::kJSFunction); | 839 DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); |
| 867 return_value.Bind(CallStub(callable_function.descriptor(), | 840 StoreFixedArrayElement( |
| 868 HeapConstant(callable_function.code()), | 841 type_feedback_vector, slot_id, |
| 869 context, arg_count, new_target, constructor, | 842 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), |
| 870 allocation_feedback.value(), first_arg)); | 843 SKIP_WRITE_BARRIER); |
| 871 Goto(&end); | 844 Goto(&call_construct_function); |
| 872 } | 845 } |
| 873 } | 846 } |
| 874 | 847 |
| 875 Bind(&call_construct); | 848 Bind(&call_construct); |
| 876 { | 849 { |
| 877 Comment("call using callConstruct builtin"); | 850 Comment("call using callConstruct builtin"); |
| 878 Callable callable = CodeFactory::InterpreterPushArgsAndConstruct( | 851 Callable callable = CodeFactory::InterpreterPushArgsAndConstruct( |
| 879 isolate(), CallableType::kAny); | 852 isolate(), CallableType::kAny); |
| 880 Node* code_target = HeapConstant(callable.code()); | 853 Node* code_target = HeapConstant(callable.code()); |
| 881 return_value.Bind(CallStub(callable.descriptor(), code_target, context, | 854 return_value.Bind(CallStub(callable.descriptor(), code_target, context, |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1358 Goto(&loop); | 1331 Goto(&loop); |
| 1359 } | 1332 } |
| 1360 Bind(&done_loop); | 1333 Bind(&done_loop); |
| 1361 | 1334 |
| 1362 return array; | 1335 return array; |
| 1363 } | 1336 } |
| 1364 | 1337 |
| 1365 } // namespace interpreter | 1338 } // namespace interpreter |
| 1366 } // namespace internal | 1339 } // namespace internal |
| 1367 } // namespace v8 | 1340 } // namespace v8 |
| OLD | NEW |