Skip to content

Commit

Permalink
fixup! Introduce sub-assembly offset output artifact
Browse files Browse the repository at this point in the history
  • Loading branch information
nikola-matic committed Jan 29, 2025
1 parent 3ca7e4b commit b1f4b68
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 156 deletions.
36 changes: 10 additions & 26 deletions libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1200,13 +1200,11 @@ LinkerObject const& Assembly::assembleLegacy() const
solAssert(m_assembledObject.linkReferences.empty());

LinkerObject& ret = m_assembledObject;

size_t subTagSize = 1;
std::map<u256, LinkerObject::ImmutableRefs> immutableReferencesBySub;
std::vector<LinkerObject> subAssemblies;
for (auto const& sub: m_subs)
{
auto const& linkerObject = sub->assemble();
auto const& linkerObject = sub->assembleLegacy();
if (!linkerObject.immutableReferences.empty())
{
assertThrow(
Expand All @@ -1216,7 +1214,6 @@ LinkerObject const& Assembly::assembleLegacy() const
);
immutableReferencesBySub = linkerObject.immutableReferences;
}
subAssemblies.push_back(linkerObject);
for (size_t tagPos: sub->m_tagPositionsInBytecode)
if (tagPos != std::numeric_limits<size_t>::max() && numberEncodingSize(tagPos) > subTagSize)
subTagSize = numberEncodingSize(tagPos);
Expand Down Expand Up @@ -1261,7 +1258,7 @@ LinkerObject const& Assembly::assembleLegacy() const

unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + static_cast<unsigned>(m_auxiliaryData.size());
for (auto const& sub: m_subs)
bytesRequiredIncludingData += static_cast<unsigned>(sub->assemble().bytecode.size());
bytesRequiredIncludingData += static_cast<unsigned>(sub->assembleLegacy().bytecode.size());

unsigned bytesPerDataRef = numberEncodingSize(bytesRequiredIncludingData);
ret.bytecode.reserve(bytesRequiredIncludingData);
Expand Down Expand Up @@ -1308,7 +1305,7 @@ LinkerObject const& Assembly::assembleLegacy() const
case PushSubSize:
{
assertThrow(item.data() <= std::numeric_limits<size_t>::max(), AssemblyException, "");
auto s = subAssemblyById(static_cast<size_t>(item.data()))->assemble().bytecode.size();
auto s = subAssemblyById(static_cast<size_t>(item.data()))->assembleLegacy().bytecode.size();
item.setPushedValue(u256(s));
unsigned b = std::max<unsigned>(1, numberEncodingSize(s));
ret.bytecode.push_back(static_cast<uint8_t>(pushInstruction(b)));
Expand Down Expand Up @@ -1395,7 +1392,7 @@ LinkerObject const& Assembly::assembleLegacy() const
std::map<LinkerObject, size_t> subAssemblyOffsets;
for (auto const& [subIdPath, bytecodeOffset]: subRefs)
{
LinkerObject subObject = subAssemblyById(subIdPath)->assemble();
LinkerObject subObject = subAssemblyById(subIdPath)->assembleLegacy();
bytesRef r(ret.bytecode.data() + bytecodeOffset, bytesPerDataRef);

// In order for de-duplication to kick in, not only must the bytecode be identical, but
Expand All @@ -1407,6 +1404,12 @@ LinkerObject const& Assembly::assembleLegacy() const
toBigEndian(ret.bytecode.size(), r);
subAssemblyOffsets[subObject] = ret.bytecode.size();
ret.bytecode += subObject.bytecode;
ret.subAssemblyData.push_back({
subAssemblyOffsets[subObject],
subObject.bytecode.size(),
subAssemblyById(subIdPath)->isCreation(),
subObject.subAssemblyData
});
}
for (auto const& ref: subObject.linkReferences)
ret.linkReferences[ref.first + subAssemblyOffsets[subObject]] = ref.second;
Expand Down Expand Up @@ -1467,16 +1470,6 @@ LinkerObject const& Assembly::assembleLegacy() const
bytesRef r(ret.bytecode.data() + pos, bytesPerDataRef);
toBigEndian(ret.bytecode.size(), r);
}

std::vector<LinkerObject::SubAssembly> nestedSubAssemblies{};
for (auto const& subAssembly: subAssemblies)
nestedSubAssemblies.insert(nestedSubAssemblies.end(), subAssembly.subAssemblyData.begin(), subAssembly.subAssemblyData.end());

size_t const currentBytecodeSize = ret.bytecode.size();
updateSubAssemblyStartOffsets(nestedSubAssemblies, currentBytecodeSize);

ret.subAssemblyData.push_back({0, ret.bytecode.size(), isCreation(), ret.toHex(), nestedSubAssemblies});

return ret;
}

