aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-06-24 23:25:36 +0800
committerchriseth <c@ethdev.com>2015-06-25 01:34:43 +0800
commite5ae5955b97009233fc46ac04070073750240698 (patch)
tree9781a740e3dc3f63110dece7127adcbdd3019380
parent1add48a652ea695032d8c664fad3ea84afbfb9ea (diff)
downloaddexon-solidity-e5ae5955b97009233fc46ac04070073750240698.tar
dexon-solidity-e5ae5955b97009233fc46ac04070073750240698.tar.gz
dexon-solidity-e5ae5955b97009233fc46ac04070073750240698.tar.bz2
dexon-solidity-e5ae5955b97009233fc46ac04070073750240698.tar.lz
dexon-solidity-e5ae5955b97009233fc46ac04070073750240698.tar.xz
dexon-solidity-e5ae5955b97009233fc46ac04070073750240698.tar.zst
dexon-solidity-e5ae5955b97009233fc46ac04070073750240698.zip
Initialisation of memory types.
-rw-r--r--ArrayUtils.cpp2
-rw-r--r--Compiler.cpp13
-rw-r--r--Compiler.h8
-rw-r--r--CompilerContext.cpp9
-rw-r--r--CompilerContext.h1
-rw-r--r--CompilerUtils.cpp8
-rw-r--r--ExpressionCompiler.cpp56
-rw-r--r--ExpressionCompiler.h7
-rw-r--r--Types.cpp22
-rw-r--r--Types.h1
10 files changed, 110 insertions, 17 deletions
diff --git a/ArrayUtils.cpp b/ArrayUtils.cpp
index a7cf4792..3be12af7 100644
--- a/ArrayUtils.cpp
+++ b/ArrayUtils.cpp
@@ -674,6 +674,8 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const
m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL;
}
m_context << eth::Instruction::ADD;
+ //@todo we should also load if it is a reference type of dynamic length
+ // but we should apply special logic if we load from calldata.
if (_arrayType.getBaseType()->isValueType())
CompilerUtils(m_context).loadFromMemoryDynamic(
*_arrayType.getBaseType(),
diff --git a/Compiler.cpp b/Compiler.cpp
index 68052e27..47729964 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -376,9 +376,9 @@ bool Compiler::visit(FunctionDefinition const& _function)
}
for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
- m_context.addAndInitializeVariable(*variable);
+ appendStackVariableInitialisation(*variable);
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
- m_context.addAndInitializeVariable(*localVariable);
+ appendStackVariableInitialisation(*localVariable);
if (_function.isConstructor())
if (auto c = m_context.getNextConstructor(dynamic_cast<ContractDefinition const&>(*_function.getScope())))
@@ -623,7 +623,7 @@ void Compiler::appendModifierOrFunctionCode()
modifier.getParameters()[i]->getType());
}
for (VariableDeclaration const* localVariable: modifier.getLocalVariables())
- m_context.addAndInitializeVariable(*localVariable);
+ appendStackVariableInitialisation(*localVariable);
unsigned const c_stackSurplus = CompilerUtils::getSizeOnStack(modifier.getParameters()) +
CompilerUtils::getSizeOnStack(modifier.getLocalVariables());
@@ -637,6 +637,13 @@ void Compiler::appendModifierOrFunctionCode()
}
}
+void Compiler::appendStackVariableInitialisation(VariableDeclaration const& _variable)
+{
+ CompilerContext::LocationSetter location(m_context, _variable);
+ m_context.addVariable(_variable);
+ ExpressionCompiler(m_context).appendStackVariableInitialisation(*_variable.getType());
+}
+
void Compiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
{
ExpressionCompiler expressionCompiler(m_context, m_optimize);
diff --git a/Compiler.h b/Compiler.h
index 60ca00e8..ac794f89 100644
--- a/Compiler.h
+++ b/Compiler.h
@@ -84,6 +84,13 @@ private:
void registerStateVariables(ContractDefinition const& _contract);
void initializeStateVariables(ContractDefinition const& _contract);
+ /// Initialises all memory arrays in the local variables to point to an empty location.
+ void initialiseMemoryArrays(std::vector<VariableDeclaration const*> _variables);
+ /// Pushes the initialised value of the given type to the stack. If the type is a memory
+ /// reference type, allocates memory and pushes the memory pointer.
+ /// Not to be used for storage references.
+ void initialiseInMemory(Type const& _type);
+
virtual bool visit(VariableDeclaration const& _variableDeclaration) override;
virtual bool visit(FunctionDefinition const& _function) override;
virtual bool visit(IfStatement const& _ifStatement) override;
@@ -100,6 +107,7 @@ private:
/// body itself if the last modifier was reached.
void appendModifierOrFunctionCode();
+ void appendStackVariableInitialisation(VariableDeclaration const& _variable);
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
bool const m_optimize;
diff --git a/CompilerContext.cpp b/CompilerContext.cpp
index fde6adac..0f6f5fe7 100644
--- a/CompilerContext.cpp
+++ b/CompilerContext.cpp
@@ -65,15 +65,6 @@ void CompilerContext::removeVariable(VariableDeclaration const& _declaration)
m_localVariables.erase(&_declaration);
}
-void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
-{
- LocationSetter locationSetter(*this, _declaration);
- addVariable(_declaration);
- int const size = _declaration.getType()->getSizeOnStack();
- for (int i = 0; i < size; ++i)
- *this << u256(0);
-}
-
bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
{
auto ret = m_compiledContracts.find(&_contract);
diff --git a/CompilerContext.h b/CompilerContext.h
index 998b0a2f..3f97d900 100644
--- a/CompilerContext.h
+++ b/CompilerContext.h
@@ -46,7 +46,6 @@ public:
void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset);
void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
void removeVariable(VariableDeclaration const& _declaration);
- void addAndInitializeVariable(VariableDeclaration const& _declaration);
void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; }
bytes const& getCompiledContract(ContractDefinition const& _contract) const;
diff --git a/CompilerUtils.cpp b/CompilerUtils.cpp
index b6d79733..b5dcfdc2 100644
--- a/CompilerUtils.cpp
+++ b/CompilerUtils.cpp
@@ -411,7 +411,13 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
break;
}
default:
- solAssert(false, "Invalid type conversion requested.");
+ solAssert(false,
+ "Invalid type conversion " +
+ _typeOnStack.toString(false) +
+ " to " +
+ _targetType.toString(false) +
+ " requested."
+ );
}
break;
}
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 7d6ed346..fb10eb83 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -56,6 +56,62 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
StorageItem(m_context, _varDecl).storeValue(*_varDecl.getType(), _varDecl.getLocation(), true);
}
+void ExpressionCompiler::appendStackVariableInitialisation(Type const& _type, bool _toMemory)
+{
+ CompilerUtils utils(m_context);
+ auto const* referenceType = dynamic_cast<ReferenceType const*>(&_type);
+ if (!referenceType || referenceType->location() == DataLocation::Storage)
+ {
+ for (size_t i = 0; i < _type.getSizeOnStack(); ++i)
+ m_context << u256(0);
+ if (_toMemory)
+ utils.storeInMemoryDynamic(_type);
+ return;
+ }
+ solAssert(referenceType->location() == DataLocation::Memory, "");
+ if (!_toMemory)
+ {
+ // allocate memory
+ utils.fetchFreeMemoryPointer();
+ m_context << eth::Instruction::DUP1 << u256(max(32u, _type.getCalldataEncodedSize()));
+ m_context << eth::Instruction::ADD;
+ utils.storeFreeMemoryPointer();
+ m_context << eth::Instruction::DUP1;
+ }
+
+ if (auto structType = dynamic_cast<StructType const*>(&_type))
+ for (auto const& member: structType->getMembers())
+ appendStackVariableInitialisation(*member.type, true);
+ else if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
+ {
+ if (arrayType->isDynamicallySized())
+ {
+ // zero length
+ m_context << u256(0);
+ CompilerUtils(m_context).storeInMemoryDynamic(IntegerType(256));
+ }
+ else if (arrayType->getLength() > 0)
+ {
+ m_context << arrayType->getLength() << eth::Instruction::SWAP1;
+ // stack: items_to_do memory_pos
+ auto repeat = m_context.newTag();
+ m_context << repeat;
+ appendStackVariableInitialisation(*arrayType->getBaseType(), true);
+ m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1;
+ m_context << eth::Instruction::SUB << eth::Instruction::SWAP1;
+ m_context << eth::Instruction::DUP2;
+ m_context.appendConditionalJumpTo(repeat);
+ m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
+ }
+ }
+ else
+ solAssert(false, "Requested initialisation for unknown type: " + _type.toString());
+
+ if (!_toMemory)
+ // remove the updated memory pointer
+ m_context << eth::Instruction::POP;
+}
+
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
{
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h
index 642560c6..747e241e 100644
--- a/ExpressionCompiler.h
+++ b/ExpressionCompiler.h
@@ -64,6 +64,13 @@ public:
/// Appends code to set a state variable to its initial value/expression.
void appendStateVariableInitialization(VariableDeclaration const& _varDecl);
+ /// Appends code to initialise a local variable.
+ /// If @a _toMemory is false, leaves the value on the stack. For memory references, this
+ /// allocates new memory.
+ /// If @a _toMemory is true, directly stores the data in the memory pos on the stack and
+ /// updates it.
+ void appendStackVariableInitialisation(Type const& _type, bool _toMemory = false);
+
/// Appends code for a State Variable accessor function
void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
diff --git a/Types.cpp b/Types.cpp
index ab93839d..01876b5a 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -826,16 +826,16 @@ string ArrayType::toString(bool _short) const
TypePointer ArrayType::externalType() const
{
if (m_arrayKind != ArrayKind::Ordinary)
- return this->copyForLocation(DataLocation::CallData, true);
+ return this->copyForLocation(DataLocation::Memory, true);
if (!m_baseType->externalType())
return TypePointer();
if (m_baseType->getCategory() == Category::Array && m_baseType->isDynamicallySized())
return TypePointer();
if (isDynamicallySized())
- return std::make_shared<ArrayType>(DataLocation::CallData, m_baseType->externalType());
+ return std::make_shared<ArrayType>(DataLocation::Memory, m_baseType->externalType());
else
- return std::make_shared<ArrayType>(DataLocation::CallData, m_baseType->externalType(), m_length);
+ return std::make_shared<ArrayType>(DataLocation::Memory, m_baseType->externalType(), m_length);
}
TypePointer ArrayType::copyForLocation(DataLocation _location, bool _isPointer) const
@@ -974,6 +974,22 @@ bool StructType::operator==(Type const& _other) const
return ReferenceType::operator==(other) && other.m_struct == m_struct;
}
+unsigned StructType::getCalldataEncodedSize(bool _padded) const
+{
+ unsigned size = 0;
+ for (auto const& member: getMembers())
+ if (!member.type->canLiveOutsideStorage())
+ return 0;
+ else
+ {
+ unsigned memberSize = member.type->getCalldataEncodedSize(_padded);
+ if (memberSize == 0)
+ return 0;
+ size += memberSize;
+ }
+ return size;
+}
+
u256 StructType::getStorageSize() const
{
return max<u256>(1, getMembers().getStorageSize());
diff --git a/Types.h b/Types.h
index 7f66b5b0..9d412cd6 100644
--- a/Types.h
+++ b/Types.h
@@ -542,6 +542,7 @@ public:
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(Type const& _other) const override;
+ virtual unsigned getCalldataEncodedSize(bool _padded) const override;
virtual u256 getStorageSize() const override;
virtual bool canLiveOutsideStorage() const override;
virtual unsigned getSizeOnStack() const override { return 2; }