• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
10 #include "src/wasm/wasm-interpreter.h"
11 #include "src/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 #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 
27 struct ExpectedTarget {
28   pc_t pc;
29   ControlTransfer expected;
30 };
31 
32 // For nicer error messages.
33 class ControlTransferMatcher : public MatcherInterface<const ControlTransfer&> {
34  public:
ControlTransferMatcher(pc_t pc,const ControlTransfer & expected)35   explicit ControlTransferMatcher(pc_t pc, const ControlTransfer& expected)
36       : pc_(pc), expected_(expected) {}
37 
DescribeTo(std::ostream * os) const38   void DescribeTo(std::ostream* os) const override {
39     *os << "@" << pc_ << " {pcdiff = " << expected_.pcdiff
40         << ", spdiff = " << expected_.spdiff
41         << ", action = " << expected_.action << "}";
42   }
43 
MatchAndExplain(const ControlTransfer & input,MatchResultListener * listener) const44   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 
61 class ControlTransferTest : public TestWithZone {
62  public:
CheckControlTransfers(const byte * start,const byte * end,ExpectedTarget * expected_targets,size_t num_targets)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 
TEST_F(ControlTransferTest,SimpleIf)108 TEST_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 
TEST_F(ControlTransferTest,SimpleIf1)119 TEST_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 
TEST_F(ControlTransferTest,SimpleIf2)131 TEST_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 
TEST_F(ControlTransferTest,SimpleIfElse)144 TEST_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 
TEST_F(ControlTransferTest,SimpleIfElse1)157 TEST_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 
TEST_F(ControlTransferTest,IfBr)172 TEST_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 
TEST_F(ControlTransferTest,IfBrElse)187 TEST_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 
TEST_F(ControlTransferTest,IfElseBr)204 TEST_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 
TEST_F(ControlTransferTest,BlockEmpty)222 TEST_F(ControlTransferTest, BlockEmpty) {
223   byte code[] = {
224       kExprBlock,  // @0
225       kExprEnd     // @1
226   };
227   EXPECT_TARGETS({1, {1, 0, ControlTransfer::kPushVoid}});
228 }
229 
TEST_F(ControlTransferTest,Br0)230 TEST_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 
TEST_F(ControlTransferTest,Br1)242 TEST_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 
TEST_F(ControlTransferTest,Br2)255 TEST_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 
TEST_F(ControlTransferTest,Br0b)269 TEST_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 
TEST_F(ControlTransferTest,Br0c)282 TEST_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 
TEST_F(ControlTransferTest,SimpleLoop1)296 TEST_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 
TEST_F(ControlTransferTest,SimpleLoop2)308 TEST_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 
TEST_F(ControlTransferTest,SimpleLoopExit1)321 TEST_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 
TEST_F(ControlTransferTest,SimpleLoopExit2)333 TEST_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 
TEST_F(ControlTransferTest,BrTable0)346 TEST_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 
TEST_F(ControlTransferTest,BrTable1)361 TEST_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 
TEST_F(ControlTransferTest,BrTable2)378 TEST_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
403