UNPKG

prepack

Version:

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

167 lines (152 loc) 9.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = function (ast, strictCode, env, realm) { let wasInPureTryStatement = realm.isInPureTryStatement; if (realm.isInPureScope()) { // TODO(1264): This is used to issue a warning if we have abstract function calls in here. // We might not need it once we have full support for handling potential errors. Even // then we might need it to know whether we should bother tracking error handling. realm.isInPureTryStatement = true; } let blockRes; try { blockRes = env.evaluateCompletionDeref(ast.block, strictCode); } finally { realm.isInPureTryStatement = wasInPureTryStatement; } let handlerRes = blockRes; let handler = ast.handler; if (handler) { // The start of the catch handler is a join point where all throw completions come together blockRes = _singletons.Functions.incorporateSavedCompletion(realm, blockRes); if (blockRes instanceof _completions.ThrowCompletion) { handlerRes = env.evaluateCompletionDeref(handler, strictCode, blockRes); // Note: The handler may have introduced new forks } else if (blockRes instanceof _completions.JoinedAbruptCompletions || blockRes instanceof _completions.PossiblyNormalCompletion) { if (blockRes instanceof _completions.PossiblyNormalCompletion) { // Nothing has been joined and we are going to keep it that way. // The current state may have advanced since the time control forked into the various paths recorded in blockRes. // Update the normal path and restore the global state to what it was at the time of the fork. let subsequentEffects = realm.getCapturedEffects(blockRes, blockRes.value); (0, _invariant2.default)(subsequentEffects !== undefined); realm.stopEffectCaptureAndUndoEffects(blockRes); _singletons.Join.updatePossiblyNormalCompletionWithSubsequentEffects(realm, blockRes, subsequentEffects); } // All of the forked threads of control are now joined together and the global state reflects their joint effects let handlerEffects = composeNestedThrowEffectsWithHandler(blockRes); handlerRes = handlerEffects[0]; if (handlerRes instanceof _index2.Value) { // This can happen if all of the abrupt completions in blockRes were throw completions // and if the handler does not introduce any abrupt completions of its own. realm.applyEffects(handlerEffects); // The global state is now all joined up } else { // more than thread of control leaves the handler // The effects of each thread is tracked in handlerRes } } else { // The handler is not invoked, so just carry on. } } let finalizerRes = handlerRes; if (ast.finalizer) { // The start of the finalizer is a join point where all threads of control come together. // However, we choose to keep the threads unjoined and to apply the finalizer separately to each thread. if (blockRes instanceof _completions.PossiblyNormalCompletion || blockRes instanceof _completions.JoinedAbruptCompletions) { // The current global state is a the point of the fork that led to blockRes // All subsequent effects are kept inside the branches of blockRes. let finalizerEffects = composeNestedEffectsWithFinalizer(blockRes); finalizerRes = finalizerEffects[0]; // The result may become abrupt because of the finalizer, but it cannot become normal. (0, _invariant2.default)(!(finalizerRes instanceof _index2.Value)); } else { // A single thread of control has produced a normal blockRes and the global state is up to date. finalizerRes = env.evaluateCompletion(ast.finalizer, strictCode); } } if (finalizerRes instanceof _completions.AbruptCompletion) throw finalizerRes; if (finalizerRes instanceof _completions.PossiblyNormalCompletion) realm.composeWithSavedCompletion(finalizerRes); if (handlerRes instanceof _completions.PossiblyNormalCompletion) handlerRes = handlerRes.value; if (handlerRes instanceof _index2.Value) return (0, _index.UpdateEmpty)(realm, handlerRes, realm.intrinsics.undefined); throw handlerRes; // The handler is a potential join point for all throw completions, but is easier to not do the join here because // it is tricky to join the joined and composed result of the throw completions with the non exceptional completions. // Unfortunately, things are still complicated because the handler may turn abrupt completions into normal // completions and the other way around. When this happens the container has to change its type. // We do this by call joinEffects to create a new container at every level of the recursion. function composeNestedThrowEffectsWithHandler(c, priorEffects = []) { let consequent = c.consequent; let consequentEffects = c.consequentEffects; priorEffects.push(consequentEffects); if (consequent instanceof _completions.JoinedAbruptCompletions || consequent instanceof _completions.PossiblyNormalCompletion) { consequentEffects = composeNestedThrowEffectsWithHandler(consequent, priorEffects); } else if (consequent instanceof _completions.ThrowCompletion) { consequentEffects = realm.evaluateForEffects(() => { for (let priorEffect of priorEffects) realm.applyEffects(priorEffect); (0, _invariant2.default)(ast.handler); return env.evaluateCompletionDeref(ast.handler, strictCode, consequent); }, undefined, "composeNestedThrowEffectsWithHandler/1"); } priorEffects.pop(); let alternate = c.alternate; let alternateEffects = c.alternateEffects; priorEffects.push(alternateEffects); if (alternate instanceof _completions.PossiblyNormalCompletion || alternate instanceof _completions.JoinedAbruptCompletions) { alternateEffects = composeNestedThrowEffectsWithHandler(alternate, priorEffects); } else if (alternate instanceof _completions.ThrowCompletion) { alternateEffects = realm.evaluateForEffects(() => { for (let priorEffect of priorEffects) realm.applyEffects(priorEffect); (0, _invariant2.default)(ast.handler); return env.evaluateCompletionDeref(ast.handler, strictCode, alternate); }, undefined, "composeNestedThrowEffectsWithHandler/2"); } priorEffects.pop(); return _singletons.Join.joinEffects(realm, c.joinCondition, consequentEffects, alternateEffects); } // The finalizer is not a join point, so update each path in the completion separately. // Things are complicated because the finalizer may turn normal completions into abrupt completions. // When this happens the container has to change its type. // We do this by call joinEffects to create a new container at every level of the recursion. function composeNestedEffectsWithFinalizer(c, priorEffects = []) { let consequent = c.consequent; let consequentEffects = c.consequentEffects; priorEffects.push(consequentEffects); if (consequent instanceof _completions.JoinedAbruptCompletions || consequent instanceof _completions.PossiblyNormalCompletion) { consequentEffects = composeNestedThrowEffectsWithHandler(consequent, priorEffects); } else { consequentEffects = realm.evaluateForEffects(() => { for (let priorEffect of priorEffects) realm.applyEffects(priorEffect); (0, _invariant2.default)(ast.finalizer); return env.evaluateCompletionDeref(ast.finalizer, strictCode); }, undefined, "composeNestedEffectsWithFinalizer/1"); if (!(consequentEffects[0] instanceof _completions.AbruptCompletion)) consequentEffects[0] = consequent; } priorEffects.pop(); let alternate = c.alternate; let alternateEffects = c.alternateEffects; priorEffects.push(alternateEffects); if (alternate instanceof _completions.PossiblyNormalCompletion || alternate instanceof _completions.JoinedAbruptCompletions) { alternateEffects = composeNestedThrowEffectsWithHandler(alternate, priorEffects); } else { alternateEffects = realm.evaluateForEffects(() => { for (let priorEffect of priorEffects) realm.applyEffects(priorEffect); (0, _invariant2.default)(ast.finalizer); return env.evaluateCompletionDeref(ast.finalizer, strictCode); }, undefined, "composeNestedThrowEffectsWithHandler"); if (!(alternateEffects[0] instanceof _completions.AbruptCompletion)) alternateEffects[0] = alternate; } priorEffects.pop(); return _singletons.Join.joinEffects(realm, c.joinCondition, consequentEffects, alternateEffects); } }; require("../environment.js"); var _completions = require("../completions.js"); var _index = require("../methods/index.js"); var _singletons = require("../singletons.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 }; } //# sourceMappingURL=TryStatement.js.map