Don't purge bindings when execution leaves scope (#2136)

Summary:
Release notes: None

For historical and apparently no longer needed reasons,
we used to forget about modified bindings when execution
leaves scopes.

However, this means that the binding no longer properly participates
in state tracking, which is conceptually dubious.

While by itself, it didn't seem to cause much (or any?) harm,
it turned out to be a blocker for #2125, where the initial state
of a binding becomes important when joining partially leaked bindings.
Closes https://github.com/facebook/prepack/pull/2136

Reviewed By: hermanventer

Differential Revision: D8528939

Pulled By: NTillmann

fbshipit-source-id: 0890c32d55f6b498cb4613171eee54ff9b445730
This commit is contained in:
Nikolai Tillmann 2018-06-19 20:48:18 -07:00 committed by Facebook Github Bot
parent 722a31a01c
commit 5ad625048a

View File

@ -495,46 +495,10 @@ export class Realm {
return context;
}
clearBlockBindings(modifiedBindings: void | Bindings, environmentRecord: DeclarativeEnvironmentRecord) {
if (modifiedBindings === undefined) return;
for (let b of modifiedBindings.keys())
if (environmentRecord.bindings[b.name] && environmentRecord.bindings[b.name] === b) modifiedBindings.delete(b);
}
clearBlockBindingsFromCompletion(completion: Completion, environmentRecord: DeclarativeEnvironmentRecord) {
if (completion instanceof PossiblyNormalCompletion) {
this.clearBlockBindings(completion.alternateEffects.modifiedBindings, environmentRecord);
this.clearBlockBindings(completion.consequentEffects.modifiedBindings, environmentRecord);
if (completion.savedEffects !== undefined)
this.clearBlockBindings(completion.savedEffects.modifiedBindings, environmentRecord);
if (completion.alternate instanceof Completion)
this.clearBlockBindingsFromCompletion(completion.alternate, environmentRecord);
if (completion.consequent instanceof Completion)
this.clearBlockBindingsFromCompletion(completion.consequent, environmentRecord);
} else if (completion instanceof ForkedAbruptCompletion) {
this.clearBlockBindings(completion.alternateEffects.modifiedBindings, environmentRecord);
this.clearBlockBindings(completion.consequentEffects.modifiedBindings, environmentRecord);
if (completion.alternate instanceof Completion)
this.clearBlockBindingsFromCompletion(completion.alternate, environmentRecord);
if (completion.consequent instanceof Completion)
this.clearBlockBindingsFromCompletion(completion.consequent, environmentRecord);
}
}
// Call when a scope falls out of scope and should be destroyed.
// Clears the Bindings corresponding to the disappearing Scope from ModifiedBindings
onDestroyScope(lexicalEnvironment: LexicalEnvironment) {
invariant(this.activeLexicalEnvironments.has(lexicalEnvironment));
let modifiedBindings = this.modifiedBindings;
if (modifiedBindings) {
// Don't undo things to global scope because it's needed past its destruction point (for serialization)
let environmentRecord = lexicalEnvironment.environmentRecord;
if (environmentRecord instanceof DeclarativeEnvironmentRecord) {
this.clearBlockBindings(modifiedBindings, environmentRecord);
if (this.savedCompletion !== undefined)
this.clearBlockBindingsFromCompletion(this.savedCompletion, environmentRecord);
}
}
// Ensures if we call onDestroyScope too early, there will be a failure.
this.activeLexicalEnvironments.delete(lexicalEnvironment);
@ -548,40 +512,7 @@ export class Realm {
this.contextStack.push(context);
}
clearFunctionBindings(modifiedBindings: void | Bindings, funcVal: FunctionValue) {
if (modifiedBindings === undefined) return;
for (let b of modifiedBindings.keys()) {
if (b.environment instanceof FunctionEnvironmentRecord && b.environment.$FunctionObject === funcVal)
modifiedBindings.delete(b);
}
}
clearFunctionBindingsFromCompletion(completion: Completion, funcVal: FunctionValue) {
if (completion instanceof PossiblyNormalCompletion) {
this.clearFunctionBindings(completion.alternateEffects.modifiedBindings, funcVal);
this.clearFunctionBindings(completion.consequentEffects.modifiedBindings, funcVal);
if (completion.savedEffects !== undefined)
this.clearFunctionBindings(completion.savedEffects.modifiedBindings, funcVal);
if (completion.alternate instanceof Completion)
this.clearFunctionBindingsFromCompletion(completion.alternate, funcVal);
if (completion.consequent instanceof Completion)
this.clearFunctionBindingsFromCompletion(completion.consequent, funcVal);
} else if (completion instanceof ForkedAbruptCompletion) {
this.clearFunctionBindings(completion.alternateEffects.modifiedBindings, funcVal);
this.clearFunctionBindings(completion.consequentEffects.modifiedBindings, funcVal);
if (completion.alternate instanceof Completion)
this.clearFunctionBindingsFromCompletion(completion.alternate, funcVal);
if (completion.consequent instanceof Completion)
this.clearFunctionBindingsFromCompletion(completion.consequent, funcVal);
}
}
popContext(context: ExecutionContext): void {
let funcVal = context.function;
if (funcVal) {
this.clearFunctionBindings(this.modifiedBindings, funcVal);
if (this.savedCompletion !== undefined) this.clearFunctionBindingsFromCompletion(this.savedCompletion, funcVal);
}
let c = this.contextStack.pop();
invariant(c === context);
}