diff options
author | Christian <c@ethdev.com> | 2015-02-10 17:45:57 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2015-02-10 17:59:23 +0800 |
commit | cf4144b70246b53589b3238213f688244485f9b0 (patch) | |
tree | deb3cb5c3b8c8ebd3424338c727a1af6e84309cf /ExpressionCompiler.cpp | |
parent | bb6f181d7dacfd1d7a070483500937004bea995c (diff) | |
download | dexon-solidity-cf4144b70246b53589b3238213f688244485f9b0.tar.gz dexon-solidity-cf4144b70246b53589b3238213f688244485f9b0.tar.zst dexon-solidity-cf4144b70246b53589b3238213f688244485f9b0.zip |
Arbitrary parameters for call() and all hash functions.
Diffstat (limited to 'ExpressionCompiler.cpp')
-rw-r--r-- | ExpressionCompiler.cpp | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index f649f1a4..1d3f23e6 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -206,7 +206,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) TypePointers const& parameterTypes = function.getParameterTypes(); vector<ASTPointer<Expression const>> const& callArguments = _functionCall.getArguments(); vector<ASTPointer<ASTString>> const& callArgumentNames = _functionCall.getNames(); - if (function.getLocation() != Location::SHA3) + if (!function.takesArbitraryParameters()) solAssert(callArguments.size() == parameterTypes.size(), ""); vector<ASTPointer<Expression const>> arguments; @@ -318,7 +318,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); appendExternalFunctionCall(FunctionType(TypePointers{}, TypePointers{}, - Location::External, true, true), {}, true); + Location::External, false, true, true), {}, true); break; case Location::Suicide: arguments.front()->accept(*this); @@ -327,7 +327,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; case Location::SHA3: { - unsigned length = appendArgumentsCopyToMemory(arguments, TypePointers(), 0, false); + unsigned length = appendArgumentsCopyToMemory(arguments, TypePointers(), 0, function.padArguments()); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; break; } @@ -700,21 +700,30 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con if (stackTypeCategory == Type::Category::String) { + 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 // only to shift right because of opposite alignment 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.getNumBits() == typeOnStack.getNumBytes() * 8, "The size should be the same."); m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV; } else { + // clear lower-order bytes for conversion to shorter strings - we always clean solAssert(targetTypeCategory == Type::Category::String, "Invalid type conversion requested."); - // nothing to do, strings are high-order-bit-aligned - //@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 || @@ -776,7 +785,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio vector<ASTPointer<Expression const>> const& _arguments, bool bare) { - solAssert(_arguments.size() == _functionType.getParameterTypes().size(), ""); + solAssert(_functionType.takesArbitraryParameters() || + _arguments.size() == _functionType.getParameterTypes().size(), ""); // Assumed stack content here: // <stack top> @@ -800,7 +810,10 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // reserve space for the function identifier unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; - dataOffset += appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), 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 Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : @@ -839,7 +852,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expression const>> const& _arguments, TypePointers const& _types, unsigned _memoryOffset, - bool _padToWordBoundaries) + bool _padToWordBoundaries, + bool _padExceptionIfFourBytes) { solAssert(_types.empty() || _types.size() == _arguments.size(), ""); unsigned length = 0; @@ -848,8 +862,12 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector<ASTPointer<Expre _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, _padToWordBoundaries); + _memoryOffset + length, pad); } return length; } |