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