From 81652686bed7c3eed85ea63f012562da478101f8 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 2 Apr 2020 17:27:35 +0200 Subject: [PATCH] Debug information for immutable references. --- libevmasm/Assembly.cpp | 9 ++--- libevmasm/LinkerObject.h | 6 ++-- libsolidity/codegen/CompilerContext.cpp | 8 +---- libsolidity/interface/StandardCompiler.cpp | 36 ++++++++++++++++--- .../standard_immutable_references/input.json | 18 ++++++++++ .../standard_immutable_references/output.json | 2 ++ 6 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 test/cmdlineTests/standard_immutable_references/input.json create mode 100644 test/cmdlineTests/standard_immutable_references/output.json diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index e67ccb8f5..fa6ea4f16 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -530,7 +530,7 @@ LinkerObject const& Assembly::assemble() const LinkerObject& ret = m_assembledObject; size_t subTagSize = 1; - map> immutableReferencesBySub; + map>> 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? diff --git a/libevmasm/LinkerObject.h b/libevmasm/LinkerObject.h index ccf5588bb..ab0e26507 100644 --- a/libevmasm/LinkerObject.h +++ b/libevmasm/LinkerObject.h @@ -40,9 +40,9 @@ struct LinkerObject /// need to be replaced by the actual addresses by the linker. std::map 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> 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>> immutableReferences; /// Appends the bytecode of @a _other and incorporates its link references. void append(LinkerObject const& _other); diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 6984a030b..06080afbd 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -90,13 +90,7 @@ size_t CompilerContext::immutableMemoryOffset(VariableDeclaration const& _variab vector 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}; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 77e00df05..00662718e 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -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 const& linkRefere return ret; } -Json::Value collectEVMObject(evmasm::LinkerObject const& _object, string const* _sourceMap) +Json::Value formatImmutableReferences(map>> 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::arrayValue); + byteRange.append(Json::UInt(byteOffset)); + byteRange.append(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(); diff --git a/test/cmdlineTests/standard_immutable_references/input.json b/test/cmdlineTests/standard_immutable_references/input.json new file mode 100644 index 000000000..15213be74 --- /dev/null +++ b/test/cmdlineTests/standard_immutable_references/input.json @@ -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" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_immutable_references/output.json b/test/cmdlineTests/standard_immutable_references/output.json new file mode 100644 index 000000000..1ba91eff7 --- /dev/null +++ b/test/cmdlineTests/standard_immutable_references/output.json @@ -0,0 +1,2 @@ +{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[[77,32]]},"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}}}