Home | History | Annotate | Download | only in wasm
      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:
     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 
     61 class 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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