Introduce machine-dependent stack adjustment.

This commit is contained in:
chriseth 2017-05-31 12:15:43 +02:00
parent 64ddb176bb
commit fefd3b866d
3 changed files with 28 additions and 15 deletions

View File

@ -105,6 +105,7 @@ void CodeTransform::operator()(FunctionCall const& _call)
{
returnLabel = m_assembly.newLabelId();
m_assembly.appendLabelReference(returnLabel);
m_stackAdjustment++;
}
Scope::Function* function = nullptr;
@ -125,6 +126,7 @@ void CodeTransform::operator()(FunctionCall const& _call)
{
m_assembly.appendJumpTo(*function->id, function->returns.size() - function->arguments.size() - 1);
m_assembly.appendLabel(returnLabel);
m_stackAdjustment--;
}
checkStackHeight(&_call);
}
@ -280,7 +282,8 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
Scope::Function& function = boost::get<Scope::Function>(m_scope->identifiers.at(_function.name));
assignLabelIdIfUnset(function.id);
int height = m_evm15 ? 0 : 1;
int const localStackAdjustment = m_evm15 ? 0 : 1;
int height = localStackAdjustment;
solAssert(m_info.scopes.at(&_function.body), "");
Scope* varScope = m_info.scopes.at(m_info.virtualBlocks.at(&_function).get()).get();
solAssert(varScope, "");
@ -294,12 +297,18 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
m_assembly.setSourceLocation(_function.location);
int stackHeightBefore = m_assembly.stackHeight();
AbstractAssembly::LabelID afterFunction = m_assembly.newLabelId();
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore + height);
if (m_evm15)
{
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore);
m_assembly.appendBeginsub(*function.id, _function.arguments.size());
}
else
{
m_assembly.appendJumpTo(afterFunction, -stackHeightBefore + height);
m_assembly.appendLabel(*function.id);
}
m_stackAdjustment += localStackAdjustment;
for (auto const& v: _function.returns)
{
@ -309,10 +318,11 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
m_assembly.appendConstant(u256(0));
}
CodeTransform(m_errorReporter, m_assembly, m_info, m_evm15, m_identifierAccess, 0).run(_function.body);
CodeTransform(m_errorReporter, m_assembly, m_info, m_evm15, m_identifierAccess, localStackAdjustment)
.run(_function.body);
if (_function.arguments.size() > 0)
{
// Stack of target positions of stack elements
vector<int> stackLayout;
if (!m_evm15)
stackLayout.push_back(_function.returns.size()); // Move return label to the top
@ -321,7 +331,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
stackLayout.push_back(i);
solAssert(stackLayout.size() <= 17, "Stack too deep");
while (stackLayout.back() != int(stackLayout.size() - 1))
while (!stackLayout.empty() && stackLayout.back() != int(stackLayout.size() - 1))
if (stackLayout.back() < 0)
{
m_assembly.appendInstruction(solidity::Instruction::POP);
@ -340,13 +350,14 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
m_assembly.appendReturnsub(_function.returns.size());
else
m_assembly.appendJump(stackHeightBefore - _function.returns.size());
m_stackAdjustment -= localStackAdjustment;
m_assembly.appendLabel(afterFunction);
checkStackHeight(&_function);
}
void CodeTransform::operator()(Block const& _block)
{
CodeTransform(m_errorReporter, m_assembly, m_info, m_evm15, m_identifierAccess, m_initialStackHeight).run(_block);
CodeTransform(m_errorReporter, m_assembly, m_info, m_evm15, m_identifierAccess, m_stackAdjustment).run(_block);
}
AbstractAssembly::LabelID CodeTransform::labelFromIdentifier(Identifier const& _identifier)
@ -420,11 +431,11 @@ void CodeTransform::checkStackHeight(void const* _astElement)
{
solAssert(m_info.stackHeightInfo.count(_astElement), "Stack height for AST element not found.");
solAssert(
m_info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_initialStackHeight,
m_info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_stackAdjustment,
"Stack height mismatch between analysis and code generation phase: Analysis: " +
to_string(m_info.stackHeightInfo.at(_astElement)) +
" code gen: " +
to_string(m_assembly.stackHeight() - m_initialStackHeight)
to_string(m_assembly.stackHeight() - m_stackAdjustment)
);
}

View File

@ -80,14 +80,14 @@ protected:
solidity::assembly::AsmAnalysisInfo& _analysisInfo,
bool _evm15,
ExternalIdentifierAccess const& _identifierAccess,
int _initialStackHeight
int _stackAdjustment
):
m_errorReporter(_errorReporter),
m_assembly(_assembly),
m_info(_analysisInfo),
m_evm15(_evm15),
m_identifierAccess(_identifierAccess),
m_initialStackHeight(_initialStackHeight)
m_stackAdjustment(_stackAdjustment)
{}
public:
@ -128,7 +128,11 @@ public:
solidity::assembly::Scope* m_scope = nullptr;
bool m_evm15 = false;
ExternalIdentifierAccess m_identifierAccess;
int const m_initialStackHeight;
/// Adjustment between the stack height as determined during the analysis phase
/// and the stack height in the assembly. This is caused by an initial stack being present
/// for inline assembly and different stack heights depending on the EVM backend used
/// (EVM 1.0 or 1.5).
int m_stackAdjustment = 0;
};
}

View File

@ -203,8 +203,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
}
int const stackHeight = m_stackHeight;
// 1 for return label, depends on VM version
m_stackHeight = 1 + _funDef.arguments.size() + _funDef.returns.size();
m_stackHeight = _funDef.arguments.size() + _funDef.returns.size();
bool success = (*this)(_funDef.body);
@ -258,11 +257,10 @@ bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall)
success = false;
}
}
m_stackHeight += 1; // Return label, but depends on backend
for (auto const& arg: _funCall.arguments | boost::adaptors::reversed)
if (!expectExpression(arg))
success = false;
m_stackHeight += int(returns) - int(arguments) - 1; // Return label, but depends on backend
m_stackHeight += int(returns) - int(arguments);
m_info.stackHeightInfo[&_funCall] = m_stackHeight;
return success;
}