Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not store JSON Yul ASTs and Yul CFG in CompilerStack #15451

Merged
merged 2 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Language Features:

Compiler Features:
* Code Generator: Transient storage value type state variables are now supported by the legacy pipeline.
* General: Generate JSON representations of Yul ASTs only on demand to reduce memory usage.


Bugfixes:
Expand Down
79 changes: 39 additions & 40 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,28 @@ void CompilerStack::link()
}
}

YulStack CompilerStack::loadGeneratedIR(std::string const& _ir) const
{
YulStack stack(
m_evmVersion,
m_eofVersion,
YulStack::Language::StrictAssembly,
m_optimiserSettings,
m_debugInfoSelection,
this, // _soliditySourceProvider
m_objectOptimizer
);
bool yulAnalysisSuccessful = stack.parseAndAnalyze("", _ir);
solAssert(
yulAnalysisSuccessful,
_ir + "\n\n"
"Invalid IR generated:\n" +
SourceReferenceFormatter::formatErrorInformation(stack.errors(), stack) + "\n"
);

return stack;
}

std::vector<std::string> CompilerStack::contractNames() const
{
solAssert(m_stackState >= Parsed, "Parsing was not successful.");
Expand Down Expand Up @@ -934,21 +956,24 @@ std::string const& CompilerStack::yulIR(std::string const& _contractName) const
return contract(_contractName).yulIR;
}

Json const& CompilerStack::yulIRAst(std::string const& _contractName) const
Json CompilerStack::yulIRAst(std::string const& _contractName) const
{
solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
solUnimplementedAssert(!isExperimentalSolidity());
return contract(_contractName).yulIRAst;

// NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
// keep it around when compiling a large project containing many contracts.
return loadGeneratedIR(contract(_contractName).yulIR).astJson();
}

Json const& CompilerStack::yulCFGJson(std::string const& _contractName) const
Json CompilerStack::yulCFGJson(std::string const& _contractName) const
{
if (m_stackState != CompilationSuccessful)
solThrow(CompilerError, "Compilation was not successful.");

solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
solUnimplementedAssert(!isExperimentalSolidity());

return contract(_contractName).yulCFGJson;
// NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
// keep it around when compiling a large project containing many contracts.
return loadGeneratedIR(contract(_contractName).yulIR).cfgJson();
}

std::string const& CompilerStack::yulIROptimized(std::string const& _contractName) const
Expand All @@ -957,11 +982,14 @@ std::string const& CompilerStack::yulIROptimized(std::string const& _contractNam
return contract(_contractName).yulIROptimized;
}

Json const& CompilerStack::yulIROptimizedAst(std::string const& _contractName) const
Json CompilerStack::yulIROptimizedAst(std::string const& _contractName) const
{
solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
solUnimplementedAssert(!isExperimentalSolidity());
return contract(_contractName).yulIROptimizedAst;

// NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
// keep it around when compiling a large project containing many contracts.
return loadGeneratedIR(contract(_contractName).yulIROptimized).astJson();
}

evmasm::LinkerObject const& CompilerStack::object(std::string const& _contractName) const
Expand Down Expand Up @@ -1516,30 +1544,11 @@ void CompilerStack::generateIR(ContractDefinition const& _contract, bool _unopti
);
}

YulStack stack(
m_evmVersion,
m_eofVersion,
YulStack::Language::StrictAssembly,
m_optimiserSettings,
m_debugInfoSelection,
this, // _soliditySourceProvider
m_objectOptimizer
);
bool yulAnalysisSuccessful = stack.parseAndAnalyze("", compiledContract.yulIR);
solAssert(
yulAnalysisSuccessful,
compiledContract.yulIR + "\n\n"
"Invalid IR generated:\n" +
SourceReferenceFormatter::formatErrorInformation(stack.errors(), stack) + "\n"
);

compiledContract.yulIRAst = stack.astJson();
compiledContract.yulCFGJson = stack.cfgJson();
YulStack stack = loadGeneratedIR(compiledContract.yulIR);
if (!_unoptimizedOnly)
{
stack.optimize();
compiledContract.yulIROptimized = stack.print();
compiledContract.yulIROptimizedAst = stack.astJson();
}
}

Expand All @@ -1556,17 +1565,7 @@ void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract)
return;

// Re-parse the Yul IR in EVM dialect
yul::YulStack stack(
m_evmVersion,
m_eofVersion,
yul::YulStack::Language::StrictAssembly,
m_optimiserSettings,
m_debugInfoSelection,
this, // _soliditySourceProvider
m_objectOptimizer
);
bool analysisSuccessful = stack.parseAndAnalyze("", compiledContract.yulIROptimized);
solAssert(analysisSuccessful);
YulStack stack = loadGeneratedIR(compiledContract.yulIROptimized);

//cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;

Expand Down
19 changes: 13 additions & 6 deletions libsolidity/interface/CompilerStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ class AssemblyItem;
using AssemblyItems = std::vector<AssemblyItem>;
}

namespace solidity::yul
{
class YulStack;
}

namespace solidity::frontend
{

Expand Down Expand Up @@ -290,15 +295,15 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac
std::string const& yulIR(std::string const& _contractName) const;

/// @returns the IR representation of a contract AST in format.
Json const& yulIRAst(std::string const& _contractName) const;
Json yulIRAst(std::string const& _contractName) const;

/// @returns the optimized IR representation of a contract.
std::string const& yulIROptimized(std::string const& _contractName) const;

/// @returns the optimized IR representation of a contract AST in JSON format.
Json const& yulIROptimizedAst(std::string const& _contractName) const;
Json yulIROptimizedAst(std::string const& _contractName) const;

Json const& yulCFGJson(std::string const& _contractName) const;
Json yulCFGJson(std::string const& _contractName) const;

/// @returns the assembled object for a contract.
virtual evmasm::LinkerObject const& object(std::string const& _contractName) const override;
Expand Down Expand Up @@ -411,9 +416,6 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac
evmasm::LinkerObject runtimeObject; ///< Runtime object.
std::string yulIR; ///< Yul IR code straight from the code generator.
std::string yulIROptimized; ///< Reparsed and possibly optimized Yul IR code.
Json yulIRAst; ///< JSON AST of Yul IR code.
Json yulIROptimizedAst; ///< JSON AST of optimized Yul IR code.
Json yulCFGJson; ///< JSON CFG of Yul IR code.
util::LazyInit<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
util::LazyInit<Json const> abi;
util::LazyInit<Json const> storageLayout;
Expand Down Expand Up @@ -490,6 +492,11 @@ class CompilerStack: public langutil::CharStreamProvider, public evmasm::Abstrac
/// library will still be kept as an unlinked placeholder in the objects.
void link();

/// Parses and analyzes specified Yul source and returns the YulStack that can be used to manipulate it.
/// Assumes that the IR was generated from sources loaded currently into CompilerStack, which
/// means that it is error-free and uses the same settings.
yul::YulStack loadGeneratedIR(std::string const& _ir) const;

/// @returns the contract object for the given @a _contractName.
/// Can only be called after state is CompilationSuccessful.
Contract const& contract(std::string const& _contractName) const;
Expand Down