mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Purge using namespace std from libyul/backends
Signed-off-by: Jun Zhang <jun@junz.org>
This commit is contained in:
parent
37e18612c5
commit
1ebdab43d8
@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
#include <libsolutil/StackTooDeepString.h>
|
#include <libsolutil/StackTooDeepString.h>
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
@ -48,9 +47,9 @@ struct MiniEVMInterpreter
|
|||||||
return std::visit(*this, _expr);
|
return std::visit(*this, _expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 eval(evmasm::Instruction _instr, vector<Expression> const& _arguments)
|
u256 eval(evmasm::Instruction _instr, std::vector<Expression> const& _arguments)
|
||||||
{
|
{
|
||||||
vector<u256> args;
|
std::vector<u256> args;
|
||||||
for (auto const& arg: _arguments)
|
for (auto const& arg: _arguments)
|
||||||
args.emplace_back(eval(arg));
|
args.emplace_back(eval(arg));
|
||||||
switch (_instr)
|
switch (_instr)
|
||||||
@ -92,7 +91,7 @@ struct MiniEVMInterpreter
|
|||||||
|
|
||||||
void ConstantOptimiser::visit(Expression& _e)
|
void ConstantOptimiser::visit(Expression& _e)
|
||||||
{
|
{
|
||||||
if (holds_alternative<Literal>(_e))
|
if (std::holds_alternative<Literal>(_e))
|
||||||
{
|
{
|
||||||
Literal const& literal = std::get<Literal>(_e);
|
Literal const& literal = std::get<Literal>(_e);
|
||||||
if (literal.kind != LiteralKind::Number)
|
if (literal.kind != LiteralKind::Number)
|
||||||
@ -115,7 +114,7 @@ Expression const* RepresentationFinder::tryFindRepresentation(u256 const& _value
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Representation const& repr = findRepresentation(_value);
|
Representation const& repr = findRepresentation(_value);
|
||||||
if (holds_alternative<Literal>(*repr.expression))
|
if (std::holds_alternative<Literal>(*repr.expression))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
else
|
else
|
||||||
return repr.expression.get();
|
return repr.expression.get();
|
||||||
@ -180,7 +179,7 @@ Representation const& RepresentationFinder::findRepresentation(u256 const& _valu
|
|||||||
Representation RepresentationFinder::represent(u256 const& _value) const
|
Representation RepresentationFinder::represent(u256 const& _value) const
|
||||||
{
|
{
|
||||||
Representation repr;
|
Representation repr;
|
||||||
repr.expression = make_unique<Expression>(Literal{m_debugData, LiteralKind::Number, YulString{formatNumber(_value)}, {}});
|
repr.expression = std::make_unique<Expression>(Literal{m_debugData, LiteralKind::Number, YulString{formatNumber(_value)}, {}});
|
||||||
repr.cost = m_meter.costs(*repr.expression);
|
repr.cost = m_meter.costs(*repr.expression);
|
||||||
return repr;
|
return repr;
|
||||||
}
|
}
|
||||||
@ -191,7 +190,7 @@ Representation RepresentationFinder::represent(
|
|||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
Representation repr;
|
Representation repr;
|
||||||
repr.expression = make_unique<Expression>(FunctionCall{
|
repr.expression = std::make_unique<Expression>(FunctionCall{
|
||||||
m_debugData,
|
m_debugData,
|
||||||
Identifier{m_debugData, _instruction},
|
Identifier{m_debugData, _instruction},
|
||||||
{ASTCopier{}.translate(*_argument.expression)}
|
{ASTCopier{}.translate(*_argument.expression)}
|
||||||
@ -207,7 +206,7 @@ Representation RepresentationFinder::represent(
|
|||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
Representation repr;
|
Representation repr;
|
||||||
repr.expression = make_unique<Expression>(FunctionCall{
|
repr.expression = std::make_unique<Expression>(FunctionCall{
|
||||||
m_debugData,
|
m_debugData,
|
||||||
Identifier{m_debugData, _instruction},
|
Identifier{m_debugData, _instruction},
|
||||||
{ASTCopier{}.translate(*_arg1.expression), ASTCopier{}.translate(*_arg2.expression)}
|
{ASTCopier{}.translate(*_arg1.expression), ASTCopier{}.translate(*_arg2.expression)}
|
||||||
|
@ -45,7 +45,6 @@
|
|||||||
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -82,15 +81,15 @@ void cleanUnreachable(CFG& _cfg)
|
|||||||
/// Sets the ``recursive`` member to ``true`` for all recursive function calls.
|
/// Sets the ``recursive`` member to ``true`` for all recursive function calls.
|
||||||
void markRecursiveCalls(CFG& _cfg)
|
void markRecursiveCalls(CFG& _cfg)
|
||||||
{
|
{
|
||||||
map<CFG::BasicBlock*, vector<CFG::FunctionCall*>> callsPerBlock;
|
std::map<CFG::BasicBlock*, std::vector<CFG::FunctionCall*>> callsPerBlock;
|
||||||
auto const& findCalls = [&](CFG::BasicBlock* _block)
|
auto const& findCalls = [&](CFG::BasicBlock* _block)
|
||||||
{
|
{
|
||||||
if (auto* calls = util::valueOrNullptr(callsPerBlock, _block))
|
if (auto* calls = util::valueOrNullptr(callsPerBlock, _block))
|
||||||
return *calls;
|
return *calls;
|
||||||
vector<CFG::FunctionCall*>& calls = callsPerBlock[_block];
|
std::vector<CFG::FunctionCall*>& calls = callsPerBlock[_block];
|
||||||
util::BreadthFirstSearch<CFG::BasicBlock*>{{_block}}.run([&](CFG::BasicBlock* _block, auto _addChild) {
|
util::BreadthFirstSearch<CFG::BasicBlock*>{{_block}}.run([&](CFG::BasicBlock* _block, auto _addChild) {
|
||||||
for (auto& operation: _block->operations)
|
for (auto& operation: _block->operations)
|
||||||
if (auto* functionCall = get_if<CFG::FunctionCall>(&operation.operation))
|
if (auto* functionCall = std::get_if<CFG::FunctionCall>(&operation.operation))
|
||||||
calls.emplace_back(functionCall);
|
calls.emplace_back(functionCall);
|
||||||
std::visit(util::GenericVisitor{
|
std::visit(util::GenericVisitor{
|
||||||
[&](CFG::BasicBlock::MainExit const&) {},
|
[&](CFG::BasicBlock::MainExit const&) {},
|
||||||
@ -131,7 +130,7 @@ void markRecursiveCalls(CFG& _cfg)
|
|||||||
/// Entering such a block means that control flow will never return to a previously visited block.
|
/// Entering such a block means that control flow will never return to a previously visited block.
|
||||||
void markStartsOfSubGraphs(CFG& _cfg)
|
void markStartsOfSubGraphs(CFG& _cfg)
|
||||||
{
|
{
|
||||||
vector<CFG::BasicBlock*> entries;
|
std::vector<CFG::BasicBlock*> entries;
|
||||||
entries.emplace_back(_cfg.entry);
|
entries.emplace_back(_cfg.entry);
|
||||||
for (auto&& functionInfo: _cfg.functionInfo | ranges::views::values)
|
for (auto&& functionInfo: _cfg.functionInfo | ranges::views::values)
|
||||||
entries.emplace_back(functionInfo.entry);
|
entries.emplace_back(functionInfo.entry);
|
||||||
@ -141,17 +140,17 @@ void markStartsOfSubGraphs(CFG& _cfg)
|
|||||||
* Detect bridges following Algorithm 1 in https://arxiv.org/pdf/2108.07346.pdf
|
* Detect bridges following Algorithm 1 in https://arxiv.org/pdf/2108.07346.pdf
|
||||||
* and mark the bridge targets as starts of sub-graphs.
|
* and mark the bridge targets as starts of sub-graphs.
|
||||||
*/
|
*/
|
||||||
set<CFG::BasicBlock*> visited;
|
std::set<CFG::BasicBlock*> visited;
|
||||||
map<CFG::BasicBlock*, size_t> disc;
|
std::map<CFG::BasicBlock*, size_t> disc;
|
||||||
map<CFG::BasicBlock*, size_t> low;
|
std::map<CFG::BasicBlock*, size_t> low;
|
||||||
map<CFG::BasicBlock*, CFG::BasicBlock*> parent;
|
std::map<CFG::BasicBlock*, CFG::BasicBlock*> parent;
|
||||||
size_t time = 0;
|
size_t time = 0;
|
||||||
auto dfs = [&](CFG::BasicBlock* _u, auto _recurse) -> void {
|
auto dfs = [&](CFG::BasicBlock* _u, auto _recurse) -> void {
|
||||||
visited.insert(_u);
|
visited.insert(_u);
|
||||||
disc[_u] = low[_u] = time;
|
disc[_u] = low[_u] = time;
|
||||||
time++;
|
time++;
|
||||||
|
|
||||||
vector<CFG::BasicBlock*> children = _u->entries;
|
std::vector<CFG::BasicBlock*> children = _u->entries;
|
||||||
visit(util::GenericVisitor{
|
visit(util::GenericVisitor{
|
||||||
[&](CFG::BasicBlock::Jump const& _jump) {
|
[&](CFG::BasicBlock::Jump const& _jump) {
|
||||||
children.emplace_back(_jump.target);
|
children.emplace_back(_jump.target);
|
||||||
@ -171,7 +170,7 @@ void markStartsOfSubGraphs(CFG& _cfg)
|
|||||||
{
|
{
|
||||||
parent[v] = _u;
|
parent[v] = _u;
|
||||||
_recurse(v, _recurse);
|
_recurse(v, _recurse);
|
||||||
low[_u] = min(low[_u], low[v]);
|
low[_u] = std::min(low[_u], low[v]);
|
||||||
if (low[v] > disc[_u])
|
if (low[v] > disc[_u])
|
||||||
{
|
{
|
||||||
// _u <-> v is a cut edge in the undirected graph
|
// _u <-> v is a cut edge in the undirected graph
|
||||||
@ -186,7 +185,7 @@ void markStartsOfSubGraphs(CFG& _cfg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (v != parent[_u])
|
else if (v != parent[_u])
|
||||||
low[_u] = min(low[_u], disc[v]);
|
low[_u] = std::min(low[_u], disc[v]);
|
||||||
};
|
};
|
||||||
dfs(entry, dfs);
|
dfs(entry, dfs);
|
||||||
}
|
}
|
||||||
@ -234,7 +233,7 @@ std::unique_ptr<CFG> ControlFlowGraphBuilder::build(
|
|||||||
ControlFlowGraphBuilder::ControlFlowGraphBuilder(
|
ControlFlowGraphBuilder::ControlFlowGraphBuilder(
|
||||||
CFG& _graph,
|
CFG& _graph,
|
||||||
AsmAnalysisInfo const& _analysisInfo,
|
AsmAnalysisInfo const& _analysisInfo,
|
||||||
map<FunctionDefinition const*, ControlFlowSideEffects> const& _functionSideEffects,
|
std::map<FunctionDefinition const*, ControlFlowSideEffects> const& _functionSideEffects,
|
||||||
Dialect const& _dialect
|
Dialect const& _dialect
|
||||||
):
|
):
|
||||||
m_graph(_graph),
|
m_graph(_graph),
|
||||||
@ -271,7 +270,7 @@ void ControlFlowGraphBuilder::operator()(VariableDeclaration const& _varDecl)
|
|||||||
yulAssert(m_currentBlock, "");
|
yulAssert(m_currentBlock, "");
|
||||||
auto declaredVariables = _varDecl.variables | ranges::views::transform([&](TypedName const& _var) {
|
auto declaredVariables = _varDecl.variables | ranges::views::transform([&](TypedName const& _var) {
|
||||||
return VariableSlot{lookupVariable(_var.name), _var.debugData};
|
return VariableSlot{lookupVariable(_var.name), _var.debugData};
|
||||||
}) | ranges::to<vector<VariableSlot>>;
|
}) | ranges::to<std::vector<VariableSlot>>;
|
||||||
Stack input;
|
Stack input;
|
||||||
if (_varDecl.value)
|
if (_varDecl.value)
|
||||||
input = visitAssignmentRightHandSide(*_varDecl.value, declaredVariables.size());
|
input = visitAssignmentRightHandSide(*_varDecl.value, declaredVariables.size());
|
||||||
@ -287,7 +286,7 @@ void ControlFlowGraphBuilder::operator()(Assignment const& _assignment)
|
|||||||
{
|
{
|
||||||
auto assignedVariables = _assignment.variableNames | ranges::views::transform([&](Identifier const& _var) {
|
auto assignedVariables = _assignment.variableNames | ranges::views::transform([&](Identifier const& _var) {
|
||||||
return VariableSlot{lookupVariable(_var.name), _var.debugData};
|
return VariableSlot{lookupVariable(_var.name), _var.debugData};
|
||||||
}) | ranges::to<vector<VariableSlot>>;
|
}) | ranges::to<std::vector<VariableSlot>>;
|
||||||
|
|
||||||
Stack input = visitAssignmentRightHandSide(*_assignment.value, assignedVariables.size());
|
Stack input = visitAssignmentRightHandSide(*_assignment.value, assignedVariables.size());
|
||||||
yulAssert(m_currentBlock);
|
yulAssert(m_currentBlock);
|
||||||
@ -314,7 +313,7 @@ void ControlFlowGraphBuilder::operator()(Block const& _block)
|
|||||||
{
|
{
|
||||||
ScopedSaveAndRestore saveScope(m_scope, m_info.scopes.at(&_block).get());
|
ScopedSaveAndRestore saveScope(m_scope, m_info.scopes.at(&_block).get());
|
||||||
for (auto const& statement: _block.statements)
|
for (auto const& statement: _block.statements)
|
||||||
if (auto const* function = get_if<FunctionDefinition>(&statement))
|
if (auto const* function = std::get_if<FunctionDefinition>(&statement))
|
||||||
registerFunction(*function);
|
registerFunction(*function);
|
||||||
for (auto const& statement: _block.statements)
|
for (auto const& statement: _block.statements)
|
||||||
std::visit(*this, statement);
|
std::visit(*this, statement);
|
||||||
@ -334,10 +333,10 @@ void ControlFlowGraphBuilder::operator()(If const& _if)
|
|||||||
void ControlFlowGraphBuilder::operator()(Switch const& _switch)
|
void ControlFlowGraphBuilder::operator()(Switch const& _switch)
|
||||||
{
|
{
|
||||||
yulAssert(m_currentBlock, "");
|
yulAssert(m_currentBlock, "");
|
||||||
shared_ptr<DebugData const> preSwitchDebugData = debugDataOf(_switch);
|
std::shared_ptr<DebugData const> preSwitchDebugData = debugDataOf(_switch);
|
||||||
|
|
||||||
auto ghostVariableId = m_graph.ghostVariables.size();
|
auto ghostVariableId = m_graph.ghostVariables.size();
|
||||||
YulString ghostVariableName("GHOST[" + to_string(ghostVariableId) + "]");
|
YulString ghostVariableName("GHOST[" + std::to_string(ghostVariableId) + "]");
|
||||||
auto& ghostVar = m_graph.ghostVariables.emplace_back(Scope::Variable{""_yulstring, ghostVariableName});
|
auto& ghostVar = m_graph.ghostVariables.emplace_back(Scope::Variable{""_yulstring, ghostVariableName});
|
||||||
|
|
||||||
// Artificially generate:
|
// Artificially generate:
|
||||||
@ -394,12 +393,12 @@ void ControlFlowGraphBuilder::operator()(Switch const& _switch)
|
|||||||
|
|
||||||
void ControlFlowGraphBuilder::operator()(ForLoop const& _loop)
|
void ControlFlowGraphBuilder::operator()(ForLoop const& _loop)
|
||||||
{
|
{
|
||||||
shared_ptr<DebugData const> preLoopDebugData = debugDataOf(_loop);
|
std::shared_ptr<DebugData const> preLoopDebugData = debugDataOf(_loop);
|
||||||
ScopedSaveAndRestore scopeRestore(m_scope, m_info.scopes.at(&_loop.pre).get());
|
ScopedSaveAndRestore scopeRestore(m_scope, m_info.scopes.at(&_loop.pre).get());
|
||||||
(*this)(_loop.pre);
|
(*this)(_loop.pre);
|
||||||
|
|
||||||
std::optional<bool> constantCondition;
|
std::optional<bool> constantCondition;
|
||||||
if (auto const* literalCondition = get_if<yul::Literal>(_loop.condition.get()))
|
if (auto const* literalCondition = std::get_if<yul::Literal>(_loop.condition.get()))
|
||||||
constantCondition = valueOfLiteral(*literalCondition) != 0;
|
constantCondition = valueOfLiteral(*literalCondition) != 0;
|
||||||
|
|
||||||
CFG::BasicBlock& loopCondition = m_graph.makeBlock(debugDataOf(*_loop.condition));
|
CFG::BasicBlock& loopCondition = m_graph.makeBlock(debugDataOf(*_loop.condition));
|
||||||
@ -497,13 +496,13 @@ void ControlFlowGraphBuilder::registerFunction(FunctionDefinition const& _functi
|
|||||||
std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_param.name)),
|
std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_param.name)),
|
||||||
_param.debugData
|
_param.debugData
|
||||||
};
|
};
|
||||||
}) | ranges::to<vector>,
|
}) | ranges::to<std::vector>,
|
||||||
_functionDefinition.returnVariables | ranges::views::transform([&](auto const& _retVar) {
|
_functionDefinition.returnVariables | ranges::views::transform([&](auto const& _retVar) {
|
||||||
return VariableSlot{
|
return VariableSlot{
|
||||||
std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_retVar.name)),
|
std::get<Scope::Variable>(virtualFunctionScope->identifiers.at(_retVar.name)),
|
||||||
_retVar.debugData
|
_retVar.debugData
|
||||||
};
|
};
|
||||||
}) | ranges::to<vector>,
|
}) | ranges::to<std::vector>,
|
||||||
{},
|
{},
|
||||||
m_functionSideEffects.at(&_functionDefinition).canContinue
|
m_functionSideEffects.at(&_functionDefinition).canContinue
|
||||||
})).second;
|
})).second;
|
||||||
@ -609,7 +608,7 @@ Scope::Variable const& ControlFlowGraphBuilder::lookupVariable(YulString _name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ControlFlowGraphBuilder::makeConditionalJump(
|
void ControlFlowGraphBuilder::makeConditionalJump(
|
||||||
shared_ptr<DebugData const> _debugData,
|
std::shared_ptr<DebugData const> _debugData,
|
||||||
StackSlot _condition,
|
StackSlot _condition,
|
||||||
CFG::BasicBlock& _nonZero,
|
CFG::BasicBlock& _nonZero,
|
||||||
CFG::BasicBlock& _zero
|
CFG::BasicBlock& _zero
|
||||||
@ -628,7 +627,7 @@ void ControlFlowGraphBuilder::makeConditionalJump(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ControlFlowGraphBuilder::jump(
|
void ControlFlowGraphBuilder::jump(
|
||||||
shared_ptr<DebugData const> _debugData,
|
std::shared_ptr<DebugData const> _debugData,
|
||||||
CFG::BasicBlock& _target,
|
CFG::BasicBlock& _target,
|
||||||
bool backwards
|
bool backwards
|
||||||
)
|
)
|
||||||
|
@ -42,7 +42,6 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
@ -56,9 +55,9 @@ CodeTransform::CodeTransform(
|
|||||||
BuiltinContext& _builtinContext,
|
BuiltinContext& _builtinContext,
|
||||||
ExternalIdentifierAccess::CodeGenerator _identifierAccessCodeGen,
|
ExternalIdentifierAccess::CodeGenerator _identifierAccessCodeGen,
|
||||||
UseNamedLabels _useNamedLabelsForFunctions,
|
UseNamedLabels _useNamedLabelsForFunctions,
|
||||||
shared_ptr<Context> _context,
|
std::shared_ptr<Context> _context,
|
||||||
vector<TypedName> _delayedReturnVariables,
|
std::vector<TypedName> _delayedReturnVariables,
|
||||||
optional<AbstractAssembly::LabelID> _functionExitLabel
|
std::optional<AbstractAssembly::LabelID> _functionExitLabel
|
||||||
):
|
):
|
||||||
m_assembly(_assembly),
|
m_assembly(_assembly),
|
||||||
m_info(_analysisInfo),
|
m_info(_analysisInfo),
|
||||||
@ -74,7 +73,7 @@ CodeTransform::CodeTransform(
|
|||||||
if (!m_context)
|
if (!m_context)
|
||||||
{
|
{
|
||||||
// initialize
|
// initialize
|
||||||
m_context = make_shared<Context>();
|
m_context = std::make_shared<Context>();
|
||||||
if (m_allowStackOpt)
|
if (m_allowStackOpt)
|
||||||
m_context->variableReferences = VariableReferenceCounter::run(m_info, _block);
|
m_context->variableReferences = VariableReferenceCounter::run(m_info, _block);
|
||||||
}
|
}
|
||||||
@ -103,7 +102,7 @@ void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (auto const& identifier: m_scope->identifiers)
|
for (auto const& identifier: m_scope->identifiers)
|
||||||
if (Scope::Variable const* var = get_if<Scope::Variable>(&identifier.second))
|
if (Scope::Variable const* var = std::get_if<Scope::Variable>(&identifier.second))
|
||||||
if (m_variablesScheduledForDeletion.count(var))
|
if (m_variablesScheduledForDeletion.count(var))
|
||||||
deleteVariable(*var);
|
deleteVariable(*var);
|
||||||
// Directly in a function body block, we can also delete the function arguments,
|
// Directly in a function body block, we can also delete the function arguments,
|
||||||
@ -112,7 +111,7 @@ void CodeTransform::freeUnusedVariables(bool _popUnusedSlotsAtStackTop)
|
|||||||
// effect, so we only do it before that.
|
// effect, so we only do it before that.
|
||||||
if (!returnVariablesAndFunctionExitAreSetup() && !m_scope->functionScope && m_scope->superScope && m_scope->superScope->functionScope)
|
if (!returnVariablesAndFunctionExitAreSetup() && !m_scope->functionScope && m_scope->superScope && m_scope->superScope->functionScope)
|
||||||
for (auto const& identifier: m_scope->superScope->identifiers)
|
for (auto const& identifier: m_scope->superScope->identifiers)
|
||||||
if (Scope::Variable const* var = get_if<Scope::Variable>(&identifier.second))
|
if (Scope::Variable const* var = std::get_if<Scope::Variable>(&identifier.second))
|
||||||
if (m_variablesScheduledForDeletion.count(var))
|
if (m_variablesScheduledForDeletion.count(var))
|
||||||
deleteVariable(*var);
|
deleteVariable(*var);
|
||||||
|
|
||||||
@ -317,7 +316,7 @@ void CodeTransform::operator()(Switch const& _switch)
|
|||||||
{
|
{
|
||||||
visitExpression(*_switch.expression);
|
visitExpression(*_switch.expression);
|
||||||
int expressionHeight = m_assembly.stackHeight();
|
int expressionHeight = m_assembly.stackHeight();
|
||||||
map<Case const*, AbstractAssembly::LabelID> caseBodies;
|
std::map<Case const*, AbstractAssembly::LabelID> caseBodies;
|
||||||
AbstractAssembly::LabelID end = m_assembly.newLabelId();
|
AbstractAssembly::LabelID end = m_assembly.newLabelId();
|
||||||
for (Case const& c: _switch.cases)
|
for (Case const& c: _switch.cases)
|
||||||
{
|
{
|
||||||
@ -447,7 +446,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
|
|
||||||
// This vector holds the desired target positions of all stack slots and is
|
// This vector holds the desired target positions of all stack slots and is
|
||||||
// modified parallel to the actual stack.
|
// modified parallel to the actual stack.
|
||||||
vector<int> stackLayout(static_cast<size_t>(m_assembly.stackHeight()), -1);
|
std::vector<int> stackLayout(static_cast<size_t>(m_assembly.stackHeight()), -1);
|
||||||
stackLayout[0] = static_cast<int>(_function.returnVariables.size()); // Move return label to the top
|
stackLayout[0] = static_cast<int>(_function.returnVariables.size()); // Move return label to the top
|
||||||
for (auto&& [n, returnVariable]: ranges::views::enumerate(_function.returnVariables))
|
for (auto&& [n, returnVariable]: ranges::views::enumerate(_function.returnVariables))
|
||||||
stackLayout.at(m_context->variableStackHeights.at(
|
stackLayout.at(m_context->variableStackHeights.at(
|
||||||
@ -463,7 +462,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
"The function " +
|
"The function " +
|
||||||
_function.name.str() +
|
_function.name.str() +
|
||||||
" has " +
|
" has " +
|
||||||
to_string(stackLayout.size() - 17) +
|
std::to_string(stackLayout.size() - 17) +
|
||||||
" parameters or return variables too many to fit the stack size."
|
" parameters or return variables too many to fit the stack size."
|
||||||
);
|
);
|
||||||
stackError(std::move(error), m_assembly.stackHeight() - static_cast<int>(_function.parameters.size()));
|
stackError(std::move(error), m_assembly.stackHeight() - static_cast<int>(_function.parameters.size()));
|
||||||
@ -479,7 +478,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u));
|
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u));
|
||||||
swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
std::swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < stackLayout.size(); ++i)
|
for (size_t i = 0; i < stackLayout.size(); ++i)
|
||||||
yulAssert(i == static_cast<size_t>(stackLayout[i]), "Error reshuffling stack.");
|
yulAssert(i == static_cast<size_t>(stackLayout[i]), "Error reshuffling stack.");
|
||||||
@ -571,7 +570,7 @@ void CodeTransform::operator()(Block const& _block)
|
|||||||
m_scope = m_info.scopes.at(&_block).get();
|
m_scope = m_info.scopes.at(&_block).get();
|
||||||
|
|
||||||
for (auto const& statement: _block.statements)
|
for (auto const& statement: _block.statements)
|
||||||
if (auto function = get_if<FunctionDefinition>(&statement))
|
if (auto function = std::get_if<FunctionDefinition>(&statement))
|
||||||
createFunctionEntryID(*function);
|
createFunctionEntryID(*function);
|
||||||
|
|
||||||
int blockStartStackHeight = m_assembly.stackHeight();
|
int blockStartStackHeight = m_assembly.stackHeight();
|
||||||
@ -579,7 +578,7 @@ void CodeTransform::operator()(Block const& _block)
|
|||||||
|
|
||||||
bool isOutermostFunctionBodyBlock = m_scope && m_scope->superScope && m_scope->superScope->functionScope;
|
bool isOutermostFunctionBodyBlock = m_scope && m_scope->superScope && m_scope->superScope->functionScope;
|
||||||
bool performValidation = !m_allowStackOpt || !isOutermostFunctionBodyBlock;
|
bool performValidation = !m_allowStackOpt || !isOutermostFunctionBodyBlock;
|
||||||
finalizeBlock(_block, performValidation ? make_optional(blockStartStackHeight) : nullopt);
|
finalizeBlock(_block, performValidation ? std::make_optional(blockStartStackHeight) : std::nullopt);
|
||||||
m_scope = originalScope;
|
m_scope = originalScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,7 +587,7 @@ void CodeTransform::createFunctionEntryID(FunctionDefinition const& _function)
|
|||||||
Scope::Function& scopeFunction = std::get<Scope::Function>(m_scope->identifiers.at(_function.name));
|
Scope::Function& scopeFunction = std::get<Scope::Function>(m_scope->identifiers.at(_function.name));
|
||||||
yulAssert(!m_context->functionEntryIDs.count(&scopeFunction), "");
|
yulAssert(!m_context->functionEntryIDs.count(&scopeFunction), "");
|
||||||
|
|
||||||
optional<size_t> astID;
|
std::optional<size_t> astID;
|
||||||
if (_function.debugData)
|
if (_function.debugData)
|
||||||
astID = _function.debugData->astID;
|
astID = _function.debugData->astID;
|
||||||
|
|
||||||
@ -659,16 +658,16 @@ void CodeTransform::setupReturnVariablesAndFunctionExit()
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
bool statementNeedsReturnVariableSetup(Statement const& _statement, vector<TypedName> const& _returnVariables)
|
bool statementNeedsReturnVariableSetup(Statement const& _statement, std::vector<TypedName> const& _returnVariables)
|
||||||
{
|
{
|
||||||
if (holds_alternative<FunctionDefinition>(_statement))
|
if (std::holds_alternative<FunctionDefinition>(_statement))
|
||||||
return true;
|
return true;
|
||||||
if (
|
if (
|
||||||
holds_alternative<ExpressionStatement>(_statement) ||
|
std::holds_alternative<ExpressionStatement>(_statement) ||
|
||||||
holds_alternative<Assignment>(_statement)
|
std::holds_alternative<Assignment>(_statement)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
map<YulString, size_t> references = VariableReferencesCounter::countReferences(_statement);
|
std::map<YulString, size_t> references = VariableReferencesCounter::countReferences(_statement);
|
||||||
auto isReferenced = [&references](TypedName const& _returnVariable) {
|
auto isReferenced = [&references](TypedName const& _returnVariable) {
|
||||||
return references.count(_returnVariable.name);
|
return references.count(_returnVariable.name);
|
||||||
};
|
};
|
||||||
@ -680,7 +679,7 @@ bool statementNeedsReturnVariableSetup(Statement const& _statement, vector<Typed
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::visitStatements(vector<Statement> const& _statements)
|
void CodeTransform::visitStatements(std::vector<Statement> const& _statements)
|
||||||
{
|
{
|
||||||
std::optional<AbstractAssembly::LabelID> jumpTarget = std::nullopt;
|
std::optional<AbstractAssembly::LabelID> jumpTarget = std::nullopt;
|
||||||
|
|
||||||
@ -716,7 +715,7 @@ void CodeTransform::visitStatements(vector<Statement> const& _statements)
|
|||||||
freeUnusedVariables();
|
freeUnusedVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartStackHeight)
|
void CodeTransform::finalizeBlock(Block const& _block, std::optional<int> blockStartStackHeight)
|
||||||
{
|
{
|
||||||
m_assembly.setSourceLocation(originLocationOf(_block));
|
m_assembly.setSourceLocation(originLocationOf(_block));
|
||||||
|
|
||||||
@ -725,7 +724,7 @@ void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartS
|
|||||||
// pop variables
|
// pop variables
|
||||||
yulAssert(m_info.scopes.at(&_block).get() == m_scope, "");
|
yulAssert(m_info.scopes.at(&_block).get() == m_scope, "");
|
||||||
for (auto const& id: m_scope->identifiers)
|
for (auto const& id: m_scope->identifiers)
|
||||||
if (holds_alternative<Scope::Variable>(id.second))
|
if (std::holds_alternative<Scope::Variable>(id.second))
|
||||||
{
|
{
|
||||||
Scope::Variable const& var = std::get<Scope::Variable>(id.second);
|
Scope::Variable const& var = std::get<Scope::Variable>(id.second);
|
||||||
if (m_allowStackOpt)
|
if (m_allowStackOpt)
|
||||||
@ -740,11 +739,11 @@ void CodeTransform::finalizeBlock(Block const& _block, optional<int> blockStartS
|
|||||||
if (blockStartStackHeight)
|
if (blockStartStackHeight)
|
||||||
{
|
{
|
||||||
int deposit = m_assembly.stackHeight() - *blockStartStackHeight;
|
int deposit = m_assembly.stackHeight() - *blockStartStackHeight;
|
||||||
yulAssert(deposit == 0, "Invalid stack height at end of block: " + to_string(deposit));
|
yulAssert(deposit == 0, "Invalid stack height at end of block: " + std::to_string(deposit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::generateMultiAssignment(vector<Identifier> const& _variableNames)
|
void CodeTransform::generateMultiAssignment(std::vector<Identifier> const& _variableNames)
|
||||||
{
|
{
|
||||||
yulAssert(m_scope, "");
|
yulAssert(m_scope, "");
|
||||||
for (auto const& variableName: _variableNames | ranges::views::reverse)
|
for (auto const& variableName: _variableNames | ranges::views::reverse)
|
||||||
@ -786,7 +785,7 @@ size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString
|
|||||||
"Variable " +
|
"Variable " +
|
||||||
_varName.str() +
|
_varName.str() +
|
||||||
" is " +
|
" is " +
|
||||||
to_string(heightDiff - limit) +
|
std::to_string(heightDiff - limit) +
|
||||||
" slot(s) too deep inside the stack. " +
|
" slot(s) too deep inside the stack. " +
|
||||||
stackTooDeepString
|
stackTooDeepString
|
||||||
);
|
);
|
||||||
@ -798,7 +797,7 @@ size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString
|
|||||||
|
|
||||||
int CodeTransform::variableStackHeight(YulString _name) const
|
int CodeTransform::variableStackHeight(YulString _name) const
|
||||||
{
|
{
|
||||||
Scope::Variable const* var = get_if<Scope::Variable>(m_scope->lookup(_name));
|
Scope::Variable const* var = std::get_if<Scope::Variable>(m_scope->lookup(_name));
|
||||||
yulAssert(var, "");
|
yulAssert(var, "");
|
||||||
return static_cast<int>(m_context->variableStackHeights.at(var));
|
return static_cast<int>(m_context->variableStackHeights.at(var));
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std::string_literals;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
@ -46,9 +46,9 @@ using namespace solidity::util;
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
std::pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
||||||
langutil::EVMVersion _evmVersion,
|
langutil::EVMVersion _evmVersion,
|
||||||
string const& _name,
|
std::string const& _name,
|
||||||
evmasm::Instruction _instruction
|
evmasm::Instruction _instruction
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -87,12 +87,12 @@ pair<YulString, BuiltinFunctionForEVM> createEVMFunction(
|
|||||||
return {name, std::move(f)};
|
return {name, std::move(f)};
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<YulString, BuiltinFunctionForEVM> createFunction(
|
std::pair<YulString, BuiltinFunctionForEVM> createFunction(
|
||||||
string _name,
|
std::string _name,
|
||||||
size_t _params,
|
size_t _params,
|
||||||
size_t _returns,
|
size_t _returns,
|
||||||
SideEffects _sideEffects,
|
SideEffects _sideEffects,
|
||||||
vector<optional<LiteralKind>> _literalArguments,
|
std::vector<std::optional<LiteralKind>> _literalArguments,
|
||||||
std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&)> _generateCode
|
std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&)> _generateCode
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -111,7 +111,7 @@ pair<YulString, BuiltinFunctionForEVM> createFunction(
|
|||||||
return {name, f};
|
return {name, f};
|
||||||
}
|
}
|
||||||
|
|
||||||
set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
std::set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
||||||
{
|
{
|
||||||
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
|
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
|
||||||
// basefee for VMs before london.
|
// basefee for VMs before london.
|
||||||
@ -122,20 +122,20 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
|||||||
|
|
||||||
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
|
// TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name
|
||||||
// prevrandao for VMs before paris.
|
// prevrandao for VMs before paris.
|
||||||
auto prevRandaoException = [&](string const& _instrName) -> bool
|
auto prevRandaoException = [&](std::string const& _instrName) -> bool
|
||||||
{
|
{
|
||||||
// Using string comparison as the opcode is the same as for "difficulty"
|
// Using string comparison as the opcode is the same as for "difficulty"
|
||||||
return _instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris();
|
return _instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris();
|
||||||
};
|
};
|
||||||
|
|
||||||
set<YulString> reserved;
|
std::set<YulString> reserved;
|
||||||
for (auto const& instr: evmasm::c_instructions)
|
for (auto const& instr: evmasm::c_instructions)
|
||||||
{
|
{
|
||||||
string name = toLower(instr.first);
|
std::string name = toLower(instr.first);
|
||||||
if (!baseFeeException(instr.second) && !prevRandaoException(name))
|
if (!baseFeeException(instr.second) && !prevRandaoException(name))
|
||||||
reserved.emplace(name);
|
reserved.emplace(name);
|
||||||
}
|
}
|
||||||
reserved += vector<YulString>{
|
reserved += std::vector<YulString>{
|
||||||
"linkersymbol"_yulstring,
|
"linkersymbol"_yulstring,
|
||||||
"datasize"_yulstring,
|
"datasize"_yulstring,
|
||||||
"dataoffset"_yulstring,
|
"dataoffset"_yulstring,
|
||||||
@ -146,19 +146,19 @@ set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion)
|
|||||||
return reserved;
|
return reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess)
|
std::map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Exclude prevrandao as builtin for VMs before paris and difficulty for VMs after paris.
|
// Exclude prevrandao as builtin for VMs before paris and difficulty for VMs after paris.
|
||||||
auto prevRandaoException = [&](string const& _instrName) -> bool
|
auto prevRandaoException = [&](std::string const& _instrName) -> bool
|
||||||
{
|
{
|
||||||
return (_instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris()) || (_instrName == "difficulty" && _evmVersion >= langutil::EVMVersion::paris());
|
return (_instrName == "prevrandao" && _evmVersion < langutil::EVMVersion::paris()) || (_instrName == "difficulty" && _evmVersion >= langutil::EVMVersion::paris());
|
||||||
};
|
};
|
||||||
|
|
||||||
map<YulString, BuiltinFunctionForEVM> builtins;
|
std::map<YulString, BuiltinFunctionForEVM> builtins;
|
||||||
for (auto const& instr: evmasm::c_instructions)
|
for (auto const& instr: evmasm::c_instructions)
|
||||||
{
|
{
|
||||||
string name = toLower(instr.first);
|
std::string name = toLower(instr.first);
|
||||||
auto const opcode = instr.second;
|
auto const opcode = instr.second;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -198,7 +198,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
BuiltinContext&
|
BuiltinContext&
|
||||||
) {
|
) {
|
||||||
yulAssert(_call.arguments.size() == 1, "");
|
yulAssert(_call.arguments.size() == 1, "");
|
||||||
Literal const* literal = get_if<Literal>(&_call.arguments.front());
|
Literal const* literal = std::get_if<Literal>(&_call.arguments.front());
|
||||||
yulAssert(literal, "");
|
yulAssert(literal, "");
|
||||||
_assembly.appendConstant(valueOfLiteral(*literal));
|
_assembly.appendConstant(valueOfLiteral(*literal));
|
||||||
})
|
})
|
||||||
@ -217,10 +217,10 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
_assembly.appendAssemblySize();
|
_assembly.appendAssemblySize();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vector<size_t> subIdPath =
|
std::vector<size_t> subIdPath =
|
||||||
_context.subIDs.count(dataName) == 0 ?
|
_context.subIDs.count(dataName) == 0 ?
|
||||||
_context.currentObject->pathToSubObject(dataName) :
|
_context.currentObject->pathToSubObject(dataName) :
|
||||||
vector<size_t>{_context.subIDs.at(dataName)};
|
std::vector<size_t>{_context.subIDs.at(dataName)};
|
||||||
yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">.");
|
yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">.");
|
||||||
_assembly.appendDataSize(subIdPath);
|
_assembly.appendDataSize(subIdPath);
|
||||||
}
|
}
|
||||||
@ -238,10 +238,10 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
_assembly.appendConstant(0);
|
_assembly.appendConstant(0);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vector<size_t> subIdPath =
|
std::vector<size_t> subIdPath =
|
||||||
_context.subIDs.count(dataName) == 0 ?
|
_context.subIDs.count(dataName) == 0 ?
|
||||||
_context.currentObject->pathToSubObject(dataName) :
|
_context.currentObject->pathToSubObject(dataName) :
|
||||||
vector<size_t>{_context.subIDs.at(dataName)};
|
std::vector<size_t>{_context.subIDs.at(dataName)};
|
||||||
yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">.");
|
yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">.");
|
||||||
_assembly.appendDataOffset(subIdPath);
|
_assembly.appendDataOffset(subIdPath);
|
||||||
}
|
}
|
||||||
@ -295,9 +295,9 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
return builtins;
|
return builtins;
|
||||||
}
|
}
|
||||||
|
|
||||||
regex const& verbatimPattern()
|
std::regex const& verbatimPattern()
|
||||||
{
|
{
|
||||||
regex static const pattern{"verbatim_([1-9]?[0-9])i_([1-9]?[0-9])o"};
|
std::regex static const pattern{"verbatim_([1-9]?[0-9])i_([1-9]?[0-9])o"};
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +316,7 @@ BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const
|
|||||||
{
|
{
|
||||||
if (m_objectAccess)
|
if (m_objectAccess)
|
||||||
{
|
{
|
||||||
smatch match;
|
std::smatch match;
|
||||||
if (regex_match(_name.str(), match, verbatimPattern()))
|
if (regex_match(_name.str(), match, verbatimPattern()))
|
||||||
return verbatimFunction(stoul(match[1]), stoul(match[2]));
|
return verbatimFunction(stoul(match[1]), stoul(match[2]));
|
||||||
}
|
}
|
||||||
@ -337,19 +337,19 @@ bool EVMDialect::reservedIdentifier(YulString _name) const
|
|||||||
|
|
||||||
EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version)
|
EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version)
|
||||||
{
|
{
|
||||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialect const>> dialects;
|
||||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||||
if (!dialects[_version])
|
if (!dialects[_version])
|
||||||
dialects[_version] = make_unique<EVMDialect>(_version, false);
|
dialects[_version] = std::make_unique<EVMDialect>(_version, false);
|
||||||
return *dialects[_version];
|
return *dialects[_version];
|
||||||
}
|
}
|
||||||
|
|
||||||
EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _version)
|
EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _version)
|
||||||
{
|
{
|
||||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialect const>> dialects;
|
||||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||||
if (!dialects[_version])
|
if (!dialects[_version])
|
||||||
dialects[_version] = make_unique<EVMDialect>(_version, true);
|
dialects[_version] = std::make_unique<EVMDialect>(_version, true);
|
||||||
return *dialects[_version];
|
return *dialects[_version];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,16 +374,16 @@ SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instructio
|
|||||||
|
|
||||||
BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, size_t _returnVariables) const
|
BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, size_t _returnVariables) const
|
||||||
{
|
{
|
||||||
pair<size_t, size_t> key{_arguments, _returnVariables};
|
std::pair<size_t, size_t> key{_arguments, _returnVariables};
|
||||||
shared_ptr<BuiltinFunctionForEVM const>& function = m_verbatimFunctions[key];
|
std::shared_ptr<BuiltinFunctionForEVM const>& function = m_verbatimFunctions[key];
|
||||||
if (!function)
|
if (!function)
|
||||||
{
|
{
|
||||||
BuiltinFunctionForEVM builtinFunction = createFunction(
|
BuiltinFunctionForEVM builtinFunction = createFunction(
|
||||||
"verbatim_" + to_string(_arguments) + "i_" + to_string(_returnVariables) + "o",
|
"verbatim_" + std::to_string(_arguments) + "i_" + std::to_string(_returnVariables) + "o",
|
||||||
1 + _arguments,
|
1 + _arguments,
|
||||||
_returnVariables,
|
_returnVariables,
|
||||||
SideEffects::worst(),
|
SideEffects::worst(),
|
||||||
vector<optional<LiteralKind>>{LiteralKind::String} + vector<optional<LiteralKind>>(_arguments),
|
std::vector<std::optional<LiteralKind>>{LiteralKind::String} + std::vector<std::optional<LiteralKind>>(_arguments),
|
||||||
[=](
|
[=](
|
||||||
FunctionCall const& _call,
|
FunctionCall const& _call,
|
||||||
AbstractAssembly& _assembly,
|
AbstractAssembly& _assembly,
|
||||||
@ -400,7 +400,7 @@ BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, siz
|
|||||||
}
|
}
|
||||||
).second;
|
).second;
|
||||||
builtinFunction.isMSize = true;
|
builtinFunction.isMSize = true;
|
||||||
function = make_shared<BuiltinFunctionForEVM const>(std::move(builtinFunction));
|
function = std::make_shared<BuiltinFunctionForEVM const>(std::move(builtinFunction));
|
||||||
}
|
}
|
||||||
return function.get();
|
return function.get();
|
||||||
}
|
}
|
||||||
@ -501,9 +501,9 @@ BuiltinFunctionForEVM const* EVMDialectTyped::equalityFunction(YulString _type)
|
|||||||
|
|
||||||
EVMDialectTyped const& EVMDialectTyped::instance(langutil::EVMVersion _version)
|
EVMDialectTyped const& EVMDialectTyped::instance(langutil::EVMVersion _version)
|
||||||
{
|
{
|
||||||
static map<langutil::EVMVersion, unique_ptr<EVMDialectTyped const>> dialects;
|
static std::map<langutil::EVMVersion, std::unique_ptr<EVMDialectTyped const>> dialects;
|
||||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||||
if (!dialects[_version])
|
if (!dialects[_version])
|
||||||
dialects[_version] = make_unique<EVMDialectTyped>(_version, true);
|
dialects[_version] = std::make_unique<EVMDialectTyped>(_version, true);
|
||||||
return *dialects[_version];
|
return *dialects[_version];
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
@ -52,7 +51,7 @@ bigint GasMeter::combineCosts(std::pair<bigint, bigint> _costs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pair<bigint, bigint> GasMeterVisitor::costs(
|
std::pair<bigint, bigint> GasMeterVisitor::costs(
|
||||||
Expression const& _expression,
|
Expression const& _expression,
|
||||||
EVMDialect const& _dialect,
|
EVMDialect const& _dialect,
|
||||||
bool _isCreation
|
bool _isCreation
|
||||||
@ -63,7 +62,7 @@ pair<bigint, bigint> GasMeterVisitor::costs(
|
|||||||
return {gmv.m_runGas, gmv.m_dataGas};
|
return {gmv.m_runGas, gmv.m_dataGas};
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<bigint, bigint> GasMeterVisitor::instructionCosts(
|
std::pair<bigint, bigint> GasMeterVisitor::instructionCosts(
|
||||||
evmasm::Instruction _instruction,
|
evmasm::Instruction _instruction,
|
||||||
EVMDialect const& _dialect,
|
EVMDialect const& _dialect,
|
||||||
bool _isCreation
|
bool _isCreation
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
void EVMObjectCompiler::compile(
|
void EVMObjectCompiler::compile(
|
||||||
Object& _object,
|
Object& _object,
|
||||||
@ -91,12 +90,12 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize)
|
|||||||
);
|
);
|
||||||
if (!stackErrors.empty())
|
if (!stackErrors.empty())
|
||||||
{
|
{
|
||||||
vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
|
std::vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
|
||||||
*_object.code,
|
*_object.code,
|
||||||
"memoryguard"_yulstring
|
"memoryguard"_yulstring
|
||||||
);
|
);
|
||||||
auto stackError = stackErrors.front();
|
auto stackError = stackErrors.front();
|
||||||
string msg = stackError.comment() ? *stackError.comment() : "";
|
std::string msg = stackError.comment() ? *stackError.comment() : "";
|
||||||
if (memoryGuardCalls.empty())
|
if (memoryGuardCalls.empty())
|
||||||
msg += "\nNo memoryguard was present. "
|
msg += "\nNo memoryguard was present. "
|
||||||
"Consider using memory-safe assembly only and annotating it via "
|
"Consider using memory-safe assembly only and annotating it via "
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
@ -122,14 +121,14 @@ void EthAssemblyAdapter::appendAssemblySize()
|
|||||||
m_assembly.appendProgramSize();
|
m_assembly.appendProgramSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, string _name)
|
std::pair<std::shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> EthAssemblyAdapter::createSubAssembly(bool _creation, std::string _name)
|
||||||
{
|
{
|
||||||
shared_ptr<evmasm::Assembly> assembly{make_shared<evmasm::Assembly>(m_assembly.evmVersion(), _creation, std::move(_name))};
|
std::shared_ptr<evmasm::Assembly> assembly{std::make_shared<evmasm::Assembly>(m_assembly.evmVersion(), _creation, std::move(_name))};
|
||||||
auto sub = m_assembly.newSub(assembly);
|
auto sub = m_assembly.newSub(assembly);
|
||||||
return {make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
return {std::make_shared<EthAssemblyAdapter>(*assembly), static_cast<size_t>(sub.data())};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EthAssemblyAdapter::appendDataOffset(vector<AbstractAssembly::SubID> const& _subPath)
|
void EthAssemblyAdapter::appendDataOffset(std::vector<AbstractAssembly::SubID> const& _subPath)
|
||||||
{
|
{
|
||||||
if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end())
|
if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end())
|
||||||
{
|
{
|
||||||
@ -141,7 +140,7 @@ void EthAssemblyAdapter::appendDataOffset(vector<AbstractAssembly::SubID> const&
|
|||||||
m_assembly.pushSubroutineOffset(m_assembly.encodeSubPath(_subPath));
|
m_assembly.pushSubroutineOffset(m_assembly.encodeSubPath(_subPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EthAssemblyAdapter::appendDataSize(vector<AbstractAssembly::SubID> const& _subPath)
|
void EthAssemblyAdapter::appendDataSize(std::vector<AbstractAssembly::SubID> const& _subPath)
|
||||||
{
|
{
|
||||||
if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end())
|
if (auto it = m_dataHashBySubId.find(_subPath[0]); it != m_dataHashBySubId.end())
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
#include <range/v3/view/iota.hpp>
|
#include <range/v3/view/iota.hpp>
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
@ -60,12 +59,12 @@ NoOutputAssembly::LabelID NoOutputAssembly::newLabelId()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractAssembly::LabelID NoOutputAssembly::namedLabel(string const&, size_t, size_t, optional<size_t>)
|
AbstractAssembly::LabelID NoOutputAssembly::namedLabel(std::string const&, size_t, size_t, std::optional<size_t>)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NoOutputAssembly::appendLinkerSymbol(string const&)
|
void NoOutputAssembly::appendLinkerSymbol(std::string const&)
|
||||||
{
|
{
|
||||||
yulAssert(false, "Linker symbols not yet implemented.");
|
yulAssert(false, "Linker symbols not yet implemented.");
|
||||||
}
|
}
|
||||||
@ -98,7 +97,7 @@ void NoOutputAssembly::appendAssemblySize()
|
|||||||
appendInstruction(evmasm::Instruction::PUSH1);
|
appendInstruction(evmasm::Instruction::PUSH1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string)
|
std::pair<std::shared_ptr<AbstractAssembly>, AbstractAssembly::SubID> NoOutputAssembly::createSubAssembly(bool, std::string)
|
||||||
{
|
{
|
||||||
yulAssert(false, "Sub assemblies not implemented.");
|
yulAssert(false, "Sub assemblies not implemented.");
|
||||||
return {};
|
return {};
|
||||||
|
@ -38,9 +38,8 @@
|
|||||||
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
std::vector<StackTooDeepError> OptimizedEVMCodeTransform::run(
|
||||||
AbstractAssembly& _assembly,
|
AbstractAssembly& _assembly,
|
||||||
AsmAnalysisInfo& _analysisInfo,
|
AsmAnalysisInfo& _analysisInfo,
|
||||||
Block const& _block,
|
Block const& _block,
|
||||||
@ -81,7 +80,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call)
|
|||||||
// Assert that we got the correct return label on stack.
|
// Assert that we got the correct return label on stack.
|
||||||
if (_call.canContinue)
|
if (_call.canContinue)
|
||||||
{
|
{
|
||||||
auto const* returnLabelSlot = get_if<FunctionCallReturnLabelSlot>(
|
auto const* returnLabelSlot = std::get_if<FunctionCallReturnLabelSlot>(
|
||||||
&m_stack.at(m_stack.size() - _call.functionCall.get().arguments.size() - 1)
|
&m_stack.at(m_stack.size() - _call.functionCall.get().arguments.size() - 1)
|
||||||
);
|
);
|
||||||
yulAssert(returnLabelSlot && &returnLabelSlot->call.get() == &_call.functionCall.get(), "");
|
yulAssert(returnLabelSlot && &returnLabelSlot->call.get() == &_call.functionCall.get(), "");
|
||||||
@ -160,7 +159,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::Assignment const& _assignment)
|
|||||||
|
|
||||||
// Invalidate occurrences of the assigned variables.
|
// Invalidate occurrences of the assigned variables.
|
||||||
for (auto& currentSlot: m_stack)
|
for (auto& currentSlot: m_stack)
|
||||||
if (VariableSlot const* varSlot = get_if<VariableSlot>(¤tSlot))
|
if (VariableSlot const* varSlot = std::get_if<VariableSlot>(¤tSlot))
|
||||||
if (util::contains(_assignment.variables, *varSlot))
|
if (util::contains(_assignment.variables, *varSlot))
|
||||||
currentSlot = JunkSlot{};
|
currentSlot = JunkSlot{};
|
||||||
|
|
||||||
@ -185,8 +184,8 @@ OptimizedEVMCodeTransform::OptimizedEVMCodeTransform(
|
|||||||
m_dfg(_dfg),
|
m_dfg(_dfg),
|
||||||
m_stackLayout(_stackLayout),
|
m_stackLayout(_stackLayout),
|
||||||
m_functionLabels([&](){
|
m_functionLabels([&](){
|
||||||
map<CFG::FunctionInfo const*, AbstractAssembly::LabelID> functionLabels;
|
std::map<CFG::FunctionInfo const*, AbstractAssembly::LabelID> functionLabels;
|
||||||
set<YulString> assignedFunctionNames;
|
std::set<YulString> assignedFunctionNames;
|
||||||
for (Scope::Function const* function: m_dfg.functions)
|
for (Scope::Function const* function: m_dfg.functions)
|
||||||
{
|
{
|
||||||
CFG::FunctionInfo const& functionInfo = m_dfg.functionInfo.at(function);
|
CFG::FunctionInfo const& functionInfo = m_dfg.functionInfo.at(function);
|
||||||
@ -199,7 +198,7 @@ OptimizedEVMCodeTransform::OptimizedEVMCodeTransform(
|
|||||||
function->name.str(),
|
function->name.str(),
|
||||||
function->arguments.size(),
|
function->arguments.size(),
|
||||||
function->returns.size(),
|
function->returns.size(),
|
||||||
functionInfo.debugData ? functionInfo.debugData->astID : nullopt
|
functionInfo.debugData ? functionInfo.debugData->astID : std::nullopt
|
||||||
) :
|
) :
|
||||||
m_assembly.newLabelId();
|
m_assembly.newLabelId();
|
||||||
}
|
}
|
||||||
@ -212,7 +211,7 @@ void OptimizedEVMCodeTransform::assertLayoutCompatibility(Stack const& _currentS
|
|||||||
{
|
{
|
||||||
yulAssert(_currentStack.size() == _desiredStack.size(), "");
|
yulAssert(_currentStack.size() == _desiredStack.size(), "");
|
||||||
for (auto&& [currentSlot, desiredSlot]: ranges::zip_view(_currentStack, _desiredStack))
|
for (auto&& [currentSlot, desiredSlot]: ranges::zip_view(_currentStack, _desiredStack))
|
||||||
yulAssert(holds_alternative<JunkSlot>(desiredSlot) || currentSlot == desiredSlot, "");
|
yulAssert(std::holds_alternative<JunkSlot>(desiredSlot) || currentSlot == desiredSlot, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractAssembly::LabelID OptimizedEVMCodeTransform::getFunctionLabel(Scope::Function const& _function)
|
AbstractAssembly::LabelID OptimizedEVMCodeTransform::getFunctionLabel(Scope::Function const& _function)
|
||||||
@ -224,15 +223,15 @@ void OptimizedEVMCodeTransform::validateSlot(StackSlot const& _slot, Expression
|
|||||||
{
|
{
|
||||||
std::visit(util::GenericVisitor{
|
std::visit(util::GenericVisitor{
|
||||||
[&](yul::Literal const& _literal) {
|
[&](yul::Literal const& _literal) {
|
||||||
auto* literalSlot = get_if<LiteralSlot>(&_slot);
|
auto* literalSlot = std::get_if<LiteralSlot>(&_slot);
|
||||||
yulAssert(literalSlot && valueOfLiteral(_literal) == literalSlot->value, "");
|
yulAssert(literalSlot && valueOfLiteral(_literal) == literalSlot->value, "");
|
||||||
},
|
},
|
||||||
[&](yul::Identifier const& _identifier) {
|
[&](yul::Identifier const& _identifier) {
|
||||||
auto* variableSlot = get_if<VariableSlot>(&_slot);
|
auto* variableSlot = std::get_if<VariableSlot>(&_slot);
|
||||||
yulAssert(variableSlot && variableSlot->variable.get().name == _identifier.name, "");
|
yulAssert(variableSlot && variableSlot->variable.get().name == _identifier.name, "");
|
||||||
},
|
},
|
||||||
[&](yul::FunctionCall const& _call) {
|
[&](yul::FunctionCall const& _call) {
|
||||||
auto* temporarySlot = get_if<TemporarySlot>(&_slot);
|
auto* temporarySlot = std::get_if<TemporarySlot>(&_slot);
|
||||||
yulAssert(temporarySlot && &temporarySlot->call.get() == &_call && temporarySlot->index == 0, "");
|
yulAssert(temporarySlot && &temporarySlot->call.get() == &_call && temporarySlot->index == 0, "");
|
||||||
}
|
}
|
||||||
}, _expression);
|
}, _expression);
|
||||||
@ -267,10 +266,10 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons
|
|||||||
StackSlot const& deepSlot = m_stack.at(m_stack.size() - _i - 1);
|
StackSlot const& deepSlot = m_stack.at(m_stack.size() - _i - 1);
|
||||||
YulString varNameDeep = slotVariableName(deepSlot);
|
YulString varNameDeep = slotVariableName(deepSlot);
|
||||||
YulString varNameTop = slotVariableName(m_stack.back());
|
YulString varNameTop = slotVariableName(m_stack.back());
|
||||||
string msg =
|
std::string msg =
|
||||||
"Cannot swap " + (varNameDeep.empty() ? "Slot " + stackSlotToString(deepSlot) : "Variable " + varNameDeep.str()) +
|
"Cannot swap " + (varNameDeep.empty() ? "Slot " + stackSlotToString(deepSlot) : "Variable " + varNameDeep.str()) +
|
||||||
" with " + (varNameTop.empty() ? "Slot " + stackSlotToString(m_stack.back()) : "Variable " + varNameTop.str()) +
|
" with " + (varNameTop.empty() ? "Slot " + stackSlotToString(m_stack.back()) : "Variable " + varNameTop.str()) +
|
||||||
": too deep in the stack by " + to_string(deficit) + " slots in " + stackToString(m_stack);
|
": too deep in the stack by " + std::to_string(deficit) + " slots in " + stackToString(m_stack);
|
||||||
m_stackErrors.emplace_back(StackTooDeepError(
|
m_stackErrors.emplace_back(StackTooDeepError(
|
||||||
m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
|
m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
|
||||||
varNameDeep.empty() ? varNameTop : varNameDeep,
|
varNameDeep.empty() ? varNameTop : varNameDeep,
|
||||||
@ -297,9 +296,9 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr<DebugData cons
|
|||||||
{
|
{
|
||||||
int deficit = static_cast<int>(*depth - 15);
|
int deficit = static_cast<int>(*depth - 15);
|
||||||
YulString varName = slotVariableName(_slot);
|
YulString varName = slotVariableName(_slot);
|
||||||
string msg =
|
std::string msg =
|
||||||
(varName.empty() ? "Slot " + stackSlotToString(_slot) : "Variable " + varName.str())
|
(varName.empty() ? "Slot " + stackSlotToString(_slot) : "Variable " + varName.str())
|
||||||
+ " is " + to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack);
|
+ " is " + std::to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack);
|
||||||
m_stackErrors.emplace_back(StackTooDeepError(
|
m_stackErrors.emplace_back(StackTooDeepError(
|
||||||
m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
|
m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{},
|
||||||
varName,
|
varName,
|
||||||
@ -503,9 +502,9 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block)
|
|||||||
[&](CFG::BasicBlock::Terminated const&)
|
[&](CFG::BasicBlock::Terminated const&)
|
||||||
{
|
{
|
||||||
yulAssert(!_block.operations.empty());
|
yulAssert(!_block.operations.empty());
|
||||||
if (CFG::BuiltinCall const* builtinCall = get_if<CFG::BuiltinCall>(&_block.operations.back().operation))
|
if (CFG::BuiltinCall const* builtinCall = std::get_if<CFG::BuiltinCall>(&_block.operations.back().operation))
|
||||||
yulAssert(builtinCall->builtin.get().controlFlowSideEffects.terminatesOrReverts(), "");
|
yulAssert(builtinCall->builtin.get().controlFlowSideEffects.terminatesOrReverts(), "");
|
||||||
else if (CFG::FunctionCall const* functionCall = get_if<CFG::FunctionCall>(&_block.operations.back().operation))
|
else if (CFG::FunctionCall const* functionCall = std::get_if<CFG::FunctionCall>(&_block.operations.back().operation))
|
||||||
yulAssert(!functionCall->canContinue);
|
yulAssert(!functionCall->canContinue);
|
||||||
else
|
else
|
||||||
yulAssert(false);
|
yulAssert(false);
|
||||||
|
@ -46,7 +46,6 @@
|
|||||||
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
StackLayout StackLayoutGenerator::run(CFG const& _cfg)
|
StackLayout StackLayoutGenerator::run(CFG const& _cfg)
|
||||||
{
|
{
|
||||||
@ -59,9 +58,9 @@ StackLayout StackLayoutGenerator::run(CFG const& _cfg)
|
|||||||
return stackLayout;
|
return stackLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<YulString, vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg)
|
std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg)
|
||||||
{
|
{
|
||||||
map<YulString, vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors;
|
std::map<YulString, std::vector<StackLayoutGenerator::StackTooDeep>> stackTooDeepErrors;
|
||||||
stackTooDeepErrors[YulString{}] = reportStackTooDeep(_cfg, YulString{});
|
stackTooDeepErrors[YulString{}] = reportStackTooDeep(_cfg, YulString{});
|
||||||
for (auto const& function: _cfg.functions)
|
for (auto const& function: _cfg.functions)
|
||||||
if (auto errors = reportStackTooDeep(_cfg, function->name); !errors.empty())
|
if (auto errors = reportStackTooDeep(_cfg, function->name); !errors.empty())
|
||||||
@ -69,7 +68,7 @@ map<YulString, vector<StackLayoutGenerator::StackTooDeep>> StackLayoutGenerator:
|
|||||||
return stackTooDeepErrors;
|
return stackTooDeepErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName)
|
std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName)
|
||||||
{
|
{
|
||||||
StackLayout stackLayout;
|
StackLayout stackLayout;
|
||||||
CFG::FunctionInfo const* functionInfo = nullptr;
|
CFG::FunctionInfo const* functionInfo = nullptr;
|
||||||
@ -98,14 +97,14 @@ StackLayoutGenerator::StackLayoutGenerator(StackLayout& _layout, CFG::FunctionIn
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
/// @returns all stack too deep errors that would occur when shuffling @a _source to @a _target.
|
/// @returns all stack too deep errors that would occur when shuffling @a _source to @a _target.
|
||||||
vector<StackLayoutGenerator::StackTooDeep> findStackTooDeep(Stack const& _source, Stack const& _target)
|
std::vector<StackLayoutGenerator::StackTooDeep> findStackTooDeep(Stack const& _source, Stack const& _target)
|
||||||
{
|
{
|
||||||
Stack currentStack = _source;
|
Stack currentStack = _source;
|
||||||
vector<StackLayoutGenerator::StackTooDeep> stackTooDeepErrors;
|
std::vector<StackLayoutGenerator::StackTooDeep> stackTooDeepErrors;
|
||||||
auto getVariableChoices = [](auto&& _range) {
|
auto getVariableChoices = [](auto&& _range) {
|
||||||
vector<YulString> result;
|
std::vector<YulString> result;
|
||||||
for (auto const& slot: _range)
|
for (auto const& slot: _range)
|
||||||
if (auto const* variableSlot = get_if<VariableSlot>(&slot))
|
if (auto const* variableSlot = std::get_if<VariableSlot>(&slot))
|
||||||
if (!util::contains(result, variableSlot->variable.get().name))
|
if (!util::contains(result, variableSlot->variable.get().name))
|
||||||
result.push_back(variableSlot->variable.get().name);
|
result.push_back(variableSlot->variable.get().name);
|
||||||
return result;
|
return result;
|
||||||
@ -160,7 +159,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
// PreviousSlot{0}, ..., PreviousSlot{n}, [output<0>], ..., [output<m>]
|
// PreviousSlot{0}, ..., PreviousSlot{n}, [output<0>], ..., [output<m>]
|
||||||
auto layout = ranges::views::iota(0u, preOperationLayoutSize) |
|
auto layout = ranges::views::iota(0u, preOperationLayoutSize) |
|
||||||
ranges::views::transform([](size_t _index) { return PreviousSlot{_index}; }) |
|
ranges::views::transform([](size_t _index) { return PreviousSlot{_index}; }) |
|
||||||
ranges::to<vector<variant<PreviousSlot, StackSlot>>>;
|
ranges::to<std::vector<std::variant<PreviousSlot, StackSlot>>>;
|
||||||
layout += _operationOutput;
|
layout += _operationOutput;
|
||||||
|
|
||||||
// Shortcut for trivial case.
|
// Shortcut for trivial case.
|
||||||
@ -171,23 +170,23 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
// that are aware of PreviousSlot's.
|
// that are aware of PreviousSlot's.
|
||||||
struct ShuffleOperations
|
struct ShuffleOperations
|
||||||
{
|
{
|
||||||
vector<variant<PreviousSlot, StackSlot>>& layout;
|
std::vector<std::variant<PreviousSlot, StackSlot>>& layout;
|
||||||
Stack const& post;
|
Stack const& post;
|
||||||
std::set<StackSlot> outputs;
|
std::set<StackSlot> outputs;
|
||||||
Multiplicity multiplicity;
|
Multiplicity multiplicity;
|
||||||
Callable generateSlotOnTheFly;
|
Callable generateSlotOnTheFly;
|
||||||
ShuffleOperations(
|
ShuffleOperations(
|
||||||
vector<variant<PreviousSlot, StackSlot>>& _layout,
|
std::vector<std::variant<PreviousSlot, StackSlot>>& _layout,
|
||||||
Stack const& _post,
|
Stack const& _post,
|
||||||
Callable _generateSlotOnTheFly
|
Callable _generateSlotOnTheFly
|
||||||
): layout(_layout), post(_post), generateSlotOnTheFly(_generateSlotOnTheFly)
|
): layout(_layout), post(_post), generateSlotOnTheFly(_generateSlotOnTheFly)
|
||||||
{
|
{
|
||||||
for (auto const& layoutSlot: layout)
|
for (auto const& layoutSlot: layout)
|
||||||
if (StackSlot const* slot = get_if<StackSlot>(&layoutSlot))
|
if (StackSlot const* slot = std::get_if<StackSlot>(&layoutSlot))
|
||||||
outputs.insert(*slot);
|
outputs.insert(*slot);
|
||||||
|
|
||||||
for (auto const& layoutSlot: layout)
|
for (auto const& layoutSlot: layout)
|
||||||
if (StackSlot const* slot = get_if<StackSlot>(&layoutSlot))
|
if (StackSlot const* slot = std::get_if<StackSlot>(&layoutSlot))
|
||||||
--multiplicity[*slot];
|
--multiplicity[*slot];
|
||||||
for (auto&& slot: post)
|
for (auto&& slot: post)
|
||||||
if (outputs.count(slot) || generateSlotOnTheFly(slot))
|
if (outputs.count(slot) || generateSlotOnTheFly(slot))
|
||||||
@ -235,7 +234,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
}
|
}
|
||||||
void swap(size_t _i)
|
void swap(size_t _i)
|
||||||
{
|
{
|
||||||
yulAssert(!holds_alternative<PreviousSlot>(layout.at(layout.size() - _i - 1)) || !holds_alternative<PreviousSlot>(layout.back()), "");
|
yulAssert(!std::holds_alternative<PreviousSlot>(layout.at(layout.size() - _i - 1)) || !std::holds_alternative<PreviousSlot>(layout.back()), "");
|
||||||
std::swap(layout.at(layout.size() - _i - 1), layout.back());
|
std::swap(layout.at(layout.size() - _i - 1), layout.back());
|
||||||
}
|
}
|
||||||
size_t sourceSize() { return layout.size(); }
|
size_t sourceSize() { return layout.size(); }
|
||||||
@ -250,7 +249,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
// output in place. The resulting permutation of the PreviousSlot yields the ideal positions of slots
|
// output in place. The resulting permutation of the PreviousSlot yields the ideal positions of slots
|
||||||
// before the operation, i.e. if PreviousSlot{2} is at a position at which _post contains VariableSlot{"tmp"},
|
// before the operation, i.e. if PreviousSlot{2} is at a position at which _post contains VariableSlot{"tmp"},
|
||||||
// then we want the variable tmp in the slot at offset 2 in the layout before the operation.
|
// then we want the variable tmp in the slot at offset 2 in the layout before the operation.
|
||||||
vector<optional<StackSlot>> idealLayout(_post.size(), nullopt);
|
std::vector<std::optional<StackSlot>> idealLayout(_post.size(), std::nullopt);
|
||||||
for (auto&& [slot, idealPosition]: ranges::zip_view(_post, layout))
|
for (auto&& [slot, idealPosition]: ranges::zip_view(_post, layout))
|
||||||
if (PreviousSlot* previousSlot = std::get_if<PreviousSlot>(&idealPosition))
|
if (PreviousSlot* previousSlot = std::get_if<PreviousSlot>(&idealPosition))
|
||||||
idealLayout.at(previousSlot->slot) = slot;
|
idealLayout.at(previousSlot->slot) = slot;
|
||||||
@ -261,7 +260,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
|
|
||||||
yulAssert(idealLayout.size() == preOperationLayoutSize, "");
|
yulAssert(idealLayout.size() == preOperationLayoutSize, "");
|
||||||
|
|
||||||
return idealLayout | ranges::views::transform([](optional<StackSlot> s) {
|
return idealLayout | ranges::views::transform([](std::optional<StackSlot> s) {
|
||||||
yulAssert(s, "");
|
yulAssert(s, "");
|
||||||
return *s;
|
return *s;
|
||||||
}) | ranges::to<Stack>;
|
}) | ranges::to<Stack>;
|
||||||
@ -271,7 +270,7 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla
|
|||||||
Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation, bool _aggressiveStackCompression)
|
Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation, bool _aggressiveStackCompression)
|
||||||
{
|
{
|
||||||
// Enable aggressive stack compression for recursive calls.
|
// Enable aggressive stack compression for recursive calls.
|
||||||
if (auto const* functionCall = get_if<CFG::FunctionCall>(&_operation.operation))
|
if (auto const* functionCall = std::get_if<CFG::FunctionCall>(&_operation.operation))
|
||||||
if (functionCall->recursive)
|
if (functionCall->recursive)
|
||||||
_aggressiveStackCompression = true;
|
_aggressiveStackCompression = true;
|
||||||
|
|
||||||
@ -285,9 +284,9 @@ Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG
|
|||||||
Stack stack = createIdealLayout(_operation.output, _exitStack, generateSlotOnTheFly);
|
Stack stack = createIdealLayout(_operation.output, _exitStack, generateSlotOnTheFly);
|
||||||
|
|
||||||
// Make sure the resulting previous slots do not overlap with any assignmed variables.
|
// Make sure the resulting previous slots do not overlap with any assignmed variables.
|
||||||
if (auto const* assignment = get_if<CFG::Assignment>(&_operation.operation))
|
if (auto const* assignment = std::get_if<CFG::Assignment>(&_operation.operation))
|
||||||
for (auto& stackSlot: stack)
|
for (auto& stackSlot: stack)
|
||||||
if (auto const* varSlot = get_if<VariableSlot>(&stackSlot))
|
if (auto const* varSlot = std::get_if<VariableSlot>(&stackSlot))
|
||||||
yulAssert(!util::contains(assignment->variables, *varSlot), "");
|
yulAssert(!util::contains(assignment->variables, *varSlot), "");
|
||||||
|
|
||||||
// Since stack+_operation.output can be easily shuffled to _exitLayout, the desired layout before the operation
|
// Since stack+_operation.output can be easily shuffled to _exitLayout, the desired layout before the operation
|
||||||
@ -335,11 +334,11 @@ Stack StackLayoutGenerator::propagateStackThroughBlock(Stack _exitStack, CFG::Ba
|
|||||||
|
|
||||||
void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry, CFG::FunctionInfo const* _functionInfo)
|
void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry, CFG::FunctionInfo const* _functionInfo)
|
||||||
{
|
{
|
||||||
list<CFG::BasicBlock const*> toVisit{&_entry};
|
std::list<CFG::BasicBlock const*> toVisit{&_entry};
|
||||||
set<CFG::BasicBlock const*> visited;
|
std::set<CFG::BasicBlock const*> visited;
|
||||||
|
|
||||||
// TODO: check whether visiting only a subset of these in the outer iteration below is enough.
|
// TODO: check whether visiting only a subset of these in the outer iteration below is enough.
|
||||||
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps = collectBackwardsJumps(_entry);
|
std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps = collectBackwardsJumps(_entry);
|
||||||
|
|
||||||
while (!toVisit.empty())
|
while (!toVisit.empty())
|
||||||
{
|
{
|
||||||
@ -407,10 +406,10 @@ void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry, CFG:
|
|||||||
fillInJunk(_entry, _functionInfo);
|
fillInJunk(_entry, _functionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
std::optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
||||||
CFG::BasicBlock const& _block,
|
CFG::BasicBlock const& _block,
|
||||||
set<CFG::BasicBlock const*> const& _visited,
|
std::set<CFG::BasicBlock const*> const& _visited,
|
||||||
list<CFG::BasicBlock const*>& _toVisit
|
std::list<CFG::BasicBlock const*>& _toVisit
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
return std::visit(util::GenericVisitor{
|
return std::visit(util::GenericVisitor{
|
||||||
@ -434,7 +433,7 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
|||||||
return m_layout.blockInfos.at(_jump.target).entryLayout;
|
return m_layout.blockInfos.at(_jump.target).entryLayout;
|
||||||
// Otherwise stage the jump target for visit and defer the current block.
|
// Otherwise stage the jump target for visit and defer the current block.
|
||||||
_toVisit.emplace_front(_jump.target);
|
_toVisit.emplace_front(_jump.target);
|
||||||
return nullopt;
|
return std::nullopt;
|
||||||
},
|
},
|
||||||
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) -> std::optional<Stack>
|
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) -> std::optional<Stack>
|
||||||
{
|
{
|
||||||
@ -456,7 +455,7 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
|||||||
_toVisit.emplace_front(_conditionalJump.zero);
|
_toVisit.emplace_front(_conditionalJump.zero);
|
||||||
if (!nonZeroVisited)
|
if (!nonZeroVisited)
|
||||||
_toVisit.emplace_front(_conditionalJump.nonZero);
|
_toVisit.emplace_front(_conditionalJump.nonZero);
|
||||||
return nullopt;
|
return std::nullopt;
|
||||||
},
|
},
|
||||||
[&](CFG::BasicBlock::FunctionReturn const& _functionReturn) -> std::optional<Stack>
|
[&](CFG::BasicBlock::FunctionReturn const& _functionReturn) -> std::optional<Stack>
|
||||||
{
|
{
|
||||||
@ -476,9 +475,9 @@ optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
|||||||
}, _block.exit);
|
}, _block.exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> StackLayoutGenerator::collectBackwardsJumps(CFG::BasicBlock const& _entry) const
|
std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> StackLayoutGenerator::collectBackwardsJumps(CFG::BasicBlock const& _entry) const
|
||||||
{
|
{
|
||||||
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps;
|
std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps;
|
||||||
util::BreadthFirstSearch<CFG::BasicBlock const*>{{&_entry}}.run([&](CFG::BasicBlock const* _block, auto _addChild) {
|
util::BreadthFirstSearch<CFG::BasicBlock const*>{{&_entry}}.run([&](CFG::BasicBlock const* _block, auto _addChild) {
|
||||||
std::visit(util::GenericVisitor{
|
std::visit(util::GenericVisitor{
|
||||||
[&](CFG::BasicBlock::MainExit const&) {},
|
[&](CFG::BasicBlock::MainExit const&) {},
|
||||||
@ -576,7 +575,7 @@ Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _sta
|
|||||||
if (!util::contains(candidate, slot))
|
if (!util::contains(candidate, slot))
|
||||||
candidate.emplace_back(slot);
|
candidate.emplace_back(slot);
|
||||||
cxx20::erase_if(candidate, [](StackSlot const& slot) {
|
cxx20::erase_if(candidate, [](StackSlot const& slot) {
|
||||||
return holds_alternative<LiteralSlot>(slot) || holds_alternative<FunctionCallReturnLabelSlot>(slot);
|
return std::holds_alternative<LiteralSlot>(slot) || std::holds_alternative<FunctionCallReturnLabelSlot>(slot);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto evaluate = [&](Stack const& _candidate) -> size_t {
|
auto evaluate = [&](Stack const& _candidate) -> size_t {
|
||||||
@ -633,9 +632,9 @@ Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _sta
|
|||||||
return commonPrefix + bestCandidate;
|
return commonPrefix + bestCandidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG::BasicBlock const& _entry) const
|
std::vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooDeep(CFG::BasicBlock const& _entry) const
|
||||||
{
|
{
|
||||||
vector<StackTooDeep> stackTooDeepErrors;
|
std::vector<StackTooDeep> stackTooDeepErrors;
|
||||||
util::BreadthFirstSearch<CFG::BasicBlock const*> breadthFirstSearch{{&_entry}};
|
util::BreadthFirstSearch<CFG::BasicBlock const*> breadthFirstSearch{{&_entry}};
|
||||||
breadthFirstSearch.run([&](CFG::BasicBlock const* _block, auto _addChild) {
|
breadthFirstSearch.run([&](CFG::BasicBlock const* _block, auto _addChild) {
|
||||||
Stack currentStack = m_layout.blockInfos.at(_block).entryLayout;
|
Stack currentStack = m_layout.blockInfos.at(_block).entryLayout;
|
||||||
@ -683,7 +682,7 @@ vector<StackLayoutGenerator::StackTooDeep> StackLayoutGenerator::reportStackTooD
|
|||||||
|
|
||||||
Stack StackLayoutGenerator::compressStack(Stack _stack)
|
Stack StackLayoutGenerator::compressStack(Stack _stack)
|
||||||
{
|
{
|
||||||
optional<size_t> firstDupOffset;
|
std::optional<size_t> firstDupOffset;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (firstDupOffset)
|
if (firstDupOffset)
|
||||||
@ -768,8 +767,8 @@ void StackLayoutGenerator::fillInJunk(CFG::BasicBlock const& _block, CFG::Functi
|
|||||||
{
|
{
|
||||||
// This has to be a previously unassigned return variable.
|
// This has to be a previously unassigned return variable.
|
||||||
// We at least sanity-check that it is among the return variables at all.
|
// We at least sanity-check that it is among the return variables at all.
|
||||||
yulAssert(m_currentFunctionInfo && holds_alternative<VariableSlot>(_slot));
|
yulAssert(m_currentFunctionInfo && std::holds_alternative<VariableSlot>(_slot));
|
||||||
yulAssert(util::contains(m_currentFunctionInfo->returnVariables, get<VariableSlot>(_slot)));
|
yulAssert(util::contains(m_currentFunctionInfo->returnVariables, std::get<VariableSlot>(_slot)));
|
||||||
// Strictly speaking the cost of the PUSH0 depends on the targeted EVM version, but the difference
|
// Strictly speaking the cost of the PUSH0 depends on the targeted EVM version, but the difference
|
||||||
// will not matter here.
|
// will not matter here.
|
||||||
opGas += evmasm::GasMeter::runGas(evmasm::pushInstruction(0), langutil::EVMVersion());;
|
opGas += evmasm::GasMeter::runGas(evmasm::pushInstruction(0), langutil::EVMVersion());;
|
||||||
|
@ -34,6 +34,7 @@ NAMESPACE_STD_FREE_FILES=(
|
|||||||
libsolidity/lsp/*
|
libsolidity/lsp/*
|
||||||
libsolidity/parsing/*
|
libsolidity/parsing/*
|
||||||
libsolutil/*
|
libsolutil/*
|
||||||
|
libyul/backends/evm/*
|
||||||
solc/*
|
solc/*
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user