mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Sol->Yul] Implementing getters for bytes and structs containing bytes member.
Co-authored-by: chriseth <chris@ethereum.org>
This commit is contained in:
parent
a9a62e86df
commit
2d5a2c65a8
@ -2271,8 +2271,25 @@ string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool
|
|||||||
|
|
||||||
string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes)
|
string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
solAssert(_type.isValueType(), "");
|
if (_type.isValueType())
|
||||||
return readFromStorageValueType(_type, {}, _splitFunctionTypes);
|
return readFromStorageValueType(_type, {}, _splitFunctionTypes);
|
||||||
|
string functionName =
|
||||||
|
"read_from_storage__dynamic_" +
|
||||||
|
string(_splitFunctionTypes ? "split_" : "") +
|
||||||
|
_type.identifier();
|
||||||
|
|
||||||
|
return m_functionCollector.createFunction(functionName, [&] {
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>(slot, offset) -> value {
|
||||||
|
if gt(offset, 0) { <panic>() }
|
||||||
|
value := <readFromStorage>(slot)
|
||||||
|
}
|
||||||
|
)")
|
||||||
|
("functionName", functionName)
|
||||||
|
("panic", panicFunction(util::PanicCode::Generic))
|
||||||
|
("readFromStorage", readFromStorageReferenceType(_type))
|
||||||
|
.render();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::readFromStorageValueType(Type const& _type, optional<size_t> _offset, bool _splitFunctionTypes)
|
string YulUtilFunctions::readFromStorageValueType(Type const& _type, optional<size_t> _offset, bool _splitFunctionTypes)
|
||||||
@ -2315,7 +2332,15 @@ string YulUtilFunctions::readFromStorageValueType(Type const& _type, optional<si
|
|||||||
|
|
||||||
string YulUtilFunctions::readFromStorageReferenceType(Type const& _type)
|
string YulUtilFunctions::readFromStorageReferenceType(Type const& _type)
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(_type.category() == Type::Category::Struct, "");
|
if (auto const* arrayType = dynamic_cast<ArrayType const*>(&_type))
|
||||||
|
{
|
||||||
|
solAssert(arrayType->dataStoredIn(DataLocation::Memory), "");
|
||||||
|
return copyArrayFromStorageToMemoryFunction(
|
||||||
|
dynamic_cast<ArrayType const&>(*arrayType->copyForLocation(DataLocation::Storage, false)),
|
||||||
|
*arrayType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
solAssert(_type.category() == Type::Category::Struct, "");
|
||||||
|
|
||||||
string functionName = "read_from_storage_reference_type_" + _type.identifier();
|
string functionName = "read_from_storage_reference_type_" + _type.identifier();
|
||||||
|
|
||||||
@ -2326,24 +2351,19 @@ string YulUtilFunctions::readFromStorageReferenceType(Type const& _type)
|
|||||||
for (size_t i = 0; i < structMembers.size(); ++i)
|
for (size_t i = 0; i < structMembers.size(); ++i)
|
||||||
{
|
{
|
||||||
auto const& [memberSlotDiff, memberStorageOffset] = structType.storageOffsetsOfMember(structMembers[i].name);
|
auto const& [memberSlotDiff, memberStorageOffset] = structType.storageOffsetsOfMember(structMembers[i].name);
|
||||||
|
solAssert(structMembers[i].type->isValueType() || memberStorageOffset == 0, "");
|
||||||
|
|
||||||
memberSetValues[i]["setMember"] = Whiskers(R"(
|
memberSetValues[i]["setMember"] = Whiskers(R"(
|
||||||
{
|
{
|
||||||
let <memberValues> := <readFromStorage>(add(slot, <memberSlotDiff>)<?hasOffset>, <memberStorageOffset></hasOffset>)
|
let <memberValues> := <readFromStorage>(add(slot, <memberSlotDiff>))
|
||||||
<writeToMemory>(add(value, <memberMemoryOffset>), <memberValues>)
|
<writeToMemory>(add(value, <memberMemoryOffset>), <memberValues>)
|
||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("memberValues", suffixedVariableNameList("memberValue_", 0, structMembers[i].type->stackItems().size()))
|
("memberValues", suffixedVariableNameList("memberValue_", 0, structMembers[i].type->stackItems().size()))
|
||||||
("memberMemoryOffset", structType.memoryOffsetOfMember(structMembers[i].name).str())
|
("memberMemoryOffset", structType.memoryOffsetOfMember(structMembers[i].name).str())
|
||||||
("memberSlotDiff", memberSlotDiff.str())
|
("memberSlotDiff", memberSlotDiff.str())
|
||||||
("memberStorageOffset", to_string(memberStorageOffset))
|
("readFromStorage", readFromStorage(*structMembers[i].type, memberStorageOffset, true))
|
||||||
("readFromStorage",
|
|
||||||
structMembers[i].type->isValueType() ?
|
|
||||||
readFromStorageDynamic(*structMembers[i].type, true) :
|
|
||||||
readFromStorage(*structMembers[i].type, memberStorageOffset, true)
|
|
||||||
)
|
|
||||||
("writeToMemory", writeToMemoryFunction(*structMembers[i].type))
|
("writeToMemory", writeToMemoryFunction(*structMembers[i].type))
|
||||||
("hasOffset", structMembers[i].type->isValueType())
|
|
||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,11 +511,12 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
|||||||
{
|
{
|
||||||
if (returnTypes[i]->category() == Type::Category::Mapping)
|
if (returnTypes[i]->category() == Type::Category::Mapping)
|
||||||
continue;
|
continue;
|
||||||
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]))
|
if (
|
||||||
if (!arrayType->isByteArray())
|
auto const* arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]);
|
||||||
continue;
|
arrayType && !arrayType->isByteArray()
|
||||||
|
)
|
||||||
|
continue;
|
||||||
|
|
||||||
// TODO conversion from storage byte arrays is not yet implemented.
|
|
||||||
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
|
||||||
vector<string> retVars = IRVariable("ret_" + to_string(returnVariables.size()), *returnTypes[i]).stackSlots();
|
vector<string> retVars = IRVariable("ret_" + to_string(returnVariables.size()), *returnTypes[i]).stackSlots();
|
||||||
returnVariables += retVars;
|
returnVariables += retVars;
|
||||||
@ -531,9 +532,11 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(returnTypes.size() == 1, "");
|
solAssert(returnTypes.size() == 1, "");
|
||||||
|
auto const* arrayType = dynamic_cast<ArrayType const*>(returnTypes.front());
|
||||||
|
if (arrayType)
|
||||||
|
solAssert(arrayType->isByteArray(), "");
|
||||||
vector<string> retVars = IRVariable("ret", *returnTypes.front()).stackSlots();
|
vector<string> retVars = IRVariable("ret", *returnTypes.front()).stackSlots();
|
||||||
returnVariables += retVars;
|
returnVariables += retVars;
|
||||||
// TODO conversion from storage byte arrays is not yet implemented.
|
|
||||||
code += Whiskers(R"(
|
code += Whiskers(R"(
|
||||||
<ret> := <readStorage>(slot, offset)
|
<ret> := <readStorage>(slot, offset)
|
||||||
)")
|
)")
|
||||||
|
10
test/libsolidity/semanticTests/getters/bytes.sol
Normal file
10
test/libsolidity/semanticTests/getters/bytes.sol
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
contract C {
|
||||||
|
bytes public b;
|
||||||
|
constructor() {
|
||||||
|
b = "abc";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// b() -> 0x20, 0x03, 0x6162630000000000000000000000000000000000000000000000000000000000
|
Loading…
Reference in New Issue
Block a user