Expand Down Expand Up @@ -1788,12 +1781,3 @@ Assembly::OptimiserSettings Assembly::OptimiserSettings::translateSettings(front
asmSettings.evmVersion = _evmVersion;
return asmSettings;
}

void Assembly::updateSubAssemblyStartOffsets(std::vector<LinkerObject::SubAssembly>& _subAssemblies, size_t const _currentBytecodeSize) const
{
for (auto& subAssembly: _subAssemblies)
{
subAssembly.start = _currentBytecodeSize - subAssembly.length;
updateSubAssemblyStartOffsets(subAssembly.subs, _currentBytecodeSize);
}
}
3 changes: 1 addition & 2 deletions libevmasm/Assembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,6 @@ class Assembly

private:
bool m_invalid = false;

Assembly const* subAssemblyById(size_t _subId) const;

void encodeAllPossibleSubPathsInAssemblyTree(std::vector<size_t> _pathFromRoot = {}, std::vector<Assembly*> _assembliesOnPath = {});
Expand All @@ -287,7 +286,7 @@ class Assembly
[[nodiscard]] bytes assemblePushDeployTimeAddress() const;
[[nodiscard]] bytes assembleTag(AssemblyItem const& _item, size_t _pos, bool _addJumpDest) const;

void updateSubAssemblyStartOffsets(std::vector<LinkerObject::SubAssembly>& _subAssemblies, size_t const _currentBytecodeSize) const;
void updateSubAssemblyStartOffsets(std::vector<LinkerObject::Structure>& _subAssemblies, size_t const _currentBytecodeSize) const;

protected:
/// 0 is reserved for exception
Expand Down
7 changes: 3 additions & 4 deletions libevmasm/LinkerObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,14 @@ struct LinkerObject
/// Bytecode offsets of named tags like function entry points.
std::map<std::string, FunctionDebugData> functionDebugData;

