mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Helper functions to access memory.
This commit is contained in:
		
							parent
							
								
									130ff85e85
								
							
						
					
					
						commit
						373f0da267
					
				
							
								
								
									
										17
									
								
								Compiler.cpp
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								Compiler.cpp
									
									
									
									
									
								
							| @ -130,7 +130,6 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b | ||||
| { | ||||
| 	// We do not check the calldata size, everything is zero-padded.
 | ||||
| 	unsigned dataOffset = 1; | ||||
| 	eth::Instruction load = _fromMemory ? eth::Instruction::MLOAD : eth::Instruction::CALLDATALOAD; | ||||
| 
 | ||||
| 	//@todo this can be done more efficiently, saving some CALLDATALOAD calls
 | ||||
| 	for (ASTPointer<VariableDeclaration> const& var: _function.getParameters()) | ||||
| @ -140,14 +139,8 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b | ||||
| 			BOOST_THROW_EXCEPTION(CompilerError() | ||||
| 								  << errinfo_sourceLocation(var->getLocation()) | ||||
| 								  << errinfo_comment("Type " + var->getType()->toString() + " not yet supported.")); | ||||
| 		if (numBytes == 32) | ||||
| 			m_context << u256(dataOffset) << load; | ||||
| 		else if (var->getType()->getCategory() == Type::Category::STRING) | ||||
| 			m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::DUP1 | ||||
| 					  << u256(dataOffset) << load << eth::Instruction::DIV << eth::Instruction::MUL; | ||||
| 		else | ||||
| 			m_context << (u256(1) << ((32 - numBytes) * 8)) << u256(dataOffset) | ||||
| 					  << load << eth::Instruction::DIV; | ||||
| 		bool leftAligned = var->getType()->getCategory() == Type::Category::STRING; | ||||
| 		CompilerUtils(m_context).loadFromMemory(dataOffset, numBytes, leftAligned, !_fromMemory); | ||||
| 		dataOffset += numBytes; | ||||
| 	} | ||||
| 	return dataOffset; | ||||
| @ -168,10 +161,8 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) | ||||
| 								  << errinfo_sourceLocation(parameters[i]->getLocation()) | ||||
| 								  << errinfo_comment("Type " + paramType.toString() + " not yet supported.")); | ||||
| 		CompilerUtils(m_context).copyToStackTop(stackDepth, paramType); | ||||
| 		if (numBytes != 32) | ||||
| 			if (paramType.getCategory() != Type::Category::STRING) | ||||
| 				m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL; | ||||
| 		m_context << u256(dataOffset) << eth::Instruction::MSTORE; | ||||
| 		bool const leftAligned = paramType.getCategory() == Type::Category::STRING; | ||||
| 		CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned); | ||||
| 		stackDepth -= paramType.getSizeOnStack(); | ||||
| 		dataOffset += numBytes; | ||||
| 	} | ||||
|  | ||||
| @ -31,6 +31,36 @@ namespace dev | ||||
| namespace solidity | ||||
| { | ||||
| 
 | ||||
| void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, bool _fromCalldata) | ||||
| { | ||||
| 	eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD; | ||||
| 	if (asserts(0 < _bytes && _bytes <= 32)) | ||||
| 		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory load of 0 or more than 32 bytes requested.")); | ||||
| 	if (_bytes == 32) | ||||
| 		m_context << u256(_offset) << load; | ||||
| 	else | ||||
| 	{ | ||||
| 		// load data and add leading or trailing zeros by dividing/multiplying depending on alignment
 | ||||
| 		u256 shiftFactor = u256(1) << ((32 - _bytes) * 8); | ||||
| 		m_context << shiftFactor; | ||||
| 		if (_leftAligned) | ||||
| 			m_context << eth::Instruction::DUP1; | ||||
| 		m_context << u256(_offset) << load << eth::Instruction::DIV; | ||||
| 		if (_leftAligned) | ||||
| 			m_context << eth::Instruction::MUL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftAligned) | ||||
| { | ||||
| 	if (asserts(0 < _bytes && _bytes <= 32)) | ||||
| 		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory store of 0 or more than 32 bytes requested.")); | ||||
| 	if (_bytes != 32 && !_leftAligned) | ||||
| 		// shift the value accordingly before storing
 | ||||
| 		m_context << (u256(1) << ((32 - _bytes) * 8)) << eth::Instruction::MUL; | ||||
| 	m_context << u256(_offset) << eth::Instruction::MSTORE; | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) | ||||
| { | ||||
| 	unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable)); | ||||
|  | ||||
| @ -35,6 +35,18 @@ class CompilerUtils | ||||
| public: | ||||
| 	CompilerUtils(CompilerContext& _context): m_context(_context) {} | ||||
| 
 | ||||
| 	/// Loads data from memory to the stack.
 | ||||
| 	/// @param _offset offset in memory (or calldata)
 | ||||
| 	/// @param _bytes number of bytes to load
 | ||||
| 	/// @param _leftAligned if true, store left aligned on stack (otherwise right aligned)
 | ||||
| 	/// @param _fromCalldata if true, load from calldata, not from memory
 | ||||
| 	void loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, bool _fromCalldata = false); | ||||
| 	/// Stores data from stack in memory.
 | ||||
| 	/// @param _offset offset in memory
 | ||||
| 	/// @param _bytes number of bytes to store
 | ||||
| 	/// @param _leftAligned if true, data is left aligned on stack (otherwise right aligned)
 | ||||
| 	void storeInMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false); | ||||
| 
 | ||||
