-
Notifications
You must be signed in to change notification settings - Fork 49.6k
[compiler] PruneNonEscapingScopes understands terminal operands #33062
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
We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. [ghstack-poisoned]
We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. ghstack-source-id: d4d58c3 Pull Request resolved: #33062
…rands" We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. [ghstack-poisoned]
We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. ghstack-source-id: f59837e Pull Request resolved: #33062
…rands" We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. [ghstack-poisoned]
We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. ghstack-source-id: a477f2c Pull Request resolved: #33062
* - rvalues: places that are aliased by the instruction's lvalues. | ||
* - level: the level of memoization to apply to this value | ||
*/ | ||
function computeMemoizationInputs( |
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.
this moves to become a method on CollectDependencies
for (const instr of value.instructions) { | ||
this.visitValueForMemoization(instr.id, instr.value, instr.lvalue); | ||
} |
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.
this is the main change: not just traversing into sequence expressions, but processing the aliasing information into the state
* If a scope reassigns any variables, set the chain of active scopes as a dependency | ||
* of those variables. This ensures that if the variable escapes that we treat the | ||
* reassignment scopes — and importantly their dependencies — as needing memoization. | ||
*/ | ||
for (const reassignment of scope.scope.reassignments) { |
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.
makes sense, thanks for the comment!
This ensures that if the variable escapes that we treat the reassignment scopes — and importantly their dependencies — as needing memoization.
I wonder how this was working previously.. If we were actually incorrectly pruning reassignment scopes, that sounds like a bug (e.g. if some reassignment scopes are pruned and others are kept due to declaring escaping values)
@@ -0,0 +1,16 @@ | |||
function useHook(nodeID, condition) { | |||
const graph = useContext(GraphContext); |
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.
nit: can we add imports for useContext
?
let value; | ||
for (const key of Object.keys(node?.fields ?? {})) { | ||
if (condition) { | ||
// (1) We currently create a scope just for this instruction, then later prune the scope because |
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.
Ahh that makes sense. I guess loops are kind of the only case that we might want to lengthen instead of completely pruning scopes. Specifically, we should rewrite / lengthen a scope if it is the outermost one in a loop.
Since flattenReactiveLoops happens before other relevant passes (flatten hook calls, propagate scope deps), this seems pretty straightforward.
Nice find!
…rands" Handles a few edge cases relating to for..of terminals, which have a compound `init` value block: * For..of with a return statement inside would not memoize the rvalue of the init expression (the collection). This is because there was no direct dependency relationship between the value being returned and the outer scope. The fix is to track the set of active scopes and make return values depend on all the active scopes at the point of the return. * For..of that reassigns a variable which later escapes were also not memoizing the collection. This is similar: the escape analysis aliasing didn't consider scopes that reassign, so there was no dependency between the returned variable and the scope that did the reassigning. The fix is to establish that dependency relationship. In both cases, adding the additional scopes as a dependency of the right variable ensures that the scope's dependencies are treated as escaping (needing memoization), ensuring the collection is memoized. [ghstack-poisoned]
We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. ghstack-source-id: 09a2923 Pull Request resolved: #33062
We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. ghstack-source-id: 09a2923 Pull Request resolved: #33062
We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. ghstack-source-id: 09a2923 Pull Request resolved: #33062 DiffTrain build for [e9db3cc](e9db3cc)
We weren't treating terminal operands as eligible for memoization in PruneNonEscapingScopes, which meant that they could end up un-memoized. Terminal operands can also be compound ReactiveValues like SequenceExpressions, so part of the fix is to make sure we don't just recurse into compound values but record the full aliasing information we would for top-level instructions. Still WIP, this needs to handle terminals other than for..of. ghstack-source-id: 09a2923 Pull Request resolved: facebook#33062 DiffTrain build for [e9db3cc](facebook@e9db3cc)
Stack from ghstack (oldest at bottom):
Handles a few edge cases relating to for..of terminals, which have a compound
init
value block:In both cases, adding the additional scopes as a dependency of the right variable ensures that the scope's dependencies are treated as escaping (needing memoization), ensuring the collection is memoized.