diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-07-25 23:43:00 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-25 23:43:00 +0200 |
commit | 06209f824cf398bcd3332dc37f2d22cbdd840647 (patch) | |
tree | 4aa5dc460363953f4bb9ab08011bbd75df8a95e1 | |
parent | 5d8d1105a408b0e1f1a89a0d9e3c3cffddd640ab (diff) |
perf: cache node resolution when accesing a global (#19930)
Reclaims some of the performance hit introduced by
https://github.com/denoland/deno/pull/19307.
-rw-r--r-- | cli/tests/testdata/run/with_package_json/npm_binary/main.out | 3 | ||||
-rw-r--r-- | ext/fs/sync.rs | 61 | ||||
-rw-r--r-- | ext/node/global.rs | 6 | ||||
-rw-r--r-- | ext/node/resolution.rs | 25 |
4 files changed, 86 insertions, 9 deletions
diff --git a/cli/tests/testdata/run/with_package_json/npm_binary/main.out b/cli/tests/testdata/run/with_package_json/npm_binary/main.out index 9e8e87bae..56cdae6f9 100644 --- a/cli/tests/testdata/run/with_package_json/npm_binary/main.out +++ b/cli/tests/testdata/run/with_package_json/npm_binary/main.out @@ -1,9 +1,6 @@ [WILDCARD]package.json file found at '[WILDCARD]with_package_json[WILDCARD]npm_binary[WILDCARD]package.json' [WILDCARD] this -[WILDCARD] is -[WILDCARD] a -[WILDCARD] test diff --git a/ext/fs/sync.rs b/ext/fs/sync.rs index c43850c28..749e4ee02 100644 --- a/ext/fs/sync.rs +++ b/ext/fs/sync.rs @@ -5,10 +5,42 @@ pub use inner::*; #[cfg(feature = "sync_fs")] mod inner { #![allow(clippy::disallowed_types)] + + use std::ops::Deref; + use std::ops::DerefMut; pub use std::sync::Arc as MaybeArc; pub use core::marker::Send as MaybeSend; pub use core::marker::Sync as MaybeSync; + + pub struct MaybeArcMutexGuard<'lock, T>(std::sync::MutexGuard<'lock, T>); + + impl<'lock, T> Deref for MaybeArcMutexGuard<'lock, T> { + type Target = std::sync::MutexGuard<'lock, T>; + fn deref(&self) -> &std::sync::MutexGuard<'lock, T> { + &self.0 + } + } + + impl<'lock, T> DerefMut for MaybeArcMutexGuard<'lock, T> { + fn deref_mut(&mut self) -> &mut std::sync::MutexGuard<'lock, T> { + &mut self.0 + } + } + + #[derive(Debug)] + pub struct MaybeArcMutex<T>(std::sync::Arc<std::sync::Mutex<T>>); + impl<T> MaybeArcMutex<T> { + pub fn new(val: T) -> Self { + Self(std::sync::Arc::new(std::sync::Mutex::new(val))) + } + } + + impl<'lock, T> MaybeArcMutex<T> { + pub fn lock(&'lock self) -> MaybeArcMutexGuard<'lock, T> { + MaybeArcMutexGuard(self.0.lock().unwrap()) + } + } } #[cfg(not(feature = "sync_fs"))] @@ -19,4 +51,33 @@ mod inner { impl<T> MaybeSync for T where T: ?Sized {} pub trait MaybeSend {} impl<T> MaybeSend for T where T: ?Sized {} + + pub struct MaybeArcMutexGuard<'lock, T>(std::cell::RefMut<'lock, T>); + + impl<'lock, T> Deref for MaybeArcMutexGuard<'lock, T> { + type Target = std::cell::RefMut<'lock, T>; + fn deref(&self) -> &std::cell::RefMut<'lock, T> { + &self.0 + } + } + + impl<'lock, T> DerefMut for MaybeArcMutexGuard<'lock, T> { + fn deref_mut(&mut self) -> &mut std::cell::RefMut<'lock, T> { + &mut self.0 + } + } + + #[derive(Debug)] + pub struct MaybeArcMutex<T>(std::rc::Rc<std::cell::RefCell<T>>); + impl<T> MaybeArcMutex<T> { + pub fn new(val: T) -> Self { + Self(std::rc::Rc::new(std::cell::RefCell::new(val))) + } + } + + impl<'lock, T> MaybeArcMutex<T> { + pub fn lock(&'lock self) -> MaybeArcMutexGuard<'lock, T> { + MaybeArcMutexGuard(self.0.borrow_mut()) + } + } } diff --git a/ext/node/global.rs b/ext/node/global.rs index 3e3bfb853..78e009971 100644 --- a/ext/node/global.rs +++ b/ext/node/global.rs @@ -267,16 +267,12 @@ fn current_mode(scope: &mut v8::HandleScope) -> Mode { return Mode::Deno; }; let string = v8_string.to_rust_string_lossy(scope); - // TODO: don't require parsing the specifier - let Ok(specifier) = deno_core::ModuleSpecifier::parse(&string) else { - return Mode::Deno; - }; let op_state = deno_core::JsRuntime::op_state_from(scope); let op_state = op_state.borrow(); let Some(node_resolver) = op_state.try_borrow::<Rc<NodeResolver>>() else { return Mode::Deno; }; - if node_resolver.in_npm_package(&specifier) { + if node_resolver.in_npm_package_with_cache(string) { Mode::Node } else { Mode::Deno diff --git a/ext/node/resolution.rs b/ext/node/resolution.rs index 748506789..143edb6fe 100644 --- a/ext/node/resolution.rs +++ b/ext/node/resolution.rs @@ -1,5 +1,6 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +use std::collections::HashMap; use std::path::Path; use std::path::PathBuf; @@ -111,17 +112,39 @@ pub type NodeResolverRc = deno_fs::sync::MaybeArc<NodeResolver>; pub struct NodeResolver { fs: FileSystemRc, npm_resolver: NpmResolverRc, + in_npm_package_cache: deno_fs::sync::MaybeArcMutex<HashMap<String, bool>>, } impl NodeResolver { pub fn new(fs: FileSystemRc, npm_resolver: NpmResolverRc) -> Self { - Self { fs, npm_resolver } + Self { + fs, + npm_resolver, + in_npm_package_cache: deno_fs::sync::MaybeArcMutex::new(HashMap::new()), + } } pub fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool { self.npm_resolver.in_npm_package(specifier) } + pub fn in_npm_package_with_cache(&self, specifier: String) -> bool { + let mut cache = self.in_npm_package_cache.lock(); + + if let Some(result) = cache.get(&specifier) { + return *result; + } + + let result = + if let Ok(specifier) = deno_core::ModuleSpecifier::parse(&specifier) { + self.npm_resolver.in_npm_package(&specifier) + } else { + false + }; + cache.insert(specifier, result); + result + } + /// This function is an implementation of `defaultResolve` in /// `lib/internal/modules/esm/resolve.js` from Node. pub fn resolve( |