Handle DebugInfoSelection in the code printing Yul and EVM assembly

This commit is contained in:
Kamil Śliwak 2021-09-03 19:38:59 +02:00
parent 25eedfafe2
commit f7c4ed849d
8 changed files with 96 additions and 35 deletions

View File

@ -96,13 +96,13 @@ public:
m_out(_out), m_prefix(_prefix), m_sourceCodes(_sourceCodes), m_assembly(_assembly)
{}
void feed(AssemblyItem const& _item)
void feed(AssemblyItem const& _item, DebugInfoSelection const& _debugInfoSelection)
{
if (_item.location().isValid() && _item.location() != m_location)
{
flush();
m_location = _item.location();
printLocation();
printLocation(_debugInfoSelection);
}
string expression = _item.toAssemblyText(m_assembly);
@ -142,16 +142,29 @@ public:
m_pending.clear();
}
void printLocation()
void printLocation(DebugInfoSelection const& _debugInfoSelection)
{
if (!m_location.isValid())
if (!m_location.isValid() || (!_debugInfoSelection.location && !_debugInfoSelection.snippet))
return;
m_out << m_prefix << " /*";
if (m_location.sourceName)
m_out << " " + escapeAndQuoteString(*m_location.sourceName);
if (m_location.hasText())
m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end);
m_out << " " << locationFromSources(m_sourceCodes, m_location);
if (_debugInfoSelection.location)
{
if (m_location.sourceName)
m_out << " " + escapeAndQuoteString(*m_location.sourceName);
if (m_location.hasText())
m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end);
}
if (_debugInfoSelection.snippet)
{
if (_debugInfoSelection.location)
m_out << " ";
m_out << locationFromSources(m_sourceCodes, m_location);
}
m_out << " */" << endl;
}
@ -167,12 +180,17 @@ private:
}
void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
void Assembly::assemblyStream(
ostream& _out,
DebugInfoSelection const& _debugInfoSelection,
string const& _prefix,
StringMap const& _sourceCodes
) const
{
Functionalizer f(_out, _prefix, _sourceCodes, *this);
for (auto const& i: m_items)
f.feed(i);
f.feed(i, _debugInfoSelection);
f.flush();
if (!m_data.empty() || !m_subs.empty())
@ -185,7 +203,7 @@ void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap co
for (size_t i = 0; i < m_subs.size(); ++i)
{
_out << endl << _prefix << "sub_" << i << ": assembly {\n";
m_subs[i]->assemblyStream(_out, _prefix + " ", _sourceCodes);
m_subs[i]->assemblyStream(_out, _debugInfoSelection, _prefix + " ", _sourceCodes);
_out << _prefix << "}" << endl;
}
}
@ -194,10 +212,13 @@ void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap co
_out << endl << _prefix << "auxdata: 0x" << util::toHex(m_auxiliaryData) << endl;
}
string Assembly::assemblyString(StringMap const& _sourceCodes) const
string Assembly::assemblyString(
DebugInfoSelection const& _debugInfoSelection,
StringMap const& _sourceCodes
) const
{
ostringstream tmp;
assemblyStream(tmp, "", _sourceCodes);
assemblyStream(tmp, _debugInfoSelection, "", _sourceCodes);
return tmp.str();
}

View File

@ -24,6 +24,7 @@
#include <libevmasm/LinkerObject.h>
#include <libevmasm/Exceptions.h>
#include <liblangutil/DebugInfoSelection.h>
#include <liblangutil/EVMVersion.h>
#include <libsolutil/Common.h>
@ -142,10 +143,12 @@ public:
/// Create a text representation of the assembly.
std::string assemblyString(
langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(),
StringMap const& _sourceCodes = StringMap()
) const;
void assemblyStream(
std::ostream& _out,
langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(),
std::string const& _prefix = "",
StringMap const& _sourceCodes = StringMap()
) const;

View File

