UNPKG

prepack

Version:

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

239 lines (202 loc) 11.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = function (ast, strictCode, env, realm) { if (ast.callee.type === "Super") { return (0, _SuperCall2.default)(ast.arguments, strictCode, env, realm); } // ECMA262 12.3.4.1 realm.setNextExecutionContextLocation(ast.loc); // 1. Let ref be the result of evaluating MemberExpression. let ref = env.evaluate(ast.callee, strictCode); // 2. Let func be ? GetValue(ref). let func = _singletons.Environment.GetValue(realm, ref); return EvaluateCall(ref, func, ast, strictCode, env, realm); }; var _errors = require("../errors.js"); var _completions = require("../completions.js"); var _environment = require("../environment.js"); var _index = require("../domains/index.js"); var _index2 = require("../values/index.js"); var _singletons = require("../singletons.js"); var _index3 = require("../methods/index.js"); var _invariant = require("../invariant.js"); var _invariant2 = _interopRequireDefault(_invariant); var _babelTypes = require("babel-types"); var t = _interopRequireWildcard(_babelTypes); var _SuperCall = require("./SuperCall"); var _SuperCall2 = _interopRequireDefault(_SuperCall); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function callBothFunctionsAndJoinTheirEffects(args, ast, strictCode, env, realm) { let [cond, func1, func2] = args; (0, _invariant2.default)(cond instanceof _index2.AbstractValue && cond.getType() === _index2.BooleanValue); (0, _invariant2.default)(_index2.Value.isTypeCompatibleWith(func1.getType(), _index2.FunctionValue)); (0, _invariant2.default)(_index2.Value.isTypeCompatibleWith(func2.getType(), _index2.FunctionValue)); let [compl1, gen1, bindings1, properties1, createdObj1] = realm.evaluateForEffects(() => EvaluateCall(func1, func1, ast, strictCode, env, realm), undefined, "callBothFunctionsAndJoinTheirEffects/1"); let [compl2, gen2, bindings2, properties2, createdObj2] = realm.evaluateForEffects(() => EvaluateCall(func2, func2, ast, strictCode, env, realm), undefined, "callBothFunctionsAndJoinTheirEffects/2"); let joinedEffects = _singletons.Join.joinEffects(realm, cond, [compl1, gen1, bindings1, properties1, createdObj1], [compl2, gen2, bindings2, properties2, createdObj2]); let completion = joinedEffects[0]; if (completion instanceof _completions.PossiblyNormalCompletion) { // in this case one of the branches may complete abruptly, which means that // not all control flow branches join into one flow at this point. // Consequently we have to continue tracking changes until the point where // all the branches come together into one. completion = realm.composeWithSavedCompletion(completion); } // Note that the effects of (non joining) abrupt branches are not included // in joinedEffects, but are tracked separately inside completion. realm.applyEffects(joinedEffects); // return or throw completion if (completion instanceof _completions.AbruptCompletion) throw completion; (0, _invariant2.default)(completion instanceof _index2.Value); return completion; } /** * 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 generateRuntimeCall(ref, func, ast, strictCode, env, realm) { let args = [func]; let [thisArg, propName] = ref instanceof _environment.Reference ? [ref.base, ref.referencedName] : []; if (thisArg instanceof _index2.Value) args = [thisArg]; if (propName !== undefined && typeof propName !== "string") args.push(propName); args = args.concat((0, _index3.ArgumentListEvaluation)(realm, strictCode, env, ast.arguments)); for (let arg of args) { if (arg !== func) { // Since we don't know which function we are calling, we assume that any unfrozen object // passed as an argument has leaked to the environment and is henceforth in an unknown (havoced) state, // as is any other object that is known to be reachable from this object. // NB: Note that this is still optimistic, particularly if the environment exposes the same object // to Prepack via alternative means, thus creating aliasing that is not tracked by Prepack. _singletons.Havoc.value(realm, arg, ast.loc); } } let resultType = (func instanceof _index2.AbstractObjectValue ? func.functionResultType : undefined) || _index2.Value; return _index2.AbstractValue.createTemporalFromBuildFunction(realm, resultType, args, nodes => { let callFunc; let argStart = 1; if (thisArg instanceof _index2.Value) { if (typeof propName === "string") { callFunc = t.isValidIdentifier(propName) ? t.memberExpression(nodes[0], t.identifier(propName), false) : t.memberExpression(nodes[0], t.stringLiteral(propName), true); } else { callFunc = t.memberExpression(nodes[0], nodes[1], true); argStart = 2; } } else { callFunc = nodes[0]; } let fun_args = nodes.slice(argStart); return t.callExpression(callFunc, fun_args); }); } function tryToEvaluateCallOrLeaveAsAbstract(ref, func, ast, strictCode, env, realm, thisValue, tailCall) { let effects; try { effects = realm.evaluateForEffects(() => (0, _index3.EvaluateDirectCall)(realm, strictCode, env, ref, func, thisValue, ast.arguments, tailCall), undefined, "tryToEvaluateCallOrLeaveAsAbstract"); } catch (error) { if (error instanceof _errors.FatalError) { return realm.evaluateWithPossibleThrowCompletion(() => generateRuntimeCall(ref, func, ast, strictCode, env, realm), _index.TypesDomain.topVal, _index.ValuesDomain.topVal); } else { throw error; } } let completion = effects[0]; if (completion instanceof _completions.PossiblyNormalCompletion) { // in this case one of the branches may complete abruptly, which means that // not all control flow branches join into one flow at this point. // Consequently we have to continue tracking changes until the point where // all the branches come together into one. completion = realm.composeWithSavedCompletion(completion); } // Note that the effects of (non joining) abrupt branches are not included // in effects, but are tracked separately inside completion. realm.applyEffects(effects); // return or throw completion if (completion instanceof _completions.AbruptCompletion) throw completion; (0, _invariant2.default)(completion instanceof _index2.Value); return completion; } function EvaluateCall(ref, func, ast, strictCode, env, realm) { if (func instanceof _index2.AbstractValue) { let loc = ast.callee.type === "MemberExpression" ? ast.callee.property.loc : ast.callee.loc; if (!_index2.Value.isTypeCompatibleWith(func.getType(), _index2.FunctionValue)) { if (!realm.isInPureScope()) { // If this is not a function, this call might throw which can change the state of the program. // If this is called from a pure function we handle it using evaluateWithPossiblyAbruptCompletion. let error = new _errors.CompilerDiagnostic("might not be a function", loc, "PP0005", "RecoverableError"); if (realm.handleError(error) === "Fail") throw new _errors.FatalError(); } } else if (func.kind === "conditional") { return callBothFunctionsAndJoinTheirEffects(func.args, ast, strictCode, env, realm); } else { // Assume that it is a safe function. TODO #705: really? } if (realm.isInPureScope()) { // In pure functions we allow abstract functions to throw, which this might. return realm.evaluateWithPossibleThrowCompletion(() => generateRuntimeCall(ref, func, ast, strictCode, env, realm), _index.TypesDomain.topVal, _index.ValuesDomain.topVal); } return generateRuntimeCall(ref, func, ast, strictCode, env, realm); } (0, _invariant2.default)(func instanceof _index2.ConcreteValue); // 3. If Type(ref) is Reference and IsPropertyReference(ref) is false and GetReferencedName(ref) is "eval", then if (ref instanceof _environment.Reference && !_singletons.Environment.IsPropertyReference(realm, ref) && _singletons.Environment.GetReferencedName(realm, ref) === "eval") { // a. If SameValue(func, %eval%) is true, then if ((0, _index3.SameValue)(realm, func, realm.intrinsics.eval)) { // i. Let argList be ? ArgumentListEvaluation(Arguments). let argList = (0, _index3.ArgumentListEvaluation)(realm, strictCode, env, ast.arguments); // ii. If argList has no elements, return undefined. if (argList.length === 0) return realm.intrinsics.undefined; // iii. Let evalText be the first element of argList. let evalText = argList[0]; // iv. If the source code matching this CallExpression is strict code, let strictCaller be true. Otherwise let strictCaller be false. let strictCaller = strictCode; // v. Let evalRealm be the current Realm Record. let evalRealm = realm; // vi. Return ? PerformEval(evalText, evalRealm, strictCaller, true). if (evalText instanceof _index2.AbstractValue) { let loc = ast.arguments[0].loc; let error = new _errors.CompilerDiagnostic("eval argument must be a known value", loc, "PP0006", "RecoverableError"); if (realm.handleError(error) === "Fail") throw new _errors.FatalError(); // Assume that it is a safe eval with no visible heap changes or abrupt control flow. return generateRuntimeCall(ref, func, ast, strictCode, env, realm); } return _singletons.Functions.PerformEval(realm, evalText, evalRealm, strictCaller, true); } } let thisValue; // 4. If Type(ref) is Reference, then if (ref instanceof _environment.Reference) { // a. If IsPropertyReference(ref) is true, then if (_singletons.Environment.IsPropertyReference(realm, ref)) { // i. Let thisValue be GetThisValue(ref). thisValue = (0, _index3.GetThisValue)(realm, ref); } else { // b. Else, the base of ref is an Environment Record // i. Let refEnv be GetBase(ref). let refEnv = _singletons.Environment.GetBase(realm, ref); (0, _invariant2.default)(refEnv instanceof _environment.EnvironmentRecord); // ii. Let thisValue be refEnv.WithBaseObject(). thisValue = refEnv.WithBaseObject(); } } else { // 5. Else Type(ref) is not Reference, // a. Let thisValue be undefined. thisValue = realm.intrinsics.undefined; } // 6. Let thisCall be this CallExpression. let thisCall = ast; // 7. Let tailCall be IsInTailPosition(thisCall). (See 14.6.1) let tailCall = (0, _index3.IsInTailPosition)(realm, thisCall); // 8. Return ? EvaluateDirectCall(func, thisValue, Arguments, tailCall). if (realm.isInPureScope()) { return tryToEvaluateCallOrLeaveAsAbstract(ref, func, ast, strictCode, env, realm, thisValue, tailCall); } else { return (0, _index3.EvaluateDirectCall)(realm, strictCode, env, ref, func, thisValue, ast.arguments, tailCall); } } //# sourceMappingURL=CallExpression.js.map