From e4f1257c83f6b320eed40853aea349d01380d8ba Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Wed, 3 Feb 2021 11:47:16 +0100 Subject: [PATCH] Yul Backend: Get rid of heuristics for finding the matching runtime --- libevmasm/Assembly.h | 6 ++++ libsolidity/interface/CompilerStack.cpp | 2 +- libsolidity/interface/StandardCompiler.cpp | 2 +- libyul/AssemblyStack.cpp | 37 ++++++++++++++++------ libyul/AssemblyStack.h | 6 ++++ libyul/backends/evm/AbstractAssembly.h | 2 +- libyul/backends/evm/AsmCodeGen.cpp | 4 +-- libyul/backends/evm/AsmCodeGen.h | 2 +- libyul/backends/evm/EVMAssembly.cpp | 2 +- libyul/backends/evm/EVMAssembly.h | 2 +- libyul/backends/evm/EVMObjectCompiler.cpp | 3 +- libyul/backends/evm/NoOutputAssembly.cpp | 2 +- libyul/backends/evm/NoOutputAssembly.h | 2 +- 13 files changed, 51 insertions(+), 21 deletions(-) diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 354304dcb..893cab955 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -44,6 +44,8 @@ using AssemblyPointer = std::shared_ptr; class Assembly { public: + explicit Assembly(std::string _name = std::string()):m_name(std::move(_name)) { } + AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, m_usedTags++); } /// Returns a tag identified by the given name. Creates it if it does not yet exist. @@ -95,6 +97,7 @@ public: int deposit() const { return m_deposit; } void adjustDeposit(int _adjustment) { m_deposit += _adjustment; assertThrow(m_deposit >= 0, InvalidDeposit, ""); } void setDeposit(int _deposit) { m_deposit = _deposit; assertThrow(m_deposit >= 0, InvalidDeposit, ""); } + std::string const& name() const { return m_name; } /// Changes the source location used for each appended item. void setSourceLocation(langutil::SourceLocation const& _location) { m_currentSourceLocation = _location; } @@ -193,6 +196,9 @@ protected: mutable std::vector m_tagPositionsInBytecode; int m_deposit = 0; + /// Internal name of the assembly object, only used with the Yul backend + /// currently + std::string m_name; langutil::SourceLocation m_currentSourceLocation; public: diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 4a0fbbd09..adcc22004 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1302,7 +1302,7 @@ void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract) // TODO: use stack.assemble here! yul::MachineAssemblyObject init; yul::MachineAssemblyObject runtime; - std::tie(init, runtime) = stack.assembleAndGuessRuntime(); + std::tie(init, runtime) = stack.assembleWithDeployed(IRNames::runtimeObject(_contract)); compiledContract.object = std::move(*init.bytecode); compiledContract.runtimeObject = std::move(*runtime.bytecode); // TODO: refactor assemblyItems, runtimeAssemblyItems, generatedSources, diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index eba5f1375..a3ad74b7e 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -1273,7 +1273,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) MachineAssemblyObject object; MachineAssemblyObject runtimeObject; - tie(object, runtimeObject) = stack.assembleAndGuessRuntime(); + tie(object, runtimeObject) = stack.assembleWithDeployed(); if (object.bytecode) object.bytecode->link(_inputsAndSettings.libraries); diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 542de51d9..5de9988a0 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -199,7 +199,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const switch (_machine) { case Machine::EVM: - return assembleAndGuessRuntime().first; + return assembleWithDeployed().first; case Machine::EVM15: { MachineAssemblyObject object; @@ -226,7 +226,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const return MachineAssemblyObject(); } -pair AssemblyStack::assembleAndGuessRuntime() const +std::pair AssemblyStack::assembleWithDeployed(optional _deployName) const { yulAssert(m_analysisSuccessful, ""); yulAssert(m_parserResult, ""); @@ -248,22 +248,39 @@ pair AssemblyStack::assembleAndGue ) ); - MachineAssemblyObject runtimeObject; - // Heuristic: If there is a single sub-assembly, this is likely the runtime object. - if (assembly.numSubs() == 1) + MachineAssemblyObject deployedObject; + optional subIndex; + + // Pick matching assembly if name was given + if (_deployName.has_value()) { - evmasm::Assembly& runtimeAssembly = assembly.sub(0); - runtimeObject.bytecode = make_shared(runtimeAssembly.assemble()); - runtimeObject.assembly = runtimeAssembly.assemblyString(); - runtimeObject.sourceMappings = make_unique( + for (size_t i = 0; i < assembly.numSubs(); i++) + if (assembly.sub(i).name() == _deployName) + { + subIndex = i; + break; + } + + solAssert(subIndex.has_value(), "Failed to find object to be deployed."); + } + // Otherwise use heuristic: If there is a single sub-assembly, this is likely the object to be deployed. + else if (assembly.numSubs() == 1) + subIndex = 0; + + if (subIndex.has_value()) + { + evmasm::Assembly& runtimeAssembly = assembly.sub(*subIndex); + deployedObject.bytecode = make_shared(runtimeAssembly.assemble()); + deployedObject.assembly = runtimeAssembly.assemblyString(); + deployedObject.sourceMappings = make_unique( evmasm::AssemblyItem::computeSourceMapping( runtimeAssembly.items(), {{scanner().charStream() ? scanner().charStream()->name() : "", 0}} ) ); } - return {std::move(creationObject), std::move(runtimeObject)}; + return {std::move(creationObject), std::move(deployedObject)}; } string AssemblyStack::print() const diff --git a/libyul/AssemblyStack.h b/libyul/AssemblyStack.h index 70325208d..ce6175215 100644 --- a/libyul/AssemblyStack.h +++ b/libyul/AssemblyStack.h @@ -95,6 +95,12 @@ public: /// Only available for EVM. std::pair assembleAndGuessRuntime() 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 the runtime code. + /// Only available for EVM. + std::pair assembleWithDeployed(std::optional _deployeName = {}) const; + /// @returns the errors generated during parsing, analysis (and potentially assembly). langutil::ErrorList const& errors() const { return m_errors; } diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index a8327c346..b4b993f77 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -100,7 +100,7 @@ public: /// Append the assembled size as a constant. virtual void appendAssemblySize() = 0; /// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset. - virtual std::pair, SubID> createSubAssembly() = 0; + virtual std::pair, SubID> createSubAssembly(std::string _name = "") = 0; /// Appends the offset of the given sub-assembly or data. virtual void appendDataOffset(std::vector const& _subPath) = 0; /// Appends the size of the given sub-assembly or data. diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index 49665e347..d94a6196c 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -140,9 +140,9 @@ void EthAssemblyAdapter::appendAssemblySize() m_assembly.appendProgramSize(); } -pair, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly() +pair, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name) { - shared_ptr assembly{make_shared()}; + shared_ptr assembly{make_shared(std::move(_name))}; auto sub = m_assembly.newSub(assembly); return {make_shared(*assembly), static_cast(sub.data())}; } diff --git a/libyul/backends/evm/AsmCodeGen.h b/libyul/backends/evm/AsmCodeGen.h index ee56f7fcb..cbbec5c81 100644 --- a/libyul/backends/evm/AsmCodeGen.h +++ b/libyul/backends/evm/AsmCodeGen.h @@ -57,7 +57,7 @@ public: void appendJumpsub(LabelID, int, int) override; void appendReturnsub(int, int) override; void appendAssemblySize() override; - std::pair, SubID> createSubAssembly() override; + std::pair, SubID> createSubAssembly(std::string _name = {}) override; void appendDataOffset(std::vector const& _subPath) override; void appendDataSize(std::vector const& _subPath) override; SubID appendData(bytes const& _data) override; diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index ade8b7e05..ffdde4e81 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -196,7 +196,7 @@ void EVMAssembly::appendAssemblySize() m_bytecode += bytes(assemblySizeReferenceSize); } -pair, AbstractAssembly::SubID> EVMAssembly::createSubAssembly() +pair, AbstractAssembly::SubID> EVMAssembly::createSubAssembly(string) { yulAssert(false, "Sub assemblies not implemented."); return {}; diff --git a/libyul/backends/evm/EVMAssembly.h b/libyul/backends/evm/EVMAssembly.h index 6e6878476..c214e733a 100644 --- a/libyul/backends/evm/EVMAssembly.h +++ b/libyul/backends/evm/EVMAssembly.h @@ -79,7 +79,7 @@ public: /// Append the assembled size as a constant. void appendAssemblySize() override; - std::pair, SubID> createSubAssembly() override; + std::pair, SubID> createSubAssembly(std::string _name = "") override; void appendDataOffset(std::vector const& _subPath) override; void appendDataSize(std::vector const& _subPath) override; SubID appendData(bytes const& _data) override; diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index 5eb83a6a8..72beeaf0b 100644 --- a/libyul/backends/evm/EVMObjectCompiler.cpp +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -42,10 +42,11 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) BuiltinContext context; context.currentObject = &_object; + for (auto const& subNode: _object.subObjects) if (auto* subObject = dynamic_cast(subNode.get())) { - auto subAssemblyAndID = m_assembly.createSubAssembly(); + auto subAssemblyAndID = m_assembly.createSubAssembly(subObject->name.str()); context.subIDs[subObject->name] = subAssemblyAndID.second; subObject->subId = subAssemblyAndID.second; compile(*subObject, *subAssemblyAndID.first, m_dialect, m_evm15, _optimize); diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index 74caf8073..60ce41611 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -127,7 +127,7 @@ void NoOutputAssembly::appendAssemblySize() appendInstruction(evmasm::Instruction::PUSH1); } -pair, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly() +pair, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(std::string) { yulAssert(false, "Sub assemblies not implemented."); return {}; diff --git a/libyul/backends/evm/NoOutputAssembly.h b/libyul/backends/evm/NoOutputAssembly.h index b2153e42a..5934c5fdf 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -67,7 +67,7 @@ public: void appendReturnsub(int _returns, int _stackDiffAfter) override; void appendAssemblySize() override; - std::pair, SubID> createSubAssembly() override; + std::pair, SubID> createSubAssembly(std::string _name = "") override; void appendDataOffset(std::vector const& _subPath) override; void appendDataSize(std::vector const& _subPath) override; SubID appendData(bytes const& _data) override;