mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Code generation for events.
This commit is contained in:
parent
4a6ed84386
commit
4e72a77546
1
AST.h
1
AST.h
@ -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
|
||||||
|
@ -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,22 +819,25 @@ 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);
|
|
||||||
appendTypeConversion(*_arguments[i]->getType(), *_types[i], true);
|
|
||||||
unsigned const c_numBytes = _types[i]->getCalldataEncodedSize();
|
|
||||||
if (c_numBytes == 0 || c_numBytes > 32)
|
|
||||||
BOOST_THROW_EXCEPTION(CompilerError()
|
|
||||||
<< errinfo_sourceLocation(_arguments[i]->getLocation())
|
|
||||||
<< errinfo_comment("Type " + _types[i]->toString() + " not yet supported."));
|
|
||||||
bool const c_leftAligned = _types[i]->getCategory() == Type::Category::STRING;
|
|
||||||
bool const c_padToWords = true;
|
|
||||||
length += CompilerUtils(m_context).storeInMemory(_memoryOffset + length, c_numBytes,
|
|
||||||
c_leftAligned, c_padToWords);
|
|
||||||
}
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
BOOST_THROW_EXCEPTION(CompilerError()
|
||||||
|
<< errinfo_sourceLocation(_expression.getLocation())
|
||||||
|
<< errinfo_comment("Type " + _expectedType.toString() + " not yet supported."));
|
||||||
|
bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING;
|
||||||
|
bool const c_padToWords = true;
|
||||||
|
return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords);
|
||||||
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
|
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType());
|
m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType());
|
||||||
|
@ -94,8 +94,13 @@ 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,
|
||||||
unsigned _memoryOffset = 0);
|
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);
|
||||||
|
|
||||||
/// Appends code for a State Variable accessor function
|
/// Appends code for a State Variable accessor function
|
||||||
void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
|
void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
|
||||||
|
Loading…
Reference in New Issue
Block a user