aboutsummaryrefslogtreecommitdiffstats
path: root/ExpressionCompiler.cpp
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-04-21 16:59:48 +0800
committerchriseth <c@ethdev.com>2015-04-22 17:43:49 +0800
commita6d08950c6a81de3698ea8be01d2d5c472fe41e6 (patch)
treef1c74eb23c8e8cf351d08ea9c07682d78db1b0b5 /ExpressionCompiler.cpp
parenta44bcb6909478543151cac871fdbbc4909ad54aa (diff)
downloaddexon-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.cpp91
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)