mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2389 from ethereum/moveLabelIDs
Move LabelIDs to generation phase.
This commit is contained in:
commit
43cfab70d0
@ -64,8 +64,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
for (auto const& variable: _varDecl.variables)
|
for (auto const& variable: _varDecl.variables)
|
||||||
{
|
{
|
||||||
auto& var = boost::get<Scope::Variable>(m_scope->identifiers.at(variable.name));
|
auto& var = boost::get<Scope::Variable>(m_scope->identifiers.at(variable.name));
|
||||||
var.stackHeight = height++;
|
m_context->variableStackHeights[&var] = height++;
|
||||||
var.active = true;
|
|
||||||
}
|
}
|
||||||
checkStackHeight(&_varDecl);
|
checkStackHeight(&_varDecl);
|
||||||
}
|
}
|
||||||
@ -91,8 +90,7 @@ void CodeTransform::operator()(Label const& _label)
|
|||||||
solAssert(m_scope, "");
|
solAssert(m_scope, "");
|
||||||
solAssert(m_scope->identifiers.count(_label.name), "");
|
solAssert(m_scope->identifiers.count(_label.name), "");
|
||||||
Scope::Label& label = boost::get<Scope::Label>(m_scope->identifiers.at(_label.name));
|
Scope::Label& label = boost::get<Scope::Label>(m_scope->identifiers.at(_label.name));
|
||||||
assignLabelIdIfUnset(label.id);
|
m_assembly.appendLabel(labelID(label));
|
||||||
m_assembly.appendLabel(*label.id);
|
|
||||||
checkStackHeight(&_label);
|
checkStackHeight(&_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +118,11 @@ void CodeTransform::operator()(FunctionCall const& _call)
|
|||||||
for (auto const& arg: _call.arguments | boost::adaptors::reversed)
|
for (auto const& arg: _call.arguments | boost::adaptors::reversed)
|
||||||
visitExpression(arg);
|
visitExpression(arg);
|
||||||
m_assembly.setSourceLocation(_call.location);
|
m_assembly.setSourceLocation(_call.location);
|
||||||
assignLabelIdIfUnset(function->id);
|
|
||||||
if (m_evm15)
|
if (m_evm15)
|
||||||
m_assembly.appendJumpsub(*function->id, function->arguments.size(), function->returns.size());
|
m_assembly.appendJumpsub(functionEntryID(*function), function->arguments.size(), function->returns.size());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_assembly.appendJumpTo(*function->id, function->returns.size() - function->arguments.size() - 1);
|
m_assembly.appendJumpTo(functionEntryID(*function), function->returns.size() - function->arguments.size() - 1);
|
||||||
m_assembly.appendLabel(returnLabel);
|
m_assembly.appendLabel(returnLabel);
|
||||||
m_stackAdjustment--;
|
m_stackAdjustment--;
|
||||||
}
|
}
|
||||||
@ -181,8 +178,7 @@ void CodeTransform::operator()(assembly::Identifier const& _identifier)
|
|||||||
},
|
},
|
||||||
[=](Scope::Label& _label)
|
[=](Scope::Label& _label)
|
||||||
{
|
{
|
||||||
assignLabelIdIfUnset(_label.id);
|
m_assembly.appendLabelReference(labelID(_label));
|
||||||
m_assembly.appendLabelReference(*_label.id);
|
|
||||||
},
|
},
|
||||||
[=](Scope::Function&)
|
[=](Scope::Function&)
|
||||||
{
|
{
|
||||||
@ -282,7 +278,6 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
solAssert(m_scope, "");
|
solAssert(m_scope, "");
|
||||||
solAssert(m_scope->identifiers.count(_function.name), "");
|
solAssert(m_scope->identifiers.count(_function.name), "");
|
||||||
Scope::Function& function = boost::get<Scope::Function>(m_scope->identifiers.at(_function.name));
|
Scope::Function& function = boost::get<Scope::Function>(m_scope->identifiers.at(_function.name));
|
||||||
assignLabelIdIfUnset(function.id);
|
|
||||||
|
|
||||||
int const localStackAdjustment = m_evm15 ? 0 : 1;
|
int const localStackAdjustment = m_evm15 ? 0 : 1;
|
||||||
int height = localStackAdjustment;
|
int height = localStackAdjustment;
|
||||||
@ -292,8 +287,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
for (auto const& v: _function.arguments | boost::adaptors::reversed)
|
for (auto const& v: _function.arguments | boost::adaptors::reversed)
|
||||||
{
|
{
|
||||||
auto& var = boost::get<Scope::Variable>(varScope->identifiers.at(v.name));
|
auto& var = boost::get<Scope::Variable>(varScope->identifiers.at(v.name));
|
||||||
var.stackHeight = height++;
|
m_context->variableStackHeights[&var] = height++;
|
||||||
var.active = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_assembly.setSourceLocation(_function.location);
|
m_assembly.setSourceLocation(_function.location);
|
||||||
@ -303,25 +297,24 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
if (m_evm15)
|
if (m_evm15)
|
||||||
{
|
{
|
||||||
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore);
|
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore);
|
||||||
m_assembly.appendBeginsub(*function.id, _function.arguments.size());
|
m_assembly.appendBeginsub(functionEntryID(function), _function.arguments.size());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore + height);
|
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore + height);
|
||||||
m_assembly.appendLabel(*function.id);
|
m_assembly.appendLabel(functionEntryID(function));
|
||||||
}
|
}
|
||||||
m_stackAdjustment += localStackAdjustment;
|
m_stackAdjustment += localStackAdjustment;
|
||||||
|
|
||||||
for (auto const& v: _function.returns)
|
for (auto const& v: _function.returns)
|
||||||
{
|
{
|
||||||
auto& var = boost::get<Scope::Variable>(varScope->identifiers.at(v.name));
|
auto& var = boost::get<Scope::Variable>(varScope->identifiers.at(v.name));
|
||||||
var.stackHeight = height++;
|
m_context->variableStackHeights[&var] = height++;
|
||||||
var.active = true;
|
|
||||||
// Preset stack slots for return variables to zero.
|
// Preset stack slots for return variables to zero.
|
||||||
m_assembly.appendConstant(u256(0));
|
m_assembly.appendConstant(u256(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeTransform(m_assembly, m_info, m_evm15, m_identifierAccess, localStackAdjustment)
|
CodeTransform(m_assembly, m_info, m_evm15, m_identifierAccess, localStackAdjustment, m_context)
|
||||||
.run(_function.body);
|
.run(_function.body);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -367,7 +360,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
|
|
||||||
void CodeTransform::operator()(Block const& _block)
|
void CodeTransform::operator()(Block const& _block)
|
||||||
{
|
{
|
||||||
CodeTransform(m_assembly, m_info, m_evm15, m_identifierAccess, m_stackAdjustment).run(_block);
|
CodeTransform(m_assembly, m_info, m_evm15, m_identifierAccess, m_stackAdjustment, m_context).run(_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractAssembly::LabelID CodeTransform::labelFromIdentifier(Identifier const& _identifier)
|
AbstractAssembly::LabelID CodeTransform::labelFromIdentifier(Identifier const& _identifier)
|
||||||
@ -377,8 +370,7 @@ AbstractAssembly::LabelID CodeTransform::labelFromIdentifier(Identifier const& _
|
|||||||
[=](Scope::Variable&) { solAssert(false, "Expected label"); },
|
[=](Scope::Variable&) { solAssert(false, "Expected label"); },
|
||||||
[&](Scope::Label& _label)
|
[&](Scope::Label& _label)
|
||||||
{
|
{
|
||||||
assignLabelIdIfUnset(_label.id);
|
label = labelID(_label);
|
||||||
label = *_label.id;
|
|
||||||
},
|
},
|
||||||
[=](Scope::Function&) { solAssert(false, "Expected label"); }
|
[=](Scope::Function&) { solAssert(false, "Expected label"); }
|
||||||
)))
|
)))
|
||||||
@ -388,6 +380,20 @@ AbstractAssembly::LabelID CodeTransform::labelFromIdentifier(Identifier const& _
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AbstractAssembly::LabelID CodeTransform::labelID(Scope::Label const& _label)
|
||||||
|
{
|
||||||
|
if (!m_context->labelIDs.count(&_label))
|
||||||
|
m_context->labelIDs[&_label] = m_assembly.newLabelId();
|
||||||
|
return m_context->labelIDs[&_label];
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractAssembly::LabelID CodeTransform::functionEntryID(Scope::Function const& _function)
|
||||||
|
{
|
||||||
|
if (!m_context->functionEntryIDs.count(&_function))
|
||||||
|
m_context->functionEntryIDs[&_function] = m_assembly.newLabelId();
|
||||||
|
return m_context->functionEntryIDs[&_function];
|
||||||
|
}
|
||||||
|
|
||||||
void CodeTransform::visitExpression(Statement const& _expression)
|
void CodeTransform::visitExpression(Statement const& _expression)
|
||||||
{
|
{
|
||||||
int height = m_assembly.stackHeight();
|
int height = m_assembly.stackHeight();
|
||||||
@ -418,7 +424,8 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
|||||||
|
|
||||||
int CodeTransform::variableHeightDiff(solidity::assembly::Scope::Variable const& _var, bool _forSwap)
|
int CodeTransform::variableHeightDiff(solidity::assembly::Scope::Variable const& _var, bool _forSwap)
|
||||||
{
|
{
|
||||||
int heightDiff = m_assembly.stackHeight() - _var.stackHeight;
|
solAssert(m_context->variableStackHeights.count(&_var), "");
|
||||||
|
int heightDiff = m_assembly.stackHeight() - m_context->variableStackHeights[&_var];
|
||||||
if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16))
|
if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16))
|
||||||
{
|
{
|
||||||
solUnimplemented(
|
solUnimplemented(
|
||||||
@ -446,9 +453,3 @@ void CodeTransform::checkStackHeight(void const* _astElement)
|
|||||||
to_string(m_assembly.stackHeight() - m_stackAdjustment)
|
to_string(m_assembly.stackHeight() - m_stackAdjustment)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::assignLabelIdIfUnset(boost::optional<AbstractAssembly::LabelID>& _labelId)
|
|
||||||
{
|
|
||||||
if (!_labelId)
|
|
||||||
_labelId.reset(m_assembly.newLabelId());
|
|
||||||
}
|
|
||||||
|
@ -64,7 +64,14 @@ public:
|
|||||||
solidity::assembly::AsmAnalysisInfo& _analysisInfo,
|
solidity::assembly::AsmAnalysisInfo& _analysisInfo,
|
||||||
bool _evm15 = false,
|
bool _evm15 = false,
|
||||||
ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()
|
ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()
|
||||||
): CodeTransform(_assembly, _analysisInfo, _evm15, _identifierAccess, _assembly.stackHeight())
|
): CodeTransform(
|
||||||
|
_assembly,
|
||||||
|
_analysisInfo,
|
||||||
|
_evm15,
|
||||||
|
_identifierAccess,
|
||||||
|
_assembly.stackHeight(),
|
||||||
|
std::make_shared<Context>()
|
||||||
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,18 +79,28 @@ public:
|
|||||||
void run(solidity::assembly::Block const& _block);
|
void run(solidity::assembly::Block const& _block);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
struct Context
|
||||||
|
{
|
||||||
|
using Scope = solidity::assembly::Scope;
|
||||||
|
std::map<Scope::Label const*, AbstractAssembly::LabelID> labelIDs;
|
||||||
|
std::map<Scope::Function const*, AbstractAssembly::LabelID> functionEntryIDs;
|
||||||
|
std::map<Scope::Variable const*, int> variableStackHeights;
|
||||||
|
};
|
||||||
|
|
||||||
CodeTransform(
|
CodeTransform(
|
||||||
julia::AbstractAssembly& _assembly,
|
julia::AbstractAssembly& _assembly,
|
||||||
solidity::assembly::AsmAnalysisInfo& _analysisInfo,
|
solidity::assembly::AsmAnalysisInfo& _analysisInfo,
|
||||||
bool _evm15,
|
bool _evm15,
|
||||||
ExternalIdentifierAccess const& _identifierAccess,
|
ExternalIdentifierAccess const& _identifierAccess,
|
||||||
int _stackAdjustment
|
int _stackAdjustment,
|
||||||
|
std::shared_ptr<Context> _context
|
||||||
):
|
):
|
||||||
m_assembly(_assembly),
|
m_assembly(_assembly),
|
||||||
m_info(_analysisInfo),
|
m_info(_analysisInfo),
|
||||||
m_evm15(_evm15),
|
m_evm15(_evm15),
|
||||||
m_identifierAccess(_identifierAccess),
|
m_identifierAccess(_identifierAccess),
|
||||||
m_stackAdjustment(_stackAdjustment)
|
m_stackAdjustment(_stackAdjustment),
|
||||||
|
m_context(_context)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -102,6 +119,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
AbstractAssembly::LabelID labelFromIdentifier(solidity::assembly::Identifier const& _identifier);
|
AbstractAssembly::LabelID labelFromIdentifier(solidity::assembly::Identifier const& _identifier);
|
||||||
|
/// @returns the label ID corresponding to the given label, allocating a new one if
|
||||||
|
/// necessary.
|
||||||
|
AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label);
|
||||||
|
AbstractAssembly::LabelID functionEntryID(solidity::assembly::Scope::Function const& _function);
|
||||||
/// Generates code for an expression that is supposed to return a single value.
|
/// Generates code for an expression that is supposed to return a single value.
|
||||||
void visitExpression(solidity::assembly::Statement const& _expression);
|
void visitExpression(solidity::assembly::Statement const& _expression);
|
||||||
|
|
||||||
@ -116,9 +137,6 @@ private:
|
|||||||
|
|
||||||
void checkStackHeight(void const* _astElement);
|
void checkStackHeight(void const* _astElement);
|
||||||
|
|
||||||
/// Assigns the label's or function's id to a value taken from eth::Assembly if it has not yet been set.
|
|
||||||
void assignLabelIdIfUnset(boost::optional<AbstractAssembly::LabelID>& _labelId);
|
|
||||||
|
|
||||||
julia::AbstractAssembly& m_assembly;
|
julia::AbstractAssembly& m_assembly;
|
||||||
solidity::assembly::AsmAnalysisInfo& m_info;
|
solidity::assembly::AsmAnalysisInfo& m_info;
|
||||||
solidity::assembly::Scope* m_scope = nullptr;
|
solidity::assembly::Scope* m_scope = nullptr;
|
||||||
@ -129,6 +147,7 @@ private:
|
|||||||
/// for inline assembly and different stack heights depending on the EVM backend used
|
/// for inline assembly and different stack heights depending on the EVM backend used
|
||||||
/// (EVM 1.0 or 1.5).
|
/// (EVM 1.0 or 1.5).
|
||||||
int m_stackAdjustment = 0;
|
int m_stackAdjustment = 0;
|
||||||
|
std::shared_ptr<Context> m_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
|
|||||||
if (m_currentScope->lookup(_identifier.name, Scope::Visitor(
|
if (m_currentScope->lookup(_identifier.name, Scope::Visitor(
|
||||||
[&](Scope::Variable const& _var)
|
[&](Scope::Variable const& _var)
|
||||||
{
|
{
|
||||||
if (!_var.active)
|
if (!m_activeVariables.count(&_var))
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
_identifier.location,
|
_identifier.location,
|
||||||
@ -187,7 +187,7 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
|
|||||||
for (auto const& variable: _varDecl.variables)
|
for (auto const& variable: _varDecl.variables)
|
||||||
{
|
{
|
||||||
expectValidType(variable.type, variable.location);
|
expectValidType(variable.type, variable.location);
|
||||||
boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)).active = true;
|
m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
|
||||||
}
|
}
|
||||||
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
||||||
return success;
|
return success;
|
||||||
@ -201,7 +201,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
|
|||||||
for (auto const& var: _funDef.arguments + _funDef.returns)
|
for (auto const& var: _funDef.arguments + _funDef.returns)
|
||||||
{
|
{
|
||||||
expectValidType(var.type, var.location);
|
expectValidType(var.type, var.location);
|
||||||
boost::get<Scope::Variable>(varScope.identifiers.at(var.name)).active = true;
|
m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int const stackHeight = m_stackHeight;
|
int const stackHeight = m_stackHeight;
|
||||||
@ -384,7 +384,7 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t
|
|||||||
m_errorReporter.typeError(_variable.location, "Assignment requires variable.");
|
m_errorReporter.typeError(_variable.location, "Assignment requires variable.");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
else if (!boost::get<Scope::Variable>(*var).active)
|
else if (!m_activeVariables.count(&boost::get<Scope::Variable>(*var)))
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(
|
m_errorReporter.declarationError(
|
||||||
_variable.location,
|
_variable.location,
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include <libsolidity/interface/Exceptions.h>
|
#include <libsolidity/interface/Exceptions.h>
|
||||||
|
|
||||||
|
#include <libsolidity/inlineasm/AsmScope.h>
|
||||||
|
|
||||||
#include <libjulia/backends/evm/AbstractAssembly.h>
|
#include <libjulia/backends/evm/AbstractAssembly.h>
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
@ -51,9 +53,6 @@ struct FunctionCall;
|
|||||||
struct Switch;
|
struct Switch;
|
||||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
|
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
|
||||||
|
|
||||||
|
|
||||||
struct Scope;
|
|
||||||
|
|
||||||
struct AsmAnalysisInfo;
|
struct AsmAnalysisInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,6 +101,9 @@ private:
|
|||||||
int m_stackHeight = 0;
|
int m_stackHeight = 0;
|
||||||
julia::ExternalIdentifierAccess::Resolver m_resolver;
|
julia::ExternalIdentifierAccess::Resolver m_resolver;
|
||||||
Scope* m_currentScope = nullptr;
|
Scope* m_currentScope = nullptr;
|
||||||
|
/// Variables that are active at the current point in assembly (as opposed to
|
||||||
|
/// "part of the scope but not yet declared")
|
||||||
|
std::set<Scope::Variable const*> m_activeVariables;
|
||||||
AsmAnalysisInfo& m_info;
|
AsmAnalysisInfo& m_info;
|
||||||
ErrorReporter& m_errorReporter;
|
ErrorReporter& m_errorReporter;
|
||||||
bool m_julia = false;
|
bool m_julia = false;
|
||||||
|
@ -46,7 +46,7 @@ bool Scope::registerFunction(string const& _name, std::vector<JuliaType> const&
|
|||||||
{
|
{
|
||||||
if (exists(_name))
|
if (exists(_name))
|
||||||
return false;
|
return false;
|
||||||
identifiers[_name] = Function(_arguments, _returns);
|
identifiers[_name] = Function{_arguments, _returns};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,27 +65,12 @@ struct Scope
|
|||||||
using JuliaType = std::string;
|
using JuliaType = std::string;
|
||||||
using LabelID = size_t;
|
using LabelID = size_t;
|
||||||
|
|
||||||
struct Variable
|
struct Variable { JuliaType type; };
|
||||||
{
|
struct Label { };
|
||||||
/// Used during code generation to store the stack height. @todo move there.
|
|
||||||
int stackHeight = 0;
|
|
||||||
/// Used during analysis to check whether we already passed the declaration inside the block.
|
|
||||||
/// @todo move there.
|
|
||||||
bool active = false;
|
|
||||||
JuliaType type;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Label
|
|
||||||
{
|
|
||||||
boost::optional<LabelID> id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Function
|
struct Function
|
||||||
{
|
{
|
||||||
Function(std::vector<JuliaType> const& _arguments, std::vector<JuliaType> const& _returns): arguments(_arguments), returns(_returns) {}
|
|
||||||
std::vector<JuliaType> arguments;
|
std::vector<JuliaType> arguments;
|
||||||
std::vector<JuliaType> returns;
|
std::vector<JuliaType> returns;
|
||||||
boost::optional<LabelID> id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using Identifier = boost::variant<Variable, Label, Function>;
|
using Identifier = boost::variant<Variable, Label, Function>;
|
||||||
|
Loading…
Reference in New Issue
Block a user