Store consequentEffects and alternateEffects in consequent and alternate (#2134)

Summary:
Release Notes: None

Follow up on #2110, this PR makes progress towards unifying PossiblyNormalCompletion and ForkedAbruptCompletion as well as unifying completion and effects.

Introduces `updateConsequentKeepingCurrentEffects` for a common pattern of updating one of the completions for a PNC/FAC and fixing up the effects.
Closes https://github.com/facebook/prepack/pull/2134

Differential Revision: D8525738

Pulled By: cblappert

fbshipit-source-id: c415eea47cd786e39820138f84213c2cc9d5e891
This commit is contained in:
Chris Blappert 2018-06-19 16:57:36 -07:00 committed by Facebook Github Bot
parent b59e918fd6
commit 891a4c6ea6
4 changed files with 88 additions and 32 deletions

View File

@ -25,6 +25,8 @@ export class Completion {
target: ?string;
location: ?BabelNodeSourceLocation;
effects: ?Effects;
toDisplayString(): string {
return "[" + this.constructor.name + " value " + (this.value ? this.value.toDisplayString() : "undefined") + "]";
}
@ -81,18 +83,48 @@ export class ForkedAbruptCompletion extends AbruptCompletion {
alternateEffects: Effects
) {
super(realm.intrinsics.empty, consequent.location);
invariant(consequentEffects);
invariant(alternateEffects);
this.joinCondition = joinCondition;
consequent.effects = consequentEffects;
this.consequent = consequent;
this.consequentEffects = consequentEffects;
alternate.effects = alternateEffects;
this.alternate = alternate;
this.alternateEffects = alternateEffects;
}
joinCondition: AbstractValue;
consequent: AbruptCompletion;
consequentEffects: Effects;
alternate: AbruptCompletion;
alternateEffects: Effects;
// For convenience, this.consequent.effects should always be defined, but accessing it directly requires
// verifying that with an invariant.
get consequentEffects(): Effects {
invariant(this.consequent.effects);
return this.consequent.effects;
}
get alternateEffects(): Effects {
invariant(this.alternate.effects);
return this.alternate.effects;
}
updateConsequentKeepingCurrentEffects(newConsequent: AbruptCompletion) {
let effects = this.consequent.effects;
invariant(effects);
newConsequent.effects = effects;
newConsequent.effects.result = newConsequent;
this.consequent = newConsequent;
return newConsequent;
}
updateAlternateKeepingCurrentEffects(newAlternate: AbruptCompletion) {
let effects = this.alternate.effects;
invariant(effects);
newAlternate.effects = effects;
newAlternate.effects.result = newAlternate;
this.alternate = newAlternate;
return newAlternate;
}
toDisplayString(): string {
let superString = super.toDisplayString().slice(0, -1);
@ -170,23 +202,51 @@ export class PossiblyNormalCompletion extends NormalCompletion {
: alternate.expressionLocation;
super(value, loc);
this.joinCondition = joinCondition;
consequent.effects = consequentEffects;
alternate.effects = alternateEffects;
this.consequent = consequent;
this.consequentEffects = consequentEffects;
this.alternate = alternate;
this.alternateEffects = alternateEffects;
this.savedEffects = savedEffects;
this.savedPathConditions = savedPathConditions;
}
joinCondition: AbstractValue;
consequent: Completion;
consequentEffects: Effects;
alternate: Completion;
alternateEffects: Effects;
savedEffects: void | Effects;
// The path conditions that applied at the time of the oldest fork that caused this completion to arise.
savedPathConditions: Array<AbstractValue>;
// For convenience, this.consequent.effects should always be defined, but accessing it directly requires
// verifying that with an invariant.
get consequentEffects(): Effects {
invariant(this.consequent.effects);
return this.consequent.effects;
}
get alternateEffects(): Effects {
invariant(this.alternate.effects);
return this.alternate.effects;
}
// TODO blappert: these functions are a copy of those in ForkedAbruptCompletion, but the two classes will be unified
// soon
updateConsequentKeepingCurrentEffects(newConsequent: Completion) {
let effects = this.consequentEffects;
newConsequent.effects = effects;
newConsequent.effects.result = newConsequent;
this.consequent = newConsequent;
return newConsequent;
}
updateAlternateKeepingCurrentEffects(newAlternate: Completion) {
let effects = this.alternateEffects;
newAlternate.effects = effects;
newAlternate.effects.result = newAlternate;
this.alternate = newAlternate;
return newAlternate;
}
toDisplayString(): string {
let superString = super.toDisplayString().slice(0, -1);
return (

View File

@ -112,7 +112,7 @@ export default function(ast: BabelNodeTryStatement, strictCode: boolean, env: Le
},
"composeNestedThrowEffectsWithHandler/1"
);
c.consequentEffects.result = c.consequent = new AbruptCompletion(realm.intrinsics.empty);
c.updateConsequentKeepingCurrentEffects(new AbruptCompletion(realm.intrinsics.empty));
}
priorEffects.pop();
let alternate = c.alternate;
@ -129,7 +129,7 @@ export default function(ast: BabelNodeTryStatement, strictCode: boolean, env: Le
},
"composeNestedThrowEffectsWithHandler/2"
);
c.alternateEffects.result = c.alternate = new AbruptCompletion(realm.intrinsics.empty);
c.updateAlternateKeepingCurrentEffects(new AbruptCompletion(realm.intrinsics.empty));
}
priorEffects.pop();
return Join.joinForkOrChoose(realm, c.joinCondition, consequentEffects, alternateEffects);

View File

@ -224,18 +224,18 @@ export class JoinImplementation {
pnc.value = v.value;
if (pnc.consequent instanceof AbruptCompletion) {
if (pnc.alternate instanceof SimpleNormalCompletion) {
pnc.alternate = v;
pnc.alternateEffects.result = v;
pnc.alternateEffects = realm.composeEffects(pnc.alternateEffects, subsequentEffects);
v.effects = realm.composeEffects(pnc.alternateEffects, subsequentEffects);
pnc.alternate = v;
} else {
invariant(pnc.alternate instanceof PossiblyNormalCompletion);
this.updatePossiblyNormalCompletionWithSubsequentEffects(realm, pnc.alternate, subsequentEffects);
}
} else {
if (pnc.consequent instanceof SimpleNormalCompletion) {
pnc.consequent = v;
pnc.consequentEffects.result = v;
pnc.consequentEffects = realm.composeEffects(pnc.consequentEffects, subsequentEffects);
v.effects = realm.composeEffects(pnc.consequentEffects, subsequentEffects);
pnc.consequent = v;
} else {
invariant(pnc.consequent instanceof PossiblyNormalCompletion);
this.updatePossiblyNormalCompletionWithSubsequentEffects(realm, pnc.consequent, subsequentEffects);
@ -251,8 +251,7 @@ export class JoinImplementation {
if (v instanceof AbstractValue) v = realm.simplifyAndRefineAbstractValue(v);
if (pnc.alternate instanceof SimpleNormalCompletion) {
nc.value = v;
pnc.alternate = nc;
pnc.alternateEffects.result = nc;
pnc.updateAlternateKeepingCurrentEffects(nc);
pnc.value = v;
} else {
invariant(pnc.alternate instanceof PossiblyNormalCompletion);
@ -266,8 +265,7 @@ export class JoinImplementation {
if (v instanceof AbstractValue) v = realm.simplifyAndRefineAbstractValue(v);
if (pnc.consequent instanceof SimpleNormalCompletion) {
nc.value = v;
pnc.consequent = nc;
pnc.consequentEffects.result = nc;
pnc.updateConsequentKeepingCurrentEffects(nc);
pnc.value = v;
} else {
invariant(pnc.consequent instanceof PossiblyNormalCompletion);
@ -364,8 +362,7 @@ export class JoinImplementation {
if (pnc.consequent instanceof AbruptCompletion) {
if (pnc.alternate instanceof SimpleNormalCompletion) {
nc.value = AbstractValue.createFromConditionalOp(realm, joinCondition, v, pnc.alternate.value);
pnc.alternate = nc;
pnc.alternateEffects.result = pnc.alternate;
pnc.updateAlternateKeepingCurrentEffects(nc);
} else {
invariant(pnc.alternate instanceof PossiblyNormalCompletion);
this.updatePossiblyNormalCompletionWithInverseConditionalSimpleNormalCompletion(
@ -378,8 +375,7 @@ export class JoinImplementation {
} else {
if (pnc.consequent instanceof SimpleNormalCompletion) {
nc.value = AbstractValue.createFromConditionalOp(realm, joinCondition, v, pnc.consequent.value);
pnc.consequent = nc;
pnc.consequentEffects.result = pnc.consequent;
pnc.updateConsequentKeepingCurrentEffects(nc);
} else {
invariant(pnc.consequent instanceof PossiblyNormalCompletion);
this.updatePossiblyNormalCompletionWithInverseConditionalSimpleNormalCompletion(
@ -444,12 +440,12 @@ export class JoinImplementation {
if (ce.result instanceof CompletionType) {
// Erase completions of type CompletionType and prepare for transformation of c to a possibly normal completion
if (c.consequent instanceof CompletionType) {
c.consequentEffects.result = c.consequent = convertToPNC
? new SimpleNormalCompletion(realm.intrinsics.empty)
: dummyCompletion;
c.updateConsequentKeepingCurrentEffects(
convertToPNC ? new SimpleNormalCompletion(realm.intrinsics.empty) : dummyCompletion
);
convertToPNC = false;
} else if (convertToPNC && c.consequent instanceof ForkedAbruptCompletion) {
c.consequentEffects.result = c.consequent = (c.consequent.transferChildrenToPossiblyNormalCompletion(): any);
c.updateConsequentKeepingCurrentEffects((c.consequent.transferChildrenToPossiblyNormalCompletion(): any));
convertToPNC = false;
}
} else {
@ -464,11 +460,11 @@ export class JoinImplementation {
if (ae.result instanceof CompletionType) {
// Erase completions of type CompletionType and prepare for transformation of c to a possibly normal completion
if (c.alternate instanceof CompletionType) {
c.alternateEffects.result = c.alternate = convertToPNC
? new SimpleNormalCompletion(realm.intrinsics.empty)
: dummyCompletion;
c.updateAlternateKeepingCurrentEffects(
convertToPNC ? new SimpleNormalCompletion(realm.intrinsics.empty) : dummyCompletion
);
} else if (convertToPNC && c.alternate instanceof ForkedAbruptCompletion) {
c.alternateEffects.result = c.alternate = (c.alternate.transferChildrenToPossiblyNormalCompletion(): any);
c.updateAlternateKeepingCurrentEffects((c.alternate.transferChildrenToPossiblyNormalCompletion(): any));
}
} else {
ae.result = new CompletionType(realm.intrinsics.empty);

View File

@ -1178,12 +1178,12 @@ export class Realm {
updateAbruptCompletions(priorEffects: Effects, c: PossiblyNormalCompletion) {
if (c.consequent instanceof AbruptCompletion) {
c.consequentEffects = this.composeEffects(priorEffects, c.consequentEffects);
c.consequent.effects = this.composeEffects(priorEffects, c.consequentEffects);
let alternate = c.alternate;
if (alternate instanceof PossiblyNormalCompletion) this.updateAbruptCompletions(priorEffects, alternate);
} else {
invariant(c.alternate instanceof AbruptCompletion);
c.alternateEffects = this.composeEffects(priorEffects, c.alternateEffects);
c.alternate.effects = this.composeEffects(priorEffects, c.alternateEffects);
let consequent = c.consequent;
if (consequent instanceof PossiblyNormalCompletion) this.updateAbruptCompletions(priorEffects, consequent);
}