Merge pull request #10552 from ethereum/gettersSol2Yul

[Sol->Yul] Implementing getter for struct with bytes member
This commit is contained in:
Đorđe Mijović 2020-12-21 15:29:29 +01:00 committed by GitHub
commit 21dc6c8356
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 93 additions and 21 deletions

View File

@ -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();
} }

View File

@ -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)
)") )")

View File

@ -2,7 +2,7 @@ contract C {
struct T { uint8 x; uint8 y; uint[] z; } struct T { uint8 x; uint8 y; uint[] z; }
T[3][] a; T[3][] a;
function f() public returns (uint8, uint8, uint, uint, uint, uint8, uint8, uint, uint, uint) { function f() public returns (uint8, uint8, uint, uint8, uint8, uint) {
a.push(); a.push();
a.push(); a.push();
a[0][1].x = 11; a[0][1].x = 11;
@ -17,10 +17,12 @@ contract C {
a[1][2].z.push(6); a[1][2].z.push(6);
T[3][] memory m = a; T[3][] memory m = a;
return ( return (
m[0][1].x, m[0][1].y, m[0][1].z[0], m[0][1].z[1], m[0][1].z[2], m[0][1].x, m[0][1].y, m[0][1].z[0],
m[1][2].x, m[1][2].y, m[1][2].z[0], m[1][2].z[1], m[1][2].z[2] m[1][2].x, m[1][2].y, m[1][2].z[0]
); );
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// f() -> 11, 0x0c, 1, 2, 3, 0x15, 22, 4, 5, 6 // f() -> 11, 0x0c, 1, 0x15, 22, 4

View File

@ -10,6 +10,8 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// test() -> // test() ->
// tester() -> 0x20, 0x3, "abc" // tester() -> 0x20, 0x3, "abc"

View File

@ -23,6 +23,8 @@ contract C {
function arrayPushEmpty() public { x.push(); } function arrayPushEmpty() public { x.push(); }
function del() public { delete x; } function del() public { delete x; }
} }
// ====
// compileViaYul: also
// ---- // ----
// x() -> 0x20, 3, 0x6162630000000000000000000000000000000000000000000000000000000000 // x() -> 0x20, 3, 0x6162630000000000000000000000000000000000000000000000000000000000
// abiEncode() -> 0x20, 3, 0x6162630000000000000000000000000000000000000000000000000000000000 // abiEncode() -> 0x20, 3, 0x6162630000000000000000000000000000000000000000000000000000000000

View File

@ -16,5 +16,7 @@ contract Sample {
p[0] = m; p[0] = m;
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// p(uint256): 0x0 -> 0xbbbb, 0xcccc, 0x80, 0xc0, 0x05, "hello", 0x05, "world" // p(uint256): 0x0 -> 0xbbbb, 0xcccc, 0x80, 0xc0, 0x05, "hello", 0x05, "world"

View File

@ -28,6 +28,8 @@ contract buggystruct {
return bug.last; return bug.last;
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// getFirst() -> 0x0a // getFirst() -> 0x0a
// getSecond() -> 0x14 // getSecond() -> 0x14

View File

@ -6,6 +6,8 @@ contract Test {
m_s = s; m_s = s;
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// constructor(): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> // constructor(): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" ->
// m_x() -> 7 // m_x() -> 7

View File

@ -10,6 +10,7 @@ contract A {
} }
} }
// ==== // ====
// compileViaYul: also
// EVMVersion: >=byzantium // EVMVersion: >=byzantium
// ---- // ----
// f() -> 0x01, 0x40, 0x00 // f() -> 0x01, 0x40, 0x00

View File

@ -0,0 +1,10 @@
contract C {
bytes public b;
constructor() {
b = "abc";
}
}
// ====
// compileViaYul: also
// ----
// b() -> 0x20, 0x03, 0x6162630000000000000000000000000000000000000000000000000000000000

View File

@ -2,13 +2,17 @@ contract C {
string public a; string public a;
string public b; string public b;
bytes public c; bytes public c;
string public d = "abcd";
constructor() { constructor() {
a = "hello world"; a = "hello world";
b = hex"41424344"; b = hex"41424344";
c = hex"ff077fff"; c = hex"ff077fff";
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// a() -> 0x20, 11, "hello world" // a() -> 0x20, 11, "hello world"
// b() -> 0x20, 4, "ABCD" // b() -> 0x20, 4, "ABCD"
// c() -> 0x20, 4, -439061522557375173052089223601630338202760422010735733633791622124826263552 // c() -> 0x20, 4, -439061522557375173052089223601630338202760422010735733633791622124826263552
// d() -> 0x20, 4, "abcd"

View File

@ -14,5 +14,7 @@ contract C {
s.d.push(10); s.d.push(10);
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// s() -> 7, 0x40, 3, 0x6162630000000000000000000000000000000000000000000000000000000000 // s() -> 7, 0x40, 3, 0x6162630000000000000000000000000000000000000000000000000000000000

View File

@ -13,5 +13,7 @@ contract C {
s.c[0] = 9; s.c[0] = 9;
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// s() -> 0x07, 0x40, 0x03, 0x6162630000000000000000000000000000000000000000000000000000000000 // s() -> 0x07, 0x40, 0x03, 0x6162630000000000000000000000000000000000000000000000000000000000

View File

@ -8,6 +8,8 @@ contract A {
externalData = msg.data; externalData = msg.data;
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// data() -> 0 // data() -> 0
// () // ()

View File

@ -21,5 +21,7 @@ contract CopyTest {
return (memoryTree.children.length, memoryTree.children[0].children.length, memoryTree.children[1].children.length); return (memoryTree.children.length, memoryTree.children[0].children.length, memoryTree.children[1].children.length);
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// run() -> 2, 23, 42 // run() -> 2, 23, 42

View File

@ -46,5 +46,7 @@ contract CopyTest {
return result; return result;
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// run() -> 0x20, 10, 0x42, 0x4200, 0x420000, 0x420001, 0x420002, 0x4201, 0x420100, 0x420101, 0x420102, 0x420103 // run() -> 0x20, 10, 0x42, 0x4200, 0x420000, 0x420001, 0x420002, 0x4201, 0x420100, 0x420101, 0x420102, 0x420103

View File

@ -64,6 +64,8 @@ contract Test {
a2 = m_x.a[1]; a2 = m_x.a[1];
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// load() -> 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 // load() -> 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
// store() -> 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 // store() -> 0x01, 0x02, 0x03, 0x04, 0x05, 0x06

View File

@ -50,6 +50,8 @@ contract Test {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// testInit() -> 0, 0, 0, 0, true // testInit() -> 0, 0, 0, 0, true
// testCopyRead() -> 1, 2, 3, 4 // testCopyRead() -> 1, 2, 3, 4

View File

@ -18,6 +18,8 @@ contract X is A
} }
// ====
// compileViaYul: also
// ---- // ----
// test() -> 0, 64, 0 // test() -> 0, 64, 0
// set() -> // set() ->

View File

@ -18,6 +18,8 @@ contract X is A
} }
// ====
// compileViaYul: also
// ---- // ----
// test(uint256): 0 -> 0, 64, 0 // test(uint256): 0 -> 0, 64, 0
// test(uint256): 42 -> 0, 64, 0 // test(uint256): 42 -> 0, 64, 0

View File

@ -12,6 +12,8 @@ contract C {
function g() public view returns (uint) { return address(0).code.length; } function g() public view returns (uint) { return address(0).code.length; }
function h() public view returns (uint) { return address(1).code.length; } function h() public view returns (uint) { return address(1).code.length; }
} }
// ====
// compileViaYul: also
// ---- // ----
// constructor() -> // constructor() ->
// initCode() -> 0x20, 0 // initCode() -> 0x20, 0

View File

@ -18,5 +18,7 @@ contract C {
} }
} }
// ====
// compileViaYul: also
// ---- // ----
// g() -> 2, 6 // g() -> 2, 6