From 82bcb7e33a4a00be8145588615c0d7a812fd4ce2 Mon Sep 17 00:00:00 2001
From: Lefteris Karapetsas <lefteris@refu.co>
Date: Sun, 1 Feb 2015 02:41:14 +0100
Subject: Code generation for mapping state variable accessor

- Work in progress
---
 ExpressionCompiler.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 67 insertions(+), 8 deletions(-)

(limited to 'ExpressionCompiler.cpp')

diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 7d58ea2e..edd04256 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -823,26 +823,85 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ
 	return length;
 }
 
-unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
-														  Expression const& _expression, unsigned _memoryOffset)
+unsigned ExpressionCompiler::appendTypeCopyToMemory(Type const& _expectedType, TypePointer const& _type,
+													Location const& _location, unsigned _memoryOffset)
 {
-	_expression.accept(*this);
-	appendTypeConversion(*_expression.getType(), _expectedType, true);
+	appendTypeConversion(*_type, _expectedType, true);
 	unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize());
 	if (c_numBytes == 0 || c_numBytes > 32)
 		BOOST_THROW_EXCEPTION(CompilerError()
-							  << errinfo_sourceLocation(_expression.getLocation())
+							  << errinfo_sourceLocation(_location)
 							  << errinfo_comment("Type " + _expectedType.toString() + " not yet supported."));
 	bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING;
 	bool const c_padToWords = true;
 	return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords);
 }
 
+unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
+														  Expression const& _expression,
+														  unsigned _memoryOffset)
+{
+	_expression.accept(*this);
+	return appendTypeCopyToMemory(_expectedType, _expression.getType(), _expression.getLocation(), _memoryOffset);
+}
+
 void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
 {
-	m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType());
-	solAssert(m_currentLValue.isInStorage(), "");
-	m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true);
+	auto mappingType = dynamic_cast<const MappingType*>(_varDecl.getType().get());
+	unsigned sizeOnStack;
+	if (mappingType != nullptr)
+	{
+		// this copies from Compiler::visit(FunctionDefinition..) for argument reading
+		unsigned parameterSize = mappingType->getKeyType()->getSizeOnStack();
+		m_context.adjustStackOffset(parameterSize);
+		m_context.addVariable(_varDecl, parameterSize);
+		// this copies from ExpressionCompiler::visit(IndexAccess .. ) for mapping access
+		TypePointer const& keyType = mappingType->getKeyType();
+		unsigned length = appendTypeCopyToMemory(*keyType, mappingType->getValueType(), Location());
+		solAssert(length == 32, "Mapping key has to take 32 bytes in memory (for now).");
+		// @todo move this once we actually use memory
+		length += CompilerUtils(m_context).storeInMemory(length);
+		m_context << u256(length) << u256(0) << eth::Instruction::SHA3;
+
+		m_currentLValue = LValue(m_context, LValue::STORAGE, *mappingType->getValueType());
+		m_currentLValue.retrieveValue(mappingType->getValueType(), Location(), true);
+
+		unsigned const c_argumentsSize = keyType->getSizeOnStack();
+		unsigned const c_returnValuesSize = mappingType->getValueType()->getSizeOnStack();
+		unsigned const c_localVariablesSize = 0;
+
+		vector<int> stackLayout;
+		stackLayout.push_back(c_returnValuesSize); // target of return address
+		stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments
+		for (unsigned i = 0; i < c_returnValuesSize; ++i)
+			stackLayout.push_back(i);
+		stackLayout += vector<int>(c_localVariablesSize, -1);
+
+		while (stackLayout.back() != int(stackLayout.size() - 1))
+			if (stackLayout.back() < 0)
+			{
+				m_context << eth::Instruction::POP;
+				stackLayout.pop_back();
+			}
+			else
+			{
+				m_context << eth::swapInstruction(stackLayout.size() - stackLayout.back() - 1);
+				swap(stackLayout[stackLayout.back()], stackLayout.back());
+			}
+		//@todo assert that everything is in place now
+
+		m_context << eth::Instruction::JUMP;
+	}
+	else
+	{
+		m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType());
+		solAssert(m_currentLValue.isInStorage(), "");
+		m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true);
+		sizeOnStack = _varDecl.getType()->getSizeOnStack();
+		solAssert(sizeOnStack <= 15, "Stack too deep.");
+		m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP;
+	}
+
 }
 
 ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType,
-- 
cgit v1.2.3