struct SubAssembly {
struct Structure {
size_t start;
size_t length;
bool isCreation;
std::string bytecode;
std::vector<SubAssembly> subs {};
std::vector<Structure> subassemblies {};
};

std::vector<SubAssembly> subAssemblyData;
std::vector<Structure> subAssemblyData;

/// Appends the bytecode of @a _other and incorporates its link references.
void append(LinkerObject const& _other);
Expand Down
56 changes: 26 additions & 30 deletions libsolidity/interface/StandardCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ bool isArtifactRequested(Json const& _outputSelection, std::string const& _file,
std::vector<std::string> evmObjectComponents(std::string const& _objectKind)
{
solAssert(_objectKind == "bytecode" || _objectKind == "deployedBytecode", "");
std::vector<std::string> components{"", ".object", ".opcodes", ".sourceMap", ".functionDebugData", ".generatedSources", ".linkReferences", ".subAssemblyOffsets"};
std::vector<std::string> components{"", ".object", ".opcodes", ".sourceMap", ".functionDebugData", ".generatedSources", ".linkReferences", ".assemblyStructure"};
if (_objectKind == "deployedBytecode")
components.push_back(".immutableReferences");
return util::applyMap(components, [&](auto const& _s) { return "evm." + _objectKind + _s; });
Expand Down Expand Up @@ -374,22 +374,22 @@ Json formatImmutableReferences(std::map<u256, evmasm::LinkerObject::ImmutableRef
return ret;
}

Json formatSubAssemblyOffsets(std::vector<evmasm::LinkerObject::SubAssembly> const& _subAssemblyOffsets)
Json formatAssemblyStructure(std::vector<evmasm::LinkerObject::Structure> const& _assemblyStructure)
{
Json subs = Json::array();
Json subassemblies = Json::array();

for (auto const& subAssembly: _subAssemblyOffsets)
for (auto const& subAssembly: _assemblyStructure)
{
Json subAssemblyInfo;
subAssemblyInfo["start"] = Json::number_unsigned_t(subAssembly.start);
subAssemblyInfo["length"] = Json::number_unsigned_t(subAssembly.length);
subAssemblyInfo["isCreation"] = Json::boolean_t(subAssembly.isCreation);
if (!subAssembly.subs.empty())
subAssemblyInfo["subs"] = formatSubAssemblyOffsets(subAssembly.subs);
subs.emplace_back(subAssemblyInfo);
Json assemblyStructure;
assemblyStructure["start"] = Json::number_unsigned_t(subAssembly.start);
assemblyStructure["length"] = Json::number_unsigned_t(subAssembly.length);
assemblyStructure["isCreation"] = Json::boolean_t(subAssembly.isCreation);
if (!subAssembly.subassemblies.empty())
assemblyStructure["subassemblies"] = formatAssemblyStructure(subAssembly.subassemblies);
subassemblies.emplace_back(assemblyStructure);
}

return subs;
return subassemblies;
}

std::optional<Json> checkKeys(Json const& _input, std::set<std::string> const& _keys, std::string const& _name)
Expand Down Expand Up @@ -1253,12 +1253,13 @@ Json StandardCompiler::importEVMAssembly(StandardCompiler::InputsAndSettings _in
creationJSON["functionDebugData"] = formatFunctionDebugData(stack.object(sourceName).functionDebugData);
if (evmCreationArtifactRequested("linkReferences"))
creationJSON["linkReferences"] = formatLinkReferences(stack.object(sourceName).linkReferences);
if (evmCreationArtifactRequested("subAssemblyOffsets"))
{
Json ret = Json::object();
ret["subs"] = formatSubAssemblyOffsets(stack.runtimeObject(sourceName).subAssemblyData);
creationJSON["subAssemblyOffsets"] = std::move(ret);
}
if (evmCreationArtifactRequested("assemblyStructure"))
creationJSON["assemblyStructure"] = {
{"start", 0},
{"length", stack.object(sourceName).bytecode.size()},
{"isCreation", true},
{"subassemblies", formatAssemblyStructure(stack.object(sourceName).subAssemblyData)}
};
evmData["bytecode"] = creationJSON;
}

Expand Down Expand Up @@ -1527,12 +1528,13 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu
creationJSON["linkReferences"] = formatLinkReferences(compilerStack.object(contractName).linkReferences);
if (evmCreationArtifactRequested("generatedSources"))
creationJSON["generatedSources"] = compilerStack.generatedSources(contractName, /* _runtime */ false);
if (evmCreationArtifactRequested("subAssemblyOffsets"))
{
Json ret = Json::object();
ret["subs"] = formatSubAssemblyOffsets(compilerStack.object(contractName).subAssemblyData);
creationJSON["subAssemblyOffsets"] = std::move(ret);
}
if (evmCreationArtifactRequested("assemblyStructure"))
creationJSON["assemblyStructure"] = {
{"start", 0},
{"length", compilerStack.object(contractName).bytecode.size()},
{"isCreation", true},
{"subassemblies", formatAssemblyStructure(compilerStack.object(contractName).subAssemblyData)}
};
evmData["bytecode"] = creationJSON;
}

Expand Down Expand Up @@ -1563,12 +1565,6 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu
deployedJSON["immutableReferences"] = formatImmutableReferences(compilerStack.runtimeObject(contractName).immutableReferences);
if (evmDeployedArtifactRequested("generatedSources"))
deployedJSON["generatedSources"] = compilerStack.generatedSources(contractName, /* _runtime */ true);
if (evmDeployedArtifactRequested("subAssemblyOffsets"))
{
Json ret = Json::object();
ret["subs"] = formatSubAssemblyOffsets(compilerStack.object(contractName).subAssemblyData);
deployedJSON["subAssemblyOffsets"] = std::move(ret);
}
evmData["deployedBytecode"] = deployedJSON;
}

Expand Down
11 changes: 7 additions & 4 deletions test/cmdlineTests/standard_import_asm_json/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
0x00
",
"bytecode": {
"assemblyStructure": {
"isCreation": true,
"length": 1,
"start": 0,
"subassemblies": []
},
"functionDebugData": {},
"linkReferences": {},
"object": "<BYTECODE REMOVED>",
"opcodes":"<OPCODES REMOVED>",
"sourceMap":"<SOURCEMAP REMOVED>",
"subAssemblyOffsets": {
"subs": []
}
"sourceMap":"<SOURCEMAP REMOVED>"
},
"deployedBytecode": {
"functionDebugData": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@
"": {
"evm": {
"bytecode": {
"assemblyStructure": {
"isCreation": true,
"length": 5,
"start": 0,
"subassemblies": []
},
"functionDebugData": {},
"linkReferences": {},
"object": "<BYTECODE REMOVED>",
"opcodes":"<OPCODES REMOVED>",
"sourceMap":"<SOURCEMAP REMOVED>",
"subAssemblyOffsets": {
"subs": [
{
"isCreation": false,
"length": 87,
"start": 0
}
]
}
"sourceMap":"<SOURCEMAP REMOVED>"
},
"deployedBytecode": {
"functionDebugData": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@
"": {
"evm": {
"bytecode": {
"assemblyStructure": {
"isCreation": true,
"length": 1,
"start": 0,
"subassemblies": []
},
"functionDebugData": {},
"linkReferences": {},
"object": "<BYTECODE REMOVED>",
"opcodes":"<OPCODES REMOVED>",
"sourceMap": "",
"subAssemblyOffsets": {
"subs": [
{
"isCreation": false,
"length": 75,
"start": 0
}
]
}
"sourceMap": ""
},
"deployedBytecode": {
"functionDebugData": {},
Expand Down
30 changes: 13 additions & 17 deletions test/cmdlineTests/standard_import_ast_select_bytecode/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,24 @@
"test": {
"evm": {
"bytecode": {
"assemblyStructure": {
"isCreation": true,
"length": 130,
"start": 0,
"subassemblies": [
{
"isCreation": false,
"length": 104,
"start": 26
}
]
},
"functionDebugData": {},
"generatedSources": [],
"linkReferences": {},
"object": "<BYTECODE REMOVED>",
"opcodes":"<OPCODES REMOVED>",
"sourceMap":"<SOURCEMAP REMOVED>",
"subAssemblyOffsets": {
"subs": [
{
"isCreation": true,
"length": 130,
"start": 0,
"subs": [
{
"isCreation": false,
"length": 104,
"start": 26
}
]
}
]
}
"sourceMap":"<SOURCEMAP REMOVED>"
}
}
}
Expand Down
30 changes: 13 additions & 17 deletions test/cmdlineTests/standard_no_append_cbor/output.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,24 @@
"test": {
"evm": {
"bytecode": {
"assemblyStructure": {
"isCreation": true,
"length": 27,
"start": 0,
"subassemblies": [
{
"isCreation": false,
"length": 3,
"start": 24
}
]
},
"functionDebugData": {},
"generatedSources": [],
"linkReferences": {},
"object": "<BYTECODE REMOVED>",
"opcodes":"<OPCODES REMOVED>",
"sourceMap":"<SOURCEMAP REMOVED>",
"subAssemblyOffsets": {
"subs": [
{
"isCreation": true,
"length": 27,
"start": 0,
"subs": [
{
"isCreation": false,
"length": 3,
"start": 24
}
]
}
]
}
"sourceMap":"<SOURCEMAP REMOVED>"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/cmdlineTests/standard_subassembly_offsets/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"outputSelection": {
"*": {
"Storage": [
"evm.bytecode.subAssemblyOffsets"
"evm.bytecode.assemblyStructure"
]
}
}
Expand Down
Loading

0 comments on commit b1f4b68

Please sign in to comment.