Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sol->Yul] Optimizing delete struct. #9985

Merged
merged 1 commit into from
Oct 15, 2020
Merged

Conversation

mijovic
Copy link
Contributor

@mijovic mijovic commented Oct 7, 2020

Depends on #9843

Copy link
Member

@ekpyron ekpyron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think this is safe, too, and could be merged right after (or together with) #9843.

@chriseth I think you asked for this to be extracted: do you have any concern here?

The main question is the last slot, so if

struct S1 { uint8 x; }

is changed to

struct S2 { uint8 x; uint8 y; }

Then this code here would already clear y as well when deleting S1, whereas the conservative method will keep an sload and mask even with #6728 . So in that sense this is an actual change in behavior - but any state variable after the struct will live in the next slot anyways, won't it?

Also #6728 won't kick in completely e.g. for the first slot of struct S { uint120 x; uint120 y; uint256 z; }, since x and y don't occupy the entire slot, so the masks won't cancel the sload out and the sload will stay. So if that's changed to struct S { uint120 x; uint120 y; uint8 a; uint256 z; }, but still deleted from code using the old definition, a will not be cleared, right?

I'd even argue that clearing all slots entirely is the better behavior for deleting structs - otherwise we could even miss deleting some members in contract upgrade situations, couldn't we? I'm not entirely sure though, it's a bit delicate... but only clearing members seems problematic to me as well in that sense.

What do you think?

@chriseth
Copy link
Contributor

chriseth commented Oct 8, 2020

There should be an issue about this problem: Do we want to make use of the knowledge that in the current storage layout, some parts of a slot are completely unused?

One reason why we did not make use of that knowledge yet is because of upgrades: Someone might want to add or remove items at the end of a struct. If this is an issue here has to be discussed, but I would prefer not to just merge this without a decision on that subject.

I think we even discussed that in the past and concluded that the gas savings are not worth the trouble.

@ekpyron
Copy link
Member

ekpyron commented Oct 8, 2020

I'm aware of that discussion, but I don't think that's exactly the same - this here is really only about deleting the struct, so the situation is slightly different, isn't it? Here I'd argue we actually should delete the whole slot, particularly with an eye of upgrades...

@ekpyron
Copy link
Member

ekpyron commented Oct 8, 2020

I.e. if I extend struct S { uint8 a; } to struct S { uint8 a; uint8 b; } - is it then sane behavior that deleting the struct might ever not delete b?

@mijovic mijovic force-pushed the deleteStructSol2Yul branch from cf799f4 to d6007aa Compare October 8, 2020 10:23
@ekpyron
Copy link
Member

ekpyron commented Oct 8, 2020

You're referring to this: #7891, right? Where we decided against it in the end?

@mijovic mijovic force-pushed the deleteStructSol2Yul branch 6 times, most recently from 24272e6 to ad8d840 Compare October 8, 2020 14:38
Base automatically changed from deleteStructSol2Yul to develop October 8, 2020 17:08
@mijovic mijovic force-pushed the optimizeDeleteStructSol2Yul branch from 870bd94 to 93e65e5 Compare October 12, 2020 13:21
@mijovic mijovic changed the base branch from develop to irBreakingChangesDocs October 12, 2020 13:21
@mijovic mijovic force-pushed the irBreakingChangesDocs branch from f2d5340 to 1c142c5 Compare October 12, 2020 13:46
@mijovic mijovic force-pushed the optimizeDeleteStructSol2Yul branch 2 times, most recently from 9235fc8 to ec4945b Compare October 12, 2020 14:45
Base automatically changed from irBreakingChangesDocs to develop October 12, 2020 16:19
This section lists the changes that are semantic-only, thus potentially
hiding new and different behavior in existing code.

* When deleting storage struct, if struct occupies less than one slot, whole slot will be cleared.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs some copy editing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changes this a bit, hope it looks better now

Copy link
Contributor

@chriseth chriseth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some tests that mix short value types with dynamically-sized arrays, or also nested arrays, or do we already have such tests?

@mijovic mijovic force-pushed the optimizeDeleteStructSol2Yul branch from ec4945b to d097e6a Compare October 13, 2020 19:05
@mijovic
Copy link
Contributor Author

mijovic commented Oct 13, 2020

@chriseth I added few tests that show where this is different to the old codegen. There are 3 different tests, and all of them fail with old codegen.

@mijovic mijovic force-pushed the optimizeDeleteStructSol2Yul branch from d097e6a to f87e396 Compare October 13, 2020 19:08
Copy link
Member

@ekpyron ekpyron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how much care we need to take for the ir-breaking-changes docs - we'll probably have to refine them again in the end either way and could think of them primarily as a reminder for now... so fine with merging it as it is, but I'll post some comments about the docs either way.

docs/ir/ir-breaking-changes.rst Outdated Show resolved Hide resolved
docs/ir/ir-breaking-changes.rst Outdated Show resolved Hide resolved
Co-authored-by: Daniel Kirchner <daniel@ekpyron.org>
@mijovic mijovic force-pushed the optimizeDeleteStructSol2Yul branch from 92a7746 to 6f7947c Compare October 14, 2020 11:35
@chriseth chriseth merged commit e17d685 into develop Oct 15, 2020
@chriseth chriseth deleted the optimizeDeleteStructSol2Yul branch October 15, 2020 14:03
hiding new and different behavior in existing code.

* When storage structs are deleted, every storage slot that contains a member of the struct is set to zero entirely. Formally, padding space was left untouched.
Consequently, if the padding space within a struct is used to store data (e.g. in the context of a contract upgrade), you have to be aware that ``delete`` will now also clear the added member (while it wouldn't have been cleared in the past).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should rather say "that old code generated for delete before adding that struct" or something like that, but I'd also say it's fine for now - we'll need to refine this in the end when we make it "public" anyways I expect.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you merged already anyways :-D.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants