mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-11-09 21:20:06 +03:00
Do not conflate prior saved completion with one from call.
Summary: Release note: Fix bug #1262 The saved completion that is present before a function call should not be incorporated into the saved completion that is created inside the call, until after return completions have been appropriately joined and applied. Closes https://github.com/facebook/prepack/pull/1263 Differential Revision: D6560937 Pulled By: hermanventer fbshipit-source-id: 76e8d67f0ad2227dec9cf54f5f035a34f1941be3
This commit is contained in:
parent
f4271d56f0
commit
5e86f790aa
@ -331,49 +331,55 @@ export function OrdinaryCallEvaluateBody(
|
||||
|
||||
// 2. Return the result of EvaluateBody of the parsed code that is the value of F's
|
||||
// [[ECMAScriptCode]] internal slot passing F as the argument.
|
||||
let code = F.$ECMAScriptCode;
|
||||
invariant(code !== undefined);
|
||||
let context = realm.getRunningContext();
|
||||
let c = context.lexicalEnvironment.evaluateCompletionDeref(code, F.$Strict);
|
||||
// We are about the leave this function and this presents a join point where all non exeptional control flows
|
||||
// converge into a single flow using the joined effects as the new state.
|
||||
c = Functions.incorporateSavedCompletion(realm, c);
|
||||
let joinedEffects;
|
||||
if (c instanceof PossiblyNormalCompletion) {
|
||||
let e = realm.getCapturedEffects(c);
|
||||
if (e !== undefined) {
|
||||
// There were earlier, conditional exits from the function
|
||||
// We join together the current effects with the effects of any earlier returns that are tracked in c.
|
||||
realm.stopEffectCaptureAndUndoEffects(c);
|
||||
} else {
|
||||
e = construct_empty_effects(realm);
|
||||
let priorSavedCompletion = realm.savedCompletion;
|
||||
try {
|
||||
realm.savedCompletion = undefined;
|
||||
let code = F.$ECMAScriptCode;
|
||||
invariant(code !== undefined);
|
||||
let context = realm.getRunningContext();
|
||||
let c = context.lexicalEnvironment.evaluateCompletionDeref(code, F.$Strict);
|
||||
// We are about the leave this function and this presents a join point where all non exeptional control flows
|
||||
// converge into a single flow using the joined effects as the new state.
|
||||
c = Functions.incorporateSavedCompletion(realm, c);
|
||||
let joinedEffects;
|
||||
if (c instanceof PossiblyNormalCompletion) {
|
||||
let e = realm.getCapturedEffects(c);
|
||||
if (e !== undefined) {
|
||||
// There were earlier, conditional exits from the function
|
||||
// We join together the current effects with the effects of any earlier returns that are tracked in c.
|
||||
realm.stopEffectCaptureAndUndoEffects(c);
|
||||
} else {
|
||||
e = construct_empty_effects(realm);
|
||||
}
|
||||
joinedEffects = Join.joinEffectsAndPromoteNestedReturnCompletions(realm, c, e);
|
||||
} else if (c instanceof JoinedAbruptCompletions) {
|
||||
joinedEffects = Join.joinEffectsAndPromoteNestedReturnCompletions(realm, c, construct_empty_effects(realm));
|
||||
}
|
||||
joinedEffects = Join.joinEffectsAndPromoteNestedReturnCompletions(realm, c, e);
|
||||
} else if (c instanceof JoinedAbruptCompletions) {
|
||||
joinedEffects = Join.joinEffectsAndPromoteNestedReturnCompletions(realm, c, construct_empty_effects(realm));
|
||||
}
|
||||
if (joinedEffects !== undefined) {
|
||||
let result = joinedEffects[0];
|
||||
if (result instanceof ReturnCompletion) {
|
||||
if (joinedEffects !== undefined) {
|
||||
let result = joinedEffects[0];
|
||||
if (result instanceof ReturnCompletion) {
|
||||
realm.applyEffects(joinedEffects);
|
||||
return result;
|
||||
}
|
||||
invariant(result instanceof JoinedAbruptCompletions);
|
||||
if (!(result.consequent instanceof ReturnCompletion || result.alternate instanceof ReturnCompletion)) {
|
||||
realm.applyEffects(joinedEffects);
|
||||
throw result;
|
||||
}
|
||||
// There is a normal return exit, but also one or more throw completions.
|
||||
// The throw completions must be extracted into a saved possibly normal completion
|
||||
// so that the caller can pick them up in its next completion.
|
||||
joinedEffects = extractAndSavePossiblyNormalCompletion(result);
|
||||
result = joinedEffects[0];
|
||||
invariant(result instanceof ReturnCompletion);
|
||||
realm.applyEffects(joinedEffects);
|
||||
return result;
|
||||
} else {
|
||||
invariant(c instanceof Value || c instanceof AbruptCompletion);
|
||||
return c;
|
||||
}
|
||||
invariant(result instanceof JoinedAbruptCompletions);
|
||||
if (!(result.consequent instanceof ReturnCompletion || result.alternate instanceof ReturnCompletion)) {
|
||||
realm.applyEffects(joinedEffects);
|
||||
throw result;
|
||||
}
|
||||
// There is a normal return exit, but also one or more throw completions.
|
||||
// The throw completions must be extracted into a saved possibly normal completion
|
||||
// so that the caller can pick them up in its next completion.
|
||||
joinedEffects = extractAndSavePossiblyNormalCompletion(result);
|
||||
result = joinedEffects[0];
|
||||
invariant(result instanceof ReturnCompletion);
|
||||
realm.applyEffects(joinedEffects);
|
||||
return result;
|
||||
} else {
|
||||
invariant(c instanceof Value || c instanceof AbruptCompletion);
|
||||
return c;
|
||||
} finally {
|
||||
realm.incorporatePriorSavedCompletion(priorSavedCompletion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
src/realm.js
10
src/realm.js
@ -612,6 +612,16 @@ export class Realm {
|
||||
return completion.value;
|
||||
}
|
||||
|
||||
incorporatePriorSavedCompletion(priorCompletion: void | PossiblyNormalCompletion) {
|
||||
if (priorCompletion === undefined) return;
|
||||
if (this.savedCompletion === undefined) {
|
||||
this.savedCompletion = priorCompletion;
|
||||
this.captureEffects(priorCompletion);
|
||||
} else {
|
||||
this.savedCompletion = Join.composePossiblyNormalCompletions(this, priorCompletion, this.savedCompletion);
|
||||
}
|
||||
}
|
||||
|
||||
captureEffects(completion: PossiblyNormalCompletion) {
|
||||
if (completion.savedEffects !== undefined) {
|
||||
// Already called captureEffects, just carry on
|
||||
|
13
test/serializer/abstract/Return9.js
Normal file
13
test/serializer/abstract/Return9.js
Normal file
@ -0,0 +1,13 @@
|
||||
let b = global.__abstract ? __abstract("boolean", "true") : true;
|
||||
function f() {}
|
||||
|
||||
function g() {
|
||||
|
||||
if (b) return "foo";
|
||||
f();
|
||||
return "bar";
|
||||
}
|
||||
|
||||
var x = g();
|
||||
|
||||
inspect = function() { return x; }
|
Loading…
Reference in New Issue
Block a user