mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'upstream/develop' into evmjit
This commit is contained in:
commit
529865196f
12
AST.cpp
12
AST.cpp
@ -603,7 +603,17 @@ void MemberAccess::checkTypeRequirements()
|
|||||||
if (!m_type)
|
if (!m_type)
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
|
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
|
||||||
"visible in " + type.toString()));
|
"visible in " + type.toString()));
|
||||||
m_isLValue = (type.getCategory() == Type::Category::Struct);
|
// This should probably move somewhere else.
|
||||||
|
if (type.getCategory() == Type::Category::Struct)
|
||||||
|
m_isLValue = true;
|
||||||
|
else if (type.getCategory() == Type::Category::Array)
|
||||||
|
{
|
||||||
|
auto const& arrayType(dynamic_cast<ArrayType const&>(type));
|
||||||
|
m_isLValue = (*m_memberName == "length" &&
|
||||||
|
arrayType.getLocation() != ArrayType::Location::CallData && arrayType.isDynamicallySized());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_isLValue = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexAccess::checkTypeRequirements()
|
void IndexAccess::checkTypeRequirements()
|
||||||
|
@ -40,7 +40,12 @@ void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaratio
|
|||||||
void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
|
void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
|
||||||
{
|
{
|
||||||
m_stateVariables[&_declaration] = m_stateVariablesSize;
|
m_stateVariables[&_declaration] = m_stateVariablesSize;
|
||||||
m_stateVariablesSize += _declaration.getType()->getStorageSize();
|
bigint newSize = bigint(m_stateVariablesSize) + _declaration.getType()->getStorageSize();
|
||||||
|
if (newSize >= bigint(1) << 256)
|
||||||
|
BOOST_THROW_EXCEPTION(TypeError()
|
||||||
|
<< errinfo_comment("State variable does not fit in storage.")
|
||||||
|
<< errinfo_sourceLocation(_declaration.getLocation()));
|
||||||
|
m_stateVariablesSize = u256(newSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerContext::startFunction(Declaration const& _function)
|
void CompilerContext::startFunction(Declaration const& _function)
|
||||||
|
@ -534,19 +534,25 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
solAssert(member == "length", "Illegal array member.");
|
solAssert(member == "length", "Illegal array member.");
|
||||||
auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.getExpression().getType());
|
auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.getExpression().getType());
|
||||||
solAssert(type.isByteArray(), "Non byte arrays not yet implemented here.");
|
if (!type.isDynamicallySized())
|
||||||
switch (type.getLocation())
|
|
||||||
{
|
{
|
||||||
case ArrayType::Location::CallData:
|
CompilerUtils(m_context).popStackElement(type);
|
||||||
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
|
m_context << type.getLength();
|
||||||
break;
|
|
||||||
case ArrayType::Location::Storage:
|
|
||||||
m_context << eth::Instruction::SLOAD;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
solAssert(false, "Unsupported array location.");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
switch (type.getLocation())
|
||||||
|
{
|
||||||
|
case ArrayType::Location::CallData:
|
||||||
|
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
|
||||||
|
break;
|
||||||
|
case ArrayType::Location::Storage:
|
||||||
|
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _memberAccess.getType());
|
||||||
|
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
solAssert(false, "Unsupported array location.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -559,19 +565,55 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
_indexAccess.getBaseExpression().accept(*this);
|
_indexAccess.getBaseExpression().accept(*this);
|
||||||
|
|
||||||
Type const& baseType = *_indexAccess.getBaseExpression().getType();
|
Type const& baseType = *_indexAccess.getBaseExpression().getType();
|
||||||
solAssert(baseType.getCategory() == Type::Category::Mapping, "");
|
if (baseType.getCategory() == Type::Category::Mapping)
|
||||||
Type const& keyType = *dynamic_cast<MappingType const&>(baseType).getKeyType();
|
{
|
||||||
m_context << u256(0);
|
Type const& keyType = *dynamic_cast<MappingType const&>(baseType).getKeyType();
|
||||||
solAssert(_indexAccess.getIndexExpression(), "Index expression expected.");
|
m_context << u256(0);
|
||||||
appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression());
|
solAssert(_indexAccess.getIndexExpression(), "Index expression expected.");
|
||||||
solAssert(baseType.getSizeOnStack() == 1,
|
appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression());
|
||||||
"Unexpected: Not exactly one stack slot taken by subscriptable expression.");
|
solAssert(baseType.getSizeOnStack() == 1,
|
||||||
m_context << eth::Instruction::SWAP1;
|
"Unexpected: Not exactly one stack slot taken by subscriptable expression.");
|
||||||
appendTypeMoveToMemory(IntegerType(256));
|
m_context << eth::Instruction::SWAP1;
|
||||||
m_context << u256(0) << eth::Instruction::SHA3;
|
appendTypeMoveToMemory(IntegerType(256));
|
||||||
|
m_context << u256(0) << eth::Instruction::SHA3;
|
||||||
|
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
|
||||||
|
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
|
||||||
|
}
|
||||||
|
else if (baseType.getCategory() == Type::Category::Array)
|
||||||
|
{
|
||||||
|
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(baseType);
|
||||||
|
solAssert(arrayType.getLocation() == ArrayType::Location::Storage,
|
||||||
|
"TODO: Index acces only implemented for storage arrays.");
|
||||||
|
solAssert(!arrayType.isByteArray(), "TODO: Index acces not implemented for byte arrays.");
|
||||||
|
solAssert(_indexAccess.getIndexExpression(), "Index expression expected.");
|
||||||
|
|
||||||
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
|
_indexAccess.getIndexExpression()->accept(*this);
|
||||||
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
|
// retrieve length
|
||||||
|
if (arrayType.isDynamicallySized())
|
||||||
|
m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD;
|
||||||
|
else
|
||||||
|
m_context << arrayType.getLength();
|
||||||
|
// stack: <base_ref> <index> <length>
|
||||||
|
// check out-of-bounds access
|
||||||
|
m_context << eth::Instruction::DUP2 << eth::Instruction::LT;
|
||||||
|
eth::AssemblyItem legalAccess = m_context.appendConditionalJump();
|
||||||
|
// out-of-bounds access throws exception (just STOP for now)
|
||||||
|
m_context << eth::Instruction::STOP;
|
||||||
|
|
||||||
|
m_context << legalAccess;
|
||||||
|
// stack: <base_ref> <index>
|
||||||
|
m_context << arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL;
|
||||||
|
if (arrayType.isDynamicallySized())
|
||||||
|
{
|
||||||
|
m_context << eth::Instruction::SWAP1;
|
||||||
|
CompilerUtils(m_context).computeHashStatic();
|
||||||
|
}
|
||||||
|
m_context << eth::Instruction::ADD;
|
||||||
|
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
|
||||||
|
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
solAssert(false, "Index access only allowed for mappings or arrays.");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1049,7 +1091,7 @@ void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _
|
|||||||
{
|
{
|
||||||
case LValueType::Stack:
|
case LValueType::Stack:
|
||||||
{
|
{
|
||||||
unsigned stackPos = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset));
|
unsigned stackPos = m_context->baseToCurrentStackOffset(m_baseStackOffset);
|
||||||
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
|
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Stack too deep."));
|
<< errinfo_comment("Stack too deep."));
|
||||||
@ -1098,7 +1140,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co
|
|||||||
{
|
{
|
||||||
case LValueType::Stack:
|
case LValueType::Stack:
|
||||||
{
|
{
|
||||||
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1;
|
unsigned stackDiff = m_context->baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1;
|
||||||
if (stackDiff > 16)
|
if (stackDiff > 16)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Stack too deep."));
|
<< errinfo_comment("Stack too deep."));
|
||||||
@ -1201,7 +1243,7 @@ void ExpressionCompiler::LValue::setToZero(Location const& _location) const
|
|||||||
{
|
{
|
||||||
case LValueType::Stack:
|
case LValueType::Stack:
|
||||||
{
|
{
|
||||||
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset));
|
unsigned stackDiff = m_context->baseToCurrentStackOffset(m_baseStackOffset);
|
||||||
if (stackDiff > 16)
|
if (stackDiff > 16)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Stack too deep."));
|
<< errinfo_comment("Stack too deep."));
|
||||||
|
19
Types.cpp
19
Types.cpp
@ -555,6 +555,19 @@ bool ArrayType::operator==(Type const& _other) const
|
|||||||
return other.m_location == m_location;
|
return other.m_location == m_location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u256 ArrayType::getStorageSize() const
|
||||||
|
{
|
||||||
|
if (isDynamicallySized())
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bigint size = bigint(getLength()) * getBaseType()->getStorageSize();
|
||||||
|
if (size >= bigint(1) << 256)
|
||||||
|
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Array too large for storage."));
|
||||||
|
return max<u256>(1, u256(size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned ArrayType::getSizeOnStack() const
|
unsigned ArrayType::getSizeOnStack() const
|
||||||
{
|
{
|
||||||
if (m_location == Location::CallData)
|
if (m_location == Location::CallData)
|
||||||
@ -665,10 +678,12 @@ bool StructType::operator==(Type const& _other) const
|
|||||||
|
|
||||||
u256 StructType::getStorageSize() const
|
u256 StructType::getStorageSize() const
|
||||||
{
|
{
|
||||||
u256 size = 0;
|
bigint size = 0;
|
||||||
for (pair<string, TypePointer> const& member: getMembers())
|
for (pair<string, TypePointer> const& member: getMembers())
|
||||||
size += member.second->getStorageSize();
|
size += member.second->getStorageSize();
|
||||||
return max<u256>(1, size);
|
if (size >= bigint(1) << 256)
|
||||||
|
BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Struct too large for storage."));
|
||||||
|
return max<u256>(1, u256(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StructType::canLiveOutsideStorage() const
|
bool StructType::canLiveOutsideStorage() const
|
||||||
|
1
Types.h
1
Types.h
@ -303,6 +303,7 @@ public:
|
|||||||
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
||||||
virtual bool operator==(const Type& _other) const override;
|
virtual bool operator==(const Type& _other) const override;
|
||||||
virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
|
virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
|
||||||
|
virtual u256 getStorageSize() const override;
|
||||||
virtual unsigned getSizeOnStack() const override;
|
virtual unsigned getSizeOnStack() const override;
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; }
|
virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; }
|
||||||
|
Loading…
Reference in New Issue
Block a user