mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
More fixes.
This commit is contained in:
parent
38cc9a3675
commit
5b9e4c47a3
@ -52,11 +52,12 @@ AssemblyItem const& Assembly::append(AssemblyItem _i)
|
|||||||
{
|
{
|
||||||
assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow.");
|
assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow.");
|
||||||
m_deposit += static_cast<int>(_i.deposit());
|
m_deposit += static_cast<int>(_i.deposit());
|
||||||
items().emplace_back(std::move(_i));
|
auto& currentItems = m_codeSections.at(m_currentCodeSection).items;
|
||||||
if (!items().back().location().isValid() && m_currentSourceLocation.isValid())
|
currentItems.emplace_back(std::move(_i));
|
||||||
items().back().setLocation(m_currentSourceLocation);
|
if (!currentItems.back().location().isValid() && m_currentSourceLocation.isValid())
|
||||||
items().back().m_modifierDepth = m_currentModifierDepth;
|
currentItems.back().setLocation(m_currentSourceLocation);
|
||||||
return items().back();
|
currentItems.back().m_modifierDepth = m_currentModifierDepth;
|
||||||
|
return currentItems.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Assembly::codeSize(unsigned subTagSize) const
|
unsigned Assembly::codeSize(unsigned subTagSize) const
|
||||||
@ -64,8 +65,6 @@ unsigned Assembly::codeSize(unsigned subTagSize) const
|
|||||||
for (unsigned tagSize = subTagSize; true; ++tagSize)
|
for (unsigned tagSize = subTagSize; true; ++tagSize)
|
||||||
{
|
{
|
||||||
size_t ret = 1;
|
size_t ret = 1;
|
||||||
for (auto const& i: m_data)
|
|
||||||
ret += i.second.size();
|
|
||||||
|
|
||||||
for (auto const& codeSection: m_codeSections)
|
for (auto const& codeSection: m_codeSections)
|
||||||
for (AssemblyItem const& i: codeSection.items)
|
for (AssemblyItem const& i: codeSection.items)
|
||||||
@ -190,7 +189,8 @@ void Assembly::assemblyStream(
|
|||||||
{
|
{
|
||||||
Functionalizer f(_out, _prefix, _sourceCodes, *this);
|
Functionalizer f(_out, _prefix, _sourceCodes, *this);
|
||||||
|
|
||||||
for (auto const& i: items())
|
// TODO: support EOF
|
||||||
|
for (auto const& i: m_codeSections.front().items)
|
||||||
f.feed(i, _debugInfoSelection);
|
f.feed(i, _debugInfoSelection);
|
||||||
f.flush();
|
f.flush();
|
||||||
|
|
||||||
@ -228,7 +228,8 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices,
|
|||||||
Json::Value root;
|
Json::Value root;
|
||||||
root[".code"] = Json::arrayValue;
|
root[".code"] = Json::arrayValue;
|
||||||
Json::Value& code = root[".code"];
|
Json::Value& code = root[".code"];
|
||||||
for (AssemblyItem const& item: items())
|
// TODO: support EOF
|
||||||
|
for (AssemblyItem const& item: m_codeSections.front().items)
|
||||||
{
|
{
|
||||||
int sourceIndex = -1;
|
int sourceIndex = -1;
|
||||||
if (item.location().sourceName)
|
if (item.location().sourceName)
|
||||||
@ -345,24 +346,25 @@ map<u256, u256> const& Assembly::optimiseInternal(
|
|||||||
std::set<size_t> _tagsReferencedFromOutside
|
std::set<size_t> _tagsReferencedFromOutside
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (m_eofVersion.has_value())
|
|
||||||
// TODO
|
|
||||||
return *m_tagReplacements;
|
|
||||||
|
|
||||||
if (m_tagReplacements)
|
if (m_tagReplacements)
|
||||||
return *m_tagReplacements;
|
return *m_tagReplacements;
|
||||||
|
|
||||||
// Run optimisation for sub-assemblies.
|
// Run optimisation for sub-assemblies.
|
||||||
|
// TODO: verify and double-check this for EOF.
|
||||||
for (size_t subId = 0; subId < m_subs.size(); ++subId)
|
for (size_t subId = 0; subId < m_subs.size(); ++subId)
|
||||||
{
|
{
|
||||||
OptimiserSettings settings = _settings;
|
OptimiserSettings settings = _settings;
|
||||||
Assembly& sub = *m_subs[subId];
|
Assembly& sub = *m_subs[subId];
|
||||||
|
std::set<size_t> referencedTags;
|
||||||
|
for (auto& codeSection: m_codeSections)
|
||||||
|
referencedTags += JumpdestRemover::referencedTags(codeSection.items, subId);
|
||||||
map<u256, u256> const& subTagReplacements = sub.optimiseInternal(
|
map<u256, u256> const& subTagReplacements = sub.optimiseInternal(
|
||||||
settings,
|
settings,
|
||||||
JumpdestRemover::referencedTags(items(), subId)
|
referencedTags
|
||||||
);
|
);
|
||||||
// Apply the replacements (can be empty).
|
// Apply the replacements (can be empty).
|
||||||
BlockDeduplicator::applyTagReplacement(items(), subTagReplacements, subId);
|
for (auto& codeSection: m_codeSections)
|
||||||
|
BlockDeduplicator::applyTagReplacement(codeSection.items, subTagReplacements, subId);
|
||||||
}
|
}
|
||||||
|
|
||||||
map<u256, u256> tagReplacements;
|
map<u256, u256> tagReplacements;
|
||||||
@ -371,9 +373,9 @@ map<u256, u256> const& Assembly::optimiseInternal(
|
|||||||
{
|
{
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
if (_settings.runInliner)
|
if (_settings.runInliner && !m_eofVersion.has_value())
|
||||||
Inliner{
|
Inliner{
|
||||||
items(),
|
m_codeSections.front().items,
|
||||||
_tagsReferencedFromOutside,
|
_tagsReferencedFromOutside,
|
||||||
_settings.expectedExecutionsPerDeployment,
|
_settings.expectedExecutionsPerDeployment,
|
||||||
isCreation(),
|
isCreation(),
|
||||||
@ -382,25 +384,34 @@ map<u256, u256> const& Assembly::optimiseInternal(
|
|||||||
|
|
||||||
if (_settings.runJumpdestRemover)
|
if (_settings.runJumpdestRemover)
|
||||||
{
|
{
|
||||||
JumpdestRemover jumpdestOpt{items()};
|
// TODO: verify this for EOF.
|
||||||
if (jumpdestOpt.optimise(_tagsReferencedFromOutside))
|
for (auto& codeSection: m_codeSections)
|
||||||
count++;
|
{
|
||||||
|
JumpdestRemover jumpdestOpt{codeSection.items};
|
||||||
|
if (jumpdestOpt.optimise(_tagsReferencedFromOutside))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_settings.runPeephole)
|
if (_settings.runPeephole)
|
||||||
{
|
{
|
||||||
PeepholeOptimiser peepOpt{items()};
|
// TODO: verify this for EOF.
|
||||||
while (peepOpt.optimise())
|
for (auto& codeSection: m_codeSections)
|
||||||
{
|
{
|
||||||
count++;
|
PeepholeOptimiser peepOpt{codeSection.items};
|
||||||
assertThrow(count < 64000, OptimizerException, "Peephole optimizer seems to be stuck.");
|
while (peepOpt.optimise())
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
assertThrow(count < 64000, OptimizerException, "Peephole optimizer seems to be stuck.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This only modifies PushTags, we have to run again to actually remove code.
|
// This only modifies PushTags, we have to run again to actually remove code.
|
||||||
if (_settings.runDeduplicate)
|
// TODO: investigate options for EOF.
|
||||||
|
if (_settings.runDeduplicate && !m_eofVersion.has_value())
|
||||||
{
|
{
|
||||||
BlockDeduplicator deduplicator{items()};
|
BlockDeduplicator deduplicator{m_codeSections.front().items};
|
||||||
if (deduplicator.deduplicate())
|
if (deduplicator.deduplicate())
|
||||||
{
|
{
|
||||||
for (auto const& replacement: deduplicator.replacedTags())
|
for (auto const& replacement: deduplicator.replacedTags())
|
||||||
@ -423,24 +434,26 @@ map<u256, u256> const& Assembly::optimiseInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_settings.runCSE)
|
// TODO: investigate for EOF
|
||||||
|
if (_settings.runCSE && !m_eofVersion.has_value())
|
||||||
{
|
{
|
||||||
// Control flow graph optimization has been here before but is disabled because it
|
// Control flow graph optimization has been here before but is disabled because it
|
||||||
// assumes we only jump to tags that are pushed. This is not the case anymore with
|
// assumes we only jump to tags that are pushed. This is not the case anymore with
|
||||||
// function types that can be stored in storage.
|
// function types that can be stored in storage.
|
||||||
AssemblyItems optimisedItems;
|
AssemblyItems optimisedItems;
|
||||||
|
|
||||||
bool usesMSize = ranges::any_of(items(), [](AssemblyItem const& _i) {
|
auto& items = m_codeSections.front().items;
|
||||||
|
bool usesMSize = ranges::any_of(items, [](AssemblyItem const& _i) {
|
||||||
return _i == AssemblyItem{Instruction::MSIZE} || _i.type() == VerbatimBytecode;
|
return _i == AssemblyItem{Instruction::MSIZE} || _i.type() == VerbatimBytecode;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto iter = items().begin();
|
auto iter = items.begin();
|
||||||
while (iter != items().end())
|
while (iter != items.end())
|
||||||
{
|
{
|
||||||
KnownState emptyState;
|
KnownState emptyState;
|
||||||
CommonSubexpressionEliminator eliminator{emptyState};
|
CommonSubexpressionEliminator eliminator{emptyState};
|
||||||
auto orig = iter;
|
auto orig = iter;
|
||||||
iter = eliminator.feedItems(iter, items().end(), usesMSize);
|
iter = eliminator.feedItems(iter, items.end(), usesMSize);
|
||||||
bool shouldReplace = false;
|
bool shouldReplace = false;
|
||||||
AssemblyItems optimisedChunk;
|
AssemblyItems optimisedChunk;
|
||||||
try
|
try
|
||||||
@ -467,9 +480,9 @@ map<u256, u256> const& Assembly::optimiseInternal(
|
|||||||
else
|
else
|
||||||
copy(orig, iter, back_inserter(optimisedItems));
|
copy(orig, iter, back_inserter(optimisedItems));
|
||||||
}
|
}
|
||||||
if (optimisedItems.size() < items().size())
|
if (optimisedItems.size() < items.size())
|
||||||
{
|
{
|
||||||
items() = std::move(optimisedItems);
|
items = std::move(optimisedItems);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,12 +554,17 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
// TODO: assert zero inputs/outputs on code section zero
|
// TODO: assert zero inputs/outputs on code section zero
|
||||||
// TODO: assert one code section being present and *only* one being present unless EOF
|
// TODO: assert one code section being present and *only* one being present unless EOF
|
||||||
|
|
||||||
|
unsigned bytesRequiredForSubs = 0;
|
||||||
|
// TODO: consider fully producing all sub and data refs in this pass already.
|
||||||
|
for (auto&& codeSection: m_codeSections)
|
||||||
|
for (AssemblyItem const& i: codeSection.items)
|
||||||
|
if (i.type() == PushSub)
|
||||||
|
bytesRequiredForSubs += static_cast<unsigned>(subAssemblyById(static_cast<size_t>(i.data()))->assemble().bytecode.size());
|
||||||
unsigned bytesRequiredForDataUpperBound = static_cast<unsigned>(m_auxiliaryData.size());
|
unsigned bytesRequiredForDataUpperBound = static_cast<unsigned>(m_auxiliaryData.size());
|
||||||
for (auto const& sub: m_subs)
|
|
||||||
bytesRequiredForDataUpperBound += static_cast<unsigned>(sub->assemble().bytecode.size());
|
|
||||||
// Some of these may be unreferenced and not actually end up in data.
|
// Some of these may be unreferenced and not actually end up in data.
|
||||||
for (auto const& dataItem: m_data)
|
for (auto const& dataItem: m_data)
|
||||||
bytesRequiredForDataUpperBound += static_cast<unsigned>(dataItem.second.size());
|
bytesRequiredForDataUpperBound += static_cast<unsigned>(dataItem.second.size());
|
||||||
|
unsigned bytesRequiredForDataAndSubsUpperBound = bytesRequiredForDataUpperBound + bytesRequiredForSubs;
|
||||||
|
|
||||||
// Insert EOF1 header.
|
// Insert EOF1 header.
|
||||||
vector<size_t> codeSectionSizeOffsets;
|
vector<size_t> codeSectionSizeOffsets;
|
||||||
@ -583,7 +601,7 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
ret.bytecode.push_back(0x00); // placeholder for length of code
|
ret.bytecode.push_back(0x00); // placeholder for length of code
|
||||||
ret.bytecode.push_back(0x00);
|
ret.bytecode.push_back(0x00);
|
||||||
}
|
}
|
||||||
if (bytesRequiredForDataUpperBound > 0)
|
if (bytesRequiredForDataAndSubsUpperBound > 0)
|
||||||
{
|
{
|
||||||
ret.bytecode.push_back(0x02); // kind=data
|
ret.bytecode.push_back(0x02); // kind=data
|
||||||
dataSectionSizeOffset = ret.bytecode.size();
|
dataSectionSizeOffset = ret.bytecode.size();
|
||||||
@ -600,7 +618,6 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned headerSize = static_cast<unsigned>(ret.bytecode.size());
|
unsigned headerSize = static_cast<unsigned>(ret.bytecode.size());
|
||||||
unsigned bytesRequiredForCode = codeSize(static_cast<unsigned>(subTagSize));
|
unsigned bytesRequiredForCode = codeSize(static_cast<unsigned>(subTagSize));
|
||||||
m_tagPositionsInBytecode = vector<size_t>(m_usedTags, numeric_limits<size_t>::max());
|
m_tagPositionsInBytecode = vector<size_t>(m_usedTags, numeric_limits<size_t>::max());
|
||||||
@ -608,19 +625,21 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
multimap<h256, unsigned> dataRef;
|
multimap<h256, unsigned> dataRef;
|
||||||
multimap<size_t, size_t> subRef;
|
multimap<size_t, size_t> subRef;
|
||||||
vector<unsigned> sizeRef; ///< Pointers to code locations where the size of the program is inserted
|
vector<unsigned> sizeRef; ///< Pointers to code locations where the size of the program is inserted
|
||||||
unsigned bytesPerTag = numberEncodingSize(headerSize + bytesRequiredForCode);
|
unsigned bytesPerTag = numberEncodingSize(headerSize + bytesRequiredForCode + bytesRequiredForDataUpperBound);
|
||||||
uint8_t tagPush = static_cast<uint8_t>(pushInstruction(bytesPerTag));
|
uint8_t tagPush = static_cast<uint8_t>(pushInstruction(bytesPerTag));
|
||||||
|
|
||||||
if (!needsEOFContainer)
|
if (!needsEOFContainer)
|
||||||
++bytesRequiredForCode; ///< Additional INVALID marker.
|
++bytesRequiredForCode; ///< Additional INVALID marker.
|
||||||
|
|
||||||
unsigned bytesRequiredIncludingDataUpperBound = headerSize + bytesRequiredForCode + bytesRequiredForDataUpperBound;
|
unsigned bytesRequiredIncludingDataAndSubsUpperBound = headerSize + bytesRequiredForCode + bytesRequiredForDataAndSubsUpperBound;
|
||||||
unsigned bytesPerDataRef = numberEncodingSize(bytesRequiredIncludingDataUpperBound);
|
unsigned bytesPerDataRef = numberEncodingSize(bytesRequiredIncludingDataAndSubsUpperBound);
|
||||||
uint8_t dataRefPush = static_cast<uint8_t>(pushInstruction(bytesPerDataRef));
|
uint8_t dataRefPush = static_cast<uint8_t>(pushInstruction(bytesPerDataRef));
|
||||||
ret.bytecode.reserve(bytesRequiredIncludingDataUpperBound);
|
ret.bytecode.reserve(bytesRequiredIncludingDataAndSubsUpperBound);
|
||||||
|
|
||||||
auto const codeStart = ret.bytecode.size();
|
auto const codeStart = ret.bytecode.size();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (auto&& [codeSectionIndex, codeSection]: m_codeSections | ranges::views::enumerate)
|
for (auto&& [codeSectionIndex, codeSection]: m_codeSections | ranges::views::enumerate)
|
||||||
{
|
{
|
||||||
auto const sectionStart = ret.bytecode.size();
|
auto const sectionStart = ret.bytecode.size();
|
||||||
@ -778,11 +797,26 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
|
|
||||||
auto const dataStart = ret.bytecode.size();
|
auto const dataStart = ret.bytecode.size();
|
||||||
|
|
||||||
for (auto const& [subIdPath, bytecodeOffset]: subRef)
|
|
||||||
{
|
{
|
||||||
bytesRef r(ret.bytecode.data() + bytecodeOffset, bytesPerDataRef);
|
std::map<h256, size_t> subAssemblyOffsets;
|
||||||
toBigEndian(ret.bytecode.size(), r);
|
for (auto const& [subIdPath, bytecodeOffset]: subRef)
|
||||||
ret.append(subAssemblyById(subIdPath)->assemble());
|
{
|
||||||
|
LinkerObject subObject = subAssemblyById(subIdPath)->assemble();
|
||||||
|
util::h256 h(util::keccak256(util::asString(subObject.bytecode)));
|
||||||
|
bytesRef r(ret.bytecode.data() + bytecodeOffset, bytesPerDataRef);
|
||||||
|
if (size_t* subAssemblyOffset = util::valueOrNullptr(subAssemblyOffsets, h))
|
||||||
|
toBigEndian(*subAssemblyOffset, r);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toBigEndian(ret.bytecode.size(), r);
|
||||||
|
subAssemblyOffsets[h] = ret.bytecode.size();
|
||||||
|
ret.bytecode += subObject.bytecode;
|
||||||
|
}
|
||||||
|
// TODO: double-check this.
|
||||||
|
for (auto const& ref: subObject.linkReferences)
|
||||||
|
ret.linkReferences[ref.first + subAssemblyOffsets[h]] = ref.second;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& i: tagRef)
|
for (auto const& i: tagRef)
|
||||||
@ -806,12 +840,13 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
{
|
{
|
||||||
size_t position = m_tagPositionsInBytecode.at(tagInfo.id);
|
size_t position = m_tagPositionsInBytecode.at(tagInfo.id);
|
||||||
optional<size_t> tagIndex;
|
optional<size_t> tagIndex;
|
||||||
for (auto&& [index, item]: items() | ranges::views::enumerate)
|
for (auto& codeSection: m_codeSections)
|
||||||
if (item.type() == Tag && static_cast<size_t>(item.data()) == tagInfo.id)
|
for (auto&& [index, item]: codeSection.items | ranges::views::enumerate)
|
||||||
{
|
if (item.type() == Tag && static_cast<size_t>(item.data()) == tagInfo.id)
|
||||||
tagIndex = index;
|
{
|
||||||
break;
|
tagIndex = index;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
ret.functionDebugData[name] = {
|
ret.functionDebugData[name] = {
|
||||||
position == numeric_limits<size_t>::max() ? nullopt : optional<size_t>{position},
|
position == numeric_limits<size_t>::max() ? nullopt : optional<size_t>{position},
|
||||||
tagIndex,
|
tagIndex,
|
||||||
@ -836,6 +871,12 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
|
|
||||||
ret.bytecode += m_auxiliaryData;
|
ret.bytecode += m_auxiliaryData;
|
||||||
|
|
||||||
|
if (needsEOFContainer && bytesRequiredForDataAndSubsUpperBound > 0 && ret.bytecode.size() == dataStart)
|
||||||
|
{
|
||||||
|
// We have commited to a data section, but not actually needed it, so create a fake one.
|
||||||
|
ret.bytecode.push_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned pos: sizeRef)
|
for (unsigned pos: sizeRef)
|
||||||
{
|
{
|
||||||
bytesRef r(ret.bytecode.data() + pos, bytesPerDataRef);
|
bytesRef r(ret.bytecode.data() + pos, bytesPerDataRef);
|
||||||
@ -845,17 +886,27 @@ LinkerObject const& Assembly::assemble() const
|
|||||||
auto dataLength = ret.bytecode.size() - dataStart;
|
auto dataLength = ret.bytecode.size() - dataStart;
|
||||||
if (needsEOFContainer)
|
if (needsEOFContainer)
|
||||||
{
|
{
|
||||||
assertThrow(bytesRequiredForDataUpperBound >= dataLength, AssemblyException, "Unexpected data size.");
|
if (bytesRequiredForDataAndSubsUpperBound < dataLength)
|
||||||
if (bytesRequiredForDataUpperBound > 0)
|
|
||||||
{
|
{
|
||||||
if (dataLength == 0)
|
std::cout << "Auxdata: " << m_auxiliaryData.size() << std::endl;
|
||||||
|
std::cout << "m_data: " << m_data.size() << std::endl;
|
||||||
|
std::cout << "subRef: " << subRef.size() << std::endl;
|
||||||
|
for (auto&& [subIdPath, offset]: subRef)
|
||||||
{
|
{
|
||||||
// We have commited to a data section, but not actually needed it, so create a fake one.
|
(void)offset;
|
||||||
++dataLength;
|
std::cout << "R: " << subAssemblyById(subIdPath) << std::endl;
|
||||||
ret.bytecode.push_back(0);
|
|
||||||
}
|
}
|
||||||
|
std::cout << "m_subs: " << m_subs.size() << std::endl;
|
||||||
|
for (auto const& sub: m_subs)
|
||||||
|
{
|
||||||
|
std::cout << "sub: " << sub.get() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertThrow(bytesRequiredForDataAndSubsUpperBound >= dataLength, AssemblyException, "More data than expected. " + to_string(dataLength) + " > " + to_string(bytesRequiredForDataUpperBound));
|
||||||
|
if (bytesRequiredForDataAndSubsUpperBound > 0)
|
||||||
|
{
|
||||||
|
assertThrow(0 < dataLength && dataLength <= 0xffff, AssemblyException, "Invalid data section size.");
|
||||||
setDataSectionSize(dataLength);
|
setDataSectionSize(dataLength);
|
||||||
assertThrow(dataLength <= 0xffff, AssemblyException, "Invalid data section size.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,18 +146,6 @@ public:
|
|||||||
/// Appends @a _data literally to the very end of the bytecode.
|
/// Appends @a _data literally to the very end of the bytecode.
|
||||||
void appendToAuxiliaryData(bytes const& _data) { m_auxiliaryData += _data; }
|
void appendToAuxiliaryData(bytes const& _data) { m_auxiliaryData += _data; }
|
||||||
|
|
||||||
/// Returns the assembly items.
|
|
||||||
AssemblyItems const& items() const
|
|
||||||
{
|
|
||||||
return m_codeSections.at(m_currentCodeSection).items;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the mutable assembly items. Use with care!
|
|
||||||
AssemblyItems& items()
|
|
||||||
{
|
|
||||||
return m_codeSections.at(m_currentCodeSection).items;
|
|
||||||
}
|
|
||||||
|
|
||||||
int deposit() const { return m_deposit; }
|
int deposit() const { return m_deposit; }
|
||||||
void adjustDeposit(int _adjustment) { m_deposit += _adjustment; assertThrow(m_deposit >= 0, InvalidDeposit, ""); }
|
void adjustDeposit(int _adjustment) { m_deposit += _adjustment; assertThrow(m_deposit >= 0, InvalidDeposit, ""); }
|
||||||
void setDeposit(int _deposit) { m_deposit = _deposit; assertThrow(m_deposit >= 0, InvalidDeposit, ""); }
|
void setDeposit(int _deposit) { m_deposit = _deposit; assertThrow(m_deposit >= 0, InvalidDeposit, ""); }
|
||||||
@ -217,6 +205,23 @@ public:
|
|||||||
|
|
||||||
bool isCreation() const { return m_creation; }
|
bool isCreation() const { return m_creation; }
|
||||||
|
|
||||||
|
struct CodeSection
|
||||||
|
{
|
||||||
|
uint8_t inputs = 0;
|
||||||
|
uint8_t outputs = 0;
|
||||||
|
AssemblyItems items{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<CodeSection>& codeSections()
|
||||||
|
{
|
||||||
|
return m_codeSections;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CodeSection> const& codeSections() const
|
||||||
|
{
|
||||||
|
return m_codeSections;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Does the same operations as @a optimise, but should only be applied to a sub and
|
/// Does the same operations as @a optimise, but should only be applied to a sub and
|
||||||
/// returns the replaced tags. Also takes an argument containing the tags of this assembly
|
/// returns the replaced tags. Also takes an argument containing the tags of this assembly
|
||||||
@ -247,12 +252,6 @@ protected:
|
|||||||
/// Data that is appended to the very end of the contract.
|
/// Data that is appended to the very end of the contract.
|
||||||
bytes m_auxiliaryData;
|
bytes m_auxiliaryData;
|
||||||
std::vector<std::shared_ptr<Assembly>> m_subs;
|
std::vector<std::shared_ptr<Assembly>> m_subs;
|
||||||
struct CodeSection
|
|
||||||
{
|
|
||||||
uint8_t inputs = 0;
|
|
||||||
uint8_t outputs = 0;
|
|
||||||
AssemblyItems items{};
|
|
||||||
};
|
|
||||||
std::vector<CodeSection> m_codeSections;
|
std::vector<CodeSection> m_codeSections;
|
||||||
uint16_t m_currentCodeSection = 0;
|
uint16_t m_currentCodeSection = 0;
|
||||||
std::map<util::h256, std::string> m_strings;
|
std::map<util::h256, std::string> m_strings;
|
||||||
|
@ -36,46 +36,49 @@ unsigned ConstantOptimisationMethod::optimiseConstants(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
// TODO: design the optimiser in a way this is not needed
|
// TODO: design the optimiser in a way this is not needed
|
||||||
AssemblyItems& _items = _assembly.items();
|
|
||||||
|
|
||||||
unsigned optimisations = 0;
|
unsigned optimisations = 0;
|
||||||
map<AssemblyItem, size_t> pushes;
|
for (auto& codeSection: _assembly.codeSections())
|
||||||
for (AssemblyItem const& item: _items)
|
|
||||||
if (item.type() == Push)
|
|
||||||
pushes[item]++;
|
|
||||||
map<u256, AssemblyItems> pendingReplacements;
|
|
||||||
for (auto it: pushes)
|
|
||||||
{
|
{
|
||||||
AssemblyItem const& item = it.first;
|
AssemblyItems& _items = codeSection.items;
|
||||||
if (item.data() < 0x100)
|
|
||||||
continue;
|
map<AssemblyItem, size_t> pushes;
|
||||||
Params params;
|
for (AssemblyItem const& item: _items)
|
||||||
params.multiplicity = it.second;
|
if (item.type() == Push)
|
||||||
params.isCreation = _isCreation;
|
pushes[item]++;
|
||||||
params.runs = _runs;
|
map<u256, AssemblyItems> pendingReplacements;
|
||||||
params.evmVersion = _evmVersion;
|
for (auto it: pushes)
|
||||||
LiteralMethod lit(params, item.data());
|
|
||||||
bigint literalGas = lit.gasNeeded();
|
|
||||||
CodeCopyMethod copy(params, item.data());
|
|
||||||
bigint copyGas = copy.gasNeeded();
|
|
||||||
ComputeMethod compute(params, item.data());
|
|
||||||
bigint computeGas = compute.gasNeeded();
|
|
||||||
AssemblyItems replacement;
|
|
||||||
if (copyGas < literalGas && copyGas < computeGas)
|
|
||||||
{
|
{
|
||||||
replacement = copy.execute(_assembly);
|
AssemblyItem const& item = it.first;
|
||||||
optimisations++;
|
if (item.data() < 0x100)
|
||||||
|
continue;
|
||||||
|
Params params;
|
||||||
|
params.multiplicity = it.second;
|
||||||
|
params.isCreation = _isCreation;
|
||||||
|
params.runs = _runs;
|
||||||
|
params.evmVersion = _evmVersion;
|
||||||
|
LiteralMethod lit(params, item.data());
|
||||||
|
bigint literalGas = lit.gasNeeded();
|
||||||
|
CodeCopyMethod copy(params, item.data());
|
||||||
|
bigint copyGas = copy.gasNeeded();
|
||||||
|
ComputeMethod compute(params, item.data());
|
||||||
|
bigint computeGas = compute.gasNeeded();
|
||||||
|
AssemblyItems replacement;
|
||||||
|
if (copyGas < literalGas && copyGas < computeGas)
|
||||||
|
{
|
||||||
|
replacement = copy.execute(_assembly);
|
||||||
|
optimisations++;
|
||||||
|
}
|
||||||
|
else if (computeGas < literalGas && computeGas <= copyGas)
|
||||||
|
{
|
||||||
|
replacement = compute.execute(_assembly);
|
||||||
|
optimisations++;
|
||||||
|
}
|
||||||
|
if (!replacement.empty())
|
||||||
|
pendingReplacements[item.data()] = replacement;
|
||||||
}
|
}
|
||||||
else if (computeGas < literalGas && computeGas <= copyGas)
|
if (!pendingReplacements.empty())
|
||||||
{
|
replaceConstants(_items, pendingReplacements);
|
||||||
replacement = compute.execute(_assembly);
|
|
||||||
optimisations++;
|
|
||||||
}
|
|
||||||
if (!replacement.empty())
|
|
||||||
pendingReplacements[item.data()] = replacement;
|
|
||||||
}
|
}
|
||||||
if (!pendingReplacements.empty())
|
|
||||||
replaceConstants(_items, pendingReplacements);
|
|
||||||
return optimisations;
|
return optimisations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -765,7 +765,8 @@ evmasm::AssemblyItems const* CompilerStack::assemblyItems(string const& _contrac
|
|||||||
solThrow(CompilerError, "Compilation was not successful.");
|
solThrow(CompilerError, "Compilation was not successful.");
|
||||||
|
|
||||||
Contract const& currentContract = contract(_contractName);
|
Contract const& currentContract = contract(_contractName);
|
||||||
return currentContract.evmAssembly ? ¤tContract.evmAssembly->items() : nullptr;
|
solAssert(currentContract.evmAssembly->codeSections().size() == 1, "Expected a single code section in legacy codegen.");
|
||||||
|
return currentContract.evmAssembly ? ¤tContract.evmAssembly->codeSections().front().items : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
evmasm::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _contractName) const
|
evmasm::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _contractName) const
|
||||||
@ -774,7 +775,8 @@ evmasm::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _
|
|||||||
solThrow(CompilerError, "Compilation was not successful.");
|
solThrow(CompilerError, "Compilation was not successful.");
|
||||||
|
|
||||||
Contract const& currentContract = contract(_contractName);
|
Contract const& currentContract = contract(_contractName);
|
||||||
return currentContract.evmRuntimeAssembly ? ¤tContract.evmRuntimeAssembly->items() : nullptr;
|
solAssert(currentContract.evmRuntimeAssembly->codeSections().size() == 1, "Expected a single code section in legacy codegen.");
|
||||||
|
return currentContract.evmRuntimeAssembly ? ¤tContract.evmRuntimeAssembly->codeSections().front().items : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value CompilerStack::generatedSources(string const& _contractName, bool _runtime) const
|
Json::Value CompilerStack::generatedSources(string const& _contractName, bool _runtime) const
|
||||||
|
@ -234,9 +234,10 @@ YulStack::assembleWithDeployed(optional<string_view> _deployName) const
|
|||||||
creationObject.bytecode = make_shared<evmasm::LinkerObject>(creationAssembly->assemble());
|
creationObject.bytecode = make_shared<evmasm::LinkerObject>(creationAssembly->assemble());
|
||||||
yulAssert(creationObject.bytecode->immutableReferences.empty(), "Leftover immutables.");
|
yulAssert(creationObject.bytecode->immutableReferences.empty(), "Leftover immutables.");
|
||||||
creationObject.assembly = creationAssembly->assemblyString(m_debugInfoSelection);
|
creationObject.assembly = creationAssembly->assemblyString(m_debugInfoSelection);
|
||||||
|
// TODO: fix for EOF
|
||||||
creationObject.sourceMappings = make_unique<string>(
|
creationObject.sourceMappings = make_unique<string>(
|
||||||
evmasm::AssemblyItem::computeSourceMapping(
|
evmasm::AssemblyItem::computeSourceMapping(
|
||||||
creationAssembly->items(),
|
creationAssembly->codeSections().front().items,
|
||||||
{{m_charStream->name(), 0}}
|
{{m_charStream->name(), 0}}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -246,9 +247,10 @@ YulStack::assembleWithDeployed(optional<string_view> _deployName) const
|
|||||||
{
|
{
|
||||||
deployedObject.bytecode = make_shared<evmasm::LinkerObject>(deployedAssembly->assemble());
|
deployedObject.bytecode = make_shared<evmasm::LinkerObject>(deployedAssembly->assemble());
|
||||||
deployedObject.assembly = deployedAssembly->assemblyString(m_debugInfoSelection);
|
deployedObject.assembly = deployedAssembly->assemblyString(m_debugInfoSelection);
|
||||||
|
// TODO: fix for EOF
|
||||||
deployedObject.sourceMappings = make_unique<string>(
|
deployedObject.sourceMappings = make_unique<string>(
|
||||||
evmasm::AssemblyItem::computeSourceMapping(
|
evmasm::AssemblyItem::computeSourceMapping(
|
||||||
deployedAssembly->items(),
|
deployedAssembly->codeSections().front().items,
|
||||||
{{m_charStream->name(), 0}}
|
{{m_charStream->name(), 0}}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user