Code generation for events.

This commit is contained in:
Christian 2015-01-29 16:42:59 +01:00
parent 4a6ed84386
commit 4e72a77546
3 changed files with 66 additions and 31 deletions

1
AST.h
View File

@ -404,7 +404,6 @@ public:
bool isStateVariable() const { return m_isStateVariable; } bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; } bool isIndexed() const { return m_isIndexed; }
private: private:
ASTPointer<TypeName> m_typeName; ///< can be empty ("var") ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
bool m_isPublic; ///< Whether there is an accessor for it or not bool m_isPublic; ///< Whether there is an accessor for it or not

View File

@ -23,6 +23,7 @@
#include <utility> #include <utility>
#include <numeric> #include <numeric>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcrypto/SHA3.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/ExpressionCompiler.h> #include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/CompilerContext.h> #include <libsolidity/CompilerContext.h>
@ -304,10 +305,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << eth::Instruction::SUICIDE; m_context << eth::Instruction::SUICIDE;
break; break;
case Location::SHA3: case Location::SHA3:
arguments.front()->accept(*this); appendExpressionCopyToMemory(*function.getParameterTypes().front(), *arguments.front());
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true);
// @todo move this once we actually use memory
CompilerUtils(m_context).storeInMemory(0);
m_context << u256(32) << u256(0) << eth::Instruction::SHA3; m_context << u256(32) << u256(0) << eth::Instruction::SHA3;
break; break;
case Location::LOG0: case Location::LOG0:
@ -317,14 +315,41 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case Location::LOG4: case Location::LOG4:
{ {
unsigned logNumber = int(function.getLocation()) - int(Location::LOG0); unsigned logNumber = int(function.getLocation()) - int(Location::LOG0);
for (int arg = logNumber; arg >= 0; --arg) for (unsigned arg = logNumber; arg > 0; --arg)
{ {
arguments[arg]->accept(*this); arguments[arg]->accept(*this);
appendTypeConversion(*arguments[arg]->getType(), *function.getParameterTypes()[arg], true); appendTypeConversion(*arguments[arg]->getType(), *function.getParameterTypes()[arg], true);
} }
// @todo move this once we actually use memory unsigned length = appendExpressionCopyToMemory(*function.getParameterTypes().front(),
CompilerUtils(m_context).storeInMemory(0); *arguments.front());
m_context << u256(32) << u256(0) << eth::logInstruction(logNumber); solAssert(length == 32, "Log data should have length 32.");
m_context << u256(length) << u256(0) << eth::logInstruction(logNumber);
break;
}
case Location::EVENT:
{
_functionCall.getExpression().accept(*this);
auto const& event = dynamic_cast<EventDefinition const&>(function.getDeclaration());
// Copy all non-indexed arguments to memory (data)
unsigned numIndexed = 0;
unsigned memLength = 0;
for (unsigned arg = 0; arg < arguments.size(); ++arg)
if (!event.getParameters()[arg]->isIndexed())
memLength += appendExpressionCopyToMemory(*function.getParameterTypes()[arg],
*arguments[arg], memLength);
// All indexed arguments go to the stack
for (unsigned arg = arguments.size(); arg > 0; --arg)
if (event.getParameters()[arg - 1]->isIndexed())
{
++numIndexed;
arguments[arg - 1]->accept(*this);
appendTypeConversion(*arguments[arg - 1]->getType(),
*function.getParameterTypes()[arg - 1], true);
}
m_context << u256(h256::Arith(dev::sha3(function.getCanonicalSignature(event.getName()))));
++numIndexed;
solAssert(numIndexed <= 4, "Too many indexed arguments.");
m_context << u256(memLength) << u256(0) << eth::logInstruction(numIndexed);
break; break;
} }
case Location::BLOCKHASH: case Location::BLOCKHASH:
@ -459,14 +484,13 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
{ {
_indexAccess.getBaseExpression().accept(*this); _indexAccess.getBaseExpression().accept(*this);
_indexAccess.getIndexExpression().accept(*this);
appendTypeConversion(*_indexAccess.getIndexExpression().getType(), TypePointer const& keyType = dynamic_cast<MappingType const&>(*_indexAccess.getBaseExpression().getType()).getKeyType();
*dynamic_cast<MappingType const&>(*_indexAccess.getBaseExpression().getType()).getKeyType(), unsigned length = appendExpressionCopyToMemory(*keyType, _indexAccess.getIndexExpression());
true); solAssert(length == 32, "Mapping key length in memory has to be 32.");
// @todo move this once we actually use memory // @todo move this once we actually use memory
CompilerUtils(m_context).storeInMemory(0); length += CompilerUtils(m_context).storeInMemory(length);
CompilerUtils(m_context).storeInMemory(32); m_context << u256(length) << u256(0) << eth::Instruction::SHA3;
m_context << u256(64) << u256(0) << eth::Instruction::SHA3;
m_currentLValue = LValue(m_context, LValue::STORAGE, *_indexAccess.getType()); m_currentLValue = LValue(m_context, LValue::STORAGE, *_indexAccess.getType());
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
@ -495,6 +519,10 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
{ {
// no-op // no-op
} }
else if (dynamic_cast<EventDefinition const*>(declaration))
{
// no-op
}
else else
{ {
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context."));
@ -791,20 +819,23 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ
{ {
unsigned length = 0; unsigned length = 0;
for (unsigned i = 0; i < _arguments.size(); ++i) for (unsigned i = 0; i < _arguments.size(); ++i)
{ length += appendExpressionCopyToMemory(*_types[i], *_arguments[i], _memoryOffset + length);
_arguments[i]->accept(*this); return length;
appendTypeConversion(*_arguments[i]->getType(), *_types[i], true); }
unsigned const c_numBytes = _types[i]->getCalldataEncodedSize();
unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
Expression const& _expression, unsigned _memoryOffset)
{
_expression.accept(*this);
appendTypeConversion(*_expression.getType(), _expectedType, true);
unsigned const c_numBytes = _expectedType.getCalldataEncodedSize();
if (c_numBytes == 0 || c_numBytes > 32) if (c_numBytes == 0 || c_numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(_arguments[i]->getLocation()) << errinfo_sourceLocation(_expression.getLocation())
<< errinfo_comment("Type " + _types[i]->toString() + " not yet supported.")); << errinfo_comment("Type " + _expectedType.toString() + " not yet supported."));
bool const c_leftAligned = _types[i]->getCategory() == Type::Category::STRING; bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING;
bool const c_padToWords = true; bool const c_padToWords = true;
length += CompilerUtils(m_context).storeInMemory(_memoryOffset + length, c_numBytes, return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords);
c_leftAligned, c_padToWords);
}
return length;
} }
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)

View File

@ -94,7 +94,12 @@ private:
bool bare = false); bool bare = false);
/// Appends code that copies the given arguments to memory (with optional offset). /// Appends code that copies the given arguments to memory (with optional offset).
/// @returns the number of bytes copied to memory /// @returns the number of bytes copied to memory
unsigned appendArgumentCopyToMemory(TypePointers const& _functionType, std::vector<ASTPointer<Expression const>> const& _arguments, unsigned appendArgumentCopyToMemory(TypePointers const& _types,
std::vector<ASTPointer<Expression const>> const& _arguments,
unsigned _memoryOffset = 0);
/// Appends code that evaluates a single expression and copies it to memory (with optional offset).
/// @returns the number of bytes copied to memory
unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression,
unsigned _memoryOffset = 0); unsigned _memoryOffset = 0);
/// Appends code for a State Variable accessor function /// Appends code for a State Variable accessor function