From 0496ac8d0257a819d81bbea2cbd299ad21503577 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 7 Jan 2025 17:48:15 +0800 Subject: [PATCH] perf: cache immutable js field --- crates/node_binding/binding.d.ts | 14 ++-- crates/rspack_binding_values/src/module.rs | 44 +++++------ packages/rspack/src/Dependency.ts | 23 ++++-- packages/rspack/src/Module.ts | 82 ++++++++++++++------ packages/rspack/src/ModuleGraph.ts | 53 ++++++++++++- packages/rspack/src/ModuleGraphConnection.ts | 18 ++++- 6 files changed, 166 insertions(+), 68 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 3ac0f01bc9e..58e87ff92fd 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -220,26 +220,26 @@ export declare class JsExportsInfo { export declare class JsModule { get constructorName(): string - get context(): string | undefined + get context(): string | null get originalSource(): JsCompatSource | undefined - get resource(): string | undefined + get resource(): string | null get moduleIdentifier(): string get nameForCondition(): string | undefined - get request(): string | undefined + get request(): string | null get userRequest(): string | undefined set userRequest(val: string) - get rawRequest(): string | undefined + get rawRequest(): string | null get factoryMeta(): JsFactoryMeta | undefined get type(): string - get layer(): string | undefined + get layer(): string | null get blocks(): JsDependenciesBlock[] get dependencies(): JsDependency[] size(ty?: string | undefined | null): number get modules(): JsModule[] | undefined get useSourceMap(): boolean libIdent(options: JsLibIdentOptions): string | null - get resourceResolveData(): JsResourceData | undefined - get matchResource(): string | undefined + get resourceResolveData(): JsResourceData | null + get matchResource(): string | null get loaders(): Array | undefined } diff --git a/crates/rspack_binding_values/src/module.rs b/crates/rspack_binding_values/src/module.rs index 71f4bce98ea..e9f6cf45a5d 100644 --- a/crates/rspack_binding_values/src/module.rs +++ b/crates/rspack_binding_values/src/module.rs @@ -77,12 +77,12 @@ impl JsModule { } #[napi(getter)] - pub fn context(&mut self) -> napi::Result> { + pub fn context(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.get_context() { - Some(ctx) => Either::A(ctx.to_string()), - None => Either::B(()), + Some(ctx) => Some(ctx.to_string()), + None => None, }) } @@ -103,12 +103,12 @@ impl JsModule { } #[napi(getter)] - pub fn resource(&mut self) -> napi::Result> { + pub fn resource(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.try_as_normal_module() { - Ok(normal_module) => Either::A(&normal_module.resource_resolved_data().resource), - Err(_) => Either::B(()), + Ok(normal_module) => Some(&normal_module.resource_resolved_data().resource), + Err(_) => None, }) } @@ -130,12 +130,12 @@ impl JsModule { } #[napi(getter)] - pub fn request(&mut self) -> napi::Result> { + pub fn request(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.try_as_normal_module() { - Ok(normal_module) => Either::A(normal_module.request()), - Err(_) => Either::B(()), + Ok(normal_module) => Some(normal_module.request()), + Err(_) => None, }) } @@ -160,12 +160,12 @@ impl JsModule { } #[napi(getter)] - pub fn raw_request(&mut self) -> napi::Result> { + pub fn raw_request(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.try_as_normal_module() { - Ok(normal_module) => Either::A(normal_module.raw_request()), - Err(_) => Either::B(()), + Ok(normal_module) => Some(normal_module.raw_request()), + Err(_) => None, }) } @@ -192,12 +192,12 @@ impl JsModule { } #[napi(getter)] - pub fn layer(&mut self) -> napi::Result> { + pub fn layer(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.get_layer() { - Some(layer) => Either::A(layer), - None => Either::B(()), + Some(layer) => Some(layer), + None => None, }) } @@ -310,23 +310,23 @@ impl JsModule { } #[napi(getter)] - pub fn resource_resolve_data(&mut self) -> napi::Result> { + pub fn resource_resolve_data(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.as_normal_module() { - Some(module) => Either::A(module.resource_resolved_data().into()), - None => Either::B(()), + Some(module) => Some(module.resource_resolved_data().into()), + None => None, }) } #[napi(getter)] - pub fn match_resource(&mut self) -> napi::Result> { + pub fn match_resource(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.as_normal_module() { Some(module) => match &module.match_resource() { - Some(match_resource) => Either::A(&match_resource.resource), - None => Either::B(()), + Some(match_resource) => Some(&match_resource.resource), + None => None, }, - None => Either::B(()), + None => None, }) } diff --git a/packages/rspack/src/Dependency.ts b/packages/rspack/src/Dependency.ts index 0e86b221d08..6bfd3f1a7c1 100644 --- a/packages/rspack/src/Dependency.ts +++ b/packages/rspack/src/Dependency.ts @@ -26,20 +26,27 @@ export const bindingDependencyFactory = { }; export class Dependency { + #type: string | undefined; + #category: string | undefined; + get type(): string { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - return binding.type; + if (this.#type === undefined) { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + this.#type = binding.type; + } } - return "unknown"; + return this.#type || "unknown"; } get category(): string { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - return binding.category; + if (this.#category === undefined) { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + this.#category = binding.category; + } } - return "unknown"; + return this.#category || "unknown"; } get request(): string | undefined { diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index 5c80563658b..0f191be177a 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -202,14 +202,23 @@ const BUILD_META_MAPPINGS = new Map>(); export class Module { #inner: JsModule; - - declare readonly context?: string; - declare readonly resource?: string; - declare readonly request?: string; + #identifier: string | undefined; + #type: string | undefined; + #layer: string | undefined | null; + #context: string | undefined | null; + #resource: string | undefined | null; + #request: string | undefined | null; + #rawRequest: string | undefined | null; + #resourceResolveData: ResolveData | undefined | null; + #matchResource: string | undefined | null; + + declare readonly context: string | null; + declare readonly resource: string | null; + declare readonly request: string | null; declare userRequest?: string; - declare readonly rawRequest?: string; + declare readonly rawRequest: string | null; declare readonly type: string; - declare readonly layer: null | string; + declare readonly layer: string | null; declare readonly factoryMeta?: JsFactoryMeta; declare readonly modules: Module[] | undefined; @@ -263,32 +272,47 @@ export class Module { Object.defineProperties(this, { type: { enumerable: true, - get(): string | null { - return module.type || null; + get: (): string => { + if (this.#type === undefined) { + this.#type = module.type; + } + return this.#type; } }, layer: { enumerable: true, - get(): string | undefined { - return module.layer; + get: (): string | null => { + if (this.#layer === undefined) { + this.#layer = module.layer; + } + return this.#layer; } }, context: { enumerable: true, - get(): string | undefined { - return module.context; + get: (): string | null => { + if (this.#context === undefined) { + this.#context = module.context; + } + return this.#context; } }, resource: { enumerable: true, - get(): string | undefined { - return module.resource; + get: (): string | null => { + if (this.#resource === undefined) { + this.#resource = module.resource; + } + return this.#resource; } }, request: { enumerable: true, - get(): string | undefined { - return module.request; + get: (): string | null => { + if (this.#request === undefined) { + this.#request = module.request; + } + return this.#request; } }, userRequest: { @@ -302,8 +326,11 @@ export class Module { }, rawRequest: { enumerable: true, - get(): string | undefined { - return module.rawRequest; + get: (): string | null => { + if (this.#rawRequest === undefined) { + this.#rawRequest = module.rawRequest; + } + return this.#rawRequest; } }, factoryMeta: { @@ -351,14 +378,20 @@ export class Module { }, resourceResolveData: { enumerable: true, - get(): ResolveData | undefined { - return module.resourceResolveData as any; + get: (): ResolveData | null => { + if (this.#resourceResolveData === undefined) { + this.#resourceResolveData = module.resourceResolveData as any; + } + return this.#resourceResolveData!; } }, matchResource: { enumerable: true, - get(): string | undefined { - return module.matchResource; + get: (): string | null => { + if (this.#matchResource === undefined) { + this.#matchResource = module.matchResource; + } + return this.#matchResource; } } }); @@ -372,7 +405,10 @@ export class Module { } identifier(): string { - return this.#inner.moduleIdentifier; + if (this.#identifier === undefined) { + this.#identifier = this.#inner.moduleIdentifier; + } + return this.#identifier; } nameForCondition(): string | null { diff --git a/packages/rspack/src/ModuleGraph.ts b/packages/rspack/src/ModuleGraph.ts index b822a055729..fc115b3f433 100644 --- a/packages/rspack/src/ModuleGraph.ts +++ b/packages/rspack/src/ModuleGraph.ts @@ -4,12 +4,37 @@ import { ExportsInfo } from "./ExportsInfo"; import { Module } from "./Module"; import { ModuleGraphConnection } from "./ModuleGraphConnection"; +class VolatileCache { + #map = new Map(); + + get(key: K): V | undefined { + return this.#map.get(key); + } + + set(key: K, value: V) { + if (this.#map.size === 0) { + queueMicrotask(() => { + this.#map.clear(); + }); + } + this.#map.set(key, value); + } + + has(key: K): boolean { + return this.#map.has(key); + } +} + export default class ModuleGraph { static __from_binding(binding: JsModuleGraph) { return new ModuleGraph(binding); } #inner: JsModuleGraph; + #resolvedModuleMappings = new VolatileCache(); + #outgoingConnectionsMappings = new VolatileCache(); + #parentBlockIndexMappings = new VolatileCache(); + #isAsyncCache = new VolatileCache(); private constructor(binding: JsModuleGraph) { this.#inner = binding; @@ -25,10 +50,15 @@ export default class ModuleGraph { } getResolvedModule(dependency: Dependency): Module | null { + if (this.#resolvedModuleMappings.get(dependency)) { + return this.#resolvedModuleMappings.get(dependency)!; + } const depBinding = bindingDependencyFactory.getBinding(dependency); if (depBinding) { const binding = this.#inner.getResolvedModule(depBinding); - return binding ? Module.__from_binding(binding) : null; + const module = binding ? Module.__from_binding(binding) : null; + this.#resolvedModuleMappings.set(dependency, module); + return module; } return null; } @@ -63,20 +93,35 @@ export default class ModuleGraph { } getOutgoingConnections(module: Module): ModuleGraphConnection[] { - return this.#inner + if (this.#outgoingConnectionsMappings.get(module)) { + return this.#outgoingConnectionsMappings.get(module)!; + } + const connections = this.#inner .getOutgoingConnections(Module.__to_binding(module)) .map(binding => ModuleGraphConnection.__from_binding(binding)); + this.#outgoingConnectionsMappings.set(module, connections); + return connections; } getParentBlockIndex(dependency: Dependency): number { + if (this.#parentBlockIndexMappings.get(dependency)) { + return this.#parentBlockIndexMappings.get(dependency)!; + } const depBinding = bindingDependencyFactory.getBinding(dependency); if (depBinding) { - return this.#inner.getParentBlockIndex(depBinding); + const index = this.#inner.getParentBlockIndex(depBinding); + this.#parentBlockIndexMappings.set(dependency, index); + return index; } return -1; } isAsync(module: Module): boolean { - return this.#inner.isAsync(Module.__to_binding(module)); + if (this.#isAsyncCache.get(module)) { + return this.#isAsyncCache.get(module)!; + } + const result = this.#inner.isAsync(Module.__to_binding(module)); + this.#isAsyncCache.set(module, result); + return result; } } diff --git a/packages/rspack/src/ModuleGraphConnection.ts b/packages/rspack/src/ModuleGraphConnection.ts index abda403c6f5..1e6b18d8986 100644 --- a/packages/rspack/src/ModuleGraphConnection.ts +++ b/packages/rspack/src/ModuleGraphConnection.ts @@ -12,6 +12,8 @@ export class ModuleGraphConnection { declare readonly dependency: Dependency; #inner: JsModuleGraphConnection; + #dependency: Dependency | undefined; + #resolvedModule: Module | undefined | null; static __from_binding(binding: JsModuleGraphConnection) { let connection = MODULE_GRAPH_CONNECTION_MAPPINGS.get(binding); @@ -39,19 +41,27 @@ export class ModuleGraphConnection { }, dependency: { enumerable: true, - get(): Dependency { - return bindingDependencyFactory.create( + get: (): Dependency => { + if (this.#dependency !== undefined) { + return this.#dependency; + } + this.#dependency = bindingDependencyFactory.create( Dependency, binding.dependency ); + return this.#dependency; } }, resolvedModule: { enumerable: true, - get(): Module | null { - return binding.resolvedModule + get: (): Module | null => { + if (this.#resolvedModule !== undefined) { + return this.#resolvedModule; + } + this.#resolvedModule = binding.resolvedModule ? Module.__from_binding(binding.resolvedModule) : null; + return this.#resolvedModule; } }, originModule: {