v8/test/unittests/wasm/wasm-text-unittest.cc
Ben Smith 8bf9ba4e7c [wasm] Add unittest for PrintWasmText
PrintWasmText is used for disassembling wasm code in DevTools, but many
instructions are not implemented. This test should make it easier to
remember to implement this when adding new instructions.

Change-Id: I6030a70113320f11a1ac0436bf0d220b5c41e6d1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1647475
Commit-Queue: Ben Smith <binji@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62063}
2019-06-08 12:39:07 +00:00

122 lines
3.4 KiB
C++

// Copyright 2019 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 <sstream>
#include "test/unittests/test-utils.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-module-builder.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-text.h"
#include "test/common/wasm/test-signatures.h"
namespace v8 {
namespace internal {
namespace wasm {
class WasmTextTest : public TestWithIsolateAndZone {
public:
TestSignatures sigs;
WasmFeatures enabled_features_;
void TestInstruction(const byte* func_start, size_t func_size) {
WasmModuleBuilder mb(zone());
auto* fb = mb.AddFunction(sigs.v_v());
fb->EmitCode(func_start, static_cast<uint32_t>(func_size));
fb->Emit(kExprEnd);
ZoneBuffer buffer(zone());
mb.WriteTo(buffer);
ModuleWireBytes wire_bytes(
Vector<const byte>(buffer.begin(), buffer.size()));
ModuleResult result = DecodeWasmModule(
enabled_features_, buffer.begin(), buffer.end(), false, kWasmOrigin,
isolate()->counters(), isolate()->wasm_engine()->allocator());
EXPECT_TRUE(result.ok());
std::stringstream ss;
PrintWasmText(result.value().get(), wire_bytes, 0, ss, nullptr);
}
};
TEST_F(WasmTextTest, EveryOpcodeCanBeDecoded) {
static const struct {
WasmOpcode opcode;
const char* debug_name;
} kValues[] = {
#define DECLARE_ELEMENT(name, opcode, sig) {kExpr##name, "kExpr" #name},
FOREACH_OPCODE(DECLARE_ELEMENT)};
#undef DECLARE_ELEMENT
for (const auto& value : kValues) {
// Pad with 0 for any immediate values. If they're not needed, they'll be
// interpreted as unreachable.
byte data[20] = {0};
printf("%s\n", value.debug_name);
switch (value.opcode) {
// Instructions that have a special case because they affect the control
// depth.
case kExprBlock:
case kExprLoop:
case kExprIf:
case kExprTry:
data[0] = value.opcode;
data[1] = kLocalVoid;
data[2] = kExprEnd;
break;
case kExprElse:
data[0] = kExprIf;
data[1] = value.opcode;
data[2] = kExprEnd;
break;
case kExprCatch:
data[0] = kExprTry;
data[1] = value.opcode;
data[2] = kExprEnd;
break;
case kExprEnd:
break;
// Instructions with special requirements for immediates.
case kExprSelectWithType:
data[0] = kExprSelectWithType;
data[1] = 1;
data[2] = kLocalI32;
break;
default: {
if (value.opcode >= 0x100) {
data[0] = value.opcode >> 8; // Prefix byte.
byte opcode = value.opcode & 0xff; // Actual opcode.
if (opcode >= 0x80) {
// Opcode with prefix, and needs to be LEB encoded (3 bytes).
// For now, this can only be in the range [0x80, 0xff], which means
// that the third byte is always 1.
data[1] = (opcode & 0x7f) | 0x80;
data[2] = 1;
} else {
// Opcode with prefix (2 bytes).
data[1] = opcode;
}
} else {
// Single-byte opcode.
data[0] = value.opcode;
}
break;
}
}
TestInstruction(data, arraysize(data));
}
}
} // namespace wasm
} // namespace internal
} // namespace v8