mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Initialisation of memory types.
This commit is contained in:
parent
1add48a652
commit
e5ae5955b9
@ -674,6 +674,8 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const
|
|||||||
m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL;
|
m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL;
|
||||||
}
|
}
|
||||||
m_context << eth::Instruction::ADD;
|
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())
|
if (_arrayType.getBaseType()->isValueType())
|
||||||
CompilerUtils(m_context).loadFromMemoryDynamic(
|
CompilerUtils(m_context).loadFromMemoryDynamic(
|
||||||
*_arrayType.getBaseType(),
|
*_arrayType.getBaseType(),
|
||||||
|
13
Compiler.cpp
13
Compiler.cpp
@ -376,9 +376,9 @@ bool Compiler::visit(FunctionDefinition const& _function)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
|
for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
|
||||||
m_context.addAndInitializeVariable(*variable);
|
appendStackVariableInitialisation(*variable);
|
||||||
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
|
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
|
||||||
m_context.addAndInitializeVariable(*localVariable);
|
appendStackVariableInitialisation(*localVariable);
|
||||||
|
|
||||||
if (_function.isConstructor())
|
if (_function.isConstructor())
|
||||||
if (auto c = m_context.getNextConstructor(dynamic_cast<ContractDefinition const&>(*_function.getScope())))
|
if (auto c = m_context.getNextConstructor(dynamic_cast<ContractDefinition const&>(*_function.getScope())))
|
||||||
@ -623,7 +623,7 @@ void Compiler::appendModifierOrFunctionCode()
|
|||||||
modifier.getParameters()[i]->getType());
|
modifier.getParameters()[i]->getType());
|
||||||
}
|
}
|
||||||
for (VariableDeclaration const* localVariable: modifier.getLocalVariables())
|
for (VariableDeclaration const* localVariable: modifier.getLocalVariables())
|
||||||
m_context.addAndInitializeVariable(*localVariable);
|
appendStackVariableInitialisation(*localVariable);
|
||||||
|
|
||||||
unsigned const c_stackSurplus = CompilerUtils::getSizeOnStack(modifier.getParameters()) +
|
unsigned const c_stackSurplus = CompilerUtils::getSizeOnStack(modifier.getParameters()) +
|
||||||
CompilerUtils::getSizeOnStack(modifier.getLocalVariables());
|
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)
|
void Compiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
|
||||||
{
|
{
|
||||||
ExpressionCompiler expressionCompiler(m_context, m_optimize);
|
ExpressionCompiler expressionCompiler(m_context, m_optimize);
|
||||||
|
@ -84,6 +84,13 @@ private:
|
|||||||
void registerStateVariables(ContractDefinition const& _contract);
|
void registerStateVariables(ContractDefinition const& _contract);
|
||||||
void initializeStateVariables(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(VariableDeclaration const& _variableDeclaration) override;
|
||||||
virtual bool visit(FunctionDefinition const& _function) override;
|
virtual bool visit(FunctionDefinition const& _function) override;
|
||||||
virtual bool visit(IfStatement const& _ifStatement) override;
|
virtual bool visit(IfStatement const& _ifStatement) override;
|
||||||
@ -100,6 +107,7 @@ private:
|
|||||||
/// body itself if the last modifier was reached.
|
/// body itself if the last modifier was reached.
|
||||||
void appendModifierOrFunctionCode();
|
void appendModifierOrFunctionCode();
|
||||||
|
|
||||||
|
void appendStackVariableInitialisation(VariableDeclaration const& _variable);
|
||||||
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
|
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
|
||||||
|
|
||||||
bool const m_optimize;
|
bool const m_optimize;
|
||||||
|
@ -65,15 +65,6 @@ void CompilerContext::removeVariable(VariableDeclaration const& _declaration)
|
|||||||
m_localVariables.erase(&_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
|
bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
|
||||||
{
|
{
|
||||||
auto ret = m_compiledContracts.find(&_contract);
|
auto ret = m_compiledContracts.find(&_contract);
|
||||||
|
@ -46,7 +46,6 @@ public:
|
|||||||
void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset);
|
void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset);
|
||||||
void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
|
void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
|
||||||
void removeVariable(VariableDeclaration const& _declaration);
|
void removeVariable(VariableDeclaration const& _declaration);
|
||||||
void addAndInitializeVariable(VariableDeclaration const& _declaration);
|
|
||||||
|
|
||||||
void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; }
|
void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; }
|
||||||
bytes const& getCompiledContract(ContractDefinition const& _contract) const;
|
bytes const& getCompiledContract(ContractDefinition const& _contract) const;
|
||||||
|
@ -411,7 +411,13 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
solAssert(false, "Invalid type conversion requested.");
|
solAssert(false,
|
||||||
|
"Invalid type conversion " +
|
||||||
|
_typeOnStack.toString(false) +
|
||||||
|
" to " +
|
||||||
|
_targetType.toString(false) +
|
||||||
|
" requested."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,62 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
|
|||||||
StorageItem(m_context, _varDecl).storeValue(*_varDecl.getType(), _varDecl.getLocation(), true);
|
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)
|
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
|
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
|
||||||
|
@ -64,6 +64,13 @@ public:
|
|||||||
/// Appends code to set a state variable to its initial value/expression.
|
/// Appends code to set a state variable to its initial value/expression.
|
||||||
void appendStateVariableInitialization(VariableDeclaration const& _varDecl);
|
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
|
/// Appends code for a State Variable accessor function
|
||||||
void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
|
void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
|
||||||
|
|
||||||
|
22
Types.cpp
22
Types.cpp
@ -826,16 +826,16 @@ string ArrayType::toString(bool _short) const
|
|||||||
TypePointer ArrayType::externalType() const
|
TypePointer ArrayType::externalType() const
|
||||||
{
|
{
|
||||||
if (m_arrayKind != ArrayKind::Ordinary)
|
if (m_arrayKind != ArrayKind::Ordinary)
|
||||||
return this->copyForLocation(DataLocation::CallData, true);
|
return this->copyForLocation(DataLocation::Memory, true);
|
||||||
if (!m_baseType->externalType())
|
if (!m_baseType->externalType())
|
||||||
return TypePointer();
|
return TypePointer();
|
||||||
if (m_baseType->getCategory() == Category::Array && m_baseType->isDynamicallySized())
|
if (m_baseType->getCategory() == Category::Array && m_baseType->isDynamicallySized())
|
||||||
return TypePointer();
|
return TypePointer();
|
||||||
|
|
||||||
if (isDynamicallySized())
|
if (isDynamicallySized())
|
||||||
return std::make_shared<ArrayType>(DataLocation::CallData, m_baseType->externalType());
|
return std::make_shared<ArrayType>(DataLocation::Memory, m_baseType->externalType());
|
||||||
else
|
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
|
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;
|
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
|
u256 StructType::getStorageSize() const
|
||||||
{
|
{
|
||||||
return max<u256>(1, getMembers().getStorageSize());
|
return max<u256>(1, getMembers().getStorageSize());
|
||||||
|
1
Types.h
1
Types.h
@ -542,6 +542,7 @@ public:
|
|||||||
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
|
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
|
||||||
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
||||||
virtual bool operator==(Type const& _other) const override;
|
virtual bool operator==(Type const& _other) const override;
|
||||||
|
virtual unsigned getCalldataEncodedSize(bool _padded) const override;
|
||||||
virtual u256 getStorageSize() const override;
|
virtual u256 getStorageSize() const override;
|
||||||
virtual bool canLiveOutsideStorage() const override;
|
virtual bool canLiveOutsideStorage() const override;
|
||||||
virtual unsigned getSizeOnStack() const override { return 2; }
|
virtual unsigned getSizeOnStack() const override { return 2; }
|
||||||
|
Loading…
Reference in New Issue
Block a user