UNPKG

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
"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