@ -41,11 +41,11 @@ void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression
_expression . accept ( compiler ) ;
_expression . accept ( compiler ) ;
}
}
void ExpressionCompiler : : appendTypeConversion ( CompilerContext & _context ,
void ExpressionCompiler : : appendTypeConversion ( CompilerContext & _context , Type const & _typeOnStack ,
Type const & _typeOnStack , Type const & _targetType )
Type const & _targetType , bool _cleanupNeeded )
{
{
ExpressionCompiler compiler ( _context ) ;
ExpressionCompiler compiler ( _context ) ;
compiler . appendTypeConversion ( _typeOnStack , _targetType ) ;
compiler . appendTypeConversion ( _typeOnStack , _targetType , _cleanupNeeded ) ;
}
}
bool ExpressionCompiler : : visit ( Assignment const & _assignment )
bool ExpressionCompiler : : visit ( Assignment const & _assignment )
@ -71,12 +71,20 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
return false ;
return false ;
}
}
void ExpressionCompiler : : endV isit( UnaryOperation const & _unaryOperation )
bool ExpressionCompiler : : v isit( UnaryOperation const & _unaryOperation )
{
{
//@todo type checking and creating code for an operator should be in the same place:
//@todo type checking and creating code for an operator should be in the same place:
// 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 )
{
m_context < < _unaryOperation . getType ( ) - > literalValue ( nullptr ) ;
return false ;
}
_unaryOperation . getSubExpression ( ) . accept ( * this ) ;
switch ( _unaryOperation . getOperator ( ) )
switch ( _unaryOperation . getOperator ( ) )
{
{
case Token : : NOT : // !
case Token : : NOT : // !
@ -128,6 +136,7 @@ void ExpressionCompiler::endVisit(UnaryOperation const& _unaryOperation)
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Invalid unary operator: " +
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Invalid unary operator: " +
string ( Token : : toString ( _unaryOperation . getOperator ( ) ) ) ) ) ;
string ( Token : : toString ( _unaryOperation . getOperator ( ) ) ) ) ) ;
}
}
return false ;
}
}
bool ExpressionCompiler : : visit ( BinaryOperation const & _binaryOperation )
bool ExpressionCompiler : : visit ( BinaryOperation const & _binaryOperation )
@ -135,21 +144,23 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
Expression const & leftExpression = _binaryOperation . getLeftExpression ( ) ;
Expression const & leftExpression = _binaryOperation . getLeftExpression ( ) ;
Expression const & rightExpression = _binaryOperation . getRightExpression ( ) ;
Expression const & rightExpression = _binaryOperation . getRightExpression ( ) ;
Type const & commonType = _binaryOperation . getCommonType ( ) ;
Type const & commonType = _binaryOperation . getCommonType ( ) ;
Token : : Value const op = _binaryOperation . getOperator ( ) ;
Token : : Value const c_ op = _binaryOperation . getOperator ( ) ;
if ( op = = Token : : AND | | 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 )
m_context < < commonType . literalValue ( nullptr ) ;
else
else
{
{
bool cleanupNeeded = false ;
bool cleanupNeeded = commonType . getCategory ( ) = = Type : : Category : : INTEGER & &
if ( commonType . getCategory ( ) = = Type : : Category : : INTEGER )
( Token : : isCompareOp ( c_op ) | | c_op = = Token : : DIV | | c_op = = Token : : MOD ) ;
if ( Token : : isCompareOp ( op ) | | op = = Token : : DIV | | op = = Token : : MOD )
cleanupNeeded = true ;
// 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
//@todo this has to be extended for literal expressions
auto isLiteral = [ ] ( Expression const & _e )
bool swap = ( m_optimize & & Token : : isCommutativeOp ( op ) & & dynamic_cast < Literal const * > ( & rightExpression )
{
& & ! dynamic_cast < Literal const * > ( & leftExpression ) ) ;
return dynamic_cast < Literal const * > ( & _e ) | | _e . getType ( ) - > getCategory ( ) = = Type : : Category : : INTEGER_CONSTANT ;
} ;
bool swap = m_optimize & & Token : : isCommutativeOp ( c_op ) & & isLiteral ( rightExpression ) & & ! isLiteral ( leftExpression ) ;
if ( swap )
if ( swap )
{
{
leftExpression . accept ( * this ) ;
leftExpression . accept ( * this ) ;
@ -164,10 +175,10 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
leftExpression . accept ( * this ) ;
leftExpression . accept ( * this ) ;
appendTypeConversion ( * leftExpression . getType ( ) , commonType , cleanupNeeded ) ;
appendTypeConversion ( * leftExpression . getType ( ) , commonType , cleanupNeeded ) ;
}
}
if ( Token : : isCompareOp ( op ) )
if ( Token : : isCompareOp ( c_ op) )
appendCompareOperatorCode ( op , commonType ) ;
appendCompareOperatorCode ( c_ op, commonType ) ;
else
else
appendOrdinaryBinaryOperatorCode ( op , commonType ) ;
appendOrdinaryBinaryOperatorCode ( c_ op, commonType ) ;
}
}
// do not visit the child nodes, we already did that explicitly
// do not visit the child nodes, we already did that explicitly
@ -183,13 +194,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
solAssert ( _functionCall . getArguments ( ) . size ( ) = = 1 , " " ) ;
solAssert ( _functionCall . getArguments ( ) . size ( ) = = 1 , " " ) ;
Expression const & firstArgument = * _functionCall . getArguments ( ) . front ( ) ;
Expression const & firstArgument = * _functionCall . getArguments ( ) . front ( ) ;
firstArgument . accept ( * this ) ;
firstArgument . accept ( * this ) ;
if ( firstArgument . getType ( ) - > getCategory ( ) = = Type : : Category : : CONTRACT & &
appendTypeConversion ( * firstArgument . getType ( ) , * _functionCall . getType ( ) ) ;
_functionCall . getType ( ) - > getCategory ( ) = = Type : : Category : : INTEGER )
{
// explicit type conversion contract -> address, nothing to do.
}
else
appendTypeConversion ( * firstArgument . getType ( ) , * _functionCall . getType ( ) ) ;
}
}
else
else
{
{
@ -239,13 +244,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
FunctionCallOptions options ;
FunctionCallOptions options ;
options . bare = true ;
options . bare = true ;
options . obtainAddress = [ & ] ( ) { _functionCall . getExpression ( ) . accept ( * this ) ; } ;
options . obtainAddress = [ & ] ( ) { _functionCall . getExpression ( ) . accept ( * this ) ; } ;
options . obtainValue = [ & ] ( ) { arguments . front ( ) - > accept ( * this ) ; } ;
options . obtainValue = [ & ] ( )
appendExternalFunctionCall ( FunctionType ( { } , { } , Location : : EXTERNAL ) , { } , options ) ;
{
arguments . front ( ) - > accept ( * this ) ;
appendTypeConversion ( * arguments . front ( ) - > getType ( ) ,
* function . getParameterTypes ( ) . front ( ) , true ) ;
} ;
appendExternalFunctionCall ( FunctionType ( TypePointers { } , TypePointers { } , Location : : EXTERNAL ) , { } , options ) ;
break ;
break ;
}
}
case Location : : SUICIDE :
case Location : : SUICIDE :
arguments . front ( ) - > accept ( * this ) ;
arguments . front ( ) - > accept ( * this ) ;
//@todo might not be necessary
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 ;
@ -256,6 +265,23 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
CompilerUtils ( m_context ) . storeInMemory ( 0 ) ;
CompilerUtils ( m_context ) . storeInMemory ( 0 ) ;
m_context < < u256 ( 32 ) < < u256 ( 0 ) < < eth : : Instruction : : SHA3 ;
m_context < < u256 ( 32 ) < < u256 ( 0 ) < < eth : : Instruction : : SHA3 ;
break ;
break ;
case Location : : LOG0 :
case Location : : LOG1 :
case Location : : LOG2 :
case Location : : LOG3 :
case Location : : LOG4 :
{
unsigned logNumber = int ( function . getLocation ( ) ) - int ( Location : : LOG0 ) ;
for ( int arg = logNumber ; arg > = 0 ; - - arg )
{
arguments [ arg ] - > accept ( * this ) ;
appendTypeConversion ( * arguments [ arg ] - > getType ( ) , * function . getParameterTypes ( ) [ arg ] , true ) ;
}
// @todo move this once we actually use memory
CompilerUtils ( m_context ) . storeInMemory ( 0 ) ;
m_context < < u256 ( 32 ) < < u256 ( 0 ) < < eth : : logInstruction ( logNumber ) ;
break ;
}
case Location : : ECRECOVER :
case Location : : ECRECOVER :
case Location : : SHA256 :
case Location : : SHA256 :
case Location : : RIPEMD160 :
case Location : : RIPEMD160 :
@ -267,7 +293,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
FunctionCallOptions options ;
FunctionCallOptions options ;
options . bare = true ;
options . bare = true ;
options . obtainAddress = [ & ] ( ) { m_context < < contractAddress ; } ;
options . obtainAddress = [ & ] ( ) { m_context < < contractAddress ; } ;
options . packDensely = false ;
appendExternalFunctionCall ( function , arguments , options ) ;
appendExternalFunctionCall ( function , arguments , options ) ;
break ;
break ;
}
}
@ -299,15 +324,16 @@ bool ExpressionCompiler::visit(NewExpression const& _newExpression)
for ( unsigned i = 0 ; i < arguments . size ( ) ; + + i )
for ( unsigned i = 0 ; i < arguments . size ( ) ; + + i )
{
{
arguments [ i ] - > accept ( * this ) ;
arguments [ i ] - > accept ( * this ) ;
appendTypeConversion ( * arguments [ i ] - > getType ( ) , * types [ i ] ) ;
appendTypeConversion ( * arguments [ i ] - > getType ( ) , * types [ i ] , true ) ;
unsigned const numBytes = types [ i ] - > getCalldataEncodedSize ( ) ;
unsigned const c_ numBytes = types [ i ] - > getCalldataEncodedSize ( ) ;
if ( numBytes > 32 )
if ( c_ numBytes > 32 )
BOOST_THROW_EXCEPTION ( CompilerError ( )
BOOST_THROW_EXCEPTION ( CompilerError ( )
< < errinfo_sourceLocation ( arguments [ i ] - > getLocation ( ) )
< < errinfo_sourceLocation ( arguments [ i ] - > getLocation ( ) )
< < errinfo_comment ( " Type " + types [ i ] - > toString ( ) + " not yet supported. " ) ) ;
< < errinfo_comment ( " Type " + types [ i ] - > toString ( ) + " not yet supported. " ) ) ;
bool const leftAligned = types [ i ] - > getCategory ( ) = = Type : : Category : : STRING ;
bool const c_leftAligned = types [ i ] - > getCategory ( ) = = Type : : Category : : STRING ;
CompilerUtils ( m_context ) . storeInMemory ( dataOffset , numBytes , leftAligned ) ;
bool const c_padToWords = true ;
dataOffset + = numBytes ;
dataOffset + = CompilerUtils ( m_context ) . storeInMemory ( dataOffset , c_numBytes ,
c_leftAligned , c_padToWords ) ;
}
}
// size, offset, endowment
// size, offset, endowment
m_context < < u256 ( dataOffset ) < < u256 ( 0 ) < < u256 ( 0 ) < < eth : : Instruction : : CREATE ;
m_context < < u256 ( dataOffset ) < < u256 ( 0 ) < < u256 ( 0 ) < < eth : : Instruction : : CREATE ;
@ -319,6 +345,18 @@ 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 :
{
ContractType const & type = dynamic_cast < ContractType const & > ( * _memberAccess . getExpression ( ) . getType ( ) ) ;
u256 identifier = type . getFunctionIdentifier ( member ) ;
if ( identifier ! = Invalid256 )
{
appendTypeConversion ( type , IntegerType ( 0 , IntegerType : : Modifier : : ADDRESS ) , true ) ;
m_context < < identifier ;
break ;
}
// fall-through to "integer" otherwise (address)
}
case Type : : Category : : INTEGER :
case Type : : Category : : INTEGER :
if ( member = = " balance " )
if ( member = = " balance " )
{
{
@ -332,12 +370,6 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
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 : : CONTRACT :
{
ContractType const & type = dynamic_cast < ContractType const & > ( * _memberAccess . getExpression ( ) . getType ( ) ) ;
m_context < < type . getFunctionIndex ( member ) ;
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 " )
@ -423,10 +455,10 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
{
{
switch ( _literal . getType ( ) - > getCategory ( ) )
switch ( _literal . getType ( ) - > getCategory ( ) )
{
{
case Type : : Category : : INTEGER :
case Type : : Category : : INTEGER_CONSTANT :
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 :
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Only integer, boolean and string literals implemented for now. " ) ) ;
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Only integer, boolean and string literals implemented for now. " ) ) ;
@ -435,12 +467,12 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
void ExpressionCompiler : : appendAndOrOperatorCode ( BinaryOperation const & _binaryOperation )
void ExpressionCompiler : : appendAndOrOperatorCode ( BinaryOperation const & _binaryOperation )
{
{
Token : : Value const op = _binaryOperation . getOperator ( ) ;
Token : : Value const c_ op = _binaryOperation . getOperator ( ) ;
solAssert ( op = = Token : : OR | | 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 ( 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 ;
@ -459,23 +491,23 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
else
else
{
{
IntegerType const & type = dynamic_cast < IntegerType const & > ( _type ) ;
IntegerType const & type = dynamic_cast < IntegerType const & > ( _type ) ;
bool const isSigned = type . isSigned ( ) ;
bool const c_ isSigned = type . isSigned ( ) ;
switch ( _operator )
switch ( _operator )
{
{
case Token : : GTE :
case Token : : GTE :
m_context < < ( 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 : : LTE :
m_context < < ( 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 : : GT :
m_context < < ( isSigned ? eth : : Instruction : : SGT : eth : : Instruction : : GT ) ;
m_context < < ( c_ isSigned ? eth : : Instruction : : SGT : eth : : Instruction : : GT ) ;
break ;
break ;
case Token : : LT :
case Token : : LT :
m_context < < ( isSigned ? eth : : Instruction : : SLT : eth : : Instruction : : LT ) ;
m_context < < ( c_ isSigned ? eth : : Instruction : : SLT : eth : : Instruction : : LT ) ;
break ;
break ;
default :
default :
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Unknown comparison operator. " ) ) ;
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Unknown comparison operator. " ) ) ;
@ -498,7 +530,7 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator
void ExpressionCompiler : : appendArithmeticOperatorCode ( Token : : Value _operator , Type const & _type )
void ExpressionCompiler : : appendArithmeticOperatorCode ( Token : : Value _operator , Type const & _type )
{
{
IntegerType const & type = dynamic_cast < IntegerType const & > ( _type ) ;
IntegerType const & type = dynamic_cast < IntegerType const & > ( _type ) ;
bool const isSigned = type . isSigned ( ) ;
bool const c_ isSigned = type . isSigned ( ) ;
switch ( _operator )
switch ( _operator )
{
{
@ -512,10 +544,10 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
m_context < < eth : : Instruction : : MUL ;
m_context < < eth : : Instruction : : MUL ;
break ;
break ;
case Token : : DIV :
case Token : : DIV :
m_context < < ( 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 < < ( isSigned ? eth : : Instruction : : SMOD : eth : : Instruction : : MOD ) ;
m_context < < ( c_ isSigned ? eth : : Instruction : : SMOD : eth : : Instruction : : MOD ) ;
break ;
break ;
default :
default :
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Unknown arithmetic operator. " ) ) ;
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Unknown arithmetic operator. " ) ) ;
@ -562,10 +594,38 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
if ( _typeOnStack = = _targetType & & ! _cleanupNeeded )
if ( _typeOnStack = = _targetType & & ! _cleanupNeeded )
return ;
return ;
if ( _typeOnStack . getCategory ( ) = = Type : : Category : : INTEGER )
Type : : Category stackTypeCategory = _typeOnStack . getCategory ( ) ;
appendHighBitsCleanup ( dynamic_cast < IntegerType const & > ( _typeOnStack ) ) ;
Type : : Category targetTypeCategory = _targetType . getCategory ( ) ;
else if ( _typeOnStack . getCategory ( ) = = Type : : Category : : STRING )
if ( stackTypeCategory = = Type : : Category : : INTEGER | | stackTypeCategory = = Type : : Category : : CONTRACT | |
stackTypeCategory = = Type : : Category : : INTEGER_CONSTANT )
{
solAssert ( targetTypeCategory = = Type : : Category : : INTEGER | | targetTypeCategory = = Type : : Category : : CONTRACT , " " ) ;
IntegerType addressType ( 0 , IntegerType : : Modifier : : ADDRESS ) ;
IntegerType const & targetType = targetTypeCategory = = Type : : Category : : INTEGER
? dynamic_cast < IntegerType const & > ( _targetType ) : addressType ;
if ( stackTypeCategory = = Type : : Category : : INTEGER_CONSTANT )
{
IntegerConstantType const & constType = dynamic_cast < IntegerConstantType const & > ( _typeOnStack ) ;
// We know that the stack is clean, we only have to clean for a narrowing conversion
// where cleanup is forced.
if ( targetType . getNumBits ( ) < constType . getIntegerType ( ) - > getNumBits ( ) & & _cleanupNeeded )
appendHighBitsCleanup ( targetType ) ;
}
else
{
IntegerType const & typeOnStack = stackTypeCategory = = Type : : Category : : INTEGER
? dynamic_cast < IntegerType const & > ( _typeOnStack ) : addressType ;
// Widening: clean up according to source type width
// Non-widening and force: clean up according to target type bits
if ( targetType . getNumBits ( ) > typeOnStack . getNumBits ( ) )
appendHighBitsCleanup ( typeOnStack ) ;
else if ( _cleanupNeeded )
appendHighBitsCleanup ( targetType ) ;
}
}
else if ( stackTypeCategory = = Type : : Category : : STRING )
{
{
solAssert ( targetTypeCategory = = Type : : Category : : STRING , " " ) ;
// nothing to do, strings are high-order-bit-aligned
// nothing to do, strings are high-order-bit-aligned
//@todo clear lower-order bytes if we allow explicit conversion to shorter strings
//@todo clear lower-order bytes if we allow explicit conversion to shorter strings
}
}
@ -590,43 +650,47 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
{
{
solAssert ( _arguments . size ( ) = = _functionType . getParameterTypes ( ) . size ( ) , " " ) ;
solAssert ( _arguments . size ( ) = = _functionType . getParameterTypes ( ) . size ( ) , " " ) ;
unsigned dataOffset = _options . bare ? 0 : 1 ; // reserve one byte for the function index
_options . obtainAddress ( ) ;
if ( ! _options . bare )
CompilerUtils ( m_context ) . storeInMemory ( 0 , CompilerUtils : : dataStartOffset ) ;
unsigned dataOffset = _options . bare ? 0 : CompilerUtils : : dataStartOffset ; // reserve 4 bytes for the function's hash identifier
for ( unsigned i = 0 ; i < _arguments . size ( ) ; + + i )
for ( unsigned i = 0 ; i < _arguments . size ( ) ; + + i )
{
{
_arguments [ i ] - > accept ( * this ) ;
_arguments [ i ] - > accept ( * this ) ;
Type const & type = * _functionType . getParameterTypes ( ) [ i ] ;
Type const & type = * _functionType . getParameterTypes ( ) [ i ] ;
appendTypeConversion ( * _arguments [ i ] - > getType ( ) , type ) ;
appendTypeConversion ( * _arguments [ i ] - > getType ( ) , type , true ) ;
unsigned const numBytes = _options . packDensely ? type . getCalldataEncodedSize ( ) : 32 ;
unsigned const c_ numBytes = type . getCalldataEncodedSize ( ) ;
if ( numBytes = = 0 | | numBytes > 32 )
if ( c_ numBytes = = 0 | | c_ numBytes > 32 )
BOOST_THROW_EXCEPTION ( CompilerError ( )
BOOST_THROW_EXCEPTION ( CompilerError ( )
< < errinfo_sourceLocation ( _arguments [ i ] - > getLocation ( ) )
< < errinfo_sourceLocation ( _arguments [ i ] - > getLocation ( ) )
< < errinfo_comment ( " Type " + type . toString ( ) + " not yet supported. " ) ) ;
< < errinfo_comment ( " Type " + type . toString ( ) + " not yet supported. " ) ) ;
bool const leftAligned = type . getCategory ( ) = = Type : : Category : : STRING ;
bool const c_leftAligned = type . getCategory ( ) = = Type : : Category : : STRING ;
CompilerUtils ( m_context ) . storeInMemory ( dataOffset , numBytes , leftAligned ) ;
bool const c_padToWords = true ;
dataOffset + = numBytes ;
dataOffset + = CompilerUtils ( m_context ) . storeInMemory ( dataOffset , c_numBytes ,
c_leftAligned , c_padToWords ) ;
}
}
//@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 :
_functionType . getReturnParameterTypes ( ) . front ( ) . get ( ) ;
_functionType . getReturnParameterTypes ( ) . front ( ) . get ( ) ;
unsigned retSize = firstType ? firstType - > getCalldataEncodedSize ( ) : 0 ;
unsigned retSize = firstType ? CompilerUtils : : getPaddedSize ( firstType - > getCalldataEncodedSize ( ) ) : 0 ;
if ( ! _options . packDensely & & retSize > 0 )
retSize = 32 ;
// CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top)
// CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top)
m_context < < u256 ( retSize ) < < u256 ( 0 ) < < u256 ( dataOffset ) < < u256 ( 0 ) ;
m_context < < u256 ( retSize ) < < u256 ( 0 ) < < u256 ( dataOffset ) < < u256 ( 0 ) ;
if ( _options . obtainValue )
if ( _options . obtainValue )
_options . obtainValue ( ) ;
_options . obtainValue ( ) ;
else
else
m_context < < u256 ( 0 ) ;
m_context < < u256 ( 0 ) ;
_options . obtainAddress ( ) ;
m_context < < eth : : dupInstruction ( 6 ) ; //copy contract address
if ( ! _options . bare )
m_context < < u256 ( 0 ) < < eth : : Instruction : : MSTORE8 ;
m_context < < u256 ( 25 ) < < eth : : Instruction : : GAS < < eth : : Instruction : : SUB
m_context < < u256 ( 25 ) < < eth : : Instruction : : GAS < < eth : : Instruction : : SUB
< < eth : : Instruction : : CALL
< < eth : : Instruction : : CALL
< < eth : : Instruction : : POP ; // @todo do not ignore failure indicator
< < eth : : Instruction : : POP // @todo do not ignore failure indicator
< < eth : : Instruction : : POP ; // pop contract address
if ( retSize > 0 )
if ( retSize > 0 )
{
{
bool const leftAligned = firstType - > getCategory ( ) = = Type : : Category : : STRING ;
bool const c_ leftAligned = firstType - > getCategory ( ) = = Type : : Category : : STRING ;
CompilerUtils ( m_context ) . loadFromMemory ( 0 , retSize , leftAligned ) ;
CompilerUtils ( m_context ) . loadFromMemory ( 0 , retSize , c_ leftAligned, false , true ) ;
}
}
}
}