Refactor ExpressionCompiler with acceptAndConvert.

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

View File

@ -121,6 +121,8 @@ private:
/// operation. /// operation.
static bool cleanupNeededForOp(Type::Category _type, Token _op); 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. /// @returns the CompilerUtils object containing the current context.
CompilerUtils utils(); CompilerUtils utils();