UserDefinedValueType.storageBytes() is correctly set

Previously it returned 32 bytes for all types, which was wasteful. This commit changes it to return
the storage bytes of the underlying type.
This commit is contained in:
hrkrshnn 2021-09-28 10:52:09 +02:00 committed by chriseth
parent 7e7c68e5bf
commit 6109b5c3a1
8 changed files with 286 additions and 0 deletions

View File

@ -2,6 +2,7 @@
Important Bugfixes:
* Immutables: Properly perform sign extension on signed immutables.
* User Defined Value Type: Fix storage layout of user defined value types for underlying types shorter than 32 bytes.
Bugfixes:

View File

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

View File

@ -0,0 +1 @@
--storage-layout

View File

@ -0,0 +1,2 @@
Warning: Source file does not specify required compiler version!
--> storage_layout_user_defined/input.sol

View File

@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL v3
type MyInt128 is int128;
type MyInt8 is int8;
contract C {
// slot 0
MyInt128 a;
MyInt128 b;
// slot 1
MyInt128 c;
MyInt8 d;
MyInt8 e;
MyInt8 f;
MyInt8 g;
// slot 2
MyInt8 h;
}

View File

@ -0,0 +1,4 @@
======= storage_layout_user_defined/input.sol:C =======
Contract Storage Layout:
{"storage":[{"astId":7,"contract":"storage_layout_user_defined/input.sol:C","label":"a","offset":0,"slot":"0","type":"t_userDefinedValueType(MyInt128)2"},{"astId":10,"contract":"storage_layout_user_defined/input.sol:C","label":"b","offset":16,"slot":"0","type":"t_userDefinedValueType(MyInt128)2"},{"astId":13,"contract":"storage_layout_user_defined/input.sol:C","label":"c","offset":0,"slot":"1","type":"t_userDefinedValueType(MyInt128)2"},{"astId":16,"contract":"storage_layout_user_defined/input.sol:C","label":"d","offset":16,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"},{"astId":19,"contract":"storage_layout_user_defined/input.sol:C","label":"e","offset":17,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"},{"astId":22,"contract":"storage_layout_user_defined/input.sol:C","label":"f","offset":18,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"},{"astId":25,"contract":"storage_layout_user_defined/input.sol:C","label":"g","offset":19,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"},{"astId":28,"contract":"storage_layout_user_defined/input.sol:C","label":"h","offset":20,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"}],"types":{"t_userDefinedValueType(MyInt128)2":{"encoding":"inplace","label":"MyInt128","numberOfBytes":"16"},"t_userDefinedValueType(MyInt8)4":{"encoding":"inplace","label":"MyInt8","numberOfBytes":"1"}}}

View File

@ -0,0 +1,74 @@
type MyInt8 is int8;
type MyAddress is address;
type MyInt96 is int96;
contract C {
MyInt8 a;
MyInt8 b;
MyInt8 c;
MyAddress d;
MyAddress e;
MyAddress f;
MyInt96 g;
function storage_a() pure external returns(uint slot, uint offset) {
assembly {
slot := a.slot
offset := a.offset
}
}
function storage_b() pure external returns(uint slot, uint offset) {
assembly {
slot := b.slot
offset := b.offset
}
}
function storage_c() pure external returns(uint slot, uint offset) {
assembly {
slot := d.slot
offset := c.offset
}
}
function storage_d() pure external returns(uint slot, uint offset) {
assembly {
slot := d.slot
offset := d.offset
}
}
function storage_e() pure external returns(uint slot, uint offset) {
assembly {
slot := e.slot
offset := e.offset
}
}
function storage_f() pure external returns(uint slot, uint offset) {
assembly {
slot := f.slot
offset := f.offset
}
}
function storage_g() pure external returns(uint slot, uint offset) {
assembly {
slot := g.slot
offset := g.offset
}
}
}
// ====
// compileViaYul: also
// ----
// storage_a() -> 0, 0
// storage_b() -> 0, 1
// storage_c() -> 0, 2
// storage_d() -> 0, 3
// storage_e() -> 1, 0
// storage_f() -> 2, 0
// storage_g() -> 2, 0x14

View File

@ -0,0 +1,167 @@
type MyInt64 is int64;
struct HalfSlot {
MyInt64 a;
MyInt64 b;
}
struct RegularHalfSlot {
int64 a;
int64 b;
}
type MyAddress is address;
type MyInt96 is int96;
struct FullSlot {
MyInt96 a;
MyAddress b;
}
struct RegularFullSlot {
int96 a;
address b;
}
contract C {
HalfSlot public a;
RegularHalfSlot public ra;
HalfSlot public b;
RegularHalfSlot public rb;
HalfSlot public c;
RegularHalfSlot public rc;
FullSlot public d;
RegularFullSlot public rd;
function storage_a() pure external returns(uint slot, uint offset) {
assembly {
slot := a.slot
offset := a.offset
}
}
function storage_ra() pure external returns(uint slot, uint offset) {
assembly {
slot := ra.slot
offset := ra.offset
}
}
function storage_b() pure external returns(uint slot, uint offset) {
assembly {
slot := b.slot
offset := b.offset
}
}
function storage_rb() pure external returns(uint slot, uint offset) {
assembly {
slot := rb.slot
offset := rb.offset
}
}
function storage_c() pure external returns(uint slot, uint offset) {
assembly {
slot := c.slot
offset := c.offset
}
}
function storage_rc() pure external returns(uint slot, uint offset) {
assembly {
slot := rc.slot
offset := rc.offset
}
}
function storage_d() pure external returns(uint slot, uint offset) {
assembly {
slot := d.slot
offset := d.offset
}
}
function storage_rd() pure external returns(uint slot, uint offset) {
assembly {
slot := rd.slot
offset := rd.offset
}
}
function set_a(MyInt64 _a, MyInt64 _b) external {
a.a = _a;
a.b = _b;
}
function set_ra(int64 _a, int64 _b) external {
ra.a = _a;
ra.b = _b;
}
function set_b(MyInt64 _a, MyInt64 _b) external {
b.a = _a;
b.b = _b;
}
function set_rb(int64 _a, int64 _b) external {
rb.a = _a;
rb.b = _b;
}
function set_c(MyInt64 _a, MyInt64 _b) external {
c.a = _a;
c.b = _b;
}
function set_rc(int64 _a, int64 _b) external {
rc.a = _a;
rc.b = _b;
}
function set_d(MyInt96 _a, MyAddress _b) external {
d.a = _a;
d.b = _b;
}
function set_rd(int96 _a, address _b) external {
rd.a = _a;
rd.b = _b;
}
function read_slot(uint slot) view external returns (uint value) {
assembly {
value := sload(slot)
}
}
}
// ====
// compileViaYul: also
// ----
// storage_a() -> 0, 0
// set_a(int64,int64): 100, 200 ->
// read_slot(uint256): 0 -> 0xc80000000000000064
// storage_ra() -> 1, 0
// set_ra(int64,int64): 100, 200 ->
// read_slot(uint256): 1 -> 0xc80000000000000064
// storage_b() -> 2, 0
// set_b(int64,int64): 0, 200 ->
// read_slot(uint256): 2 -> 3689348814741910323200
// storage_rb() -> 3, 0
// set_rb(int64,int64): 0, 200 ->
// read_slot(uint256): 3 -> 3689348814741910323200
// storage_c() -> 4, 0
// set_c(int64,int64): 100, 0 ->
// read_slot(uint256): 4 -> 0x64
// storage_rc() -> 5, 0
// set_rc(int64,int64): 100, 0 ->
// read_slot(uint256): 5 -> 0x64
// storage_d() -> 6, 0
// set_d(int96,address): 39614081257132168796771975167, 1461501637330902918203684832716283019655932542975 ->
// read_slot(uint256): 6 -> -39614081257132168796771975169
// storage_rd() -> 7, 0
// set_rd(int96,address): 39614081257132168796771975167, 1461501637330902918203684832716283019655932542975 ->
// read_slot(uint256): 7 -> -39614081257132168796771975169