| 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 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 Node* stack_pointer_after_call = LoadStackPointer(); | 485 Node* stack_pointer_after_call = LoadStackPointer(); |
| 486 Node* stack_pointer_before_call = stack_pointer_before_call_; | 486 Node* stack_pointer_before_call = stack_pointer_before_call_; |
| 487 stack_pointer_before_call_ = nullptr; | 487 stack_pointer_before_call_ = nullptr; |
| 488 AbortIfWordNotEqual(stack_pointer_before_call, stack_pointer_after_call, | 488 AbortIfWordNotEqual(stack_pointer_before_call, stack_pointer_after_call, |
| 489 kUnexpectedStackPointer); | 489 kUnexpectedStackPointer); |
| 490 } | 490 } |
| 491 } | 491 } |
| 492 | 492 |
| 493 Node* InterpreterAssembler::IncrementCallCount(Node* type_feedback_vector, | 493 Node* InterpreterAssembler::IncrementCallCount(Node* type_feedback_vector, |
| 494 Node* slot_id) { | 494 Node* slot_id) { |
| 495 Comment("increment call count"); |
| 495 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1)); | 496 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1)); |
| 496 Node* call_count = | 497 Node* call_count = |
| 497 LoadFixedArrayElement(type_feedback_vector, call_count_slot); | 498 LoadFixedArrayElement(type_feedback_vector, call_count_slot); |
| 498 Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1))); | 499 Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1))); |
| 499 // Count is Smi, so we don't need a write barrier. | 500 // Count is Smi, so we don't need a write barrier. |
| 500 return StoreFixedArrayElement(type_feedback_vector, call_count_slot, | 501 return StoreFixedArrayElement(type_feedback_vector, call_count_slot, |
| 501 new_count, SKIP_WRITE_BARRIER); | 502 new_count, SKIP_WRITE_BARRIER); |
| 502 } | 503 } |
| 503 | 504 |
| 504 Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context, | 505 Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context, |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 Node* is_js_function = | 742 Node* is_js_function = |
| 742 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); | 743 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); |
| 743 BranchIf(is_js_function, &js_function, &call_construct); | 744 BranchIf(is_js_function, &js_function, &call_construct); |
| 744 | 745 |
| 745 Bind(&js_function); | 746 Bind(&js_function); |
| 746 { | 747 { |
| 747 // Cache the called function in a feedback vector slot. Cache states | 748 // Cache the called function in a feedback vector slot. Cache states |
| 748 // are uninitialized, monomorphic (indicated by a JSFunction), and | 749 // are uninitialized, monomorphic (indicated by a JSFunction), and |
| 749 // megamorphic. | 750 // megamorphic. |
| 750 // TODO(mythria/v8:5210): Check if it is better to mark extra_checks as a | 751 // TODO(mythria/v8:5210): Check if it is better to mark extra_checks as a |
| 751 // deferred block so that call_construct_function will be scheduled just | 752 // deferred block so that call_construct_function will be scheduled. |
| 752 // after increment_count and in the fast path we can reduce one branch in | 753 Label extra_checks(this), call_construct_function(this); |
| 753 // the | |
| 754 // fast path. | |
| 755 Label increment_count(this), extra_checks(this), | |
| 756 call_construct_function(this); | |
| 757 | 754 |
| 758 Node* feedback_element = | 755 Node* feedback_element = |
| 759 LoadFixedArrayElement(type_feedback_vector, slot_id); | 756 LoadFixedArrayElement(type_feedback_vector, slot_id); |
| 760 Node* feedback_value = LoadWeakCellValue(feedback_element); | 757 Node* feedback_value = LoadWeakCellValue(feedback_element); |
| 761 Node* is_monomorphic = WordEqual(constructor, feedback_value); | 758 Node* is_monomorphic = WordEqual(constructor, feedback_value); |
| 762 BranchIf(is_monomorphic, &increment_count, &extra_checks); | 759 BranchIf(is_monomorphic, &call_construct_function, &extra_checks); |
| 763 | 760 |
| 764 Bind(&extra_checks); | 761 Bind(&extra_checks); |
| 765 { | 762 { |
| 766 Label mark_megamorphic(this), initialize(this), | 763 Label mark_megamorphic(this), initialize(this), |
| 767 check_allocation_site(this), check_initialized(this), | 764 check_allocation_site(this), check_initialized(this), |
| 768 set_alloc_feedback_and_inc_count(this); | 765 set_alloc_feedback_and_call(this); |
| 769 { | 766 { |
| 770 // Check if it is a megamorphic target | 767 // Check if it is a megamorphic target |
| 771 Comment("check if megamorphic"); | 768 Comment("check if megamorphic"); |
| 772 Node* is_megamorphic = WordEqual( | 769 Node* is_megamorphic = WordEqual( |
| 773 feedback_element, | 770 feedback_element, |
| 774 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); | 771 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); |
| 775 GotoIf(is_megamorphic, &call_construct_function); | 772 GotoIf(is_megamorphic, &call_construct_function); |
| 776 | 773 |
| 777 Comment("check if weak cell"); | 774 Comment("check if weak cell"); |
| 778 Node* is_weak_cell = WordEqual(LoadMap(feedback_element), | 775 Node* is_weak_cell = WordEqual(LoadMap(feedback_element), |
| (...skipping 12 matching lines...) Expand all Loading... |
| 791 Node* is_allocation_site = | 788 Node* is_allocation_site = |
| 792 WordEqual(LoadObjectField(feedback_element, 0), | 789 WordEqual(LoadObjectField(feedback_element, 0), |
| 793 LoadRoot(Heap::kAllocationSiteMapRootIndex)); | 790 LoadRoot(Heap::kAllocationSiteMapRootIndex)); |
| 794 GotoUnless(is_allocation_site, &check_initialized); | 791 GotoUnless(is_allocation_site, &check_initialized); |
| 795 | 792 |
| 796 // Make sure the function is the Array() function | 793 // Make sure the function is the Array() function |
| 797 Node* context_slot = | 794 Node* context_slot = |
| 798 LoadFixedArrayElement(LoadNativeContext(context), | 795 LoadFixedArrayElement(LoadNativeContext(context), |
| 799 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); | 796 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); |
| 800 Node* is_array_function = WordEqual(context_slot, constructor); | 797 Node* is_array_function = WordEqual(context_slot, constructor); |
| 801 BranchIf(is_array_function, &set_alloc_feedback_and_inc_count, | 798 BranchIf(is_array_function, &set_alloc_feedback_and_call, |
| 802 &mark_megamorphic); | 799 &mark_megamorphic); |
| 803 } | 800 } |
| 804 | 801 |
| 805 Bind(&set_alloc_feedback_and_inc_count); | 802 Bind(&set_alloc_feedback_and_call); |
| 806 { | 803 { |
| 807 allocation_feedback.Bind(feedback_element); | 804 allocation_feedback.Bind(feedback_element); |
| 808 Goto(&increment_count); | 805 Goto(&call_construct_function); |
| 809 } | 806 } |
| 810 | 807 |
| 811 Bind(&check_initialized); | 808 Bind(&check_initialized); |
| 812 { | 809 { |
| 813 // Check if it is uninitialized. | 810 // Check if it is uninitialized. |
| 814 Comment("check if uninitialized"); | 811 Comment("check if uninitialized"); |
| 815 Node* is_uninitialized = WordEqual( | 812 Node* is_uninitialized = WordEqual( |
| 816 feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex)); | 813 feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex)); |
| 817 BranchIf(is_uninitialized, &initialize, &mark_megamorphic); | 814 BranchIf(is_uninitialized, &initialize, &mark_megamorphic); |
| 818 } | 815 } |
| 819 | 816 |
| 820 Bind(&initialize); | 817 Bind(&initialize); |
| 821 { | 818 { |
| 822 Label initialize_count(this), create_weak_cell(this), | 819 Label create_weak_cell(this), create_allocation_site(this); |
| 823 create_allocation_site(this); | |
| 824 Comment("initialize the feedback element"); | 820 Comment("initialize the feedback element"); |
| 825 // Check that it is the Array() function. | 821 // Check that it is the Array() function. |
| 826 Node* context_slot = | 822 Node* context_slot = |
| 827 LoadFixedArrayElement(LoadNativeContext(context), | 823 LoadFixedArrayElement(LoadNativeContext(context), |
| 828 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); | 824 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); |
| 829 Node* is_array_function = WordEqual(context_slot, constructor); | 825 Node* is_array_function = WordEqual(context_slot, constructor); |
| 830 BranchIf(is_array_function, &create_allocation_site, &create_weak_cell); | 826 BranchIf(is_array_function, &create_allocation_site, &create_weak_cell); |
| 831 | 827 |
| 832 Bind(&create_allocation_site); | 828 Bind(&create_allocation_site); |
| 833 { | 829 { |
| 834 // TODO(mythria): Inline the creation of allocation site. | 830 // TODO(mythria): Inline the creation of allocation site. |
| 835 CreateAllocationSiteStub create_stub(isolate()); | 831 CreateAllocationSiteStub create_stub(isolate()); |
| 836 CallStub(create_stub.GetCallInterfaceDescriptor(), | 832 CallStub(create_stub.GetCallInterfaceDescriptor(), |
| 837 HeapConstant(create_stub.GetCode()), context, | 833 HeapConstant(create_stub.GetCode()), context, |
| 838 type_feedback_vector, SmiTag(slot_id)); | 834 type_feedback_vector, SmiTag(slot_id)); |
| 839 Node* feedback_element = | 835 Node* feedback_element = |
| 840 LoadFixedArrayElement(type_feedback_vector, slot_id); | 836 LoadFixedArrayElement(type_feedback_vector, slot_id); |
| 841 allocation_feedback.Bind(feedback_element); | 837 allocation_feedback.Bind(feedback_element); |
| 842 Goto(&initialize_count); | 838 Goto(&call_construct_function); |
| 843 } | 839 } |
| 844 | 840 |
| 845 Bind(&create_weak_cell); | 841 Bind(&create_weak_cell); |
| 846 { | 842 { |
| 847 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), | 843 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), |
| 848 constructor); | 844 constructor); |
| 849 Goto(&initialize_count); | |
| 850 } | |
| 851 | |
| 852 Bind(&initialize_count); | |
| 853 { | |
| 854 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1)); | |
| 855 // Count is Smi, so we don't need a write barrier. | |
| 856 StoreFixedArrayElement(type_feedback_vector, call_count_slot, | |
| 857 SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER); | |
| 858 Goto(&call_construct_function); | 845 Goto(&call_construct_function); |
| 859 } | 846 } |
| 860 } | 847 } |
| 861 | 848 |
| 862 Bind(&mark_megamorphic); | 849 Bind(&mark_megamorphic); |
| 863 { | 850 { |
| 864 // MegamorphicSentinel is an immortal immovable object so | 851 // MegamorphicSentinel is an immortal immovable object so |
| 865 // write-barrier is not needed. | 852 // write-barrier is not needed. |
| 866 Comment("transition to megamorphic"); | 853 Comment("transition to megamorphic"); |
| 867 DCHECK( | 854 DCHECK( |
| 868 Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); | 855 Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); |
| 869 StoreFixedArrayElement( | 856 StoreFixedArrayElement( |
| 870 type_feedback_vector, slot_id, | 857 type_feedback_vector, slot_id, |
| 871 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), | 858 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), |
| 872 SKIP_WRITE_BARRIER); | 859 SKIP_WRITE_BARRIER); |
| 873 Goto(&call_construct_function); | 860 Goto(&call_construct_function); |
| 874 } | 861 } |
| 875 } | 862 } |
| 876 | 863 |
| 877 Bind(&increment_count); | |
| 878 { | |
| 879 // Increment the call count. | |
| 880 Comment("increment call count"); | |
| 881 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1)); | |
| 882 Node* call_count = | |
| 883 LoadFixedArrayElement(type_feedback_vector, call_count_slot); | |
| 884 Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1))); | |
| 885 // Count is Smi, so we don't need a write barrier. | |
| 886 StoreFixedArrayElement(type_feedback_vector, call_count_slot, new_count, | |
| 887 SKIP_WRITE_BARRIER); | |
| 888 Goto(&call_construct_function); | |
| 889 } | |
| 890 | |
| 891 Bind(&call_construct_function); | 864 Bind(&call_construct_function); |
| 892 { | 865 { |
| 893 Comment("call using callConstructFunction"); | 866 Comment("call using callConstructFunction"); |
| 867 IncrementCallCount(type_feedback_vector, slot_id); |
| 894 Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct( | 868 Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct( |
| 895 isolate(), CallableType::kJSFunction); | 869 isolate(), CallableType::kJSFunction); |
| 896 return_value.Bind(CallStub(callable_function.descriptor(), | 870 return_value.Bind(CallStub(callable_function.descriptor(), |
| 897 HeapConstant(callable_function.code()), | 871 HeapConstant(callable_function.code()), |
| 898 context, arg_count, new_target, constructor, | 872 context, arg_count, new_target, constructor, |
| 899 allocation_feedback.value(), first_arg)); | 873 allocation_feedback.value(), first_arg)); |
| 900 Goto(&end); | 874 Goto(&end); |
| 901 } | 875 } |
| 902 } | 876 } |
| 903 | 877 |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1359 Goto(&loop); | 1333 Goto(&loop); |
| 1360 } | 1334 } |
| 1361 Bind(&done_loop); | 1335 Bind(&done_loop); |
| 1362 | 1336 |
| 1363 return array; | 1337 return array; |
| 1364 } | 1338 } |
| 1365 | 1339 |
| 1366 } // namespace interpreter | 1340 } // namespace interpreter |
| 1367 } // namespace internal | 1341 } // namespace internal |
| 1368 } // namespace v8 | 1342 } // namespace v8 |
| OLD | NEW |