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) | ### 0.5.8 (unreleased) | ||||||
| 
 | 
 | ||||||
| Language Features: | Language Features: | ||||||
|  |  * Code Generation: Implement copying recursive structs from storage to memory. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Compiler Features: | Compiler Features: | ||||||
|  | |||||||
| @ -987,25 +987,42 @@ void CompilerUtils::convertType( | |||||||
| 			switch (typeOnStack.location()) | 			switch (typeOnStack.location()) | ||||||
| 			{ | 			{ | ||||||
| 			case DataLocation::Storage: | 			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>
 | 					// stack: <source ref>
 | ||||||
| 				allocateMemory(typeOnStack.memorySize()); | 					utils.allocateMemory(typeOnStack->memorySize()); | ||||||
| 				m_context << Instruction::SWAP1 << Instruction::DUP2; | 					_context << Instruction::SWAP1 << Instruction::DUP2; | ||||||
| 					// stack: <memory ptr> <source ref> <memory ptr>
 | 					// 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()) | 						if (!member.type->canLiveOutsideStorage()) | ||||||
| 							continue; | 							continue; | ||||||
| 					pair<u256, unsigned> const& offsets = typeOnStack.storageOffsetsOfMember(member.name); | 						pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name); | ||||||
| 					m_context << offsets.first << Instruction::DUP3 << Instruction::ADD; | 						_context << offsets.first << Instruction::DUP3 << Instruction::ADD; | ||||||
| 					m_context << u256(offsets.second); | 						_context << u256(offsets.second); | ||||||
| 					StorageItem(m_context, *member.type).retrieveValue(SourceLocation(), true); | 						StorageItem(_context, *member.type).retrieveValue(SourceLocation(), true); | ||||||
| 					TypePointer targetMemberType = targetType.memberType(member.name); | 						TypePointer targetMemberType = targetType->memberType(member.name); | ||||||
| 						solAssert(!!targetMemberType, "Member not found in target type."); | 						solAssert(!!targetMemberType, "Member not found in target type."); | ||||||
| 					convertType(*member.type, *targetMemberType, true); | 						utils.convertType(*member.type, *targetMemberType, true); | ||||||
| 					storeInMemoryDynamic(*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; | 				break; | ||||||
|  | 			} | ||||||
| 			case DataLocation::CallData: | 			case DataLocation::CallData: | ||||||
| 			{ | 			{ | ||||||
| 				solUnimplementedAssert(!typeOnStack.isDynamicallyEncoded(), ""); | 				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