prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
691 lines (650 loc) • 34.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.JoinImplementation = undefined;
var _errors = require("../errors.js");
var _completions = require("../completions.js");
var _environment = require("../environment.js");
var _index = require("../methods/index.js");
var _realm = require("../realm.js");
var _generator = require("../utils/generator.js");
var _index2 = require("../values/index.js");
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function joinGenerators(realm, joinCondition, generator1, generator2) {
let result = new _generator.Generator(realm, "joined");
if (!generator1.empty() || !generator2.empty()) {
result.joinGenerators(joinCondition, generator1, generator2);
}
return result;
} /**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
function joinArrays(realm, v1, v2, getAbstractValue) {
let e = v1 && v1[0] || v2 && v2[0];
if (e instanceof _index2.Value) return joinArraysOfValues(realm, v1, v2, getAbstractValue);else return joinArrayOfsMapEntries(realm, v1, v2, getAbstractValue);
}
function joinArrayOfsMapEntries(realm, a1, a2, getAbstractValue) {
let empty = realm.intrinsics.empty;
let n = Math.max(a1 && a1.length || 0, a2 && a2.length || 0);
let result = [];
for (let i = 0; i < n; i++) {
let { $Key: key1, $Value: val1 } = a1 && a1[i] || { $Key: empty, $Value: empty };
let { $Key: key2, $Value: val2 } = a2 && a2[i] || { $Key: empty, $Value: empty };
if (key1 === undefined && key2 === undefined) {
result[i] = { $Key: undefined, $Value: undefined };
} else {
let key3 = getAbstractValue(key1, key2);
let val3 = getAbstractValue(val1, val2);
result[i] = { $Key: key3, $Value: val3 };
}
}
return result;
}
function joinArraysOfValues(realm, a1, a2, getAbstractValue) {
let n = Math.max(a1 && a1.length || 0, a2 && a2.length || 0);
let result = [];
for (let i = 0; i < n; i++) {
result[i] = getAbstractValue(a1 && a1[i] || undefined, a2 && a2[i] || undefined);
}
return result;
}
class JoinImplementation {
stopEffectCaptureJoinApplyAndReturnCompletion(c1, c2, realm) {
let e = realm.getCapturedEffects(c1);
(0, _invariant2.default)(e !== undefined);
realm.stopEffectCaptureAndUndoEffects(c1);
let joined_effects = this.joinPossiblyNormalCompletionWithAbruptCompletion(realm, c1, c2, e);
realm.applyEffects(joined_effects);
let result = joined_effects[0];
(0, _invariant2.default)(result instanceof _completions.AbruptCompletion);
return result;
}
unbundleNormalCompletion(completionOrValue) {
let completion, value;
if (completionOrValue instanceof _completions.PossiblyNormalCompletion) {
completion = completionOrValue;
value = completionOrValue.value;
} else {
(0, _invariant2.default)(completionOrValue instanceof _index2.Value || completionOrValue instanceof _environment.Reference);
value = completionOrValue;
}
return [completion, value];
}
composeNormalCompletions(leftCompletion, rightCompletion, resultValue, realm) {
if (leftCompletion instanceof _completions.PossiblyNormalCompletion) {
if (rightCompletion instanceof _completions.PossiblyNormalCompletion) {
this.updatePossiblyNormalCompletionWithValue(realm, rightCompletion, resultValue);
return this.composePossiblyNormalCompletions(realm, leftCompletion, rightCompletion);
}
this.updatePossiblyNormalCompletionWithValue(realm, leftCompletion, resultValue);
return leftCompletion;
} else if (rightCompletion instanceof _completions.PossiblyNormalCompletion) {
this.updatePossiblyNormalCompletionWithValue(realm, rightCompletion, resultValue);
return rightCompletion;
} else {
(0, _invariant2.default)(leftCompletion === undefined && rightCompletion === undefined);
return resultValue;
}
}
composePossiblyNormalCompletions(realm, pnc, c) {
(0, _invariant2.default)(c.savedEffects === undefined); // the caller should ensure this
let savedPathConditions = pnc.savedPathConditions;
if (pnc.consequent instanceof _completions.AbruptCompletion) {
if (pnc.alternate instanceof _index2.Value) {
let [, g, b, p, o] = pnc.alternateEffects;
let newAlternateEffects = [c, g, b, p, o];
return new _completions.PossiblyNormalCompletion(c.value, pnc.joinCondition, pnc.consequent, pnc.consequentEffects, c, newAlternateEffects, savedPathConditions, pnc.savedEffects);
}
(0, _invariant2.default)(pnc.alternate instanceof _completions.PossiblyNormalCompletion);
let new_alternate = this.composePossiblyNormalCompletions(realm, pnc.alternate, c);
let [, g, b, p, o] = pnc.alternateEffects;
let newAlternateEffects = [new_alternate, g, b, p, o];
return new _completions.PossiblyNormalCompletion(new_alternate.value, pnc.joinCondition, pnc.consequent, pnc.consequentEffects, new_alternate, newAlternateEffects, savedPathConditions, pnc.savedEffects);
} else {
(0, _invariant2.default)(pnc.alternate instanceof _completions.AbruptCompletion);
if (pnc.consequent instanceof _index2.Value) {
let [, g, b, p, o] = pnc.consequentEffects;
let newConsequentEffects = [c, g, b, p, o];
return new _completions.PossiblyNormalCompletion(c.value, pnc.joinCondition, c, newConsequentEffects, pnc.alternate, pnc.alternateEffects, savedPathConditions, pnc.savedEffects);
}
(0, _invariant2.default)(pnc.consequent instanceof _completions.PossiblyNormalCompletion);
let new_consequent = this.composePossiblyNormalCompletions(realm, pnc.consequent, c);
let [, g, b, p, o] = pnc.consequentEffects;
let newConsequentEffects = [new_consequent, g, b, p, o];
return new _completions.PossiblyNormalCompletion(new_consequent.value, pnc.joinCondition, new_consequent, newConsequentEffects, pnc.alternate, pnc.alternateEffects, savedPathConditions, pnc.savedEffects);
}
}
updatePossiblyNormalCompletionWithSubsequentEffects(realm, pnc, subsequentEffects) {
let v = subsequentEffects[0];
(0, _invariant2.default)(v instanceof _index2.Value);
pnc.value = v;
if (pnc.consequent instanceof _completions.AbruptCompletion) {
if (pnc.alternate instanceof _index2.Value) {
pnc.alternate = v;
pnc.alternateEffects[0] = v;
pnc.alternateEffects = realm.composeEffects(pnc.alternateEffects, subsequentEffects);
} else {
(0, _invariant2.default)(pnc.alternate instanceof _completions.PossiblyNormalCompletion);
this.updatePossiblyNormalCompletionWithSubsequentEffects(realm, pnc.alternate, subsequentEffects);
}
} else {
if (pnc.consequent instanceof _index2.Value) {
pnc.consequent = v;
pnc.consequentEffects[0] = v;
pnc.consequentEffects = realm.composeEffects(pnc.consequentEffects, subsequentEffects);
} else {
(0, _invariant2.default)(pnc.consequent instanceof _completions.PossiblyNormalCompletion);
this.updatePossiblyNormalCompletionWithSubsequentEffects(realm, pnc.consequent, subsequentEffects);
}
}
}
updatePossiblyNormalCompletionWithValue(realm, pnc, v) {
pnc.value = v;
if (pnc.consequent instanceof _completions.AbruptCompletion) {
if (pnc.alternate instanceof _index2.Value) {
pnc.alternate = v;
pnc.alternateEffects[0] = v;
} else {
(0, _invariant2.default)(pnc.alternate instanceof _completions.PossiblyNormalCompletion);
this.updatePossiblyNormalCompletionWithValue(realm, pnc.alternate, v);
}
} else {
if (pnc.consequent instanceof _index2.Value) {
pnc.consequent = v;
pnc.consequentEffects[0] = v;
} else {
(0, _invariant2.default)(pnc.consequent instanceof _completions.PossiblyNormalCompletion);
this.updatePossiblyNormalCompletionWithValue(realm, pnc.consequent, v);
}
}
}
// Returns the joined effects of all of the paths in pnc.
// The normal path in pnc is modified to become terminated by ac,
// so the overall completion will always be an instance of JoinedAbruptCompletions
joinPossiblyNormalCompletionWithAbruptCompletion(realm,
// a forked path with a non abrupt (normal) component
pnc,
// an abrupt completion that completes the normal path
ac,
// effects collected after pnc was constructed
e) {
// set up e with ac as the completion. It's OK to do this repeatedly since ac is not changed by recursive calls.
e[0] = ac;
if (pnc.consequent instanceof _completions.AbruptCompletion) {
if (pnc.alternate instanceof _index2.Value) {
return this.joinEffects(realm, pnc.joinCondition, pnc.consequentEffects, realm.composeEffects(pnc.alternateEffects, e));
}
(0, _invariant2.default)(pnc.alternate instanceof _completions.PossiblyNormalCompletion);
let alternate_effects = this.joinPossiblyNormalCompletionWithAbruptCompletion(realm, pnc.alternate, ac, e);
let composedEffects = realm.composeEffects(pnc.alternateEffects, alternate_effects);
(0, _invariant2.default)(pnc.consequent instanceof _completions.AbruptCompletion);
return this.joinEffects(realm, pnc.joinCondition, pnc.consequentEffects, composedEffects);
} else {
(0, _invariant2.default)(pnc.alternate instanceof _completions.AbruptCompletion);
if (pnc.consequent instanceof _index2.Value) {
return this.joinEffects(realm, pnc.joinCondition, realm.composeEffects(pnc.consequentEffects, e), pnc.alternateEffects);
}
(0, _invariant2.default)(pnc.consequent instanceof _completions.PossiblyNormalCompletion);
let consequent_effects = this.joinPossiblyNormalCompletionWithAbruptCompletion(realm, pnc.consequent, ac, e);
let composedEffects = realm.composeEffects(pnc.consequentEffects, consequent_effects);
(0, _invariant2.default)(pnc.alternate instanceof _completions.AbruptCompletion);
return this.joinEffects(realm, pnc.joinCondition, composedEffects, pnc.alternateEffects);
}
}
joinPossiblyNormalCompletionWithValue(realm, joinCondition, pnc, v) {
if (pnc.consequent instanceof _completions.AbruptCompletion) {
if (pnc.alternate instanceof _index2.Value) {
pnc.alternate = this.joinValuesAsConditional(realm, joinCondition, pnc.alternate, v);
pnc.alternateEffects[0] = pnc.alternate;
} else {
(0, _invariant2.default)(pnc.alternate instanceof _completions.PossiblyNormalCompletion);
this.joinPossiblyNormalCompletionWithValue(realm, joinCondition, pnc.alternate, v);
}
} else {
if (pnc.consequent instanceof _index2.Value) {
pnc.consequent = this.joinValuesAsConditional(realm, joinCondition, pnc.consequent, v);
pnc.consequentEffects[0] = pnc.consequent;
} else {
(0, _invariant2.default)(pnc.consequent instanceof _completions.PossiblyNormalCompletion);
this.joinPossiblyNormalCompletionWithValue(realm, joinCondition, pnc.consequent, v);
}
}
}
joinValueWithPossiblyNormalCompletion(realm, joinCondition, pnc, v) {
if (pnc.consequent instanceof _completions.AbruptCompletion) {
if (pnc.alternate instanceof _index2.Value) {
pnc.alternate = this.joinValuesAsConditional(realm, joinCondition, v, pnc.alternate);
pnc.alternateEffects[0] = pnc.alternate;
} else {
(0, _invariant2.default)(pnc.alternate instanceof _completions.PossiblyNormalCompletion);
this.joinValueWithPossiblyNormalCompletion(realm, joinCondition, pnc.alternate, v);
}
} else {
if (pnc.consequent instanceof _index2.Value) {
pnc.consequent = this.joinValuesAsConditional(realm, joinCondition, v, pnc.consequent);
pnc.consequentEffects[0] = pnc.consequent;
} else {
(0, _invariant2.default)(pnc.consequent instanceof _completions.PossiblyNormalCompletion);
this.joinValueWithPossiblyNormalCompletion(realm, joinCondition, pnc.consequent, v);
}
}
}
joinPossiblyNormalCompletions(realm, joinCondition, c, a) {
let rJoinCondition;
let cp;
let ap;
if (c.consequent instanceof _completions.AbruptCompletion) {
if (a.consequent instanceof _completions.AbruptCompletion) {
rJoinCondition = _index2.AbstractValue.createFromLogicalOp(realm, "&&", c.joinCondition, a.joinCondition);
cp = [c.consequentEffects, a.consequentEffects];
ap = [c.alternateEffects, a.alternateEffects];
} else {
let notA = _index2.AbstractValue.createFromUnaryOp(realm, "!", a.joinCondition);
rJoinCondition = _index2.AbstractValue.createFromLogicalOp(realm, "&&", c.joinCondition, notA);
cp = [c.consequentEffects, a.alternateEffects];
ap = [c.alternateEffects, a.consequentEffects];
}
} else {
let notC = _index2.AbstractValue.createFromUnaryOp(realm, "!", c.joinCondition);
if (a.consequent instanceof _completions.AbruptCompletion) {
rJoinCondition = _index2.AbstractValue.createFromLogicalOp(realm, "&&", notC, a.joinCondition);
cp = [c.alternateEffects, a.consequentEffects];
ap = [c.consequentEffects, a.alternateEffects];
} else {
let notA = _index2.AbstractValue.createFromUnaryOp(realm, "!", a.joinCondition);
rJoinCondition = _index2.AbstractValue.createFromLogicalOp(realm, "&&", notC, notA);
cp = [c.alternateEffects, a.alternateEffects];
ap = [c.consequentEffects, a.consequentEffects];
}
}
(0, _invariant2.default)(rJoinCondition instanceof _index2.AbstractValue); // the transformations will not result in tautologies
let [ce1, ce2] = cp;
let [ae1, ae2] = ap;
let rce = this.joinEffects(realm, joinCondition, ce1, ce2);
let rae = this.joinEffects(realm, joinCondition, ae1, ae2);
let rc = rce[0];
(0, _invariant2.default)(rc instanceof _index2.Value || rc instanceof _completions.Completion);
let ra = rae[0];
(0, _invariant2.default)(ra instanceof _index2.Value || ra instanceof _completions.Completion);
let rv = ra instanceof _completions.PossiblyNormalCompletion ? ra.value : ra;
(0, _invariant2.default)(rv instanceof _index2.Value);
return new _completions.PossiblyNormalCompletion(rv, rJoinCondition, rc, rce, ra, rae, []);
}
joinEffectsAndPromoteNestedReturnCompletions(realm, c, e, nested_effects) {
if (c instanceof _index2.Value) {
// If not undefined, the nested effects were captured when evaluating a conditional code block that ended normally.
// e represent effects that were captured since reaching the join point where the normal and abrupt
// completions came together into the completion supplied to the outermost call to this recursive function.
if (nested_effects !== undefined) e = realm.composeEffects(nested_effects, e);
return e;
}
if (c instanceof _completions.AbruptCompletion && !(c instanceof _completions.JoinedAbruptCompletions)) {
// The nested effects were captured when evaluating a conditional code block that ended abruptly.
// An abrupt completion does not care about the effects that were collected since the join point.
(0, _invariant2.default)(nested_effects !== undefined);
return nested_effects;
}
if (c instanceof _completions.PossiblyNormalCompletion) {
let e1 = this.joinEffectsAndPromoteNestedReturnCompletions(realm, c.consequent, e, c.consequentEffects);
let e2 = this.joinEffectsAndPromoteNestedReturnCompletions(realm, c.alternate, e, c.alternateEffects);
if (e1[0] instanceof _completions.AbruptCompletion) {
if (e2[0] instanceof _index2.Value) e2[0] = new _completions.ReturnCompletion(realm.intrinsics.undefined, realm.currentLocation);
return this.joinEffects(realm, c.joinCondition, e1, e2);
} else if (e2[0] instanceof _completions.AbruptCompletion) {
if (e1[0] instanceof _index2.Value) e1[0] = new _completions.ReturnCompletion(realm.intrinsics.undefined, realm.currentLocation);
return this.joinEffects(realm, c.joinCondition, e1, e2);
}
}
(0, _invariant2.default)(c instanceof _completions.JoinedAbruptCompletions);
// e will be ignored in the calls below since the branches are all abrupt.
let e1 = this.joinEffectsAndPromoteNestedReturnCompletions(realm, c.consequent, e, c.consequentEffects);
let e2 = this.joinEffectsAndPromoteNestedReturnCompletions(realm, c.alternate, e, c.alternateEffects);
let [r1, r2] = [e1[0], e2[0]];
if (r1 instanceof _completions.ReturnCompletion) {
// this can happen because joinEffectsAndPromoteNestedReturnCompletions above both had nested ReturnCompletions
if (r2 instanceof _completions.ReturnCompletion) {
return this.joinEffects(realm, c.joinCondition, e1, e2);
}
if (r2 instanceof _completions.JoinedAbruptCompletions) {
if (r2.consequent instanceof _completions.ReturnCompletion) {
let r1jr2c = this.joinEffects(realm, c.joinCondition, e1, r2.consequentEffects);
(0, _invariant2.default)(r1jr2c[0] instanceof _completions.ReturnCompletion);
let or = _index2.AbstractValue.createFromLogicalOp(realm, "||", c.joinCondition, r2.joinCondition);
(0, _invariant2.default)(or instanceof _index2.AbstractValue);
return this.joinEffects(realm, or, r1jr2c, r2.alternateEffects);
}
if (r2.alternate instanceof _completions.ReturnCompletion) {
let r1jr2a = this.joinEffects(realm, c.joinCondition, e1, r2.alternateEffects);
(0, _invariant2.default)(r1jr2a[0] instanceof _completions.ReturnCompletion);
let notR2jc = _index2.AbstractValue.createFromUnaryOp(realm, "!", r2.joinCondition);
let or = _index2.AbstractValue.createFromLogicalOp(realm, "||", c.joinCondition, notR2jc);
(0, _invariant2.default)(or instanceof _index2.AbstractValue);
return this.joinEffects(realm, or, r1jr2a, r2.consequentEffects);
}
}
} else if (r2 instanceof _completions.ReturnCompletion) {
(0, _invariant2.default)(!(r1 instanceof _completions.ReturnCompletion)); // Otherwise their values should have been joined
if (r1 instanceof _completions.JoinedAbruptCompletions) {
if (r1.consequent instanceof _completions.ReturnCompletion) {
let r2jr1c = this.joinEffects(realm, c.joinCondition, r1.consequentEffects, e2);
(0, _invariant2.default)(r2jr1c[0] instanceof _completions.ReturnCompletion);
let or = _index2.AbstractValue.createFromLogicalOp(realm, "||", c.joinCondition, r1.joinCondition);
(0, _invariant2.default)(or instanceof _index2.AbstractValue);
return this.joinEffects(realm, or, r2jr1c, r1.alternateEffects);
}
if (r1.alternate instanceof _completions.ReturnCompletion) {
let r2jr1a = this.joinEffects(realm, c.joinCondition, r1.alternateEffects, e2);
let notR1jc = _index2.AbstractValue.createFromUnaryOp(realm, "!", r1.joinCondition);
(0, _invariant2.default)(r2jr1a[0] instanceof _completions.ReturnCompletion);
let or = _index2.AbstractValue.createFromLogicalOp(realm, "||", c.joinCondition, notR1jc);
(0, _invariant2.default)(or instanceof _index2.AbstractValue);
return this.joinEffects(realm, or, r2jr1a, r1.consequentEffects);
}
}
}
let e3 = this.joinEffects(realm, c.joinCondition, e1, e2);
let [r3] = e3;
if (r3 instanceof _completions.JoinedAbruptCompletions) {
let [joinedEffects, possiblyNormalCompletion] = this.unbundleReturnCompletion(realm, r3);
realm.composeWithSavedCompletion(possiblyNormalCompletion);
return joinedEffects;
}
return e3;
}
unbundleReturnCompletion(realm, c) {
let empty_effects = (0, _realm.construct_empty_effects)(realm);
let v = realm.intrinsics.empty;
if (c.consequent instanceof _completions.ReturnCompletion) {
let pnc = new _completions.PossiblyNormalCompletion(v, c.joinCondition, v, empty_effects, c.alternate, c.alternateEffects, []);
return [c.consequentEffects, pnc];
} else if (c.alternate instanceof _completions.ReturnCompletion) {
let pnc = new _completions.PossiblyNormalCompletion(v, c.joinCondition, c.consequent, c.consequentEffects, v, empty_effects, []);
return [c.alternateEffects, pnc];
} else {
(0, _invariant2.default)(false, "unbundleReturnCompletion needs an argument that contains a non nested return completion");
}
}
removeNormalEffects(realm, c) {
if (c.consequent instanceof _completions.AbruptCompletion) {
if (c.alternate instanceof _index2.Value) {
let result = c.alternateEffects;
c.alternateEffects = (0, _realm.construct_empty_effects)(realm);
return result;
} else {
(0, _invariant2.default)(c.alternate instanceof _completions.PossiblyNormalCompletion);
let result = realm.composeEffects(c.alternateEffects, this.removeNormalEffects(realm, c.alternate));
c.alternateEffects = (0, _realm.construct_empty_effects)(realm);
return result;
}
} else {
if (c.consequent instanceof _index2.Value) {
let result = c.consequentEffects;
c.consequentEffects = (0, _realm.construct_empty_effects)(realm);
return result;
} else {
(0, _invariant2.default)(c.consequent instanceof _completions.PossiblyNormalCompletion);
let result = realm.composeEffects(c.consequentEffects, this.removeNormalEffects(realm, c.consequent));
c.consequentEffects = (0, _realm.construct_empty_effects)(realm);
return result;
}
}
}
joinEffects(realm, joinCondition, e1, e2) {
let [result1, gen1, bindings1, properties1, createdObj1] = e1;
let [result2, gen2, bindings2, properties2, createdObj2] = e2;
let result = this.joinResults(realm, joinCondition, result1, result2, e1, e2);
if (result1 instanceof _completions.AbruptCompletion) {
if (!(result2 instanceof _completions.AbruptCompletion)) {
(0, _invariant2.default)(result instanceof _completions.PossiblyNormalCompletion);
return [result, gen2, bindings2, properties2, createdObj2];
}
} else if (result2 instanceof _completions.AbruptCompletion) {
(0, _invariant2.default)(result instanceof _completions.PossiblyNormalCompletion);
return [result, gen1, bindings1, properties1, createdObj1];
}
let bindings = this.joinBindings(realm, joinCondition, bindings1, bindings2);
let properties = this.joinPropertyBindings(realm, joinCondition, properties1, properties2, createdObj1, createdObj2);
let createdObjects = new Set();
createdObj1.forEach(o => {
createdObjects.add(o);
});
createdObj2.forEach(o => {
createdObjects.add(o);
});
let generator = joinGenerators(realm, joinCondition, gen1, gen2);
return [result, generator, bindings, properties, createdObjects];
}
joinResults(realm, joinCondition, result1, result2, e1, e2) {
let getAbstractValue = (v1, v2) => {
return this.joinValuesAsConditional(realm, joinCondition, v1, v2);
};
if (result1 instanceof _environment.Reference || result2 instanceof _environment.Reference) {
_index2.AbstractValue.reportIntrospectionError(joinCondition);
throw new _errors.FatalError();
}
if (result1 instanceof _completions.BreakCompletion && result2 instanceof _completions.BreakCompletion && result1.target === result2.target) {
return new _completions.BreakCompletion(realm.intrinsics.empty, joinCondition.expressionLocation, result1.target);
}
if (result1 instanceof _completions.ContinueCompletion && result2 instanceof _completions.ContinueCompletion && result1.target === result2.target) {
return new _completions.ContinueCompletion(realm.intrinsics.empty, joinCondition.expressionLocation, result1.target);
}
if (result1 instanceof _completions.ReturnCompletion && result2 instanceof _completions.ReturnCompletion) {
let val = this.joinValues(realm, result1.value, result2.value, getAbstractValue);
(0, _invariant2.default)(val instanceof _index2.Value);
return new _completions.ReturnCompletion(val, joinCondition.expressionLocation);
}
if (result1 instanceof _completions.ThrowCompletion && result2 instanceof _completions.ThrowCompletion) {
let val = this.joinValues(realm, result1.value, result2.value, getAbstractValue);
(0, _invariant2.default)(val instanceof _index2.Value);
return new _completions.ThrowCompletion(val, result1.location);
}
if (result1 instanceof _completions.AbruptCompletion && result2 instanceof _completions.AbruptCompletion) {
return new _completions.JoinedAbruptCompletions(realm, joinCondition, result1, e1, result2, e2);
}
if (result1 instanceof _index2.Value && result2 instanceof _index2.Value) {
let val = this.joinValues(realm, result1, result2, getAbstractValue);
(0, _invariant2.default)(val instanceof _index2.Value);
return val;
}
if (result1 instanceof _completions.PossiblyNormalCompletion && result2 instanceof _completions.PossiblyNormalCompletion) {
return this.joinPossiblyNormalCompletions(realm, joinCondition, result1, result2);
}
if (result1 instanceof _completions.AbruptCompletion) {
let value = result2;
let savedEffects;
let savedPathConditions = [];
if (result2 instanceof _completions.PossiblyNormalCompletion) {
value = result2.value;
savedEffects = result2.savedEffects;
savedPathConditions = result2.savedPathConditions;
}
(0, _invariant2.default)(value instanceof _index2.Value);
return new _completions.PossiblyNormalCompletion(value, joinCondition, result1, e1, result2, e2, savedPathConditions, savedEffects);
}
if (result2 instanceof _completions.AbruptCompletion) {
let value = result1;
let savedEffects;
let savedPathConditions = [];
if (result1 instanceof _completions.PossiblyNormalCompletion) {
value = result1.value;
savedEffects = result1.savedEffects;
savedPathConditions = result1.savedPathConditions;
}
(0, _invariant2.default)(value instanceof _index2.Value);
return new _completions.PossiblyNormalCompletion(value, joinCondition, result1, e1, result2, e2, savedPathConditions, savedEffects);
}
if (result1 instanceof _completions.PossiblyNormalCompletion) {
(0, _invariant2.default)(result2 instanceof _index2.Value);
this.joinPossiblyNormalCompletionWithValue(realm, joinCondition, result1, result2);
return result1;
}
if (result2 instanceof _completions.PossiblyNormalCompletion) {
(0, _invariant2.default)(result1 instanceof _index2.Value);
this.joinValueWithPossiblyNormalCompletion(realm, joinCondition, result2, result1);
return result2;
}
(0, _invariant2.default)(false);
}
composeGenerators(realm, generator1, generator2) {
let result = new _generator.Generator(realm, "composed");
if (!generator1.empty() || !generator2.empty()) {
result.composeGenerators(generator1, generator2);
}
return result;
}
// Creates a single map that joins together maps m1 and m2 using the given join
// operator. If an entry is present in one map but not the other, the missing
// entry is treated as if it were there and its value were undefined.
joinMaps(m1, m2, join) {
let m3 = new Map();
m1.forEach((val1, key, map1) => {
let val2 = m2.get(key);
let val3 = join(key, val1, val2);
m3.set(key, val3);
});
m2.forEach((val2, key, map2) => {
if (!m1.has(key)) {
m3.set(key, join(key, undefined, val2));
}
});
return m3;
}
// Creates a single map that has an key, value pair for the union of the key
// sets of m1 and m2. The value of a pair is the join of m1[key] and m2[key]
// where the join is defined to be just m1[key] if m1[key] === m2[key] and
// and abstract value with expression "joinCondition ? m1[key] : m2[key]" if not.
joinBindings(realm, joinCondition, m1, m2) {
let getAbstractValue = (v1, v2) => {
return this.joinValuesAsConditional(realm, joinCondition, v1, v2);
};
let join = (b, b1, b2) => {
let l1 = b1 === undefined ? b.hasLeaked : b1.hasLeaked;
let l2 = b2 === undefined ? b.hasLeaked : b2.hasLeaked;
let v1 = b1 === undefined ? b.value : b1.value;
let v2 = b2 === undefined ? b.value : b2.value;
let hasLeaked = l1 || l2; // If either has leaked, then this binding has leaked.
let value = this.joinValues(realm, v1, v2, getAbstractValue);
(0, _invariant2.default)(value instanceof _index2.Value);
return { hasLeaked, value };
};
return this.joinMaps(m1, m2, join);
}
// If v1 is known and defined and v1 === v2 return v1,
// otherwise return getAbstractValue(v1, v2)
joinValues(realm, v1, v2, getAbstractValue) {
if (Array.isArray(v1) || Array.isArray(v2)) {
(0, _invariant2.default)(v1 === undefined || Array.isArray(v1));
(0, _invariant2.default)(v2 === undefined || Array.isArray(v2));
return joinArrays(realm, v1, v2, getAbstractValue);
}
(0, _invariant2.default)(v1 === undefined || v1 instanceof _index2.Value);
(0, _invariant2.default)(v2 === undefined || v2 instanceof _index2.Value);
if (v1 !== undefined && v2 !== undefined && !(v1 instanceof _index2.AbstractValue) && !(v2 instanceof _index2.AbstractValue) && (0, _index.StrictEqualityComparison)(realm, v1.throwIfNotConcrete(), v2.throwIfNotConcrete())) {
return v1;
} else {
return getAbstractValue(v1, v2);
}
}
joinValuesAsConditional(realm, condition, v1, v2) {
return _index2.AbstractValue.createFromConditionalOp(realm, condition, v1, v2);
}
joinPropertyBindings(realm, joinCondition, m1, m2, c1, c2) {
let join = (b, d1, d2) => {
// If the PropertyBinding object has been freshly allocated do not join
if (d1 === undefined) {
if (b.object instanceof _index2.ObjectValue && c2.has(b.object)) return d2; // no join
if (b.descriptor !== undefined && m1.has(b)) {
// property was deleted
d1 = (0, _index.cloneDescriptor)(b.descriptor);
(0, _invariant2.default)(d1 !== undefined);
d1.value = realm.intrinsics.empty;
} else {
// no write to property
d1 = b.descriptor; //Get value of property before the split
}
}
if (d2 === undefined) {
if (b.object instanceof _index2.ObjectValue && c1.has(b.object)) return d1; // no join
if (b.descriptor !== undefined && m2.has(b)) {
// property was deleted
d2 = (0, _index.cloneDescriptor)(b.descriptor);
(0, _invariant2.default)(d2 !== undefined);
d2.value = realm.intrinsics.empty;
} else {
// no write to property
d2 = b.descriptor; //Get value of property before the split
}
}
return this.joinDescriptors(realm, joinCondition, d1, d2);
};
return this.joinMaps(m1, m2, join);
}
joinDescriptors(realm, joinCondition, d1, d2) {
let getAbstractValue = (v1, v2) => {
return this.joinValuesAsConditional(realm, joinCondition, v1, v2);
};
let clone_with_abstract_value = d => {
if (!(0, _index.IsDataDescriptor)(realm, d)) {
let d3 = {};
d3.joinCondition = joinCondition;
return d3;
}
let dc = (0, _index.cloneDescriptor)(d);
(0, _invariant2.default)(dc !== undefined);
let dcValue = dc.value;
if (Array.isArray(dcValue)) {
(0, _invariant2.default)(dcValue.length > 0);
let elem0 = dcValue[0];
if (elem0 instanceof _index2.Value) {
dc.value = dcValue.map(e => getAbstractValue(e, realm.intrinsics.empty));
} else {
dc.value = dcValue.map(e => {
let { $Key: key1, $Value: val1 } = e;
let key3 = getAbstractValue(key1, realm.intrinsics.empty);
let val3 = getAbstractValue(val1, realm.intrinsics.empty);
return { $Key: key3, $Value: val3 };
});
}
} else {
(0, _invariant2.default)(dcValue === undefined || dcValue instanceof _index2.Value);
dc.value = getAbstractValue(dcValue, realm.intrinsics.empty);
}
return dc;
};
if (d1 === undefined) {
if (d2 === undefined) return undefined;
// d2 is a new property created in only one branch, join with empty
let d3 = clone_with_abstract_value(d2);
if (!(0, _index.IsDataDescriptor)(realm, d2)) d3.descriptor2 = d2;
return d3;
} else if (d2 === undefined) {
(0, _invariant2.default)(d1 !== undefined);
// d1 is a new property created in only one branch, join with empty
let d3 = clone_with_abstract_value(d1);
if (!(0, _index.IsDataDescriptor)(realm, d1)) d3.descriptor1 = d1;
return d3;
} else {
if ((0, _index.equalDescriptors)(d1, d2) && (0, _index.IsDataDescriptor)(realm, d1)) {
let dc = (0, _index.cloneDescriptor)(d1);
(0, _invariant2.default)(dc !== undefined);
dc.value = this.joinValues(realm, d1.value, d2.value, getAbstractValue);
return dc;
}
let d3 = {};
d3.joinCondition = joinCondition;
d3.descriptor1 = d1;
d3.descriptor2 = d2;
return d3;
}
}
}
exports.JoinImplementation = JoinImplementation;
//# sourceMappingURL=join.js.map