diff options
author | chriseth <c@ethdev.com> | 2015-04-21 16:59:48 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-04-22 17:43:49 +0800 |
commit | a6d08950c6a81de3698ea8be01d2d5c472fe41e6 (patch) | |
tree | f1c74eb23c8e8cf351d08ea9c07682d78db1b0b5 /ExpressionCompiler.cpp | |
parent | a44bcb6909478543151cac871fdbbc4909ad54aa (diff) | |
download | dexon-solidity-a6d08950c6a81de3698ea8be01d2d5c472fe41e6.tar.gz dexon-solidity-a6d08950c6a81de3698ea8be01d2d5c472fe41e6.tar.zst dexon-solidity-a6d08950c6a81de3698ea8be01d2d5c472fe41e6.zip |
bytes parameters for events and sha3.
Diffstat (limited to 'ExpressionCompiler.cpp')
-rw-r--r-- | ExpressionCompiler.cpp | 91 |
1 files changed, 80 insertions, 11 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index cf6a01ec..a11c9944 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -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) |