move usedExports into ExportsInfo
This commit is contained in:
parent
923e16dd5a
commit
739fef4fda
|
@ -44,7 +44,6 @@ const StatsFactory = require("./stats/StatsFactory");
|
|||
const StatsPrinter = require("./stats/StatsPrinter");
|
||||
const AsyncQueue = require("./util/AsyncQueue");
|
||||
const Queue = require("./util/Queue");
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
const {
|
||||
compareLocations,
|
||||
concatComparators,
|
||||
|
@ -1497,7 +1496,7 @@ class Compilation {
|
|||
this.chunkGraph.connectChunkAndRuntimeModule(chunk, module);
|
||||
|
||||
// Setup internals
|
||||
this.moduleGraph.setUsedExports(module, new SortableSet());
|
||||
this.moduleGraph.getExportsInfo(module).setUsedForSideEffectsOnly();
|
||||
this.chunkGraph.addModuleRuntimeRequirements(module, [
|
||||
RuntimeGlobals.require
|
||||
]);
|
||||
|
|
|
@ -6,30 +6,13 @@
|
|||
"use strict";
|
||||
|
||||
const { STAGE_DEFAULT } = require("./OptimizationStages");
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
const Queue = require("./util/Queue");
|
||||
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
|
||||
/** @typedef {import("./Dependency")} Dependency */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
/** @typedef {false | true | SortableSet<string>} UsedExports */
|
||||
|
||||
/**
|
||||
* @param {UsedExports} moduleUsedExports the current used exports of the module
|
||||
* @param {false | true | string[]} newUsedExports the new used exports
|
||||
* @returns {boolean} true, if the newUsedExports is part of the moduleUsedExports
|
||||
*/
|
||||
const isContained = (moduleUsedExports, newUsedExports) => {
|
||||
if (moduleUsedExports === null) return false;
|
||||
if (moduleUsedExports === true) return true;
|
||||
if (newUsedExports === true) return false;
|
||||
if (newUsedExports === false) return true;
|
||||
if (moduleUsedExports === false) return false;
|
||||
if (newUsedExports.length > moduleUsedExports.size) return false;
|
||||
return newUsedExports.every(item => moduleUsedExports.has(item));
|
||||
};
|
||||
|
||||
class FlagDependencyUsagePlugin {
|
||||
/**
|
||||
* @param {Compiler} compiler the compiler instance
|
||||
|
@ -51,79 +34,62 @@ class FlagDependencyUsagePlugin {
|
|||
* @returns {void}
|
||||
*/
|
||||
const processModule = (module, usedExports) => {
|
||||
let ue = moduleGraph.getUsedExports(module);
|
||||
if (ue === true) return;
|
||||
const exportsInfo = moduleGraph.getExportsInfo(module);
|
||||
let changed = false;
|
||||
if (usedExports === true) {
|
||||
moduleGraph.setUsedExports(module, (ue = true));
|
||||
} else if (Array.isArray(usedExports)) {
|
||||
if (!ue) {
|
||||
moduleGraph.setUsedExports(
|
||||
module,
|
||||
(ue = new SortableSet(usedExports))
|
||||
);
|
||||
} else {
|
||||
const old = ue ? ue.size : -1;
|
||||
for (const exportName of usedExports) {
|
||||
ue.add(exportName);
|
||||
}
|
||||
if (ue.size === old) {
|
||||
return;
|
||||
changed = exportsInfo.setUsedInUnknownWay();
|
||||
} else if (usedExports) {
|
||||
for (const exportName of usedExports) {
|
||||
const exportInfo = exportsInfo.getExportInfo(exportName);
|
||||
if (exportInfo.used !== true) {
|
||||
exportInfo.used = true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ue !== false) return;
|
||||
moduleGraph.setUsedExports(module, (ue = new SortableSet()));
|
||||
// for a module without side effects we stop tracking usage here when no export is used
|
||||
// This module won't be evaluated in this case
|
||||
if (module.factoryMeta.sideEffectFree) return;
|
||||
changed = exportsInfo.setUsedForSideEffectsOnly();
|
||||
}
|
||||
|
||||
// for a module without side effects we stop tracking usage here when no export is used
|
||||
// This module won't be evaluated in this case
|
||||
if (module.factoryMeta.sideEffectFree) {
|
||||
if (ue !== true && ue.size === 0) return;
|
||||
if (changed) {
|
||||
queue.enqueue(module);
|
||||
}
|
||||
|
||||
queue.push([module, module, ue]);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @param {DependenciesBlock} depBlock the dependencies block
|
||||
* @param {UsedExports} usedExports the used exports
|
||||
* @returns {void}
|
||||
*/
|
||||
const processDependenciesBlock = (module, depBlock, usedExports) => {
|
||||
const processDependenciesBlock = depBlock => {
|
||||
for (const dep of depBlock.dependencies) {
|
||||
processDependency(module, dep);
|
||||
processDependency(dep);
|
||||
}
|
||||
for (const block of depBlock.blocks) {
|
||||
queue.push([module, block, usedExports]);
|
||||
queue.enqueue(block);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @param {Dependency} dep the dependency
|
||||
* @returns {void}
|
||||
*/
|
||||
const processDependency = (module, dep) => {
|
||||
const processDependency = dep => {
|
||||
const reference = compilation.getDependencyReference(dep);
|
||||
if (!reference) return;
|
||||
const referenceModule = reference.module;
|
||||
const importedNames = reference.importedNames;
|
||||
const oldUsedExports = moduleGraph.getUsedExports(referenceModule);
|
||||
if (
|
||||
!oldUsedExports ||
|
||||
!isContained(oldUsedExports, importedNames)
|
||||
) {
|
||||
processModule(referenceModule, importedNames);
|
||||
}
|
||||
processModule(referenceModule, importedNames);
|
||||
};
|
||||
|
||||
for (const module of modules) {
|
||||
moduleGraph.setUsedExports(module, false);
|
||||
moduleGraph.getExportsInfo(module).setHasUseInfo();
|
||||
}
|
||||
|
||||
/** @type {[Module, DependenciesBlock, UsedExports][]} */
|
||||
const queue = [];
|
||||
/** @type {Queue<DependenciesBlock>} */
|
||||
const queue = new Queue();
|
||||
|
||||
for (const deps of compilation.entryDependencies.values()) {
|
||||
for (const dep of deps) {
|
||||
const module = moduleGraph.getModule(dep);
|
||||
|
@ -134,8 +100,8 @@ class FlagDependencyUsagePlugin {
|
|||
}
|
||||
|
||||
while (queue.length) {
|
||||
const queueItem = queue.pop();
|
||||
processDependenciesBlock(queueItem[0], queueItem[1], queueItem[2]);
|
||||
const depBlock = queue.dequeue();
|
||||
processDependenciesBlock(depBlock);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -30,7 +30,7 @@ class FlagInitialModulesAsUsedPlugin {
|
|||
return;
|
||||
}
|
||||
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
moduleGraph.setUsedExports(module, true);
|
||||
moduleGraph.getExportsInfo(module).setUsedInUnknownWay();
|
||||
moduleGraph.addExtraReason(module, this.explanation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,13 +218,6 @@ class Module extends DependenciesBlock {
|
|||
).getUsedExports(this);
|
||||
}
|
||||
|
||||
set usedExports(value) {
|
||||
ModuleGraph.getModuleGraphForModule(
|
||||
this,
|
||||
"Module.usedExports"
|
||||
).setUsedExports(this, value);
|
||||
}
|
||||
|
||||
get optimizationBailout() {
|
||||
return ModuleGraph.getModuleGraphForModule(
|
||||
this,
|
||||
|
@ -403,7 +396,7 @@ class Module extends DependenciesBlock {
|
|||
* @returns {boolean} true, if the module is used
|
||||
*/
|
||||
isModuleUsed(moduleGraph) {
|
||||
return moduleGraph.getUsedExports(this) !== false;
|
||||
return moduleGraph.getExportsInfo(this).isUsed() !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -412,10 +405,8 @@ class Module extends DependenciesBlock {
|
|||
* @returns {boolean} true, if the export is used
|
||||
*/
|
||||
isExportUsed(moduleGraph, exportName) {
|
||||
const usedExports = moduleGraph.getUsedExports(this);
|
||||
if (usedExports === null || usedExports === true) return true;
|
||||
if (usedExports === false) return false;
|
||||
return usedExports.has(exportName);
|
||||
const exportInfo = moduleGraph.getExportInfo(this, exportName);
|
||||
return exportInfo.used !== false;
|
||||
}
|
||||
|
||||
// TODO move to ModuleGraph
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
|
||||
const util = require("util");
|
||||
const ModuleGraphConnection = require("./ModuleGraphConnection");
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
|
||||
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
|
||||
/** @typedef {import("./Dependency")} Dependency */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleProfile")} ModuleProfile */
|
||||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @template T @typedef {import("./util/SortableSet")<T>} SortableSet<T> */
|
||||
|
||||
/**
|
||||
* @callback OptimizationBailoutFunction
|
||||
|
@ -26,6 +26,7 @@ class ExportsInfo {
|
|||
/** @type {Map<string, ExportInfo>} */
|
||||
this._exports = new Map();
|
||||
this._otherExportsInfo = new ExportInfo(null);
|
||||
this._sideEffectsOnlyInfo = new ExportInfo("*side effects only*");
|
||||
this._exportsIsOrdered = false;
|
||||
}
|
||||
|
||||
|
@ -63,6 +64,20 @@ class ExportsInfo {
|
|||
}
|
||||
}
|
||||
|
||||
setHasUseInfo() {
|
||||
for (const exportInfo of this._exports.values()) {
|
||||
if (exportInfo.used === undefined) {
|
||||
exportInfo.used = false;
|
||||
}
|
||||
}
|
||||
if (this._otherExportsInfo.used === undefined) {
|
||||
this._otherExportsInfo.used = false;
|
||||
}
|
||||
if (this._sideEffectsOnlyInfo.used === undefined) {
|
||||
this._sideEffectsOnlyInfo.used = false;
|
||||
}
|
||||
}
|
||||
|
||||
getExportInfo(name) {
|
||||
const info = this._exports.get(name);
|
||||
if (info !== undefined) return info;
|
||||
|
@ -107,6 +122,90 @@ class ExportsInfo {
|
|||
return changed;
|
||||
}
|
||||
|
||||
setUsedInUnknownWay() {
|
||||
let changed = false;
|
||||
if (this._isUsed === false) {
|
||||
this._isUsed = true;
|
||||
changed = true;
|
||||
}
|
||||
for (const exportInfo of this._exports.values()) {
|
||||
if (exportInfo.used !== true && exportInfo.used !== null) {
|
||||
exportInfo.used = null;
|
||||
changed = true;
|
||||
}
|
||||
if (exportInfo.canMangle !== false) {
|
||||
exportInfo.canMangle = false;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
this._otherExportsInfo.used !== true &&
|
||||
this._otherExportsInfo.used !== null
|
||||
) {
|
||||
this._otherExportsInfo.used = null;
|
||||
changed = true;
|
||||
}
|
||||
if (this._otherExportsInfo.canMangle !== false) {
|
||||
this._otherExportsInfo.canMangle = false;
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
setUsedForSideEffectsOnly() {
|
||||
if (this._sideEffectsOnlyInfo.used === false) {
|
||||
this._sideEffectsOnlyInfo.used = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isUsed() {
|
||||
if (this._otherExportsInfo.used !== false) {
|
||||
return true;
|
||||
}
|
||||
if (this._sideEffectsOnlyInfo.used !== false) {
|
||||
return true;
|
||||
}
|
||||
for (const exportInfo of this._exports.values()) {
|
||||
if (exportInfo.used !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getUsedExports() {
|
||||
switch (this._otherExportsInfo.used) {
|
||||
case undefined:
|
||||
return null;
|
||||
case null:
|
||||
return true;
|
||||
case true:
|
||||
return true;
|
||||
}
|
||||
const array = [];
|
||||
if (!this._exportsIsOrdered) this._sortExports();
|
||||
for (const exportInfo of this._exports.values()) {
|
||||
switch (exportInfo.used) {
|
||||
case undefined:
|
||||
return null;
|
||||
case null:
|
||||
return true;
|
||||
case true:
|
||||
array.push(exportInfo.name);
|
||||
}
|
||||
}
|
||||
if (array.length === 0) {
|
||||
switch (this._sideEffectsOnlyInfo.used) {
|
||||
case undefined:
|
||||
return null;
|
||||
case false:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return new SortableSet(array);
|
||||
}
|
||||
|
||||
getProvidedExports() {
|
||||
switch (this._otherExportsInfo.provided) {
|
||||
case undefined:
|
||||
|
@ -183,6 +282,14 @@ class ExportInfo {
|
|||
constructor(name, initFrom) {
|
||||
/** @type {string} */
|
||||
this.name = name;
|
||||
/**
|
||||
* true: it is used
|
||||
* false: it is not used
|
||||
* null: only the runtime knows if it is used
|
||||
* undefined: it was not determined if it is used
|
||||
* @type {boolean | null | undefined}
|
||||
*/
|
||||
this.used = initFrom ? initFrom.used : undefined;
|
||||
/**
|
||||
* true: it is provided
|
||||
* false: it is not provided
|
||||
|
@ -201,7 +308,16 @@ class ExportInfo {
|
|||
}
|
||||
|
||||
getUsedInfo() {
|
||||
return "no usage info";
|
||||
switch (this.used) {
|
||||
case undefined:
|
||||
return "no usage info";
|
||||
case null:
|
||||
return "maybe used (runtime-defined)";
|
||||
case true:
|
||||
return "used";
|
||||
case false:
|
||||
return "unused";
|
||||
}
|
||||
}
|
||||
|
||||
getProvidedInfo() {
|
||||
|
@ -241,8 +357,6 @@ class ModuleGraphModule {
|
|||
this.optimizationBailout = [];
|
||||
/** @type {ExportsInfo} */
|
||||
this.exports = new ExportsInfo();
|
||||
/** @type {false | true | SortableSet<string> | null} */
|
||||
this.usedExports = null;
|
||||
/** @type {number} */
|
||||
this.preOrderIndex = null;
|
||||
/** @type {number} */
|
||||
|
@ -390,7 +504,6 @@ class ModuleGraph {
|
|||
newMgm.postOrderIndex = oldMgm.postOrderIndex;
|
||||
newMgm.preOrderIndex = oldMgm.preOrderIndex;
|
||||
newMgm.depth = oldMgm.depth;
|
||||
newMgm.usedExports = oldMgm.usedExports;
|
||||
// TODO optimize this
|
||||
newMgm.exports.restoreProvided(oldMgm.exports.getRestoreProvidedData());
|
||||
}
|
||||
|
@ -621,17 +734,7 @@ class ModuleGraph {
|
|||
*/
|
||||
getUsedExports(module) {
|
||||
const mgm = this._getModuleGraphModule(module);
|
||||
return mgm.usedExports;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @param {false | true | SortableSet<string>} usedExports the used exports
|
||||
* @returns {void}
|
||||
*/
|
||||
setUsedExports(module, usedExports) {
|
||||
const mgm = this._getModuleGraphModule(module);
|
||||
mgm.usedExports = usedExports;
|
||||
return mgm.exports.getUsedExports();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,7 @@ class RequireIncludeDependency extends ModuleDependency {
|
|||
// This doesn't use any export
|
||||
return new DependencyReference(
|
||||
() => moduleGraph.getModule(this),
|
||||
[],
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
|
|
@ -849,8 +849,7 @@ class ConcatenatedModule extends Module {
|
|||
const result = new ConcatSource();
|
||||
|
||||
// add harmony compatibility flag (must be first because of possible circular dependencies)
|
||||
const usedExports = moduleGraph.getUsedExports(this.rootModule);
|
||||
if (usedExports === true) {
|
||||
if (moduleGraph.getExportsInfo(this).otherExportsInfo.used !== false) {
|
||||
result.add(
|
||||
runtimeTemplate.defineEsModuleFlagStatement({
|
||||
exportsArgument: this.exportsArgument,
|
||||
|
|
|
@ -18,9 +18,10 @@ module.exports = {
|
|||
Array.isArray(ref.importedNames) &&
|
||||
ref.importedNames.includes("unused")
|
||||
) {
|
||||
const newExports = ref.importedNames.filter(item => item !== "unused");
|
||||
return new DependencyReference(
|
||||
() => ref.module,
|
||||
ref.importedNames.filter(item => item !== "unused"),
|
||||
newExports.length > 0 ? newExports : false,
|
||||
ref.weak,
|
||||
ref.order
|
||||
);
|
||||
|
|
|
@ -18,9 +18,10 @@ module.exports = {
|
|||
Array.isArray(ref.importedNames) &&
|
||||
ref.importedNames.includes("unused")
|
||||
) {
|
||||
const newExports = ref.importedNames.filter(item => item !== "unused");
|
||||
return new DependencyReference(
|
||||
() => ref.module,
|
||||
ref.importedNames.filter(item => item !== "unused"),
|
||||
newExports.length > 0 ? newExports : false,
|
||||
ref.weak,
|
||||
ref.order
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue