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/bytecode-analysis.h" | |
8 #include "src/interpreter/bytecode-array-builder.h" | |
9 #include "src/interpreter/bytecode-array-iterator.h" | |
10 #include "src/interpreter/bytecode-decoder.h" | |
11 #include "src/interpreter/bytecode-label.h" | |
12 #include "src/interpreter/control-flow-builders.h" | |
13 #include "test/unittests/test-utils.h" | |
14 | |
15 namespace v8 { | |
16 namespace internal { | |
17 namespace compiler { | |
18 | |
19 class BytecodeAnalysisTest : public TestWithIsolateAndZone { | |
20 public: | |
21 BytecodeAnalysisTest() {} | |
22 ~BytecodeAnalysisTest() override {} | |
23 | |
24 static void SetUpTestCase() { | |
25 old_FLAG_ignition_peephole_ = i::FLAG_ignition_peephole; | |
26 i::FLAG_ignition_peephole = false; | |
27 | |
28 old_FLAG_ignition_reo_ = i::FLAG_ignition_reo; | |
29 i::FLAG_ignition_reo = false; | |
30 | |
31 TestWithIsolateAndZone::SetUpTestCase(); | |
32 } | |
33 | |
34 static void TearDownTestCase() { | |
35 TestWithIsolateAndZone::TearDownTestCase(); | |
36 i::FLAG_ignition_peephole = old_FLAG_ignition_peephole_; | |
37 i::FLAG_ignition_reo = old_FLAG_ignition_reo_; | |
38 } | |
39 | |
40 std::string ToLivenessString(const BitVector* liveness) const { | |
41 std::string out; | |
42 out.resize(liveness->length()); | |
43 for (int i = 0; i < liveness->length(); ++i) { | |
44 if (liveness->Contains(i)) { | |
45 out[i] = 'L'; | |
46 } else { | |
47 out[i] = '.'; | |
48 } | |
49 } | |
50 return out; | |
51 } | |
52 | |
53 void EnsureLivenessMatches( | |
54 Handle<BytecodeArray> bytecode, | |
55 const std::vector<std::pair<std::string, std::string>>& | |
56 expected_liveness) { | |
57 BytecodeAnalysis analysis(bytecode, zone(), true); | |
58 analysis.Analyze(); | |
59 | |
60 interpreter::BytecodeArrayIterator iterator(bytecode); | |
61 for (auto liveness : expected_liveness) { | |
62 std::stringstream ss; | |
63 ss << std::setw(4) << iterator.current_offset() << " : "; | |
64 iterator.PrintTo(ss); | |
65 | |
66 EXPECT_EQ(liveness.first, ToLivenessString(analysis.GetInLivenessFor( | |
67 iterator.current_offset()))) | |
68 << " at bytecode " << ss.str(); | |
69 | |
70 EXPECT_EQ(liveness.second, ToLivenessString(analysis.GetOutLivenessFor( | |
71 iterator.current_offset()))) | |
72 << " at bytecode " << ss.str(); | |
73 | |
74 iterator.Advance(); | |
75 } | |
76 | |
77 EXPECT_TRUE(iterator.done()); | |
78 } | |
79 | |
80 private: | |
81 static bool old_FLAG_ignition_peephole_; | |
82 static bool old_FLAG_ignition_reo_; | |
83 | |
84 DISALLOW_COPY_AND_ASSIGN(BytecodeAnalysisTest); | |
85 }; | |
86 | |
87 bool BytecodeAnalysisTest::old_FLAG_ignition_peephole_; | |
88 bool BytecodeAnalysisTest::old_FLAG_ignition_reo_; | |
89 | |
90 TEST_F(BytecodeAnalysisTest, EmptyBlock) { | |
91 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
92 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
93 | |
94 interpreter::Register reg_0(0); | |
95 | |
96 builder.Return(); | |
97 expected_liveness.emplace_back("...L", "...."); | |
98 | |
99 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
100 | |
101 EnsureLivenessMatches(bytecode, expected_liveness); | |
102 } | |
103 | |
104 TEST_F(BytecodeAnalysisTest, SimpleLoad) { | |
105 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
106 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
107 | |
108 interpreter::Register reg_0(0); | |
109 | |
110 builder.LoadAccumulatorWithRegister(reg_0); | |
111 expected_liveness.emplace_back("L...", "...L"); | |
112 | |
113 builder.Return(); | |
114 expected_liveness.emplace_back("...L", "...."); | |
115 | |
116 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
117 | |
118 EnsureLivenessMatches(bytecode, expected_liveness); | |
119 } | |
120 | |
121 TEST_F(BytecodeAnalysisTest, StoreThenLoad) { | |
122 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
123 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
124 | |
125 interpreter::Register reg_0(0); | |
126 | |
127 builder.StoreAccumulatorInRegister(reg_0); | |
128 expected_liveness.emplace_back("...L", "L..."); | |
129 | |
130 builder.LoadNull(); | |
131 expected_liveness.emplace_back("L...", "L..."); | |
132 | |
133 builder.LoadAccumulatorWithRegister(reg_0); | |
134 expected_liveness.emplace_back("L...", "...L"); | |
135 | |
136 builder.Return(); | |
137 expected_liveness.emplace_back("...L", "...."); | |
138 | |
139 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
140 | |
141 EnsureLivenessMatches(bytecode, expected_liveness); | |
142 } | |
143 | |
144 TEST_F(BytecodeAnalysisTest, DiamondLoad) { | |
145 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
146 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
147 | |
148 interpreter::Register reg_0(0); | |
149 interpreter::Register reg_1(1); | |
150 interpreter::Register reg_2(2); | |
151 | |
152 interpreter::BytecodeLabel ld1_label; | |
153 interpreter::BytecodeLabel end_label; | |
154 | |
155 builder.JumpIfTrue(&ld1_label); | |
156 expected_liveness.emplace_back("LLLL", "LLL."); | |
157 | |
158 builder.LoadAccumulatorWithRegister(reg_0); | |
159 expected_liveness.emplace_back("L.L.", "..L."); | |
160 | |
161 builder.Jump(&end_label); | |
162 expected_liveness.emplace_back("..L.", "..L."); | |
163 | |
164 builder.Bind(&ld1_label); | |
165 builder.LoadAccumulatorWithRegister(reg_1); | |
166 expected_liveness.emplace_back(".LL.", "..L."); | |
167 | |
168 builder.Bind(&end_label); | |
169 | |
170 builder.LoadAccumulatorWithRegister(reg_2); | |
171 expected_liveness.emplace_back("..L.", "...L"); | |
172 | |
173 builder.Return(); | |
174 expected_liveness.emplace_back("...L", "...."); | |
175 | |
176 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
177 | |
178 EnsureLivenessMatches(bytecode, expected_liveness); | |
179 } | |
180 | |
181 TEST_F(BytecodeAnalysisTest, DiamondLookupsAndBinds) { | |
182 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
183 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
184 | |
185 interpreter::Register reg_0(0); | |
186 interpreter::Register reg_1(1); | |
187 interpreter::Register reg_2(2); | |
188 | |
189 interpreter::BytecodeLabel ld1_label; | |
190 interpreter::BytecodeLabel end_label; | |
191 | |
192 builder.StoreAccumulatorInRegister(reg_0); | |
193 expected_liveness.emplace_back(".LLL", "LLLL"); | |
194 | |
195 builder.JumpIfTrue(&ld1_label); | |
196 expected_liveness.emplace_back("LLLL", "LLL."); | |
197 | |
198 { | |
199 builder.LoadAccumulatorWithRegister(reg_0); | |
200 expected_liveness.emplace_back("L...", "...L"); | |
201 | |
202 builder.StoreAccumulatorInRegister(reg_2); | |
203 expected_liveness.emplace_back("...L", "..L."); | |
204 | |
205 builder.Jump(&end_label); | |
206 expected_liveness.emplace_back("..L.", "..L."); | |
207 } | |
208 | |
209 builder.Bind(&ld1_label); | |
210 { | |
211 builder.LoadAccumulatorWithRegister(reg_1); | |
212 expected_liveness.emplace_back(".LL.", "..L."); | |
213 } | |
214 | |
215 builder.Bind(&end_label); | |
216 | |
217 builder.LoadAccumulatorWithRegister(reg_2); | |
218 expected_liveness.emplace_back("..L.", "...L"); | |
219 | |
220 builder.Return(); | |
221 expected_liveness.emplace_back("...L", "...."); | |
222 | |
223 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
224 | |
225 EnsureLivenessMatches(bytecode, expected_liveness); | |
226 } | |
227 | |
228 TEST_F(BytecodeAnalysisTest, SimpleLoop) { | |
229 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
230 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
231 | |
232 interpreter::Register reg_0(0); | |
233 interpreter::Register reg_1(1); | |
234 interpreter::Register reg_2(2); | |
235 | |
236 builder.StoreAccumulatorInRegister(reg_0); | |
237 expected_liveness.emplace_back("..LL", "L.LL"); | |
238 | |
239 interpreter::LoopBuilder loop_builder(&builder); | |
240 loop_builder.LoopHeader(); | |
241 { | |
242 builder.JumpIfTrue(loop_builder.break_labels()->New()); | |
243 expected_liveness.emplace_back("L.LL", "L.L."); | |
244 | |
245 builder.LoadAccumulatorWithRegister(reg_0); | |
246 expected_liveness.emplace_back("L...", "L..L"); | |
247 | |
248 builder.StoreAccumulatorInRegister(reg_2); | |
249 expected_liveness.emplace_back("L..L", "L.LL"); | |
250 | |
251 loop_builder.BindContinueTarget(); | |
252 loop_builder.JumpToHeader(0); | |
253 expected_liveness.emplace_back("L.LL", "L.LL"); | |
254 } | |
255 loop_builder.EndLoop(); | |
256 | |
257 builder.LoadAccumulatorWithRegister(reg_2); | |
258 expected_liveness.emplace_back("..L.", "...L"); | |
259 | |
260 builder.Return(); | |
261 expected_liveness.emplace_back("...L", "...."); | |
262 | |
263 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
264 | |
265 EnsureLivenessMatches(bytecode, expected_liveness); | |
266 } | |
267 | |
268 TEST_F(BytecodeAnalysisTest, TryCatch) { | |
269 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
270 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
271 | |
272 interpreter::Register reg_0(0); | |
273 interpreter::Register reg_1(1); | |
274 interpreter::Register reg_context(2); | |
275 | |
276 builder.StoreAccumulatorInRegister(reg_0); | |
277 expected_liveness.emplace_back(".LLL", "LLL."); | |
278 | |
279 interpreter::TryCatchBuilder try_builder(&builder, HandlerTable::CAUGHT); | |
280 try_builder.BeginTry(reg_context); | |
281 { | |
282 builder.LoadAccumulatorWithRegister(reg_0); | |
283 expected_liveness.emplace_back("LLL.", ".LLL"); | |
284 | |
285 builder.StoreAccumulatorInRegister(reg_0); | |
286 expected_liveness.emplace_back(".LLL", ".LL."); | |
287 | |
288 builder.CallRuntime(Runtime::kThrow); | |
289 expected_liveness.emplace_back(".LL.", ".LLL"); | |
290 | |
291 builder.StoreAccumulatorInRegister(reg_0); | |
292 // Star can't throw, so doesn't take handler liveness | |
293 expected_liveness.emplace_back("...L", "...L"); | |
294 } | |
295 try_builder.EndTry(); | |
296 expected_liveness.emplace_back("...L", "...L"); | |
297 | |
298 // Catch | |
299 { | |
300 builder.LoadAccumulatorWithRegister(reg_1); | |
301 expected_liveness.emplace_back(".L..", "...L"); | |
302 } | |
303 try_builder.EndCatch(); | |
304 | |
305 builder.Return(); | |
306 expected_liveness.emplace_back("...L", "...."); | |
307 | |
308 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
309 | |
310 EnsureLivenessMatches(bytecode, expected_liveness); | |
311 } | |
312 | |
313 TEST_F(BytecodeAnalysisTest, DiamondInLoop) { | |
314 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
315 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
316 | |
317 interpreter::Register reg_0(0); | |
318 interpreter::Register reg_1(1); | |
319 interpreter::Register reg_2(2); | |
320 | |
321 builder.StoreAccumulatorInRegister(reg_0); | |
322 expected_liveness.emplace_back("...L", "L..L"); | |
323 | |
324 interpreter::LoopBuilder loop_builder(&builder); | |
325 loop_builder.LoopHeader(); | |
326 { | |
327 builder.JumpIfTrue(loop_builder.break_labels()->New()); | |
328 expected_liveness.emplace_back("L..L", "L..L"); | |
329 | |
330 interpreter::BytecodeLabel ld1_label; | |
331 interpreter::BytecodeLabel end_label; | |
332 builder.JumpIfTrue(&ld1_label); | |
333 expected_liveness.emplace_back("L..L", "L..L"); | |
334 | |
335 { | |
336 builder.Jump(&end_label); | |
337 expected_liveness.emplace_back("L..L", "L..L"); | |
338 } | |
339 | |
340 builder.Bind(&ld1_label); | |
341 { | |
342 builder.LoadAccumulatorWithRegister(reg_0); | |
343 expected_liveness.emplace_back("L...", "L..L"); | |
344 } | |
345 | |
346 builder.Bind(&end_label); | |
347 | |
348 loop_builder.BindContinueTarget(); | |
349 loop_builder.JumpToHeader(0); | |
350 expected_liveness.emplace_back("L..L", "L..L"); | |
351 } | |
352 loop_builder.EndLoop(); | |
353 | |
354 builder.Return(); | |
355 expected_liveness.emplace_back("...L", "...."); | |
356 | |
357 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
358 | |
359 EnsureLivenessMatches(bytecode, expected_liveness); | |
360 } | |
361 | |
362 TEST_F(BytecodeAnalysisTest, KillingLoopInsideLoop) { | |
363 interpreter::BytecodeArrayBuilder builder(isolate(), zone(), 3, 0, 3); | |
364 std::vector<std::pair<std::string, std::string>> expected_liveness; | |
365 | |
366 interpreter::Register reg_0(0); | |
367 interpreter::Register reg_1(1); | |
368 | |
369 builder.StoreAccumulatorInRegister(reg_0); | |
370 expected_liveness.emplace_back(".L.L", "LL.."); | |
371 | |
372 interpreter::LoopBuilder loop_builder(&builder); | |
373 loop_builder.LoopHeader(); | |
374 { | |
375 builder.LoadAccumulatorWithRegister(reg_0); | |
376 expected_liveness.emplace_back("LL..", ".L.."); | |
377 | |
378 builder.LoadAccumulatorWithRegister(reg_1); | |
379 expected_liveness.emplace_back(".L..", ".L.L"); | |
380 | |
381 builder.JumpIfTrue(loop_builder.break_labels()->New()); | |
382 expected_liveness.emplace_back(".L.L", ".L.L"); | |
383 | |
384 interpreter::LoopBuilder inner_loop_builder(&builder); | |
385 inner_loop_builder.LoopHeader(); | |
386 { | |
387 builder.StoreAccumulatorInRegister(reg_0); | |
388 expected_liveness.emplace_back(".L.L", "LL.L"); | |
389 | |
390 builder.JumpIfTrue(inner_loop_builder.break_labels()->New()); | |
391 expected_liveness.emplace_back("LL.L", "LL.L"); | |
392 | |
393 inner_loop_builder.BindContinueTarget(); | |
394 inner_loop_builder.JumpToHeader(1); | |
395 expected_liveness.emplace_back(".L.L", ".L.L"); | |
396 } | |
397 inner_loop_builder.EndLoop(); | |
398 | |
399 loop_builder.BindContinueTarget(); | |
400 loop_builder.JumpToHeader(0); | |
401 expected_liveness.emplace_back("LL..", "LL.."); | |
402 } | |
403 loop_builder.EndLoop(); | |
404 | |
405 builder.Return(); | |
406 expected_liveness.emplace_back("...L", "...."); | |
407 | |
408 Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); | |
409 | |
410 EnsureLivenessMatches(bytecode, expected_liveness); | |
411 } | |
412 | |
413 } // namespace compiler | |
414 } // namespace internal | |
415 } // namespace v8 | |
OLD | NEW |