mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12047 from ethereum/fixFixedBytesCompilerUtils
Properly handle fixed-byte-like types.
This commit is contained in:
@@ -2537,6 +2537,7 @@ Type const& UserDefinedValueType::underlyingType() const
|
||||
{
|
||||
Type const* type = m_definition.underlyingType()->annotation().type;
|
||||
solAssert(type, "");
|
||||
solAssert(type->category() != Category::UserDefinedValueType, "");
|
||||
return *type;
|
||||
}
|
||||
|
||||
@@ -3071,10 +3072,7 @@ u256 FunctionType::storageSize() const
|
||||
|
||||
bool FunctionType::leftAligned() const
|
||||
{
|
||||
if (m_kind == Kind::External)
|
||||
return true;
|
||||
else
|
||||
solAssert(false, "Alignment property of non-exportable function type requested.");
|
||||
return m_kind == Kind::External;
|
||||
}
|
||||
|
||||
unsigned FunctionType::storageBytes() const
|
||||
|
||||
@@ -1108,6 +1108,8 @@ public:
|
||||
bool leftAligned() const override { return underlyingType().leftAligned(); }
|
||||
bool canBeStored() const override { return underlyingType().canBeStored(); }
|
||||
u256 storageSize() const override { return underlyingType().storageSize(); }
|
||||
unsigned storageBytes() const override { return underlyingType().storageBytes(); }
|
||||
|
||||
bool isValueType() const override
|
||||
{
|
||||
solAssert(underlyingType().isValueType(), "");
|
||||
@@ -1119,6 +1121,25 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool containsNestedMapping() const override
|
||||
{
|
||||
solAssert(nameable(), "Called for a non nameable type.");
|
||||
solAssert(!underlyingType().containsNestedMapping(), "");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasSimpleZeroValueInMemory() const override
|
||||
{
|
||||
solAssert(underlyingType().hasSimpleZeroValueInMemory(), "");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dataStoredIn(DataLocation _loc) const override
|
||||
{
|
||||
solAssert(!underlyingType().dataStoredIn(_loc), "");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override { solAssert(false, ""); }
|
||||
std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); }
|
||||
|
||||
@@ -1552,10 +1552,13 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
|
||||
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWords)
|
||||
{
|
||||
solAssert(_type.isValueType(), "");
|
||||
Type const* type = &_type;
|
||||
if (auto const* userDefined = dynamic_cast<UserDefinedValueType const*>(type))
|
||||
type = &userDefined->underlyingType();
|
||||
|
||||
unsigned numBytes = _type.calldataEncodedSize(_padToWords);
|
||||
unsigned numBytes = type->calldataEncodedSize(_padToWords);
|
||||
bool isExternalFunctionType = false;
|
||||
if (auto const* funType = dynamic_cast<FunctionType const*>(&_type))
|
||||
if (auto const* funType = dynamic_cast<FunctionType const*>(type))
|
||||
if (funType->kind() == FunctionType::Kind::External)
|
||||
isExternalFunctionType = true;
|
||||
if (numBytes == 0)
|
||||
@@ -1570,21 +1573,20 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
|
||||
splitExternalFunctionType(true);
|
||||
else if (numBytes != 32)
|
||||
{
|
||||
bool leftAligned = _type.category() == Type::Category::FixedBytes;
|
||||
// add leading or trailing zeros by dividing/multiplying depending on alignment
|
||||
unsigned shiftFactor = (32 - numBytes) * 8;
|
||||
rightShiftNumberOnStack(shiftFactor);
|
||||
if (leftAligned)
|
||||
if (type->leftAligned())
|
||||
{
|
||||
leftShiftNumberOnStack(shiftFactor);
|
||||
cleanupNeeded = false;
|
||||
}
|
||||
else if (IntegerType const* intType = dynamic_cast<IntegerType const*>(&_type))
|
||||
else if (IntegerType const* intType = dynamic_cast<IntegerType const*>(type))
|
||||
if (!intType->isSigned())
|
||||
cleanupNeeded = false;
|
||||
}
|
||||
if (_fromCalldata)
|
||||
convertType(_type, _type, cleanupNeeded, false, true);
|
||||
convertType(_type, *type, cleanupNeeded, false, true);
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
@@ -1639,12 +1641,10 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords,
|
||||
"Memory store of more than 32 bytes requested (Type: " + _type.toString(true) + ")."
|
||||
);
|
||||
|
||||
bool leftAligned = _type.category() == Type::Category::FixedBytes;
|
||||
|
||||
if (_cleanup)
|
||||
convertType(_type, _type, true);
|
||||
|
||||
if (numBytes != 32 && !leftAligned && !_padToWords)
|
||||
if (numBytes != 32 && !_type.leftAligned() && !_padToWords)
|
||||
// shift the value accordingly before storing
|
||||
leftShiftNumberOnStack((32 - numBytes) * 8);
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool
|
||||
if (!m_padded)
|
||||
{
|
||||
solAssert(m_dataType->calldataEncodedSize(false) == 1, "Invalid non-padded type.");
|
||||
solAssert(m_dataType->category() != Type::Category::UserDefinedValueType, "");
|
||||
if (m_dataType->category() == Type::Category::FixedBytes)
|
||||
m_context << u256(0) << Instruction::BYTE;
|
||||
m_context << Instruction::SWAP1 << Instruction::MSTORE8;
|
||||
@@ -226,27 +227,17 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
|
||||
m_context << Instruction::POP << Instruction::SLOAD;
|
||||
else
|
||||
{
|
||||
Type const* type = m_dataType;
|
||||
if (type->category() == Type::Category::UserDefinedValueType)
|
||||
type = type->encodingType();
|
||||
bool cleaned = false;
|
||||
m_context
|
||||
<< Instruction::SWAP1 << Instruction::SLOAD << Instruction::SWAP1
|
||||
<< u256(0x100) << Instruction::EXP << Instruction::SWAP1 << Instruction::DIV;
|
||||
if (m_dataType->category() == Type::Category::FixedPoint)
|
||||
if (type->category() == Type::Category::FixedPoint)
|
||||
// implementation should be very similar to the integer case.
|
||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
||||
if (m_dataType->category() == Type::Category::FixedBytes)
|
||||
{
|
||||
CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * m_dataType->storageBytes());
|
||||
cleaned = true;
|
||||
}
|
||||
else if (
|
||||
m_dataType->category() == Type::Category::Integer &&
|
||||
dynamic_cast<IntegerType const&>(*m_dataType).isSigned()
|
||||
)
|
||||
{
|
||||
m_context << u256(m_dataType->storageBytes() - 1) << Instruction::SIGNEXTEND;
|
||||
cleaned = true;
|
||||
}
|
||||
else if (FunctionType const* fun = dynamic_cast<decltype(fun)>(m_dataType))
|
||||
else if (FunctionType const* fun = dynamic_cast<decltype(fun)>(type))
|
||||
{
|
||||
if (fun->kind() == FunctionType::Kind::External)
|
||||
{
|
||||
@@ -260,10 +251,24 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
|
||||
m_context << Instruction::MUL << Instruction::OR;
|
||||
}
|
||||
}
|
||||
else if (type->leftAligned())
|
||||
{
|
||||
CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * type->storageBytes());
|
||||
cleaned = true;
|
||||
}
|
||||
else if (
|
||||
type->category() == Type::Category::Integer &&
|
||||
dynamic_cast<IntegerType const&>(*type).isSigned()
|
||||
)
|
||||
{
|
||||
m_context << u256(type->storageBytes() - 1) << Instruction::SIGNEXTEND;
|
||||
cleaned = true;
|
||||
}
|
||||
|
||||
if (!cleaned)
|
||||
{
|
||||
solAssert(m_dataType->sizeOnStack() == 1, "");
|
||||
m_context << ((u256(0x1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::AND;
|
||||
solAssert(type->sizeOnStack() == 1, "");
|
||||
m_context << ((u256(0x1) << (8 * type->storageBytes())) - 1) << Instruction::AND;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,10 +334,13 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
Instruction::AND;
|
||||
}
|
||||
}
|
||||
else if (m_dataType->category() == Type::Category::FixedBytes)
|
||||
else if (m_dataType->leftAligned())
|
||||
{
|
||||
solAssert(_sourceType.category() == Type::Category::FixedBytes, "source not fixed bytes");
|
||||
CompilerUtils(m_context).rightShiftNumberOnStack(256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes());
|
||||
solAssert(_sourceType.category() == Type::Category::FixedBytes || (
|
||||
_sourceType.encodingType() &&
|
||||
_sourceType.encodingType()->category() == Type::Category::FixedBytes
|
||||
), "source not fixed bytes");
|
||||
CompilerUtils(m_context).rightShiftNumberOnStack(256 - 8 * m_dataType->storageBytes());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -2912,24 +2912,20 @@ string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type)
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
|
||||
unsigned storageBytes = _type.storageBytes();
|
||||
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
|
||||
if (type->isSigned() && storageBytes != 32)
|
||||
Type const* encodingType = &_type;
|
||||
if (_type.category() == Type::Category::UserDefinedValueType)
|
||||
encodingType = _type.encodingType();
|
||||
unsigned storageBytes = encodingType->storageBytes();
|
||||
if (IntegerType const* intType = dynamic_cast<IntegerType const*>(encodingType))
|
||||
if (intType->isSigned() && storageBytes != 32)
|
||||
{
|
||||
templ("cleaned", "signextend(" + to_string(storageBytes - 1) + ", value)");
|
||||
return templ.render();
|
||||
}
|
||||
|
||||
bool leftAligned = false;
|
||||
if (
|
||||
_type.category() != Type::Category::Function ||
|
||||
dynamic_cast<FunctionType const&>(_type).kind() == FunctionType::Kind::External
|
||||
)
|
||||
leftAligned = _type.leftAligned();
|
||||
|
||||
if (storageBytes == 32)
|
||||
templ("cleaned", "value");
|
||||
else if (leftAligned)
|
||||
else if (encodingType->leftAligned())
|
||||
templ("cleaned", shiftLeftFunction(256 - 8 * storageBytes) + "(value)");
|
||||
else
|
||||
templ("cleaned", "and(value, " + toCompactHexWithPrefix((u256(1) << (8 * storageBytes)) - 1) + ")");
|
||||
@@ -2965,7 +2961,7 @@ string YulUtilFunctions::prepareStoreFunction(Type const& _type)
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
if (_type.category() == Type::Category::FixedBytes)
|
||||
if (_type.leftAligned())
|
||||
templ("actualPrepare", shiftRightFunction(256 - 8 * _type.storageBytes()) + "(value)");
|
||||
else
|
||||
templ("actualPrepare", "value");
|
||||
@@ -3304,6 +3300,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||
bodyTemplate("cleanOutput", cleanupFunction(_to));
|
||||
string convert;
|
||||
|
||||
solAssert(_to.category() != Type::Category::UserDefinedValueType, "");
|
||||
if (auto const* toFixedBytes = dynamic_cast<FixedBytesType const*>(&_to))
|
||||
convert = shiftLeftFunction(256 - toFixedBytes->numBytes() * 8);
|
||||
else if (dynamic_cast<FixedPointType const*>(&_to))
|
||||
|
||||
Reference in New Issue
Block a user