diff options
Diffstat (limited to 'deps/v8/test/unittests/wasm/control-transfer-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/wasm/control-transfer-unittest.cc | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/deps/v8/test/unittests/wasm/control-transfer-unittest.cc b/deps/v8/test/unittests/wasm/control-transfer-unittest.cc new file mode 100644 index 0000000000..2b67f12ef5 --- /dev/null +++ b/deps/v8/test/unittests/wasm/control-transfer-unittest.cc @@ -0,0 +1,402 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "test/unittests/test-utils.h" +#include "testing/gmock/include/gmock/gmock.h" + +#include "src/v8.h" + +#include "src/wasm/wasm-interpreter.h" +#include "src/wasm/wasm-macro-gen.h" + +using testing::MakeMatcher; +using testing::Matcher; +using testing::MatcherInterface; +using testing::MatchResultListener; +using testing::StringMatchResultListener; + +namespace v8 { +namespace internal { +namespace wasm { + +#define B1(a) kExprBlock, a, kExprEnd +#define B2(a, b) kExprBlock, a, b, kExprEnd +#define B3(a, b, c) kExprBlock, a, b, c, kExprEnd + +struct ExpectedTarget { + pc_t pc; + ControlTransfer expected; +}; + +// For nicer error messages. +class ControlTransferMatcher : public MatcherInterface<const ControlTransfer&> { + public: + explicit ControlTransferMatcher(pc_t pc, const ControlTransfer& expected) + : pc_(pc), expected_(expected) {} + + void DescribeTo(std::ostream* os) const override { + *os << "@" << pc_ << " {pcdiff = " << expected_.pcdiff + << ", spdiff = " << expected_.spdiff + << ", action = " << expected_.action << "}"; + } + + bool MatchAndExplain(const ControlTransfer& input, + MatchResultListener* listener) const override { + if (input.pcdiff != expected_.pcdiff || input.spdiff != expected_.spdiff || + input.action != expected_.action) { + *listener << "@" << pc_ << " {pcdiff = " << input.pcdiff + << ", spdiff = " << input.spdiff + << ", action = " << input.action << "}"; + return false; + } + return true; + } + + private: + pc_t pc_; + const ControlTransfer& expected_; +}; + +class ControlTransferTest : public TestWithZone { + public: + void CheckControlTransfers(const byte* start, const byte* end, + ExpectedTarget* expected_targets, + size_t num_targets) { + ControlTransferMap map = + WasmInterpreter::ComputeControlTransfersForTesting(zone(), start, end); + // Check all control targets in the map. + for (size_t i = 0; i < num_targets; i++) { + pc_t pc = expected_targets[i].pc; + auto it = map.find(pc); + if (it == map.end()) { + printf("expected control target @ +%zu\n", pc); + EXPECT_TRUE(false); + } else { + ControlTransfer& expected = expected_targets[i].expected; + ControlTransfer& target = it->second; + EXPECT_THAT(target, + MakeMatcher(new ControlTransferMatcher(pc, expected))); + } + } + + // Check there are no other control targets. + for (pc_t pc = 0; start + pc < end; pc++) { + bool found = false; + for (size_t i = 0; i < num_targets; i++) { + if (expected_targets[i].pc == pc) { + found = true; + break; + } + } + if (found) continue; + if (map.find(pc) != map.end()) { + printf("expected no control @ +%zu\n", pc); + EXPECT_TRUE(false); + } + } + } +}; + +// Macro for simplifying tests below. +#define EXPECT_TARGETS(...) \ + do { \ + ExpectedTarget pairs[] = {__VA_ARGS__}; \ + CheckControlTransfers(code, code + sizeof(code), pairs, arraysize(pairs)); \ + } while (false) + +TEST_F(ControlTransferTest, SimpleIf) { + byte code[] = { + kExprI32Const, // @0 + 0, // +1 + kExprIf, // @2 + kExprEnd // @3 + }; + EXPECT_TARGETS({2, {2, 0, ControlTransfer::kPushVoid}}, // -- + {3, {1, 0, ControlTransfer::kPushVoid}}); +} + +TEST_F(ControlTransferTest, SimpleIf1) { + byte code[] = { + kExprI32Const, // @0 + 0, // +1 + kExprIf, // @2 + kExprNop, // @3 + kExprEnd // @4 + }; + EXPECT_TARGETS({2, {3, 0, ControlTransfer::kPushVoid}}, // -- + {4, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, SimpleIf2) { + byte code[] = { + kExprI32Const, // @0 + 0, // +1 + kExprIf, // @2 + kExprNop, // @3 + kExprNop, // @4 + kExprEnd // @5 + }; + EXPECT_TARGETS({2, {4, 0, ControlTransfer::kPushVoid}}, // -- + {5, {1, 2, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, SimpleIfElse) { + byte code[] = { + kExprI32Const, // @0 + 0, // +1 + kExprIf, // @2 + kExprElse, // @3 + kExprEnd // @4 + }; + EXPECT_TARGETS({2, {2, 0, ControlTransfer::kNoAction}}, // -- + {3, {2, 0, ControlTransfer::kPushVoid}}, // -- + {4, {1, 0, ControlTransfer::kPushVoid}}); +} + +TEST_F(ControlTransferTest, SimpleIfElse1) { + byte code[] = { + kExprI32Const, // @0 + 0, // +1 + kExprIf, // @2 + kExprNop, // @3 + kExprElse, // @4 + kExprNop, // @5 + kExprEnd // @6 + }; + EXPECT_TARGETS({2, {3, 0, ControlTransfer::kNoAction}}, // -- + {4, {3, 1, ControlTransfer::kPopAndRepush}}, // -- + {6, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, IfBr) { + byte code[] = { + kExprI32Const, // @0 + 0, // +1 + kExprIf, // @2 + kExprBr, // @3 + ARITY_0, // +1 + 0, // +1 + kExprEnd // @6 + }; + EXPECT_TARGETS({2, {5, 0, ControlTransfer::kPushVoid}}, // -- + {3, {4, 0, ControlTransfer::kPushVoid}}, // -- + {6, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, IfBrElse) { + byte code[] = { + kExprI32Const, // @0 + 0, // +1 + kExprIf, // @2 + kExprBr, // @3 + ARITY_0, // +1 + 0, // +1 + kExprElse, // @6 + kExprEnd // @7 + }; + EXPECT_TARGETS({2, {5, 0, ControlTransfer::kNoAction}}, // -- + {3, {5, 0, ControlTransfer::kPushVoid}}, // -- + {6, {2, 1, ControlTransfer::kPopAndRepush}}, // -- + {7, {1, 0, ControlTransfer::kPushVoid}}); +} + +TEST_F(ControlTransferTest, IfElseBr) { + byte code[] = { + kExprI32Const, // @0 + 0, // +1 + kExprIf, // @2 + kExprNop, // @3 + kExprElse, // @4 + kExprBr, // @5 + ARITY_0, // +1 + 0, // +1 + kExprEnd // @8 + }; + EXPECT_TARGETS({2, {3, 0, ControlTransfer::kNoAction}}, // -- + {4, {5, 1, ControlTransfer::kPopAndRepush}}, // -- + {5, {4, 0, ControlTransfer::kPushVoid}}, // -- + {8, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, BlockEmpty) { + byte code[] = { + kExprBlock, // @0 + kExprEnd // @1 + }; + EXPECT_TARGETS({1, {1, 0, ControlTransfer::kPushVoid}}); +} + +TEST_F(ControlTransferTest, Br0) { + byte code[] = { + kExprBlock, // @0 + kExprBr, // @1 + ARITY_0, // +1 + 0, // +1 + kExprEnd // @4 + }; + EXPECT_TARGETS({1, {4, 0, ControlTransfer::kPushVoid}}, + {4, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, Br1) { + byte code[] = { + kExprBlock, // @0 + kExprNop, // @1 + kExprBr, // @2 + ARITY_0, // +1 + 0, // +1 + kExprEnd // @5 + }; + EXPECT_TARGETS({2, {4, 1, ControlTransfer::kPopAndRepush}}, // -- + {5, {1, 2, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, Br2) { + byte code[] = { + kExprBlock, // @0 + kExprNop, // @1 + kExprNop, // @2 + kExprBr, // @3 + ARITY_0, // +1 + 0, // +1 + kExprEnd // @6 + }; + EXPECT_TARGETS({3, {4, 2, ControlTransfer::kPopAndRepush}}, // -- + {6, {1, 3, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, Br0b) { + byte code[] = { + kExprBlock, // @0 + kExprBr, // @1 + ARITY_0, // +1 + 0, // +1 + kExprNop, // @4 + kExprEnd // @5 + }; + EXPECT_TARGETS({1, {5, 0, ControlTransfer::kPushVoid}}, // -- + {5, {1, 2, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, Br0c) { + byte code[] = { + kExprBlock, // @0 + kExprBr, // @1 + ARITY_0, // +1 + 0, // +1 + kExprNop, // @4 + kExprNop, // @5 + kExprEnd // @6 + }; + EXPECT_TARGETS({1, {6, 0, ControlTransfer::kPushVoid}}, // -- + {6, {1, 3, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, SimpleLoop1) { + byte code[] = { + kExprLoop, // @0 + kExprBr, // @1 + ARITY_0, // +1 + 0, // +1 + kExprEnd // @4 + }; + EXPECT_TARGETS({1, {-1, 0, ControlTransfer::kNoAction}}, // -- + {4, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, SimpleLoop2) { + byte code[] = { + kExprLoop, // @0 + kExprNop, // @1 + kExprBr, // @2 + ARITY_0, // +1 + 0, // +1 + kExprEnd // @5 + }; + EXPECT_TARGETS({2, {-2, 1, ControlTransfer::kNoAction}}, // -- + {5, {1, 2, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, SimpleLoopExit1) { + byte code[] = { + kExprLoop, // @0 + kExprBr, // @1 + ARITY_0, // +1 + 1, // +1 + kExprEnd // @4 + }; + EXPECT_TARGETS({1, {4, 0, ControlTransfer::kPushVoid}}, // -- + {4, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, SimpleLoopExit2) { + byte code[] = { + kExprLoop, // @0 + kExprNop, // @1 + kExprBr, // @2 + ARITY_0, // +1 + 1, // +1 + kExprEnd // @5 + }; + EXPECT_TARGETS({2, {4, 1, ControlTransfer::kPopAndRepush}}, // -- + {5, {1, 2, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, BrTable0) { + byte code[] = { + kExprBlock, // @0 + kExprI8Const, // @1 + 0, // +1 + kExprBrTable, // @3 + ARITY_0, // +1 + 0, // +1 + U32_LE(0), // +4 + kExprEnd // @10 + }; + EXPECT_TARGETS({3, {8, 0, ControlTransfer::kPushVoid}}, // -- + {10, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, BrTable1) { + byte code[] = { + kExprBlock, // @0 + kExprI8Const, // @1 + 0, // +1 + kExprBrTable, // @3 + ARITY_0, // +1 + 1, // +1 + U32_LE(0), // +4 + U32_LE(0), // +4 + kExprEnd // @14 + }; + EXPECT_TARGETS({3, {12, 0, ControlTransfer::kPushVoid}}, // -- + {4, {11, 0, ControlTransfer::kPushVoid}}, // -- + {14, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +TEST_F(ControlTransferTest, BrTable2) { + byte code[] = { + kExprBlock, // @0 + kExprBlock, // @1 + kExprI8Const, // @2 + 0, // +1 + kExprBrTable, // @4 + ARITY_0, // +1 + 2, // +1 + U32_LE(0), // +4 + U32_LE(0), // +4 + U32_LE(1), // +4 + kExprEnd, // @19 + kExprEnd // @19 + }; + EXPECT_TARGETS({4, {16, 0, ControlTransfer::kPushVoid}}, // -- + {5, {15, 0, ControlTransfer::kPushVoid}}, // -- + {6, {15, 0, ControlTransfer::kPushVoid}}, // -- + {19, {1, 1, ControlTransfer::kPopAndRepush}}, // -- + {20, {1, 1, ControlTransfer::kPopAndRepush}}); +} + +} // namespace wasm +} // namespace internal +} // namespace v8 |