prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
118 lines (93 loc) • 3.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ClosureRefVisitor = void 0;
var _realm = require("../realm.js");
var t = _interopRequireWildcard(require("@babel/types"));
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)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
/**
* 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.
*/
/* strict-local */
function visitName(path, state, node, modified) {
// Is the name bound to some local identifier? If so, we don't need to do anything
if (path.scope.hasBinding(node.name,
/*noGlobals*/
true)) return; // Otherwise, let's record that there's an unbound identifier
let nodes = state.functionInfo.unbound.get(node.name);
if (nodes === undefined) state.functionInfo.unbound.set(node.name, nodes = []);
nodes.push(node);
if (modified) state.functionInfo.modified.add(node.name);
}
function ignorePath(path) {
let parent = path.parent;
return t.isLabeledStatement(parent) || t.isBreakStatement(parent) || t.isContinueStatement(parent);
}
let ClosureRefVisitor = {
"FunctionDeclaration|ArrowFunctionExpression|FunctionExpression": {
enter(path, state) {
state.functionInfo.depth++;
},
exit(path, state) {
state.functionInfo.depth--;
}
},
ArrowFunctionExpression: {
enter(path, state) {
state.functionInfo.depth++;
state.functionInfo.lexicalDepth++;
},
exit(path, state) {
state.functionInfo.depth--;
state.functionInfo.lexicalDepth--;
}
},
CallExpression(path, state) {
// Here we apply the require optimization by replacing require calls with their
// corresponding initialized modules.
if (state.getModuleIdIfNodeIsRequireFunction === undefined) return;
let moduleId = state.getModuleIdIfNodeIsRequireFunction(path.scope, path.node);
if (moduleId === undefined) return;
state.functionInfo.requireCalls.set(path.node, moduleId);
},
ReferencedIdentifier(path, state) {
if (ignorePath(path)) return;
let innerName = path.node.name;
if (innerName === "arguments") {
if (state.functionInfo.depth === 1) {
state.functionInfo.usesArguments = true;
} // "arguments" bound to local scope. therefore, there's no need to visit this identifier.
return;
}
visitName(path, state, path.node, false);
},
ThisExpression(path, state) {
if (state.functionInfo.depth - state.functionInfo.lexicalDepth === 1) {
state.functionInfo.usesThis = true;
}
},
"AssignmentExpression|UpdateExpression"(path, state) {
let ids = path.getBindingIdentifiers();
for (let name in ids) {
visitName(path, state, ids[name], true);
}
},
"ForInStatement|ForOfStatement"(path, state) {
if (path.node.left !== "VariableDeclaration") {
// `LeftHandSideExpression`s in a for-in/for-of statement perform `DestructuringAssignment` on the current loop
// value so we need to make sure we visit these bindings and mark them as modified.
const ids = path.get("left").getBindingIdentifiers();
for (const name in ids) {
visitName(path, state, ids[name], true);
}
}
}
};
exports.ClosureRefVisitor = ClosureRefVisitor;
//# sourceMappingURL=visitors.js.map