aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2015-02-23 02:15:41 +0800
committerChristian <c@ethdev.com>2015-02-24 01:25:49 +0800
commit754c804d191ad8f05d886566e599a82efbd38d8e (patch)
tree3872af65523e734487f9ef2eb605ae0329d0caa2
parent3abbb8d625bd3a904c54dfda7558a77d5543ac70 (diff)
downloaddexon-solidity-754c804d191ad8f05d886566e599a82efbd38d8e.tar
dexon-solidity-754c804d191ad8f05d886566e599a82efbd38d8e.tar.gz
dexon-solidity-754c804d191ad8f05d886566e599a82efbd38d8e.tar.bz2
dexon-solidity-754c804d191ad8f05d886566e599a82efbd38d8e.tar.lz
dexon-solidity-754c804d191ad8f05d886566e599a82efbd38d8e.tar.xz
dexon-solidity-754c804d191ad8f05d886566e599a82efbd38d8e.tar.zst
dexon-solidity-754c804d191ad8f05d886566e599a82efbd38d8e.zip
Implementation of index access.
-rw-r--r--CompilerContext.cpp7
-rw-r--r--ExpressionCompiler.cpp74
-rw-r--r--Types.cpp19
-rw-r--r--Types.h1
4 files changed, 74 insertions, 27 deletions
diff --git a/CompilerContext.cpp b/CompilerContext.cpp
index 01a71d7c..8d32a1a5 100644
--- a/CompilerContext.cpp
+++ b/CompilerContext.cpp
@@ -40,7 +40,12 @@ void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaratio
void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
{
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)
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 94f65b93..dcd411c3 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -534,19 +534,24 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{
solAssert(member == "length", "Illegal array member.");
auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.getExpression().getType());
- solAssert(type.isByteArray(), "Non byte arrays not yet implemented here.");
- switch (type.getLocation())
+ if (!type.isDynamicallySized())
{
- 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;
+ CompilerUtils(m_context).popStackElement(type);
+ m_context << type.getLength();
}
+ 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;
}
default:
@@ -559,19 +564,40 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
_indexAccess.getBaseExpression().accept(*this);
Type const& baseType = *_indexAccess.getBaseExpression().getType();
- solAssert(baseType.getCategory() == Type::Category::Mapping, "");
- Type const& keyType = *dynamic_cast<MappingType const&>(baseType).getKeyType();
- m_context << u256(0);
- solAssert(_indexAccess.getIndexExpression(), "Index expression expected.");
- appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression());
- solAssert(baseType.getSizeOnStack() == 1,
- "Unexpected: Not exactly one stack slot taken by subscriptable expression.");
- m_context << eth::Instruction::SWAP1;
- appendTypeMoveToMemory(IntegerType(256));
- m_context << u256(0) << eth::Instruction::SHA3;
-
- m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
- m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
+ if (baseType.getCategory() == Type::Category::Mapping)
+ {
+ Type const& keyType = *dynamic_cast<MappingType const&>(baseType).getKeyType();
+ m_context << u256(0);
+ solAssert(_indexAccess.getIndexExpression(), "Index expression expected.");
+ appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression());
+ solAssert(baseType.getSizeOnStack() == 1,
+ "Unexpected: Not exactly one stack slot taken by subscriptable expression.");
+ m_context << eth::Instruction::SWAP1;
+ appendTypeMoveToMemory(IntegerType(256));
+ m_context << u256(0) << eth::Instruction::SHA3;
+ m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
+ 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;
}
diff --git a/Types.cpp b/Types.cpp
index c0be0d93..adcd2e54 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -555,6 +555,19 @@ bool ArrayType::operator==(Type const& _other) const
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
{
if (m_location == Location::CallData)
@@ -665,10 +678,12 @@ bool StructType::operator==(Type const& _other) const
u256 StructType::getStorageSize() const
{
- u256 size = 0;
+ bigint size = 0;
for (pair<string, TypePointer> const& member: getMembers())
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
diff --git a/Types.h b/Types.h
index 0d24b722..9961f03a 100644
--- a/Types.h
+++ b/Types.h
@@ -303,6 +303,7 @@ public:
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override;
virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
+ virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() const override;
virtual std::string toString() const override;
virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; }