From f92a4f1965429de364ce4fd3f7671f41ff239e3c Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 12 May 2020 16:33:05 +0200 Subject: [PATCH] Provide runtime object in Yul mode. --- libevmasm/Assembly.h | 1 + libsolidity/interface/StandardCompiler.cpp | 32 ++++++++--- libyul/AssemblyStack.cpp | 57 +++++++++++++------ libyul/AssemblyStack.h | 6 ++ .../standard_yul_object_name/output.json | 2 +- 5 files changed, 72 insertions(+), 26 deletions(-) diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index e9e3630a8..27d825268 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -52,6 +52,7 @@ public: AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); } Assembly const& sub(size_t _sub) const { return *m_subs.at(_sub); } Assembly& sub(size_t _sub) { return *m_subs.at(_sub); } + size_t numSubs() const { return m_subs.size(); } AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem newPushLibraryAddress(std::string const& _identifier); AssemblyItem newPushImmutable(std::string const& _identifier); diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 0abc867e8..6cf13c309 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -1127,16 +1128,29 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) stack.optimize(); - MachineAssemblyObject object = stack.assemble(AssemblyStack::Machine::EVM); + MachineAssemblyObject object; + MachineAssemblyObject runtimeObject; + tie(object, runtimeObject) = stack.assembleAndGuessRuntime(); - if (isArtifactRequested( - _inputsAndSettings.outputSelection, - sourceName, - contractName, - { "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" }, - wildcardMatchesExperimental - )) - output["contracts"][sourceName][contractName]["evm"]["bytecode"] = collectEVMObject(*object.bytecode, object.sourceMappings.get(), false); + for (string const& objectKind: vector{"bytecode", "deployedBytecode"}) + { + auto artifacts = util::applyMap( + vector{"", ".object", ".opcodes", ".sourceMap", ".linkReferences"}, + [&](auto const& _s) { return "evm." + objectKind + _s; } + ); + if (isArtifactRequested( + _inputsAndSettings.outputSelection, + sourceName, + contractName, + artifacts, + wildcardMatchesExperimental + )) + { + MachineAssemblyObject const& o = objectKind == "bytecode" ? object : runtimeObject; + if (o.bytecode) + output["contracts"][sourceName][contractName]["evm"][objectKind] = collectEVMObject(*o.bytecode, o.sourceMappings.get(), false); + } + } if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "irOptimized", wildcardMatchesExperimental)) output["contracts"][sourceName][contractName]["irOptimized"] = stack.print(); diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 3988bc3fd..e0ff93939 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -198,22 +198,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const switch (_machine) { case Machine::EVM: - { - MachineAssemblyObject object; - evmasm::Assembly assembly; - EthAssemblyAdapter adapter(assembly); - compileEVM(adapter, false, m_optimiserSettings.optimizeStackAllocation); - object.bytecode = make_shared(assembly.assemble()); - yulAssert(object.bytecode->immutableReferences.empty(), "Leftover immutables."); - object.assembly = assembly.assemblyString(); - object.sourceMappings = make_unique( - evmasm::AssemblyItem::computeSourceMapping( - assembly.items(), - {{scanner().charStream() ? scanner().charStream()->name() : "", 0}} - ) - ); - return object; - } + return assembleAndGuessRuntime().first; case Machine::EVM15: { MachineAssemblyObject object; @@ -240,6 +225,46 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const return MachineAssemblyObject(); } +pair AssemblyStack::assembleAndGuessRuntime() const +{ + yulAssert(m_analysisSuccessful, ""); + yulAssert(m_parserResult, ""); + yulAssert(m_parserResult->code, ""); + yulAssert(m_parserResult->analysisInfo, ""); + + evmasm::Assembly assembly; + EthAssemblyAdapter adapter(assembly); + compileEVM(adapter, false, m_optimiserSettings.optimizeStackAllocation); + + MachineAssemblyObject creationObject; + creationObject.bytecode = make_shared(assembly.assemble()); + yulAssert(creationObject.bytecode->immutableReferences.empty(), "Leftover immutables."); + creationObject.assembly = assembly.assemblyString(); + creationObject.sourceMappings = make_unique( + evmasm::AssemblyItem::computeSourceMapping( + assembly.items(), + {{scanner().charStream() ? scanner().charStream()->name() : "", 0}} + ) + ); + + MachineAssemblyObject runtimeObject; + // Heuristic: If there is a single sub-assembly, this is likely the runtime object. + if (assembly.numSubs() == 1) + { + evmasm::Assembly& runtimeAssembly = assembly.sub(0); + runtimeObject.bytecode = make_shared(runtimeAssembly.assemble()); + runtimeObject.assembly = runtimeAssembly.assemblyString(); + runtimeObject.sourceMappings = make_unique( + evmasm::AssemblyItem::computeSourceMapping( + runtimeAssembly.items(), + {{scanner().charStream() ? scanner().charStream()->name() : "", 0}} + ) + ); + } + return {std::move(creationObject), std::move(runtimeObject)}; + +} + string AssemblyStack::print() const { yulAssert(m_parserResult, ""); diff --git a/libyul/AssemblyStack.h b/libyul/AssemblyStack.h index 60efd9674..f9d235505 100644 --- a/libyul/AssemblyStack.h +++ b/libyul/AssemblyStack.h @@ -88,6 +88,12 @@ public: /// Run the assembly step (should only be called after parseAndAnalyze). MachineAssemblyObject assemble(Machine _machine) const; + /// Run the assembly step (should only be called after parseAndAnalyze). + /// In addition to the value returned by @a assemble, returns + /// a second object that is guessed to be the runtime code. + /// Only available for EVM. + std::pair assembleAndGuessRuntime() const; + /// @returns the errors generated during parsing, analysis (and potentially assembly). langutil::ErrorList const& errors() const { return m_errors; } diff --git a/test/cmdlineTests/standard_yul_object_name/output.json b/test/cmdlineTests/standard_yul_object_name/output.json index 2fdd9bc11..58d78b3a9 100644 --- a/test/cmdlineTests/standard_yul_object_name/output.json +++ b/test/cmdlineTests/standard_yul_object_name/output.json @@ -22,7 +22,7 @@ sub_0: assembly { /* \"A\":137:149 */ revert } -","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"NamedObject\" { +","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"},"deployedBytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"NamedObject\" { code { let x := dataoffset(\"DataName\") sstore(add(x, 0), 0)