Merge pull request #7361 from ethereum/exprCompRefactor

Refactor ExpressionCompiler with acceptAndConvert helper.
This commit is contained in:
chriseth 2019-09-05 15:35:22 +02:00 committed by GitHub
commit 7dcc47ed57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 66 deletions

View File

@ -78,8 +78,7 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration const& _varDecl)
{
solAssert(_varDecl.isConstant(), "");
_varDecl.value()->accept(*this);
utils().convertType(*_varDecl.value()->annotation().type, *_varDecl.annotation().type);
acceptAndConvert(*_varDecl.value(), *_varDecl.annotation().type);
// append return
m_context << dupInstruction(_varDecl.annotation().type->sizeOnStack() + 1);
@ -225,14 +224,12 @@ bool ExpressionCompiler::visit(Conditional const& _condition)
CompilerContext::LocationSetter locationSetter(m_context, _condition);
_condition.condition().accept(*this);
eth::AssemblyItem trueTag = m_context.appendConditionalJump();
_condition.falseExpression().accept(*this);
utils().convertType(*_condition.falseExpression().annotation().type, *_condition.annotation().type);
acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type);
eth::AssemblyItem endTag = m_context.appendJumpToNew();
m_context << trueTag;
int offset = _condition.annotation().type->sizeOnStack();
m_context.adjustStackOffset(-offset);
_condition.trueExpression().accept(*this);
utils().convertType(*_condition.trueExpression().annotation().type, *_condition.annotation().type);
acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type);
m_context << endTag;
return false;
}
@ -322,8 +319,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
for (auto const& component: _tuple.components())
{
component->accept(*this);
utils().convertType(*component->annotation().type, *arrayType.baseType(), true);
acceptAndConvert(*component, *arrayType.baseType(), true);
utils().storeInMemoryDynamic(*arrayType.baseType(), true);
}
@ -451,17 +447,13 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
bool swap = m_optimiseOrderLiterals && TokenTraits::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
if (swap)
{
leftExpression.accept(*this);
utils().convertType(*leftExpression.annotation().type, *leftTargetType, cleanupNeeded);
rightExpression.accept(*this);
utils().convertType(*rightExpression.annotation().type, *rightTargetType, cleanupNeeded);
acceptAndConvert(leftExpression, *leftTargetType, cleanupNeeded);
acceptAndConvert(rightExpression, *rightTargetType, cleanupNeeded);
}
else
{
rightExpression.accept(*this);
utils().convertType(*rightExpression.annotation().type, *rightTargetType, cleanupNeeded);
leftExpression.accept(*this);
utils().convertType(*leftExpression.annotation().type, *leftTargetType, cleanupNeeded);
acceptAndConvert(rightExpression, *rightTargetType, cleanupNeeded);
acceptAndConvert(leftExpression, *leftTargetType, cleanupNeeded);
}
if (TokenTraits::isShiftOp(c_op))
// shift only cares about the signedness of both sides
@ -483,9 +475,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
solAssert(_functionCall.arguments().size() == 1, "");
solAssert(_functionCall.names().empty(), "");
Expression const& firstArgument = *_functionCall.arguments().front();
firstArgument.accept(*this);
utils().convertType(*firstArgument.annotation().type, *_functionCall.annotation().type);
acceptAndConvert(*_functionCall.arguments().front(), *_functionCall.annotation().type);
return false;
}
@ -531,8 +521,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
for (unsigned i = 0; i < arguments.size(); ++i)
{
arguments[i]->accept(*this);
utils().convertType(*arguments[i]->annotation().type, *functionType->parameterTypes()[i]);
acceptAndConvert(*arguments[i], *functionType->parameterTypes()[i]);
utils().storeInMemoryDynamic(*functionType->parameterTypes()[i]);
}
m_context << Instruction::POP;
@ -552,10 +541,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
eth::AssemblyItem returnLabel = m_context.pushNewTag();
for (unsigned i = 0; i < arguments.size(); ++i)
{
arguments[i]->accept(*this);
utils().convertType(*arguments[i]->annotation().type, *function.parameterTypes()[i]);
}
acceptAndConvert(*arguments[i], *function.parameterTypes()[i]);
{
bool shortcutTaken = false;
@ -647,8 +633,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// stack layout: contract_address function_id [gas] [value]
_functionCall.expression().accept(*this);
arguments.front()->accept(*this);
utils().convertType(*arguments.front()->annotation().type, *TypeProvider::uint256(), true);
acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true);
// Note that function is not the original function, but the ".gas" function.
// Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
@ -673,11 +658,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// Provide the gas stipend manually at first because we may send zero ether.
// Will be zeroed if we send more than zero ether.
m_context << u256(eth::GasCosts::callStipend);
arguments.front()->accept(*this);
utils().convertType(
*arguments.front()->annotation().type,
*function.parameterTypes().front(), true
);
acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), true);
// gas <- gas * !value
m_context << Instruction::SWAP1 << Instruction::DUP2;
m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
@ -705,8 +686,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
}
break;
case FunctionType::Kind::Selfdestruct:
arguments.front()->accept(*this);
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), true);
acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), true);
m_context << Instruction::SELFDESTRUCT;
break;
case FunctionType::Kind::Revert:
@ -754,10 +734,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
unsigned logNumber = int(function.kind()) - int(FunctionType::Kind::Log0);
for (unsigned arg = logNumber; arg > 0; --arg)
{
arguments[arg]->accept(*this);
utils().convertType(*arguments[arg]->annotation().type, *function.parameterTypes()[arg], true);
}
acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true);
arguments.front()->accept(*this);
utils().fetchFreeMemoryPointer();
solAssert(function.parameterTypes().front()->isValueType(), "");
@ -827,23 +804,18 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
}
case FunctionType::Kind::BlockHash:
{
arguments[0]->accept(*this);
utils().convertType(*arguments[0]->annotation().type, *function.parameterTypes()[0], true);
acceptAndConvert(*arguments[0], *function.parameterTypes()[0], true);
m_context << Instruction::BLOCKHASH;
break;
}
case FunctionType::Kind::AddMod:
case FunctionType::Kind::MulMod:
{
arguments[2]->accept(*this);
utils().convertType(*arguments[2]->annotation().type, *TypeProvider::uint256());
acceptAndConvert(*arguments[2], *TypeProvider::uint256());
m_context << Instruction::DUP1 << Instruction::ISZERO;
m_context.appendConditionalInvalid();
for (unsigned i = 1; i < 3; i ++)
{
arguments[2 - i]->accept(*this);
utils().convertType(*arguments[2 - i]->annotation().type, *TypeProvider::uint256());
}
acceptAndConvert(*arguments[2 - i], *TypeProvider::uint256());
if (function.kind() == FunctionType::Kind::AddMod)
m_context << Instruction::ADDMOD;
else
@ -927,8 +899,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
solAssert(arguments.size() == 1, "");
// Fetch requested length.
arguments[0]->accept(*this);
utils().convertType(*arguments[0]->annotation().type, *TypeProvider::uint256());
acceptAndConvert(*arguments[0], *TypeProvider::uint256());
// Stack: requested_length
utils().fetchFreeMemoryPointer();
@ -967,8 +938,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::Assert:
case FunctionType::Kind::Require:
{
arguments.front()->accept(*this);
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), false);
acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), false);
if (arguments.size() > 1)
{
// Users probably expect the second argument to be evaluated
@ -1149,12 +1119,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type))
if (funType->bound())
{
_memberAccess.expression().accept(*this);
utils().convertType(
*_memberAccess.expression().annotation().type,
*funType->selfType(),
true
);
acceptAndConvert(_memberAccess.expression(), *funType->selfType(), true);
if (funType->kind() == FunctionType::Kind::Internal)
{
FunctionDefinition const& funDef = dynamic_cast<decltype(funDef)>(funType->declaration());
@ -1568,8 +1533,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(baseType);
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
_indexAccess.indexExpression()->accept(*this);
utils().convertType(*_indexAccess.indexExpression()->annotation().type, *TypeProvider::uint256(), true);
acceptAndConvert(*_indexAccess.indexExpression(), *TypeProvider::uint256(), true);
// stack layout: <base_ref> [<length>] <index>
switch (arrayType.location())
{
@ -1597,8 +1561,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
FixedBytesType const& fixedBytesType = dynamic_cast<FixedBytesType const&>(baseType);
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
_indexAccess.indexExpression()->accept(*this);
utils().convertType(*_indexAccess.indexExpression()->annotation().type, *TypeProvider::uint256(), true);
acceptAndConvert(*_indexAccess.indexExpression(), *TypeProvider::uint256(), true);
// stack layout: <value> <index>
// check out-of-bounds access
m_context << u256(fixedBytesType.numBytes());
@ -2207,8 +2170,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression)
{
solUnimplementedAssert(_expectedType.isValueType(), "Not implemented for non-value types.");
_expression.accept(*this);
utils().convertType(*_expression.annotation().type, _expectedType, true);
acceptAndConvert(_expression, _expectedType, true);
utils().storeInMemoryDynamic(_expectedType);
}
@ -2217,10 +2179,7 @@ void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Ex
if (!_variable.isConstant())
setLValueFromDeclaration(_variable, _expression);
else
{
_variable.value()->accept(*this);
utils().convertType(*_variable.value()->annotation().type, *_variable.annotation().type);
}
acceptAndConvert(*_variable.value(), *_variable.annotation().type);
}
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)
@ -2252,6 +2211,12 @@ bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token _op)
return false;
}
void ExpressionCompiler::acceptAndConvert(Expression const& _expression, Type const& _type, bool _cleanupNeeded)
{
_expression.accept(*this);
utils().convertType(*_expression.annotation().type, _type, _cleanupNeeded);
}
CompilerUtils ExpressionCompiler::utils()
{
return CompilerUtils(m_context);

View File

@ -121,6 +121,8 @@ private:
/// operation.
static bool cleanupNeededForOp(Type::Category _type, Token _op);
void acceptAndConvert(Expression const& _expression, Type const& _type, bool _cleanupNeeded = false);
/// @returns the CompilerUtils object containing the current context.
CompilerUtils utils();