mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8581 from ethereum/immutableDebug
Debug information for immutable references.
This commit is contained in:
commit
3f52ee43a8
@ -302,7 +302,8 @@ Input Description
|
||||
// evm.bytecode.opcodes - Opcodes list
|
||||
// evm.bytecode.sourceMap - Source mapping (useful for debugging)
|
||||
// evm.bytecode.linkReferences - Link references (if unlinked object)
|
||||
// evm.deployedBytecode* - Deployed bytecode (has the same options as evm.bytecode)
|
||||
// evm.deployedBytecode* - Deployed bytecode (has all the options that evm.bytecode has)
|
||||
// evm.deployedBytecode.immutableReferences - Map from AST ids to bytecode ranges that reference immutables
|
||||
// evm.methodIdentifiers - The list of function hashes
|
||||
// evm.gasEstimates - Function gas estimates
|
||||
// ewasm.wast - eWASM S-expressions format (not supported at the moment)
|
||||
@ -424,8 +425,14 @@ Output Description
|
||||
}
|
||||
}
|
||||
},
|
||||
// The same layout as above.
|
||||
"deployedBytecode": { },
|
||||
"deployedBytecode": {
|
||||
..., // The same layout as above.
|
||||
"immutableReferences": [
|
||||
// There are two references to the immutable with AST ID 3, both 32 bytes long. One is
|
||||
// at bytecode offset 42, the other at bytecode offset 80.
|
||||
"3": [{ "start": 42, "length": 32 }, { "start": 80, "length": 32 }]
|
||||
]
|
||||
},
|
||||
// The list of function hashes
|
||||
"methodIdentifiers": {
|
||||
"delegate(address)": "5c19a95c"
|
||||
|
@ -530,7 +530,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
LinkerObject& ret = m_assembledObject;
|
||||
|
||||
size_t subTagSize = 1;
|
||||
map<u256, vector<size_t>> immutableReferencesBySub;
|
||||
map<u256, pair<string, vector<size_t>>> immutableReferencesBySub;
|
||||
for (auto const& sub: m_subs)
|
||||
{
|
||||
auto const& linkerObject = sub->assemble();
|
||||
@ -554,7 +554,7 @@ LinkerObject const& Assembly::assemble() const
|
||||
for (auto const& i: m_items)
|
||||
if (i.type() == AssignImmutable)
|
||||
{
|
||||
i.setImmutableOccurrences(immutableReferencesBySub[i.data()].size());
|
||||
i.setImmutableOccurrences(immutableReferencesBySub[i.data()].second.size());
|
||||
setsImmutables = true;
|
||||
}
|
||||
else if (i.type() == PushImmutable)
|
||||
@ -660,11 +660,12 @@ LinkerObject const& Assembly::assemble() const
|
||||
break;
|
||||
case PushImmutable:
|
||||
ret.bytecode.push_back(uint8_t(Instruction::PUSH32));
|
||||
ret.immutableReferences[i.data()].emplace_back(ret.bytecode.size());
|
||||
ret.immutableReferences[i.data()].first = m_immutables.at(i.data());
|
||||
ret.immutableReferences[i.data()].second.emplace_back(ret.bytecode.size());
|
||||
ret.bytecode.resize(ret.bytecode.size() + 32);
|
||||
break;
|
||||
case AssignImmutable:
|
||||
for (auto const& offset: immutableReferencesBySub[i.data()])
|
||||
for (auto const& offset: immutableReferencesBySub[i.data()].second)
|
||||
{
|
||||
ret.bytecode.push_back(uint8_t(Instruction::DUP1));
|
||||
// TODO: should we make use of the constant optimizer methods for pushing the offsets?
|
||||
|
@ -40,9 +40,9 @@ struct LinkerObject
|
||||
/// need to be replaced by the actual addresses by the linker.
|
||||
std::map<size_t, std::string> linkReferences;
|
||||
|
||||
/// Map from hashes of the identifiers of immutable variables to a list of offsets into the bytecode
|
||||
/// that refer to their values.
|
||||
std::map<u256, std::vector<size_t>> immutableReferences;
|
||||
/// Map from hashes of the identifiers of immutable variables to the full identifier of the immutable and
|
||||
/// to a list of offsets into the bytecode that refer to their values.
|
||||
std::map<u256, std::pair<std::string, std::vector<size_t>>> immutableReferences;
|
||||
|
||||
/// Appends the bytecode of @a _other and incorporates its link references.
|
||||
void append(LinkerObject const& _other);
|
||||
|
@ -90,13 +90,7 @@ size_t CompilerContext::immutableMemoryOffset(VariableDeclaration const& _variab
|
||||
|
||||
vector<string> CompilerContext::immutableVariableSlotNames(VariableDeclaration const& _variable)
|
||||
{
|
||||
string baseName =
|
||||
_variable.annotation().contract->fullyQualifiedName() +
|
||||
"." +
|
||||
_variable.name() +
|
||||
" (" +
|
||||
to_string(_variable.id()) +
|
||||
")";
|
||||
string baseName = to_string(_variable.id());
|
||||
solAssert(_variable.annotation().type->sizeOnStack() > 0, "");
|
||||
if (_variable.annotation().type->sizeOnStack() == 1)
|
||||
return {baseName};
|
||||
|
@ -234,6 +234,7 @@ bool isBinaryRequested(Json::Value const& _outputSelection)
|
||||
"wast", "wasm", "ewasm.wast", "ewasm.wasm",
|
||||
"evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes",
|
||||
"evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences",
|
||||
"evm.deployedBytecode.immutableReferences",
|
||||
"evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap",
|
||||
"evm.bytecode.linkReferences",
|
||||
"evm.gasEstimates", "evm.legacyAssembly", "evm.assembly"
|
||||
@ -309,13 +310,36 @@ Json::Value formatLinkReferences(std::map<size_t, std::string> const& linkRefere
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value collectEVMObject(evmasm::LinkerObject const& _object, string const* _sourceMap)
|
||||
Json::Value formatImmutableReferences(map<u256, pair<string, vector<size_t>>> const& _immutableReferences)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
for (auto const& immutableReference: _immutableReferences)
|
||||
{
|
||||
auto const& [identifier, byteOffsets] = immutableReference.second;
|
||||
Json::Value array(Json::arrayValue);
|
||||
for (size_t byteOffset: byteOffsets)
|
||||
{
|
||||
Json::Value byteRange(Json::objectValue);
|
||||
byteRange["start"] = Json::UInt(byteOffset);
|
||||
byteRange["length"] = Json::UInt(32); // immutable references are currently always 32 bytes wide
|
||||
array.append(byteRange);
|
||||
}
|
||||
ret[identifier] = array;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value collectEVMObject(evmasm::LinkerObject const& _object, string const* _sourceMap, bool _runtimeObject)
|
||||
{
|
||||
Json::Value output = Json::objectValue;
|
||||
output["object"] = _object.toHex();
|
||||
output["opcodes"] = evmasm::disassemble(_object.bytecode);
|
||||
output["sourceMap"] = _sourceMap ? *_sourceMap : "";
|
||||
output["linkReferences"] = formatLinkReferences(_object.linkReferences);
|
||||
if (_runtimeObject)
|
||||
output["immutableReferences"] = formatImmutableReferences(_object.immutableReferences);
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -982,19 +1006,21 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
))
|
||||
evmData["bytecode"] = collectEVMObject(
|
||||
compilerStack.object(contractName),
|
||||
compilerStack.sourceMapping(contractName)
|
||||
compilerStack.sourceMapping(contractName),
|
||||
false
|
||||
);
|
||||
|
||||
if (compilationSuccess && isArtifactRequested(
|
||||
_inputsAndSettings.outputSelection,
|
||||
file,
|
||||
name,
|
||||
{ "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences" },
|
||||
{ "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences", "evm.deployedBytecode.immutableReferences" },
|
||||
wildcardMatchesExperimental
|
||||
))
|
||||
evmData["deployedBytecode"] = collectEVMObject(
|
||||
compilerStack.runtimeObject(contractName),
|
||||
compilerStack.runtimeSourceMapping(contractName)
|
||||
compilerStack.runtimeSourceMapping(contractName),
|
||||
true
|
||||
);
|
||||
|
||||
if (!evmData.empty())
|
||||
@ -1081,7 +1107,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
|
||||
{ "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());
|
||||
output["contracts"][sourceName][contractName]["evm"]["bytecode"] = collectEVMObject(*object.bytecode, object.sourceMappings.get(), false);
|
||||
|
||||
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "irOptimized", wildcardMatchesExperimental))
|
||||
output["contracts"][sourceName][contractName]["irOptimized"] = stack.print();
|
||||
|
18
test/cmdlineTests/standard_immutable_references/input.json
Normal file
18
test/cmdlineTests/standard_immutable_references/input.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources": {
|
||||
"a.sol": {
|
||||
"content": "contract A { uint256 immutable x = 1; function f() public view returns (uint256) { return x; } }"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"evmVersion": "petersburg",
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"A": [
|
||||
"evm.deployedBytecode.immutableReferences"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"0:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;0:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;38:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;72:7;90:1;83:8;;38:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
|
||||
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}}
|
Loading…
Reference in New Issue
Block a user