mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Store whether a subassembly is creation code and optimize accordingly.
This commit is contained in:
parent
7c91dd05a7
commit
d5b2d94cb7
@ -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<string, unsigned> 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<u256, u256> 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<u256, u256> const& subTagReplacements = m_subs[subId]->optimiseInternal(
|
||||
settings.isCreation = m_subs[subId].second;
|
||||
map<u256, u256> const& subTagReplacements = m_subs[subId].first->optimiseInternal(
|
||||
settings,
|
||||
JumpdestRemover::referencedTags(m_items, subId)
|
||||
);
|
||||
@ -582,7 +581,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
map<u256, pair<string, vector<size_t>>> 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<size_t>::max() && tagPos > subTagSize)
|
||||
subTagSize = tagPos;
|
||||
}
|
||||
@ -626,7 +625,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
|
||||
unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + static_cast<unsigned>(m_auxiliaryData.size());
|
||||
for (auto const& sub: m_subs)
|
||||
bytesRequiredIncludingData += static_cast<unsigned>(sub->assemble().bytecode.size());
|
||||
bytesRequiredIncludingData += static_cast<unsigned>(sub.first->assemble().bytecode.size());
|
||||
|
||||
unsigned bytesPerDataRef = numberEncodingSize(bytesRequiredIncludingData);
|
||||
uint8_t dataRefPush = static_cast<uint8_t>(pushInstruction(bytesPerDataRef));
|
||||
@ -780,7 +779,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
vector<size_t> const& tagPositions =
|
||||
subId == numeric_limits<size_t>::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<size_t>::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, "");
|
||||
}
|
||||
|
||||
|
@ -56,9 +56,9 @@ public:
|
||||
AssemblyItem namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional<uint64_t> _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<util::h256, bytes> m_data;
|
||||
/// Data that is appended to the very end of the contract.
|
||||
bytes m_auxiliaryData;
|
||||
std::vector<std::shared_ptr<Assembly>> m_subs;
|
||||
std::vector<std::pair<std::shared_ptr<Assembly>, bool>> m_subs;
|
||||
std::map<util::h256, std::string> m_strings;
|
||||
std::map<util::h256, std::string> m_libraries; ///< Identifiers of libraries to be linked.
|
||||
std::map<util::h256, std::string> m_immutables; ///< Identifiers of immutables.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -37,9 +37,13 @@
|
||||
#include <libyul/optimiser/Suite.h>
|
||||
|
||||
#include <libevmasm/Assembly.h>
|
||||
|
||||
#include <liblangutil/Scanner.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <optional>
|
||||
|
||||
|
||||
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<Object*>(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<GasMeter> meter;
|
||||
|
@ -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<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = "") = 0;
|
||||
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name, bool _creation) = 0;
|
||||
/// Appends the offset of the given sub-assembly or data.
|
||||
virtual void appendDataOffset(std::vector<SubID> const& _subPath) = 0;
|
||||
/// Appends the size of the given sub-assembly or data.
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include <libyul/Object.h>
|
||||
#include <libyul/Exceptions.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
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<Object*>(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);
|
||||
|
@ -122,10 +122,10 @@ void EthAssemblyAdapter::appendAssemblySize()
|
||||
m_assembly.appendProgramSize();
|
||||
}
|
||||
|
||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name)
|
||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name, bool _creation)
|
||||
{
|
||||
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(std::move(_name))};
|
||||
auto sub = m_assembly.newSub(assembly);
|
||||
auto sub = m_assembly.newSub(assembly, _creation);
|
||||
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||
}
|
||||
|
||||
|
@ -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<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = {}) override;
|
||||
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name, bool _creation) override;
|
||||
void appendDataOffset(std::vector<SubID> const& _subPath) override;
|
||||
void appendDataSize(std::vector<SubID> const& _subPath) override;
|
||||
SubID appendData(bytes const& _data) override;
|
||||
|
@ -98,7 +98,7 @@ void NoOutputAssembly::appendAssemblySize()
|
||||
appendInstruction(evmasm::Instruction::PUSH1);
|
||||
}
|
||||
|
||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(std::string)
|
||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(std::string, bool)
|
||||
{
|
||||
yulAssert(false, "Sub assemblies not implemented.");
|
||||
return {};
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
|
||||
|
||||
void appendAssemblySize() override;
|
||||
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = "") override;
|
||||
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name, bool _creation) override;
|
||||
void appendDataOffset(std::vector<SubID> const& _subPath) override;
|
||||
void appendDataSize(std::vector<SubID> const& _subPath) override;
|
||||
SubID appendData(bytes const& _data) override;
|
||||
|
@ -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<size_t>(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<size_t>(sub.data()));
|
||||
|
||||
checkCompilation(_assembly);
|
||||
@ -354,8 +354,8 @@ BOOST_AUTO_TEST_CASE(subobject_encode_decode)
|
||||
shared_ptr<Assembly> subAsmPtr = make_shared<Assembly>();
|
||||
shared_ptr<Assembly> subSubAsmPtr = make_shared<Assembly>();
|
||||
|
||||
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);
|
||||
|
@ -1272,7 +1272,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
|
||||
sub->append(t4.pushTag());
|
||||
sub->append(Instruction::JUMP);
|
||||
|
||||
size_t subId = static_cast<size_t>(main.appendSubroutine(sub).data());
|
||||
size_t subId = static_cast<size_t>(main.appendSubroutine(sub, false).data());
|
||||
main.append(t1.toSubAssemblyTag(subId));
|
||||
main.append(t1.toSubAssemblyTag(subId));
|
||||
main.append(u256(8));
|
||||
|
Loading…
Reference in New Issue
Block a user