mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8868 from ethereum/functionEntryPoints
Note function entry points.
This commit is contained in:
commit
9d156b52c4
@ -6,6 +6,7 @@ Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Standard JSON / combined JSON: New artifact "functionDebugData" that contains bytecode offsets of entry points of functions and potentially more information in the future.
|
||||
* Yul Optimizer: Evaluate ``keccak256(a, c)``, when the value at memory location ``a`` is known at compile time and ``c`` is a constant ``<= 32``.
|
||||
|
||||
|
||||
|
@ -344,6 +344,7 @@ Input Description
|
||||
// storageLayout - Slots, offsets and types of the contract's state variables.
|
||||
// evm.assembly - New assembly format
|
||||
// evm.legacyAssembly - Old-style assembly format in JSON
|
||||
// evm.bytecode.functionDebugData - Debugging information at function level
|
||||
// evm.bytecode.object - Bytecode object
|
||||
// evm.bytecode.opcodes - Opcodes list
|
||||
// evm.bytecode.sourceMap - Source mapping (useful for debugging)
|
||||
@ -476,6 +477,17 @@ Output Description
|
||||
"legacyAssembly": {},
|
||||
// Bytecode and related details.
|
||||
"bytecode": {
|
||||
// Debugging data at the level of functions.
|
||||
"functionDebugData": {
|
||||
// Now follows a set of functions including compiler-internal and
|
||||
// user-defined function. The set does not have to be complete.
|
||||
"@mint_13": { // Internal name of the function
|
||||
"entryPoint": 128, // Byte offset into the bytecode where the function starts (optional)
|
||||
"id": 13, // AST ID of the function definition or null for compiler-internal functions (optional)
|
||||
"parameterSlots": 2, // Number of EVM stack slots for the function parameters (optional)
|
||||
"returnSlots": 1 // Number of EVM stack slots for the return values (optional)
|
||||
}
|
||||
},
|
||||
// The bytecode as a hex string.
|
||||
"object": "00fe",
|
||||
// Opcodes list (string)
|
||||
|
@ -348,12 +348,18 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices)
|
||||
return root;
|
||||
}
|
||||
|
||||
AssemblyItem Assembly::namedTag(string const& _name)
|
||||
AssemblyItem Assembly::namedTag(string const& _name, size_t _params, size_t _returns, optional<uint64_t> _sourceID)
|
||||
{
|
||||
assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");
|
||||
if (!m_namedTags.count(_name))
|
||||
m_namedTags[_name] = static_cast<size_t>(newTag().data());
|
||||
return AssemblyItem{Tag, m_namedTags.at(_name)};
|
||||
if (m_namedTags.count(_name))
|
||||
{
|
||||
assertThrow(m_namedTags.at(_name).params == _params, AssemblyException, "");
|
||||
assertThrow(m_namedTags.at(_name).returns == _returns, AssemblyException, "");
|
||||
assertThrow(m_namedTags.at(_name).sourceID == _sourceID, AssemblyException, "");
|
||||
}
|
||||
else
|
||||
m_namedTags[_name] = {static_cast<size_t>(newTag().data()), _sourceID, _params, _returns};
|
||||
return AssemblyItem{Tag, m_namedTags.at(_name).id};
|
||||
}
|
||||
|
||||
AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier)
|
||||
@ -722,13 +728,16 @@ LinkerObject const& Assembly::assemble() const
|
||||
ret.bytecode.resize(ret.bytecode.size() + 20);
|
||||
break;
|
||||
case Tag:
|
||||
{
|
||||
assertThrow(i.data() != 0, AssemblyException, "Invalid tag position.");
|
||||
assertThrow(i.splitForeignPushTag().first == numeric_limits<size_t>::max(), AssemblyException, "Foreign tag.");
|
||||
size_t tagId = static_cast<size_t>(i.data());
|
||||
assertThrow(ret.bytecode.size() < 0xffffffffL, AssemblyException, "Tag too large.");
|
||||
assertThrow(m_tagPositionsInBytecode[static_cast<size_t>(i.data())] == numeric_limits<size_t>::max(), AssemblyException, "Duplicate tag position.");
|
||||
m_tagPositionsInBytecode[static_cast<size_t>(i.data())] = ret.bytecode.size();
|
||||
assertThrow(m_tagPositionsInBytecode[tagId] == numeric_limits<size_t>::max(), AssemblyException, "Duplicate tag position.");
|
||||
m_tagPositionsInBytecode[tagId] = ret.bytecode.size();
|
||||
ret.bytecode.push_back(static_cast<uint8_t>(Instruction::JUMPDEST));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assertThrow(false, InvalidOpcode, "Unexpected opcode while assembling.");
|
||||
}
|
||||
@ -770,6 +779,17 @@ LinkerObject const& Assembly::assemble() const
|
||||
bytesRef r(ret.bytecode.data() + i.first, bytesPerTag);
|
||||
toBigEndian(pos, r);
|
||||
}
|
||||
for (auto const& [name, tagInfo]: m_namedTags)
|
||||
{
|
||||
size_t position = m_tagPositionsInBytecode.at(tagInfo.id);
|
||||
ret.functionDebugData[name] = {
|
||||
position == numeric_limits<size_t>::max() ? nullopt : optional<size_t>{position},
|
||||
tagInfo.sourceID,
|
||||
tagInfo.params,
|
||||
tagInfo.returns
|
||||
};
|
||||
}
|
||||
|
||||
for (auto const& dataItem: m_data)
|
||||
{
|
||||
auto references = dataRef.equal_range(dataItem.first);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
namespace solidity::evmasm
|
||||
{
|
||||
@ -49,7 +50,7 @@ public:
|
||||
AssemblyItem newTag() { assertThrow(m_usedTags < 0xffffffff, AssemblyException, ""); return AssemblyItem(Tag, 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.
|
||||
AssemblyItem namedTag(std::string const& _name);
|
||||
AssemblyItem namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional<uint64_t> _sourceID);
|
||||
AssemblyItem newData(bytes const& _data) { util::h256 h(util::keccak256(util::asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); }
|
||||
bytes const& data(util::h256 const& _i) const { return m_data.at(_i); }
|
||||
AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); }
|
||||
@ -184,7 +185,16 @@ private:
|
||||
protected:
|
||||
/// 0 is reserved for exception
|
||||
unsigned m_usedTags = 1;
|
||||
std::map<std::string, size_t> m_namedTags;
|
||||
|
||||
struct NamedTagInfo
|
||||
{
|
||||
size_t id;
|
||||
std::optional<size_t> sourceID;
|
||||
size_t params;
|
||||
size_t returns;
|
||||
};
|
||||
|
||||
std::map<std::string, NamedTagInfo> m_namedTags;
|
||||
AssemblyItems m_items;
|
||||
std::map<util::h256, bytes> m_data;
|
||||
/// Data that is appended to the very end of the contract.
|
||||
|
@ -45,6 +45,17 @@ struct LinkerObject
|
||||
/// 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;
|
||||
|
||||
struct FunctionDebugData
|
||||
{
|
||||
std::optional<size_t> bytecodeOffset;
|
||||
std::optional<size_t> sourceID;
|
||||
size_t params = {};
|
||||
size_t returns = {};
|
||||
};
|
||||
|
||||
/// Bytecode offsets of named tags like function entry points.
|
||||
std::map<std::string, FunctionDebugData> functionDebugData;
|
||||
|
||||
/// Appends the bytecode of @a _other and incorporates its link references.
|
||||
void append(LinkerObject const& _other);
|
||||
|
||||
|
@ -148,7 +148,7 @@ void CompilerContext::callYulFunction(
|
||||
m_externallyUsedYulFunctions.insert(_name);
|
||||
auto const retTag = pushNewTag();
|
||||
CompilerUtils(*this).moveIntoStack(_inArgs);
|
||||
appendJumpTo(namedTag(_name), evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
appendJumpTo(namedTag(_name, _inArgs, _outArgs, {}), evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
|
||||
*this << retTag.tag();
|
||||
}
|
||||
@ -596,7 +596,23 @@ evmasm::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel(
|
||||
auto res = m_entryLabels.find(&_declaration);
|
||||
if (res == m_entryLabels.end())
|
||||
{
|
||||
evmasm::AssemblyItem tag(_context.newTag());
|
||||
size_t params = 0;
|
||||
size_t returns = 0;
|
||||
if (auto const* function = dynamic_cast<FunctionDefinition const*>(&_declaration))
|
||||
{
|
||||
FunctionType functionType(*function, FunctionType::Kind::Internal);
|
||||
params = CompilerUtils::sizeOnStack(functionType.parameterTypes());
|
||||
returns = CompilerUtils::sizeOnStack(functionType.returnParameterTypes());
|
||||
}
|
||||
|
||||
// some name that cannot clash with yul function names.
|
||||
string labelName = "@" + _declaration.name() + "_" + to_string(_declaration.id());
|
||||
evmasm::AssemblyItem tag = _context.namedTag(
|
||||
labelName,
|
||||
params,
|
||||
returns,
|
||||
_declaration.id()
|
||||
);
|
||||
m_entryLabels.insert(make_pair(&_declaration, tag));
|
||||
m_functionsToCompile.push(&_declaration);
|
||||
return tag.tag();
|
||||
|
@ -216,7 +216,10 @@ public:
|
||||
/// @returns a new tag without pushing any opcodes or data
|
||||
evmasm::AssemblyItem newTag() { return m_asm->newTag(); }
|
||||
/// @returns a new tag identified by name.
|
||||
evmasm::AssemblyItem namedTag(std::string const& _name) { return m_asm->namedTag(_name); }
|
||||
evmasm::AssemblyItem namedTag(std::string const& _name, size_t _params, size_t _returns, std::optional<uint64_t> _sourceID)
|
||||
{
|
||||
return m_asm->namedTag(_name, _params, _returns, _sourceID);
|
||||
}
|
||||
/// Adds a subroutine to the code (in the data section) and pushes its size (via a tag)
|
||||
/// on the stack. @returns the pushsub assembly item.
|
||||
evmasm::AssemblyItem addSubroutine(evmasm::AssemblyPointer const& _assembly) { return m_asm->appendSubroutine(_assembly); }
|
||||
|
@ -241,7 +241,7 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil
|
||||
vector<string> evmObjectComponents(string const& _objectKind)
|
||||
{
|
||||
solAssert(_objectKind == "bytecode" || _objectKind == "deployedBytecode", "");
|
||||
vector<string> components{"", ".object", ".opcodes", ".sourceMap", ".generatedSources", ".linkReferences"};
|
||||
vector<string> components{"", ".object", ".opcodes", ".sourceMap", ".functionDebugData", ".generatedSources", ".linkReferences"};
|
||||
if (_objectKind == "deployedBytecode")
|
||||
components.push_back(".immutableReferences");
|
||||
return util::applyMap(components, [&](auto const& _s) { return "evm." + _objectKind + _s; });
|
||||
@ -388,6 +388,8 @@ Json::Value collectEVMObject(
|
||||
output["opcodes"] = evmasm::disassemble(_object.bytecode);
|
||||
if (_artifactRequested("sourceMap"))
|
||||
output["sourceMap"] = _sourceMap ? *_sourceMap : "";
|
||||
if (_artifactRequested("functionDebugData"))
|
||||
output["functionDebugData"] = StandardCompiler::formatFunctionDebugData(_object.functionDebugData);
|
||||
if (_artifactRequested("linkReferences"))
|
||||
output["linkReferences"] = formatLinkReferences(_object.linkReferences);
|
||||
if (_runtimeObject && _artifactRequested("immutableReferences"))
|
||||
@ -614,6 +616,7 @@ std::variant<OptimiserSettings, Json::Value> parseOptimizerSettings(Json::Value
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler::parseInput(Json::Value const& _input)
|
||||
{
|
||||
InputsAndSettings ret;
|
||||
@ -1423,3 +1426,27 @@ string StandardCompiler::compile(string const& _input) noexcept
|
||||
return "{\"errors\":[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error writing output JSON.\"}]}";
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value StandardCompiler::formatFunctionDebugData(
|
||||
map<string, evmasm::LinkerObject::FunctionDebugData> const& _debugInfo
|
||||
)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
for (auto const& [name, info]: _debugInfo)
|
||||
{
|
||||
Json::Value fun;
|
||||
if (info.sourceID)
|
||||
fun["id"] = Json::UInt64(*info.sourceID);
|
||||
else
|
||||
fun["id"] = Json::nullValue;
|
||||
if (info.bytecodeOffset)
|
||||
fun["entryPoint"] = Json::UInt64(*info.bytecodeOffset);
|
||||
else
|
||||
fun["entryPoint"] = Json::nullValue;
|
||||
fun["parameterSlots"] = Json::UInt64(info.params);
|
||||
fun["returnSlots"] = Json::UInt64(info.returns);
|
||||
ret[name] = move(fun);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -58,6 +58,10 @@ public:
|
||||
/// output. Parsing errors are returned as regular errors.
|
||||
std::string compile(std::string const& _input) noexcept;
|
||||
|
||||
static Json::Value formatFunctionDebugData(
|
||||
std::map<std::string, evmasm::LinkerObject::FunctionDebugData> const& _debugInfo
|
||||
);
|
||||
|
||||
private:
|
||||
struct InputsAndSettings
|
||||
{
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
@ -74,7 +75,7 @@ public:
|
||||
/// Generate a new unique label.
|
||||
virtual LabelID newLabelId() = 0;
|
||||
/// Returns a label identified by the given name. Creates it if it does not yet exist.
|
||||
virtual LabelID namedLabel(std::string const& _name) = 0;
|
||||
virtual LabelID namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional<size_t> _sourceID) = 0;
|
||||
/// Append a reference to a to-be-linked symbol.
|
||||
/// Currently, we assume that the value is always a 20 byte number.
|
||||
virtual void appendLinkerSymbol(std::string const& _name) = 0;
|
||||
|
@ -78,7 +78,7 @@ EVMAssembly::LabelID EVMAssembly::newLabelId()
|
||||
return m_nextLabelId++;
|
||||
}
|
||||
|
||||
AbstractAssembly::LabelID EVMAssembly::namedLabel(string const& _name)
|
||||
AbstractAssembly::LabelID EVMAssembly::namedLabel(string const& _name, size_t, size_t, std::optional<size_t>)
|
||||
{
|
||||
yulAssert(!_name.empty(), "");
|
||||
if (!m_namedLabels.count(_name))
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
/// Generate a new unique label.
|
||||
LabelID newLabelId() override;
|
||||
/// Returns a label identified by the given name. Creates it if it does not yet exist.
|
||||
LabelID namedLabel(std::string const& _name) override;
|
||||
LabelID namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional<size_t> _sourceID) override;
|
||||
/// Append a reference to a to-be-linked symbol.
|
||||
/// Currently, we assume that the value is always a 20 byte number.
|
||||
void appendLinkerSymbol(std::string const& _name) override;
|
||||
|
@ -578,7 +578,7 @@ AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope:
|
||||
{
|
||||
AbstractAssembly::LabelID id =
|
||||
m_useNamedLabelsForFunctions ?
|
||||
m_assembly.namedLabel(_name.str()) :
|
||||
m_assembly.namedLabel(_name.str(), _function.arguments.size(), _function.returns.size(), {}) :
|
||||
m_assembly.newLabelId();
|
||||
m_context->functionEntryIDs[&_function] = id;
|
||||
}
|
||||
|
@ -84,9 +84,9 @@ size_t EthAssemblyAdapter::newLabelId()
|
||||
return assemblyTagToIdentifier(m_assembly.newTag());
|
||||
}
|
||||
|
||||
size_t EthAssemblyAdapter::namedLabel(std::string const& _name)
|
||||
size_t EthAssemblyAdapter::namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional<size_t> _sourceID)
|
||||
{
|
||||
return assemblyTagToIdentifier(m_assembly.namedTag(_name));
|
||||
return assemblyTagToIdentifier(m_assembly.namedTag(_name, _params, _returns, _sourceID));
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendLinkerSymbol(std::string const& _linkerSymbol)
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
void appendLabel(LabelID _labelId) override;
|
||||
void appendLabelReference(LabelID _labelId) override;
|
||||
size_t newLabelId() override;
|
||||
size_t namedLabel(std::string const& _name) override;
|
||||
size_t namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional<size_t> _sourceID) override;
|
||||
void appendLinkerSymbol(std::string const& _linkerSymbol) override;
|
||||
void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override;
|
||||
void appendJump(int _stackDiffAfter, JumpType _jumpType) override;
|
||||
|
@ -59,7 +59,7 @@ NoOutputAssembly::LabelID NoOutputAssembly::newLabelId()
|
||||
return 1;
|
||||
}
|
||||
|
||||
AbstractAssembly::LabelID NoOutputAssembly::namedLabel(string const&)
|
||||
AbstractAssembly::LabelID NoOutputAssembly::namedLabel(string const&, size_t, size_t, optional<size_t>)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
void appendLabel(LabelID _labelId) override;
|
||||
void appendLabelReference(LabelID _labelId) override;
|
||||
LabelID newLabelId() override;
|
||||
LabelID namedLabel(std::string const& _name) override;
|
||||
LabelID namedLabel(std::string const& _name, size_t _params, size_t _returns, std::optional<size_t> _sourceID) override;
|
||||
void appendLinkerSymbol(std::string const& _name) override;
|
||||
void appendVerbatim(bytes _data, size_t _arguments, size_t _returnVariables) override;
|
||||
|
||||
|
@ -189,6 +189,8 @@ static string const g_strSources = "sources";
|
||||
static string const g_strSourceList = "sourceList";
|
||||
static string const g_strSrcMap = "srcmap";
|
||||
static string const g_strSrcMapRuntime = "srcmap-runtime";
|
||||
static string const g_strFunDebug = "function-debug";
|
||||
static string const g_strFunDebugRuntime = "function-debug-runtime";
|
||||
static string const g_strStandardJSON = "standard-json";
|
||||
static string const g_strStrictAssembly = "strict-assembly";
|
||||
static string const g_strSwarm = "swarm";
|
||||
@ -257,6 +259,8 @@ static set<string> const g_combinedJsonArgs
|
||||
g_strBinary,
|
||||
g_strBinaryRuntime,
|
||||
g_strCompactJSON,
|
||||
g_strFunDebug,
|
||||
g_strFunDebugRuntime,
|
||||
g_strGeneratedSources,
|
||||
g_strGeneratedSourcesRuntime,
|
||||
g_strInterface,
|
||||
@ -1672,6 +1676,14 @@ void CommandLineInterface::handleCombinedJSON()
|
||||
auto map = m_compiler->runtimeSourceMapping(contractName);
|
||||
contractData[g_strSrcMapRuntime] = map ? *map : "";
|
||||
}
|
||||
if (requests.count(g_strFunDebug) && m_compiler->compilationSuccessful())
|
||||
contractData[g_strFunDebug] = StandardCompiler::formatFunctionDebugData(
|
||||
m_compiler->object(contractName).functionDebugData
|
||||
);
|
||||
if (requests.count(g_strFunDebugRuntime) && m_compiler->compilationSuccessful())
|
||||
contractData[g_strFunDebugRuntime] = StandardCompiler::formatFunctionDebugData(
|
||||
m_compiler->runtimeObject(contractName).functionDebugData
|
||||
);
|
||||
if (requests.count(g_strSignatureHashes))
|
||||
contractData[g_strSignatureHashes] = m_compiler->methodIdentifiers(contractName);
|
||||
if (requests.count(g_strNatspecDev))
|
||||
|
1
test/cmdlineTests/function_debug_info/args
Normal file
1
test/cmdlineTests/function_debug_info/args
Normal file
@ -0,0 +1 @@
|
||||
--optimize --combined-json function-debug,function-debug-runtime --pretty-json
|
1
test/cmdlineTests/function_debug_info/err
Normal file
1
test/cmdlineTests/function_debug_info/err
Normal file
@ -0,0 +1 @@
|
||||
|
11
test/cmdlineTests/function_debug_info/input.sol
Normal file
11
test/cmdlineTests/function_debug_info/input.sol
Normal file
@ -0,0 +1,11 @@
|
||||
pragma solidity >=0.0;
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
contract C {
|
||||
function f(uint[] calldata x) pure external returns (uint) { return x[0]; }
|
||||
// This will be optimized out
|
||||
function g() pure internal {}
|
||||
mapping(uint => uint) public t;
|
||||
constructor(uint x) {
|
||||
t[0] = x;
|
||||
}
|
||||
}
|
57
test/cmdlineTests/function_debug_info/output
Normal file
57
test/cmdlineTests/function_debug_info/output
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"contracts":
|
||||
{
|
||||
"function_debug_info/input.sol:C":
|
||||
{
|
||||
"function-debug":
|
||||
{
|
||||
"@_34":
|
||||
{
|
||||
"id": 34,
|
||||
"parameterSlots": 1,
|
||||
"returnSlots": 0
|
||||
},
|
||||
"abi_decode_tuple_t_uint256_fromMemory":
|
||||
{
|
||||
"entryPoint": 94,
|
||||
"parameterSlots": 2,
|
||||
"returnSlots": 1
|
||||
}
|
||||
},
|
||||
"function-debug-runtime":
|
||||
{
|
||||
"@f_14":
|
||||
{
|
||||
"entryPoint": 128,
|
||||
"id": 14,
|
||||
"parameterSlots": 2,
|
||||
"returnSlots": 1
|
||||
},
|
||||
"@t_22":
|
||||
{
|
||||
"id": 22,
|
||||
"parameterSlots": 0,
|
||||
"returnSlots": 0
|
||||
},
|
||||
"abi_decode_tuple_t_array$_t_uint256_$dyn_calldata_ptr":
|
||||
{
|
||||
"entryPoint": 178,
|
||||
"parameterSlots": 2,
|
||||
"returnSlots": 2
|
||||
},
|
||||
"abi_decode_tuple_t_uint256":
|
||||
{
|
||||
"entryPoint": 295,
|
||||
"parameterSlots": 2,
|
||||
"returnSlots": 1
|
||||
},
|
||||
"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed":
|
||||
{
|
||||
"parameterSlots": 2,
|
||||
"returnSlots": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": "<VERSION REMOVED>"
|
||||
}
|
1
test/cmdlineTests/function_debug_info_via_yul/args
Normal file
1
test/cmdlineTests/function_debug_info_via_yul/args
Normal file
@ -0,0 +1 @@
|
||||
--experimental-via-ir --optimize --combined-json function-debug,function-debug-runtime --pretty-json
|
1
test/cmdlineTests/function_debug_info_via_yul/err
Normal file
1
test/cmdlineTests/function_debug_info_via_yul/err
Normal file
@ -0,0 +1 @@
|
||||
|
7
test/cmdlineTests/function_debug_info_via_yul/input.sol
Normal file
7
test/cmdlineTests/function_debug_info_via_yul/input.sol
Normal file
@ -0,0 +1,7 @@
|
||||
pragma solidity >=0.0;
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
contract C {
|
||||
function f(uint[] calldata x) pure external returns (uint) { return x[0]; }
|
||||
// This will be optimized out
|
||||
function g() pure internal {}
|
||||
}
|
11
test/cmdlineTests/function_debug_info_via_yul/output
Normal file
11
test/cmdlineTests/function_debug_info_via_yul/output
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"contracts":
|
||||
{
|
||||
"function_debug_info_via_yul/input.sol:C":
|
||||
{
|
||||
"function-debug": {},
|
||||
"function-debug-runtime": {}
|
||||
}
|
||||
},
|
||||
"version": "<VERSION REMOVED>"
|
||||
}
|
18
test/cmdlineTests/standard_function_debug_info/input.json
Normal file
18
test/cmdlineTests/standard_function_debug_info/input.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources": {
|
||||
"a.sol": {
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; pragma abicoder v2; contract A { function f(uint[] memory x) public pure returns (uint256) { return x[0] + x[1];} }"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"A": [
|
||||
"evm.deployedBytecode.functionDebugData",
|
||||
"evm.bytecode.functionDebugData"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"functionDebugData":{}},"deployedBytecode":{"functionDebugData":{"@f_19":{"entryPoint":96,"id":19,"parameterSlots":1,"returnSlots":1},"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":247,"id":null,"parameterSlots":3,"returnSlots":1},"abi_decode_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":359,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_t_uint256":{"entryPoint":405,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":426,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_t_uint256_to_t_uint256_fromStack":{"entryPoint":499,"id":null,"parameterSlots":2,"returnSlots":0},"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed":{"entryPoint":514,"id":null,"parameterSlots":2,"returnSlots":1},"allocate_memory":{"entryPoint":541,"id":null,"parameterSlots":1,"returnSlots":1},"allocate_unbounded":{"entryPoint":568,"id":null,"parameterSlots":0,"returnSlots":1},"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":578,"id":null,"parameterSlots":1,"returnSlots":1},"checked_add_t_uint256":{"entryPoint":622,"id":null,"parameterSlots":2,"returnSlots":1},"cleanup_t_uint256":{"entryPoint":708,"id":null,"parameterSlots":1,"returnSlots":1},"finalize_allocation":{"entryPoint":718,"id":null,"parameterSlots":2,"returnSlots":0},"panic_error_0x11":{"entryPoint":767,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x41":{"entryPoint":814,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d":{"entryPoint":861,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef":{"entryPoint":866,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db":{"entryPoint":871,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b":{"entryPoint":876,"id":null,"parameterSlots":0,"returnSlots":0},"round_up_to_mul_of_32":{"entryPoint":881,"id":null,"parameterSlots":1,"returnSlots":1},"validator_revert_t_uint256":{"entryPoint":898,"id":null,"parameterSlots":1,"returnSlots":0}}}}}}},"sources":{"a.sol":{"id":0}}}
|
@ -14,7 +14,7 @@
|
||||
sstore
|
||||
/* \"A\":0:42 */
|
||||
pop
|
||||
","bytecode":{"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"object\" {
|
||||
","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"object\" {
|
||||
code {
|
||||
let x := mload(0)
|
||||
sstore(add(x, 0), 0)
|
||||
|
@ -13,7 +13,7 @@
|
||||
pop
|
||||
stop
|
||||
data_4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 616263
|
||||
","bytecode":{"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"NamedObject\" {
|
||||
","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"NamedObject\" {
|
||||
code {
|
||||
let x := dataoffset(\"DataName\")
|
||||
sstore(add(x, 0), 0)
|
||||
|
@ -22,7 +22,7 @@ sub_0: assembly {
|
||||
/* \"A\":137:149 */
|
||||
revert
|
||||
}
|
||||
","bytecode":{"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"},"deployedBytecode":{"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"NamedObject\" {
|
||||
","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"NamedObject\" {
|
||||
code {
|
||||
let x := dataoffset(\"DataName\")
|
||||
sstore(add(x, 0), 0)
|
||||
|
@ -13,7 +13,7 @@
|
||||
/* \"A\":20:40 */
|
||||
sstore
|
||||
pop
|
||||
","bytecode":{"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"object\" {
|
||||
","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"object\" {
|
||||
code {
|
||||
let x := mload(0)
|
||||
sstore(add(x, 0), 0)
|
||||
|
@ -5,7 +5,7 @@
|
||||
mload
|
||||
/* \"A\":20:40 */
|
||||
sstore
|
||||
","bytecode":{"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"object\" {
|
||||
","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"<BYTECODE REMOVED>","opcodes":"<OPCODES REMOVED>","sourceMap":"<SOURCEMAP REMOVED>"}},"ir":"object \"object\" {
|
||||
code {
|
||||
let x := mload(0)
|
||||
sstore(add(x, 0), 0)
|
||||
|
Loading…
Reference in New Issue
Block a user