mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #6445 from ethereum/circularStorageMemoryCopy
Implemented copying recursive structs from storage to memory.
This commit is contained in:
		
						commit
						1b7878cfde
					
				| @ -1,6 +1,7 @@ | ||||
| ### 0.5.8 (unreleased) | ||||
| 
 | ||||
| Language Features: | ||||
|  * Code Generation: Implement copying recursive structs from storage to memory. | ||||
| 
 | ||||
| 
 | ||||
| Compiler Features: | ||||
|  | ||||
| @ -987,25 +987,42 @@ void CompilerUtils::convertType( | ||||
| 			switch (typeOnStack.location()) | ||||
| 			{ | ||||
| 			case DataLocation::Storage: | ||||
| 			{ | ||||
| 				auto conversionImpl = [ | ||||
| 					typeOnStack = dynamic_pointer_cast<StructType const>(_typeOnStack.shared_from_this()), | ||||
| 					targetType = dynamic_pointer_cast<StructType const>(targetType.shared_from_this()) | ||||
| 				](CompilerContext& _context) { | ||||
| 					CompilerUtils utils(_context); | ||||
| 					// stack: <source ref>
 | ||||
| 				allocateMemory(typeOnStack.memorySize()); | ||||
| 				m_context << Instruction::SWAP1 << Instruction::DUP2; | ||||
| 					utils.allocateMemory(typeOnStack->memorySize()); | ||||
| 					_context << Instruction::SWAP1 << Instruction::DUP2; | ||||
| 					// stack: <memory ptr> <source ref> <memory ptr>
 | ||||
| 				for (auto const& member: typeOnStack.members(nullptr)) | ||||
| 					for (auto const& member: typeOnStack->members(nullptr)) | ||||
| 					{ | ||||
| 						if (!member.type->canLiveOutsideStorage()) | ||||
| 							continue; | ||||
| 					pair<u256, unsigned> const& offsets = typeOnStack.storageOffsetsOfMember(member.name); | ||||
| 					m_context << offsets.first << Instruction::DUP3 << Instruction::ADD; | ||||
| 					m_context << u256(offsets.second); | ||||
| 					StorageItem(m_context, *member.type).retrieveValue(SourceLocation(), true); | ||||
| 					TypePointer targetMemberType = targetType.memberType(member.name); | ||||
| 						pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name); | ||||
| 						_context << offsets.first << Instruction::DUP3 << Instruction::ADD; | ||||
| 						_context << u256(offsets.second); | ||||
| 						StorageItem(_context, *member.type).retrieveValue(SourceLocation(), true); | ||||
| 						TypePointer targetMemberType = targetType->memberType(member.name); | ||||
| 						solAssert(!!targetMemberType, "Member not found in target type."); | ||||
| 					convertType(*member.type, *targetMemberType, true); | ||||
| 					storeInMemoryDynamic(*targetMemberType, true); | ||||
| 						utils.convertType(*member.type, *targetMemberType, true); | ||||
| 						utils.storeInMemoryDynamic(*targetMemberType, true); | ||||
| 					} | ||||
| 				m_context << Instruction::POP << Instruction::POP; | ||||
| 					_context << Instruction::POP << Instruction::POP; | ||||
| 				}; | ||||
| 				if (typeOnStack.recursive()) | ||||
| 					m_context.callLowLevelFunction( | ||||
| 						"$convertRecursiveArrayStorageToMemory_" + typeOnStack.identifier() + "_to_" + targetType.identifier(), | ||||
| 						1, | ||||
| 						1, | ||||
| 						conversionImpl | ||||
| 					); | ||||
| 				else | ||||
| 					conversionImpl(m_context); | ||||
| 				break; | ||||
| 			} | ||||
| 			case DataLocation::CallData: | ||||
| 			{ | ||||
| 				solUnimplementedAssert(!typeOnStack.isDynamicallyEncoded(), ""); | ||||
|  | ||||
| @ -0,0 +1,20 @@ | ||||
| contract CopyTest { | ||||
| 	struct Tree { | ||||
| 		Tree[] children; | ||||
| 	} | ||||
| 	Tree storageTree; | ||||
| 
 | ||||
| 	constructor() public { | ||||
| 		storageTree.children.length = 2; | ||||
| 		storageTree.children[0].children.length = 23; | ||||
| 		storageTree.children[1].children.length = 42; | ||||
| 	} | ||||
| 
 | ||||
| 	function run() public returns (uint256, uint256, uint256) { | ||||
| 		Tree memory memoryTree; | ||||
| 		memoryTree = storageTree; | ||||
| 		return (memoryTree.children.length, memoryTree.children[0].children.length, memoryTree.children[1].children.length); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // run() -> 2, 23, 42 | ||||
| @ -0,0 +1,46 @@ | ||||
| contract CopyTest { | ||||
| 	struct Tree { | ||||
| 		uint256 data; | ||||
| 		Tree[] children; | ||||
| 	} | ||||
| 	Tree storageTree; | ||||
| 
 | ||||
| 	constructor() public { | ||||
| 		storageTree.data = 0x42; | ||||
| 		storageTree.children.length = 2; | ||||
| 		storageTree.children[0].data = 0x4200; | ||||
| 		storageTree.children[1].data = 0x4201; | ||||
| 		storageTree.children[0].children.length = 3; | ||||
| 		for (uint i = 0; i < 3; i++) | ||||
| 		    storageTree.children[0].children[i].data = 0x420000 + i; | ||||
| 		storageTree.children[1].children.length = 4; | ||||
| 		for (uint i = 0; i < 4; i++) | ||||
| 		    storageTree.children[1].children[i].data = 0x420100 + i; | ||||
| 	} | ||||
| 
 | ||||
| 	function countData(Tree memory tree) internal returns (uint256 c) { | ||||
| 	    c = 1; | ||||
| 	    for (uint i = 0; i < tree.children.length; i++) { | ||||
| 	        c += countData(tree.children[i]); | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
| 	function copyFromTree(Tree memory tree, uint256[] memory data, uint256 offset) internal returns (uint256) { | ||||
| 	    data[offset++] = tree.data; | ||||
| 	    for (uint i = 0; i < tree.children.length; i++) { | ||||
| 	        offset = copyFromTree(tree.children[i], data, offset); | ||||
| 	    } | ||||
| 	    return offset; | ||||
| 	} | ||||
| 
 | ||||
| 	function run() public returns (uint256[] memory) { | ||||
| 		Tree memory memoryTree; | ||||
| 		memoryTree = storageTree; | ||||
| 		uint256 length = countData(memoryTree); | ||||
| 		uint256[] memory result = new uint256[](length); | ||||
| 		copyFromTree(memoryTree, result, 0); | ||||
| 		return result; | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // run() -> 0x20, 10, 0x42, 0x4200, 0x420000, 0x420001, 0x420002, 0x4201, 0x420100, 0x420101, 0x420102, 0x420103 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user