Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

memory and performance optimizations #13097

Merged
merged 5 commits into from Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions lib/CodeGenerationResults.js
Expand Up @@ -27,6 +27,7 @@ class CodeGenerationResults {
* @returns {CodeGenerationResult} the CodeGenerationResult
*/
get(module, runtime) {
this._verifyAlive();
const entry = this.map.get(module);
if (entry === undefined) {
throw new Error(
Expand Down Expand Up @@ -72,6 +73,7 @@ Caller might not support runtime-dependent code generation (opt-out via optimiza
* @returns {boolean} true, when we have data for this
*/
has(module, runtime) {
this._verifyAlive();
const entry = this.map.get(module);
if (entry === undefined) {
return false;
Expand Down Expand Up @@ -142,9 +144,23 @@ Caller might not support runtime-dependent code generation (opt-out via optimiza
* @returns {void}
*/
add(module, runtime, result) {
this._verifyAlive();
const map = provide(this.map, module, () => new RuntimeSpecMap());
map.set(runtime, result);
}

_verifyAlive() {
if (this.map === undefined) {
throw new Error(
"CodeGenerationResults has been accessed after its lifetime. They are no longer available after sealing the compilation."
);
}
}

dispose() {
this.map.clear();
this.map = undefined;
}
}

module.exports = CodeGenerationResults;
20 changes: 13 additions & 7 deletions lib/Compilation.js
Expand Up @@ -358,12 +358,13 @@ class Compilation {
const { fn, additionalAssets, ...remainingTap } = tap;
const additionalAssetsFn =
additionalAssets === true ? fn : additionalAssets;
let processedAssets = undefined;
const processedAssets = additionalAssetsFn ? new WeakSet() : undefined;
switch (type) {
case "sync":
if (additionalAssetsFn) {
this.hooks.processAdditionalAssets.tap(name, assets => {
if (processedAssets === this.assets) additionalAssetsFn(assets);
if (processedAssets.has(this.assets))
additionalAssetsFn(assets);
});
}
return {
Expand All @@ -375,7 +376,8 @@ class Compilation {
} catch (e) {
return callback(e);
}
processedAssets = this.assets;
if (processedAssets !== undefined)
processedAssets.add(this.assets);
const newAssets = popNewAssets(assets);
if (newAssets !== undefined) {
this.hooks.processAdditionalAssets.callAsync(
Expand All @@ -392,7 +394,7 @@ class Compilation {
this.hooks.processAdditionalAssets.tapAsync(
name,
(assets, callback) => {
if (processedAssets === this.assets)
if (processedAssets.has(this.assets))
return additionalAssetsFn(assets, callback);
callback();
}
Expand All @@ -403,7 +405,8 @@ class Compilation {
fn: (assets, callback) => {
fn(assets, err => {
if (err) return callback(err);
processedAssets = this.assets;
if (processedAssets !== undefined)
processedAssets.add(this.assets);
const newAssets = popNewAssets(assets);
if (newAssets !== undefined) {
this.hooks.processAdditionalAssets.callAsync(
Expand All @@ -419,7 +422,7 @@ class Compilation {
case "promise":
if (additionalAssetsFn) {
this.hooks.processAdditionalAssets.tapPromise(name, assets => {
if (processedAssets === this.assets)
if (processedAssets.has(this.assets))
return additionalAssetsFn(assets);
return Promise.resolve();
});
Expand All @@ -430,7 +433,8 @@ class Compilation {
const p = fn(assets);
if (!p || !p.then) return p;
return p.then(() => {
processedAssets = this.assets;
if (processedAssets !== undefined)
processedAssets.add(this.assets);
const newAssets = popNewAssets(assets);
if (newAssets !== undefined) {
return this.hooks.processAdditionalAssets.promise(
Expand Down Expand Up @@ -2128,6 +2132,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
this.assets = {};
this.assetsInfo.clear();
this.moduleGraph.removeAllModuleAttributes();
this.codeGenerationResults = undefined;
}

/**
Expand Down Expand Up @@ -2414,6 +2419,7 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
this.unseal();
return this.seal(callback);
}
this.codeGenerationResults.dispose();
return this.hooks.afterSeal.callAsync(err => {
if (err) {
return callback(
Expand Down
7 changes: 5 additions & 2 deletions lib/Compiler.js
Expand Up @@ -359,12 +359,13 @@ class Compiler {
// e.g. move compilation specific info from Modules into ModuleGraph
_cleanupLastCompilation() {
if (this._lastCompilation !== undefined) {
for (const module of this._lastCompilation.modules) {
const c = this._lastCompilation;
for (const module of c.modules) {
ChunkGraph.clearChunkGraphForModule(module);
ModuleGraph.clearModuleGraphForModule(module);
module.cleanupForCache();
}
for (const chunk of this._lastCompilation.chunks) {
for (const chunk of c.chunks) {
ChunkGraph.clearChunkGraphForChunk(chunk);
}
this._lastCompilation = undefined;
Expand Down Expand Up @@ -820,6 +821,8 @@ ${other}`);
}
},
err => {
// Clear map to free up memory
caseInsensitiveMap.clear();
if (err) return callback(err);

this.hooks.afterEmit.callAsync(compilation, err => {
Expand Down
51 changes: 17 additions & 34 deletions lib/serialization/BinaryMiddleware.js
Expand Up @@ -114,31 +114,6 @@ const identifyNumber = n => {
* @extends {SerializerMiddleware<DeserializedType, SerializedType>}
*/
class BinaryMiddleware extends SerializerMiddleware {
static optimizeSerializedData(data) {
const result = [];
const temp = [];
const flush = () => {
if (temp.length > 0) {
if (temp.length === 1) {
result.push(temp[0]);
} else {
result.push(Buffer.concat(temp));
}
temp.length = 0;
}
};
for (const item of data) {
if (Buffer.isBuffer(item)) {
temp.push(item);
} else {
flush();
result.push(item);
}
}
flush();
return result;
}

/**
* @param {DeserializedType} data data
* @param {Object} context context object
Expand All @@ -162,7 +137,7 @@ class BinaryMiddleware extends SerializerMiddleware {
/** @type {BufferSerializableType[]} */
const buffers = [];
let buffersTotalLength = 0;
const allocate = (bytesNeeded, exact = false) => {
const allocate = bytesNeeded => {
if (currentBuffer !== null) {
if (currentBuffer.length - currentPosition >= bytesNeeded) return;
flush();
Expand All @@ -171,8 +146,8 @@ class BinaryMiddleware extends SerializerMiddleware {
currentBuffer = leftOverBuffer;
leftOverBuffer = null;
} else {
currentBuffer = Buffer.allocUnsafe(
exact ? bytesNeeded : Math.max(bytesNeeded, buffersTotalLength, 1024)
currentBuffer = Buffer.allocUnsafeSlow(
Math.max(bytesNeeded, buffersTotalLength, 16384)
);
}
};
Expand Down Expand Up @@ -264,8 +239,8 @@ class BinaryMiddleware extends SerializerMiddleware {
for (const l of lengths) {
writeU32(l);
}
flush();
for (const item of serializedData) {
flush();
buffers.push(item);
}
}
Expand Down Expand Up @@ -463,11 +438,19 @@ class BinaryMiddleware extends SerializerMiddleware {
writeU32(n - 260);
}
} else if (Buffer.isBuffer(thing)) {
allocate(HEADER_SIZE + I32_SIZE, true);
writeU8(BUFFER_HEADER);
writeU32(thing.length);
flush();
buffers.push(thing);
if (thing.length < 8192) {
allocate(HEADER_SIZE + I32_SIZE + thing.length);
writeU8(BUFFER_HEADER);
writeU32(thing.length);
thing.copy(currentBuffer, currentPosition);
currentPosition += thing.length;
} else {
allocate(HEADER_SIZE + I32_SIZE);
writeU8(BUFFER_HEADER);
writeU32(thing.length);
flush();
buffers.push(thing);
}
}
break;
}
Expand Down
1 change: 1 addition & 0 deletions types.d.ts
Expand Up @@ -1174,6 +1174,7 @@ declare abstract class CodeGenerationResults {
getData(module: Module, runtime: RuntimeSpec, key: string): any;
getHash(module: Module, runtime: RuntimeSpec): any;
add(module: Module, runtime: RuntimeSpec, result: CodeGenerationResult): void;
dispose(): void;
}
type CodeValue =
| undefined
Expand Down