Merge pull request #10286 from smelukov/inner-graph-decouple-parser-state
decouple inner-graph and parser state
This commit is contained in:
commit
1be6dc1dcb
|
@ -5,6 +5,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const InnerGraph = require("./optimize/InnerGraph");
|
||||
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
|
||||
class FlagUsingEvalPlugin {
|
||||
|
@ -20,6 +22,7 @@ class FlagUsingEvalPlugin {
|
|||
parser.hooks.call.for("eval").tap("FlagUsingEvalPlugin", () => {
|
||||
parser.state.module.buildInfo.moduleConcatenationBailout = "eval()";
|
||||
parser.state.module.buildInfo.usingEval = true;
|
||||
InnerGraph.bailout(parser.state);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { topLevelSymbolTag } = require("../optimize/InnerGraphPlugin");
|
||||
const { topLevelSymbolTag } = require("../optimize/InnerGraph");
|
||||
const ConstDependency = require("./ConstDependency");
|
||||
const HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency");
|
||||
const HarmonyExportHeaderDependency = require("./HarmonyExportHeaderDependency");
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"use strict";
|
||||
|
||||
const HotModuleReplacementPlugin = require("../HotModuleReplacementPlugin");
|
||||
const InnerGraph = require("../optimize/InnerGraph");
|
||||
const ConstDependency = require("./ConstDependency");
|
||||
const HarmonyAcceptDependency = require("./HarmonyAcceptDependency");
|
||||
const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency");
|
||||
|
@ -13,8 +14,8 @@ const HarmonyExports = require("./HarmonyExports");
|
|||
const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency");
|
||||
const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency");
|
||||
|
||||
/** @typedef {import("../optimize/InnerGraphPlugin").InnerGraph} InnerGraph */
|
||||
/** @typedef {import("../optimize/InnerGraphPlugin").TopLevelSymbol} TopLevelSymbol */
|
||||
/** @typedef {import("../optimize/InnerGraph").InnerGraph} InnerGraph */
|
||||
/** @typedef {import("../optimize/InnerGraph").TopLevelSymbol} TopLevelSymbol */
|
||||
/** @typedef {import("./HarmonyImportDependency")} HarmonyImportDependency */
|
||||
|
||||
const harmonySpecifierTag = Symbol("harmony import");
|
||||
|
@ -79,14 +80,14 @@ module.exports = class HarmonyImportDependencyParserPlugin {
|
|||
* @returns {void}
|
||||
*/
|
||||
const addDepToInnerGraph = dep => {
|
||||
const { harmonyAllExportDependentDependencies } = parser.state;
|
||||
if (!harmonyAllExportDependentDependencies) return;
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
if (!innerGraph) return;
|
||||
harmonyAllExportDependentDependencies.add(dep);
|
||||
const currentTopLevelSymbol =
|
||||
/** @type {TopLevelSymbol} */ (parser.state.currentTopLevelSymbol);
|
||||
const innerGraphState = InnerGraph.getState(parser.state);
|
||||
if (!innerGraphState) return;
|
||||
const {
|
||||
innerGraph,
|
||||
allExportDependentDependencies,
|
||||
currentTopLevelSymbol
|
||||
} = innerGraphState;
|
||||
allExportDependentDependencies.add(dep);
|
||||
if (!currentTopLevelSymbol) {
|
||||
innerGraph.set(dep, true);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Sergey Melyukov @smelukov
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("estree").Node} AnyNode */
|
||||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../dependencies/HarmonyImportSpecifierDependency")} HarmonyImportSpecifierDependency */
|
||||
/** @typedef {import("../dependencies/PureExpressionDependency")} PureExpressionDependency */
|
||||
/** @typedef {import("../Parser").ParserState} ParserState */
|
||||
/** @typedef {Map<TopLevelSymbol | Dependency, Set<string | TopLevelSymbol> | true>} InnerGraph */
|
||||
/** @typedef {false|{innerGraph: InnerGraph, allExportDependentDependencies: Set<PureExpressionDependency|HarmonyImportSpecifierDependency>, currentTopLevelSymbol: TopLevelSymbol|void}} State */
|
||||
|
||||
/** @type {WeakMap<ParserState, State>} */
|
||||
const parserStateMap = new WeakMap();
|
||||
const topLevelSymbolTag = Symbol("top level symbol");
|
||||
|
||||
exports.parserStateMap = parserStateMap;
|
||||
|
||||
/**
|
||||
* @param {ParserState} parserState parser state
|
||||
* @returns {void}
|
||||
*/
|
||||
exports.bailout = parserState => {
|
||||
parserStateMap.set(parserState, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ParserState} parserState parser state
|
||||
* @returns {void}
|
||||
*/
|
||||
exports.enable = parserState => {
|
||||
const state = parserStateMap.get(parserState);
|
||||
if (state === false) {
|
||||
return;
|
||||
}
|
||||
parserStateMap.set(parserState, {
|
||||
innerGraph: new Map(),
|
||||
allExportDependentDependencies: new Set(),
|
||||
currentTopLevelSymbol: undefined
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ParserState} parserState parser state
|
||||
* @returns {boolean} true, when enabled
|
||||
*/
|
||||
exports.isEnabled = parserState => {
|
||||
const state = parserStateMap.get(parserState);
|
||||
return !!state;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ParserState} parserState parser state
|
||||
* @returns {State} state
|
||||
*/
|
||||
exports.getState = parserState => {
|
||||
return parserStateMap.get(parserState);
|
||||
};
|
||||
|
||||
class TopLevelSymbol {
|
||||
/**
|
||||
* @param {string} name name of the function
|
||||
* @param {InnerGraph} innerGraph reference to the graph
|
||||
*/
|
||||
constructor(name, innerGraph) {
|
||||
this.name = name;
|
||||
this.innerGraph = innerGraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | TopLevelSymbol | true} dep export or top level symbol or always
|
||||
* @returns {void}
|
||||
*/
|
||||
addDependency(dep) {
|
||||
const info = this.innerGraph.get(this);
|
||||
if (dep === true) {
|
||||
this.innerGraph.set(this, true);
|
||||
} else if (info === undefined) {
|
||||
this.innerGraph.set(this, new Set([dep]));
|
||||
} else if (info !== true) {
|
||||
info.add(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.TopLevelSymbol = TopLevelSymbol;
|
||||
exports.topLevelSymbolTag = topLevelSymbolTag;
|
|
@ -9,14 +9,16 @@ const {
|
|||
harmonySpecifierTag
|
||||
} = require("../dependencies/HarmonyImportDependencyParserPlugin");
|
||||
const PureExpressionDependency = require("../dependencies/PureExpressionDependency");
|
||||
const InnerGraph = require("./InnerGraph");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../dependencies/HarmonyImportSpecifierDependency")} HarmonyImportSpecifierDependency */
|
||||
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
|
||||
/** @typedef {import("./InnerGraph").InnerGraph} InnerGraph */
|
||||
/** @typedef {import("./InnerGraph").TopLevelSymbol} TopLevelSymbol */
|
||||
|
||||
const topLevelSymbolTag = Symbol("top level symbol");
|
||||
|
||||
/** @typedef {Map<TopLevelSymbol | Dependency, Set<string | TopLevelSymbol> | true>} InnerGraph */
|
||||
const { TopLevelSymbol, topLevelSymbolTag } = InnerGraph;
|
||||
|
||||
/**
|
||||
* @param {any} expr an expression
|
||||
|
@ -90,32 +92,6 @@ const isPure = (expr, parser, commentsStartPos) => {
|
|||
return false;
|
||||
};
|
||||
|
||||
class TopLevelSymbol {
|
||||
/**
|
||||
* @param {string} name name of the function
|
||||
* @param {InnerGraph} innerGraph reference to the graph
|
||||
*/
|
||||
constructor(name, innerGraph) {
|
||||
this.name = name;
|
||||
this.innerGraph = innerGraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | TopLevelSymbol | true} dep export or top level symbol or always
|
||||
* @returns {void}
|
||||
*/
|
||||
addDependency(dep) {
|
||||
const info = this.innerGraph.get(this);
|
||||
if (dep === true) {
|
||||
this.innerGraph.set(this, true);
|
||||
} else if (info === undefined) {
|
||||
this.innerGraph.set(this, new Set([dep]));
|
||||
} else if (info !== true) {
|
||||
info.add(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InnerGraphPlugin {
|
||||
/**
|
||||
* @param {Compiler} compiler webpack compiler
|
||||
|
@ -136,14 +112,17 @@ class InnerGraphPlugin {
|
|||
*/
|
||||
const handler = (parser, parserOptions) => {
|
||||
parser.hooks.program.tap("InnerGraphPlugin", () => {
|
||||
parser.state.harmonyInnerGraph = new Map();
|
||||
parser.state.harmonyAllExportDependentDependencies = new Set();
|
||||
InnerGraph.enable(parser.state);
|
||||
});
|
||||
|
||||
parser.hooks.finish.tap("InnerGraphPlugin", () => {
|
||||
if (parser.state.module.buildInfo.usingEval) return;
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
const innerGraphState = InnerGraph.getState(parser.state);
|
||||
if (!innerGraphState) return;
|
||||
|
||||
const {
|
||||
innerGraph,
|
||||
allExportDependentDependencies
|
||||
} = innerGraphState;
|
||||
// flatten graph to terminal nodes (string, undefined or true)
|
||||
const nonTerminal = new Set(innerGraph.keys());
|
||||
while (nonTerminal.size > 0) {
|
||||
|
@ -188,8 +167,7 @@ class InnerGraphPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
for (const dep of parser.state
|
||||
.harmonyAllExportDependentDependencies) {
|
||||
for (const dep of allExportDependentDependencies) {
|
||||
const value = innerGraph.get(dep);
|
||||
switch (value) {
|
||||
case undefined:
|
||||
|
@ -199,7 +177,7 @@ class InnerGraphPlugin {
|
|||
dep.usedByExports = true;
|
||||
break;
|
||||
default:
|
||||
dep.usedByExports = value;
|
||||
dep.usedByExports = /** @type {Set<string>} */ (value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -207,10 +185,12 @@ class InnerGraphPlugin {
|
|||
/** @type {WeakMap<{}, TopLevelSymbol>} */
|
||||
const statementWithTopLevelSymbol = new WeakMap();
|
||||
parser.hooks.preStatement.tap("InnerGraphPlugin", statement => {
|
||||
const innerGraphState = InnerGraph.getState(parser.state);
|
||||
if (!innerGraphState) return;
|
||||
|
||||
if (parser.scope.topLevelScope === true) {
|
||||
if (statement.type === "FunctionDeclaration") {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
const { innerGraph } = innerGraphState;
|
||||
const name = statement.id ? statement.id.name : "*default*";
|
||||
parser.defineVariable(name);
|
||||
const fn = new TopLevelSymbol(name, innerGraph);
|
||||
|
@ -221,10 +201,12 @@ class InnerGraphPlugin {
|
|||
}
|
||||
});
|
||||
parser.hooks.blockPreStatement.tap("InnerGraphPlugin", statement => {
|
||||
const innerGraphState = InnerGraph.getState(parser.state);
|
||||
if (!innerGraphState) return;
|
||||
|
||||
if (parser.scope.topLevelScope === true) {
|
||||
if (statement.type === "ClassDeclaration") {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
const { innerGraph } = innerGraphState;
|
||||
const name = statement.id ? statement.id.name : "*default*";
|
||||
parser.defineVariable(name);
|
||||
const fn = new TopLevelSymbol(name, innerGraph);
|
||||
|
@ -240,8 +222,7 @@ class InnerGraphPlugin {
|
|||
decl.type === "ClassExpression" ||
|
||||
decl.type === "Identifier"
|
||||
) {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
const { innerGraph } = innerGraphState;
|
||||
const name = "*default*";
|
||||
parser.defineVariable(name);
|
||||
const fn = new TopLevelSymbol(name, innerGraph);
|
||||
|
@ -251,9 +232,8 @@ class InnerGraphPlugin {
|
|||
}
|
||||
}
|
||||
});
|
||||
const tagVar = name => {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
const tagVar = (innerGraphState, name) => {
|
||||
const { innerGraph } = innerGraphState;
|
||||
parser.defineVariable(name);
|
||||
const existingTag = parser.getTagData(name, topLevelSymbolTag);
|
||||
const fn = existingTag || new TopLevelSymbol(name, innerGraph);
|
||||
|
@ -268,6 +248,8 @@ class InnerGraphPlugin {
|
|||
parser.hooks.preDeclarator.tap(
|
||||
"InnerGraphPlugin",
|
||||
(decl, statement) => {
|
||||
const innerGraphState = InnerGraph.getState(parser.state);
|
||||
if (!innerGraphState) return;
|
||||
if (
|
||||
parser.scope.topLevelScope === true &&
|
||||
decl.init &&
|
||||
|
@ -279,13 +261,13 @@ class InnerGraphPlugin {
|
|||
decl.init.type === "ClassExpression"
|
||||
) {
|
||||
const name = decl.id.name;
|
||||
const fn = tagVar(name);
|
||||
const fn = tagVar(innerGraphState, name);
|
||||
declWithTopLevelSymbol.set(decl, fn);
|
||||
return true;
|
||||
}
|
||||
if (isPure(decl.init, parser, decl.id.range[1])) {
|
||||
const name = decl.id.name;
|
||||
const fn = tagVar(name);
|
||||
const fn = tagVar(innerGraphState, name);
|
||||
declWithTopLevelSymbol.set(decl, fn);
|
||||
pureDeclarators.add(decl);
|
||||
return true;
|
||||
|
@ -294,43 +276,52 @@ class InnerGraphPlugin {
|
|||
}
|
||||
);
|
||||
parser.hooks.statement.tap("InnerGraphPlugin", statement => {
|
||||
const innerGraphState = InnerGraph.getState(parser.state);
|
||||
if (!innerGraphState) return;
|
||||
if (parser.scope.topLevelScope === true) {
|
||||
parser.state.currentTopLevelSymbol = undefined;
|
||||
innerGraphState.currentTopLevelSymbol = undefined;
|
||||
const fn = statementWithTopLevelSymbol.get(statement);
|
||||
if (fn) {
|
||||
parser.state.currentTopLevelSymbol = fn;
|
||||
innerGraphState.currentTopLevelSymbol = fn;
|
||||
}
|
||||
}
|
||||
});
|
||||
parser.hooks.declarator.tap("InnerGraphPlugin", (decl, statement) => {
|
||||
const innerGraphState = InnerGraph.getState(parser.state);
|
||||
if (!innerGraphState) return;
|
||||
const {
|
||||
innerGraph,
|
||||
allExportDependentDependencies
|
||||
} = innerGraphState;
|
||||
const fn = declWithTopLevelSymbol.get(decl);
|
||||
if (fn) {
|
||||
if (pureDeclarators.has(decl)) {
|
||||
const innerGraph =
|
||||
/** @type {InnerGraph} */ (parser.state.harmonyInnerGraph);
|
||||
const dep = new PureExpressionDependency(decl.init.range);
|
||||
dep.loc = decl.loc;
|
||||
parser.state.module.addDependency(dep);
|
||||
innerGraph.set(dep, new Set([fn]));
|
||||
parser.state.harmonyAllExportDependentDependencies.add(dep);
|
||||
allExportDependentDependencies.add(dep);
|
||||
}
|
||||
parser.state.currentTopLevelSymbol = fn;
|
||||
innerGraphState.currentTopLevelSymbol = fn;
|
||||
parser.walkExpression(decl.init);
|
||||
parser.state.currentTopLevelSymbol = undefined;
|
||||
innerGraphState.currentTopLevelSymbol = undefined;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
parser.hooks.expression
|
||||
.for(topLevelSymbolTag)
|
||||
.tap("InnerGraphPlugin", expr => {
|
||||
const innerGraphState = InnerGraph.getState(parser.state);
|
||||
if (!innerGraphState) return;
|
||||
const topLevelSymbol =
|
||||
/** @type {TopLevelSymbol} */ (parser.currentTagData);
|
||||
const currentTopLevelSymbol = parser.state.currentTopLevelSymbol;
|
||||
const { currentTopLevelSymbol } = innerGraphState;
|
||||
topLevelSymbol.addDependency(currentTopLevelSymbol || true);
|
||||
});
|
||||
parser.hooks.assign
|
||||
.for(topLevelSymbolTag)
|
||||
.tap("InnerGraphPlugin", expr => {
|
||||
if (!InnerGraph.isEnabled(parser.state)) return;
|
||||
if (expr.operator === "=") return true;
|
||||
});
|
||||
};
|
||||
|
@ -340,16 +331,9 @@ class InnerGraphPlugin {
|
|||
normalModuleFactory.hooks.parser
|
||||
.for("javascript/esm")
|
||||
.tap("InnerGraphPlugin", handler);
|
||||
|
||||
compilation.hooks.optimizeDependencies.tap(
|
||||
"InnerGraphPlugin",
|
||||
modules => {}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = InnerGraphPlugin;
|
||||
module.exports.TopLevelSymbol = TopLevelSymbol;
|
||||
module.exports.topLevelSymbolTag = topLevelSymbolTag;
|
||||
|
|
Loading…
Reference in New Issue