aboutsummaryrefslogtreecommitdiffstats
path: root/ExpressionCompiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ExpressionCompiler.cpp')
-rw-r--r--ExpressionCompiler.cpp107
1 files changed, 71 insertions, 36 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index bd8c8653..5d44c86f 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -48,6 +48,12 @@ void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, Type co
compiler.appendTypeConversion(_typeOnStack, _targetType, _cleanupNeeded);
}
+void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize)
+{
+ ExpressionCompiler compiler(_context, _optimize);
+ compiler.appendStateVariableAccessor(_varDecl);
+}
+
bool ExpressionCompiler::visit(Assignment const& _assignment)
{
_assignment.getRightHandSide().accept(*this);
@@ -60,7 +66,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
{
if (m_currentLValue.storesReferenceOnStack())
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
- m_currentLValue.retrieveValue(_assignment, true);
+ m_currentLValue.retrieveValue(_assignment.getType(), _assignment.getLocation(), true);
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
if (m_currentLValue.storesReferenceOnStack())
m_context << eth::Instruction::SWAP1;
@@ -101,7 +107,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
case Token::INC: // ++ (pre- or postfix)
case Token::DEC: // -- (pre- or postfix)
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
- m_currentLValue.retrieveValue(_unaryOperation);
+ m_currentLValue.retrieveValue(_unaryOperation.getType(), _unaryOperation.getLocation());
if (!_unaryOperation.isPrefixOperation())
{
if (m_currentLValue.storesReferenceOnStack())
@@ -359,15 +365,25 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{
case Type::Category::CONTRACT:
{
+ bool alsoSearchInteger = false;
ContractType const& type = dynamic_cast<ContractType const&>(*_memberAccess.getExpression().getType());
- u256 identifier = type.getFunctionIdentifier(member);
- if (identifier != Invalid256)
+ if (type.isSuper())
+ m_context << m_context.getSuperFunctionEntryLabel(member, type.getContractDefinition()).pushTag();
+ else
{
- appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::ADDRESS), true);
- m_context << identifier;
- break;
+ // ordinary contract type
+ u256 identifier = type.getFunctionIdentifier(member);
+ if (identifier != Invalid256)
+ {
+ appendTypeConversion(type, IntegerType(0, IntegerType::Modifier::ADDRESS), true);
+ m_context << identifier;
+ }
+ else
+ // not found in contract, search in members inherited from address
+ alsoSearchInteger = true;
}
- // fall-through to "integer" otherwise (address)
+ if (!alsoSearchInteger)
+ break;
}
case Type::Category::INTEGER:
if (member == "balance")
@@ -463,8 +479,10 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
Declaration const* declaration = _identifier.getReferencedDeclaration();
if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration))
{
- if (magicVar->getType()->getCategory() == Type::Category::CONTRACT) // must be "this"
- m_context << eth::Instruction::ADDRESS;
+ if (magicVar->getType()->getCategory() == Type::Category::CONTRACT)
+ // "this" or "super"
+ if (!dynamic_cast<ContractType const&>(*magicVar->getType()).isSuper())
+ m_context << eth::Instruction::ADDRESS;
}
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag();
@@ -789,6 +807,13 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ
return length;
}
+void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
+{
+ m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType());
+ solAssert(m_currentLValue.isInStorage(), "");
+ m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true);
+}
+
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType,
unsigned _baseStackOffset):
m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset)
@@ -801,7 +826,7 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType
m_size = unsigned(_dataType.getSizeOnStack());
}
-void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bool _remove) const
+void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Location const& _location, bool _remove) const
{
switch (m_type)
{
@@ -809,42 +834,47 @@ void ExpressionCompiler::LValue::retrieveValue(Expression const& _expression, bo
{
unsigned stackPos = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset));
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Stack too deep."));
for (unsigned i = 0; i < m_size; ++i)
*m_context << eth::dupInstruction(stackPos + 1);
break;
}
case STORAGE:
- if (!_expression.getType()->isValueType())
- break; // no distinction between value and reference for non-value types
- if (!_remove)
- *m_context << eth::Instruction::DUP1;
- if (m_size == 1)
- *m_context << eth::Instruction::SLOAD;
- else
- for (unsigned i = 0; i < m_size; ++i)
- {
- *m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1;
- if (i + 1 < m_size)
- *m_context << u256(1) << eth::Instruction::ADD;
- else
- *m_context << eth::Instruction::POP;
- }
+ retrieveValueFromStorage(_type, _remove);
break;
case MEMORY:
- if (!_expression.getType()->isValueType())
+ if (!_type->isValueType())
break; // no distinction between value and reference for non-value types
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Location type not yet implemented."));
break;
default:
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Unsupported location type."));
break;
}
}
+void ExpressionCompiler::LValue::retrieveValueFromStorage(TypePointer const& _type, bool _remove) const
+{
+ if (!_type->isValueType())
+ return; // no distinction between value and reference for non-value types
+ if (!_remove)
+ *m_context << eth::Instruction::DUP1;
+ if (m_size == 1)
+ *m_context << eth::Instruction::SLOAD;
+ else
+ for (unsigned i = 0; i < m_size; ++i)
+ {
+ *m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1;
+ if (i + 1 < m_size)
+ *m_context << u256(1) << eth::Instruction::ADD;
+ else
+ *m_context << eth::Instruction::POP;
+ }
+}
+
void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool _move) const
{
switch (m_type)
@@ -859,7 +889,7 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, bool
for (unsigned i = 0; i < m_size; ++i)
*m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP;
if (!_move)
- retrieveValue(_expression);
+ retrieveValue(_expression.getType(), _expression.getLocation());
break;
}
case LValue::STORAGE:
@@ -946,11 +976,19 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co
{
if (!_expression.lvalueRequested())
{
- retrieveValue(_expression, true);
+ retrieveValue(_expression.getType(), _expression.getLocation(), true);
reset();
}
}
+void ExpressionCompiler::LValue::fromStateVariable(Declaration const& _varDecl, TypePointer const& _type)
+{
+ m_type = STORAGE;
+ solAssert(_type->getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " + _type->toString() + " should fit in an unsigned");
+ *m_context << m_context->getStorageLocationOfVariable(_varDecl);
+ m_size = unsigned(_type->getStorageSize());
+}
+
void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration)
{
if (m_context->isLocalVariable(&_declaration))
@@ -961,10 +999,7 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D
}
else if (m_context->isStateVariable(&_declaration))
{
- m_type = STORAGE;
- solAssert(_identifier.getType()->getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " + _identifier.getType()->toString() + " should fit in unsigned");
- m_size = unsigned(_identifier.getType()->getStorageSize());
- *m_context << m_context->getStorageLocationOfVariable(_declaration);
+ fromStateVariable(_declaration, _identifier.getType());
}
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation())