| 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/execution.h" | 7 #include "src/execution.h" |
| 8 #include "src/handles.h" | 8 #include "src/handles.h" |
| 9 #include "src/interpreter/bytecode-array-builder.h" | 9 #include "src/interpreter/bytecode-array-builder.h" |
| 10 #include "src/interpreter/bytecode-array-iterator.h" | 10 #include "src/interpreter/bytecode-array-iterator.h" |
| (...skipping 772 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999)); | 783 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999)); |
| 784 | 784 |
| 785 // Test transition to megamorphic IC. | 785 // Test transition to megamorphic IC. |
| 786 Handle<Object> object2 = | 786 Handle<Object> object2 = |
| 787 InterpreterTester::NewObject("({ val : 456, other : 123 })"); | 787 InterpreterTester::NewObject("({ val : 456, other : 123 })"); |
| 788 callable(object2).ToHandleChecked(); | 788 callable(object2).ToHandleChecked(); |
| 789 CHECK(Runtime::GetObjectProperty(isolate, object2, name).ToHandle(&result)); | 789 CHECK(Runtime::GetObjectProperty(isolate, object2, name).ToHandle(&result)); |
| 790 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999)); | 790 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999)); |
| 791 } | 791 } |
| 792 | 792 |
| 793 static void TestInterpreterCall(TailCallMode tail_call_mode) { | 793 static void TestInterpreterCall(TailCallMode tail_call_mode, |
| 794 bool has_feedback_slot) { |
| 794 HandleAndZoneScope handles; | 795 HandleAndZoneScope handles; |
| 795 i::Isolate* isolate = handles.main_isolate(); | 796 i::Isolate* isolate = handles.main_isolate(); |
| 796 i::Factory* factory = isolate->factory(); | 797 i::Factory* factory = isolate->factory(); |
| 797 i::Zone zone(isolate->allocator()); | 798 i::Zone zone(isolate->allocator()); |
| 798 | 799 |
| 799 i::FeedbackVectorSpec feedback_spec(&zone); | 800 i::FeedbackVectorSpec feedback_spec(&zone); |
| 800 i::FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot(); | 801 i::FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot(); |
| 802 i::FeedbackVectorSlot call_slot = feedback_spec.AddCallICSlot(); |
| 801 | 803 |
| 802 Handle<i::TypeFeedbackVector> vector = | 804 Handle<i::TypeFeedbackVector> vector = |
| 803 i::NewTypeFeedbackVector(isolate, &feedback_spec); | 805 i::NewTypeFeedbackVector(isolate, &feedback_spec); |
| 804 int slot_index = vector->GetIndex(slot); | 806 int slot_index = vector->GetIndex(slot); |
| 807 int call_slot_index = -1; |
| 808 if (has_feedback_slot) { |
| 809 call_slot_index = vector->GetIndex(call_slot); |
| 810 } |
| 805 | 811 |
| 806 Handle<i::String> name = factory->NewStringFromAsciiChecked("func"); | 812 Handle<i::String> name = factory->NewStringFromAsciiChecked("func"); |
| 807 name = factory->string_table()->LookupString(isolate, name); | 813 name = factory->string_table()->LookupString(isolate, name); |
| 808 | 814 |
| 809 // Check with no args. | 815 // Check with no args. |
| 810 { | 816 { |
| 811 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, | 817 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, |
| 812 0, 1); | 818 0, 1); |
| 813 | 819 |
| 814 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) | 820 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) |
| 815 .StoreAccumulatorInRegister(Register(0)) | 821 .StoreAccumulatorInRegister(Register(0)); |
| 816 .Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode) | 822 |
| 817 .Return(); | 823 if (has_feedback_slot) { |
| 824 builder.CallWithFeedback(Register(0), builder.Parameter(0), 1, |
| 825 call_slot_index, tail_call_mode); |
| 826 } else { |
| 827 builder.Call(Register(0), builder.Parameter(0), 1, tail_call_mode); |
| 828 } |
| 829 |
| 830 builder.Return(); |
| 818 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | 831 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 819 | 832 |
| 820 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector); | 833 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector); |
| 821 auto callable = tester.GetCallable<Handle<Object>>(); | 834 auto callable = tester.GetCallable<Handle<Object>>(); |
| 822 | 835 |
| 823 Handle<Object> object = InterpreterTester::NewObject( | 836 Handle<Object> object = InterpreterTester::NewObject( |
| 824 "new (function Obj() { this.func = function() { return 0x265; }})()"); | 837 "new (function Obj() { this.func = function() { return 0x265; }})()"); |
| 825 Handle<Object> return_val = callable(object).ToHandleChecked(); | 838 Handle<Object> return_val = callable(object).ToHandleChecked(); |
| 826 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x265)); | 839 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x265)); |
| 827 } | 840 } |
| 828 | 841 |
| 829 // Check that receiver is passed properly. | 842 // Check that receiver is passed properly. |
| 830 { | 843 { |
| 831 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, | 844 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, |
| 832 0, 1); | 845 0, 1); |
| 833 | 846 |
| 834 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) | 847 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) |
| 835 .StoreAccumulatorInRegister(Register(0)) | 848 .StoreAccumulatorInRegister(Register(0)); |
| 836 .Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode) | 849 if (has_feedback_slot) { |
| 837 .Return(); | 850 builder.CallWithFeedback(Register(0), builder.Parameter(0), 1, |
| 851 call_slot_index, tail_call_mode); |
| 852 } else { |
| 853 builder.Call(Register(0), builder.Parameter(0), 1, tail_call_mode); |
| 854 } |
| 855 builder.Return(); |
| 838 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | 856 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 839 | 857 |
| 840 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector); | 858 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector); |
| 841 auto callable = tester.GetCallable<Handle<Object>>(); | 859 auto callable = tester.GetCallable<Handle<Object>>(); |
| 842 | 860 |
| 843 Handle<Object> object = InterpreterTester::NewObject( | 861 Handle<Object> object = InterpreterTester::NewObject( |
| 844 "new (function Obj() {" | 862 "new (function Obj() {" |
| 845 " this.val = 1234;" | 863 " this.val = 1234;" |
| 846 " this.func = function() { return this.val; };" | 864 " this.func = function() { return this.val; };" |
| 847 "})()"); | 865 "})()"); |
| 848 Handle<Object> return_val = callable(object).ToHandleChecked(); | 866 Handle<Object> return_val = callable(object).ToHandleChecked(); |
| 849 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(1234)); | 867 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(1234)); |
| 850 } | 868 } |
| 851 | 869 |
| 852 // Check with two parameters (+ receiver). | 870 // Check with two parameters (+ receiver). |
| 853 { | 871 { |
| 854 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, | 872 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, |
| 855 0, 4); | 873 0, 4); |
| 856 | 874 |
| 857 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) | 875 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) |
| 858 .StoreAccumulatorInRegister(Register(0)) | 876 .StoreAccumulatorInRegister(Register(0)) |
| 859 .LoadAccumulatorWithRegister(builder.Parameter(0)) | 877 .LoadAccumulatorWithRegister(builder.Parameter(0)) |
| 860 .StoreAccumulatorInRegister(Register(1)) | 878 .StoreAccumulatorInRegister(Register(1)) |
| 861 .LoadLiteral(Smi::FromInt(51)) | 879 .LoadLiteral(Smi::FromInt(51)) |
| 862 .StoreAccumulatorInRegister(Register(2)) | 880 .StoreAccumulatorInRegister(Register(2)) |
| 863 .LoadLiteral(Smi::FromInt(11)) | 881 .LoadLiteral(Smi::FromInt(11)) |
| 864 .StoreAccumulatorInRegister(Register(3)) | 882 .StoreAccumulatorInRegister(Register(3)); |
| 865 .Call(Register(0), Register(1), 3, 0, tail_call_mode) | 883 |
| 866 .Return(); | 884 if (has_feedback_slot) { |
| 885 builder.CallWithFeedback(Register(0), Register(1), 3, call_slot_index, |
| 886 tail_call_mode); |
| 887 } else { |
| 888 builder.Call(Register(0), Register(1), 3, tail_call_mode); |
| 889 } |
| 890 |
| 891 builder.Return(); |
| 892 |
| 867 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | 893 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 868 | 894 |
| 869 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector); | 895 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector); |
| 870 auto callable = tester.GetCallable<Handle<Object>>(); | 896 auto callable = tester.GetCallable<Handle<Object>>(); |
| 871 | 897 |
| 872 Handle<Object> object = InterpreterTester::NewObject( | 898 Handle<Object> object = InterpreterTester::NewObject( |
| 873 "new (function Obj() { " | 899 "new (function Obj() { " |
| 874 " this.func = function(a, b) { return a - b; }" | 900 " this.func = function(a, b) { return a - b; }" |
| 875 "})()"); | 901 "})()"); |
| 876 Handle<Object> return_val = callable(object).ToHandleChecked(); | 902 Handle<Object> return_val = callable(object).ToHandleChecked(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 898 .StoreAccumulatorInRegister(Register(6)) | 924 .StoreAccumulatorInRegister(Register(6)) |
| 899 .LoadLiteral(factory->NewStringFromAsciiChecked("f")) | 925 .LoadLiteral(factory->NewStringFromAsciiChecked("f")) |
| 900 .StoreAccumulatorInRegister(Register(7)) | 926 .StoreAccumulatorInRegister(Register(7)) |
| 901 .LoadLiteral(factory->NewStringFromAsciiChecked("g")) | 927 .LoadLiteral(factory->NewStringFromAsciiChecked("g")) |
| 902 .StoreAccumulatorInRegister(Register(8)) | 928 .StoreAccumulatorInRegister(Register(8)) |
| 903 .LoadLiteral(factory->NewStringFromAsciiChecked("h")) | 929 .LoadLiteral(factory->NewStringFromAsciiChecked("h")) |
| 904 .StoreAccumulatorInRegister(Register(9)) | 930 .StoreAccumulatorInRegister(Register(9)) |
| 905 .LoadLiteral(factory->NewStringFromAsciiChecked("i")) | 931 .LoadLiteral(factory->NewStringFromAsciiChecked("i")) |
| 906 .StoreAccumulatorInRegister(Register(10)) | 932 .StoreAccumulatorInRegister(Register(10)) |
| 907 .LoadLiteral(factory->NewStringFromAsciiChecked("j")) | 933 .LoadLiteral(factory->NewStringFromAsciiChecked("j")) |
| 908 .StoreAccumulatorInRegister(Register(11)) | 934 .StoreAccumulatorInRegister(Register(11)); |
| 909 .Call(Register(0), Register(1), 11, 0, tail_call_mode) | 935 |
| 910 .Return(); | 936 if (has_feedback_slot) { |
| 937 builder.CallWithFeedback(Register(0), Register(1), 11, call_slot_index, |
| 938 tail_call_mode); |
| 939 } else { |
| 940 builder.Call(Register(0), Register(1), 11, tail_call_mode); |
| 941 } |
| 942 |
| 943 builder.Return(); |
| 944 |
| 911 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | 945 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 912 | 946 |
| 913 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector); | 947 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector); |
| 914 auto callable = tester.GetCallable<Handle<Object>>(); | 948 auto callable = tester.GetCallable<Handle<Object>>(); |
| 915 | 949 |
| 916 Handle<Object> object = InterpreterTester::NewObject( | 950 Handle<Object> object = InterpreterTester::NewObject( |
| 917 "new (function Obj() { " | 951 "new (function Obj() { " |
| 918 " this.prefix = \"prefix_\";" | 952 " this.prefix = \"prefix_\";" |
| 919 " this.func = function(a, b, c, d, e, f, g, h, i, j) {" | 953 " this.func = function(a, b, c, d, e, f, g, h, i, j) {" |
| 920 " return this.prefix + a + b + c + d + e + f + g + h + i + j;" | 954 " return this.prefix + a + b + c + d + e + f + g + h + i + j;" |
| 921 " }" | 955 " }" |
| 922 "})()"); | 956 "})()"); |
| 923 Handle<Object> return_val = callable(object).ToHandleChecked(); | 957 Handle<Object> return_val = callable(object).ToHandleChecked(); |
| 924 Handle<i::String> expected = | 958 Handle<i::String> expected = |
| 925 factory->NewStringFromAsciiChecked("prefix_abcdefghij"); | 959 factory->NewStringFromAsciiChecked("prefix_abcdefghij"); |
| 926 CHECK(i::String::cast(*return_val)->Equals(*expected)); | 960 CHECK(i::String::cast(*return_val)->Equals(*expected)); |
| 927 } | 961 } |
| 928 } | 962 } |
| 929 | 963 |
| 930 TEST(InterpreterCall) { TestInterpreterCall(TailCallMode::kDisallow); } | 964 TEST(InterpreterCall) { TestInterpreterCall(TailCallMode::kDisallow, false); } |
| 931 | 965 |
| 932 TEST(InterpreterTailCall) { TestInterpreterCall(TailCallMode::kAllow); } | 966 TEST(InterpreterTailCall) { TestInterpreterCall(TailCallMode::kAllow, false); } |
| 967 |
| 968 TEST(InterpreterCallWithFeedback) { |
| 969 TestInterpreterCall(TailCallMode::kDisallow, true); |
| 970 } |
| 971 |
| 972 TEST(InterpreterTailCallWithFeedback) { |
| 973 TestInterpreterCall(TailCallMode::kAllow, true); |
| 974 } |
| 933 | 975 |
| 934 static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder, | 976 static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder, |
| 935 Register reg, int value, | 977 Register reg, int value, |
| 936 Register scratch) { | 978 Register scratch) { |
| 937 return builder.StoreAccumulatorInRegister(scratch) | 979 return builder.StoreAccumulatorInRegister(scratch) |
| 938 .LoadLiteral(Smi::FromInt(value)) | 980 .LoadLiteral(Smi::FromInt(value)) |
| 939 .StoreAccumulatorInRegister(reg) | 981 .StoreAccumulatorInRegister(reg) |
| 940 .LoadAccumulatorWithRegister(scratch); | 982 .LoadAccumulatorWithRegister(scratch); |
| 941 } | 983 } |
| 942 | 984 |
| (...skipping 3251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4194 Handle<i::Object> return_value = callable().ToHandleChecked(); | 4236 Handle<i::Object> return_value = callable().ToHandleChecked(); |
| 4195 CHECK(return_value->SameValue(*tests[i].second)); | 4237 CHECK(return_value->SameValue(*tests[i].second)); |
| 4196 } | 4238 } |
| 4197 | 4239 |
| 4198 FLAG_ignition_generators = old_flag; | 4240 FLAG_ignition_generators = old_flag; |
| 4199 } | 4241 } |
| 4200 | 4242 |
| 4201 } // namespace interpreter | 4243 } // namespace interpreter |
| 4202 } // namespace internal | 4244 } // namespace internal |
| 4203 } // namespace v8 | 4245 } // namespace v8 |
| OLD | NEW |