@ -135,11 +135,15 @@ string dispenseLocationComment(langutil::SourceLocation const& _location, IRGene
{
solAssert(_location.sourceName, "");
_context.markSourceUsed(*_location.sourceName);
return "/// " + AsmPrinter::formatSourceLocation(
string debugInfo = AsmPrinter::formatSourceLocation(
_location,
_context.sourceIndices(),
_context.debugInfoSelection(),
_context.soliditySourceProvider()
);
return debugInfo.empty() ? "" : "/// " + debugInfo;
}
string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context)

View File

@ -30,6 +30,7 @@
#include <libsolidity/codegen/ir/Common.h>
#include <liblangutil/CharStreamProvider.h>
#include <liblangutil/DebugInfoSelection.h>
#include <liblangutil/EVMVersion.h>
#include <libsolutil/Common.h>
@ -174,6 +175,7 @@ public:
bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); }
langutil::DebugInfoSelection debugInfoSelection() const { return m_debugInfoSelection; }
langutil::CharStreamProvider const* soliditySourceProvider() const { return m_soliditySourceProvider; }
private:
@ -220,6 +222,7 @@ private:
std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects;
langutil::DebugInfoSelection m_debugInfoSelection = langutil::DebugInfoSelection::Default();
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr;
};

View File

@ -340,8 +340,7 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables();
Whiskers t(R"(
/// @ast-id <astID>
<sourceLocationComment>
<astIDComment><sourceLocationComment>
function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> {
<retInit>
<body>
@ -349,7 +348,10 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
<contractSourceLocationComment>
)");
t("astID", to_string(_function.id()));
if (m_context.debugInfoSelection().astID)
t("astIDComment", "/// @ast-id " + to_string(_function.id()) + "\n");
else
t("astIDComment", "");
t("sourceLocationComment", dispenseLocationComment(_function));
t(
"contractSourceLocationComment",
@ -409,8 +411,7 @@ string IRGenerator::generateModifier(
return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables();
Whiskers t(R"(
/// @ast-id <astID>
<sourceLocationComment>
<astIDComment><sourceLocationComment>
function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> {
<assignRetParams>
<evalArgs>
@ -418,6 +419,7 @@ string IRGenerator::generateModifier(
}
<contractSourceLocationComment>
)");
t("functionName", functionName);
vector<string> retParamsIn;
for (auto const& varDecl: _function.returnParameters())
@ -440,7 +442,11 @@ string IRGenerator::generateModifier(
_modifierInvocation.name().annotation().referencedDeclaration
);
solAssert(modifier, "");
t("astID", to_string(modifier->id()));
if (m_context.debugInfoSelection().astID)
t("astIDComment", "/// @ast-id " + to_string(modifier->id()) + "\n");
else
t("astIDComment", "");
t("sourceLocationComment", dispenseLocationComment(*modifier));
t(
"contractSourceLocationComment",
@ -546,14 +552,18 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
solAssert(paramTypes.empty(), "");
solUnimplementedAssert(type->sizeOnStack() == 1);
return Whiskers(R"(
/// @ast-id <astID>
<sourceLocationComment>
<astIDComment><sourceLocationComment>
function <functionName>() -> rval {
rval := loadimmutable("<id>")
}
<contractSourceLocationComment>
)")
("astID", to_string(_varDecl.id()))
(
"astIDComment",
m_context.debugInfoSelection().astID ?
"/// @ast-id " + to_string(_varDecl.id()) + "\n" :
""
)
("sourceLocationComment", dispenseLocationComment(_varDecl))
(
"contractSourceLocationComment",
@ -567,14 +577,18 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
{
solAssert(paramTypes.empty(), "");
return Whiskers(R"(
/// @ast-id <astID>
<sourceLocationComment>
<astIDComment><sourceLocationComment>
function <functionName>() -> <ret> {
<ret> := <constantValueFunction>()
}
<contractSourceLocationComment>
)")
("astID", to_string(_varDecl.id()))
(
"astIDComment",
m_context.debugInfoSelection().astID ?
"/// @ast-id " + to_string(_varDecl.id()) + "\n" :
""
)
("sourceLocationComment", dispenseLocationComment(_varDecl))
(
"contractSourceLocationComment",
@ -691,8 +705,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
}
return Whiskers(R"(
/// @ast-id <astID>
<sourceLocationComment>
<astIDComment><sourceLocationComment>
function <functionName>(<params>) -> <retVariables> {
<code>
}
@ -702,7 +715,12 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
("params", joinHumanReadable(parameters))
("retVariables", joinHumanReadable(returnVariables))
("code", std::move(code))
("astID", to_string(_varDecl.id()))
(
"astIDComment",
m_context.debugInfoSelection().astID ?
"/// @ast-id " + to_string(_varDecl.id()) + "\n" :
""
)
("sourceLocationComment", dispenseLocationComment(_varDecl))
(
"contractSourceLocationComment",
@ -829,7 +847,7 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract)
for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters())
params += m_context.addLocalVariable(*varDecl).stackSlots();
if (contract->constructor())
if (m_context.debugInfoSelection().astID && contract->constructor())
t("astIDComment", "/// @ast-id " + to_string(contract->constructor()->id()) + "\n");
else
t("astIDComment", "");

View File

@ -882,7 +882,7 @@ string CompilerStack::assemblyString(string const& _contractName, StringMap cons
Contract const& currentContract = contract(_contractName);
if (currentContract.evmAssembly)
return currentContract.evmAssembly->assemblyString(_sourceCodes);
return currentContract.evmAssembly->assemblyString(DebugInfoSelection::Default(), _sourceCodes);
else
return string();
}

View File

@ -261,10 +261,16 @@ string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const
string AsmPrinter::formatSourceLocation(
SourceLocation const& _location,
map<string, unsigned> const& _nameToSourceIndex,
DebugInfoSelection const& _debugInfoSelection,
CharStreamProvider const* _soliditySourceProvider
)
{
yulAssert(!_nameToSourceIndex.empty(), "");
if (_debugInfoSelection.snippet)
yulAssert(_debugInfoSelection.location, "@src tag must always contain the source location");
if (_debugInfoSelection.none())
return "";
string sourceIndex = "-1";
string solidityCodeSnippet = "";
@ -272,7 +278,7 @@ string AsmPrinter::formatSourceLocation(
{
sourceIndex = to_string(_nameToSourceIndex.at(*_location.sourceName));
if (_soliditySourceProvider)
if (_debugInfoSelection.snippet && _soliditySourceProvider)
{
solidityCodeSnippet = escapeAndQuoteString(
_soliditySourceProvider->charStream(*_location.sourceName).singleLineSnippet(_location)
@ -298,12 +304,15 @@ string AsmPrinter::formatSourceLocation(
string AsmPrinter::formatDebugData(shared_ptr<DebugData const> const& _debugData, bool _statement)
{
if (!_debugData)
DebugInfoSelection debugInfoSelection = DebugInfoSelection::Default();
if (!_debugData || debugInfoSelection.none())
return "";
vector<string> items;
if (auto id = _debugData->astID)
items.emplace_back("@ast-id " + to_string(*id));
if (debugInfoSelection.astID)
items.emplace_back("@ast-id " + to_string(*id));
if (
m_lastLocation != _debugData->originLocation &&
@ -315,6 +324,7 @@ string AsmPrinter::formatDebugData(shared_ptr<DebugData const> const& _debugData
items.emplace_back(formatSourceLocation(
_debugData->originLocation,
m_nameToSourceIndex,
debugInfoSelection,
m_soliditySourceProvider
));
}

View File

@ -29,6 +29,7 @@
#include <libsolutil/CommonData.h>
#include <liblangutil/CharStreamProvider.h>
#include <liblangutil/DebugInfoSelection.h>
#include <liblangutil/SourceLocation.h>
#include <map>
@ -83,6 +84,7 @@ public:
static std::string formatSourceLocation(
langutil::SourceLocation const& _location,
std::map<std::string, unsigned> const& _nameToSourceIndex,
langutil::DebugInfoSelection const& _debugInfoSelection = langutil::DebugInfoSelection::Default(),
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr
);