// 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 #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(func_size)); fb->Emit(kExprEnd); ZoneBuffer buffer(zone()); mb.WriteTo(&buffer); ModuleWireBytes wire_bytes( Vector(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