mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Compute packing offsets.
This commit is contained in:
		
							parent
							
								
									fff3f98f58
								
							
						
					
					
						commit
						7f64584b7f
					
				
							
								
								
									
										95
									
								
								Types.cpp
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								Types.cpp
									
									
									
									
									
								
							| @ -35,6 +35,56 @@ namespace dev | |||||||
| namespace solidity | namespace solidity | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
|  | std::pair<u256, unsigned> const* MemberList::getMemberStorageOffset(string const& _name) const | ||||||
|  | { | ||||||
|  | 	if (!m_storageOffsets) | ||||||
|  | 	{ | ||||||
|  | 		bigint slotOffset = 0; | ||||||
|  | 		unsigned byteOffset = 0; | ||||||
|  | 		map<string, pair<u256, unsigned>> offsets; | ||||||
|  | 		for (auto const& nameAndType: m_memberTypes) | ||||||
|  | 		{ | ||||||
|  | 			TypePointer const& type = nameAndType.second; | ||||||
|  | 			if (!type->canBeStored()) | ||||||
|  | 				continue; | ||||||
|  | 			if (byteOffset + type->getStorageBytes() > 32) | ||||||
|  | 			{ | ||||||
|  | 				// would overflow, go to next slot
 | ||||||
|  | 				++slotOffset; | ||||||
|  | 				byteOffset = 0; | ||||||
|  | 			} | ||||||
|  | 			if (slotOffset >= bigint(1) << 256) | ||||||
|  | 				BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Object too large for storage.")); | ||||||
|  | 			offsets[nameAndType.first] = make_pair(u256(slotOffset), byteOffset); | ||||||
|  | 			solAssert(type->getStorageSize() >= 1, "Invalid storage size."); | ||||||
|  | 			if (type->getStorageSize() == 1 && byteOffset + type->getStorageBytes() <= 32) | ||||||
|  | 				byteOffset += type->getStorageBytes(); | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				slotOffset += type->getStorageSize(); | ||||||
|  | 				byteOffset = 0; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (byteOffset > 0) | ||||||
|  | 			++slotOffset; | ||||||
|  | 		if (slotOffset >= bigint(1) << 256) | ||||||
|  | 			BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Object too large for storage.")); | ||||||
|  | 		m_storageSize = u256(slotOffset); | ||||||
|  | 		m_storageOffsets.reset(new decltype(offsets)(move(offsets))); | ||||||
|  | 	} | ||||||
|  | 	if (m_storageOffsets->count(_name)) | ||||||
|  | 		return &((*m_storageOffsets)[_name]); | ||||||
|  | 	else | ||||||
|  | 		return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u256 const& MemberList::getStorageSize() const | ||||||
|  | { | ||||||
|  | 	// trigger lazy computation
 | ||||||
|  | 	getMemberStorageOffset(""); | ||||||
|  | 	return m_storageSize; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) | TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) | ||||||
| { | { | ||||||
| 	char const* tokenCstr = Token::toString(_typeToken); | 	char const* tokenCstr = Token::toString(_typeToken); | ||||||
| @ -751,12 +801,7 @@ bool StructType::operator==(Type const& _other) const | |||||||
| 
 | 
 | ||||||
| u256 StructType::getStorageSize() const | u256 StructType::getStorageSize() const | ||||||
| { | { | ||||||
| 	bigint size = 0; | 	return max<u256>(1, getMembers().getStorageSize()); | ||||||
| 	for (pair<string, TypePointer> const& member: getMembers()) |  | ||||||
| 		size += member.second->getStorageSize(); |  | ||||||
| 	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 | ||||||
| @ -787,6 +832,7 @@ MemberList const& StructType::getMembers() const | |||||||
| 
 | 
 | ||||||
| u256 StructType::getStorageOffsetOfMember(string const& _name) const | u256 StructType::getStorageOffsetOfMember(string const& _name) const | ||||||
| { | { | ||||||
|  | 
 | ||||||
| 	//@todo cache member offset?
 | 	//@todo cache member offset?
 | ||||||
| 	u256 offset; | 	u256 offset; | ||||||
| 	for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers()) | 	for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers()) | ||||||
| @ -811,6 +857,15 @@ bool EnumType::operator==(Type const& _other) const | |||||||
| 	return other.m_enum == m_enum; | 	return other.m_enum == m_enum; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | unsigned EnumType::getStorageBytes() const | ||||||
|  | { | ||||||
|  | 	size_t elements = m_enum.getMembers().size(); | ||||||
|  | 	if (elements <= 1) | ||||||
|  | 		return 1; | ||||||
|  | 	else | ||||||
|  | 		return dev::bytesRequired(elements - 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| string EnumType::toString() const | string EnumType::toString() const | ||||||
| { | { | ||||||
| 	return string("enum ") + m_enum.getName(); | 	return string("enum ") + m_enum.getName(); | ||||||
| @ -955,6 +1010,13 @@ string FunctionType::toString() const | |||||||
| 	return name + ")"; | 	return name + ")"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | u256 FunctionType::getStorageSize() const | ||||||
|  | { | ||||||
|  | 	BOOST_THROW_EXCEPTION( | ||||||
|  | 		InternalCompilerError() | ||||||
|  | 			<< errinfo_comment("Storage size of non-storable function type requested.")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| unsigned FunctionType::getSizeOnStack() const | unsigned FunctionType::getSizeOnStack() const | ||||||
| { | { | ||||||
| 	Location location = m_location; | 	Location location = m_location; | ||||||
| @ -1077,6 +1139,13 @@ string MappingType::toString() const | |||||||
| 	return "mapping(" + getKeyType()->toString() + " => " + getValueType()->toString() + ")"; | 	return "mapping(" + getKeyType()->toString() + " => " + getValueType()->toString() + ")"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | u256 VoidType::getStorageSize() const | ||||||
|  | { | ||||||
|  | 	BOOST_THROW_EXCEPTION( | ||||||
|  | 		InternalCompilerError() | ||||||
|  | 			<< errinfo_comment("Storage size of non-storable void type requested.")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool TypeType::operator==(Type const& _other) const | bool TypeType::operator==(Type const& _other) const | ||||||
| { | { | ||||||
| 	if (_other.getCategory() != getCategory()) | 	if (_other.getCategory() != getCategory()) | ||||||
| @ -1085,6 +1154,13 @@ bool TypeType::operator==(Type const& _other) const | |||||||
| 	return *getActualType() == *other.getActualType(); | 	return *getActualType() == *other.getActualType(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | u256 TypeType::getStorageSize() const | ||||||
|  | { | ||||||
|  | 	BOOST_THROW_EXCEPTION( | ||||||
|  | 		InternalCompilerError() | ||||||
|  | 			<< errinfo_comment("Storage size of non-storable type type requested.")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| MemberList const& TypeType::getMembers() const | MemberList const& TypeType::getMembers() const | ||||||
| { | { | ||||||
| 	// We need to lazy-initialize it because of recursive references.
 | 	// We need to lazy-initialize it because of recursive references.
 | ||||||
| @ -1122,6 +1198,13 @@ ModifierType::ModifierType(const ModifierDefinition& _modifier) | |||||||
| 	swap(params, m_parameterTypes); | 	swap(params, m_parameterTypes); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | u256 ModifierType::getStorageSize() const | ||||||
|  | { | ||||||
|  | 	BOOST_THROW_EXCEPTION( | ||||||
|  | 		InternalCompilerError() | ||||||
|  | 			<< errinfo_comment("Storage size of non-storable type type requested.")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool ModifierType::operator==(Type const& _other) const | bool ModifierType::operator==(Type const& _other) const | ||||||
| { | { | ||||||
| 	if (_other.getCategory() != getCategory()) | 	if (_other.getCategory() != getCategory()) | ||||||
|  | |||||||
							
								
								
									
										30
									
								
								Types.h
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								Types.h
									
									
									
									
									
								
							| @ -60,12 +60,19 @@ public: | |||||||
| 				return it.second; | 				return it.second; | ||||||
| 		return TypePointer(); | 		return TypePointer(); | ||||||
| 	} | 	} | ||||||
|  | 	/// @returns the offset of the given member in storage slots and bytes inside a slot or
 | ||||||
|  | 	/// a nullptr if the member is not part of storage.
 | ||||||
|  | 	std::pair<u256, unsigned> const* getMemberStorageOffset(std::string const& _name) const; | ||||||
|  | 	/// @returns the number of storage slots occupied by the members.
 | ||||||
|  | 	u256 const& getStorageSize() const; | ||||||
| 
 | 
 | ||||||
| 	MemberMap::const_iterator begin() const { return m_memberTypes.begin(); } | 	MemberMap::const_iterator begin() const { return m_memberTypes.begin(); } | ||||||
| 	MemberMap::const_iterator end() const { return m_memberTypes.end(); } | 	MemberMap::const_iterator end() const { return m_memberTypes.end(); } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	MemberMap m_memberTypes; | 	MemberMap m_memberTypes; | ||||||
|  | 	mutable u256 m_storageSize = 0; | ||||||
|  | 	mutable std::unique_ptr<std::map<std::string, std::pair<u256, unsigned>>> m_storageOffsets; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -97,6 +104,8 @@ public: | |||||||
| 	/// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
 | 	/// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
 | ||||||
| 	static TypePointer commonType(TypePointer const& _a, TypePointer const& _b); | 	static TypePointer commonType(TypePointer const& _a, TypePointer const& _b); | ||||||
| 
 | 
 | ||||||
|  | 	/// Calculates the
 | ||||||
|  | 
 | ||||||
| 	virtual Category getCategory() const = 0; | 	virtual Category getCategory() const = 0; | ||||||
| 	virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } | 	virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } | ||||||
| 	virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const | 	virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const | ||||||
| @ -126,9 +135,15 @@ public: | |||||||
| 	unsigned getCalldataEncodedSize() const { return getCalldataEncodedSize(true); } | 	unsigned getCalldataEncodedSize() const { return getCalldataEncodedSize(true); } | ||||||
| 	/// @returns true if the type is dynamically encoded in calldata
 | 	/// @returns true if the type is dynamically encoded in calldata
 | ||||||
| 	virtual bool isDynamicallySized() const { return false; } | 	virtual bool isDynamicallySized() const { return false; } | ||||||
| 	/// @returns number of bytes required to hold this value in storage.
 | 	/// @returns the number of storage slots required to hold this value in storage.
 | ||||||
| 	/// For dynamically "allocated" types, it returns the size of the statically allocated head,
 | 	/// For dynamically "allocated" types, it returns the size of the statically allocated head,
 | ||||||
| 	virtual u256 getStorageSize() const { return 1; } | 	virtual u256 getStorageSize() const { return 1; } | ||||||
|  | 	/// Multiple small types can be packed into a single storage slot. If such a packing is possible
 | ||||||
|  | 	/// this function @returns the size in bytes smaller than 32. Data is moved to the next slot if
 | ||||||
|  | 	/// it does not fit.
 | ||||||
|  | 	/// In order to avoid computation at runtime of whether such moving is necessary, structs and
 | ||||||
|  | 	/// array data (not each element) always start a new slot.
 | ||||||
|  | 	virtual unsigned getStorageBytes() const { return 32; } | ||||||
| 	/// Returns true if the type can be stored in storage.
 | 	/// Returns true if the type can be stored in storage.
 | ||||||
| 	virtual bool canBeStored() const { return true; } | 	virtual bool canBeStored() const { return true; } | ||||||
| 	/// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
 | 	/// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
 | ||||||
| @ -179,6 +194,7 @@ public: | |||||||
| 	virtual bool operator==(Type const& _other) const override; | 	virtual bool operator==(Type const& _other) const override; | ||||||
| 
 | 
 | ||||||
| 	virtual unsigned getCalldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_bits / 8; } | 	virtual unsigned getCalldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_bits / 8; } | ||||||
|  | 	virtual unsigned getStorageBytes() const override { return m_bits / 8; } | ||||||
| 	virtual bool isValueType() const override { return true; } | 	virtual bool isValueType() const override { return true; } | ||||||
| 
 | 
 | ||||||
| 	virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; } | 	virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; } | ||||||
| @ -251,6 +267,7 @@ public: | |||||||
| 	virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; | 	virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; | ||||||
| 
 | 
 | ||||||
| 	virtual unsigned getCalldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; } | 	virtual unsigned getCalldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; } | ||||||
|  | 	virtual unsigned getStorageBytes() const override { return m_bytes; } | ||||||
| 	virtual bool isValueType() const override { return true; } | 	virtual bool isValueType() const override { return true; } | ||||||
| 
 | 
 | ||||||
| 	virtual std::string toString() const override { return "bytes" + dev::toString(m_bytes); } | 	virtual std::string toString() const override { return "bytes" + dev::toString(m_bytes); } | ||||||
| @ -275,6 +292,7 @@ public: | |||||||
| 	virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; | 	virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; | ||||||
| 
 | 
 | ||||||
| 	virtual unsigned getCalldataEncodedSize(bool _padded) const { return _padded ? 32 : 1; } | 	virtual unsigned getCalldataEncodedSize(bool _padded) const { return _padded ? 32 : 1; } | ||||||
|  | 	virtual unsigned getStorageBytes() const override { return 1; } | ||||||
| 	virtual bool isValueType() const override { return true; } | 	virtual bool isValueType() const override { return true; } | ||||||
| 
 | 
 | ||||||
| 	virtual std::string toString() const override { return "bool"; } | 	virtual std::string toString() const override { return "bool"; } | ||||||
| @ -348,6 +366,7 @@ public: | |||||||
| 	virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; | 	virtual bool isExplicitlyConvertibleTo(Type const& _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 getStorageBytes() const override { return 20; } | ||||||
| 	virtual bool isValueType() const override { return true; } | 	virtual bool isValueType() const override { return true; } | ||||||
| 	virtual std::string toString() const override; | 	virtual std::string toString() const override; | ||||||
| 
 | 
 | ||||||
| @ -411,6 +430,7 @@ public: | |||||||
| 	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 getSizeOnStack() const override { return 1; } | 	virtual unsigned getSizeOnStack() const override { return 1; } | ||||||
|  | 	virtual unsigned getStorageBytes() const override; | ||||||
| 	virtual std::string toString() const override; | 	virtual std::string toString() const override; | ||||||
| 	virtual bool isValueType() const override { return true; } | 	virtual bool isValueType() const override { return true; } | ||||||
| 
 | 
 | ||||||
| @ -480,7 +500,7 @@ public: | |||||||
| 	virtual bool operator==(Type const& _other) const override; | 	virtual bool operator==(Type const& _other) const override; | ||||||
| 	virtual std::string toString() const override; | 	virtual std::string toString() const override; | ||||||
| 	virtual bool canBeStored() const override { return false; } | 	virtual bool canBeStored() const override { return false; } | ||||||
| 	virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); } | 	virtual u256 getStorageSize() const override; | ||||||
| 	virtual bool canLiveOutsideStorage() const override { return false; } | 	virtual bool canLiveOutsideStorage() const override { return false; } | ||||||
| 	virtual unsigned getSizeOnStack() const override; | 	virtual unsigned getSizeOnStack() const override; | ||||||
| 	virtual MemberList const& getMembers() const override; | 	virtual MemberList const& getMembers() const override; | ||||||
| @ -565,7 +585,7 @@ public: | |||||||
| 	virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } | 	virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } | ||||||
| 	virtual std::string toString() const override { return "void"; } | 	virtual std::string toString() const override { return "void"; } | ||||||
| 	virtual bool canBeStored() const override { return false; } | 	virtual bool canBeStored() const override { return false; } | ||||||
| 	virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } | 	virtual u256 getStorageSize() const override; | ||||||
| 	virtual bool canLiveOutsideStorage() const override { return false; } | 	virtual bool canLiveOutsideStorage() const override { return false; } | ||||||
| 	virtual unsigned getSizeOnStack() const override { return 0; } | 	virtual unsigned getSizeOnStack() const override { return 0; } | ||||||
| }; | }; | ||||||
| @ -585,7 +605,7 @@ public: | |||||||
| 	virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } | 	virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } | ||||||
| 	virtual bool operator==(Type const& _other) const override; | 	virtual bool operator==(Type const& _other) const override; | ||||||
| 	virtual bool canBeStored() const override { return false; } | 	virtual bool canBeStored() const override { return false; } | ||||||
| 	virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } | 	virtual u256 getStorageSize() const override; | ||||||
| 	virtual bool canLiveOutsideStorage() const override { return false; } | 	virtual bool canLiveOutsideStorage() const override { return false; } | ||||||
| 	virtual unsigned getSizeOnStack() const override { return 0; } | 	virtual unsigned getSizeOnStack() const override { return 0; } | ||||||
| 	virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } | 	virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } | ||||||
| @ -611,7 +631,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 	virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } | 	virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } | ||||||
| 	virtual bool canBeStored() const override { return false; } | 	virtual bool canBeStored() const override { return false; } | ||||||
| 	virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } | 	virtual u256 getStorageSize() const override; | ||||||
| 	virtual bool canLiveOutsideStorage() const override { return false; } | 	virtual bool canLiveOutsideStorage() const override { return false; } | ||||||
| 	virtual unsigned getSizeOnStack() const override { return 0; } | 	virtual unsigned getSizeOnStack() const override { return 0; } | ||||||
| 	virtual bool operator==(Type const& _other) const override; | 	virtual bool operator==(Type const& _other) const override; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user