UNPKG

prepack

Version:

Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.

546 lines (443 loc) 22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JoinImplementation = void 0; var _realm = require("../realm.js"); var _descriptors = require("../descriptors.js"); var _completions = require("../completions.js"); var _index = require("../methods/index.js"); var _singletons = require("../singletons.js"); var _generator = require("../utils/generator.js"); var _index2 = require("../values/index.js"); var _invariant = _interopRequireDefault(require("../invariant.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * 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 joinGenerators(joinCondition, generator1, generator2) { let realm = joinCondition.$Realm; let result = new _generator.Generator(realm, "joined", realm.pathConditions); if (!generator1.empty() || !generator2.empty()) { result.joinGenerators(joinCondition, generator1, generator2); } return result; } 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 { composeCompletions(leftCompletion, rightCompletion) { if (leftCompletion instanceof _completions.AbruptCompletion) return leftCompletion; if (leftCompletion instanceof _completions.JoinedNormalAndAbruptCompletions) { if (rightCompletion instanceof _completions.JoinedNormalAndAbruptCompletions) { rightCompletion.composedWith = leftCompletion; rightCompletion.pathConditionsAtCreation = leftCompletion.pathConditionsAtCreation; return rightCompletion; } let c = this.composeCompletions(leftCompletion.consequent, rightCompletion); if (c instanceof _index2.Value) c = new _completions.SimpleNormalCompletion(c); let a = this.composeCompletions(leftCompletion.alternate, rightCompletion); if (a instanceof _index2.Value) a = new _completions.SimpleNormalCompletion(a); let joinedCompletion = this.joinCompletions(leftCompletion.joinCondition, c, a); if (joinedCompletion instanceof _completions.JoinedNormalAndAbruptCompletions) { joinedCompletion.composedWith = leftCompletion.composedWith; joinedCompletion.pathConditionsAtCreation = leftCompletion.pathConditionsAtCreation; joinedCompletion.savedEffects = leftCompletion.savedEffects; } return joinedCompletion; } if (leftCompletion instanceof _index2.Value) leftCompletion = new _completions.SimpleNormalCompletion(leftCompletion); if (leftCompletion instanceof _completions.Completion && leftCompletion.value === leftCompletion.value.$Realm.intrinsics.__bottomValue) { return leftCompletion; } if (rightCompletion instanceof _index2.Value) rightCompletion = new _completions.SimpleNormalCompletion(rightCompletion); return rightCompletion; } composeWithEffects(completion, normalEffects) { if (completion instanceof _completions.JoinedNormalAndAbruptCompletions) { let selectAbrupt = c => c instanceof _completions.AbruptCompletion && c.value !== c.value.$Realm.intrinsics.__bottomValue; let composableCompletions = _completions.Completion.makeSelectedCompletionsInfeasibleInCopy(selectAbrupt, completion); let composedNormalCompletion = this.composeCompletions(composableCompletions, normalEffects.result); normalEffects.result = composedNormalCompletion; let selectNormal = c => c instanceof _completions.SimpleNormalCompletion && c.value !== c.value.$Realm.intrinsics.__bottomValue; let nonComposableCompletions = _completions.Completion.makeSelectedCompletionsInfeasibleInCopy(selectNormal, completion); let nonComposedEffects = (0, _realm.construct_empty_effects)(completion.value.$Realm, nonComposableCompletions); let joinCondition = _index2.AbstractValue.createJoinConditionForSelectedCompletions(selectNormal, completion); return this.joinEffects(joinCondition, normalEffects, nonComposedEffects); } else if (completion instanceof _completions.AbruptCompletion) { return (0, _realm.construct_empty_effects)(completion.value.$Realm, completion); } else { return normalEffects; } } _collapseSimilarCompletions(joinCondition, c1, c2) { let realm = joinCondition.$Realm; let getAbstractValue = (v1, v2) => { if (v1 instanceof _index2.EmptyValue) return v2 || realm.intrinsics.undefined; if (v2 instanceof _index2.EmptyValue) return v1 || realm.intrinsics.undefined; return _index2.AbstractValue.createFromConditionalOp(realm, joinCondition, v1, v2); }; if (c1 instanceof _completions.BreakCompletion && c2 instanceof _completions.BreakCompletion && c1.target === c2.target) { let val = this.joinValues(realm, c1.value, c2.value, getAbstractValue); (0, _invariant.default)(val instanceof _index2.Value); return new _completions.BreakCompletion(val, joinCondition.expressionLocation, c1.target); } if (c1 instanceof _completions.ContinueCompletion && c2 instanceof _completions.ContinueCompletion && c1.target === c2.target) { return new _completions.ContinueCompletion(realm.intrinsics.empty, joinCondition.expressionLocation, c1.target); } if (c1 instanceof _completions.ReturnCompletion && c2 instanceof _completions.ReturnCompletion) { let val = this.joinValues(realm, c1.value, c2.value, getAbstractValue); (0, _invariant.default)(val instanceof _index2.Value); return new _completions.ReturnCompletion(val, joinCondition.expressionLocation); } if (c1 instanceof _completions.ThrowCompletion && c2 instanceof _completions.ThrowCompletion) { getAbstractValue = (v1, v2) => { return _index2.AbstractValue.createFromConditionalOp(realm, joinCondition, v1, v2); }; let val = this.joinValues(realm, c1.value, c2.value, getAbstractValue); (0, _invariant.default)(val instanceof _index2.Value); return new _completions.ThrowCompletion(val, c1.location); } if (c1 instanceof _completions.SimpleNormalCompletion && c2 instanceof _completions.SimpleNormalCompletion) { return new _completions.SimpleNormalCompletion(getAbstractValue(c1.value, c2.value)); } return undefined; } joinCompletions(joinCondition, c1, c2) { if (!joinCondition.mightNotBeTrue()) return c1; if (!joinCondition.mightNotBeFalse()) return c2; (0, _invariant.default)(joinCondition instanceof _index2.AbstractValue); let c = this._collapseSimilarCompletions(joinCondition, c1, c2); if (c === undefined) { if (c1 instanceof _completions.AbruptCompletion && c2 instanceof _completions.AbruptCompletion) c = new _completions.JoinedAbruptCompletions(joinCondition, c1, c2);else { (0, _invariant.default)(c1 instanceof _completions.AbruptCompletion || c1 instanceof _completions.NormalCompletion); (0, _invariant.default)(c2 instanceof _completions.AbruptCompletion || c2 instanceof _completions.NormalCompletion); c = new _completions.JoinedNormalAndAbruptCompletions(joinCondition, c1, c2); } } return c; } joinEffects(joinCondition, e1, e2) { (0, _invariant.default)(e1.canBeApplied); (0, _invariant.default)(e2.canBeApplied); if (!joinCondition.mightNotBeTrue()) return e1; if (!joinCondition.mightNotBeFalse()) return e2; (0, _invariant.default)(joinCondition instanceof _index2.AbstractValue); let { result: c1, generator: generator1, modifiedBindings: modifiedBindings1, modifiedProperties: modifiedProperties1, createdObjects: createdObjects1 } = e1; let { result: c2, generator: generator2, modifiedBindings: modifiedBindings2, modifiedProperties: modifiedProperties2, createdObjects: createdObjects2 } = e2; let realm = joinCondition.$Realm; let c = this.joinCompletions(joinCondition, c1, c2); let [modifiedGenerator1, modifiedGenerator2, bindings] = this._joinBindings(joinCondition, generator1, modifiedBindings1, generator2, modifiedBindings2); let generator = joinGenerators(joinCondition, modifiedGenerator1, modifiedGenerator2); let properties = this.joinPropertyBindings(realm, joinCondition, modifiedProperties1, modifiedProperties2, createdObjects1, createdObjects2); let createdObjects = new Set(); createdObjects1.forEach(o => { createdObjects.add(o); }); createdObjects2.forEach(o => { createdObjects.add(o); }); return new _realm.Effects(c, generator, bindings, properties, createdObjects); } joinValuesOfSelectedCompletions(selector, completion, keepInfeasiblePaths = false) { let realm = completion.value.$Realm; let bottom = realm.intrinsics.__bottomValue; if (completion instanceof _completions.JoinedAbruptCompletions || completion instanceof _completions.JoinedNormalAndAbruptCompletions) { let joinCondition = completion.joinCondition; let c = this.joinValuesOfSelectedCompletions(selector, completion.consequent); let a = this.joinValuesOfSelectedCompletions(selector, completion.alternate); // do some simplification if (c === bottom) { // joinCondition will never be true when this completion is reached if (a instanceof _index2.AbstractValue) { a = _singletons.Path.withInverseCondition(joinCondition, () => { (0, _invariant.default)(a instanceof _index2.AbstractValue); return realm.simplifyAndRefineAbstractValue(a); }); } if (!keepInfeasiblePaths) return a; } else if (a === bottom) { // joinCondition will never be false when this completion is reached if (c instanceof _index2.AbstractValue) { c = _singletons.Path.withCondition(joinCondition, () => { (0, _invariant.default)(c instanceof _index2.AbstractValue); return realm.simplifyAndRefineAbstractValue(c); }); } if (!keepInfeasiblePaths) return c; } let getAbstractValue = (v1, v2) => { if (v1 === bottom) v1 = realm.intrinsics.empty; if (v2 === bottom) v2 = realm.intrinsics.empty; return _index2.AbstractValue.createFromConditionalOp(realm, joinCondition, v1, v2); }; let jv = this.joinValues(realm, c, a, getAbstractValue); (0, _invariant.default)(jv instanceof _index2.Value); if (completion instanceof _completions.JoinedNormalAndAbruptCompletions && completion.composedWith !== undefined) { let composedWith = completion.composedWith; if (!composedWith.containsSelectedCompletion(selector)) return jv; let cjv = this.joinValuesOfSelectedCompletions(selector, composedWith); joinCondition = _index2.AbstractValue.createJoinConditionForSelectedCompletions(selector, composedWith); jv = this.joinValues(realm, jv, cjv, getAbstractValue); (0, _invariant.default)(jv instanceof _index2.Value); } return jv; } if (selector(completion)) return completion.value; return bottom; } // 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(joinCondition, g1, m1, g2, m2) { let realm = joinCondition.$Realm; let getAbstractValue = (v1, v2) => { return _index2.AbstractValue.createFromConditionalOp(realm, joinCondition, v1, v2, undefined, true, true); }; let rewritten1 = false; let rewritten2 = false; let leak = (b, g, v, rewritten) => { // just like to what happens in leakBinding, we are going to append a // binding-assignment generator entry; however, we play it safe and don't // mutate the generator; instead, we create a new one that wraps around the old one. if (!rewritten) { let h = new _generator.Generator(realm, "RewrittenToAppendBindingAssignments", g.pathConditions); if (!g.empty()) h.appendGenerator(g, ""); g = h; rewritten = true; } if (v !== undefined && v !== realm.intrinsics.undefined) g.emitBindingAssignment(b, v); return [g, rewritten]; }; 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; // ensure that if either none or both sides have leaked // note that if one side didn't have a binding entry yet, then there's nothing to actively leak if (!l1 && l2) [g1, rewritten1] = leak(b, g1, v1, rewritten1);else if (l1 && !l2) [g2, rewritten2] = leak(b, g2, v2, rewritten2); let hasLeaked = l1 || l2; // For leaked (and mutable) bindings, the actual value is no longer directly available. // In that case, we reset the value to undefined to prevent any use of the last known value. let value = hasLeaked ? undefined : this.joinValues(realm, v1, v2, getAbstractValue); (0, _invariant.default)(value === undefined || value instanceof _index2.Value); return { hasLeaked, value }; }; let joinedBindings = this.joinMaps(m1, m2, join); return [g1, g2, joinedBindings]; } // 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, _invariant.default)(v1 === undefined || Array.isArray(v1)); (0, _invariant.default)(v2 === undefined || Array.isArray(v2)); return joinArrays(realm, v1, v2, getAbstractValue); } (0, _invariant.default)(v1 === undefined || v1 instanceof _index2.Value); (0, _invariant.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); } } 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 (c2.has(b.object)) return d2; // no join if (b.descriptor !== undefined && m1.has(b)) { // property was deleted d1 = (0, _descriptors.cloneDescriptor)(b.descriptor.throwIfNotConcrete(realm)); (0, _invariant.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 (c1.has(b.object)) return d1; // no join if (b.descriptor !== undefined && m2.has(b)) { // property was deleted d2 = (0, _descriptors.cloneDescriptor)(b.descriptor.throwIfNotConcrete(realm)); (0, _invariant.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 _index2.AbstractValue.createFromConditionalOp(realm, joinCondition, v1, v2); }; let clone_with_abstract_value = d => { (0, _invariant.default)(d === d1 || d === d2); if (!(0, _index.IsDataDescriptor)(realm, d)) { return new _descriptors.AbstractJoinedDescriptor(joinCondition); } let dc; let dcValue; if (d instanceof _descriptors.InternalSlotDescriptor) { dc = new _descriptors.InternalSlotDescriptor(d.value); dcValue = dc.value; if (Array.isArray(dcValue)) { (0, _invariant.default)(dcValue.length > 0); let elem0 = dcValue[0]; if (elem0 instanceof _index2.Value) { dc.value = dcValue.map(e => { return d === d1 ? getAbstractValue(e, realm.intrinsics.empty) : getAbstractValue(realm.intrinsics.empty, e); }); } else { dc.value = dcValue.map(e => { let { $Key: key1, $Value: val1 } = e; let key3 = d === d1 ? getAbstractValue(key1, realm.intrinsics.empty) : getAbstractValue(realm.intrinsics.empty, key1); let val3 = d === d1 ? getAbstractValue(val1, realm.intrinsics.empty) : getAbstractValue(realm.intrinsics.empty, val1); return { $Key: key3, $Value: val3 }; }); } } } else { dc = (0, _descriptors.cloneDescriptor)(d.throwIfNotConcrete(realm)); (0, _invariant.default)(dc !== undefined); dcValue = dc.value; } (0, _invariant.default)(dcValue === undefined || dcValue instanceof _index2.Value); dc.value = d === d1 ? getAbstractValue(dcValue, realm.intrinsics.empty) : getAbstractValue(realm.intrinsics.empty, dcValue); 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 (d3 instanceof _descriptors.AbstractJoinedDescriptor) d3.descriptor2 = d2; return d3; } else if (d2 === undefined) { (0, _invariant.default)(d1 !== undefined); // d1 is a new property created in only one branch, join with empty let d3 = clone_with_abstract_value(d1); if (d3 instanceof _descriptors.AbstractJoinedDescriptor) d3.descriptor1 = d1; return d3; } else { if (d1 instanceof _descriptors.PropertyDescriptor && d2 instanceof _descriptors.PropertyDescriptor && (0, _descriptors.equalDescriptors)(d1, d2) && (0, _index.IsDataDescriptor)(realm, d1)) { let dc = (0, _descriptors.cloneDescriptor)(d1); (0, _invariant.default)(dc !== undefined); let dcValue = this.joinValues(realm, d1.value, d2.value, getAbstractValue); (0, _invariant.default)(dcValue instanceof _index2.Value); dc.value = dcValue; return dc; } if (d1 instanceof _descriptors.InternalSlotDescriptor && d2 instanceof _descriptors.InternalSlotDescriptor) { return new _descriptors.InternalSlotDescriptor(this.joinValues(realm, d1.value, d2.value, getAbstractValue)); } return new _descriptors.AbstractJoinedDescriptor(joinCondition, d1, d2); } } mapAndJoin(realm, values, joinConditionFactory, functionToMap) { (0, _invariant.default)(values.size > 1); let joinedEffects; for (let val of values) { let condition = joinConditionFactory(val); let effects = realm.evaluateForEffects(() => { (0, _invariant.default)(condition instanceof _index2.AbstractValue); return _singletons.Path.withCondition(condition, () => { return functionToMap(val); }); }, undefined, "mapAndJoin"); joinedEffects = joinedEffects === undefined ? effects : this.joinEffects(condition, effects, joinedEffects); } (0, _invariant.default)(joinedEffects !== undefined); realm.applyEffects(joinedEffects); return realm.returnOrThrowCompletion(joinedEffects.result); } } exports.JoinImplementation = JoinImplementation; //# sourceMappingURL=join.js.map