mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Yul Backend: Get rid of heuristics for finding the matching runtime
This commit is contained in:
parent
d393624384
commit
e4f1257c83
@ -44,6 +44,8 @@ using AssemblyPointer = std::shared_ptr<Assembly>;
|
|||||||
class Assembly
|
class Assembly
|
||||||
{
|
{
|
||||||
public:
|
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 newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, m_usedTags++); }
|
||||||
AssemblyItem newPushTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(PushTag, 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.
|
/// Returns a tag identified by the given name. Creates it if it does not yet exist.
|
||||||
@ -95,6 +97,7 @@ public:
|
|||||||
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, ""); }
|
||||||
|
std::string const& name() const { return m_name; }
|
||||||
|
|
||||||
/// Changes the source location used for each appended item.
|
/// Changes the source location used for each appended item.
|
||||||
void setSourceLocation(langutil::SourceLocation const& _location) { m_currentSourceLocation = _location; }
|
void setSourceLocation(langutil::SourceLocation const& _location) { m_currentSourceLocation = _location; }
|
||||||
@ -193,6 +196,9 @@ protected:
|
|||||||
mutable std::vector<size_t> m_tagPositionsInBytecode;
|
mutable std::vector<size_t> m_tagPositionsInBytecode;
|
||||||
|
|
||||||
int m_deposit = 0;
|
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;
|
langutil::SourceLocation m_currentSourceLocation;
|
||||||
public:
|
public:
|
||||||
|
@ -1302,7 +1302,7 @@ void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract)
|
|||||||
// TODO: use stack.assemble here!
|
// TODO: use stack.assemble here!
|
||||||
yul::MachineAssemblyObject init;
|
yul::MachineAssemblyObject init;
|
||||||
yul::MachineAssemblyObject runtime;
|
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.object = std::move(*init.bytecode);
|
||||||
compiledContract.runtimeObject = std::move(*runtime.bytecode);
|
compiledContract.runtimeObject = std::move(*runtime.bytecode);
|
||||||
// TODO: refactor assemblyItems, runtimeAssemblyItems, generatedSources,
|
// TODO: refactor assemblyItems, runtimeAssemblyItems, generatedSources,
|
||||||
|
@ -1273,7 +1273,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
|
|||||||
|
|
||||||
MachineAssemblyObject object;
|
MachineAssemblyObject object;
|
||||||
MachineAssemblyObject runtimeObject;
|
MachineAssemblyObject runtimeObject;
|
||||||
tie(object, runtimeObject) = stack.assembleAndGuessRuntime();
|
tie(object, runtimeObject) = stack.assembleWithDeployed();
|
||||||
|
|
||||||
if (object.bytecode)
|
if (object.bytecode)
|
||||||
object.bytecode->link(_inputsAndSettings.libraries);
|
object.bytecode->link(_inputsAndSettings.libraries);
|
||||||
|
@ -199,7 +199,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
|
|||||||
switch (_machine)
|
switch (_machine)
|
||||||
{
|
{
|
||||||
case Machine::EVM:
|
case Machine::EVM:
|
||||||
return assembleAndGuessRuntime().first;
|
return assembleWithDeployed().first;
|
||||||
case Machine::EVM15:
|
case Machine::EVM15:
|
||||||
{
|
{
|
||||||
MachineAssemblyObject object;
|
MachineAssemblyObject object;
|
||||||
@ -226,7 +226,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
|
|||||||
return MachineAssemblyObject();
|
return MachineAssemblyObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<MachineAssemblyObject, MachineAssemblyObject> AssemblyStack::assembleAndGuessRuntime() const
|
std::pair<MachineAssemblyObject, MachineAssemblyObject> AssemblyStack::assembleWithDeployed(optional<string_view> _deployName) const
|
||||||
{
|
{
|
||||||
yulAssert(m_analysisSuccessful, "");
|
yulAssert(m_analysisSuccessful, "");
|
||||||
yulAssert(m_parserResult, "");
|
yulAssert(m_parserResult, "");
|
||||||
@ -248,22 +248,39 @@ pair<MachineAssemblyObject, MachineAssemblyObject> AssemblyStack::assembleAndGue
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineAssemblyObject runtimeObject;
|
MachineAssemblyObject deployedObject;
|
||||||
// Heuristic: If there is a single sub-assembly, this is likely the runtime object.
|
optional<size_t> subIndex;
|
||||||
if (assembly.numSubs() == 1)
|
|
||||||
|
// Pick matching assembly if name was given
|
||||||
|
if (_deployName.has_value())
|
||||||
{
|
{
|
||||||
evmasm::Assembly& runtimeAssembly = assembly.sub(0);
|
for (size_t i = 0; i < assembly.numSubs(); i++)
|
||||||
runtimeObject.bytecode = make_shared<evmasm::LinkerObject>(runtimeAssembly.assemble());
|
if (assembly.sub(i).name() == _deployName)
|
||||||
runtimeObject.assembly = runtimeAssembly.assemblyString();
|
{
|
||||||
runtimeObject.sourceMappings = make_unique<string>(
|
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(*subIndex);
|
||||||
|
deployedObject.bytecode = make_shared<evmasm::LinkerObject>(runtimeAssembly.assemble());
|
||||||
|
deployedObject.assembly = runtimeAssembly.assemblyString();
|
||||||
|
deployedObject.sourceMappings = make_unique<string>(
|
||||||
evmasm::AssemblyItem::computeSourceMapping(
|
evmasm::AssemblyItem::computeSourceMapping(
|
||||||
runtimeAssembly.items(),
|
runtimeAssembly.items(),
|
||||||
{{scanner().charStream() ? scanner().charStream()->name() : "", 0}}
|
{{scanner().charStream() ? scanner().charStream()->name() : "", 0}}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return {std::move(creationObject), std::move(runtimeObject)};
|
|
||||||
|
|
||||||
|
return {std::move(creationObject), std::move(deployedObject)};
|
||||||
}
|
}
|
||||||
|
|
||||||
string AssemblyStack::print() const
|
string AssemblyStack::print() const
|
||||||
|
@ -95,6 +95,12 @@ public:
|
|||||||
/// Only available for EVM.
|
/// Only available for EVM.
|
||||||
std::pair<MachineAssemblyObject, MachineAssemblyObject> assembleAndGuessRuntime() const;
|
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).
|
/// @returns the errors generated during parsing, analysis (and potentially assembly).
|
||||||
langutil::ErrorList const& errors() const { return m_errors; }
|
langutil::ErrorList const& errors() const { return m_errors; }
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ public:
|
|||||||
/// Append the assembled size as a constant.
|
/// Append the assembled size as a constant.
|
||||||
virtual void appendAssemblySize() = 0;
|
virtual void appendAssemblySize() = 0;
|
||||||
/// Creates a new sub-assembly, which can be referenced using dataSize and dataOffset.
|
/// 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.
|
/// Appends the offset of the given sub-assembly or data.
|
||||||
virtual void appendDataOffset(std::vector<SubID> const& _subPath) = 0;
|
virtual void appendDataOffset(std::vector<SubID> const& _subPath) = 0;
|
||||||
/// Appends the size of the given sub-assembly or data.
|
/// Appends the size of the given sub-assembly or data.
|
||||||
|
@ -140,9 +140,9 @@ void EthAssemblyAdapter::appendAssemblySize()
|
|||||||
m_assembly.appendProgramSize();
|
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);
|
auto sub = m_assembly.newSub(assembly);
|
||||||
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ public:
|
|||||||
void appendJumpsub(LabelID, int, int) override;
|
void appendJumpsub(LabelID, int, int) override;
|
||||||
void appendReturnsub(int, int) override;
|
void appendReturnsub(int, int) override;
|
||||||
void appendAssemblySize() 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 appendDataOffset(std::vector<SubID> const& _subPath) override;
|
||||||
void appendDataSize(std::vector<SubID> const& _subPath) override;
|
void appendDataSize(std::vector<SubID> const& _subPath) override;
|
||||||
SubID appendData(bytes const& _data) override;
|
SubID appendData(bytes const& _data) override;
|
||||||
|
@ -196,7 +196,7 @@ void EVMAssembly::appendAssemblySize()
|
|||||||
m_bytecode += bytes(assemblySizeReferenceSize);
|
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.");
|
yulAssert(false, "Sub assemblies not implemented.");
|
||||||
return {};
|
return {};
|
||||||
|
@ -79,7 +79,7 @@ public:
|
|||||||
|
|
||||||
/// Append the assembled size as a constant.
|
/// Append the assembled size as a constant.
|
||||||
void appendAssemblySize() 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 appendDataOffset(std::vector<SubID> const& _subPath) override;
|
||||||
void appendDataSize(std::vector<SubID> const& _subPath) override;
|
void appendDataSize(std::vector<SubID> const& _subPath) override;
|
||||||
SubID appendData(bytes const& _data) override;
|
SubID appendData(bytes const& _data) override;
|
||||||
|
@ -42,10 +42,11 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize)
|
|||||||
BuiltinContext context;
|
BuiltinContext context;
|
||||||
context.currentObject = &_object;
|
context.currentObject = &_object;
|
||||||
|
|
||||||
|
|
||||||
for (auto const& subNode: _object.subObjects)
|
for (auto const& subNode: _object.subObjects)
|
||||||
if (auto* subObject = dynamic_cast<Object*>(subNode.get()))
|
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;
|
context.subIDs[subObject->name] = subAssemblyAndID.second;
|
||||||
subObject->subId = subAssemblyAndID.second;
|
subObject->subId = subAssemblyAndID.second;
|
||||||
compile(*subObject, *subAssemblyAndID.first, m_dialect, m_evm15, _optimize);
|
compile(*subObject, *subAssemblyAndID.first, m_dialect, m_evm15, _optimize);
|
||||||
|
@ -127,7 +127,7 @@ void NoOutputAssembly::appendAssemblySize()
|
|||||||
appendInstruction(evmasm::Instruction::PUSH1);
|
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.");
|
yulAssert(false, "Sub assemblies not implemented.");
|
||||||
return {};
|
return {};
|
||||||
|
@ -67,7 +67,7 @@ public:
|
|||||||
void appendReturnsub(int _returns, int _stackDiffAfter) override;
|
void appendReturnsub(int _returns, int _stackDiffAfter) override;
|
||||||
|
|
||||||
void appendAssemblySize() 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 appendDataOffset(std::vector<SubID> const& _subPath) override;
|
||||||
void appendDataSize(std::vector<SubID> const& _subPath) override;
|
void appendDataSize(std::vector<SubID> const& _subPath) override;
|
||||||
SubID appendData(bytes const& _data) override;
|
SubID appendData(bytes const& _data) override;
|
||||||
|
Loading…
Reference in New Issue
Block a user