@ -64,7 +64,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
solAssert ( m_currentLValue . isValid ( ) , " LValue not retrieved. " ) ;
solAssert ( m_currentLValue . isValid ( ) , " LValue not retrieved. " ) ;
Token : : Value op = _assignment . getAssignmentOperator ( ) ;
Token : : Value op = _assignment . getAssignmentOperator ( ) ;
if ( op ! = Token : : ASSIGN ) // compound assignment
if ( op ! = Token : : Assign ) // compound assignment
{
{
if ( m_currentLValue . storesReferenceOnStack ( ) )
if ( m_currentLValue . storesReferenceOnStack ( ) )
m_context < < eth : : Instruction : : SWAP1 < < eth : : Instruction : : DUP2 ;
m_context < < eth : : Instruction : : SWAP1 < < eth : : Instruction : : DUP2 ;
@ -85,7 +85,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
// the operator should know how to convert itself and to which types it applies, so
// the operator should know how to convert itself and to which types it applies, so
// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
// represents the operator
// represents the operator
if ( _unaryOperation . getType ( ) - > getCategory ( ) = = Type : : Category : : INTEGER_CONSTANT )
if ( _unaryOperation . getType ( ) - > getCategory ( ) = = Type : : Category : : IntegerConstant )
{
{
m_context < < _unaryOperation . getType ( ) - > literalValue ( nullptr ) ;
m_context < < _unaryOperation . getType ( ) - > literalValue ( nullptr ) ;
return false ;
return false ;
@ -95,19 +95,19 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
switch ( _unaryOperation . getOperator ( ) )
switch ( _unaryOperation . getOperator ( ) )
{
{
case Token : : NOT : // !
case Token : : Not : // !
m_context < < eth : : Instruction : : ISZERO ;
m_context < < eth : : Instruction : : ISZERO ;
break ;
break ;
case Token : : BIT_NOT : // ~
case Token : : BitNot : // ~
m_context < < eth : : Instruction : : NOT ;
m_context < < eth : : Instruction : : NOT ;
break ;
break ;
case Token : : DELETE : // delete
case Token : : Delete : // delete
solAssert ( m_currentLValue . isValid ( ) , " LValue not retrieved. " ) ;
solAssert ( m_currentLValue . isValid ( ) , " LValue not retrieved. " ) ;
m_currentLValue . setToZero ( _unaryOperation ) ;
m_currentLValue . setToZero ( _unaryOperation ) ;
m_currentLValue . reset ( ) ;
m_currentLValue . reset ( ) ;
break ;
break ;
case Token : : INC : // ++ (pre- or postfix)
case Token : : Inc : // ++ (pre- or postfix)
case Token : : DEC : // -- (pre- or postfix)
case Token : : Dec : // -- (pre- or postfix)
solAssert ( m_currentLValue . isValid ( ) , " LValue not retrieved. " ) ;
solAssert ( m_currentLValue . isValid ( ) , " LValue not retrieved. " ) ;
m_currentLValue . retrieveValue ( _unaryOperation . getType ( ) , _unaryOperation . getLocation ( ) ) ;
m_currentLValue . retrieveValue ( _unaryOperation . getType ( ) , _unaryOperation . getLocation ( ) ) ;
if ( ! _unaryOperation . isPrefixOperation ( ) )
if ( ! _unaryOperation . isPrefixOperation ( ) )
@ -118,7 +118,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
m_context < < eth : : Instruction : : DUP1 ;
m_context < < eth : : Instruction : : DUP1 ;
}
}
m_context < < u256 ( 1 ) ;
m_context < < u256 ( 1 ) ;
if ( _unaryOperation . getOperator ( ) = = Token : : INC )
if ( _unaryOperation . getOperator ( ) = = Token : : Inc )
m_context < < eth : : Instruction : : ADD ;
m_context < < eth : : Instruction : : ADD ;
else
else
m_context < < eth : : Instruction : : SWAP1 < < eth : : Instruction : : SUB ; // @todo avoid the swap
m_context < < eth : : Instruction : : SWAP1 < < eth : : Instruction : : SUB ; // @todo avoid the swap
@ -129,10 +129,10 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
m_currentLValue . storeValue ( _unaryOperation , ! _unaryOperation . isPrefixOperation ( ) ) ;
m_currentLValue . storeValue ( _unaryOperation , ! _unaryOperation . isPrefixOperation ( ) ) ;
m_currentLValue . reset ( ) ;
m_currentLValue . reset ( ) ;
break ;
break ;
case Token : : ADD : // +
case Token : : Add : // +
// unary add, so basically no-op
// unary add, so basically no-op
break ;
break ;
case Token : : SUB : // -
case Token : : Sub : // -
m_context < < u256 ( 0 ) < < eth : : Instruction : : SUB ;
m_context < < u256 ( 0 ) < < eth : : Instruction : : SUB ;
break ;
break ;
default :
default :
@ -149,19 +149,19 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
Type const & commonType = _binaryOperation . getCommonType ( ) ;
Type const & commonType = _binaryOperation . getCommonType ( ) ;
Token : : Value const c_op = _binaryOperation . getOperator ( ) ;
Token : : Value const c_op = _binaryOperation . getOperator ( ) ;
if ( c_op = = Token : : AND | | c_op = = Token : : OR ) // special case: short-circuiting
if ( c_op = = Token : : And | | c_op = = Token : : Or ) // special case: short-circuiting
appendAndOrOperatorCode ( _binaryOperation ) ;
appendAndOrOperatorCode ( _binaryOperation ) ;
else if ( commonType . getCategory ( ) = = Type : : Category : : INTEGER_CONSTANT )
else if ( commonType . getCategory ( ) = = Type : : Category : : IntegerConstant )
m_context < < commonType . literalValue ( nullptr ) ;
m_context < < commonType . literalValue ( nullptr ) ;
else
else
{
{
bool cleanupNeeded = commonType . getCategory ( ) = = Type : : Category : : INTEGER & &
bool cleanupNeeded = commonType . getCategory ( ) = = Type : : Category : : Integer & &
( Token : : isCompareOp ( c_op ) | | c_op = = Token : : DIV | | c_op = = Token : : MOD ) ;
( Token : : isCompareOp ( c_op ) | | c_op = = Token : : Div | | c_op = = Token : : Mod ) ;
// for commutative operators, push the literal as late as possible to allow improved optimization
// for commutative operators, push the literal as late as possible to allow improved optimization
auto isLiteral = [ ] ( Expression const & _e )
auto isLiteral = [ ] ( Expression const & _e )
{
{
return dynamic_cast < Literal const * > ( & _e ) | | _e . getType ( ) - > getCategory ( ) = = Type : : Category : : INTEGER_CONSTANT ;
return dynamic_cast < Literal const * > ( & _e ) | | _e . getType ( ) - > getCategory ( ) = = Type : : Category : : IntegerConstant ;
} ;
} ;
bool swap = m_optimize & & Token : : isCommutativeOp ( c_op ) & & isLiteral ( rightExpression ) & & ! isLiteral ( leftExpression ) ;
bool swap = m_optimize & & Token : : isCommutativeOp ( c_op ) & & isLiteral ( rightExpression ) & & ! isLiteral ( leftExpression ) ;
if ( swap )
if ( swap )
@ -206,6 +206,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
TypePointers const & parameterTypes = function . getParameterTypes ( ) ;
TypePointers const & parameterTypes = function . getParameterTypes ( ) ;
vector < ASTPointer < Expression const > > const & callArguments = _functionCall . getArguments ( ) ;
vector < ASTPointer < Expression const > > const & callArguments = _functionCall . getArguments ( ) ;
vector < ASTPointer < ASTString > > const & callArgumentNames = _functionCall . getNames ( ) ;
vector < ASTPointer < ASTString > > const & callArgumentNames = _functionCall . getNames ( ) ;
if ( ! function . takesArbitraryParameters ( ) )
solAssert ( callArguments . size ( ) = = parameterTypes . size ( ) , " " ) ;
solAssert ( callArguments . size ( ) = = parameterTypes . size ( ) , " " ) ;
vector < ASTPointer < Expression const > > arguments ;
vector < ASTPointer < Expression const > > arguments ;
@ -226,7 +227,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
switch ( function . getLocation ( ) )
switch ( function . getLocation ( ) )
{
{
case Location : : INTERNAL :
case Location : : Internal :
{
{
// Calling convention: Caller pushes return address and arguments
// Calling convention: Caller pushes return address and arguments
// Callee removes them and pushes return values
// Callee removes them and pushes return values
@ -252,12 +253,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
CompilerUtils ( m_context ) . popStackElement ( * function . getReturnParameterTypes ( ) [ i ] ) ;
CompilerUtils ( m_context ) . popStackElement ( * function . getReturnParameterTypes ( ) [ i ] ) ;
break ;
break ;
}
}
case Location : : EXTERNAL :
case Location : : External :
case Location : : BARE :
case Location : : Bare :
_functionCall . getExpression ( ) . accept ( * this ) ;
_functionCall . getExpression ( ) . accept ( * this ) ;
appendExternalFunctionCall ( function , arguments , function . getLocation ( ) = = Location : : BARE ) ;
appendExternalFunctionCall ( function , arguments , function . getLocation ( ) = = Location : : Bare ) ;
break ;
break ;
case Location : : CREATION :
case Location : : Creation :
{
{
_functionCall . getExpression ( ) . accept ( * this ) ;
_functionCall . getExpression ( ) . accept ( * this ) ;
solAssert ( ! function . gasSet ( ) , " Gas limit set for contract creation. " ) ;
solAssert ( ! function . gasSet ( ) , " Gas limit set for contract creation. " ) ;
@ -274,7 +275,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context < < u256 ( 0 ) < < eth : : Instruction : : CODECOPY ;
m_context < < u256 ( 0 ) < < eth : : Instruction : : CODECOPY ;
unsigned length = bytecode . size ( ) ;
unsigned length = bytecode . size ( ) ;
length + = appendArgumentCopyToMemory ( function . getParameterTypes ( ) , arguments , length ) ;
length + = appendArguments CopyToMemory ( arguments , function . getParameterTypes ( ) , length ) ;
// size, offset, endowment
// size, offset, endowment
m_context < < u256 ( length ) < < u256 ( 0 ) ;
m_context < < u256 ( length ) < < u256 ( 0 ) ;
if ( function . valueSet ( ) )
if ( function . valueSet ( ) )
@ -286,7 +287,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context < < eth : : swapInstruction ( 1 ) < < eth : : Instruction : : POP ;
m_context < < eth : : swapInstruction ( 1 ) < < eth : : Instruction : : POP ;
break ;
break ;
}
}
case Location : : SET_GAS :
case Location : : SetGas :
{
{
// stack layout: contract_address function_id [gas] [value]
// stack layout: contract_address function_id [gas] [value]
_functionCall . getExpression ( ) . accept ( * this ) ;
_functionCall . getExpression ( ) . accept ( * this ) ;
@ -301,7 +302,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context < < eth : : Instruction : : POP ;
m_context < < eth : : Instruction : : POP ;
break ;
break ;
}
}
case Location : : SET_VALUE :
case Location : : SetValue :
// stack layout: contract_address function_id [gas] [value]
// stack layout: contract_address function_id [gas] [value]
_functionCall . getExpression ( ) . accept ( * this ) ;
_functionCall . getExpression ( ) . accept ( * this ) ;
// Note that function is not the original function, but the ".value" function.
// Note that function is not the original function, but the ".value" function.
@ -310,31 +311,33 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context < < eth : : Instruction : : POP ;
m_context < < eth : : Instruction : : POP ;
arguments . front ( ) - > accept ( * this ) ;
arguments . front ( ) - > accept ( * this ) ;
break ;
break ;
case Location : : SEND :
case Location : : Send :
_functionCall . getExpression ( ) . accept ( * this ) ;
_functionCall . getExpression ( ) . accept ( * this ) ;
m_context < < u256 ( 0 ) ; // 0 gas, we do not want to execute code
m_context < < u256 ( 0 ) ; // 0 gas, we do not want to execute code
arguments . front ( ) - > accept ( * this ) ;
arguments . front ( ) - > accept ( * this ) ;
appendTypeConversion ( * arguments . front ( ) - > getType ( ) ,
appendTypeConversion ( * arguments . front ( ) - > getType ( ) ,
* function . getParameterTypes ( ) . front ( ) , true ) ;
* function . getParameterTypes ( ) . front ( ) , true ) ;
appendExternalFunctionCall ( FunctionType ( TypePointers { } , TypePointers { } ,
appendExternalFunctionCall ( FunctionType ( TypePointers { } , TypePointers { } ,
Location : : EXTERNAL , true , true ) , { } , true ) ;
Location : : External , false , true , true ) , { } , true ) ;
break ;
break ;
case Location : : SUICIDE :
case Location : : Suicide :
arguments . front ( ) - > accept ( * this ) ;
arguments . front ( ) - > accept ( * this ) ;
appendTypeConversion ( * arguments . front ( ) - > getType ( ) , * function . getParameterTypes ( ) . front ( ) , true ) ;
appendTypeConversion ( * arguments . front ( ) - > getType ( ) , * function . getParameterTypes ( ) . front ( ) , true ) ;
m_context < < eth : : Instruction : : SUICIDE ;
m_context < < eth : : Instruction : : SUICIDE ;
break ;
break ;
case Location : : SHA3 :
case Location : : SHA3 :
appendExpressionCopyToMemory ( * function . getParameterTypes ( ) . front ( ) , * arguments . front ( ) ) ;
{
m_context < < u256 ( 32 ) < < u256 ( 0 ) < < eth : : Instruction : : SHA3 ;
unsigned length = appendArgumentsCopyToMemory ( arguments , TypePointers ( ) , 0 , function . padArguments ( ) ) ;
m_context < < u256 ( length ) < < u256 ( 0 ) < < eth : : Instruction : : SHA3 ;
break ;
break ;
case Location : : LOG0 :
}
case Location : : LOG1 :
case Location : : Log0 :
case Location : : LOG2 :
case Location : : Log1 :
case Location : : LOG3 :
case Location : : Log2 :
case Location : : LOG4 :
case Location : : Log3 :
case Location : : Log4 :
{
{
unsigned logNumber = int ( function . getLocation ( ) ) - int ( Location : : LOG 0 ) ;
unsigned logNumber = int ( function . getLocation ( ) ) - int ( Location : : Log 0 ) ;
for ( unsigned arg = logNumber ; arg > 0 ; - - arg )
for ( unsigned arg = logNumber ; arg > 0 ; - - arg )
{
{
arguments [ arg ] - > accept ( * this ) ;
arguments [ arg ] - > accept ( * this ) ;
@ -346,7 +349,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context < < u256 ( length ) < < u256 ( 0 ) < < eth : : logInstruction ( logNumber ) ;
m_context < < u256 ( length ) < < u256 ( 0 ) < < eth : : logInstruction ( logNumber ) ;
break ;
break ;
}
}
case Location : : EVENT :
case Location : : Event :
{
{
_functionCall . getExpression ( ) . accept ( * this ) ;
_functionCall . getExpression ( ) . accept ( * this ) ;
auto const & event = dynamic_cast < EventDefinition const & > ( function . getDeclaration ( ) ) ;
auto const & event = dynamic_cast < EventDefinition const & > ( function . getDeclaration ( ) ) ;
@ -372,18 +375,18 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context < < u256 ( memLength ) < < u256 ( 0 ) < < eth : : logInstruction ( numIndexed ) ;
m_context < < u256 ( memLength ) < < u256 ( 0 ) < < eth : : logInstruction ( numIndexed ) ;
break ;
break ;
}
}
case Location : : BLOCKHASH :
case Location : : BlockHash :
{
{
arguments [ 0 ] - > accept ( * this ) ;
arguments [ 0 ] - > accept ( * this ) ;
appendTypeConversion ( * arguments [ 0 ] - > getType ( ) , * function . getParameterTypes ( ) [ 0 ] , true ) ;
appendTypeConversion ( * arguments [ 0 ] - > getType ( ) , * function . getParameterTypes ( ) [ 0 ] , true ) ;
m_context < < eth : : Instruction : : BLOCKHASH ;
m_context < < eth : : Instruction : : BLOCKHASH ;
break ;
break ;
}
}
case Location : : ECRECOVER :
case Location : : ECRecover :
case Location : : SHA256 :
case Location : : SHA256 :
case Location : : RIPEMD160 :
case Location : : RIPEMD160 :
{
{
static const map < Location , u256 > contractAddresses { { Location : : ECRECOVER , 1 } ,
static const map < Location , u256 > contractAddresses { { Location : : ECRecover , 1 } ,
{ Location : : SHA256 , 2 } ,
{ Location : : SHA256 , 2 } ,
{ Location : : RIPEMD160 , 3 } } ;
{ Location : : RIPEMD160 , 3 } } ;
m_context < < contractAddresses . find ( function . getLocation ( ) ) - > second ;
m_context < < contractAddresses . find ( function . getLocation ( ) ) - > second ;
@ -408,7 +411,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
ASTString const & member = _memberAccess . getMemberName ( ) ;
ASTString const & member = _memberAccess . getMemberName ( ) ;
switch ( _memberAccess . getExpression ( ) . getType ( ) - > getCategory ( ) )
switch ( _memberAccess . getExpression ( ) . getType ( ) - > getCategory ( ) )
{
{
case Type : : Category : : CONTRACT :
case Type : : Category : : Contract :
{
{
bool alsoSearchInteger = false ;
bool alsoSearchInteger = false ;
ContractType const & type = dynamic_cast < ContractType const & > ( * _memberAccess . getExpression ( ) . getType ( ) ) ;
ContractType const & type = dynamic_cast < ContractType const & > ( * _memberAccess . getExpression ( ) . getType ( ) ) ;
@ -420,7 +423,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
u256 identifier = type . getFunctionIdentifier ( member ) ;
u256 identifier = type . getFunctionIdentifier ( member ) ;
if ( identifier ! = Invalid256 )
if ( identifier ! = Invalid256 )
{
{
appendTypeConversion ( type , IntegerType ( 0 , IntegerType : : Modifier : : ADDRESS ) , true ) ;
appendTypeConversion ( type , IntegerType ( 0 , IntegerType : : Modifier : : Address ) , true ) ;
m_context < < identifier ;
m_context < < identifier ;
}
}
else
else
@ -430,24 +433,24 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
if ( ! alsoSearchInteger )
if ( ! alsoSearchInteger )
break ;
break ;
}
}
case Type : : Category : : INTEGER :
case Type : : Category : : Integer :
if ( member = = " balance " )
if ( member = = " balance " )
{
{
appendTypeConversion ( * _memberAccess . getExpression ( ) . getType ( ) ,
appendTypeConversion ( * _memberAccess . getExpression ( ) . getType ( ) ,
IntegerType ( 0 , IntegerType : : Modifier : : ADDRESS ) , true ) ;
IntegerType ( 0 , IntegerType : : Modifier : : Address ) , true ) ;
m_context < < eth : : Instruction : : BALANCE ;
m_context < < eth : : Instruction : : BALANCE ;
}
}
else if ( member = = " send " | | member . substr ( 0 , min < size_t > ( member . size ( ) , 4 ) ) = = " call " )
else if ( member = = " send " | | member . substr ( 0 , min < size_t > ( member . size ( ) , 4 ) ) = = " call " )
appendTypeConversion ( * _memberAccess . getExpression ( ) . getType ( ) ,
appendTypeConversion ( * _memberAccess . getExpression ( ) . getType ( ) ,
IntegerType ( 0 , IntegerType : : Modifier : : ADDRESS ) , true ) ;
IntegerType ( 0 , IntegerType : : Modifier : : Address ) , true ) ;
else
else
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Invalid member access to integer. " ) ) ;
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Invalid member access to integer. " ) ) ;
break ;
break ;
case Type : : Category : : FUNCTION :
case Type : : Category : : Function :
solAssert ( ! ! _memberAccess . getExpression ( ) . getType ( ) - > getMemberType ( member ) ,
solAssert ( ! ! _memberAccess . getExpression ( ) . getType ( ) - > getMemberType ( member ) ,
" Invalid member access to function. " ) ;
" Invalid member access to function. " ) ;
break ;
break ;
case Type : : Category : : MAGIC :
case Type : : Category : : Magic :
// we can ignore the kind of magic and only look at the name of the member
// we can ignore the kind of magic and only look at the name of the member
if ( member = = " coinbase " )
if ( member = = " coinbase " )
m_context < < eth : : Instruction : : COINBASE ;
m_context < < eth : : Instruction : : COINBASE ;
@ -472,15 +475,15 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
else
else
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Unknown magic member. " ) ) ;
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Unknown magic member. " ) ) ;
break ;
break ;
case Type : : Category : : STRUCT :
case Type : : Category : : Struct :
{
{
StructType const & type = dynamic_cast < StructType const & > ( * _memberAccess . getExpression ( ) . getType ( ) ) ;
StructType const & type = dynamic_cast < StructType const & > ( * _memberAccess . getExpression ( ) . getType ( ) ) ;
m_context < < type . getStorageOffsetOfMember ( member ) < < eth : : Instruction : : ADD ;
m_context < < type . getStorageOffsetOfMember ( member ) < < eth : : Instruction : : ADD ;
m_currentLValue = LValue ( m_context , LValue : : STORAGE , * _memberAccess . getType ( ) ) ;
m_currentLValue = LValue ( m_context , LValue : : LValueType : : Storage , * _memberAccess . getType ( ) ) ;
m_currentLValue . retrieveValueIfLValueNotRequested ( _memberAccess ) ;
m_currentLValue . retrieveValueIfLValueNotRequested ( _memberAccess ) ;
break ;
break ;
}
}
case Type : : Category : : TYPE :
case Type : : Category : : TypeType :
{
{
TypeType const & type = dynamic_cast < TypeType const & > ( * _memberAccess . getExpression ( ) . getType ( ) ) ;
TypeType const & type = dynamic_cast < TypeType const & > ( * _memberAccess . getExpression ( ) . getType ( ) ) ;
if ( type . getMembers ( ) . getMemberType ( member ) )
if ( type . getMembers ( ) . getMemberType ( member ) )
@ -512,7 +515,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
length + = CompilerUtils ( m_context ) . storeInMemory ( length ) ;
length + = CompilerUtils ( m_context ) . storeInMemory ( length ) ;
m_context < < u256 ( length ) < < u256 ( 0 ) < < eth : : Instruction : : SHA3 ;
m_context < < u256 ( length ) < < u256 ( 0 ) < < eth : : Instruction : : SHA3 ;
m_currentLValue = LValue ( m_context , LValue : : STORAGE , * _indexAccess . getType ( ) ) ;
m_currentLValue = LValue ( m_context , LValue : : LValueType : : Storage , * _indexAccess . getType ( ) ) ;
m_currentLValue . retrieveValueIfLValueNotRequested ( _indexAccess ) ;
m_currentLValue . retrieveValueIfLValueNotRequested ( _indexAccess ) ;
return false ;
return false ;
@ -523,7 +526,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
Declaration const * declaration = _identifier . getReferencedDeclaration ( ) ;
Declaration const * declaration = _identifier . getReferencedDeclaration ( ) ;
if ( MagicVariableDeclaration const * magicVar = dynamic_cast < MagicVariableDeclaration const * > ( declaration ) )
if ( MagicVariableDeclaration const * magicVar = dynamic_cast < MagicVariableDeclaration const * > ( declaration ) )
{
{
if ( magicVar - > getType ( ) - > getCategory ( ) = = Type : : Category : : CONTRACT )
if ( magicVar - > getType ( ) - > getCategory ( ) = = Type : : Category : : Contract )
// "this" or "super"
// "this" or "super"
if ( ! dynamic_cast < ContractType const & > ( * magicVar - > getType ( ) ) . isSuper ( ) )
if ( ! dynamic_cast < ContractType const & > ( * magicVar - > getType ( ) ) . isSuper ( ) )
m_context < < eth : : Instruction : : ADDRESS ;
m_context < < eth : : Instruction : : ADDRESS ;
@ -553,9 +556,9 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
{
{
switch ( _literal . getType ( ) - > getCategory ( ) )
switch ( _literal . getType ( ) - > getCategory ( ) )
{
{
case Type : : Category : : INTEGER_CONSTANT :
case Type : : Category : : IntegerConstant :
case Type : : Category : : BOOL :
case Type : : Category : : Bool :
case Type : : Category : : STRING :
case Type : : Category : : String :
m_context < < _literal . getType ( ) - > literalValue ( & _literal ) ;
m_context < < _literal . getType ( ) - > literalValue ( & _literal ) ;
break ;
break ;
default :
default :
@ -566,11 +569,11 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
void ExpressionCompiler : : appendAndOrOperatorCode ( BinaryOperation const & _binaryOperation )
void ExpressionCompiler : : appendAndOrOperatorCode ( BinaryOperation const & _binaryOperation )
{
{
Token : : Value const c_op = _binaryOperation . getOperator ( ) ;
Token : : Value const c_op = _binaryOperation . getOperator ( ) ;
solAssert ( c_op = = Token : : OR | | c_op = = Token : : AND , " " ) ;
solAssert ( c_op = = Token : : Or | | c_op = = Token : : And , " " ) ;
_binaryOperation . getLeftExpression ( ) . accept ( * this ) ;
_binaryOperation . getLeftExpression ( ) . accept ( * this ) ;
m_context < < eth : : Instruction : : DUP1 ;
m_context < < eth : : Instruction : : DUP1 ;
if ( c_op = = Token : : AND )
if ( c_op = = Token : : And )
m_context < < eth : : Instruction : : ISZERO ;
m_context < < eth : : Instruction : : ISZERO ;
eth : : AssemblyItem endLabel = m_context . appendConditionalJump ( ) ;
eth : : AssemblyItem endLabel = m_context . appendConditionalJump ( ) ;
m_context < < eth : : Instruction : : POP ;
m_context < < eth : : Instruction : : POP ;
@ -580,10 +583,10 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO
void ExpressionCompiler : : appendCompareOperatorCode ( Token : : Value _operator , Type const & _type )
void ExpressionCompiler : : appendCompareOperatorCode ( Token : : Value _operator , Type const & _type )
{
{
if ( _operator = = Token : : EQ | | _operator = = Token : : NE )
if ( _operator = = Token : : Equal | | _operator = = Token : : Not Equal )
{
{
m_context < < eth : : Instruction : : EQ ;
m_context < < eth : : Instruction : : EQ ;
if ( _operator = = Token : : NE )
if ( _operator = = Token : : Not Equal )
m_context < < eth : : Instruction : : ISZERO ;
m_context < < eth : : Instruction : : ISZERO ;
}
}
else
else
@ -593,18 +596,18 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
switch ( _operator )
switch ( _operator )
{
{
case Token : : GTE :
case Token : : Greater ThanOr Equal :
m_context < < ( c_isSigned ? eth : : Instruction : : SLT : eth : : Instruction : : LT )
m_context < < ( c_isSigned ? eth : : Instruction : : SLT : eth : : Instruction : : LT )
< < eth : : Instruction : : ISZERO ;
< < eth : : Instruction : : ISZERO ;
break ;
break ;
case Token : : LTE :
case Token : : Less ThanOr Equal :
m_context < < ( c_isSigned ? eth : : Instruction : : SGT : eth : : Instruction : : GT )
m_context < < ( c_isSigned ? eth : : Instruction : : SGT : eth : : Instruction : : GT )
< < eth : : Instruction : : ISZERO ;
< < eth : : Instruction : : ISZERO ;
break ;
break ;
case Token : : GT :
case Token : : Greater Than :
m_context < < ( c_isSigned ? eth : : Instruction : : SGT : eth : : Instruction : : GT ) ;
m_context < < ( c_isSigned ? eth : : Instruction : : SGT : eth : : Instruction : : GT ) ;
break ;
break ;
case Token : : LT :
case Token : : Less Than :
m_context < < ( c_isSigned ? eth : : Instruction : : SLT : eth : : Instruction : : LT ) ;
m_context < < ( c_isSigned ? eth : : Instruction : : SLT : eth : : Instruction : : LT ) ;
break ;
break ;
default :
default :
@ -632,19 +635,19 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
switch ( _operator )
switch ( _operator )
{
{
case Token : : ADD :
case Token : : Add :
m_context < < eth : : Instruction : : ADD ;
m_context < < eth : : Instruction : : ADD ;
break ;
break ;
case Token : : SUB :
case Token : : Sub :
m_context < < eth : : Instruction : : SUB ;
m_context < < eth : : Instruction : : SUB ;
break ;
break ;
case Token : : MUL :
case Token : : Mul :
m_context < < eth : : Instruction : : MUL ;
m_context < < eth : : Instruction : : MUL ;
break ;
break ;
case Token : : DIV :
case Token : : Div :
m_context < < ( c_isSigned ? eth : : Instruction : : SDIV : eth : : Instruction : : DIV ) ;
m_context < < ( c_isSigned ? eth : : Instruction : : SDIV : eth : : Instruction : : DIV ) ;
break ;
break ;
case Token : : MOD :
case Token : : Mod :
m_context < < ( c_isSigned ? eth : : Instruction : : SMOD : eth : : Instruction : : MOD ) ;
m_context < < ( c_isSigned ? eth : : Instruction : : SMOD : eth : : Instruction : : MOD ) ;
break ;
break ;
default :
default :
@ -656,13 +659,13 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator)
{
{
switch ( _operator )
switch ( _operator )
{
{
case Token : : BIT_OR :
case Token : : BitOr :
m_context < < eth : : Instruction : : OR ;
m_context < < eth : : Instruction : : OR ;
break ;
break ;
case Token : : BIT_AND :
case Token : : BitAnd :
m_context < < eth : : Instruction : : AND ;
m_context < < eth : : Instruction : : AND ;
break ;
break ;
case Token : : BIT_XOR :
case Token : : BitXor :
m_context < < eth : : Instruction : : XOR ;
m_context < < eth : : Instruction : : XOR ;
break ;
break ;
default :
default :
@ -695,29 +698,38 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
Type : : Category stackTypeCategory = _typeOnStack . getCategory ( ) ;
Type : : Category stackTypeCategory = _typeOnStack . getCategory ( ) ;
Type : : Category targetTypeCategory = _targetType . getCategory ( ) ;
Type : : Category targetTypeCategory = _targetType . getCategory ( ) ;
if ( stackTypeCategory = = Type : : Category : : STRING )
if ( stackTypeCategory = = Type : : Category : : String )
{
{
if ( targetTypeCategory = = Type : : Category : : INTEGER )
StaticStringType const & typeOnStack = dynamic_cast < StaticStringType const & > ( _typeOnStack ) ;
if ( targetTypeCategory = = Type : : Category : : Integer )
{
{
// conversion from string to hash. no need to clean the high bit
// conversion from string to hash. no need to clean the high bit
// only to shift right because of opposite alignment
// only to shift right because of opposite alignment
IntegerType const & targetIntegerType = dynamic_cast < IntegerType const & > ( _targetType ) ;
IntegerType const & targetIntegerType = dynamic_cast < IntegerType const & > ( _targetType ) ;
StaticStringType const & typeOnStack = dynamic_cast < StaticStringType const & > ( _typeOnStack ) ;
solAssert ( targetIntegerType . isHash ( ) , " Only conversion between String and Hash is allowed. " ) ;
solAssert ( targetIntegerType . isHash ( ) , " Only conversion between String and Hash is allowed. " ) ;
solAssert ( targetIntegerType . getNumBits ( ) = = typeOnStack . getNumBytes ( ) * 8 , " The size should be the same. " ) ;
solAssert ( targetIntegerType . getNumBits ( ) = = typeOnStack . getNumBytes ( ) * 8 , " The size should be the same. " ) ;
m_context < < ( u256 ( 1 ) < < ( 256 - typeOnStack . getNumBytes ( ) * 8 ) ) < < eth : : Instruction : : SWAP1 < < eth : : Instruction : : DIV ;
m_context < < ( u256 ( 1 ) < < ( 256 - typeOnStack . getNumBytes ( ) * 8 ) ) < < eth : : Instruction : : SWAP1 < < eth : : Instruction : : DIV ;
}
}
else
else
{
{
solAssert ( targetTypeCategory = = Type : : Category : : STRING , " Invalid type conversion requested. " ) ;
// clear lower-order bytes for conversion to shorter strings - we always clean
// nothing to do, strings are high-order-bit-aligned
solAssert ( targetTypeCategory = = Type : : Category : : String , " Invalid type conversion requested. " ) ;
//@todo clear lower-order bytes if we allow explicit conversion to shorter strings
StaticStringType const & targetType = dynamic_cast < StaticStringType const & > ( _targetType ) ;
if ( targetType . getNumBytes ( ) < typeOnStack . getNumBytes ( ) )
{
if ( targetType . getNumBytes ( ) = = 0 )
m_context < < eth : : Instruction : : DUP1 < < eth : : Instruction : : XOR ;
else
m_context < < ( u256 ( 1 ) < < ( 256 - targetType . getNumBytes ( ) * 8 ) )
< < eth : : Instruction : : DUP1 < < eth : : Instruction : : SWAP2
< < eth : : Instruction : : DIV < < eth : : Instruction : : MUL ;
}
}
}
}
}
else if ( stackTypeCategory = = Type : : Category : : INTEGER | | stackTypeCategory = = Type : : Category : : CONTRACT | |
else if ( stackTypeCategory = = Type : : Category : : Integer | | stackTypeCategory = = Type : : Category : : Contract | |
stackTypeCategory = = Type : : Category : : INTEGER_CONSTANT )
stackTypeCategory = = Type : : Category : : IntegerConstant )
{
{
if ( targetTypeCategory = = Type : : Category : : STRING & & stackTypeCategory = = Type : : Category : : INTEGER )
if ( targetTypeCategory = = Type : : Category : : String & & stackTypeCategory = = Type : : Category : : Integer )
{
{
// conversion from hash to string. no need to clean the high bit
// conversion from hash to string. no need to clean the high bit
// only to shift left because of opposite alignment
// only to shift left because of opposite alignment
@ -729,11 +741,11 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
}
}
else
else
{
{
solAssert ( targetTypeCategory = = Type : : Category : : INTEGER | | targetTypeCategory = = Type : : Category : : CONTRACT , " " ) ;
solAssert ( targetTypeCategory = = Type : : Category : : Integer | | targetTypeCategory = = Type : : Category : : Contract , " " ) ;
IntegerType addressType ( 0 , IntegerType : : Modifier : : ADDRESS ) ;
IntegerType addressType ( 0 , IntegerType : : Modifier : : Address ) ;
IntegerType const & targetType = targetTypeCategory = = Type : : Category : : INTEGER
IntegerType const & targetType = targetTypeCategory = = Type : : Category : : Integer
? dynamic_cast < IntegerType const & > ( _targetType ) : addressType ;
? dynamic_cast < IntegerType const & > ( _targetType ) : addressType ;
if ( stackTypeCategory = = Type : : Category : : INTEGER_CONSTANT )
if ( stackTypeCategory = = Type : : Category : : IntegerConstant )
{
{
IntegerConstantType const & constType = dynamic_cast < IntegerConstantType const & > ( _typeOnStack ) ;
IntegerConstantType const & constType = dynamic_cast < IntegerConstantType const & > ( _typeOnStack ) ;
// We know that the stack is clean, we only have to clean for a narrowing conversion
// We know that the stack is clean, we only have to clean for a narrowing conversion
@ -743,7 +755,7 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
}
}
else
else
{
{
IntegerType const & typeOnStack = stackTypeCategory = = Type : : Category : : INTEGER
IntegerType const & typeOnStack = stackTypeCategory = = Type : : Category : : Integer
? dynamic_cast < IntegerType const & > ( _typeOnStack ) : addressType ;
? dynamic_cast < IntegerType const & > ( _typeOnStack ) : addressType ;
// Widening: clean up according to source type width
// Widening: clean up according to source type width
// Non-widening and force: clean up according to target type bits
// Non-widening and force: clean up according to target type bits
@ -773,7 +785,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
vector < ASTPointer < Expression const > > const & _arguments ,
vector < ASTPointer < Expression const > > const & _arguments ,
bool bare )
bool bare )
{
{
solAssert ( _arguments . size ( ) = = _functionType . getParameterTypes ( ) . size ( ) , " " ) ;
solAssert ( _functionType . takesArbitraryParameters ( ) | |
_arguments . size ( ) = = _functionType . getParameterTypes ( ) . size ( ) , " " ) ;
// Assumed stack content here:
// Assumed stack content here:
// <stack top>
// <stack top>
@ -797,7 +810,10 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
// reserve space for the function identifier
// reserve space for the function identifier
unsigned dataOffset = bare ? 0 : CompilerUtils : : dataStartOffset ;
unsigned dataOffset = bare ? 0 : CompilerUtils : : dataStartOffset ;
dataOffset + = appendArgumentCopyToMemory ( _functionType . getParameterTypes ( ) , _arguments , dataOffset ) ;
// For bare call, activate "4 byte pad exception": If the first argument has exactly 4 bytes,
// do not pad it to 32 bytes.
dataOffset + = appendArgumentsCopyToMemory ( _arguments , _functionType . getParameterTypes ( ) , dataOffset ,
_functionType . padArguments ( ) , bare ) ;
//@todo only return the first return value for now
//@todo only return the first return value for now
Type const * firstType = _functionType . getReturnParameterTypes ( ) . empty ( ) ? nullptr :
Type const * firstType = _functionType . getReturnParameterTypes ( ) . empty ( ) ? nullptr :
@ -828,33 +844,44 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
if ( retSize > 0 )
if ( retSize > 0 )
{
{
bool const c_leftAligned = firstType - > getCategory ( ) = = Type : : Category : : STRING ;
bool const c_leftAligned = firstType - > getCategory ( ) = = Type : : Category : : String ;
CompilerUtils ( m_context ) . loadFromMemory ( 0 , retSize , c_leftAligned , false , true ) ;
CompilerUtils ( m_context ) . loadFromMemory ( 0 , retSize , c_leftAligned , false , true ) ;
}
}
}
}
unsigned ExpressionCompiler : : appendArgumentCopyToMemory ( TypePointers const & _types ,
unsigned ExpressionCompiler : : appendArgumentsCopyToMemory ( vector < ASTPointer < Expression const > > const & _arguments ,
vector < ASTPointer < Expression const > > const & _arguments ,
TypePointers const & _types ,
unsigned _memoryOffset )
unsigned _memoryOffset ,
bool _padToWordBoundaries ,
bool _padExceptionIfFourBytes )
{
{
solAssert ( _types . empty ( ) | | _types . size ( ) = = _arguments . size ( ) , " " ) ;
unsigned length = 0 ;
unsigned length = 0 ;
for ( unsigned i = 0 ; i < _arguments . size ( ) ; + + i )
for ( size_t i = 0 ; i < _arguments . size ( ) ; + + i )
length + = appendExpressionCopyToMemory ( * _types [ i ] , * _arguments [ i ] , _memoryOffset + length ) ;
{
_arguments [ i ] - > accept ( * this ) ;
TypePointer const & expectedType = _types . empty ( ) ? _arguments [ i ] - > getType ( ) - > getRealType ( ) : _types [ i ] ;
appendTypeConversion ( * _arguments [ i ] - > getType ( ) , * expectedType , true ) ;
bool pad = _padToWordBoundaries ;
// Do not pad if the first argument has exactly four bytes
if ( i = = 0 & & pad & & _padExceptionIfFourBytes & & expectedType - > getCalldataEncodedSize ( ) = = 4 )
pad = false ;
length + = appendTypeMoveToMemory ( * expectedType , _arguments [ i ] - > getLocation ( ) ,
_memoryOffset + length , pad ) ;
}
return length ;
return length ;
}
}
unsigned ExpressionCompiler : : appendTypeConversionAndMoveToMemory ( Type const & _expectedType , Type const & _type ,
unsigned ExpressionCompiler : : appendTypeMoveToMemory ( Type const & _type , Location const & _location , unsigned _memoryOffset , bool _padToWordBoundaries )
Location const & _location , unsigned _memoryOffset )
{
{
appendTypeConversion ( _type , _expectedType , true ) ;
unsigned const c_encodedSize = _type . getCalldataEncodedSize ( ) ;
unsigned const c_numBytes = CompilerUtils : : getPaddedSize ( _expectedType . getCalldataEncodedSize ( ) ) ;
unsigned const c_numBytes = _padToWordBoundaries ? CompilerUtils : : getPaddedSize ( c_encodedSize ) : c_encodedSize ;
if ( c_numBytes = = 0 | | c_numBytes > 32 )
if ( c_numBytes = = 0 | | c_numBytes > 32 )
BOOST_THROW_EXCEPTION ( CompilerError ( )
BOOST_THROW_EXCEPTION ( CompilerError ( )
< < errinfo_sourceLocation ( _location )
< < errinfo_sourceLocation ( _location )
< < errinfo_comment ( " Type " + _expectedType . toString ( ) + " not yet supported. " ) ) ;
< < errinfo_comment ( " Type " + _type . toString ( ) + " not yet supported. " ) ) ;
bool const c_leftAligned = _expectedType . getCategory ( ) = = Type : : Category : : STRING ;
bool const c_leftAligned = _type . getCategory ( ) = = Type : : Category : : String ;
bool const c_padToWords = true ;
return CompilerUtils ( m_context ) . storeInMemory ( _memoryOffset , c_numBytes , c_leftAligned , _padToWordBoundaries ) ;
return CompilerUtils ( m_context ) . storeInMemory ( _memoryOffset , c_numBytes , c_leftAligned , c_padToWords ) ;
}
}
unsigned ExpressionCompiler : : appendExpressionCopyToMemory ( Type const & _expectedType ,
unsigned ExpressionCompiler : : appendExpressionCopyToMemory ( Type const & _expectedType ,
@ -862,39 +889,65 @@ unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedT
unsigned _memoryOffset )
unsigned _memoryOffset )
{
{
_expression . accept ( * this ) ;
_expression . accept ( * this ) ;
return appendTypeConversionAndMoveToMemory ( _expectedType , * _expression . getType ( ) , _expression . getLocation ( ) , _memoryOffset ) ;
appendTypeConversion ( * _expression . getType ( ) , _expectedType , true ) ;
return appendTypeMoveToMemory ( _expectedType , _expression . getLocation ( ) , _memoryOffset ) ;
}
}
void ExpressionCompiler : : appendStateVariableAccessor ( VariableDeclaration const & _varDecl )
void ExpressionCompiler : : appendStateVariableAccessor ( VariableDeclaration const & _varDecl )
{
{
FunctionType thisType ( _varDecl ) ;
FunctionType accessorType ( _varDecl ) ;
solAssert ( thisType . getReturnParameterTypes ( ) . size ( ) = = 1 , " " ) ;
TypePointer const & resultType = thisType . getReturnParameterTypes ( ) . front ( ) ;
unsigned sizeOnStack ;
unsigned length = 0 ;
unsigned length = 0 ;
TypePointers const & params = this Type. getParameterTypes ( ) ;
TypePointers const & paramTypes = accessorType . getParameterTypes ( ) ;
// move arguments to memory
// move arguments to memory
for ( TypePointer const & param : boost : : adaptors : : reverse ( params ) )
for ( TypePointer const & paramType : boost : : adaptors : : reverse ( paramType s ) )
length + = appendTypeConversionAnd MoveToMemory ( * param , * param , Location ( ) , length ) ;
length + = appendTypeMoveToMemory ( * paramType , Location ( ) , length ) ;
// retrieve the position of the mapping
// retrieve the position of the variable
m_context < < m_context . getStorageLocationOfVariable ( _varDecl ) ;
m_context < < m_context . getStorageLocationOfVariable ( _varDecl ) ;
TypePointer returnType = _varDecl . getType ( ) ;
for ( TypePointer const & param : params )
for ( TypePointer const & paramType : paramType s )
{
{
// move offset to memory
// move offset to memory
CompilerUtils ( m_context ) . storeInMemory ( length ) ;
CompilerUtils ( m_context ) . storeInMemory ( length ) ;
unsigned argLen = CompilerUtils : : getPaddedSize ( param - > getCalldataEncodedSize ( ) ) ;
unsigned argLen = CompilerUtils : : getPaddedSize ( paramType - > getCalldataEncodedSize ( ) ) ;
length - = argLen ;
length - = argLen ;
m_context < < u256 ( argLen + 32 ) < < u256 ( length ) < < eth : : Instruction : : SHA3 ;
m_context < < u256 ( argLen + 32 ) < < u256 ( length ) < < eth : : Instruction : : SHA3 ;
returnType = dynamic_cast < MappingType const & > ( * returnType ) . getValueType ( ) ;
}
}
m_currentLValue = LValue ( m_context , LValue : : STORAGE , * resultType ) ;
unsigned retSizeOnStack = 0 ;
m_currentLValue . retrieveValue ( resultType , Location ( ) , true ) ;
solAssert ( accessorType . getReturnParameterTypes ( ) . size ( ) > = 1 , " " ) ;
sizeOnStack = resultType - > getSizeOnStack ( ) ;
if ( StructType const * structType = dynamic_cast < StructType const * > ( returnType . get ( ) ) )
solAssert ( sizeOnStack < = 15 , " Stack too deep. " ) ;
{
m_context < < eth : : dupInstruction ( sizeOnStack + 1 ) < < eth : : Instruction : : JUMP ;
auto const & names = accessorType . getReturnParameterNames ( ) ;
auto const & types = accessorType . getReturnParameterTypes ( ) ;
// struct
for ( size_t i = 0 ; i < names . size ( ) ; + + i )
{
m_context < < eth : : Instruction : : DUP1
< < structType - > getStorageOffsetOfMember ( names [ i ] )
< < eth : : Instruction : : ADD ;
m_currentLValue = LValue ( m_context , LValue : : LValueType : : Storage , * types [ i ] ) ;
m_currentLValue . retrieveValue ( types [ i ] , Location ( ) , true ) ;
solAssert ( types [ i ] - > getSizeOnStack ( ) = = 1 , " Returning struct elements with stack size != 1 not yet implemented. " ) ;
m_context < < eth : : Instruction : : SWAP1 ;
retSizeOnStack + = types [ i ] - > getSizeOnStack ( ) ;
}
m_context < < eth : : Instruction : : POP ;
}
else
{
// simple value
solAssert ( accessorType . getReturnParameterTypes ( ) . size ( ) = = 1 , " " ) ;
m_currentLValue = LValue ( m_context , LValue : : LValueType : : Storage , * returnType ) ;
m_currentLValue . retrieveValue ( returnType , Location ( ) , true ) ;
retSizeOnStack = returnType - > getSizeOnStack ( ) ;
}
solAssert ( retSizeOnStack < = 15 , " Stack too deep. " ) ;
m_context < < eth : : dupInstruction ( retSizeOnStack + 1 ) < < eth : : Instruction : : JUMP ;
}
}
ExpressionCompiler : : LValue : : LValue ( CompilerContext & _compilerContext , LValueType _type , Type const & _dataType ,
ExpressionCompiler : : LValue : : LValue ( CompilerContext & _compilerContext , LValueType _type , Type const & _dataType ,
@ -903,7 +956,7 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType
{
{
//@todo change the type cast for arrays
//@todo change the type cast for arrays
solAssert ( _dataType . getStorageSize ( ) < = numeric_limits < unsigned > : : max ( ) , " The storage size of " + _dataType . toString ( ) + " should fit in unsigned " ) ;
solAssert ( _dataType . getStorageSize ( ) < = numeric_limits < unsigned > : : max ( ) , " The storage size of " + _dataType . toString ( ) + " should fit in unsigned " ) ;
if ( m_type = = STORAGE )
if ( m_type = = LValueType : : Storage )
m_size = unsigned ( _dataType . getStorageSize ( ) ) ;
m_size = unsigned ( _dataType . getStorageSize ( ) ) ;
else
else
m_size = unsigned ( _dataType . getSizeOnStack ( ) ) ;
m_size = unsigned ( _dataType . getSizeOnStack ( ) ) ;
@ -913,7 +966,7 @@ void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Locatio
{
{
switch ( m_type )
switch ( m_type )
{
{
case STACK :
case LValueType : : Stack :
{
{
unsigned stackPos = m_context - > baseToCurrentStackOffset ( unsigned ( m_baseStackOffset ) ) ;
unsigned stackPos = m_context - > baseToCurrentStackOffset ( unsigned ( m_baseStackOffset ) ) ;
if ( stackPos > = 15 ) //@todo correct this by fetching earlier or moving to memory
if ( stackPos > = 15 ) //@todo correct this by fetching earlier or moving to memory
@ -923,10 +976,10 @@ void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Locatio
* m_context < < eth : : dupInstruction ( stackPos + 1 ) ;
* m_context < < eth : : dupInstruction ( stackPos + 1 ) ;
break ;
break ;
}
}
case STORAGE :
case LValueType : : Storage :
retrieveValueFromStorage ( _type , _remove ) ;
retrieveValueFromStorage ( _type , _remove ) ;
break ;
break ;
case MEMORY :
case LValueType : : Memory :
if ( ! _type - > isValueType ( ) )
if ( ! _type - > isValueType ( ) )
break ; // no distinction between value and reference for non-value types
break ; // no distinction between value and reference for non-value types
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_sourceLocation ( _location )
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_sourceLocation ( _location )
@ -962,7 +1015,7 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool
{
{
switch ( m_type )
switch ( m_type )
{
{
case STACK :
case LValueType : : Stack :
{
{
unsigned stackDiff = m_context - > baseToCurrentStackOffset ( unsigned ( m_baseStackOffset ) ) - m_size + 1 ;
unsigned stackDiff = m_context - > baseToCurrentStackOffset ( unsigned ( m_baseStackOffset ) ) - m_size + 1 ;
if ( stackDiff > 16 )
if ( stackDiff > 16 )
@ -975,7 +1028,7 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool
retrieveValue ( _expression . getType ( ) , _expression . getLocation ( ) ) ;
retrieveValue ( _expression . getType ( ) , _expression . getLocation ( ) ) ;
break ;
break ;
}
}
case LValue : : STORAGE :
case LValueType : : Storage :
if ( ! _expression . getType ( ) - > isValueType ( ) )
if ( ! _expression . getType ( ) - > isValueType ( ) )
break ; // no distinction between value and reference for non-value types
break ; // no distinction between value and reference for non-value types
// stack layout: value value ... value ref
// stack layout: value value ... value ref
@ -1000,7 +1053,7 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool
< < u256 ( 1 ) < < eth : : Instruction : : SWAP1 < < eth : : Instruction : : SUB ;
< < u256 ( 1 ) < < eth : : Instruction : : SWAP1 < < eth : : Instruction : : SUB ;
}
}
break ;
break ;
case LValue : : MEMORY :
case LValueType : : Memory :
if ( ! _expression . getType ( ) - > isValueType ( ) )
if ( ! _expression . getType ( ) - > isValueType ( ) )
break ; // no distinction between value and reference for non-value types
break ; // no distinction between value and reference for non-value types
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_sourceLocation ( _expression . getLocation ( ) )
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_sourceLocation ( _expression . getLocation ( ) )
@ -1017,7 +1070,7 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const
{
{
switch ( m_type )
switch ( m_type )
{
{
case STACK :
case LValueType : : Stack :
{
{
unsigned stackDiff = m_context - > baseToCurrentStackOffset ( unsigned ( m_baseStackOffset ) ) ;
unsigned stackDiff = m_context - > baseToCurrentStackOffset ( unsigned ( m_baseStackOffset ) ) ;
if ( stackDiff > 16 )
if ( stackDiff > 16 )
@ -1029,7 +1082,7 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const
< < eth : : Instruction : : POP ;
< < eth : : Instruction : : POP ;
break ;
break ;
}
}
case LValue : : STORAGE :
case LValueType : : Storage :
if ( m_size = = 0 )
if ( m_size = = 0 )
* m_context < < eth : : Instruction : : POP ;
* m_context < < eth : : Instruction : : POP ;
for ( unsigned i = 0 ; i < m_size ; + + i )
for ( unsigned i = 0 ; i < m_size ; + + i )
@ -1041,7 +1094,7 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression) const
< < u256 ( 1 ) < < eth : : Instruction : : ADD ;
< < u256 ( 1 ) < < eth : : Instruction : : ADD ;
}
}
break ;
break ;
case LValue : : MEMORY :
case LValueType : : Memory :
if ( ! _expression . getType ( ) - > isValueType ( ) )
if ( ! _expression . getType ( ) - > isValueType ( ) )
break ; // no distinction between value and reference for non-value types
break ; // no distinction between value and reference for non-value types
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_sourceLocation ( _expression . getLocation ( ) )
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_sourceLocation ( _expression . getLocation ( ) )
@ -1066,7 +1119,7 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co
void ExpressionCompiler : : LValue : : fromStateVariable ( Declaration const & _varDecl , TypePointer const & _type )
void ExpressionCompiler : : LValue : : fromStateVariable ( Declaration const & _varDecl , TypePointer const & _type )
{
{
m_type = STORAGE ;
m_type = LValueType : : Storage ;
solAssert ( _type - > getStorageSize ( ) < = numeric_limits < unsigned > : : max ( ) , " The storage size of " + _type - > toString ( ) + " should fit in an unsigned " ) ;
solAssert ( _type - > getStorageSize ( ) < = numeric_limits < unsigned > : : max ( ) , " The storage size of " + _type - > toString ( ) + " should fit in an unsigned " ) ;
* m_context < < m_context - > getStorageLocationOfVariable ( _varDecl ) ;
* m_context < < m_context - > getStorageLocationOfVariable ( _varDecl ) ;
m_size = unsigned ( _type - > getStorageSize ( ) ) ;
m_size = unsigned ( _type - > getStorageSize ( ) ) ;
@ -1076,7 +1129,7 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D
{
{
if ( m_context - > isLocalVariable ( & _declaration ) )
if ( m_context - > isLocalVariable ( & _declaration ) )
{
{
m_type = STACK ;
m_type = LValueType : : Stack ;
m_size = _identifier . getType ( ) - > getSizeOnStack ( ) ;
m_size = _identifier . getType ( ) - > getSizeOnStack ( ) ;
m_baseStackOffset = m_context - > getBaseStackOffsetOfVariable ( _declaration ) ;
m_baseStackOffset = m_context - > getBaseStackOffsetOfVariable ( _declaration ) ;
}
}