Skip to content

Commit

Permalink
Yul Backend: Get rid of heuristics for finding the matching runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
Marenz committed Feb 9, 2021
1 parent d393624 commit e4f1257
Show file tree
Hide file tree
Showing 13 changed files with 51 additions and 21 deletions.
6 changes: 6 additions & 0 deletions libevmasm/Assembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ using AssemblyPointer = std::shared_ptr<Assembly>;
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.
Expand Down Expand Up @@ -95,6 +97,7 @@ class Assembly
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; }
Expand Down Expand Up @@ -193,6 +196,9 @@ class Assembly
mutable std::vector<size_t> 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:
Expand Down
2 changes: 1 addition & 1 deletion libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion libsolidity/interface/StandardCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
37 changes: 27 additions & 10 deletions libyul/AssemblyStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -226,7 +226,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
return MachineAssemblyObject();
}

pair<MachineAssemblyObject, MachineAssemblyObject> AssemblyStack::assembleAndGuessRuntime() const
std::pair<MachineAssemblyObject, MachineAssemblyObject> AssemblyStack::assembleWithDeployed(optional<string_view> _deployName) const
{
yulAssert(m_analysisSuccessful, "");
yulAssert(m_parserResult, "");
Expand All @@ -248,22 +248,39 @@ pair<MachineAssemblyObject, MachineAssemblyObject> 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<size_t> subIndex;

// Pick matching assembly if name was given
if (_deployName.has_value())
{
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(0);
runtimeObject.bytecode = make_shared<evmasm::LinkerObject>(runtimeAssembly.assemble());
runtimeObject.assembly = runtimeAssembly.assemblyString();
runtimeObject.sourceMappings = make_unique<string>(
evmasm::Assembly& runtimeAssembly = assembly.sub(*subIndex);
deployedObject.bytecode = make_shared<evmasm::LinkerObject>(runtimeAssembly.assemble());
deployedObject.assembly = runtimeAssembly.assemblyString();
deployedObject.sourceMappings = make_unique<string>(
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
Expand Down
6 changes: 6 additions & 0 deletions libyul/AssemblyStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ class AssemblyStack
/// Only available for EVM.
std::pair<MachineAssemblyObject, MachineAssemblyObject> 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<MachineAssemblyObject, MachineAssemblyObject> assembleWithDeployed(std::optional<std::string_view> _deployeName = {}) const;

/// @returns the errors generated during parsing, analysis (and potentially assembly).
langutil::ErrorList const& errors() const { return m_errors; }

Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/AbstractAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class AbstractAssembly
/// 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() = 0;
virtual std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = "") = 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.
Expand Down
4 changes: 2 additions & 2 deletions libyul/backends/evm/AsmCodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ void EthAssemblyAdapter::appendAssemblySize()
m_assembly.appendProgramSize();
}

pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly()
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(string _name)
{
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>()};
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(std::move(_name))};
auto sub = m_assembly.newSub(assembly);
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
}
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/AsmCodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class EthAssemblyAdapter: public AbstractAssembly
void appendJumpsub(LabelID, int, int) override;
void appendReturnsub(int, int) override;
void appendAssemblySize() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = {}) override;
void appendDataOffset(std::vector<SubID> const& _subPath) override;
void appendDataSize(std::vector<SubID> const& _subPath) override;
SubID appendData(bytes const& _data) override;
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/EVMAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ void EVMAssembly::appendAssemblySize()
m_bytecode += bytes(assemblySizeReferenceSize);
}

pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EVMAssembly::createSubAssembly()
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EVMAssembly::createSubAssembly(string)
{
yulAssert(false, "Sub assemblies not implemented.");
return {};
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/EVMAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class EVMAssembly: public AbstractAssembly

/// Append the assembled size as a constant.
void appendAssemblySize() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = "") override;
void appendDataOffset(std::vector<SubID> const& _subPath) override;
void appendDataSize(std::vector<SubID> const& _subPath) override;
SubID appendData(bytes const& _data) override;
Expand Down
3 changes: 2 additions & 1 deletion libyul/backends/evm/EVMObjectCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Object*>(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);
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/NoOutputAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ void NoOutputAssembly::appendAssemblySize()
appendInstruction(evmasm::Instruction::PUSH1);
}

pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly()
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(std::string)
{
yulAssert(false, "Sub assemblies not implemented.");
return {};
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/NoOutputAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class NoOutputAssembly: public AbstractAssembly
void appendReturnsub(int _returns, int _stackDiffAfter) override;

void appendAssemblySize() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly() override;
std::pair<std::shared_ptr<AbstractAssembly>, SubID> createSubAssembly(std::string _name = "") override;
void appendDataOffset(std::vector<SubID> const& _subPath) override;
void appendDataSize(std::vector<SubID> const& _subPath) override;
SubID appendData(bytes const& _data) override;
Expand Down

0 comments on commit e4f1257

Please sign in to comment.