| 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 |