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..f851b3875054a47afbbabf0466cd7479b3c486dd |
--- /dev/null |
+++ b/test/cctest/interpreter/test-source-positions.cc |
@@ -0,0 +1,253 @@ |
+// 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 { |
+ |
+struct BytecodeFrameInfo { |
+ explicit BytecodeFrameInfo(int locals_count = -1) |
+ : number_of_locals(locals_count) {} |
+ |
+ int number_of_locals; |
+}; |
+ |
+class OptimizedBytecodeSourcePositionTester final { |
+ public: |
+ explicit OptimizedBytecodeSourcePositionTester(Isolate* isolate) |
+ : isolate_(isolate) { |
+ optimization_flags_ = {&FLAG_ignition_peephole, &FLAG_ignition_reo}; |
+ SaveFlags(); |
+ } |
+ ~OptimizedBytecodeSourcePositionTester() { RestoreFlags(); } |
+ |
+ bool SourcePositionsMatch(const char* function_body, |
+ const char* function_decl_params = "", |
+ const char* function_args = ""); |
+ |
+ private: |
+ Handle<BytecodeArray> MakeBytecode(size_t optimization_flags, |
+ const char* function_body, |
+ const char* function_decl_params, |
+ const char* function_args, |
+ BytecodeFrameInfo* frame_info); |
+ static std::string MakeFunctionName(size_t flags); |
+ static std::string MakeScript(const char* function_name, |
+ const char* function_body, |
+ const char* function_decl_params, |
+ const char* function_args); |
+ |
+ void SetOptimizationFlags(size_t bitmask); |
+ void SaveFlags(); |
+ void RestoreFlags(); |
+ |
+ Isolate* isolate() const { return isolate_; } |
+ |
+ Isolate* isolate_; |
+ std::vector<bool*> optimization_flags_; |
+ std::vector<bool> saved_flags_; |
+}; |
+ |
+// static |
+std::string OptimizedBytecodeSourcePositionTester::MakeFunctionName( |
+ size_t flags) { |
+ std::ostringstream os; |
+ os << "test_function_" << flags; |
+ 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( |
+ size_t flags, const char* function_body, const char* function_decl_params, |
+ const char* function_args, BytecodeFrameInfo* frame_info) { |
+ std::string function_name = MakeFunctionName(flags); |
+ std::string script = MakeScript(function_name.c_str(), function_body, |
+ function_decl_params, function_args); |
+ SetOptimizationFlags(flags); |
+ CompileRun(script.c_str()); |
+ |
+ // Get number of locals and store in frame_info. |
+ 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)); |
+ frame_info->number_of_locals = |
+ function->shared()->scope_info()->StackSlotCount(); |
+ |
+ return handle(function->shared()->bytecode_array()); |
+} |
+ |
+void OptimizedBytecodeSourcePositionTester::SetOptimizationFlags( |
+ size_t bitmask) { |
rmcilroy
2016/06/07 09:46:11
Could we just have bools for each of the flags or
oth
2016/06/07 13:46:18
The intent was adding a new optimization stage wou
|
+ size_t bit = 1; |
+ for (size_t i = 0; i < optimization_flags_.size(); ++i) { |
+ *optimization_flags_[i] = bitmask & bit ? true : false; |
+ bit <<= 1; |
+ } |
+} |
+ |
+void OptimizedBytecodeSourcePositionTester::SaveFlags() { |
+ saved_flags_.resize(optimization_flags_.size()); |
+ for (size_t i = 0; i < optimization_flags_.size(); ++i) { |
+ saved_flags_[i] = *optimization_flags_[i]; |
+ } |
+} |
+ |
+void OptimizedBytecodeSourcePositionTester::RestoreFlags() { |
+ for (size_t i = 0; i < optimization_flags_.size(); ++i) { |
+ *optimization_flags_[i] = saved_flags_[i]; |
+ } |
+} |
+ |
+bool OptimizedBytecodeSourcePositionTester::SourcePositionsMatch( |
+ const char* function_body, const char* function_decl_params, |
+ const char* function_args) { |
+ BytecodeFrameInfo unoptimized_frame_info; |
+ Handle<BytecodeArray> unoptimized_bytecode = |
+ MakeBytecode(0, function_body, function_decl_params, function_args, |
+ &unoptimized_frame_info); |
+ size_t count = static_cast<size_t>(1u) << optimization_flags_.size(); |
+ for (size_t i = 1; i < count; ++i) { |
rmcilroy
2016/06/07 09:46:11
I'd prefer we had seperate tests for each optimiza
oth
2016/06/07 13:46:18
I'm not sure this scales. The code currently test
|
+ BytecodeFrameInfo optimized_frame_info; |
+ Handle<BytecodeArray> optimized_bytecode = |
+ MakeBytecode(i, function_body, function_decl_params, function_args, |
+ &optimized_frame_info); |
+ SourcePositionMatcher matcher(unoptimized_frame_info.number_of_locals); |
+ if (!matcher.Match(unoptimized_bytecode, optimized_bytecode)) { |
+ printf("Unoptimized:\n"); |
rmcilroy
2016/06/07 09:46:11
remove logging
oth
2016/06/07 13:46:18
Done.
|
+ unoptimized_bytecode->Print(); |
+ printf("Optimized:\n"); |
+ optimized_bytecode->Print(); |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
+ |
+class ScopedFlag { |
+ public: |
+ explicit ScopedFlag(bool* flag) : flag_(flag), saved_value_(flag) {} |
+ ~ScopedFlag() { *flag_ = saved_value_; } |
+ |
+ ScopedFlag& operator=(bool value) { |
+ *flag_ = value; |
+ return *this; |
+ } |
+ |
+ private: |
+ bool* flag_; |
+ bool saved_value_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ScopedFlag); |
+}; |
+ |
+TEST(SourcePositionsEquivalent) { |
+ HandleAndZoneScope handles; |
+ |
+ ScopedFlag always_opt_flag(&FLAG_always_opt); |
+ always_opt_flag = false; |
+ |
+ ScopedFlag ignition_flag(&FLAG_ignition); |
+ ignition_flag = true; |
rmcilroy
2016/06/07 09:46:11
nit - You could set these flags (and initialize th
oth
2016/06/07 13:46:18
Done.
|
+ |
+ // Ensure handler table is generated. |
+ handles.main_isolate()->interpreter()->Initialize(); |
+ |
+ const char* test_scripts[] = { |
+ "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"}; |
+ |
+ OptimizedBytecodeSourcePositionTester tester(handles.main_isolate()); |
+ for (size_t i = 0; i < arraysize(test_scripts); ++i) { |
+ CHECK(tester.SourcePositionsMatch(test_scripts[i])); |
+ } |
+} |
+ |
+} // namespace interpreter |
+} // namespace internal |
+} // namespace v8 |