OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/v8.h" |
| 6 |
| 7 #include "src/compiler/pipeline.h" |
| 8 #include "src/handles.h" |
| 9 #include "src/interpreter/bytecode-generator.h" |
| 10 #include "src/interpreter/interpreter.h" |
| 11 #include "src/isolate.h" |
| 12 #include "src/parsing/parser.h" |
| 13 #include "test/cctest/cctest.h" |
| 14 #include "test/cctest/interpreter/source-position-matcher.h" |
| 15 |
| 16 namespace v8 { |
| 17 namespace internal { |
| 18 namespace interpreter { |
| 19 |
| 20 // Flags enabling optimizations that change generated bytecode array. |
| 21 // Format is <command-line flag> <flag name> <bit index> |
| 22 #define OPTIMIZATION_FLAGS(V) \ |
| 23 V(FLAG_ignition_reo, kUseReo, 0) \ |
| 24 V(FLAG_ignition_peephole, kUsePeephole, 1) |
| 25 |
| 26 #define DECLARE_BIT(_, Name, BitIndex) static const int Name = 1 << BitIndex; |
| 27 OPTIMIZATION_FLAGS(DECLARE_BIT) |
| 28 #undef DECLARE_BIT |
| 29 |
| 30 // Test cases source positions are checked for. Please ensure all |
| 31 // combinations of flags are present here. This is done manually |
| 32 // because it provides easier to comprehend failure case for humans. |
| 33 #define TEST_CASES(V) \ |
| 34 V(UsingReo, kUseReo) \ |
| 35 V(UsingReoAndPeephole, kUseReo | kUsePeephole) \ |
| 36 V(UsingPeephole, kUsePeephole) |
| 37 |
| 38 static const char* kTestScripts[] = { |
| 39 "var x = (y = 3) + (x = y); return x + y;", |
| 40 |
| 41 "var x = 55;\n" |
| 42 "var y = x + (x = 1) + (x = 2) + (x = 3);\n" |
| 43 "return y;", |
| 44 |
| 45 "var x = 10; return x >>> 3;", |
| 46 |
| 47 "var x = 0; return x || (1, 2, 3);", |
| 48 |
| 49 "return a || (a, b, a, b, c = 5, 3); ", |
| 50 |
| 51 "var a = 3; var b = 4; a = b; b = a; a = b; return a;", |
| 52 |
| 53 "var a = 1; return [[a, 2], [a + 2]];", |
| 54 |
| 55 "var a = 1; if (a || a < 0) { return 1; }", |
| 56 |
| 57 "var b;" |
| 58 "b = a.name;" |
| 59 "b = a.name;" |
| 60 "a.name = a;" |
| 61 "b = a.name;" |
| 62 "a.name = a;" |
| 63 "return b;", |
| 64 |
| 65 "var sum = 0;\n" |
| 66 "outer: {\n" |
| 67 " for (var x = 0; x < 10; ++x) {\n" |
| 68 " for (var y = 0; y < 3; ++y) {\n" |
| 69 " ++sum;\n" |
| 70 " if (x + y == 12) { break outer; }\n" |
| 71 " }\n" |
| 72 " }\n" |
| 73 "}\n" |
| 74 "return sum;\n", |
| 75 |
| 76 "var a = 1;" |
| 77 "switch (a) {" |
| 78 " case 1: return a * a + 1;" |
| 79 " case 1: break;" |
| 80 " case 2: return (a = 3) * a + (a = 4);" |
| 81 " case 3:" |
| 82 "}" |
| 83 "return a;", |
| 84 |
| 85 "for (var p of [0, 1, 2]) {}", |
| 86 |
| 87 "var x = { 'a': 1, 'b': 2 };" |
| 88 "for (x['a'] of [1,2,3]) { return x['a']; }", |
| 89 |
| 90 "while (x == 4) {\n" |
| 91 " var y = x + 1;\n" |
| 92 " if (y == 2) break;\n" |
| 93 " for (z['a'] of [0]) {\n" |
| 94 " x += (x *= 3) + y;" |
| 95 " }\n" |
| 96 "}\n", |
| 97 |
| 98 "function g(a, b) { return a.func(b + b, b); }\n" |
| 99 "g(new (function Obj() { this.func = function() { return; }})(), 1)\n"}; |
| 100 |
| 101 class OptimizedBytecodeSourcePositionTester final { |
| 102 public: |
| 103 explicit OptimizedBytecodeSourcePositionTester(Isolate* isolate) |
| 104 : isolate_(isolate) { |
| 105 SaveOptimizationFlags(); |
| 106 saved_flag_ignition_ = FLAG_ignition; |
| 107 FLAG_ignition = true; |
| 108 saved_flag_always_opt_ = FLAG_always_opt; |
| 109 FLAG_always_opt = false; |
| 110 } |
| 111 |
| 112 ~OptimizedBytecodeSourcePositionTester() { |
| 113 RestoreOptimizationFlags(); |
| 114 FLAG_ignition = saved_flag_ignition_; |
| 115 FLAG_always_opt = saved_flag_always_opt_; |
| 116 } |
| 117 |
| 118 bool SourcePositionsMatch(int optimization_bitmap, const char* function_body, |
| 119 const char* function_decl_params = "", |
| 120 const char* function_args = ""); |
| 121 |
| 122 private: |
| 123 Handle<BytecodeArray> MakeBytecode(int optimization_bitmap, |
| 124 const char* function_body, |
| 125 const char* function_decl_params, |
| 126 const char* function_args); |
| 127 static std::string MakeFunctionName(int optimization_bitmap); |
| 128 static std::string MakeScript(const char* function_name, |
| 129 const char* function_body, |
| 130 const char* function_decl_params, |
| 131 const char* function_args); |
| 132 |
| 133 void SetOptimizationFlags(int optimization_bitmap); |
| 134 void SaveOptimizationFlags(); |
| 135 void RestoreOptimizationFlags(); |
| 136 |
| 137 Isolate* isolate() const { return isolate_; } |
| 138 |
| 139 Isolate* isolate_; |
| 140 int saved_optimization_bitmap_; |
| 141 bool saved_flag_ignition_; |
| 142 bool saved_flag_always_opt_; |
| 143 }; |
| 144 |
| 145 // static |
| 146 std::string OptimizedBytecodeSourcePositionTester::MakeFunctionName( |
| 147 int optimization_bitmap) { |
| 148 std::ostringstream os; |
| 149 os << "test_function_" << optimization_bitmap; |
| 150 return os.str(); |
| 151 } |
| 152 |
| 153 // static |
| 154 std::string OptimizedBytecodeSourcePositionTester::MakeScript( |
| 155 const char* function_name, const char* function_body, |
| 156 const char* function_decl_params, const char* function_args) { |
| 157 std::ostringstream os; |
| 158 os << "function " << function_name << "(" << function_decl_params << ") {"; |
| 159 os << function_body; |
| 160 os << "}"; |
| 161 os << function_name << "(" << function_args << ");"; |
| 162 return os.str(); |
| 163 } |
| 164 |
| 165 Handle<BytecodeArray> OptimizedBytecodeSourcePositionTester::MakeBytecode( |
| 166 int optimization_bitmap, const char* function_body, |
| 167 const char* function_decl_params, const char* function_args) { |
| 168 std::string function_name = MakeFunctionName(optimization_bitmap); |
| 169 std::string script = MakeScript(function_name.c_str(), function_body, |
| 170 function_decl_params, function_args); |
| 171 SetOptimizationFlags(optimization_bitmap); |
| 172 CompileRun(script.c_str()); |
| 173 |
| 174 Local<Function> api_function = |
| 175 Local<Function>::Cast(CcTest::global() |
| 176 ->Get(CcTest::isolate()->GetCurrentContext(), |
| 177 v8_str(function_name.c_str())) |
| 178 .ToLocalChecked()); |
| 179 Handle<JSFunction> function = |
| 180 Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function)); |
| 181 return handle(function->shared()->bytecode_array()); |
| 182 } |
| 183 |
| 184 void OptimizedBytecodeSourcePositionTester::SetOptimizationFlags( |
| 185 int optimization_bitmap) { |
| 186 #define SET_FLAG(V8Flag, BitName, _) \ |
| 187 V8Flag = (optimization_bitmap & BitName) ? true : false; |
| 188 OPTIMIZATION_FLAGS(SET_FLAG) |
| 189 #undef SET_FLAG |
| 190 } |
| 191 |
| 192 void OptimizedBytecodeSourcePositionTester::SaveOptimizationFlags() { |
| 193 saved_optimization_bitmap_ = 0; |
| 194 #define SAVE_FLAG(V8Flag, BitName, _) \ |
| 195 if (V8Flag) saved_optimization_bitmap_ |= BitName; |
| 196 #undef SET_FLAG |
| 197 } |
| 198 |
| 199 void OptimizedBytecodeSourcePositionTester::RestoreOptimizationFlags() { |
| 200 SetOptimizationFlags(saved_optimization_bitmap_); |
| 201 } |
| 202 |
| 203 bool OptimizedBytecodeSourcePositionTester::SourcePositionsMatch( |
| 204 int optimization_bitmap, const char* function_body, |
| 205 const char* function_decl_params, const char* function_args) { |
| 206 Handle<BytecodeArray> unoptimized_bytecode = |
| 207 MakeBytecode(0, function_body, function_decl_params, function_args); |
| 208 Handle<BytecodeArray> optimized_bytecode = MakeBytecode( |
| 209 optimization_bitmap, function_body, function_decl_params, function_args); |
| 210 SourcePositionMatcher matcher; |
| 211 if (!matcher.Match(unoptimized_bytecode, optimized_bytecode)) { |
| 212 return false; |
| 213 } |
| 214 return true; |
| 215 } |
| 216 |
| 217 void TestSourcePositionsEquivalent(int optimization_bitmap) { |
| 218 HandleAndZoneScope handles; |
| 219 // Ensure handler table is generated. |
| 220 handles.main_isolate()->interpreter()->Initialize(); |
| 221 |
| 222 OptimizedBytecodeSourcePositionTester tester(handles.main_isolate()); |
| 223 for (auto test_script : kTestScripts) { |
| 224 CHECK(tester.SourcePositionsMatch(optimization_bitmap, test_script)); |
| 225 } |
| 226 } |
| 227 |
| 228 #define MAKE_TEST(Name, Bitmap) \ |
| 229 TEST(TestSourcePositionsEquivalent##Name) { \ |
| 230 TestSourcePositionsEquivalent(Bitmap); \ |
| 231 } |
| 232 TEST_CASES(MAKE_TEST) |
| 233 #undef MAKE_TEST |
| 234 |
| 235 } // namespace interpreter |
| 236 } // namespace internal |
| 237 } // namespace v8 |
OLD | NEW |