Introduce virtual blocks for function arguments.

This commit is contained in:
chriseth 2017-05-26 21:46:02 +02:00
parent 002df12d13
commit 4af55c78eb
5 changed files with 28 additions and 21 deletions

View File

@ -46,7 +46,7 @@ set<string> const builtinTypes{"bool", "u8", "s8", "u32", "s32", "u64", "s64", "
bool AsmAnalyzer::analyze(Block const& _block) bool AsmAnalyzer::analyze(Block const& _block)
{ {
if (!(ScopeFiller(m_info.scopes, m_errors))(_block)) if (!(ScopeFiller(m_info, m_errors))(_block))
return false; return false;
return (*this)(_block); return (*this)(_block);
@ -206,16 +206,17 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef) bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
{ {
Scope& bodyScope = scope(&_funDef.body); Block const* virtualBlock = m_info.virtualBlocks.at(&_funDef).get();
solAssert(virtualBlock, "");
Scope& varScope = scope(virtualBlock);
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>(bodyScope.identifiers.at(var.name)).active = true; boost::get<Scope::Variable>(varScope.identifiers.at(var.name)).active = true;
} }
int const stackHeight = m_stackHeight; int const stackHeight = m_stackHeight;
m_stackHeight = _funDef.arguments.size() + _funDef.returns.size(); m_stackHeight = _funDef.arguments.size() + _funDef.returns.size();
m_virtualVariablesInNextBlock = m_stackHeight;
bool success = (*this)(_funDef.body); bool success = (*this)(_funDef.body);
@ -337,10 +338,10 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
bool AsmAnalyzer::operator()(Block const& _block) bool AsmAnalyzer::operator()(Block const& _block)
{ {
bool success = true; bool success = true;
auto previousScope = m_currentScope;
m_currentScope = &scope(&_block); m_currentScope = &scope(&_block);
int const initialStackHeight = m_stackHeight - m_virtualVariablesInNextBlock; int const initialStackHeight = m_stackHeight;
m_virtualVariablesInNextBlock = 0;
for (auto const& s: _block.statements) for (auto const& s: _block.statements)
if (!boost::apply_visitor(*this, s)) if (!boost::apply_visitor(*this, s))
@ -366,8 +367,8 @@ bool AsmAnalyzer::operator()(Block const& _block)
success = false; success = false;
} }
m_currentScope = m_currentScope->superScope;
m_info.stackHeightInfo[&_block] = m_stackHeight; m_info.stackHeightInfo[&_block] = m_stackHeight;
m_currentScope = previousScope;
return success; return success;
} }

View File

@ -91,10 +91,6 @@ private:
Scope& scope(assembly::Block const* _block); Scope& scope(assembly::Block const* _block);
void expectValidType(std::string const& type, SourceLocation const& _location); void expectValidType(std::string const& type, SourceLocation const& _location);
/// This is used when we enter the body of a function definition. There, the parameters
/// and return parameters appear as variables which are already on the stack before
/// we enter the block.
int m_virtualVariablesInNextBlock = 0;
int m_stackHeight = 0; int m_stackHeight = 0;
julia::ExternalIdentifierAccess::Resolver const& m_resolver; julia::ExternalIdentifierAccess::Resolver const& m_resolver;
Scope* m_currentScope = nullptr; Scope* m_currentScope = nullptr;

View File

@ -24,6 +24,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <vector>
namespace dev namespace dev
{ {
@ -55,6 +56,8 @@ struct AsmAnalysisInfo
using Scopes = std::map<assembly::Block const*, std::shared_ptr<Scope>>; using Scopes = std::map<assembly::Block const*, std::shared_ptr<Scope>>;
Scopes scopes; Scopes scopes;
StackHeightInfo stackHeightInfo; StackHeightInfo stackHeightInfo;
/// Virtual blocks which will be used for scopes for function arguments and return values.
std::map<FunctionDefinition const*, std::shared_ptr<assembly::Block const>> virtualBlocks;
}; };
} }

View File

@ -22,6 +22,7 @@
#include <libsolidity/inlineasm/AsmData.h> #include <libsolidity/inlineasm/AsmData.h>
#include <libsolidity/inlineasm/AsmScope.h> #include <libsolidity/inlineasm/AsmScope.h>
#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
#include <libsolidity/interface/Exceptions.h> #include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/Utils.h> #include <libsolidity/interface/Utils.h>
@ -36,8 +37,8 @@ using namespace dev;
using namespace dev::solidity; using namespace dev::solidity;
using namespace dev::solidity::assembly; using namespace dev::solidity::assembly;
ScopeFiller::ScopeFiller(ScopeFiller::Scopes& _scopes, ErrorList& _errors): ScopeFiller::ScopeFiller(AsmAnalysisInfo& _info, ErrorList& _errors):
m_scopes(_scopes), m_errors(_errors) m_info(_info), m_errors(_errors)
{ {
m_currentScope = &scope(nullptr); m_currentScope = &scope(nullptr);
} }
@ -84,16 +85,22 @@ bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef)
)); ));
success = false; success = false;
} }
Scope& body = scope(&_funDef.body);
body.superScope = m_currentScope; auto virtualBlock = m_info.virtualBlocks[&_funDef] = make_shared<Block>();
body.functionScope = true; Scope& varScope = scope(virtualBlock.get());
varScope.superScope = m_currentScope;
m_currentScope = &varScope;
varScope.functionScope = true;
for (auto const& var: _funDef.arguments + _funDef.returns) for (auto const& var: _funDef.arguments + _funDef.returns)
if (!registerVariable(var, _funDef.location, body)) if (!registerVariable(var, _funDef.location, varScope))
success = false; success = false;
if (!(*this)(_funDef.body)) if (!(*this)(_funDef.body))
success = false; success = false;
solAssert(m_currentScope == &varScope, "");
m_currentScope = m_currentScope->superScope;
return success; return success;
} }
@ -137,7 +144,7 @@ bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const&
Scope& ScopeFiller::scope(Block const* _block) Scope& ScopeFiller::scope(Block const* _block)
{ {
auto& scope = m_scopes[_block]; auto& scope = m_info.scopes[_block];
if (!scope) if (!scope)
scope = make_shared<Scope>(); scope = make_shared<Scope>();
return *scope; return *scope;

View File

@ -49,6 +49,7 @@ struct FunctionCall;
struct Switch; struct Switch;
struct Scope; struct Scope;
struct AsmAnalysisInfo;
/** /**
* Fills scopes with identifiers and checks for name clashes. * Fills scopes with identifiers and checks for name clashes.
@ -57,8 +58,7 @@ struct Scope;
class ScopeFiller: public boost::static_visitor<bool> class ScopeFiller: public boost::static_visitor<bool>
{ {
public: public:
using Scopes = std::map<assembly::Block const*, std::shared_ptr<Scope>>; ScopeFiller(AsmAnalysisInfo& _info, ErrorList& _errors);
ScopeFiller(Scopes& _scopes, ErrorList& _errors);
bool operator()(assembly::Instruction const&) { return true; } bool operator()(assembly::Instruction const&) { return true; }
bool operator()(assembly::Literal const&) { return true; } bool operator()(assembly::Literal const&) { return true; }
@ -83,7 +83,7 @@ private:
Scope& scope(assembly::Block const* _block); Scope& scope(assembly::Block const* _block);
Scope* m_currentScope = nullptr; Scope* m_currentScope = nullptr;
Scopes& m_scopes; AsmAnalysisInfo& m_info;
ErrorList& m_errors; ErrorList& m_errors;
}; };