From e5396e42c3e219e0bf394cdd9408ce00da11a46b Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 9 Nov 2020 21:04:00 +0000 Subject: [PATCH 1/2] Add wasm support to libyul/ObjectCompilerTest --- test/libyul/ObjectCompilerTest.cpp | 42 ++++++---- test/libyul/ObjectCompilerTest.h | 1 + .../objectCompiler/wasm/no_main_function.yul | 22 ++++++ test/libyul/objectCompiler/wasm/simple.yul | 23 ++++++ test/libyul/objectCompiler/wasm/subObject.yul | 19 +++++ .../objectCompiler/wasm/subObjectAccess.yul | 76 +++++++++++++++++++ 6 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 test/libyul/objectCompiler/wasm/no_main_function.yul create mode 100644 test/libyul/objectCompiler/wasm/simple.yul create mode 100644 test/libyul/objectCompiler/wasm/subObject.yul create mode 100644 test/libyul/objectCompiler/wasm/subObjectAccess.yul diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index 950c0210f..94e244cfb 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -44,6 +44,7 @@ ObjectCompilerTest::ObjectCompilerTest(string const& _filename): { m_source = m_reader.source(); m_optimize = m_reader.boolSetting("optimize", false); + m_wasm = m_reader.boolSetting("wasm", false); m_expectation = m_reader.simpleExpectations(); } @@ -51,7 +52,7 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li { AssemblyStack stack( EVMVersion(), - AssemblyStack::Language::StrictAssembly, + m_wasm ? AssemblyStack::Language::Ewasm : AssemblyStack::Language::StrictAssembly, m_optimize ? OptimiserSettings::full() : OptimiserSettings::minimal() ); if (!stack.parseAndAnalyze("source", m_source)) @@ -62,22 +63,33 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li } stack.optimize(); - MachineAssemblyObject obj = stack.assemble(AssemblyStack::Machine::EVM); - solAssert(obj.bytecode, ""); - solAssert(obj.sourceMappings, ""); + if (m_wasm) + { + MachineAssemblyObject obj = stack.assemble(AssemblyStack::Machine::Ewasm); + solAssert(obj.bytecode, ""); - m_obtainedResult = "Assembly:\n" + obj.assembly; - if (obj.bytecode->bytecode.empty()) - m_obtainedResult += "-- empty bytecode --\n"; + m_obtainedResult = "Text:\n" + obj.assembly + "\n"; + m_obtainedResult += "Binary:\n" + toHex(obj.bytecode->bytecode) + "\n"; + } else - m_obtainedResult += - "Bytecode: " + - toHex(obj.bytecode->bytecode) + - "\nOpcodes: " + - boost::trim_copy(evmasm::disassemble(obj.bytecode->bytecode)) + - "\nSourceMappings:" + - (obj.sourceMappings->empty() ? "" : " " + *obj.sourceMappings) + - "\n"; + { + MachineAssemblyObject obj = stack.assemble(AssemblyStack::Machine::EVM); + solAssert(obj.bytecode, ""); + solAssert(obj.sourceMappings, ""); + + m_obtainedResult = "Assembly:\n" + obj.assembly; + if (obj.bytecode->bytecode.empty()) + m_obtainedResult += "-- empty bytecode --\n"; + else + m_obtainedResult += + "Bytecode: " + + toHex(obj.bytecode->bytecode) + + "\nOpcodes: " + + boost::trim_copy(evmasm::disassemble(obj.bytecode->bytecode)) + + "\nSourceMappings:" + + (obj.sourceMappings->empty() ? "" : " " + *obj.sourceMappings) + + "\n"; + } return checkResult(_stream, _linePrefix, _formatted); } diff --git a/test/libyul/ObjectCompilerTest.h b/test/libyul/ObjectCompilerTest.h index 85a46a1cf..771942e59 100644 --- a/test/libyul/ObjectCompilerTest.h +++ b/test/libyul/ObjectCompilerTest.h @@ -55,6 +55,7 @@ private: static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors); bool m_optimize = false; + bool m_wasm = false; }; } diff --git a/test/libyul/objectCompiler/wasm/no_main_function.yul b/test/libyul/objectCompiler/wasm/no_main_function.yul new file mode 100644 index 000000000..89a0a5779 --- /dev/null +++ b/test/libyul/objectCompiler/wasm/no_main_function.yul @@ -0,0 +1,22 @@ +{ + function not_main() { + i64.drop(i64.add(0, 1)) + } +} +// ==== +// wasm: true +// ---- +// Text: +// (module +// (memory $memory (export "memory") 1) +// +// (func $not_main +// (block $label_ +// (drop (i64.add (i64.const 0) (i64.const 1))) +// ) +// ) +// +// ) +// +// Binary: +// 0061736d01000000010401600000020100030201000503010001060100070a01066d656d6f727902000a0801060002401a0b0b diff --git a/test/libyul/objectCompiler/wasm/simple.yul b/test/libyul/objectCompiler/wasm/simple.yul new file mode 100644 index 000000000..db3f0038e --- /dev/null +++ b/test/libyul/objectCompiler/wasm/simple.yul @@ -0,0 +1,23 @@ +{ + function main() { + i64.drop(i64.add(0, 1)) + } +} +// ==== +// wasm: true +// ---- +// Text: +// (module +// (memory $memory (export "memory") 1) +// (export "main" (func $main)) +// +// (func $main +// (block $label_ +// (drop (i64.add (i64.const 0) (i64.const 1))) +// ) +// ) +// +// ) +// +// Binary: +// 0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0801060002401a0b0b diff --git a/test/libyul/objectCompiler/wasm/subObject.yul b/test/libyul/objectCompiler/wasm/subObject.yul new file mode 100644 index 000000000..22c20abbf --- /dev/null +++ b/test/libyul/objectCompiler/wasm/subObject.yul @@ -0,0 +1,19 @@ +object "a" { + code {} + // Unreferenced data is not added to the assembled bytecode. + data "str" "Hello, World!" + object "sub" { code { function main() { i64.drop(11) } } } +} +// ==== +// wasm: true +// ---- +// Text: +// (module +// ;; sub-module "sub" will be encoded as custom section in binary here, but is skipped in text mode. +// ;; custom-section "str" will be encoded as custom section in binary here, but is skipped in text mode. +// (memory $memory (export "memory") 1) +// +// ) +// +// Binary: +// 0061736d010000000101000201000301000503010001060100070a01066d656d6f72790200003e037375620061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0801060002401a0b0b00110373747248656c6c6f2c20576f726c64210a0100 diff --git a/test/libyul/objectCompiler/wasm/subObjectAccess.yul b/test/libyul/objectCompiler/wasm/subObjectAccess.yul new file mode 100644 index 000000000..ad0f25cc3 --- /dev/null +++ b/test/libyul/objectCompiler/wasm/subObjectAccess.yul @@ -0,0 +1,76 @@ +object "A" { + code { + function main() { + // TODO: support this + // i64.drop(dataoffset("A")) + // i64.drop(datasize("A")) + i64.drop(dataoffset("B")) + i64.drop(datasize("B")) + // TODO: support sub-subobjects + // i64.drop(dataoffset("B.C")) + // i64.drop(datasize("B.C")) + // i64.drop(dataoffset("B.E")) + // i64.drop(datasize("B.E")) + // i64.drop(dataoffset("B.C.D")) + // i64.drop(datasize("B.C.D")) + } + } + + data "data1" "Hello, World!" + + object "B" { + code { + function main() { + i64.drop(dataoffset("C")) + i64.drop(datasize("C")) + i64.drop(dataoffset("E")) + i64.drop(datasize("E")) + // i64.drop(dataoffset("C.D")) + // i64.drop(datasize("C.D")) + } + } + object "C" { + code { + function main() { + i64.drop(dataoffset("D")) + i64.drop(datasize("D")) + } + } + object "D" { + code { + function main() { + unreachable() + } + } + } + } + object "E" { + code { + function main() { + unreachable() + } + } + } + } +} +// ==== +// wasm: true +// ---- +// Text: +// (module +// ;; sub-module "B" will be encoded as custom section in binary here, but is skipped in text mode. +// ;; custom-section "data1" will be encoded as custom section in binary here, but is skipped in text mode. +// (memory $memory (export "memory") 1) +// (export "main" (func $main)) +// +// (func $main +// (block $label_ +// (drop (dataoffset "B")) +// (drop (datasize "B")) +// ) +// ) +// +// ) +// +// Binary: +// 0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e000000fa0101420061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000007b01430061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000003c01440061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0901070002401a1a0b0b003c01450061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0b01090002401a1a1a1a0b0b001305646174613148656c6c6f2c20576f726c64210a0901070002401a1a0b0b From 6f6bcdd5264a73db57c88d1e3c89ed6e0b3c416d Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 9 Nov 2020 21:18:23 +0000 Subject: [PATCH 2/2] [ewasm] Display custom sections as hex string in the text output --- libyul/backends/wasm/TextTransform.cpp | 30 ++++++++++++++----- .../standard_eWasm_requested/output.json | 4 ++- test/libyul/objectCompiler/wasm/subObject.yul | 7 +++-- .../objectCompiler/wasm/subObjectAccess.yul | 7 +++-- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index 05514cd7c..16dc466c3 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -19,10 +19,13 @@ * Component that transforms internal Wasm representation to text. */ +#include #include #include +#include +#include #include #include @@ -39,16 +42,27 @@ using namespace solidity::util; string TextTransform::run(wasm::Module const& _module) { string ret = "(module\n"; - for (auto const& sub: _module.subModules) + for (auto const& [name, module]: _module.subModules) ret += - " ;; sub-module \"" + - sub.first + - "\" will be encoded as custom section in binary here, but is skipped in text mode.\n"; - for (auto const& data: _module.customSections) + " ;; custom section for sub-module\n" + " ;; The Keccak-256 hash of the text representation of \"" + + name + + "\": " + + toHex(keccak256(run(module))) + + "\n" + " ;; (@custom \"" + + name + + "\" \"" + + toHex(BinaryTransform::run(module)) + + "\")\n"; + for (auto const& [name, data]: _module.customSections) ret += - " ;; custom-section \"" + - data.first + - "\" will be encoded as custom section in binary here, but is skipped in text mode.\n"; + " ;; custom section for data\n" + " ;; (@custom \"" + + name + + "\" \"" + + toHex(data) + + "\")\n"; for (wasm::FunctionImport const& imp: _module.imports) { ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName; diff --git a/test/cmdlineTests/standard_eWasm_requested/output.json b/test/cmdlineTests/standard_eWasm_requested/output.json index a3885d128..f7a0debaa 100644 --- a/test/cmdlineTests/standard_eWasm_requested/output.json +++ b/test/cmdlineTests/standard_eWasm_requested/output.json @@ -1,5 +1,7 @@ {"contracts":{"A":{"C":{"ewasm":{"wast":"(module - ;; sub-module \"C_2_deployed\" will be encoded as custom section in binary here, but is skipped in text mode. + ;; custom section for sub-module + ;; The Keccak-256 hash of the text representation of \"C_2_deployed\": f03f5b9154b9eb6803a947177e38e92e2860de95e90ba0e75eb71a58f18ed589 + ;; (@custom \"C_2_deployed\" \"0061736d0100000001160460000060017e017e60047e7e7e7e017f60027f7f0002130108657468657265756d067265766572740003030504000201010503010001060100071102066d656d6f72790200046d61696e00010ab60204ca0104017e027f057e037f02404200210020002000200042c00010022101200141c0006a210220022001490440000b20001003421086210320032000421088100384422086210420042000422088100484210520022005370000200241086a2005370000200241106a20053700004280011003421086210620064280014210881003844220862107200241186a2007428001422088100484370000200020002000200010022108200020002000200010022109200941c0006a210a200a2009490440000b200a200810000b0b2901017f024042002000200184200284520440000b42002003422088520440000b2003a721040b20040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100342108621022002200042108810038421010b20010b\") (import \"ethereum\" \"codeCopy\" (func $eth.codeCopy (param i32 i32 i32))) (import \"ethereum\" \"revert\" (func $eth.revert (param i32 i32))) (import \"ethereum\" \"getCallValue\" (func $eth.getCallValue (param i32))) diff --git a/test/libyul/objectCompiler/wasm/subObject.yul b/test/libyul/objectCompiler/wasm/subObject.yul index 22c20abbf..e9252fbe2 100644 --- a/test/libyul/objectCompiler/wasm/subObject.yul +++ b/test/libyul/objectCompiler/wasm/subObject.yul @@ -9,8 +9,11 @@ object "a" { // ---- // Text: // (module -// ;; sub-module "sub" will be encoded as custom section in binary here, but is skipped in text mode. -// ;; custom-section "str" will be encoded as custom section in binary here, but is skipped in text mode. +// ;; custom section for sub-module +// ;; The Keccak-256 hash of the text representation of "sub": 78ac3419d75c8d6f42f663717b8e964eeb994d77ff175145133084422dbd23d7 +// ;; (@custom "sub" "0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0801060002401a0b0b") +// ;; custom section for data +// ;; (@custom "str" "48656c6c6f2c20576f726c6421") // (memory $memory (export "memory") 1) // // ) diff --git a/test/libyul/objectCompiler/wasm/subObjectAccess.yul b/test/libyul/objectCompiler/wasm/subObjectAccess.yul index ad0f25cc3..ca85655de 100644 --- a/test/libyul/objectCompiler/wasm/subObjectAccess.yul +++ b/test/libyul/objectCompiler/wasm/subObjectAccess.yul @@ -58,8 +58,11 @@ object "A" { // ---- // Text: // (module -// ;; sub-module "B" will be encoded as custom section in binary here, but is skipped in text mode. -// ;; custom-section "data1" will be encoded as custom section in binary here, but is skipped in text mode. +// ;; custom section for sub-module +// ;; The Keccak-256 hash of the text representation of "B": 1eeffe5bc8d8819350ead60cc71ccd92c223cf52a908330db53461eb9ac89b62 +// ;; (@custom "B" "0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000007b01430061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e0000003c01440061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0901070002401a1a0b0b003c01450061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a080106000240000b0b0a0b01090002401a1a1a1a0b0b") +// ;; custom section for data +// ;; (@custom "data1" "48656c6c6f2c20576f726c6421") // (memory $memory (export "memory") 1) // (export "main" (func $main)) //