|
|
@ -532,7 +532,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) |
|
|
|
case Location::SHA3: |
|
|
|
{ |
|
|
|
m_context << u256(0); |
|
|
|
appendArgumentsCopyToMemory(arguments, TypePointers(), function.padArguments()); |
|
|
|
appendArgumentsCopyToMemory(arguments, TypePointers(), function.padArguments(), false, true); |
|
|
|
m_context << u256(0) << eth::Instruction::SHA3; |
|
|
|
break; |
|
|
|
} |
|
|
@ -575,9 +575,15 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) |
|
|
|
solAssert(numIndexed <= 4, "Too many indexed arguments."); |
|
|
|
// Copy all non-indexed arguments to memory (data)
|
|
|
|
m_context << u256(0); |
|
|
|
vector<ASTPointer<Expression const>> nonIndexedArgs; |
|
|
|
TypePointers nonIndexedTypes; |
|
|
|
for (unsigned arg = 0; arg < arguments.size(); ++arg) |
|
|
|
if (!event.getParameters()[arg]->isIndexed()) |
|
|
|
appendExpressionCopyToMemory(*function.getParameterTypes()[arg], *arguments[arg]); |
|
|
|
{ |
|
|
|
nonIndexedArgs.push_back(arguments[arg]); |
|
|
|
nonIndexedTypes.push_back(function.getParameterTypes()[arg]); |
|
|
|
} |
|
|
|
appendArgumentsCopyToMemory(nonIndexedArgs, nonIndexedTypes); |
|
|
|
m_context << u256(0) << eth::logInstruction(numIndexed); |
|
|
|
break; |
|
|
|
} |
|
|
@ -1046,8 +1052,14 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio |
|
|
|
|
|
|
|
// For bare call, activate "4 byte pad exception": If the first argument has exactly 4 bytes,
|
|
|
|
// do not pad it to 32 bytes.
|
|
|
|
appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), |
|
|
|
_functionType.padArguments(), bare); |
|
|
|
// If the function takes arbitrary parameters, copy dynamic length data in place.
|
|
|
|
appendArgumentsCopyToMemory( |
|
|
|
_arguments, |
|
|
|
_functionType.getParameterTypes(), |
|
|
|
_functionType.padArguments(), |
|
|
|
bare, |
|
|
|
_functionType.takesArbitraryParameters() |
|
|
|
); |
|
|
|
|
|
|
|
// CALL arguments: outSize, outOff, inSize, (already present up to here)
|
|
|
|
// inOff, value, addr, gas (stack top)
|
|
|
@ -1089,20 +1101,72 @@ void ExpressionCompiler::appendArgumentsCopyToMemory( |
|
|
|
vector<ASTPointer<Expression const>> const& _arguments, |
|
|
|
TypePointers const& _types, |
|
|
|
bool _padToWordBoundaries, |
|
|
|
bool _padExceptionIfFourBytes |
|
|
|
bool _padExceptionIfFourBytes, |
|
|
|
bool _copyDynamicDataInPlace |
|
|
|
) |
|
|
|
{ |
|
|
|
solAssert(_types.empty() || _types.size() == _arguments.size(), ""); |
|
|
|
TypePointers types = _types; |
|
|
|
if (_types.empty()) |
|
|
|
for (ASTPointer<Expression const> const& argument: _arguments) |
|
|
|
types.push_back(argument->getType()->getRealType()); |
|
|
|
|
|
|
|
vector<size_t> dynamicArguments; |
|
|
|
unsigned stackSizeOfDynamicTypes = 0; |
|
|
|
for (size_t i = 0; i < _arguments.size(); ++i) |
|
|
|
{ |
|
|
|
_arguments[i]->accept(*this); |
|
|
|
TypePointer const& expectedType = _types.empty() ? _arguments[i]->getType()->getRealType() : _types[i]; |
|
|
|
appendTypeConversion(*_arguments[i]->getType(), *expectedType, true); |
|
|
|
TypePointer argType = types[i]->externalType(); |
|
|
|
solAssert(!!argType, "Externalable type expected."); |
|
|
|
if (argType->isValueType()) |
|
|
|
appendTypeConversion(*_arguments[i]->getType(), *argType, true); |
|
|
|
else |
|
|
|
argType = _arguments[i]->getType()->getRealType()->externalType(); |
|
|
|
solAssert(!!argType, "Externalable type expected."); |
|
|
|
bool pad = _padToWordBoundaries; |
|
|
|
// Do not pad if the first argument has exactly four bytes
|
|
|
|
if (i == 0 && pad && _padExceptionIfFourBytes && expectedType->getCalldataEncodedSize(false) == 4) |
|
|
|
if (i == 0 && pad && _padExceptionIfFourBytes && argType->getCalldataEncodedSize(false) == 4) |
|
|
|
pad = false; |
|
|
|
appendTypeMoveToMemory(*expectedType, pad); |
|
|
|
if (!_copyDynamicDataInPlace && argType->isDynamicallySized()) |
|
|
|
{ |
|
|
|
solAssert(argType->getCategory() == Type::Category::Array, "Unknown dynamic type."); |
|
|
|
auto const& arrayType = dynamic_cast<ArrayType const&>(*_arguments[i]->getType()); |
|
|
|
// move memory reference to top of stack
|
|
|
|
CompilerUtils(m_context).moveToStackTop(arrayType.getSizeOnStack()); |
|
|
|
if (arrayType.getLocation() == ArrayType::Location::CallData) |
|
|
|
m_context << eth::Instruction::DUP2; // length is on stack
|
|
|
|
else if (arrayType.getLocation() == ArrayType::Location::Storage) |
|
|
|
m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD; |
|
|
|
else |
|
|
|
{ |
|
|
|
solAssert(arrayType.getLocation() == ArrayType::Location::Memory, ""); |
|
|
|
m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD; |
|
|
|
} |
|
|
|
appendTypeMoveToMemory(IntegerType(256), true); |
|
|
|
stackSizeOfDynamicTypes += arrayType.getSizeOnStack(); |
|
|
|
dynamicArguments.push_back(i); |
|
|
|
} |
|
|
|
else |
|
|
|
appendTypeMoveToMemory(*argType, pad); |
|
|
|
} |
|
|
|
|
|
|
|
// copy dynamic values to memory
|
|
|
|
unsigned dynStackPointer = stackSizeOfDynamicTypes; |
|
|
|
// stack layout: <dyn arg 1> ... <dyn arg m> <memory pointer>
|
|
|
|
for (size_t i: dynamicArguments) |
|
|
|
{ |
|
|
|
auto const& arrayType = dynamic_cast<ArrayType const&>(*_arguments[i]->getType()); |
|
|
|
CompilerUtils(m_context).copyToStackTop(1 + dynStackPointer, arrayType.getSizeOnStack()); |
|
|
|
dynStackPointer -= arrayType.getSizeOnStack(); |
|
|
|
appendTypeMoveToMemory(arrayType, true); |
|
|
|
} |
|
|
|
solAssert(dynStackPointer == 0, ""); |
|
|
|
|
|
|
|
// remove dynamic values (and retain memory pointer)
|
|
|
|
if (stackSizeOfDynamicTypes > 0) |
|
|
|
{ |
|
|
|
m_context << eth::swapInstruction(stackSizeOfDynamicTypes); |
|
|
|
CompilerUtils(m_context).popStackSlots(stackSizeOfDynamicTypes); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -1114,8 +1178,13 @@ void ExpressionCompiler::appendTypeMoveToMemory(Type const& _type, bool _padToWo |
|
|
|
void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression) |
|
|
|
{ |
|
|
|
_expression.accept(*this); |
|
|
|
appendTypeConversion(*_expression.getType(), _expectedType, true); |
|
|
|
appendTypeMoveToMemory(_expectedType); |
|
|
|
if (_expectedType.isValueType()) |
|
|
|
{ |
|
|
|
appendTypeConversion(*_expression.getType(), _expectedType, true); |
|
|
|
appendTypeMoveToMemory(_expectedType); |
|
|
|
} |
|
|
|
else |
|
|
|
appendTypeMoveToMemory(*_expression.getType()->getRealType()); |
|
|
|
} |
|
|
|
|
|
|
|
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) |
|
|
|