Skip to content

Commit cb2b369

Browse files
committed
perf: JsHookUsageTracker
1 parent 2fa739a commit cb2b369

6 files changed

Lines changed: 170 additions & 197 deletions

File tree

crates/node_binding/napi-binding.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,8 @@ export const EXPECTED_RSPACK_CORE_VERSION: string
645645

646646
export declare function formatDiagnostic(diagnostic: JsDiagnostic): ExternalObject<'Diagnostic'>
647647

648+
export declare function getRegisterJsTapScopeKinds(): RegisterJsTapScopeKinds
649+
648650
export interface JsAddingRuntimeModule {
649651
name: string
650652
generator: () => String
@@ -3190,6 +3192,11 @@ export interface RegisterJsTaps {
31903192
registerRsdoctorPluginAssetsTaps: (stages: Array<number>) => Array<{ function: ((arg: JsRsdoctorAssetPatch) => Promise<boolean | undefined>); stage: number; }>
31913193
}
31923194

3195+
export interface RegisterJsTapScopeKinds {
3196+
compiler: Array<RegisterJsTapKind>
3197+
compilation: Array<RegisterJsTapKind>
3198+
}
3199+
31933200
export interface ResolveResult {
31943201
path?: string
31953202
error?: string

crates/rspack_binding_api/src/plugins/interceptor.rs

Lines changed: 88 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ use std::{
22
ffi::c_void,
33
hash::Hash,
44
ptr::NonNull,
5-
sync::{
6-
Arc, RwLock,
7-
atomic::{AtomicU8, Ordering},
8-
},
5+
sync::{Arc, RwLock},
96
};
107

118
use async_trait::async_trait;
@@ -190,51 +187,31 @@ type RegisterFunction<T, R> = ThreadsafeFunction<Vec<i32>, RegisterFunctionOutpu
190187

191188
#[derive(Clone)]
192189
pub(super) struct HookUsageChecker {
193-
inner: Arc<HookUsageCheckerInner>,
194-
}
195-
196-
struct HookUsageCheckerInner {
197-
_buffer: Buffer,
198-
bytes: NonNull<AtomicU8>,
199-
len: usize,
190+
buffer: Arc<Buffer>,
200191
}
201192

202-
unsafe impl Send for HookUsageCheckerInner {}
203-
unsafe impl Sync for HookUsageCheckerInner {}
204-
205193
impl HookUsageChecker {
206194
pub(super) fn new(buffer: Buffer) -> Self {
195+
assert_eq!(
196+
buffer.len(),
197+
HOOK_USAGE_BUFFER_BYTE_LENGTH,
198+
"hook usage Buffer length mismatch",
199+
);
207200
Self {
208-
inner: {
209-
let len = buffer.len();
210-
#[allow(clippy::unwrap_used)]
211-
let bytes = NonNull::new(buffer.as_ref().as_ptr() as *mut AtomicU8).unwrap();
212-
Arc::new(HookUsageCheckerInner {
213-
_buffer: buffer,
214-
bytes,
215-
len,
216-
})
217-
},
201+
buffer: Arc::new(buffer),
218202
}
219203
}
220204

221-
pub(super) fn is_used(&self, kind: &RegisterJsTapKind) -> bool {
222-
let inner = &self.inner;
223-
let bit_index = *kind as usize;
205+
#[inline(always)]
206+
pub(super) fn is_used(&self, kind: RegisterJsTapKind) -> bool {
207+
let bit_index = kind as usize;
224208
let byte_index = bit_index >> 3;
225209
let bit_mask = 1 << (bit_index & 7);
226-
if byte_index >= inner.len {
227-
return false;
228-
}
229-
let byte = unsafe { &*inner.bytes.as_ptr().add(byte_index) }.load(Ordering::Acquire);
210+
let byte = self.buffer.as_ref()[byte_index];
230211
byte & bit_mask != 0
231212
}
232213
}
233214

234-
fn should_skip_register(hook_usage_checker: &HookUsageChecker, kind: &RegisterJsTapKind) -> bool {
235-
!hook_usage_checker.is_used(kind)
236-
}
237-
238215
struct RegisterJsTapsInner<T: 'static + JsValuesTupleIntoVec, R> {
239216
register: RegisterFunction<T, R>,
240217
cache: RegisterJsTapsCache<T, R>,
@@ -399,7 +376,7 @@ macro_rules! define_register {
399376
&self,
400377
hook: &$tap_hook,
401378
) -> rspack_error::Result<Vec<<$tap_hook as Hook>::Tap>> {
402-
if should_skip_register(&self.inner.hook_usage_checker, &$kind) {
379+
if !self.inner.hook_usage_checker.is_used($kind) {
403380
return Ok(Vec::new());
404381
}
405382
let js_taps = self.inner.call_register(hook).await?;
@@ -414,6 +391,7 @@ macro_rules! define_register {
414391
}
415392

416393
#[napi]
394+
#[repr(u8)]
417395
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
418396
pub enum RegisterJsTapKind {
419397
CompilerThisCompilation,
@@ -469,6 +447,80 @@ pub enum RegisterJsTapKind {
469447
RsdoctorPluginAssets,
470448
}
471449

450+
const HOOK_USAGE_BUFFER_BYTE_LENGTH: usize =
451+
((RegisterJsTapKind::RsdoctorPluginAssets as usize) >> 3) + 1;
452+
453+
const COMPILER_HOOKS: &[RegisterJsTapKind] = &[
454+
RegisterJsTapKind::CompilerThisCompilation,
455+
RegisterJsTapKind::CompilerCompilation,
456+
RegisterJsTapKind::CompilerMake,
457+
RegisterJsTapKind::CompilerFinishMake,
458+
RegisterJsTapKind::CompilerShouldEmit,
459+
RegisterJsTapKind::CompilerEmit,
460+
RegisterJsTapKind::CompilerAfterEmit,
461+
RegisterJsTapKind::CompilerAssetEmitted,
462+
];
463+
464+
const COMPILATION_HOOKS: &[RegisterJsTapKind] = &[
465+
RegisterJsTapKind::CompilationBuildModule,
466+
RegisterJsTapKind::CompilationStillValidModule,
467+
RegisterJsTapKind::CompilationSucceedModule,
468+
RegisterJsTapKind::CompilationExecuteModule,
469+
RegisterJsTapKind::CompilationFinishModules,
470+
RegisterJsTapKind::CompilationOptimizeModules,
471+
RegisterJsTapKind::CompilationAfterOptimizeModules,
472+
RegisterJsTapKind::CompilationOptimizeTree,
473+
RegisterJsTapKind::CompilationOptimizeChunkModules,
474+
RegisterJsTapKind::CompilationBeforeModuleIds,
475+
RegisterJsTapKind::CompilationAdditionalTreeRuntimeRequirements,
476+
RegisterJsTapKind::CompilationRuntimeRequirementInTree,
477+
RegisterJsTapKind::CompilationRuntimeModule,
478+
RegisterJsTapKind::CompilationChunkHash,
479+
RegisterJsTapKind::CompilationChunkAsset,
480+
RegisterJsTapKind::CompilationProcessAssets,
481+
RegisterJsTapKind::CompilationAfterProcessAssets,
482+
RegisterJsTapKind::CompilationSeal,
483+
RegisterJsTapKind::CompilationAfterSeal,
484+
RegisterJsTapKind::NormalModuleFactoryBeforeResolve,
485+
RegisterJsTapKind::NormalModuleFactoryFactorize,
486+
RegisterJsTapKind::NormalModuleFactoryResolve,
487+
RegisterJsTapKind::NormalModuleFactoryAfterResolve,
488+
RegisterJsTapKind::NormalModuleFactoryCreateModule,
489+
RegisterJsTapKind::NormalModuleFactoryResolveForScheme,
490+
RegisterJsTapKind::ContextModuleFactoryBeforeResolve,
491+
RegisterJsTapKind::ContextModuleFactoryAfterResolve,
492+
RegisterJsTapKind::JavascriptModulesChunkHash,
493+
RegisterJsTapKind::HtmlPluginBeforeAssetTagGeneration,
494+
RegisterJsTapKind::HtmlPluginAlterAssetTags,
495+
RegisterJsTapKind::HtmlPluginAlterAssetTagGroups,
496+
RegisterJsTapKind::HtmlPluginAfterTemplateExecution,
497+
RegisterJsTapKind::HtmlPluginBeforeEmit,
498+
RegisterJsTapKind::HtmlPluginAfterEmit,
499+
RegisterJsTapKind::RuntimePluginCreateScript,
500+
RegisterJsTapKind::RuntimePluginCreateLink,
501+
RegisterJsTapKind::RuntimePluginLinkPreload,
502+
RegisterJsTapKind::RuntimePluginLinkPrefetch,
503+
RegisterJsTapKind::RsdoctorPluginModuleGraph,
504+
RegisterJsTapKind::RsdoctorPluginChunkGraph,
505+
RegisterJsTapKind::RsdoctorPluginModuleIds,
506+
RegisterJsTapKind::RsdoctorPluginModuleSources,
507+
RegisterJsTapKind::RsdoctorPluginAssets,
508+
];
509+
510+
#[napi(object)]
511+
pub struct RegisterJsTapScopeKinds {
512+
pub compiler: Vec<RegisterJsTapKind>,
513+
pub compilation: Vec<RegisterJsTapKind>,
514+
}
515+
516+
#[napi]
517+
pub fn get_register_js_tap_scope_kinds() -> RegisterJsTapScopeKinds {
518+
RegisterJsTapScopeKinds {
519+
compiler: COMPILER_HOOKS.to_vec(),
520+
compilation: COMPILATION_HOOKS.to_vec(),
521+
}
522+
}
523+
472524
#[derive(Clone)]
473525
#[napi(object, object_to_js = false)]
474526
pub struct RegisterJsTaps {
@@ -2027,45 +2079,3 @@ impl RsdoctorPluginAssets for RsdoctorPluginAssetsTap {
20272079
self.stage
20282080
}
20292081
}
2030-
2031-
#[cfg(test)]
2032-
mod tests {
2033-
use super::*;
2034-
2035-
fn checker_with_used_kinds(kinds: &[RegisterJsTapKind]) -> HookUsageChecker {
2036-
let byte_len = ((RegisterJsTapKind::RsdoctorPluginAssets as usize) >> 3) + 1;
2037-
let mut bytes = vec![0; byte_len];
2038-
for kind in kinds {
2039-
let bit_index = *kind as usize;
2040-
bytes[bit_index >> 3] |= 1 << (bit_index & 7);
2041-
}
2042-
HookUsageChecker::new(Buffer::from(bytes))
2043-
}
2044-
2045-
#[test]
2046-
fn hook_usage_checker_reads_bits() {
2047-
let checker = checker_with_used_kinds(&[
2048-
RegisterJsTapKind::CompilerCompilation,
2049-
RegisterJsTapKind::CompilationProcessAssets,
2050-
]);
2051-
2052-
assert!(checker.is_used(&RegisterJsTapKind::CompilerCompilation));
2053-
assert!(checker.is_used(&RegisterJsTapKind::CompilationProcessAssets));
2054-
assert!(!checker.is_used(&RegisterJsTapKind::CompilerMake));
2055-
}
2056-
2057-
#[test]
2058-
fn checker_path_skips_unused_registers() {
2059-
let empty_checker = checker_with_used_kinds(&[]);
2060-
let used_checker = checker_with_used_kinds(&[RegisterJsTapKind::CompilerCompilation]);
2061-
2062-
assert!(should_skip_register(
2063-
&empty_checker,
2064-
&RegisterJsTapKind::CompilationBuildModule,
2065-
));
2066-
assert!(!should_skip_register(
2067-
&used_checker,
2068-
&RegisterJsTapKind::CompilerCompilation,
2069-
));
2070-
}
2071-
}

packages/rspack/src/Compiler.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ import {
4747
import {
4848
COMPILER_HOOK_USAGE_TRACKERS,
4949
JsHookUsageTracker,
50-
markHookInterceptorAsInternal,
5150
trackHookUsage,
5251
} from './HookUsageTracker';
5352
import type { FileSystemInfoEntry } from './FileSystemInfo';
@@ -983,11 +982,9 @@ class Compiler {
983982
// reassign new compilation in thisCompilation
984983
this.#compilation = undefined;
985984
// ensure thisCompilation must call
986-
this.hooks.thisCompilation.intercept(
987-
markHookInterceptorAsInternal({
988-
call: () => {},
989-
}),
990-
);
985+
this.hooks.thisCompilation.intercept({
986+
call: () => {},
987+
});
991988
}
992989

993990
#newCompilationParams(): CompilationParams {
@@ -997,8 +994,10 @@ class Compiler {
997994
hookUsageTracker,
998995
);
999996
this.hooks.normalModuleFactory.call(normalModuleFactory);
997+
1000998
const contextModuleFactory = new ContextModuleFactory(hookUsageTracker);
1001999
this.hooks.contextModuleFactory.call(contextModuleFactory);
1000+
10021001
const params = {
10031002
normalModuleFactory,
10041003
contextModuleFactory,

0 commit comments

Comments
 (0)