v8/test/unittests/wasm/wasm-disassembler-unittest.cc
Clemens Backes 95cdb3c573 [wasm] Always use the engine allocator for decoded modules
As Wasm module can live longer than the isolate that initially created
them, it generally makes sense to use the WasmEngine's accounting
allocator for the decoded WasmModule.

Instead of passing that allocator through many functions, we can just
get it directly from the one global WasmEngine when we need it.

R=ahaas@chromium.org

Change-Id: I552f8e19072f2305a3186b821c2f5b3969eac83f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4071464
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84611}
2022-12-02 12:22:06 +00:00

133 lines
5.0 KiB
C++

// Copyright 2022 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 <regex>
#include <string>
#include "src/base/vector.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/string-builder-multiline.h"
#include "src/wasm/wasm-disassembler-impl.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
namespace wasm {
class WasmDisassemblerTest : public ::v8::TestWithPlatform {};
// Code that is shared for all tests, the only difference is the input module
// and expected disassembler output.
void CheckDisassemblerOutput(base::Vector<const byte> module_bytes,
std::string expected_output) {
AccountingAllocator allocator;
ModuleResult module_result = DecodeWasmModuleForDisassembler(module_bytes);
DCHECK(module_result.ok());
WasmModule* module = module_result.value().get();
ModuleWireBytes wire_bytes(module_bytes);
NamesProvider names(module, module_bytes);
MultiLineStringBuilder output_sb;
ModuleDisassembler md(output_sb, module, &names, wire_bytes, &allocator);
constexpr size_t max_mb = 100; // Even 1 would be enough.
md.PrintModule({0, 2}, max_mb);
std::ostringstream output;
output_sb.WriteTo(output);
// Remove comment lines from expected output since they cannot be recovered
// by a disassembler.
// They were also used as part of the C++/WAT polyglot trick described below.
std::regex comment_regex(" *;;[^\\n]*\\n?");
expected_output = std::regex_replace(expected_output, comment_regex, "");
std::string output_str = std::regex_replace(output.str(), comment_regex, "");
EXPECT_EQ(expected_output, output_str);
}
TEST_F(WasmDisassemblerTest, Mvp) {
// If you want to extend this test (and the other tests below):
// 1. Modify the included .wat.inc file(s), e.g., add more instructions.
// 2. Convert the Wasm text file to a Wasm binary with `wat2wasm`.
// 3. Convert the Wasm binary to an array init expression with
// `wami --full-hexdump` and paste it into the included file below.
// One liner example (Linux):
// wat2wasm wasm-disassembler-unittest-mvp.wat.inc --output=-
// | wami --full-hexdump
// | head -n-1 | tail -n+2 > wasm-disassembler-unittest-mvp.wasm.inc
constexpr byte module_bytes[] = {
#include "wasm-disassembler-unittest-mvp.wasm.inc"
};
// Little trick: polyglot C++/WebAssembly text file.
// We want to include the expected disassembler text output as a string into
// this test (instead of reading it from the file at runtime, which would make
// it dependent on the current working directory).
// At the same time, we want the included file itself to be valid WAT, such
// that it can be processed e.g. by wat2wasm to build the module bytes above.
// For that to work, we abuse that ;; starts a line comment in WAT, but at
// the same time, ;; in C++ are just two empty statements, which are no
// harm when including the file here either.
std::string expected;
#include "wasm-disassembler-unittest-mvp.wat.inc"
CheckDisassemblerOutput(base::ArrayVector(module_bytes), expected);
}
TEST_F(WasmDisassemblerTest, Names) {
// You can create a binary with a custom name section from the text format via
// `wat2wasm --debug-names`.
constexpr byte module_bytes[] = {
#include "wasm-disassembler-unittest-names.wasm.inc"
};
std::string expected;
#include "wasm-disassembler-unittest-names.wat.inc"
CheckDisassemblerOutput(base::ArrayVector(module_bytes), expected);
}
TEST_F(WasmDisassemblerTest, Simd) {
constexpr byte module_bytes[] = {
#include "wasm-disassembler-unittest-simd.wasm.inc"
};
std::string expected;
#include "wasm-disassembler-unittest-simd.wat.inc"
CheckDisassemblerOutput(base::ArrayVector(module_bytes), expected);
}
TEST_F(WasmDisassemblerTest, Gc) {
// Since WABT's `wat2wasm` didn't support some GC features yet, I used
// Binaryen's `wasm-as --enable-gc --hybrid` here to produce the binary.
constexpr byte module_bytes[] = {
#include "wasm-disassembler-unittest-gc.wasm.inc"
};
std::string expected;
#include "wasm-disassembler-unittest-gc.wat.inc"
CheckDisassemblerOutput(base::ArrayVector(module_bytes), expected);
}
TEST_F(WasmDisassemblerTest, TooManyends) {
constexpr byte module_bytes[] = {
#include "wasm-disassembler-unittest-too-many-ends.wasm.inc"
};
std::string expected;
#include "wasm-disassembler-unittest-too-many-ends.wat.inc"
CheckDisassemblerOutput(base::ArrayVector(module_bytes), expected);
}
// TODO(dlehmann): Add tests for the following Wasm features and extensions:
// - custom name section for Wasm GC constructs (struct and array type names,
// struct fields).
// - exception-related instructions (try, catch, catch_all, delegate) and named
// exception tags.
// - atomic instructions (threads proposal, 0xfe prefix).
// - some "numeric" instructions (0xfc prefix).
} // namespace wasm
} // namespace internal
} // namespace v8