More fixes.

This commit is contained in:
Daniel Kirchner 2022-12-14 16:49:11 +01:00
parent 38cc9a3675
commit 5b9e4c47a3
5 changed files with 172 additions and 115 deletions

View File

@ -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.");
} }
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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 ? &currentContract.evmAssembly->items() : nullptr; solAssert(currentContract.evmAssembly->codeSections().size() == 1, "Expected a single code section in legacy codegen.");
return currentContract.evmAssembly ? &currentContract.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 ? &currentContract.evmRuntimeAssembly->items() : nullptr; solAssert(currentContract.evmRuntimeAssembly->codeSections().size() == 1, "Expected a single code section in legacy codegen.");
return currentContract.evmRuntimeAssembly ? &currentContract.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

View File

@ -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}}
) )
); );