From 04cf4867fe4fb2fe0c32580d1de3a7d1b7e8b73e Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 1 Dec 2020 02:01:06 +0000 Subject: [PATCH] [ewasm] Clean up opcodes/builtins in the binary encoder Also make sure that `i32.drop/i64.drop` won't silently drop its arguments, as they may have side-effects. --- libyul/backends/wasm/BinaryTransform.cpp | 58 +++++++------------ libyul/backends/wasm/WasmDialect.h | 2 +- .../objectCompiler/wasm/no_main_function.yul | 2 +- test/libyul/objectCompiler/wasm/simple.yul | 2 +- test/libyul/objectCompiler/wasm/subObject.yul | 4 +- .../objectCompiler/wasm/subObjectAccess.yul | 6 +- 6 files changed, 30 insertions(+), 44 deletions(-) diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index df700527e..c395864ec 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -107,33 +107,24 @@ bytes toBytes(Export _export) return toBytes(uint8_t(_export)); } +// NOTE: This is a subset of WebAssembly opcodes. +// Those available as a builtin are listed further down. enum class Opcode: uint8_t { - Unreachable = 0x00, - Nop = 0x01, Block = 0x02, Loop = 0x03, If = 0x04, Else = 0x05, - Try = 0x06, - Catch = 0x07, - Throw = 0x08, - Rethrow = 0x09, - BrOnExn = 0x0a, End = 0x0b, Br = 0x0c, BrIf = 0x0d, - BrTable = 0x0e, + BrTable = 0x0e, // Not used yet. Return = 0x0f, Call = 0x10, - CallIndirect = 0x11, - ReturnCall = 0x12, - ReturnCallIndirect = 0x13, - Drop = 0x1a, - Select = 0x1b, + CallIndirect = 0x11, // Not used yet. LocalGet = 0x20, LocalSet = 0x21, - LocalTee = 0x22, + LocalTee = 0x22, // Not used yet. GlobalGet = 0x23, GlobalSet = 0x24, I32Const = 0x41, @@ -156,6 +147,10 @@ Opcode constOpcodeFor(ValueType _type) } static map const builtins = { + {"unreachable", 0x00}, + {"nop", 0x01}, + {"i32.drop", 0x1a}, + {"i64.drop", 0x1a}, {"i32.select", 0x1b}, {"i64.select", 0x1b}, {"i32.load", 0x28}, @@ -381,30 +376,21 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call) return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast(m_subModulePosAndSize.at(name).second)); } + yulAssert(builtins.count(_call.functionName), "Builtin " + _call.functionName + " not found"); + // NOTE: the dialect ensures we have the right amount of arguments bytes args = visit(_call.arguments); + bytes ret = move(args) + toBytes(builtins.at(_call.functionName)); + if ( + _call.functionName.find(".load") != string::npos || + _call.functionName.find(".store") != string::npos + ) + // Alignment hint and offset. Interpreters ignore the alignment. JITs/AOTs can take it + // into account to generate more efficient code but if the hint is invalid it could + // actually be more expensive. It's best to hint at 1-byte alignment if we don't plan + // to control the memory layout accordingly. + ret += bytes{{0, 0}}; // 2^0 == 1-byte alignment - if (_call.functionName == "unreachable") - return toBytes(Opcode::Unreachable); - else if (_call.functionName == "nop") - return toBytes(Opcode::Nop); - else if (_call.functionName == "i32.drop" || _call.functionName == "i64.drop") - return toBytes(Opcode::Drop); - else - { - yulAssert(builtins.count(_call.functionName), "Builtin " + _call.functionName + " not found"); - bytes ret = move(args) + toBytes(builtins.at(_call.functionName)); - if ( - _call.functionName.find(".load") != string::npos || - _call.functionName.find(".store") != string::npos - ) - // Alignment hint and offset. Interpreters ignore the alignment. JITs/AOTs can take it - // into account to generate more efficient code but if the hint is invalid it could - // actually be more expensive. It's best to hint at 1-byte alignment if we don't plan - // to control the memory layout accordingly. - ret += bytes{{0, 0}}; // 2^0 == 1-byte alignment - - return ret; - } + return ret; } bytes BinaryTransform::operator()(FunctionCall const& _call) diff --git a/libyul/backends/wasm/WasmDialect.h b/libyul/backends/wasm/WasmDialect.h index a9cf826ae..5abc69fc4 100644 --- a/libyul/backends/wasm/WasmDialect.h +++ b/libyul/backends/wasm/WasmDialect.h @@ -38,7 +38,7 @@ struct Object; * * Builtin functions are a subset of the wasm instructions. * - * There is a builtin function `i32.drop` that takes an i32, while `drop` takes i64. + * There is a builtin function `i32.drop` that takes an i32, while `i64.drop` takes i64. * */ struct WasmDialect: public Dialect diff --git a/test/libyul/objectCompiler/wasm/no_main_function.yul b/test/libyul/objectCompiler/wasm/no_main_function.yul index 89a0a5779..2dd91a166 100644 --- a/test/libyul/objectCompiler/wasm/no_main_function.yul +++ b/test/libyul/objectCompiler/wasm/no_main_function.yul @@ -19,4 +19,4 @@ // ) // // Binary: -// 0061736d01000000010401600000020100030201000503010001060100070a01066d656d6f727902000a0801060002401a0b0b +// 0061736d01000000010401600000020100030201000503010001060100070a01066d656d6f727902000a0d010b000240420042017c1a0b0b diff --git a/test/libyul/objectCompiler/wasm/simple.yul b/test/libyul/objectCompiler/wasm/simple.yul index db3f0038e..b158aea52 100644 --- a/test/libyul/objectCompiler/wasm/simple.yul +++ b/test/libyul/objectCompiler/wasm/simple.yul @@ -20,4 +20,4 @@ // ) // // Binary: -// 0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0801060002401a0b0b +// 0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0d010b000240420042017c1a0b0b diff --git a/test/libyul/objectCompiler/wasm/subObject.yul b/test/libyul/objectCompiler/wasm/subObject.yul index e9252fbe2..683e64be1 100644 --- a/test/libyul/objectCompiler/wasm/subObject.yul +++ b/test/libyul/objectCompiler/wasm/subObject.yul @@ -11,7 +11,7 @@ object "a" { // (module // ;; custom section for sub-module // ;; The Keccak-256 hash of the text representation of "sub": 78ac3419d75c8d6f42f663717b8e964eeb994d77ff175145133084422dbd23d7 -// ;; (@custom "sub" "0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0801060002401a0b0b") +// ;; (@custom "sub" "0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0a0108000240420b1a0b0b") // ;; custom section for data // ;; (@custom "str" "48656c6c6f2c20576f726c6421") // (memory $memory (export "memory") 1) @@ -19,4 +19,4 @@ object "a" { // ) // // Binary: -// 0061736d010000000101000201000301000503010001060100070a01066d656d6f72790200003e037375620061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0801060002401a0b0b00110373747248656c6c6f2c20576f726c64210a0100 +// 0061736d010000000101000201000301000503010001060100070a01066d656d6f727902000040037375620061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0a0108000240420b1a0b0b00110373747248656c6c6f2c20576f726c64210a0100 diff --git a/test/libyul/objectCompiler/wasm/subObjectAccess.yul b/test/libyul/objectCompiler/wasm/subObjectAccess.yul index ca85655de..8acced97f 100644 --- a/test/libyul/objectCompiler/wasm/subObjectAccess.yul +++ b/test/libyul/objectCompiler/wasm/subObjectAccess.yul @@ -59,8 +59,8 @@ object "A" { // Text: // (module // ;; custom section for sub-module -// ;; The Keccak-256 hash of the text representation of "B": 1eeffe5bc8d8819350ead60cc71ccd92c223cf52a908330db53461eb9ac89b62 -// ;; (@custom "B" "0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000007b01430061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000003c01440061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0901070002401a1a0b0b003c01450061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0b01090002401a1a1a1a0b0b") +// ;; The Keccak-256 hash of the text representation of "B": ccfc48ce1c0d0542ffd25ae6858777b2f7b8a6d2b6608f679458182e719f5434 +// ;; (@custom "B" "0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000007f01430061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000003c01440061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0d010b00024042341a423a1a0b0b003c01450061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a15011300024042341a42fd001a42b5011a423a1a0b0b") // ;; custom section for data // ;; (@custom "data1" "48656c6c6f2c20576f726c6421") // (memory $memory (export "memory") 1) @@ -76,4 +76,4 @@ object "A" { // ) // // Binary: -// 0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e000000fa0101420061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000007b01430061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000003c01440061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0901070002401a1a0b0b003c01450061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0b01090002401a1a1a1a0b0b001305646174613148656c6c6f2c20576f726c64210a0901070002401a1a0b0b +// 0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e000000880201420061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000007f01430061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000003c01440061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0d010b00024042341a423a1a0b0b003c01450061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a15011300024042341a42fd001a42b5011a423a1a0b0b001305646174613148656c6c6f2c20576f726c64210a0e010c00024042351a4286021a0b0b