Line data Source code
1 : // Copyright 2016 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 "test/unittests/test-utils.h"
6 : #include "testing/gmock/include/gmock/gmock.h"
7 :
8 : #include "src/v8.h"
9 : #include "src/wasm/wasm-interpreter.h"
10 :
11 : #include "test/common/wasm/wasm-macro-gen.h"
12 :
13 : using testing::MakeMatcher;
14 : using testing::Matcher;
15 : using testing::MatcherInterface;
16 : using testing::MatchResultListener;
17 : using testing::StringMatchResultListener;
18 :
19 : namespace v8 {
20 : namespace internal {
21 : namespace wasm {
22 :
23 : struct ExpectedControlTransfer {
24 : pc_t pc;
25 : pcdiff_t pc_diff;
26 : uint32_t sp_diff;
27 : uint32_t target_arity;
28 : };
29 :
30 : // For nicer error messages.
31 82 : class ControlTransferMatcher
32 : : public MatcherInterface<const ControlTransferEntry&> {
33 : public:
34 : explicit ControlTransferMatcher(pc_t pc,
35 : const ExpectedControlTransfer& expected)
36 41 : : pc_(pc), expected_(expected) {}
37 :
38 0 : void DescribeTo(std::ostream* os) const override {
39 0 : *os << "@" << pc_ << ": pcdiff = " << expected_.pc_diff
40 0 : << ", spdiff = " << expected_.sp_diff
41 0 : << ", target arity = " << expected_.target_arity;
42 0 : }
43 :
44 41 : bool MatchAndExplain(const ControlTransferEntry& input,
45 : MatchResultListener* listener) const override {
46 82 : if (input.pc_diff == expected_.pc_diff &&
47 82 : input.sp_diff == expected_.sp_diff &&
48 41 : input.target_arity == expected_.target_arity) {
49 : return true;
50 : }
51 : *listener << "@" << pc_ << ": pcdiff = " << input.pc_diff
52 : << ", spdiff = " << input.sp_diff
53 : << ", target arity = " << input.target_arity;
54 0 : return false;
55 : }
56 :
57 : private:
58 : pc_t pc_;
59 : const ExpectedControlTransfer& expected_;
60 : };
61 :
62 60 : class ControlTransferTest : public TestWithZone {
63 : public:
64 : template <int code_len>
65 30 : void CheckTransfers(
66 : const byte (&code)[code_len],
67 : std::initializer_list<ExpectedControlTransfer> expected_transfers) {
68 : byte code_with_end[code_len + 1]; // NOLINT: code_len is a constant here
69 : memcpy(code_with_end, code, code_len);
70 30 : code_with_end[code_len] = kExprEnd;
71 :
72 : ControlTransferMap map = WasmInterpreter::ComputeControlTransfersForTesting(
73 30 : zone(), nullptr, code_with_end, code_with_end + code_len + 1);
74 : // Check all control targets in the map.
75 112 : for (auto& expected_transfer : expected_transfers) {
76 41 : pc_t pc = expected_transfer.pc;
77 82 : EXPECT_TRUE(map.count(pc) > 0) << "expected control target @" << pc;
78 41 : if (!map.count(pc)) continue;
79 41 : auto& entry = map[pc];
80 164 : EXPECT_THAT(entry, MakeMatcher(new ControlTransferMatcher(
81 : pc, expected_transfer)));
82 : }
83 :
84 : // Check there are no other control targets.
85 30 : CheckNoOtherTargets(code_with_end, code_with_end + code_len + 1, map,
86 : expected_transfers);
87 30 : }
88 :
89 30 : void CheckNoOtherTargets(
90 : const byte* start, const byte* end, ControlTransferMap& map,
91 : std::initializer_list<ExpectedControlTransfer> targets) {
92 : // Check there are no other control targets.
93 560 : for (pc_t pc = 0; start + pc < end; pc++) {
94 : bool found = false;
95 929 : for (auto& target : targets) {
96 373 : if (target.pc == pc) {
97 : found = true;
98 : break;
99 : }
100 : }
101 265 : if (found) continue;
102 448 : EXPECT_TRUE(map.count(pc) == 0) << "expected no control @ +" << pc;
103 : }
104 30 : }
105 : };
106 :
107 15444 : TEST_F(ControlTransferTest, SimpleIf) {
108 : byte code[] = {
109 : kExprI32Const, // @0
110 : 0, // @1
111 : kExprIf, // @2
112 : kLocalVoid, // @3
113 : kExprEnd // @4
114 1 : };
115 1 : CheckTransfers(code, {{2, 2, 0, 0}});
116 1 : }
117 :
118 15444 : TEST_F(ControlTransferTest, SimpleIf1) {
119 : byte code[] = {
120 : kExprI32Const, // @0
121 : 0, // @1
122 : kExprIf, // @2
123 : kLocalVoid, // @3
124 : kExprNop, // @4
125 : kExprEnd // @5
126 1 : };
127 1 : CheckTransfers(code, {{2, 3, 0, 0}});
128 1 : }
129 :
130 15444 : TEST_F(ControlTransferTest, SimpleIf2) {
131 : byte code[] = {
132 : kExprI32Const, // @0
133 : 0, // @1
134 : kExprIf, // @2
135 : kLocalVoid, // @3
136 : kExprNop, // @4
137 : kExprNop, // @5
138 : kExprEnd // @6
139 1 : };
140 1 : CheckTransfers(code, {{2, 4, 0, 0}});
141 1 : }
142 :
143 15444 : TEST_F(ControlTransferTest, SimpleIfElse) {
144 : byte code[] = {
145 : kExprI32Const, // @0
146 : 0, // @1
147 : kExprIf, // @2
148 : kLocalVoid, // @3
149 : kExprElse, // @4
150 : kExprEnd // @5
151 1 : };
152 1 : CheckTransfers(code, {{2, 3, 0, 0}, {4, 2, 0, 0}});
153 1 : }
154 :
155 15444 : TEST_F(ControlTransferTest, SimpleIfElse_v1) {
156 : byte code[] = {
157 : kExprI32Const, // @0
158 : 0, // @1
159 : kExprIf, // @2
160 : kLocalVoid, // @3
161 : kExprI32Const, // @4
162 : 0, // @5
163 : kExprElse, // @6
164 : kExprI32Const, // @7
165 : 0, // @8
166 : kExprEnd // @9
167 1 : };
168 1 : CheckTransfers(code, {{2, 5, 0, 0}, {6, 4, 1, 0}});
169 1 : }
170 :
171 15444 : TEST_F(ControlTransferTest, SimpleIfElse1) {
172 : byte code[] = {
173 : kExprI32Const, // @0
174 : 0, // @1
175 : kExprIf, // @2
176 : kLocalVoid, // @3
177 : kExprElse, // @4
178 : kExprNop, // @5
179 : kExprEnd // @6
180 1 : };
181 1 : CheckTransfers(code, {{2, 3, 0, 0}, {4, 3, 0, 0}});
182 1 : }
183 :
184 15444 : TEST_F(ControlTransferTest, IfBr) {
185 : byte code[] = {
186 : kExprI32Const, // @0
187 : 0, // @1
188 : kExprIf, // @2
189 : kLocalVoid, // @3
190 : kExprBr, // @4
191 : 0, // @5
192 : kExprEnd // @6
193 1 : };
194 1 : CheckTransfers(code, {{2, 4, 0, 0}, {4, 3, 0, 0}});
195 1 : }
196 :
197 15444 : TEST_F(ControlTransferTest, IfBrElse) {
198 : byte code[] = {
199 : kExprI32Const, // @0
200 : 0, // @1
201 : kExprIf, // @2
202 : kLocalVoid, // @3
203 : kExprBr, // @4
204 : 0, // @5
205 : kExprElse, // @6
206 : kExprEnd // @7
207 1 : };
208 1 : CheckTransfers(code, {{2, 5, 0, 0}, {4, 4, 0, 0}, {6, 2, 0, 0}});
209 1 : }
210 :
211 15444 : TEST_F(ControlTransferTest, IfElseBr) {
212 : byte code[] = {
213 : kExprI32Const, // @0
214 : 0, // @1
215 : kExprIf, // @2
216 : kLocalVoid, // @3
217 : kExprElse, // @4
218 : kExprBr, // @5
219 : 0, // @6
220 : kExprEnd // @7
221 1 : };
222 1 : CheckTransfers(code, {{2, 3, 0, 0}, {4, 4, 0, 0}, {5, 3, 0, 0}});
223 1 : }
224 :
225 15444 : TEST_F(ControlTransferTest, BlockEmpty) {
226 : byte code[] = {
227 : kExprBlock, // @0
228 : kLocalVoid, // @1
229 : kExprEnd // @2
230 1 : };
231 1 : CheckTransfers(code, {});
232 1 : }
233 :
234 15444 : TEST_F(ControlTransferTest, Br0) {
235 : byte code[] = {
236 : kExprBlock, // @0
237 : kLocalVoid, // @1
238 : kExprBr, // @2
239 : 0, // @3
240 : kExprEnd // @4
241 1 : };
242 1 : CheckTransfers(code, {{2, 3, 0, 0}});
243 1 : }
244 :
245 15444 : TEST_F(ControlTransferTest, Br1) {
246 : byte code[] = {
247 : kExprBlock, // @0
248 : kLocalVoid, // @1
249 : kExprNop, // @2
250 : kExprBr, // @3
251 : 0, // @4
252 : kExprEnd // @5
253 1 : };
254 1 : CheckTransfers(code, {{3, 3, 0, 0}});
255 1 : }
256 :
257 15444 : TEST_F(ControlTransferTest, Br_v1a) {
258 : byte code[] = {
259 : kExprBlock, // @0
260 : kLocalVoid, // @1
261 : kExprI32Const, // @2
262 : 0, // @3
263 : kExprBr, // @4
264 : 0, // @5
265 : kExprEnd // @6
266 1 : };
267 1 : CheckTransfers(code, {{4, 3, 1, 0}});
268 1 : }
269 :
270 15444 : TEST_F(ControlTransferTest, Br_v1b) {
271 : byte code[] = {
272 : kExprBlock, // @0
273 : kLocalVoid, // @1
274 : kExprI32Const, // @2
275 : 0, // @3
276 : kExprBr, // @4
277 : 0, // @5
278 : kExprEnd // @6
279 1 : };
280 1 : CheckTransfers(code, {{4, 3, 1, 0}});
281 1 : }
282 :
283 15444 : TEST_F(ControlTransferTest, Br_v1c) {
284 : byte code[] = {
285 : kExprI32Const, // @0
286 : 0, // @1
287 : kExprBlock, // @2
288 : kLocalVoid, // @3
289 : kExprBr, // @4
290 : 0, // @5
291 : kExprEnd // @6
292 1 : };
293 1 : CheckTransfers(code, {{4, 3, 0, 0}});
294 1 : }
295 :
296 15444 : TEST_F(ControlTransferTest, Br_v1d) {
297 : byte code[] = {
298 : kExprBlock, // @0
299 : kLocalI32, // @1
300 : kExprI32Const, // @2
301 : 0, // @3
302 : kExprBr, // @4
303 : 0, // @5
304 : kExprEnd // @6
305 1 : };
306 1 : CheckTransfers(code, {{4, 3, 1, 1}});
307 1 : }
308 :
309 15444 : TEST_F(ControlTransferTest, Br2) {
310 : byte code[] = {
311 : kExprBlock, // @0
312 : kLocalVoid, // @1
313 : kExprNop, // @2
314 : kExprNop, // @3
315 : kExprBr, // @4
316 : 0, // @5
317 : kExprEnd // @6
318 1 : };
319 1 : CheckTransfers(code, {{4, 3, 0, 0}});
320 1 : }
321 :
322 15444 : TEST_F(ControlTransferTest, Br0b) {
323 : byte code[] = {
324 : kExprBlock, // @0
325 : kLocalVoid, // @1
326 : kExprBr, // @2
327 : 0, // @3
328 : kExprNop, // @4
329 : kExprEnd // @5
330 1 : };
331 1 : CheckTransfers(code, {{2, 4, 0, 0}});
332 1 : }
333 :
334 15444 : TEST_F(ControlTransferTest, Br0c) {
335 : byte code[] = {
336 : kExprBlock, // @0
337 : kLocalVoid, // @1
338 : kExprBr, // @2
339 : 0, // @3
340 : kExprNop, // @4
341 : kExprNop, // @5
342 : kExprEnd // @6
343 1 : };
344 1 : CheckTransfers(code, {{2, 5, 0, 0}});
345 1 : }
346 :
347 15444 : TEST_F(ControlTransferTest, SimpleLoop1) {
348 : byte code[] = {
349 : kExprLoop, // @0
350 : kLocalVoid, // @1
351 : kExprBr, // @2
352 : 0, // @3
353 : kExprEnd // @4
354 1 : };
355 1 : CheckTransfers(code, {{2, -2, 0, 0}});
356 1 : }
357 :
358 15444 : TEST_F(ControlTransferTest, SimpleLoop2) {
359 : byte code[] = {
360 : kExprLoop, // @0
361 : kLocalVoid, // @1
362 : kExprNop, // @2
363 : kExprBr, // @3
364 : 0, // @4
365 : kExprEnd // @5
366 1 : };
367 1 : CheckTransfers(code, {{3, -3, 0, 0}});
368 1 : }
369 :
370 15444 : TEST_F(ControlTransferTest, SimpleLoopExit1) {
371 : byte code[] = {
372 : kExprLoop, // @0
373 : kLocalVoid, // @1
374 : kExprBr, // @2
375 : 1, // @3
376 : kExprEnd // @4
377 1 : };
378 1 : CheckTransfers(code, {{2, 4, 0, 0}});
379 1 : }
380 :
381 15444 : TEST_F(ControlTransferTest, SimpleLoopExit2) {
382 : byte code[] = {
383 : kExprLoop, // @0
384 : kLocalVoid, // @1
385 : kExprNop, // @2
386 : kExprBr, // @3
387 : 1, // @4
388 : kExprEnd // @5
389 1 : };
390 1 : CheckTransfers(code, {{3, 4, 0, 0}});
391 1 : }
392 :
393 15444 : TEST_F(ControlTransferTest, BrTable0) {
394 : byte code[] = {
395 : kExprBlock, // @0
396 : kLocalVoid, // @1
397 : kExprI32Const, // @2
398 : 0, // @3
399 : kExprBrTable, // @4
400 : 0, // @5
401 : U32V_1(0), // @6
402 : kExprEnd // @7
403 1 : };
404 1 : CheckTransfers(code, {{4, 4, 0, 0}});
405 1 : }
406 :
407 15444 : TEST_F(ControlTransferTest, BrTable0_v1a) {
408 : byte code[] = {
409 : kExprBlock, // @0
410 : kLocalVoid, // @1
411 : kExprI32Const, // @2
412 : 0, // @3
413 : kExprI32Const, // @4
414 : 0, // @5
415 : kExprBrTable, // @6
416 : 0, // @7
417 : U32V_1(0), // @8
418 : kExprEnd // @9
419 1 : };
420 1 : CheckTransfers(code, {{6, 4, 1, 0}});
421 1 : }
422 :
423 15444 : TEST_F(ControlTransferTest, BrTable0_v1b) {
424 : byte code[] = {
425 : kExprBlock, // @0
426 : kLocalVoid, // @1
427 : kExprI32Const, // @2
428 : 0, // @3
429 : kExprI32Const, // @4
430 : 0, // @5
431 : kExprBrTable, // @6
432 : 0, // @7
433 : U32V_1(0), // @8
434 : kExprEnd // @9
435 1 : };
436 1 : CheckTransfers(code, {{6, 4, 1, 0}});
437 1 : }
438 :
439 15444 : TEST_F(ControlTransferTest, BrTable1) {
440 : byte code[] = {
441 : kExprBlock, // @0
442 : kLocalVoid, // @1
443 : kExprI32Const, // @2
444 : 0, // @3
445 : kExprBrTable, // @4
446 : 1, // @5
447 : U32V_1(0), // @6
448 : U32V_1(0), // @7
449 : kExprEnd // @8
450 1 : };
451 1 : CheckTransfers(code, {{4, 5, 0, 0}, {5, 4, 0, 0}});
452 1 : }
453 :
454 15444 : TEST_F(ControlTransferTest, BrTable2) {
455 : byte code[] = {
456 : kExprBlock, // @0
457 : kLocalVoid, // @1
458 : kExprBlock, // @2
459 : kLocalVoid, // @3
460 : kExprI32Const, // @4
461 : 0, // @5
462 : kExprBrTable, // @6
463 : 2, // @7
464 : U32V_1(0), // @8
465 : U32V_1(0), // @9
466 : U32V_1(1), // @10
467 : kExprEnd, // @11
468 : kExprEnd // @12
469 1 : };
470 1 : CheckTransfers(code, {{6, 6, 0, 0}, {7, 5, 0, 0}, {8, 5, 0, 0}});
471 1 : }
472 :
473 15444 : TEST_F(ControlTransferTest, BiggerSpDiffs) {
474 : byte code[] = {
475 : kExprBlock, // @0
476 : kLocalI32, // @1
477 : kExprI32Const, // @2
478 : 0, // @3
479 : kExprBlock, // @4
480 : kLocalVoid, // @5
481 : kExprI32Const, // @6
482 : 0, // @7
483 : kExprI32Const, // @8
484 : 0, // @9
485 : kExprI32Const, // @10
486 : 0, // @11
487 : kExprBrIf, // @12
488 : 0, // @13
489 : kExprBr, // @14
490 : 1, // @15
491 : kExprEnd, // @16
492 : kExprEnd // @17
493 1 : };
494 1 : CheckTransfers(code, {{12, 5, 2, 0}, {14, 4, 3, 1}});
495 1 : }
496 :
497 15444 : TEST_F(ControlTransferTest, NoInfoForUnreachableCode) {
498 : byte code[] = {
499 : kExprBlock, // @0
500 : kLocalVoid, // @1
501 : kExprBr, // @2
502 : 0, // @3
503 : kExprBr, // @4 -- no control transfer entry!
504 : 1, // @5
505 : kExprEnd, // @6
506 : kExprBlock, // @7
507 : kLocalVoid, // @8
508 : kExprUnreachable, // @9
509 : kExprI32Const, // @10
510 : 0, // @11
511 : kExprIf, // @12 -- no control transfer entry!
512 : kLocalVoid, // @13
513 : kExprBr, // @14 -- no control transfer entry!
514 : 0, // @15
515 : kExprElse, // @16 -- no control transfer entry!
516 : kExprEnd, // @17
517 : kExprEnd // @18
518 1 : };
519 1 : CheckTransfers(code, {{2, 5, 0, 0}});
520 1 : }
521 :
522 : } // namespace wasm
523 : } // namespace internal
524 9264 : } // namespace v8
|