Merge remote-tracking branch 'ethereum/develop' into sol_overloadingFunctions

Conflicts:
	libsolidity/Types.cpp
This commit is contained in:
chriseth 2015-04-15 17:43:23 +02:00
commit c7b428fdb1
6 changed files with 72 additions and 30 deletions

View File

@ -27,7 +27,6 @@ endif()
target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} devcrypto)
install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )

View File

@ -83,6 +83,7 @@ public:
/// Converts an offset relative to the current stack height to a value that can be used later
/// with baseToCurrentStackOffset to point to the same stack element.
unsigned currentToBaseStackOffset(unsigned _offset) const;
/// @returns pair of slot and byte offset of the value inside this slot.
std::pair<u256, unsigned> getStorageLocationOfVariable(Declaration const& _declaration) const;
/// Appends a JUMPI instruction to a new tag and @returns the tag

View File

@ -157,8 +157,12 @@ void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
void CompilerUtils::popStackElement(Type const& _type)
{
unsigned const size = _type.getSizeOnStack();
for (unsigned i = 0; i < size; ++i)
popStackSlots(_type.getSizeOnStack());
}
void CompilerUtils::popStackSlots(size_t _amount)
{
for (size_t i = 0; i < _amount; ++i)
m_context << eth::Instruction::POP;
}

View File

@ -79,6 +79,8 @@ public:
void copyToStackTop(unsigned _stackDepth, unsigned _itemSize);
/// Removes the current value from the top of the stack.
void popStackElement(Type const& _type);
/// Removes element from the top of the stack _amount times.
void popStackSlots(size_t _amount);
template <class T>
static unsigned getSizeOnStack(std::vector<T> const& _variables);

View File

@ -60,57 +60,82 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
FunctionType accessorType(_varDecl);
unsigned length = 0;
TypePointers const& paramTypes = accessorType.getParameterTypes();
// move arguments to memory
for (TypePointer const& paramType: boost::adaptors::reverse(paramTypes))
length += CompilerUtils(m_context).storeInMemory(length, *paramType, true);
// retrieve the position of the variable
auto const& location = m_context.getStorageLocationOfVariable(_varDecl);
m_context << location.first;
m_context << location.first << u256(location.second);
TypePointer returnType = _varDecl.getType();
for (TypePointer const& paramType: paramTypes)
for (size_t i = 0; i < paramTypes.size(); ++i)
{
// move offset to memory
CompilerUtils(m_context).storeInMemory(length);
unsigned argLen = paramType->getCalldataEncodedSize();
length -= argLen;
m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3;
returnType = dynamic_cast<MappingType const&>(*returnType).getValueType();
if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
{
// pop offset
m_context << eth::Instruction::POP;
// move storage offset to memory.
CompilerUtils(m_context).storeInMemory(32);
// move key to memory.
CompilerUtils(m_context).copyToStackTop(paramTypes.size() - i, 1);
CompilerUtils(m_context).storeInMemory(0);
m_context << u256(64) << u256(0) << eth::Instruction::SHA3;
// push offset
m_context << u256(0);
returnType = mappingType->getValueType();
}
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
{
// pop offset
m_context << eth::Instruction::POP;
CompilerUtils(m_context).copyToStackTop(paramTypes.size() - i + 1, 1);
ArrayUtils(m_context).accessIndex(*arrayType);
returnType = arrayType->getBaseType();
}
else
solAssert(false, "Index access is allowed only for \"mapping\" and \"array\" types.");
}
// remove index arguments.
if (paramTypes.size() == 1)
m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::SWAP1;
else if (paramTypes.size() >= 2)
{
m_context << eth::swapInstruction(paramTypes.size());
m_context << eth::Instruction::POP;
m_context << eth::swapInstruction(paramTypes.size());
CompilerUtils(m_context).popStackSlots(paramTypes.size() - 1);
}
unsigned retSizeOnStack = 0;
solAssert(accessorType.getReturnParameterTypes().size() >= 1, "");
if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get()))
{
// remove offset
m_context << eth::Instruction::POP;
auto const& names = accessorType.getReturnParameterNames();
auto const& types = accessorType.getReturnParameterTypes();
// struct
for (size_t i = 0; i < names.size(); ++i)
{
if (types[i]->getCategory() == Type::Category::Mapping)
if (types[i]->getCategory() == Type::Category::Mapping || types[i]->getCategory() == Type::Category::Array)
continue;
pair<u256, unsigned> const& offsets = structType->getStorageOffsetsOfMember(names[i]);
m_context << eth::Instruction::DUP1 << u256(offsets.first) << eth::Instruction::ADD << u256(offsets.second);
StorageItem(m_context, *types[i]).retrieveValue(SourceLocation(), true);
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 is not yet implemented.");
m_context << eth::Instruction::SWAP1;
retSizeOnStack += types[i]->getSizeOnStack();
}
// remove slot
m_context << eth::Instruction::POP;
}
else
{
// simple value
solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
m_context << u256(location.second);
StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true);
retSizeOnStack = returnType->getSizeOnStack();
}
solAssert(retSizeOnStack <= 15, "Stack too deep.");
solAssert(retSizeOnStack <= 15, "Stack is too deep.");
m_context << eth::dupInstruction(retSizeOnStack + 1);
m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction);
}
@ -758,7 +783,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
appendTypeMoveToMemory(IntegerType(256));
m_context << u256(0) << eth::Instruction::SHA3;
m_context << u256(0);
setLValueToStorageItem( _indexAccess);
setLValueToStorageItem(_indexAccess);
}
else if (baseType.getCategory() == Type::Category::Array)
{
@ -1038,7 +1063,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
else
// send all gas except the amount needed to execute "SUB" and "CALL"
// @todo this retains too much gas for now, needs to be fine-tuned.
m_context << u256(50 + (_functionType.valueSet() ? 9000 : 0)) << eth::Instruction::GAS << eth::Instruction::SUB;
m_context << u256(50 + (_functionType.valueSet() ? 9000 : 0) + 25000) << eth::Instruction::GAS << eth::Instruction::SUB;
m_context << eth::Instruction::CALL;
auto tag = m_context.appendConditionalJump();
m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.

View File

@ -1000,15 +1000,26 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
FunctionType::FunctionType(VariableDeclaration const& _varDecl):
m_location(Location::External), m_isConstant(true), m_declaration(&_varDecl)
{
TypePointers params;
TypePointers paramTypes;
vector<string> paramNames;
auto returnType = _varDecl.getType();
while (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
while (true)
{
params.push_back(mappingType->getKeyType());
paramNames.push_back("");
returnType = mappingType->getValueType();
if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
{
paramTypes.push_back(mappingType->getKeyType());
paramNames.push_back("");
returnType = mappingType->getValueType();
}
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
{
returnType = arrayType->getBaseType();
paramNames.push_back("");
paramTypes.push_back(make_shared<IntegerType>(256));
}
else
break;
}
TypePointers retParams;
@ -1016,7 +1027,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
if (auto structType = dynamic_cast<StructType const*>(returnType.get()))
{
for (auto const& member: structType->getMembers())
if (member.type->canLiveOutsideStorage())
if (member.type->getCategory() != Category::Mapping && member.type->getCategory() != Category::Array)
{
retParamNames.push_back(member.name);
retParams.push_back(member.type);
@ -1028,7 +1039,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
retParamNames.push_back("");
}
swap(params, m_parameterTypes);
swap(paramTypes, m_parameterTypes);
swap(paramNames, m_parameterNames);
swap(retParams, m_returnParameterTypes);
swap(retParamNames, m_returnParameterNames);