Skip to content

Commit

Permalink
Propagate more scopes in FunctionAnalysis
Browse files Browse the repository at this point in the history
Summary:
Detect when a closure is being stored into an inner scope, and use that
to propagate the scope, since the closure scope is still reachable from
the inner scope. This is especially useful in the presence of scope
hoisting, because the closure's parent may be changed to some outer
scope, while it is still being stored in the original scope.

Reviewed By: avp

Differential Revision: D68187124

fbshipit-source-id: 6ed0f408cba5c7cc5fcef9a9fed234ad19f32fc6
  • Loading branch information
neildhar authored and facebook-github-bot committed Feb 13, 2025
1 parent 4df0908 commit 6ddb3a9
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 6 deletions.
33 changes: 28 additions & 5 deletions lib/Optimizer/Scalar/FunctionAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,11 +350,34 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
continue;
}

// If the scope is the same as the scope we are storing into, we know
// that the scope of the closure will always just be a pointer back to
// the scope. We can therefore can propagate it by simply using the
// scope at the point it is loaded.
bool propagateScope = store->getScope() == knownScope;
// If the scope is a descendent of the scope we are storing into, we
// know that the enclosing scope of the closure will always be reachable
// from the scope that the closure is loaded from. We can therefore can
// propagate it by simply using the scope at the point it is loaded.
bool propagateScope = false;
if (knownScope) {
// Get the scope instruction that is closest to the closure scope in
// this function. Any descendent of this must also be a descendent of
// the closure scope.
Instruction *parent =
getResolveScopeStart(knownScope, knownVarScope, closureVarScope)
.first;
Value *iterScope = store->getScope();
// Walk up the scope chain from the store scope, and see if we reach
// the same parent.
for (;;) {
if (iterScope == parent) {
// The store scope is a descendent of the closure scope, and can
// be used to reach it.
propagateScope = true;
break;
}
auto *CSI = llvh::dyn_cast<CreateScopeInst>(iterScope);
if (!CSI)
break;
iterScope = CSI->getParentScope();
}
}

for (Instruction *varUser : var->getUsers()) {
auto *load = llvh::dyn_cast<LoadFrameInst>(varUser);
Expand Down
3 changes: 2 additions & 1 deletion test/Optimizer/function-analysis-chained-vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ function main() {
// CHECK-NEXT:%BB0:
// CHECK-NEXT: %0 = GetParentScopeInst (:environment) %VS2: any, %parentScope: environment
// CHECK-NEXT: %1 = LoadFrameInst (:object) %0: environment, [%VS2.y]: object
// CHECK-NEXT: %2 = CallInst (:number) %1: object, %x(): functionCode, true: boolean, empty: any, undefined: undefined, 0: number
// CHECK-NEXT: %2 = ResolveScopeInst (:environment) %VS1: any, %VS2: any, %0: environment
// CHECK-NEXT: %3 = CallInst (:number) %1: object, %x(): functionCode, true: boolean, %2: environment, undefined: undefined, 0: number
// CHECK-NEXT: ReturnInst undefined: undefined
// CHECK-NEXT:function_end

0 comments on commit 6ddb3a9

Please sign in to comment.