Provide runtime object in Yul mode.

This commit is contained in:
chriseth 2020-05-12 16:33:05 +02:00
parent 142a6b0d4f
commit f92a4f1965
5 changed files with 72 additions and 26 deletions

View File

@ -52,6 +52,7 @@ public:
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); }
size_t numSubs() const { return m_subs.size(); }
AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); }
AssemblyItem newPushLibraryAddress(std::string const& _identifier);
AssemblyItem newPushImmutable(std::string const& _identifier);

View File

@ -30,6 +30,7 @@
#include <libevmasm/Instruction.h>
#include <libsolutil/JSON.h>
#include <libsolutil/Keccak256.h>
#include <libsolutil/CommonData.h>
#include <boost/algorithm/string/predicate.hpp>
@ -1127,16 +1128,29 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
stack.optimize();
MachineAssemblyObject object = stack.assemble(AssemblyStack::Machine::EVM);
MachineAssemblyObject object;
MachineAssemblyObject runtimeObject;
tie(object, runtimeObject) = stack.assembleAndGuessRuntime();
if (isArtifactRequested(
_inputsAndSettings.outputSelection,
sourceName,
contractName,
{ "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" },
wildcardMatchesExperimental
))
output["contracts"][sourceName][contractName]["evm"]["bytecode"] = collectEVMObject(*object.bytecode, object.sourceMappings.get(), false);
for (string const& objectKind: vector<string>{"bytecode", "deployedBytecode"})
{
auto artifacts = util::applyMap(
vector<string>{"", ".object", ".opcodes", ".sourceMap", ".linkReferences"},
[&](auto const& _s) { return "evm." + objectKind + _s; }
);
if (isArtifactRequested(
_inputsAndSettings.outputSelection,
sourceName,
contractName,
artifacts,
wildcardMatchesExperimental
))
{
MachineAssemblyObject const& o = objectKind == "bytecode" ? object : runtimeObject;
if (o.bytecode)
output["contracts"][sourceName][contractName]["evm"][objectKind] = collectEVMObject(*o.bytecode, o.sourceMappings.get(), false);
}
}
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "irOptimized", wildcardMatchesExperimental))
output["contracts"][sourceName][contractName]["irOptimized"] = stack.print();

View File

@ -198,22 +198,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
switch (_machine)
{
case Machine::EVM:
{
MachineAssemblyObject object;
evmasm::Assembly assembly;
EthAssemblyAdapter adapter(assembly);
compileEVM(adapter, false, m_optimiserSettings.optimizeStackAllocation);
object.bytecode = make_shared<evmasm::LinkerObject>(assembly.assemble());
yulAssert(object.bytecode->immutableReferences.empty(), "Leftover immutables.");
object.assembly = assembly.assemblyString();
object.sourceMappings = make_unique<string>(
evmasm::AssemblyItem::computeSourceMapping(
assembly.items(),
{{scanner().charStream() ? scanner().charStream()->name() : "", 0}}
)
);
return object;
}
return assembleAndGuessRuntime().first;
case Machine::EVM15:
{
MachineAssemblyObject object;
@ -240,6 +225,46 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
return MachineAssemblyObject();
}
pair<MachineAssemblyObject, MachineAssemblyObject> AssemblyStack::assembleAndGuessRuntime() const
{
yulAssert(m_analysisSuccessful, "");
yulAssert(m_parserResult, "");
yulAssert(m_parserResult->code, "");
yulAssert(m_parserResult->analysisInfo, "");
evmasm::Assembly assembly;
EthAssemblyAdapter adapter(assembly);
compileEVM(adapter, false, m_optimiserSettings.optimizeStackAllocation);
MachineAssemblyObject creationObject;
creationObject.bytecode = make_shared<evmasm::LinkerObject>(assembly.assemble());
yulAssert(creationObject.bytecode->immutableReferences.empty(), "Leftover immutables.");
creationObject.assembly = assembly.assemblyString();
creationObject.sourceMappings = make_unique<string>(
evmasm::AssemblyItem::computeSourceMapping(
assembly.items(),
{{scanner().charStream() ? scanner().charStream()->name() : "", 0}}
)
);
MachineAssemblyObject runtimeObject;
// Heuristic: If there is a single sub-assembly, this is likely the runtime object.
if (assembly.numSubs() == 1)
{
evmasm::Assembly& runtimeAssembly = assembly.sub(0);
runtimeObject.bytecode = make_shared<evmasm::LinkerObject>(runtimeAssembly.assemble());
runtimeObject.assembly = runtimeAssembly.assemblyString();
runtimeObject.sourceMappings = make_unique<string>(
evmasm::AssemblyItem::computeSourceMapping(
runtimeAssembly.items(),
{{scanner().charStream() ? scanner().charStream()->name() : "", 0}}
)
);
}
return {std::move(creationObject), std::move(runtimeObject)};
}
string AssemblyStack::print() const
{
yulAssert(m_parserResult, "");

View File

@ -88,6 +88,12 @@ public:
/// Run the assembly step (should only be called after parseAndAnalyze).
MachineAssemblyObject assemble(Machine _machine) 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 guessed to be the runtime code.
/// Only available for EVM.
std::pair<MachineAssemblyObject, MachineAssemblyObject> assembleAndGuessRuntime() const;
/// @returns the errors generated during parsing, analysis (and potentially assembly).
langutil::ErrorList const& errors() const { return m_errors; }

View File

@ -22,7 +22,7 @@ sub_0: assembly {
/* \"A\":137:149 */
revert
}
","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"NamedObject\" {
","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"},"deployedBytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"NamedObject\" {
code {
let x := dataoffset(\"DataName\")
sstore(add(x, 0), 0)