| 	/// Moves the value that is at the top of the stack to a stack variable.
 | ||||
| 	void moveToStackVariable(VariableDeclaration const& _variable); | ||||
| 	/// Copies a variable of type @a _type from a stack depth of @a _stackDepth to the top of the stack.
 | ||||
|  | ||||
| @ -225,15 +225,14 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) | ||||
| 					BOOST_THROW_EXCEPTION(CompilerError() | ||||
| 										  << errinfo_sourceLocation(arguments[i]->getLocation()) | ||||
| 										  << errinfo_comment("Type " + type.toString() + " not yet supported.")); | ||||
| 				if (numBytes != 32) | ||||
| 					if (type.getCategory() != Type::Category::STRING) | ||||
| 						m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL; | ||||
| 				m_context << u256(dataOffset) << eth::Instruction::MSTORE; | ||||
| 				bool const leftAligned = type.getCategory() == Type::Category::STRING; | ||||
| 				CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned); | ||||
| 				dataOffset += numBytes; | ||||
| 			} | ||||
| 			//@todo only return the first return value for now
 | ||||
| 			unsigned retSize = function.getReturnParameterTypes().empty() ? 0 | ||||
| 									: function.getReturnParameterTypes().front()->getCalldataEncodedSize(); | ||||
| 			Type const* firstType = function.getReturnParameterTypes().empty() ? nullptr : | ||||
| 									function.getReturnParameterTypes().front().get(); | ||||
| 			unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0; | ||||
| 			// CALL arguments: outSize, outOff, inSize, inOff, value, addr, gas (stack top)
 | ||||
| 			m_context << u256(retSize) << u256(0) << u256(dataOffset) << u256(0) << u256(0); | ||||
| 			_functionCall.getExpression().accept(*this); // pushes addr and function index
 | ||||
| @ -241,17 +240,10 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) | ||||
| 					  << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB | ||||
| 					  << eth::Instruction::CALL | ||||
| 					  << eth::Instruction::POP; // @todo do not ignore failure indicator
 | ||||
| 			if (retSize == 32) | ||||
| 				m_context << u256(0) << eth::Instruction::MLOAD; | ||||
| 			else if (retSize > 0) | ||||
| 			if (retSize > 0) | ||||
| 			{ | ||||
| 				if (function.getReturnParameterTypes().front()->getCategory() == Type::Category::STRING) | ||||
| 					m_context << (u256(1) << ((32 - retSize) * 8)) << eth::Instruction::DUP1 | ||||
| 							  << u256(0) << eth::Instruction::MLOAD | ||||
| 							  << eth::Instruction::DIV << eth::Instruction::MUL; | ||||
| 				else | ||||
| 					m_context << (u256(1) << ((32 - retSize) * 8)) | ||||
| 							  << u256(0) << eth::Instruction::MLOAD << eth::Instruction::DIV; | ||||
| 				bool const leftAligned = firstType->getCategory() == Type::Category::STRING; | ||||
| 				CompilerUtils(m_context).loadFromMemory(0, retSize, leftAligned); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| @ -275,7 +267,8 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) | ||||
| 			arguments.front()->accept(*this); | ||||
| 			appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); | ||||
| 			// @todo move this once we actually use memory
 | ||||
| 			m_context << u256(0) << eth::Instruction::MSTORE << u256(32) << u256(0) << eth::Instruction::SHA3; | ||||
| 			CompilerUtils(m_context).storeInMemory(0); | ||||
| 			m_context << u256(32) << u256(0) << eth::Instruction::SHA3; | ||||
| 			break; | ||||
| 		case Location::ECRECOVER: | ||||
| 		case Location::SHA256: | ||||
| @ -291,13 +284,13 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) | ||||
| 				arguments[i]->accept(*this); | ||||
| 				appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i], true); | ||||
| 				// @todo move this once we actually use memory
 | ||||
| 				m_context << u256(i * 32) << eth::Instruction::MSTORE; | ||||
| 				CompilerUtils(m_context).storeInMemory(i * 32); | ||||
| 			} | ||||
| 			m_context << u256(32) << u256(0) << u256(arguments.size() * 32) << u256(0) << u256(0) | ||||
| 					  << contractAddress << u256(500) //@todo determine actual gas requirement
 | ||||
| 					  << eth::Instruction::CALL | ||||
| 					  << eth::Instruction::POP | ||||
| 					  << u256(0) << eth::Instruction::MLOAD; | ||||
| 					  << eth::Instruction::POP; | ||||
| 			CompilerUtils(m_context).loadFromMemory(0); | ||||
| 			break; | ||||
| 		} | ||||
| 		default: | ||||
| @ -381,7 +374,8 @@ bool ExpressionCompiler::visit(IndexAccess& _indexAccess) | ||||
| 						 *dynamic_cast<MappingType const&>(*_indexAccess.getBaseExpression().getType()).getKeyType(), | ||||
| 						 true); | ||||
| 	// @todo move this once we actually use memory
 | ||||
| 	m_context << u256(32) << eth::Instruction::MSTORE << u256(0) << eth::Instruction::MSTORE; | ||||
| 	CompilerUtils(m_context).storeInMemory(0); | ||||
| 	CompilerUtils(m_context).storeInMemory(32); | ||||
| 	m_context << u256(64) << u256(0) << eth::Instruction::SHA3; | ||||
| 
 | ||||
| 	m_currentLValue = LValue(m_context, LValue::STORAGE, *_indexAccess.getType()); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user