bytes parameters for events and sha3.

This commit is contained in:
chriseth
2015-04-22 11:43:49 +02:00
parent a44bcb6909
commit a6d08950c6
7 changed files with 111 additions and 30 deletions
+80 -11
View File
@@ -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)