diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 12c7be230..b5c99ad6d 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -203,7 +203,7 @@ void Assembly::assemblyStream( for (size_t i = 0; i < m_subs.size(); ++i) { _out << endl << _prefix << "sub_" << i << ": assembly {\n"; - m_subs[i]->assemblyStream(_out, _debugInfoSelection, _prefix + " ", _sourceCodes); + m_subs[i].first->assemblyStream(_out, _debugInfoSelection, _prefix + " ", _sourceCodes); _out << _prefix << "}" << endl; } } @@ -352,7 +352,7 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices) { std::stringstream hexStr; hexStr << hex << i; - data[hexStr.str()] = m_subs[i]->assemblyJSON(_sourceIndices); + data[hexStr.str()] = m_subs[i].first->assemblyJSON(_sourceIndices); } } @@ -435,9 +435,8 @@ map const& Assembly::optimiseInternal( for (size_t subId = 0; subId < m_subs.size(); ++subId) { OptimiserSettings settings = _settings; - // Disable creation mode for sub-assemblies. - settings.isCreation = false; - map const& subTagReplacements = m_subs[subId]->optimiseInternal( + settings.isCreation = m_subs[subId].second; + map const& subTagReplacements = m_subs[subId].first->optimiseInternal( settings, JumpdestRemover::referencedTags(m_items, subId) ); @@ -582,7 +581,7 @@ LinkerObject const& Assembly::assemble() const map>> immutableReferencesBySub; for (auto const& sub: m_subs) { - auto const& linkerObject = sub->assemble(); + auto const& linkerObject = sub.first->assemble(); if (!linkerObject.immutableReferences.empty()) { assertThrow( @@ -592,7 +591,7 @@ LinkerObject const& Assembly::assemble() const ); immutableReferencesBySub = linkerObject.immutableReferences; } - for (size_t tagPos: sub->m_tagPositionsInBytecode) + for (size_t tagPos: sub.first->m_tagPositionsInBytecode) if (tagPos != numeric_limits::max() && tagPos > subTagSize) subTagSize = tagPos; } @@ -626,7 +625,7 @@ LinkerObject const& Assembly::assemble() const unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + static_cast(m_auxiliaryData.size()); for (auto const& sub: m_subs) - bytesRequiredIncludingData += static_cast(sub->assemble().bytecode.size()); + bytesRequiredIncludingData += static_cast(sub.first->assemble().bytecode.size()); unsigned bytesPerDataRef = numberEncodingSize(bytesRequiredIncludingData); uint8_t dataRefPush = static_cast(pushInstruction(bytesPerDataRef)); @@ -780,7 +779,7 @@ LinkerObject const& Assembly::assemble() const vector const& tagPositions = subId == numeric_limits::max() ? m_tagPositionsInBytecode : - m_subs[subId]->m_tagPositionsInBytecode; + m_subs[subId].first->m_tagPositionsInBytecode; assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag."); size_t pos = tagPositions[tagId]; assertThrow(pos != numeric_limits::max(), AssemblyException, "Reference to tag without position."); @@ -870,7 +869,7 @@ Assembly const* Assembly::subAssemblyById(size_t _subId) const Assembly const* currentAssembly = this; for (size_t currentSubId: subIds) { - currentAssembly = currentAssembly->m_subs.at(currentSubId).get(); + currentAssembly = currentAssembly->m_subs.at(currentSubId).first.get(); assertThrow(currentAssembly, AssemblyException, ""); } diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index f768ffe31..374fc55de 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -56,9 +56,9 @@ public: AssemblyItem namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional _sourceID); AssemblyItem newData(bytes const& _data) { util::h256 h(util::keccak256(util::asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); } bytes const& data(util::h256 const& _i) const { return m_data.at(_i); } - 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); } + AssemblyItem newSub(AssemblyPointer const& _sub, bool _creation) { m_subs.emplace_back(_sub, _creation); return AssemblyItem(PushSub, m_subs.size() - 1); } + Assembly const& sub(size_t _sub) const { return *m_subs.at(_sub).first; } + Assembly& sub(size_t _sub) { return *m_subs.at(_sub).first; } size_t numSubs() const { return m_subs.size(); } AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem newPushLibraryAddress(std::string const& _identifier); @@ -89,7 +89,7 @@ public: /// Adds a subroutine to the code (in the data section) and pushes its size (via a tag) /// on the stack. @returns the pushsub assembly item. - AssemblyItem appendSubroutine(AssemblyPointer const& _assembly) { auto sub = newSub(_assembly); append(newPushSubSize(size_t(sub.data()))); return sub; } + AssemblyItem appendSubroutine(AssemblyPointer const& _assembly, bool _creation) { auto sub = newSub(_assembly, _creation); append(newPushSubSize(size_t(sub.data()))); return sub; } void pushSubroutineSize(size_t _subRoutine) { append(newPushSubSize(_subRoutine)); } /// Pushes the offset of the subroutine. void pushSubroutineOffset(size_t _subRoutine) { append(AssemblyItem(PushSub, _subRoutine)); } @@ -204,7 +204,7 @@ protected: std::map m_data; /// Data that is appended to the very end of the contract. bytes m_auxiliaryData; - std::vector> m_subs; + std::vector, bool>> m_subs; std::map m_strings; std::map m_libraries; ///< Identifiers of libraries to be linked. std::map m_immutables; ///< Identifiers of immutables. diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index cd71d5a4d..ee53c7d75 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -74,7 +74,7 @@ public: m_yulUtilFunctions(m_evmVersion, m_revertStrings, m_yulFunctionCollector) { if (m_runtimeContext) - m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data()); + m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm, false).data()); } langutil::EVMVersion const& evmVersion() const { return m_evmVersion; } @@ -224,7 +224,7 @@ public: } /// Adds a subroutine to the code (in the data section) and pushes its size (via a tag) /// on the stack. @returns the pushsub assembly item. - evmasm::AssemblyItem addSubroutine(evmasm::AssemblyPointer const& _assembly) { return m_asm->appendSubroutine(_assembly); } + evmasm::AssemblyItem addSubroutine(evmasm::AssemblyPointer const& _assembly, bool _creation) { return m_asm->appendSubroutine(_assembly, _creation); } /// Pushes the size of the subroutine. void pushSubroutineSize(size_t _subRoutine) { m_asm->pushSubroutineSize(_subRoutine); } /// Pushes the offset of the subroutine. diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 0ad37241b..73e2fe8d7 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1521,7 +1521,7 @@ void CompilerUtils::copyContractCodeToMemory(ContractDefinition const& contract, _context.compiledContract(contract) : _context.compiledContractRuntime(contract); // pushes size - auto subroutine = _context.addSubroutine(assembly); + auto subroutine = _context.addSubroutine(assembly, _creation); _context << Instruction::DUP1 << subroutine; _context << Instruction::DUP4 << Instruction::CODECOPY; _context << Instruction::ADD; diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 30ad58d77..82365d54d 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -37,9 +37,13 @@ #include #include + #include + +#include #include + using namespace std; using namespace solidity; using namespace solidity::yul; @@ -194,7 +198,11 @@ void AssemblyStack::optimize(Object& _object, bool _isCreation) yulAssert(_object.analysisInfo, ""); for (auto& subNode: _object.subObjects) if (auto subObject = dynamic_cast(subNode.get())) - optimize(*subObject, false); + { + // TODO: determine this more properly, resp. store it earlier when the subobject is created + bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed"); + optimize(*subObject, isCreation); + } Dialect const& dialect = languageToDialect(m_language, m_evmVersion); unique_ptr meter; diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 66d5333e2..671554dbb 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -98,7 +98,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(std::string _name = "") = 0; + virtual std::pair, SubID> createSubAssembly(std::string _name, bool _creation) = 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/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index bede32d17..3868f9247 100644 --- a/libyul/backends/evm/EVMObjectCompiler.cpp +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -28,6 +28,8 @@ #include #include +#include + using namespace solidity::yul; using namespace std; @@ -46,7 +48,9 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) for (auto const& subNode: _object.subObjects) if (auto* subObject = dynamic_cast(subNode.get())) { - auto subAssemblyAndID = m_assembly.createSubAssembly(subObject->name.str()); + // TODO: determine this more properly, resp. store it earlier when the subobject is created + bool isCreation = !boost::ends_with(subObject->name.str(), "_deployed"); + auto subAssemblyAndID = m_assembly.createSubAssembly(subObject->name.str(), isCreation); context.subIDs[subObject->name] = subAssemblyAndID.second; subObject->subId = subAssemblyAndID.second; compile(*subObject, *subAssemblyAndID.first, m_dialect, _optimize); diff --git a/libyul/backends/evm/EthAssemblyAdapter.cpp b/libyul/backends/evm/EthAssemblyAdapter.cpp index 1c41534b2..1beeb6f7e 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.cpp +++ b/libyul/backends/evm/EthAssemblyAdapter.cpp @@ -122,10 +122,10 @@ void EthAssemblyAdapter::appendAssemblySize() m_assembly.appendProgramSize(); } -pair, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name) +pair, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name, bool _creation) { shared_ptr assembly{make_shared(std::move(_name))}; - auto sub = m_assembly.newSub(assembly); + auto sub = m_assembly.newSub(assembly, _creation); return {make_shared(*assembly), static_cast(sub.data())}; } diff --git a/libyul/backends/evm/EthAssemblyAdapter.h b/libyul/backends/evm/EthAssemblyAdapter.h index c11b375f6..dc83ac463 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.h +++ b/libyul/backends/evm/EthAssemblyAdapter.h @@ -55,7 +55,7 @@ public: void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override; void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; void appendAssemblySize() override; - std::pair, SubID> createSubAssembly(std::string _name = {}) override; + std::pair, SubID> createSubAssembly(std::string _name, bool _creation) 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/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index 62c0ad119..8ad9f05e1 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -98,7 +98,7 @@ void NoOutputAssembly::appendAssemblySize() appendInstruction(evmasm::Instruction::PUSH1); } -pair, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(std::string) +pair, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(std::string, bool) { yulAssert(false, "Sub assemblies not implemented."); return {}; diff --git a/libyul/backends/evm/NoOutputAssembly.h b/libyul/backends/evm/NoOutputAssembly.h index b41d7f4a6..945600b21 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -65,7 +65,7 @@ public: void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override; void appendAssemblySize() override; - std::pair, SubID> createSubAssembly(std::string _name = "") override; + std::pair, SubID> createSubAssembly(std::string _name, bool _creation) override; void appendDataOffset(std::vector const& _subPath) override; void appendDataSize(std::vector const& _subPath) override; SubID appendData(bytes const& _data) override; diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index 78e598bca..02f27fdd0 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) // PushData _assembly.append(bytes{0x1, 0x2, 0x3, 0x4}); // PushSubSize - auto sub = _assembly.appendSubroutine(_subAsmPtr); + auto sub = _assembly.appendSubroutine(_subAsmPtr, false); // PushSub _assembly.pushSubroutineOffset(static_cast(sub.data())); // PushDeployTimeAddress @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps) assembly.appendImmutableAssignment(string(1, char('a' + i - 1))); } - assembly.appendSubroutine(subAsm); + assembly.appendSubroutine(subAsm, false); checkCompilation(assembly); @@ -275,7 +275,7 @@ BOOST_AUTO_TEST_CASE(immutable) _assembly.append(u256(0)); _assembly.appendImmutableAssignment("someOtherImmutable"); - auto sub = _assembly.appendSubroutine(_subAsmPtr); + auto sub = _assembly.appendSubroutine(_subAsmPtr, false); _assembly.pushSubroutineOffset(static_cast(sub.data())); checkCompilation(_assembly); @@ -354,8 +354,8 @@ BOOST_AUTO_TEST_CASE(subobject_encode_decode) shared_ptr subAsmPtr = make_shared(); shared_ptr subSubAsmPtr = make_shared(); - assembly.appendSubroutine(subAsmPtr); - subAsmPtr->appendSubroutine(subSubAsmPtr); + assembly.appendSubroutine(subAsmPtr, false); + subAsmPtr->appendSubroutine(subSubAsmPtr, false); BOOST_CHECK(assembly.encodeSubPath({0}) == 0); BOOST_REQUIRE_THROW(assembly.encodeSubPath({1}), solidity::evmasm::AssemblyException); diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index c8bb93c41..a31bee9e7 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -1272,7 +1272,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies) sub->append(t4.pushTag()); sub->append(Instruction::JUMP); - size_t subId = static_cast(main.appendSubroutine(sub).data()); + size_t subId = static_cast(main.appendSubroutine(sub, false).data()); main.append(t1.toSubAssemblyTag(subId)); main.append(t1.toSubAssemblyTag(subId)); main.append(u256(8));