Implementation of index access.

This commit is contained in:
Christian 2015-02-22 19:15:41 +01:00
parent 3abbb8d625
commit 754c804d19
4 changed files with 74 additions and 27 deletions

View File

@ -40,7 +40,12 @@ void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaratio
void CompilerContext::addStateVariable(VariableDeclaration const& _declaration) void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
{ {
m_stateVariables[&_declaration] = m_stateVariablesSize; m_stateVariables[&_declaration] = m_stateVariablesSize;
m_stateVariablesSize += _declaration.getType()->getStorageSize(); bigint newSize = bigint(m_stateVariablesSize) + _declaration.getType()->getStorageSize();
if (newSize >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(TypeError()
<< errinfo_comment("State variable does not fit in storage.")
<< errinfo_sourceLocation(_declaration.getLocation()));
m_stateVariablesSize = u256(newSize);
} }
void CompilerContext::startFunction(Declaration const& _function) void CompilerContext::startFunction(Declaration const& _function)

View File

@ -534,19 +534,24 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{ {
solAssert(member == "length", "Illegal array member."); solAssert(member == "length", "Illegal array member.");
auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.getExpression().getType()); auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.getExpression().getType());
solAssert(type.isByteArray(), "Non byte arrays not yet implemented here."); if (!type.isDynamicallySized())
switch (type.getLocation())
{ {
case ArrayType::Location::CallData: CompilerUtils(m_context).popStackElement(type);
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; m_context << type.getLength();
break;
case ArrayType::Location::Storage:
m_context << eth::Instruction::SLOAD;
break;
default:
solAssert(false, "Unsupported array location.");
break;
} }
else
switch (type.getLocation())
{
case ArrayType::Location::CallData:
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
break;
case ArrayType::Location::Storage:
m_context << eth::Instruction::SLOAD;
break;
default:
solAssert(false, "Unsupported array location.");
break;
}
break; break;
} }
default: default:
@ -559,19 +564,40 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
_indexAccess.getBaseExpression().accept(*this); _indexAccess.getBaseExpression().accept(*this);
Type const& baseType = *_indexAccess.getBaseExpression().getType(); Type const& baseType = *_indexAccess.getBaseExpression().getType();
solAssert(baseType.getCategory() == Type::Category::Mapping, ""); if (baseType.getCategory() == Type::Category::Mapping)
Type const& keyType = *dynamic_cast<MappingType const&>(baseType).getKeyType(); {
m_context << u256(0); Type const& keyType = *dynamic_cast<MappingType const&>(baseType).getKeyType();
solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); m_context << u256(0);
appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); solAssert(_indexAccess.getIndexExpression(), "Index expression expected.");
solAssert(baseType.getSizeOnStack() == 1, appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression());
"Unexpected: Not exactly one stack slot taken by subscriptable expression."); solAssert(baseType.getSizeOnStack() == 1,
m_context << eth::Instruction::SWAP1; "Unexpected: Not exactly one stack slot taken by subscriptable expression.");
appendTypeMoveToMemory(IntegerType(256)); m_context << eth::Instruction::SWAP1;
m_context << u256(0) << eth::Instruction::SHA3; appendTypeMoveToMemory(IntegerType(256));
m_context << u256(0) << eth::Instruction::SHA3;
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType()); m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
}
else if (baseType.getCategory() == Type::Category::Array)
{
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(baseType);
solAssert(arrayType.getLocation() == ArrayType::Location::Storage,
"TODO: Index acces only implemented for storage arrays.");
solAssert(!arrayType.isDynamicallySized(),
"TODO: Index acces only implemented for fixed-size arrays.");
solAssert(!arrayType.isByteArray(),
"TODO: Index acces not implemented for byte arrays.");
solAssert(_indexAccess.getIndexExpression(), "Index expression expected.");
// TODO: for dynamically-sized arrays, update the length for each write
// TODO: do we want to check the index?
_indexAccess.getIndexExpression()->accept(*this);
m_context << arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL
<< eth::Instruction::ADD;
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
}
else
solAssert(false, "Index access only allowed for mappings or arrays.");
return false; return false;
} }

View File

@ -555,6 +555,19 @@ bool ArrayType::operator==(Type const& _other) const
return other.m_location == m_location; return other.m_location == m_location;
} }
u256 ArrayType::getStorageSize() const
{
if (isDynamicallySized())
return 1;
else
{
bigint size = bigint(getLength()) * getBaseType()->getStorageSize();
if (size >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Array too large for storage."));
return max<u256>(1, u256(size));
}
}
unsigned ArrayType::getSizeOnStack() const unsigned ArrayType::getSizeOnStack() const
{ {
if (m_location == Location::CallData) if (m_location == Location::CallData)
@ -665,10 +678,12 @@ bool StructType::operator==(Type const& _other) const
u256 StructType::getStorageSize() const u256 StructType::getStorageSize() const
{ {
u256 size = 0; bigint size = 0;
for (pair<string, TypePointer> const& member: getMembers()) for (pair<string, TypePointer> const& member: getMembers())
size += member.second->getStorageSize(); size += member.second->getStorageSize();
return max<u256>(1, size); if (size >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Struct too large for storage."));
return max<u256>(1, u256(size));
} }
bool StructType::canLiveOutsideStorage() const bool StructType::canLiveOutsideStorage() const

View File

@ -303,6 +303,7 @@ public:
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override; virtual bool operator==(const Type& _other) const override;
virtual bool isDynamicallySized() const { return m_hasDynamicLength; } virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() const override; virtual unsigned getSizeOnStack() const override;
virtual std::string toString() const override; virtual std::string toString() const override;
virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; } virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; }