Index: test/cctest/interpreter/test-source-positions.cc |
diff --git a/test/cctest/interpreter/test-source-positions.cc b/test/cctest/interpreter/test-source-positions.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..20bb4404d9cbb652c3cb934bd81a5851a6e132f7 |
--- /dev/null |
+++ b/test/cctest/interpreter/test-source-positions.cc |
@@ -0,0 +1,237 @@ |
+// Copyright 2015 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "src/v8.h" |
+ |
+#include "src/compiler/pipeline.h" |
+#include "src/handles.h" |
+#include "src/interpreter/bytecode-generator.h" |
+#include "src/interpreter/interpreter.h" |
+#include "src/isolate.h" |
+#include "src/parsing/parser.h" |
+#include "test/cctest/cctest.h" |
+#include "test/cctest/interpreter/source-position-matcher.h" |
+ |
+namespace v8 { |
+namespace internal { |
+namespace interpreter { |
+ |
+// Flags enabling optimizations that change generated bytecode array. |
+// Format is <command-line flag> <flag name> <bit index> |
+#define OPTIMIZATION_FLAGS(V) \ |
+ V(FLAG_ignition_reo, kUseReo, 0) \ |
+ V(FLAG_ignition_peephole, kUsePeephole, 1) |
+ |
+#define DECLARE_BIT(_, Name, BitIndex) static const int Name = 1 << BitIndex; |
+OPTIMIZATION_FLAGS(DECLARE_BIT) |
+#undef DECLARE_BIT |
+ |
+// Test cases source positions are checked for. Please ensure all |
+// combinations of flags are present here. This is done manually |
+// because it provides easier to comprehend failure case for humans. |
+#define TEST_CASES(V) \ |
+ V(UsingReo, kUseReo) \ |
+ V(UsingReoAndPeephole, kUseReo | kUsePeephole) \ |
+ V(UsingPeephole, kUsePeephole) |
+ |
+static const char* kTestScripts[] = { |
+ "var x = (y = 3) + (x = y); return x + y;", |
+ |
+ "var x = 55;\n" |
+ "var y = x + (x = 1) + (x = 2) + (x = 3);\n" |
+ "return y;", |
+ |
+ "var x = 10; return x >>> 3;", |
+ |
+ "var x = 0; return x || (1, 2, 3);", |
+ |
+ "return a || (a, b, a, b, c = 5, 3); ", |
+ |
+ "var a = 3; var b = 4; a = b; b = a; a = b; return a;", |
+ |
+ "var a = 1; return [[a, 2], [a + 2]];", |
+ |
+ "var a = 1; if (a || a < 0) { return 1; }", |
+ |
+ "var b;" |
+ "b = a.name;" |
+ "b = a.name;" |
+ "a.name = a;" |
+ "b = a.name;" |
+ "a.name = a;" |
+ "return b;", |
+ |
+ "var sum = 0;\n" |
+ "outer: {\n" |
+ " for (var x = 0; x < 10; ++x) {\n" |
+ " for (var y = 0; y < 3; ++y) {\n" |
+ " ++sum;\n" |
+ " if (x + y == 12) { break outer; }\n" |
+ " }\n" |
+ " }\n" |
+ "}\n" |
+ "return sum;\n", |
+ |
+ "var a = 1;" |
+ "switch (a) {" |
+ " case 1: return a * a + 1;" |
+ " case 1: break;" |
+ " case 2: return (a = 3) * a + (a = 4);" |
+ " case 3:" |
+ "}" |
+ "return a;", |
+ |
+ "for (var p of [0, 1, 2]) {}", |
+ |
+ "var x = { 'a': 1, 'b': 2 };" |
+ "for (x['a'] of [1,2,3]) { return x['a']; }", |
+ |
+ "while (x == 4) {\n" |
+ " var y = x + 1;\n" |
+ " if (y == 2) break;\n" |
+ " for (z['a'] of [0]) {\n" |
+ " x += (x *= 3) + y;" |
+ " }\n" |
+ "}\n", |
+ |
+ "function g(a, b) { return a.func(b + b, b); }\n" |
+ "g(new (function Obj() { this.func = function() { return; }})(), 1)\n"}; |
+ |
+class OptimizedBytecodeSourcePositionTester final { |
+ public: |
+ explicit OptimizedBytecodeSourcePositionTester(Isolate* isolate) |
+ : isolate_(isolate) { |
+ SaveOptimizationFlags(); |
+ saved_flag_ignition_ = FLAG_ignition; |
+ FLAG_ignition = true; |
+ saved_flag_always_opt_ = FLAG_always_opt; |
+ FLAG_always_opt = false; |
+ } |
+ |
+ ~OptimizedBytecodeSourcePositionTester() { |
+ RestoreOptimizationFlags(); |
+ FLAG_ignition = saved_flag_ignition_; |
+ FLAG_always_opt = saved_flag_always_opt_; |
+ } |
+ |
+ bool SourcePositionsMatch(int optimization_bitmap, const char* function_body, |
+ const char* function_decl_params = "", |
+ const char* function_args = ""); |
+ |
+ private: |
+ Handle<BytecodeArray> MakeBytecode(int optimization_bitmap, |
+ const char* function_body, |
+ const char* function_decl_params, |
+ const char* function_args); |
+ static std::string MakeFunctionName(int optimization_bitmap); |
+ static std::string MakeScript(const char* function_name, |
+ const char* function_body, |
+ const char* function_decl_params, |
+ const char* function_args); |
+ |
+ void SetOptimizationFlags(int optimization_bitmap); |
+ void SaveOptimizationFlags(); |
+ void RestoreOptimizationFlags(); |
+ |
+ Isolate* isolate() const { return isolate_; } |
+ |
+ Isolate* isolate_; |
+ int saved_optimization_bitmap_; |
+ bool saved_flag_ignition_; |
+ bool saved_flag_always_opt_; |
+}; |
+ |
+// static |
+std::string OptimizedBytecodeSourcePositionTester::MakeFunctionName( |
+ int optimization_bitmap) { |
+ std::ostringstream os; |
+ os << "test_function_" << optimization_bitmap; |
+ return os.str(); |
+} |
+ |
+// static |
+std::string OptimizedBytecodeSourcePositionTester::MakeScript( |
+ const char* function_name, const char* function_body, |
+ const char* function_decl_params, const char* function_args) { |
+ std::ostringstream os; |
+ os << "function " << function_name << "(" << function_decl_params << ") {"; |
+ os << function_body; |
+ os << "}"; |
+ os << function_name << "(" << function_args << ");"; |
+ return os.str(); |
+} |
+ |
+Handle<BytecodeArray> OptimizedBytecodeSourcePositionTester::MakeBytecode( |
+ int optimization_bitmap, const char* function_body, |
+ const char* function_decl_params, const char* function_args) { |
+ std::string function_name = MakeFunctionName(optimization_bitmap); |
+ std::string script = MakeScript(function_name.c_str(), function_body, |
+ function_decl_params, function_args); |
+ SetOptimizationFlags(optimization_bitmap); |
+ CompileRun(script.c_str()); |
+ |
+ Local<Function> api_function = |
+ Local<Function>::Cast(CcTest::global() |
+ ->Get(CcTest::isolate()->GetCurrentContext(), |
+ v8_str(function_name.c_str())) |
+ .ToLocalChecked()); |
+ Handle<JSFunction> function = |
+ Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function)); |
+ return handle(function->shared()->bytecode_array()); |
+} |
+ |
+void OptimizedBytecodeSourcePositionTester::SetOptimizationFlags( |
+ int optimization_bitmap) { |
+#define SET_FLAG(V8Flag, BitName, _) \ |
+ V8Flag = (optimization_bitmap & BitName) ? true : false; |
+ OPTIMIZATION_FLAGS(SET_FLAG) |
+#undef SET_FLAG |
+} |
+ |
+void OptimizedBytecodeSourcePositionTester::SaveOptimizationFlags() { |
+ saved_optimization_bitmap_ = 0; |
+#define SAVE_FLAG(V8Flag, BitName, _) \ |
+ if (V8Flag) saved_optimization_bitmap_ |= BitName; |
+#undef SET_FLAG |
+} |
+ |
+void OptimizedBytecodeSourcePositionTester::RestoreOptimizationFlags() { |
+ SetOptimizationFlags(saved_optimization_bitmap_); |
+} |
+ |
+bool OptimizedBytecodeSourcePositionTester::SourcePositionsMatch( |
+ int optimization_bitmap, const char* function_body, |
+ const char* function_decl_params, const char* function_args) { |
+ Handle<BytecodeArray> unoptimized_bytecode = |
+ MakeBytecode(0, function_body, function_decl_params, function_args); |
+ Handle<BytecodeArray> optimized_bytecode = MakeBytecode( |
+ optimization_bitmap, function_body, function_decl_params, function_args); |
+ SourcePositionMatcher matcher; |
+ if (!matcher.Match(unoptimized_bytecode, optimized_bytecode)) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+void TestSourcePositionsEquivalent(int optimization_bitmap) { |
+ HandleAndZoneScope handles; |
+ // Ensure handler table is generated. |
+ handles.main_isolate()->interpreter()->Initialize(); |
+ |
+ OptimizedBytecodeSourcePositionTester tester(handles.main_isolate()); |
+ for (auto test_script : kTestScripts) { |
+ CHECK(tester.SourcePositionsMatch(optimization_bitmap, test_script)); |
+ } |
+} |
+ |
+#define MAKE_TEST(Name, Bitmap) \ |
+ TEST(TestSourcePositionsEquivalent##Name) { \ |
+ TestSourcePositionsEquivalent(Bitmap); \ |
+ } |
+TEST_CASES(MAKE_TEST) |
+#undef MAKE_TEST |
+ |
+} // namespace interpreter |
+} // namespace internal |
+} // namespace v8 |