blob: 2b67f12ef5152c295c5515be1baf2e1a5cd25b09 [file] [log] [blame]
Ben Murdoch61f157c2016-09-16 13:49:30 +01001// 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
10#include "src/wasm/wasm-interpreter.h"
11#include "src/wasm/wasm-macro-gen.h"
12
13using testing::MakeMatcher;
14using testing::Matcher;
15using testing::MatcherInterface;
16using testing::MatchResultListener;
17using testing::StringMatchResultListener;
18
19namespace v8 {
20namespace internal {
21namespace wasm {
22
23#define B1(a) kExprBlock, a, kExprEnd
24#define B2(a, b) kExprBlock, a, b, kExprEnd
25#define B3(a, b, c) kExprBlock, a, b, c, kExprEnd
26
27struct ExpectedTarget {
28 pc_t pc;
29 ControlTransfer expected;
30};
31
32// For nicer error messages.
33class ControlTransferMatcher : public MatcherInterface<const ControlTransfer&> {
34 public:
35 explicit ControlTransferMatcher(pc_t pc, const ControlTransfer& expected)
36 : pc_(pc), expected_(expected) {}
37
38 void DescribeTo(std::ostream* os) const override {
39 *os << "@" << pc_ << " {pcdiff = " << expected_.pcdiff
40 << ", spdiff = " << expected_.spdiff
41 << ", action = " << expected_.action << "}";
42 }
43
44 bool MatchAndExplain(const ControlTransfer& input,
45 MatchResultListener* listener) const override {
46 if (input.pcdiff != expected_.pcdiff || input.spdiff != expected_.spdiff ||
47 input.action != expected_.action) {
48 *listener << "@" << pc_ << " {pcdiff = " << input.pcdiff
49 << ", spdiff = " << input.spdiff
50 << ", action = " << input.action << "}";
51 return false;
52 }
53 return true;
54 }
55
56 private:
57 pc_t pc_;
58 const ControlTransfer& expected_;
59};
60
61class ControlTransferTest : public TestWithZone {
62 public:
63 void CheckControlTransfers(const byte* start, const byte* end,
64 ExpectedTarget* expected_targets,
65 size_t num_targets) {
66 ControlTransferMap map =
67 WasmInterpreter::ComputeControlTransfersForTesting(zone(), start, end);
68 // Check all control targets in the map.
69 for (size_t i = 0; i < num_targets; i++) {
70 pc_t pc = expected_targets[i].pc;
71 auto it = map.find(pc);
72 if (it == map.end()) {
73 printf("expected control target @ +%zu\n", pc);
74 EXPECT_TRUE(false);
75 } else {
76 ControlTransfer& expected = expected_targets[i].expected;
77 ControlTransfer& target = it->second;
78 EXPECT_THAT(target,
79 MakeMatcher(new ControlTransferMatcher(pc, expected)));
80 }
81 }
82
83 // Check there are no other control targets.
84 for (pc_t pc = 0; start + pc < end; pc++) {
85 bool found = false;
86 for (size_t i = 0; i < num_targets; i++) {
87 if (expected_targets[i].pc == pc) {
88 found = true;
89 break;
90 }
91 }
92 if (found) continue;
93 if (map.find(pc) != map.end()) {
94 printf("expected no control @ +%zu\n", pc);
95 EXPECT_TRUE(false);
96 }
97 }
98 }
99};
100
101// Macro for simplifying tests below.
102#define EXPECT_TARGETS(...) \
103 do { \
104 ExpectedTarget pairs[] = {__VA_ARGS__}; \
105 CheckControlTransfers(code, code + sizeof(code), pairs, arraysize(pairs)); \
106 } while (false)
107
108TEST_F(ControlTransferTest, SimpleIf) {
109 byte code[] = {
110 kExprI32Const, // @0
111 0, // +1
112 kExprIf, // @2
113 kExprEnd // @3
114 };
115 EXPECT_TARGETS({2, {2, 0, ControlTransfer::kPushVoid}}, // --
116 {3, {1, 0, ControlTransfer::kPushVoid}});
117}
118
119TEST_F(ControlTransferTest, SimpleIf1) {
120 byte code[] = {
121 kExprI32Const, // @0
122 0, // +1
123 kExprIf, // @2
124 kExprNop, // @3
125 kExprEnd // @4
126 };
127 EXPECT_TARGETS({2, {3, 0, ControlTransfer::kPushVoid}}, // --
128 {4, {1, 1, ControlTransfer::kPopAndRepush}});
129}
130
131TEST_F(ControlTransferTest, SimpleIf2) {
132 byte code[] = {
133 kExprI32Const, // @0
134 0, // +1
135 kExprIf, // @2
136 kExprNop, // @3
137 kExprNop, // @4
138 kExprEnd // @5
139 };
140 EXPECT_TARGETS({2, {4, 0, ControlTransfer::kPushVoid}}, // --
141 {5, {1, 2, ControlTransfer::kPopAndRepush}});
142}
143
144TEST_F(ControlTransferTest, SimpleIfElse) {
145 byte code[] = {
146 kExprI32Const, // @0
147 0, // +1
148 kExprIf, // @2
149 kExprElse, // @3
150 kExprEnd // @4
151 };
152 EXPECT_TARGETS({2, {2, 0, ControlTransfer::kNoAction}}, // --
153 {3, {2, 0, ControlTransfer::kPushVoid}}, // --
154 {4, {1, 0, ControlTransfer::kPushVoid}});
155}
156
157TEST_F(ControlTransferTest, SimpleIfElse1) {
158 byte code[] = {
159 kExprI32Const, // @0
160 0, // +1
161 kExprIf, // @2
162 kExprNop, // @3
163 kExprElse, // @4
164 kExprNop, // @5
165 kExprEnd // @6
166 };
167 EXPECT_TARGETS({2, {3, 0, ControlTransfer::kNoAction}}, // --
168 {4, {3, 1, ControlTransfer::kPopAndRepush}}, // --
169 {6, {1, 1, ControlTransfer::kPopAndRepush}});
170}
171
172TEST_F(ControlTransferTest, IfBr) {
173 byte code[] = {
174 kExprI32Const, // @0
175 0, // +1
176 kExprIf, // @2
177 kExprBr, // @3
178 ARITY_0, // +1
179 0, // +1
180 kExprEnd // @6
181 };
182 EXPECT_TARGETS({2, {5, 0, ControlTransfer::kPushVoid}}, // --
183 {3, {4, 0, ControlTransfer::kPushVoid}}, // --
184 {6, {1, 1, ControlTransfer::kPopAndRepush}});
185}
186
187TEST_F(ControlTransferTest, IfBrElse) {
188 byte code[] = {
189 kExprI32Const, // @0
190 0, // +1
191 kExprIf, // @2
192 kExprBr, // @3
193 ARITY_0, // +1
194 0, // +1
195 kExprElse, // @6
196 kExprEnd // @7
197 };
198 EXPECT_TARGETS({2, {5, 0, ControlTransfer::kNoAction}}, // --
199 {3, {5, 0, ControlTransfer::kPushVoid}}, // --
200 {6, {2, 1, ControlTransfer::kPopAndRepush}}, // --
201 {7, {1, 0, ControlTransfer::kPushVoid}});
202}
203
204TEST_F(ControlTransferTest, IfElseBr) {
205 byte code[] = {
206 kExprI32Const, // @0
207 0, // +1
208 kExprIf, // @2
209 kExprNop, // @3
210 kExprElse, // @4
211 kExprBr, // @5
212 ARITY_0, // +1
213 0, // +1
214 kExprEnd // @8
215 };
216 EXPECT_TARGETS({2, {3, 0, ControlTransfer::kNoAction}}, // --
217 {4, {5, 1, ControlTransfer::kPopAndRepush}}, // --
218 {5, {4, 0, ControlTransfer::kPushVoid}}, // --
219 {8, {1, 1, ControlTransfer::kPopAndRepush}});
220}
221
222TEST_F(ControlTransferTest, BlockEmpty) {
223 byte code[] = {
224 kExprBlock, // @0
225 kExprEnd // @1
226 };
227 EXPECT_TARGETS({1, {1, 0, ControlTransfer::kPushVoid}});
228}
229
230TEST_F(ControlTransferTest, Br0) {
231 byte code[] = {
232 kExprBlock, // @0
233 kExprBr, // @1
234 ARITY_0, // +1
235 0, // +1
236 kExprEnd // @4
237 };
238 EXPECT_TARGETS({1, {4, 0, ControlTransfer::kPushVoid}},
239 {4, {1, 1, ControlTransfer::kPopAndRepush}});
240}
241
242TEST_F(ControlTransferTest, Br1) {
243 byte code[] = {
244 kExprBlock, // @0
245 kExprNop, // @1
246 kExprBr, // @2
247 ARITY_0, // +1
248 0, // +1
249 kExprEnd // @5
250 };
251 EXPECT_TARGETS({2, {4, 1, ControlTransfer::kPopAndRepush}}, // --
252 {5, {1, 2, ControlTransfer::kPopAndRepush}});
253}
254
255TEST_F(ControlTransferTest, Br2) {
256 byte code[] = {
257 kExprBlock, // @0
258 kExprNop, // @1
259 kExprNop, // @2
260 kExprBr, // @3
261 ARITY_0, // +1
262 0, // +1
263 kExprEnd // @6
264 };
265 EXPECT_TARGETS({3, {4, 2, ControlTransfer::kPopAndRepush}}, // --
266 {6, {1, 3, ControlTransfer::kPopAndRepush}});
267}
268
269TEST_F(ControlTransferTest, Br0b) {
270 byte code[] = {
271 kExprBlock, // @0
272 kExprBr, // @1
273 ARITY_0, // +1
274 0, // +1
275 kExprNop, // @4
276 kExprEnd // @5
277 };
278 EXPECT_TARGETS({1, {5, 0, ControlTransfer::kPushVoid}}, // --
279 {5, {1, 2, ControlTransfer::kPopAndRepush}});
280}
281
282TEST_F(ControlTransferTest, Br0c) {
283 byte code[] = {
284 kExprBlock, // @0
285 kExprBr, // @1
286 ARITY_0, // +1
287 0, // +1
288 kExprNop, // @4
289 kExprNop, // @5
290 kExprEnd // @6
291 };
292 EXPECT_TARGETS({1, {6, 0, ControlTransfer::kPushVoid}}, // --
293 {6, {1, 3, ControlTransfer::kPopAndRepush}});
294}
295
296TEST_F(ControlTransferTest, SimpleLoop1) {
297 byte code[] = {
298 kExprLoop, // @0
299 kExprBr, // @1
300 ARITY_0, // +1
301 0, // +1
302 kExprEnd // @4
303 };
304 EXPECT_TARGETS({1, {-1, 0, ControlTransfer::kNoAction}}, // --
305 {4, {1, 1, ControlTransfer::kPopAndRepush}});
306}
307
308TEST_F(ControlTransferTest, SimpleLoop2) {
309 byte code[] = {
310 kExprLoop, // @0
311 kExprNop, // @1
312 kExprBr, // @2
313 ARITY_0, // +1
314 0, // +1
315 kExprEnd // @5
316 };
317 EXPECT_TARGETS({2, {-2, 1, ControlTransfer::kNoAction}}, // --
318 {5, {1, 2, ControlTransfer::kPopAndRepush}});
319}
320
321TEST_F(ControlTransferTest, SimpleLoopExit1) {
322 byte code[] = {
323 kExprLoop, // @0
324 kExprBr, // @1
325 ARITY_0, // +1
326 1, // +1
327 kExprEnd // @4
328 };
329 EXPECT_TARGETS({1, {4, 0, ControlTransfer::kPushVoid}}, // --
330 {4, {1, 1, ControlTransfer::kPopAndRepush}});
331}
332
333TEST_F(ControlTransferTest, SimpleLoopExit2) {
334 byte code[] = {
335 kExprLoop, // @0
336 kExprNop, // @1
337 kExprBr, // @2
338 ARITY_0, // +1
339 1, // +1
340 kExprEnd // @5
341 };
342 EXPECT_TARGETS({2, {4, 1, ControlTransfer::kPopAndRepush}}, // --
343 {5, {1, 2, ControlTransfer::kPopAndRepush}});
344}
345
346TEST_F(ControlTransferTest, BrTable0) {
347 byte code[] = {
348 kExprBlock, // @0
349 kExprI8Const, // @1
350 0, // +1
351 kExprBrTable, // @3
352 ARITY_0, // +1
353 0, // +1
354 U32_LE(0), // +4
355 kExprEnd // @10
356 };
357 EXPECT_TARGETS({3, {8, 0, ControlTransfer::kPushVoid}}, // --
358 {10, {1, 1, ControlTransfer::kPopAndRepush}});
359}
360
361TEST_F(ControlTransferTest, BrTable1) {
362 byte code[] = {
363 kExprBlock, // @0
364 kExprI8Const, // @1
365 0, // +1
366 kExprBrTable, // @3
367 ARITY_0, // +1
368 1, // +1
369 U32_LE(0), // +4
370 U32_LE(0), // +4
371 kExprEnd // @14
372 };
373 EXPECT_TARGETS({3, {12, 0, ControlTransfer::kPushVoid}}, // --
374 {4, {11, 0, ControlTransfer::kPushVoid}}, // --
375 {14, {1, 1, ControlTransfer::kPopAndRepush}});
376}
377
378TEST_F(ControlTransferTest, BrTable2) {
379 byte code[] = {
380 kExprBlock, // @0
381 kExprBlock, // @1
382 kExprI8Const, // @2
383 0, // +1
384 kExprBrTable, // @4
385 ARITY_0, // +1
386 2, // +1
387 U32_LE(0), // +4
388 U32_LE(0), // +4
389 U32_LE(1), // +4
390 kExprEnd, // @19
391 kExprEnd // @19
392 };
393 EXPECT_TARGETS({4, {16, 0, ControlTransfer::kPushVoid}}, // --
394 {5, {15, 0, ControlTransfer::kPushVoid}}, // --
395 {6, {15, 0, ControlTransfer::kPushVoid}}, // --
396 {19, {1, 1, ControlTransfer::kPopAndRepush}}, // --
397 {20, {1, 1, ControlTransfer::kPopAndRepush}});
398}
399
400} // namespace wasm
401} // namespace internal
402} // namespace v8