Skip to content

Commit

Permalink
perf: VolatileValue
Browse files Browse the repository at this point in the history
  • Loading branch information
SyMind committed Jan 10, 2025
1 parent 725152e commit 3a51cc9
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 48 deletions.
2 changes: 1 addition & 1 deletion crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export declare class JsDependency {
get request(): string | undefined
get critical(): boolean
set critical(val: boolean)
get ids(): Array<string> | undefined
get ids(): Array<string> | null
}

export declare class JsEntries {
Expand Down
12 changes: 6 additions & 6 deletions crates/rspack_binding_values/src/dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl JsDependency {
}

#[napi(getter)]
pub fn ids(&mut self, env: Env) -> napi::Result<Either<Vec<JsString>, ()>> {
pub fn ids(&mut self, env: Env) -> napi::Result<Option<Vec<JsString>>> {
let (dependency, compilation) = self.as_ref()?;

Ok(match compilation {
Expand All @@ -114,7 +114,7 @@ impl JsDependency {
.into_iter()
.map(|atom| env.create_string(atom.as_str()))
.collect::<napi::Result<Vec<_>>>()?;
Either::A(ids)
Some(ids)
} else if let Some(dependency) =
dependency.downcast_ref::<ESMExportImportedSpecifierDependency>()
{
Expand All @@ -123,19 +123,19 @@ impl JsDependency {
.into_iter()
.map(|atom| env.create_string(atom.as_str()))
.collect::<napi::Result<Vec<_>>>()?;
Either::A(ids)
Some(ids)
} else if let Some(dependency) = dependency.downcast_ref::<ESMImportSpecifierDependency>() {
let ids = dependency
.get_ids(&module_graph)
.into_iter()
.map(|atom| env.create_string(atom.as_str()))
.collect::<napi::Result<Vec<_>>>()?;
Either::A(ids)
Some(ids)
} else {
Either::B(())
None
}
}
None => Either::B(()),
None => None,
})
}
}
Expand Down
12 changes: 10 additions & 2 deletions packages/rspack/src/Dependency.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { JsDependency } from "@rspack/binding";
import { VolatileValue } from "./util/volatile";

const TO_BINDING_MAPPINGS = new WeakMap<Dependency, JsDependency>();
const BINDING_MAPPINGS = new WeakMap<JsDependency, Dependency>();
Expand Down Expand Up @@ -28,6 +29,7 @@ export const bindingDependencyFactory = {
export class Dependency {
#type: string | undefined;
#category: string | undefined;
#ids = new VolatileValue<string[] | null>();

get type(): string {
if (this.#type === undefined) {
Expand Down Expand Up @@ -71,10 +73,16 @@ export class Dependency {
}
}

get ids(): string[] | undefined {
get ids(): string[] | null {
const binding = bindingDependencyFactory.getBinding(this);
if (this.#ids.get() !== undefined) {
return this.#ids.get()!;
}
if (binding) {
return binding.ids;
const ids = binding.ids;
this.#ids.set(ids);
return ids;
}
return null;
}
}
54 changes: 17 additions & 37 deletions packages/rspack/src/ModuleGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,18 @@ import { bindingDependencyFactory, Dependency } from "./Dependency";
import { ExportsInfo } from "./ExportsInfo";
import { Module } from "./Module";
import { ModuleGraphConnection } from "./ModuleGraphConnection";

class VolatileCache<K, V> {
#map = new Map<K, V>();

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);
}
}
import { VolatileMap } from "./util/volatile";

export default class ModuleGraph {
static __from_binding(binding: JsModuleGraph) {
return new ModuleGraph(binding);
}

#inner: JsModuleGraph;
#resolvedModuleMappings = new VolatileCache<Dependency, Module | null>();
#outgoingConnectionsMappings = new VolatileCache<Module, ModuleGraphConnection[]>();
#parentBlockIndexMappings = new VolatileCache<Dependency, number>();
#isAsyncCache = new VolatileCache<Module, boolean>();
#resolvedModuleMap = new VolatileMap<Dependency, Module | null>();
#outgoingConnectionsMap = new VolatileMap<Module, ModuleGraphConnection[]>();
#parentBlockIndexMap = new VolatileMap<Dependency, number>();
#isAsyncMap = new VolatileMap<Module, boolean>();

private constructor(binding: JsModuleGraph) {
this.#inner = binding;
Expand All @@ -50,14 +30,14 @@ export default class ModuleGraph {
}

getResolvedModule(dependency: Dependency): Module | null {
if (this.#resolvedModuleMappings.get(dependency)) {
return this.#resolvedModuleMappings.get(dependency)!;
if (this.#resolvedModuleMap.get(dependency) !== undefined) {
return this.#resolvedModuleMap.get(dependency)!;
}
const depBinding = bindingDependencyFactory.getBinding(dependency);
if (depBinding) {
const binding = this.#inner.getResolvedModule(depBinding);
const module = binding ? Module.__from_binding(binding) : null;
this.#resolvedModuleMappings.set(dependency, module);
this.#resolvedModuleMap.set(dependency, module);
return module;
}
return null;
Expand Down Expand Up @@ -93,35 +73,35 @@ export default class ModuleGraph {
}

getOutgoingConnections(module: Module): ModuleGraphConnection[] {
if (this.#outgoingConnectionsMappings.get(module)) {
return this.#outgoingConnectionsMappings.get(module)!;
if (this.#outgoingConnectionsMap.get(module)) {
return this.#outgoingConnectionsMap.get(module)!;
}
const connections = this.#inner
.getOutgoingConnections(Module.__to_binding(module))
.map(binding => ModuleGraphConnection.__from_binding(binding));
this.#outgoingConnectionsMappings.set(module, connections);
this.#outgoingConnectionsMap.set(module, connections);
return connections;
}

getParentBlockIndex(dependency: Dependency): number {
if (this.#parentBlockIndexMappings.get(dependency)) {
return this.#parentBlockIndexMappings.get(dependency)!;
if (this.#parentBlockIndexMap.get(dependency) !== undefined) {
return this.#parentBlockIndexMap.get(dependency)!;
}
const depBinding = bindingDependencyFactory.getBinding(dependency);
if (depBinding) {
const index = this.#inner.getParentBlockIndex(depBinding);
this.#parentBlockIndexMappings.set(dependency, index);
this.#parentBlockIndexMap.set(dependency, index);
return index;
}
return -1;
}

isAsync(module: Module): boolean {
if (this.#isAsyncCache.get(module)) {
return this.#isAsyncCache.get(module)!;
if (this.#isAsyncMap.get(module) !== undefined) {
return this.#isAsyncMap.get(module)!;
}
const result = this.#inner.isAsync(Module.__to_binding(module));
this.#isAsyncCache.set(module, result);
this.#isAsyncMap.set(module, result);
return result;
}
}
13 changes: 11 additions & 2 deletions packages/rspack/src/ModuleGraphConnection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { JsModuleGraphConnection } from "@rspack/binding";
import { bindingDependencyFactory, Dependency } from "./Dependency";
import { Module } from "./Module";
import { VolatileValue } from "./util/volatile";

const MODULE_GRAPH_CONNECTION_MAPPINGS = new WeakMap<
JsModuleGraphConnection,
Expand All @@ -12,6 +13,7 @@ export class ModuleGraphConnection {
declare readonly dependency: Dependency;

#inner: JsModuleGraphConnection;
#module: VolatileValue<Module | null> = new VolatileValue();
#dependency: Dependency | undefined;
#resolvedModule: Module | undefined | null;

Expand All @@ -35,8 +37,15 @@ export class ModuleGraphConnection {
Object.defineProperties(this, {
module: {
enumerable: true,
get(): Module | null {
return binding.module ? Module.__from_binding(binding.module) : null;
get: (): Module | null => {
if (this.#module.get() !== undefined) {
return this.#module.get()!;
}
const module = binding.module
? Module.__from_binding(binding.module)
: null;
this.#module.set(module);
return module;
}
},
dependency: {
Expand Down
54 changes: 54 additions & 0 deletions packages/rspack/src/util/volatile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class MicrotaskQueue {
#callbacks: (() => void)[] = [];

queue(callback: () => void) {
if (this.#callbacks.length === 0) {
queueMicrotask(() => {
for (const cb of this.#callbacks) {
cb();
}
});
}
this.#callbacks.push(callback);
}
}

const GLOBAL_MICROTASK_QUEUE = new MicrotaskQueue();

export class VolatileMap<K, V> {
#map = new Map<K, V>();

get(key: K): V | undefined {
return this.#map.get(key);
}

set(key: K, value: V) {
if (this.#map.size === 0) {
GLOBAL_MICROTASK_QUEUE.queue(() => {
this.#map.clear();
});
}
this.#map.set(key, value);
}

has(key: K): boolean {
return this.#map.has(key);
}
}

export class VolatileValue<V> {
#value: V | undefined = undefined;

get(): V | undefined {
return this.#value;
}

set(value: V) {
if (this.#value === undefined) {
GLOBAL_MICROTASK_QUEUE.queue(() => {
this.#value = undefined;
});
}
this.#value = value;
}
}

0 comments on commit 3a51cc9

Please sign in to comment.