From 321e971eb3a460b745a4cadfec46b794f7569d12 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Tue, 29 Sep 2020 19:23:47 -0500 Subject: [PATCH] [ewasm] Add support for hera debugging module. --- libyul/backends/wasm/WasmCodeTransform.cpp | 43 +++++++----- libyul/backends/wasm/WasmCodeTransform.h | 7 ++ libyul/backends/wasm/WasmDialect.cpp | 77 ++++++++++++---------- libyul/backends/wasm/WasmDialect.h | 2 +- 4 files changed, 75 insertions(+), 54 deletions(-) diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index b6bc026a4..2aaa0473a 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -118,28 +118,35 @@ wasm::Expression WasmCodeTransform::operator()(yul::ExpressionStatement const& _ return visitReturnByValue(_statement.expression); } +void WasmCodeTransform::importBuiltinFunction(BuiltinFunction const* _builtin, string const& _module, string const& _externalName, string const& _internalName) +{ + yulAssert(_builtin, ""); + yulAssert(_builtin->returns.size() <= 1, ""); + // Imported function, use regular call, but mark for import. + YulString internalName(_internalName); + if (!m_functionsToImport.count(internalName)) + { + wasm::FunctionImport imp{ + _module, + _externalName, + _internalName, + {}, + _builtin->returns.empty() ? nullopt : make_optional(translatedType(_builtin->returns.front())) + }; + for (auto const& param: _builtin->parameters) + imp.paramTypes.emplace_back(translatedType(param)); + m_functionsToImport[internalName] = move(imp); + } +} + wasm::Expression WasmCodeTransform::operator()(yul::FunctionCall const& _call) { if (BuiltinFunction const* builtin = m_dialect.builtin(_call.functionName.name)) { - if (_call.functionName.name.str().substr(0, 4) == "eth.") - { - yulAssert(builtin->returns.size() <= 1, ""); - // Imported function, use regular call, but mark for import. - if (!m_functionsToImport.count(builtin->name)) - { - wasm::FunctionImport imp{ - "ethereum", - builtin->name.str().substr(4), - builtin->name.str(), - {}, - builtin->returns.empty() ? nullopt : make_optional(translatedType(builtin->returns.front())) - }; - for (auto const& param: builtin->parameters) - imp.paramTypes.emplace_back(translatedType(param)); - m_functionsToImport[builtin->name] = std::move(imp); - } - } + if (_call.functionName.name.str().substr(0, 6) == "debug.") + importBuiltinFunction(builtin, "debug", builtin->name.str().substr(6), builtin->name.str()); + else if (_call.functionName.name.str().substr(0, 4) == "eth.") + importBuiltinFunction(builtin, "ethereum", builtin->name.str().substr(4), builtin->name.str()); else { vector arguments; diff --git a/libyul/backends/wasm/WasmCodeTransform.h b/libyul/backends/wasm/WasmCodeTransform.h index 1e9f1fd9c..98b761e8d 100644 --- a/libyul/backends/wasm/WasmCodeTransform.h +++ b/libyul/backends/wasm/WasmCodeTransform.h @@ -85,6 +85,13 @@ private: wasm::FunctionDefinition translateFunction(yul::FunctionDefinition const& _funDef); + /// Imports an external function into the current module. + /// @param _builtin _builtin the builtin that will be imported into the current module. + /// @param _module _module the module name under which the external function can be found. + /// @param _externalName the name of the external function within the module _module. + /// @param _internalName the name of the internal function under that the external function is accessible. + void importBuiltinFunction(BuiltinFunction const* _builtin, std::string const& _module, std::string const& _externalName, std::string const& _internalName); + std::string newLabel(); /// Selects a subset of global variables matching specified sequence of variable types. /// Defines more global variables of a given type if there's not enough. diff --git a/libyul/backends/wasm/WasmDialect.cpp b/libyul/backends/wasm/WasmDialect.cpp index eb2d1712c..8249007c8 100644 --- a/libyul/backends/wasm/WasmDialect.cpp +++ b/libyul/backends/wasm/WasmDialect.cpp @@ -135,7 +135,7 @@ WasmDialect::WasmDialect() addFunction("datasize", {i64}, {i64}, true, {LiteralKind::String}); addFunction("dataoffset", {i64}, {i64}, true, {LiteralKind::String}); - addEthereumExternals(); + addExternals(); } BuiltinFunction const* WasmDialect::builtin(YulString _name) const @@ -172,7 +172,7 @@ WasmDialect const& WasmDialect::instance() return *dialect; } -void WasmDialect::addEthereumExternals() +void WasmDialect::addExternals() { // These are not YulStrings because that would be too complicated with regards // to the YulStringRepository reset. @@ -181,48 +181,55 @@ void WasmDialect::addEthereumExternals() static string const i32ptr{"i32"}; // Uses "i32" on purpose. struct External { + string module; string name; vector parameters; vector returns; ControlFlowSideEffects controlFlowSideEffects = ControlFlowSideEffects{}; }; static vector externals{ - {"getAddress", {i32ptr}, {}}, - {"getExternalBalance", {i32ptr, i32ptr}, {}}, - {"getBlockHash", {i64, i32ptr}, {i32}}, - {"call", {i64, i32ptr, i32ptr, i32ptr, i32}, {i32}}, - {"callDataCopy", {i32ptr, i32, i32}, {}}, - {"getCallDataSize", {}, {i32}}, - {"callCode", {i64, i32ptr, i32ptr, i32ptr, i32}, {i32}}, - {"callDelegate", {i64, i32ptr, i32ptr, i32}, {i32}}, - {"callStatic", {i64, i32ptr, i32ptr, i32}, {i32}}, - {"storageStore", {i32ptr, i32ptr}, {}}, - {"storageLoad", {i32ptr, i32ptr}, {}}, - {"getCaller", {i32ptr}, {}}, - {"getCallValue", {i32ptr}, {}}, - {"codeCopy", {i32ptr, i32, i32}, {}}, - {"getCodeSize", {}, {i32}}, - {"getBlockCoinbase", {i32ptr}, {}}, - {"create", {i32ptr, i32ptr, i32, i32ptr}, {i32}}, - {"getBlockDifficulty", {i32ptr}, {}}, - {"externalCodeCopy", {i32ptr, i32ptr, i32, i32}, {}}, - {"getExternalCodeSize", {i32ptr}, {i32}}, - {"getGasLeft", {}, {i64}}, - {"getBlockGasLimit", {}, {i64}}, - {"getTxGasPrice", {i32ptr}, {}}, - {"log", {i32ptr, i32, i32, i32ptr, i32ptr, i32ptr, i32ptr}, {}}, - {"getBlockNumber", {}, {i64}}, - {"getTxOrigin", {i32ptr}, {}}, - {"finish", {i32ptr, i32}, {}, ControlFlowSideEffects{true, false}}, - {"revert", {i32ptr, i32}, {}, ControlFlowSideEffects{true, true}}, - {"getReturnDataSize", {}, {i32}}, - {"returnDataCopy", {i32ptr, i32, i32}, {}}, - {"selfDestruct", {i32ptr}, {}, ControlFlowSideEffects{true, false}}, - {"getBlockTimestamp", {}, {i64}} + {"eth", "getAddress", {i32ptr}, {}}, + {"eth", "getExternalBalance", {i32ptr, i32ptr}, {}}, + {"eth", "getBlockHash", {i64, i32ptr}, {i32}}, + {"eth", "call", {i64, i32ptr, i32ptr, i32ptr, i32}, {i32}}, + {"eth", "callDataCopy", {i32ptr, i32, i32}, {}}, + {"eth", "getCallDataSize", {}, {i32}}, + {"eth", "callCode", {i64, i32ptr, i32ptr, i32ptr, i32}, {i32}}, + {"eth", "callDelegate", {i64, i32ptr, i32ptr, i32}, {i32}}, + {"eth", "callStatic", {i64, i32ptr, i32ptr, i32}, {i32}}, + {"eth", "storageStore", {i32ptr, i32ptr}, {}}, + {"eth", "storageLoad", {i32ptr, i32ptr}, {}}, + {"eth", "getCaller", {i32ptr}, {}}, + {"eth", "getCallValue", {i32ptr}, {}}, + {"eth", "codeCopy", {i32ptr, i32, i32}, {}}, + {"eth", "getCodeSize", {}, {i32}}, + {"eth", "getBlockCoinbase", {i32ptr}, {}}, + {"eth", "create", {i32ptr, i32ptr, i32, i32ptr}, {i32}}, + {"eth", "getBlockDifficulty", {i32ptr}, {}}, + {"eth", "externalCodeCopy", {i32ptr, i32ptr, i32, i32}, {}}, + {"eth", "getExternalCodeSize", {i32ptr}, {i32}}, + {"eth", "getGasLeft", {}, {i64}}, + {"eth", "getBlockGasLimit", {}, {i64}}, + {"eth", "getTxGasPrice", {i32ptr}, {}}, + {"eth", "log", {i32ptr, i32, i32, i32ptr, i32ptr, i32ptr, i32ptr}, {}}, + {"eth", "getBlockNumber", {}, {i64}}, + {"eth", "getTxOrigin", {i32ptr}, {}}, + {"eth", "finish", {i32ptr, i32}, {}, ControlFlowSideEffects{true, false}}, + {"eth", "revert", {i32ptr, i32}, {}, ControlFlowSideEffects{true, true}}, + {"eth", "getReturnDataSize", {}, {i32}}, + {"eth", "returnDataCopy", {i32ptr, i32, i32}, {}}, + {"eth", "selfDestruct", {i32ptr}, {}, ControlFlowSideEffects{true, false}}, + {"eth", "getBlockTimestamp", {}, {i64}}, + {"debug", "print32", {i32}, {}}, + {"debug", "print64", {i64}, {}}, + {"debug", "printMem", {i32, i32}, {}}, + {"debug", "printMemHex", {i32, i32}, {}}, + {"debug", "printStorage", {i32}, {}}, + {"debug", "printStorageHex", {i32}, {}}, }; for (External const& ext: externals) { - YulString name{"eth." + ext.name}; + YulString name{ext.module + "." + ext.name}; BuiltinFunction& f = m_functions[name]; f.name = name; for (string const& p: ext.parameters) diff --git a/libyul/backends/wasm/WasmDialect.h b/libyul/backends/wasm/WasmDialect.h index 5abc69fc4..2776c14e7 100644 --- a/libyul/backends/wasm/WasmDialect.h +++ b/libyul/backends/wasm/WasmDialect.h @@ -55,7 +55,7 @@ struct WasmDialect: public Dialect static WasmDialect const& instance(); private: - void addEthereumExternals(); + void addExternals(); void addFunction( std::string _name,