7ed3c4d791
R=clemensh@chromium.org BUG= Review-Url: https://codereview.chromium.org/2595733003 Cr-Commit-Position: refs/heads/master@{#42141}
467 lines
11 KiB
C++
467 lines
11 KiB
C++
// 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
|
|
|
|
#define TRANSFER_VOID 0
|
|
#define TRANSFER_ONE 1
|
|
|
|
struct ExpectedPcDelta {
|
|
pc_t pc;
|
|
pcdiff_t expected;
|
|
};
|
|
|
|
// For nicer error messages.
|
|
class ControlTransferMatcher : public MatcherInterface<const pcdiff_t&> {
|
|
public:
|
|
explicit ControlTransferMatcher(pc_t pc, const pcdiff_t& expected)
|
|
: pc_(pc), expected_(expected) {}
|
|
|
|
void DescribeTo(std::ostream* os) const override {
|
|
*os << "@" << pc_ << " pcdiff = " << expected_;
|
|
}
|
|
|
|
bool MatchAndExplain(const pcdiff_t& input,
|
|
MatchResultListener* listener) const override {
|
|
if (input != expected_) {
|
|
*listener << "@" << pc_ << " pcdiff = " << input;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
pc_t pc_;
|
|
const pcdiff_t& expected_;
|
|
};
|
|
|
|
class ControlTransferTest : public TestWithZone {
|
|
public:
|
|
void CheckPcDeltas(const byte* start, const byte* end,
|
|
ExpectedPcDelta* expected_deltas, 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_deltas[i].pc;
|
|
auto it = map.find(pc);
|
|
if (it == map.end()) {
|
|
EXPECT_TRUE(false) << "expected control target @ " << pc;
|
|
} else {
|
|
pcdiff_t expected = expected_deltas[i].expected;
|
|
pcdiff_t& target = it->second;
|
|
EXPECT_THAT(target,
|
|
MakeMatcher(new ControlTransferMatcher(pc, expected)));
|
|
}
|
|
}
|
|
|
|
// Check there are no other control targets.
|
|
CheckNoOtherTargets<ExpectedPcDelta>(start, end, map, expected_deltas,
|
|
num_targets);
|
|
}
|
|
|
|
template <typename T>
|
|
void CheckNoOtherTargets(const byte* start, const byte* end,
|
|
ControlTransferMap& map, T* targets,
|
|
size_t num_targets) {
|
|
// 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 (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);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
#define EXPECT_PC_DELTAS(...) \
|
|
do { \
|
|
ExpectedPcDelta pairs[] = {__VA_ARGS__}; \
|
|
CheckPcDeltas(code, code + sizeof(code), pairs, arraysize(pairs)); \
|
|
} while (false)
|
|
|
|
TEST_F(ControlTransferTest, SimpleIf) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprEnd // @4
|
|
};
|
|
EXPECT_PC_DELTAS({2, 2});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleIf1) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprNop, // @4
|
|
kExprEnd // @5
|
|
};
|
|
EXPECT_PC_DELTAS({2, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleIf2) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprNop, // @4
|
|
kExprNop, // @5
|
|
kExprEnd // @6
|
|
};
|
|
EXPECT_PC_DELTAS({2, 4});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleIfElse) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprElse, // @4
|
|
kExprEnd // @5
|
|
};
|
|
EXPECT_PC_DELTAS({2, 3}, {4, 2});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleIfElse_v1) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprI32Const, // @4
|
|
0, // @5
|
|
kExprElse, // @6
|
|
kExprI32Const, // @7
|
|
0, // @8
|
|
kExprEnd // @9
|
|
};
|
|
EXPECT_PC_DELTAS({2, 5}, {6, 4});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleIfElse1) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprElse, // @4
|
|
kExprNop, // @5
|
|
kExprEnd // @6
|
|
};
|
|
EXPECT_PC_DELTAS({2, 3}, {4, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, IfBr) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprBr, // @4
|
|
0, // @5
|
|
kExprEnd // @6
|
|
};
|
|
EXPECT_PC_DELTAS({2, 4}, {4, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, IfBrElse) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprBr, // @4
|
|
0, // @5
|
|
kExprElse, // @6
|
|
kExprEnd // @7
|
|
};
|
|
EXPECT_PC_DELTAS({2, 5}, {4, 4}, {6, 2});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, IfElseBr) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprIf, // @2
|
|
kLocalVoid, // @3
|
|
kExprElse, // @4
|
|
kExprBr, // @5
|
|
0, // @6
|
|
kExprEnd // @7
|
|
};
|
|
EXPECT_PC_DELTAS({2, 3}, {4, 4}, {5, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, BlockEmpty) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kExprEnd // @1
|
|
};
|
|
CheckPcDeltas(code, code + sizeof(code), nullptr, 0);
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, Br0) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprBr, // @2
|
|
0, // @3
|
|
kExprEnd // @4
|
|
};
|
|
EXPECT_PC_DELTAS({2, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, Br1) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprNop, // @2
|
|
kExprBr, // @3
|
|
0, // @4
|
|
kExprEnd // @5
|
|
};
|
|
EXPECT_PC_DELTAS({3, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, Br_v1a) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprI32Const, // @2
|
|
0, // @3
|
|
kExprBr, // @4
|
|
0, // @5
|
|
kExprEnd // @6
|
|
};
|
|
EXPECT_PC_DELTAS({4, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, Br_v1b) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprI32Const, // @2
|
|
0, // @3
|
|
kExprBr, // @4
|
|
0, // @5
|
|
kExprEnd // @6
|
|
};
|
|
EXPECT_PC_DELTAS({4, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, Br_v1c) {
|
|
byte code[] = {
|
|
kExprI32Const, // @0
|
|
0, // @1
|
|
kExprBlock, // @2
|
|
kLocalVoid, // @3
|
|
kExprBr, // @4
|
|
0, // @5
|
|
kExprEnd // @6
|
|
};
|
|
EXPECT_PC_DELTAS({4, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, Br2) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprNop, // @2
|
|
kExprNop, // @3
|
|
kExprBr, // @4
|
|
0, // @5
|
|
kExprEnd // @6
|
|
};
|
|
EXPECT_PC_DELTAS({4, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, Br0b) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprBr, // @2
|
|
0, // @3
|
|
kExprNop, // @4
|
|
kExprEnd // @5
|
|
};
|
|
EXPECT_PC_DELTAS({2, 4});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, Br0c) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprBr, // @2
|
|
0, // @3
|
|
kExprNop, // @4
|
|
kExprNop, // @5
|
|
kExprEnd // @6
|
|
};
|
|
EXPECT_PC_DELTAS({2, 5});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleLoop1) {
|
|
byte code[] = {
|
|
kExprLoop, // @0
|
|
kLocalVoid, // @1
|
|
kExprBr, // @2
|
|
0, // @3
|
|
kExprEnd // @4
|
|
};
|
|
EXPECT_PC_DELTAS({2, -2});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleLoop2) {
|
|
byte code[] = {
|
|
kExprLoop, // @0
|
|
kLocalVoid, // @1
|
|
kExprNop, // @2
|
|
kExprBr, // @3
|
|
0, // @4
|
|
kExprEnd // @5
|
|
};
|
|
EXPECT_PC_DELTAS({3, -3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleLoopExit1) {
|
|
byte code[] = {
|
|
kExprLoop, // @0
|
|
kLocalVoid, // @1
|
|
kExprBr, // @2
|
|
1, // @3
|
|
kExprEnd // @4
|
|
};
|
|
EXPECT_PC_DELTAS({2, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, SimpleLoopExit2) {
|
|
byte code[] = {
|
|
kExprLoop, // @0
|
|
kLocalVoid, // @1
|
|
kExprNop, // @2
|
|
kExprBr, // @3
|
|
1, // @4
|
|
kExprEnd // @5
|
|
};
|
|
EXPECT_PC_DELTAS({3, 3});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, BrTable0) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprI32Const, // @2
|
|
0, // @3
|
|
kExprBrTable, // @4
|
|
0, // @5
|
|
U32V_1(0), // @6
|
|
kExprEnd // @7
|
|
};
|
|
EXPECT_PC_DELTAS({4, 4});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, BrTable0_v1a) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprI32Const, // @2
|
|
0, // @3
|
|
kExprI32Const, // @4
|
|
0, // @5
|
|
kExprBrTable, // @6
|
|
0, // @7
|
|
U32V_1(0), // @8
|
|
kExprEnd // @9
|
|
};
|
|
EXPECT_PC_DELTAS({6, 4});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, BrTable0_v1b) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprI32Const, // @2
|
|
0, // @3
|
|
kExprI32Const, // @4
|
|
0, // @5
|
|
kExprBrTable, // @6
|
|
0, // @7
|
|
U32V_1(0), // @8
|
|
kExprEnd // @9
|
|
};
|
|
EXPECT_PC_DELTAS({6, 4});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, BrTable1) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprI32Const, // @2
|
|
0, // @3
|
|
kExprBrTable, // @4
|
|
1, // @5
|
|
U32V_1(0), // @6
|
|
U32V_1(0), // @7
|
|
kExprEnd // @8
|
|
};
|
|
EXPECT_PC_DELTAS({4, 5}, {5, 4});
|
|
}
|
|
|
|
TEST_F(ControlTransferTest, BrTable2) {
|
|
byte code[] = {
|
|
kExprBlock, // @0
|
|
kLocalVoid, // @1
|
|
kExprBlock, // @2
|
|
kLocalVoid, // @3
|
|
kExprI32Const, // @4
|
|
0, // @5
|
|
kExprBrTable, // @6
|
|
2, // @7
|
|
U32V_1(0), // @8
|
|
U32V_1(0), // @9
|
|
U32V_1(1), // @10
|
|
kExprEnd, // @11
|
|
kExprEnd // @12
|
|
};
|
|
EXPECT_PC_DELTAS({6, 6}, {7, 5}, {8, 5});
|
|
}
|
|
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|