-
Notifications
You must be signed in to change notification settings - Fork 831
[WasmGC] Heap2Local: Optimize RefEq #6703
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
Conversation
| if (!analyzer.reached.count(curr)) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure I understand: we've done a data flow analysis and determined that this expression is not dead? Is it possible for reached to be nonzero and still have type Type::unreachable below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah, "reach" is used in two ways here. reached means that the allocation, the struct.new / array.new, reaches this location. So this first check is just making sure that we only look in the places we traced the path of the allocation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider
(ref.eq
(unreachable)
(struct.new ..)
)That allocation reaches the ref.eq, but also the ref.eq is unreachable code, separately.
| int32_t result = analyzer.reached.count(curr->left) > 0 && | ||
| analyzer.reached.count(curr->right) > 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this checking whether the expression is compared to itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reached is the places the allocation reaches. So if the allocation is on both sides, we must be equal. If the allocation reached only one, then since it did not escape to a place we can't analyze, the other arm must be something totally different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if one (or both) of the arms may or may not be the analyzed allocation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are never in an ambiguous situation. If one arm can contain a mixture of the analyzed allocation and something else then we consider that the Mixes situation, which we ignore:
binaryen/src/passes/Heap2Local.cpp
Lines 243 to 248 in 60050be
| if (interaction == ParentChildInteraction::Escapes || | |
| interaction == ParentChildInteraction::Mixes) { | |
| // If the parent may let us escape, or the parent mixes other values | |
| // up with us, give up. | |
| return true; | |
| } |
In theory we could add runtime checks "is this the allocation", but it seems unpromising.
If an allocation does not escape, then we can compute
ref.eqfor it: whencompared to itself the result is 1, and when compared to anything else it
is 0 (since it did not escape, anything else must be different).
This unblocks a few cases on real-world Java code I am looking at.