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 | ||||
| { | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
| 	char const* tokenCstr = Token::toString(_typeToken); | ||||
| @ -751,12 +801,7 @@ bool StructType::operator==(Type const& _other) const | ||||
| 
 | ||||
| u256 StructType::getStorageSize() const | ||||
| { | ||||
| 	bigint size = 0; | ||||
| 	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)); | ||||
| 	return max<u256>(1, getMembers().getStorageSize()); | ||||
| } | ||||
| 
 | ||||
| bool StructType::canLiveOutsideStorage() const | ||||
| @ -787,6 +832,7 @@ MemberList const& StructType::getMembers() const | ||||
| 
 | ||||
| u256 StructType::getStorageOffsetOfMember(string const& _name) const | ||||
| { | ||||
| 
 | ||||
| 	//@todo cache member offset?
 | ||||
| 	u256 offset; | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
| 	return string("enum ") + m_enum.getName(); | ||||
| @ -955,6 +1010,13 @@ string FunctionType::toString() const | ||||
| 	return name + ")"; | ||||
| } | ||||
| 
 | ||||
| u256 FunctionType::getStorageSize() const | ||||
| { | ||||
| 	BOOST_THROW_EXCEPTION( | ||||
| 		InternalCompilerError() | ||||
| 			<< errinfo_comment("Storage size of non-storable function type requested.")); | ||||
| } | ||||
| 
 | ||||
| unsigned FunctionType::getSizeOnStack() const | ||||
| { | ||||
| 	Location location = m_location; | ||||
| @ -1077,6 +1139,13 @@ string MappingType::toString() const | ||||
| 	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 | ||||
| { | ||||
| 	if (_other.getCategory() != getCategory()) | ||||
| @ -1085,6 +1154,13 @@ bool TypeType::operator==(Type const& _other) const | ||||
| 	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 | ||||
| { | ||||
| 	// We need to lazy-initialize it because of recursive references.
 | ||||
| @ -1122,6 +1198,13 @@ ModifierType::ModifierType(const ModifierDefinition& _modifier) | ||||
| 	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 | ||||
| { | ||||
| 	if (_other.getCategory() != getCategory()) | ||||
|  | ||||
							
								
								
									
										30
									
								
								Types.h
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								Types.h
									
									
									
									
									
								
							| @ -60,12 +60,19 @@ public: | ||||
| 				return it.second; | ||||
| 		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 end() const { return m_memberTypes.end(); } | ||||
| 
 | ||||
| private: | ||||
| 	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
 | ||||
| 	static TypePointer commonType(TypePointer const& _a, TypePointer const& _b); | ||||
| 
 | ||||
| 	/// Calculates the
 | ||||
| 
 | ||||
| 	virtual Category getCategory() const = 0; | ||||
| 	virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } | ||||
| 	virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const | ||||
| @ -126,9 +135,15 @@ public: | ||||
| 	unsigned getCalldataEncodedSize() const { return getCalldataEncodedSize(true); } | ||||
| 	/// @returns true if the type is dynamically encoded in calldata
 | ||||
| 	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,
 | ||||
| 	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.
 | ||||
| 	virtual bool canBeStored() const { return true; } | ||||
| 	/// 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 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 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 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 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 unsigned getCalldataEncodedSize(bool _padded) const { return _padded ? 32 : 1; } | ||||
| 	virtual unsigned getStorageBytes() const override { return 1; } | ||||
| 	virtual bool isValueType() const override { return true; } | ||||
| 
 | ||||
| 	virtual std::string toString() const override { return "bool"; } | ||||
| @ -348,6 +366,7 @@ public: | ||||
| 	virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; | ||||
| 	virtual TypePointer unaryOperatorResult(Token::Value _operator) 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 std::string toString() const override; | ||||
| 
 | ||||
| @ -411,6 +430,7 @@ public: | ||||
| 	virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; | ||||
| 	virtual bool operator==(Type const& _other) const override; | ||||
| 	virtual unsigned getSizeOnStack() const override { return 1; } | ||||
| 	virtual unsigned getStorageBytes() const override; | ||||
| 	virtual std::string toString() const override; | ||||
| 	virtual bool isValueType() const override { return true; } | ||||
| 
 | ||||
| @ -480,7 +500,7 @@ public: | ||||
| 	virtual bool operator==(Type const& _other) const override; | ||||
| 	virtual std::string toString() const override; | ||||
| 	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 unsigned getSizeOnStack() 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 std::string toString() const override { return "void"; } | ||||
| 	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 unsigned getSizeOnStack() const override { return 0; } | ||||
| }; | ||||
| @ -585,7 +605,7 @@ public: | ||||
| 	virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } | ||||
| 	virtual bool operator==(Type const& _other) const override; | ||||
| 	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 unsigned getSizeOnStack() const override { return 0; } | ||||
| 	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 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 unsigned getSizeOnStack() const override { return 0; } | ||||
| 	virtual bool operator==(Type const& _other) const override; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user