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/interpreter.h" | 10 #include "src/interpreter/interpreter.h" |
11 #include "test/cctest/cctest.h" | 11 #include "test/cctest/cctest.h" |
| 12 #include "test/cctest/interpreter/interpreter-tester.h" |
12 #include "test/cctest/test-feedback-vector.h" | 13 #include "test/cctest/test-feedback-vector.h" |
13 | 14 |
14 namespace v8 { | 15 namespace v8 { |
15 namespace internal { | 16 namespace internal { |
16 namespace interpreter { | 17 namespace interpreter { |
17 | 18 |
18 | 19 |
19 static MaybeHandle<Object> CallInterpreter(Isolate* isolate, | |
20 Handle<JSFunction> function) { | |
21 return Execution::Call(isolate, function, | |
22 isolate->factory()->undefined_value(), 0, nullptr); | |
23 } | |
24 | |
25 | |
26 template <class... A> | |
27 static MaybeHandle<Object> CallInterpreter(Isolate* isolate, | |
28 Handle<JSFunction> function, | |
29 A... args) { | |
30 Handle<Object> argv[] = { args... }; | |
31 return Execution::Call(isolate, function, | |
32 isolate->factory()->undefined_value(), sizeof...(args), | |
33 argv); | |
34 } | |
35 | |
36 | |
37 template <class... A> | |
38 class InterpreterCallable { | |
39 public: | |
40 InterpreterCallable(Isolate* isolate, Handle<JSFunction> function) | |
41 : isolate_(isolate), function_(function) {} | |
42 virtual ~InterpreterCallable() {} | |
43 | |
44 MaybeHandle<Object> operator()(A... args) { | |
45 return CallInterpreter(isolate_, function_, args...); | |
46 } | |
47 | |
48 private: | |
49 Isolate* isolate_; | |
50 Handle<JSFunction> function_; | |
51 }; | |
52 | |
53 | |
54 static const char* kFunctionName = "f"; | |
55 | |
56 | |
57 class InterpreterTester { | |
58 public: | |
59 InterpreterTester(Isolate* isolate, const char* source, | |
60 MaybeHandle<BytecodeArray> bytecode, | |
61 MaybeHandle<TypeFeedbackVector> feedback_vector, | |
62 const char* filter) | |
63 : isolate_(isolate), | |
64 source_(source), | |
65 bytecode_(bytecode), | |
66 feedback_vector_(feedback_vector) { | |
67 i::FLAG_ignition = true; | |
68 i::FLAG_always_opt = false; | |
69 // Set ignition filter flag via SetFlagsFromString to avoid double-free | |
70 // (or potential leak with StrDup() based on ownership confusion). | |
71 ScopedVector<char> ignition_filter(64); | |
72 SNPrintF(ignition_filter, "--ignition-filter=%s", filter); | |
73 FlagList::SetFlagsFromString(ignition_filter.start(), | |
74 ignition_filter.length()); | |
75 // Ensure handler table is generated. | |
76 isolate->interpreter()->Initialize(); | |
77 } | |
78 | |
79 InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode, | |
80 MaybeHandle<TypeFeedbackVector> feedback_vector = | |
81 MaybeHandle<TypeFeedbackVector>(), | |
82 const char* filter = kFunctionName) | |
83 : InterpreterTester(isolate, nullptr, bytecode, feedback_vector, filter) { | |
84 } | |
85 | |
86 | |
87 InterpreterTester(Isolate* isolate, const char* source, | |
88 const char* filter = kFunctionName) | |
89 : InterpreterTester(isolate, source, MaybeHandle<BytecodeArray>(), | |
90 MaybeHandle<TypeFeedbackVector>(), filter) {} | |
91 | |
92 virtual ~InterpreterTester() {} | |
93 | |
94 template <class... A> | |
95 InterpreterCallable<A...> GetCallable() { | |
96 return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>()); | |
97 } | |
98 | |
99 Local<Message> CheckThrowsReturnMessage() { | |
100 TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_)); | |
101 auto callable = GetCallable<>(); | |
102 MaybeHandle<Object> no_result = callable(); | |
103 CHECK(isolate_->has_pending_exception()); | |
104 CHECK(try_catch.HasCaught()); | |
105 CHECK(no_result.is_null()); | |
106 isolate_->OptionalRescheduleException(true); | |
107 CHECK(!try_catch.Message().IsEmpty()); | |
108 return try_catch.Message(); | |
109 } | |
110 | |
111 static Handle<Object> NewObject(const char* script) { | |
112 return v8::Utils::OpenHandle(*CompileRun(script)); | |
113 } | |
114 | |
115 static Handle<String> GetName(Isolate* isolate, const char* name) { | |
116 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(name); | |
117 return isolate->factory()->string_table()->LookupString(isolate, result); | |
118 } | |
119 | |
120 static std::string SourceForBody(const char* body) { | |
121 return "function " + function_name() + "() {\n" + std::string(body) + "\n}"; | |
122 } | |
123 | |
124 static std::string function_name() { | |
125 return std::string(kFunctionName); | |
126 } | |
127 | |
128 private: | |
129 Isolate* isolate_; | |
130 const char* source_; | |
131 MaybeHandle<BytecodeArray> bytecode_; | |
132 MaybeHandle<TypeFeedbackVector> feedback_vector_; | |
133 | |
134 template <class... A> | |
135 Handle<JSFunction> GetBytecodeFunction() { | |
136 Handle<JSFunction> function; | |
137 if (source_) { | |
138 CompileRun(source_); | |
139 v8::Local<v8::Context> context = | |
140 v8::Isolate::GetCurrent()->GetCurrentContext(); | |
141 Local<Function> api_function = | |
142 Local<Function>::Cast(CcTest::global() | |
143 ->Get(context, v8_str(kFunctionName)) | |
144 .ToLocalChecked()); | |
145 function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function)); | |
146 } else { | |
147 int arg_count = sizeof...(A); | |
148 std::string source("(function " + function_name() + "("); | |
149 for (int i = 0; i < arg_count; i++) { | |
150 source += i == 0 ? "a" : ", a"; | |
151 } | |
152 source += "){})"; | |
153 function = Handle<JSFunction>::cast(v8::Utils::OpenHandle( | |
154 *v8::Local<v8::Function>::Cast(CompileRun(source.c_str())))); | |
155 function->ReplaceCode( | |
156 *isolate_->builtins()->InterpreterEntryTrampoline()); | |
157 } | |
158 | |
159 if (!bytecode_.is_null()) { | |
160 function->shared()->set_function_data(*bytecode_.ToHandleChecked()); | |
161 } | |
162 if (!feedback_vector_.is_null()) { | |
163 function->shared()->set_feedback_vector( | |
164 *feedback_vector_.ToHandleChecked()); | |
165 } | |
166 return function; | |
167 } | |
168 | |
169 DISALLOW_COPY_AND_ASSIGN(InterpreterTester); | |
170 }; | |
171 | |
172 | |
173 TEST(InterpreterReturn) { | 20 TEST(InterpreterReturn) { |
174 HandleAndZoneScope handles; | 21 HandleAndZoneScope handles; |
175 Handle<Object> undefined_value = | 22 Handle<Object> undefined_value = |
176 handles.main_isolate()->factory()->undefined_value(); | 23 handles.main_isolate()->factory()->undefined_value(); |
177 | 24 |
178 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, | 25 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, |
179 0, 0); | 26 0, 0); |
180 builder.Return(); | 27 builder.Return(); |
181 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | 28 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
182 | 29 |
(...skipping 1449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1632 .Return(); | 1479 .Return(); |
1633 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | 1480 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
1634 | 1481 |
1635 InterpreterTester tester(handles.main_isolate(), bytecode_array); | 1482 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
1636 auto callable = tester.GetCallable<>(); | 1483 auto callable = tester.GetCallable<>(); |
1637 | 1484 |
1638 Handle<Object> return_val = callable().ToHandleChecked(); | 1485 Handle<Object> return_val = callable().ToHandleChecked(); |
1639 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55)); | 1486 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55)); |
1640 } | 1487 } |
1641 | 1488 |
| 1489 TEST(InterpreterInvokeIntrinsic) { |
| 1490 HandleAndZoneScope handles; |
| 1491 |
| 1492 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, |
| 1493 0, 2); |
| 1494 builder.LoadLiteral(Smi::FromInt(15)) |
| 1495 .StoreAccumulatorInRegister(Register(0)) |
| 1496 .CallRuntime(Runtime::kInlineIsArray, Register(0), 1) |
| 1497 .Return(); |
| 1498 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 1499 |
| 1500 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
| 1501 auto callable = tester.GetCallable<>(); |
| 1502 |
| 1503 Handle<Object> return_val = callable().ToHandleChecked(); |
| 1504 CHECK(return_val->IsBoolean()); |
| 1505 CHECK_EQ(return_val->BooleanValue(), false); |
| 1506 } |
1642 | 1507 |
1643 TEST(InterpreterFunctionLiteral) { | 1508 TEST(InterpreterFunctionLiteral) { |
1644 HandleAndZoneScope handles; | 1509 HandleAndZoneScope handles; |
1645 | 1510 |
1646 // Test calling a function literal. | 1511 // Test calling a function literal. |
1647 std::string source( | 1512 std::string source( |
1648 "function " + InterpreterTester::function_name() + "(a) {\n" | 1513 "function " + InterpreterTester::function_name() + "(a) {\n" |
1649 " return (function(x){ return x + 2; })(a);\n" | 1514 " return (function(x){ return x + 2; })(a);\n" |
1650 "}"); | 1515 "}"); |
1651 InterpreterTester tester(handles.main_isolate(), source.c_str()); | 1516 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
(...skipping 2588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4240 Handle<i::Object> return_value = callable().ToHandleChecked(); | 4105 Handle<i::Object> return_value = callable().ToHandleChecked(); |
4241 CHECK(return_value->SameValue(*const_decl[i].second)); | 4106 CHECK(return_value->SameValue(*const_decl[i].second)); |
4242 } | 4107 } |
4243 | 4108 |
4244 FLAG_legacy_const = old_flag_legacy_const; | 4109 FLAG_legacy_const = old_flag_legacy_const; |
4245 } | 4110 } |
4246 | 4111 |
4247 } // namespace interpreter | 4112 } // namespace interpreter |
4248 } // namespace internal | 4113 } // namespace internal |
4249 } // namespace v8 | 4114 } // namespace v8 |
OLD | NEW |