mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
perf(ext/node): reduce some allocations in require (#25197)
This commit is contained in:
parent
e53678fd58
commit
d8dfe6dc97
2 changed files with 52 additions and 53 deletions
|
@ -10,6 +10,7 @@ use deno_core::JsRuntimeInspector;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_fs::FileSystemRc;
|
use deno_fs::FileSystemRc;
|
||||||
|
use deno_package_json::PackageJsonRc;
|
||||||
use node_resolver::NodeModuleKind;
|
use node_resolver::NodeModuleKind;
|
||||||
use node_resolver::NodeResolutionMode;
|
use node_resolver::NodeResolutionMode;
|
||||||
use node_resolver::REQUIRE_CONDITIONS;
|
use node_resolver::REQUIRE_CONDITIONS;
|
||||||
|
@ -22,7 +23,6 @@ use crate::NodePermissions;
|
||||||
use crate::NodeRequireResolverRc;
|
use crate::NodeRequireResolverRc;
|
||||||
use crate::NodeResolverRc;
|
use crate::NodeResolverRc;
|
||||||
use crate::NpmResolverRc;
|
use crate::NpmResolverRc;
|
||||||
use crate::PackageJson;
|
|
||||||
|
|
||||||
fn ensure_read_permission<P>(
|
fn ensure_read_permission<P>(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
|
@ -70,7 +70,7 @@ pub fn op_require_init_paths() -> Vec<String> {
|
||||||
|
|
||||||
// let mut paths = paths
|
// let mut paths = paths
|
||||||
// .into_iter()
|
// .into_iter()
|
||||||
// .map(|p| p.to_string_lossy().to_string())
|
// .map(|p| p.to_string_lossy().into_owned())
|
||||||
// .collect();
|
// .collect();
|
||||||
|
|
||||||
// if !node_path.is_empty() {
|
// if !node_path.is_empty() {
|
||||||
|
@ -98,15 +98,13 @@ where
|
||||||
{
|
{
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
// Guarantee that "from" is absolute.
|
// Guarantee that "from" is absolute.
|
||||||
let from_url = if from.starts_with("file:///") {
|
let from = if from.starts_with("file:///") {
|
||||||
Url::parse(&from)?
|
url_to_file_path(&Url::parse(&from)?)?
|
||||||
} else {
|
} else {
|
||||||
deno_core::resolve_path(
|
let current_dir =
|
||||||
&from,
|
&(fs.cwd().map_err(AnyError::from)).context("Unable to get CWD")?;
|
||||||
&(fs.cwd().map_err(AnyError::from)).context("Unable to get CWD")?,
|
deno_core::normalize_path(current_dir.join(from))
|
||||||
)?
|
|
||||||
};
|
};
|
||||||
let from = url_to_file_path(&from_url)?;
|
|
||||||
|
|
||||||
ensure_read_permission::<P>(state, &from)?;
|
ensure_read_permission::<P>(state, &from)?;
|
||||||
|
|
||||||
|
@ -117,7 +115,7 @@ where
|
||||||
let bytes = from_str.as_bytes();
|
let bytes = from_str.as_bytes();
|
||||||
if bytes[from_str.len() - 1] == b'\\' && bytes[from_str.len() - 2] == b':'
|
if bytes[from_str.len() - 1] == b'\\' && bytes[from_str.len() - 2] == b':'
|
||||||
{
|
{
|
||||||
let p = from_str.to_owned() + "node_modules";
|
let p = format!("{}node_modules", from_str);
|
||||||
return Ok(vec![p]);
|
return Ok(vec![p]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,12 +127,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut paths = vec![];
|
let mut paths = Vec::with_capacity(from.components().count());
|
||||||
let mut current_path = from.as_path();
|
let mut current_path = from.as_path();
|
||||||
let mut maybe_parent = Some(current_path);
|
let mut maybe_parent = Some(current_path);
|
||||||
while let Some(parent) = maybe_parent {
|
while let Some(parent) = maybe_parent {
|
||||||
if !parent.ends_with("node_modules") {
|
if !parent.ends_with("node_modules") {
|
||||||
paths.push(parent.join("node_modules").to_string_lossy().to_string());
|
paths.push(parent.join("node_modules").to_string_lossy().into_owned());
|
||||||
}
|
}
|
||||||
current_path = parent;
|
current_path = parent;
|
||||||
maybe_parent = current_path.parent();
|
maybe_parent = current_path.parent();
|
||||||
|
@ -158,7 +156,7 @@ pub fn op_require_proxy_path(#[string] filename: String) -> String {
|
||||||
|
|
||||||
if trailing_slash {
|
if trailing_slash {
|
||||||
let p = PathBuf::from(filename);
|
let p = PathBuf::from(filename);
|
||||||
p.join("noop.js").to_string_lossy().to_string()
|
p.join("noop.js").to_string_lossy().into_owned()
|
||||||
} else {
|
} else {
|
||||||
filename
|
filename
|
||||||
}
|
}
|
||||||
|
@ -200,7 +198,7 @@ pub fn op_require_resolve_deno_dir(
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|p| p.to_string_lossy().to_string())
|
.map(|p| p.to_string_lossy().into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
|
@ -251,7 +249,7 @@ pub fn op_require_resolve_lookup_paths(
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let p = PathBuf::from(parent_filename);
|
let p = PathBuf::from(parent_filename);
|
||||||
Some(vec![p.parent().unwrap().to_string_lossy().to_string()])
|
Some(vec![p.parent().unwrap().to_string_lossy().into_owned()])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
|
@ -295,24 +293,23 @@ where
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
let canonicalized_path =
|
let canonicalized_path =
|
||||||
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
deno_core::strip_unc_prefix(fs.realpath_sync(&path)?);
|
||||||
Ok(canonicalized_path.to_string_lossy().to_string())
|
Ok(canonicalized_path.to_string_lossy().into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_resolve(parts: Vec<String>) -> String {
|
fn path_resolve<'a>(mut parts: impl Iterator<Item = &'a str>) -> PathBuf {
|
||||||
assert!(!parts.is_empty());
|
let mut p = PathBuf::from(parts.next().unwrap());
|
||||||
let mut p = PathBuf::from(&parts[0]);
|
for part in parts {
|
||||||
if parts.len() > 1 {
|
p = p.join(part);
|
||||||
for part in &parts[1..] {
|
|
||||||
p = p.join(part);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
normalize_path(p).to_string_lossy().to_string()
|
normalize_path(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
#[string]
|
#[string]
|
||||||
pub fn op_require_path_resolve(#[serde] parts: Vec<String>) -> String {
|
pub fn op_require_path_resolve(#[serde] parts: Vec<String>) -> String {
|
||||||
path_resolve(parts)
|
path_resolve(parts.iter().map(|s| s.as_str()))
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
|
@ -322,7 +319,7 @@ pub fn op_require_path_dirname(
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
let p = PathBuf::from(request);
|
let p = PathBuf::from(request);
|
||||||
if let Some(parent) = p.parent() {
|
if let Some(parent) = p.parent() {
|
||||||
Ok(parent.to_string_lossy().to_string())
|
Ok(parent.to_string_lossy().into_owned())
|
||||||
} else {
|
} else {
|
||||||
Err(generic_error("Path doesn't have a parent"))
|
Err(generic_error("Path doesn't have a parent"))
|
||||||
}
|
}
|
||||||
|
@ -335,7 +332,7 @@ pub fn op_require_path_basename(
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, AnyError> {
|
||||||
let p = PathBuf::from(request);
|
let p = PathBuf::from(request);
|
||||||
if let Some(path) = p.file_name() {
|
if let Some(path) = p.file_name() {
|
||||||
Ok(path.to_string_lossy().to_string())
|
Ok(path.to_string_lossy().into_owned())
|
||||||
} else {
|
} else {
|
||||||
Err(generic_error("Path doesn't have a file name"))
|
Err(generic_error("Path doesn't have a file name"))
|
||||||
}
|
}
|
||||||
|
@ -365,7 +362,7 @@ where
|
||||||
let fs = state.borrow::<FileSystemRc>();
|
let fs = state.borrow::<FileSystemRc>();
|
||||||
if let Ok(cwd) = fs.cwd() {
|
if let Ok(cwd) = fs.cwd() {
|
||||||
ensure_read_permission::<P>(state, &cwd)?;
|
ensure_read_permission::<P>(state, &cwd)?;
|
||||||
return Ok(Some(cwd.to_string_lossy().to_string()));
|
return Ok(Some(cwd.to_string_lossy().into_owned()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,9 +385,7 @@ where
|
||||||
|
|
||||||
let node_resolver = state.borrow::<NodeResolverRc>();
|
let node_resolver = state.borrow::<NodeResolverRc>();
|
||||||
let pkg = node_resolver
|
let pkg = node_resolver
|
||||||
.get_closest_package_json(
|
.get_closest_package_json_from_path(&PathBuf::from(parent_path.unwrap()))
|
||||||
&Url::from_file_path(parent_path.unwrap()).unwrap(),
|
|
||||||
)
|
|
||||||
.ok()
|
.ok()
|
||||||
.flatten();
|
.flatten();
|
||||||
if pkg.is_none() {
|
if pkg.is_none() {
|
||||||
|
@ -457,7 +452,7 @@ where
|
||||||
pub fn op_require_as_file_path(#[string] file_or_url: String) -> String {
|
pub fn op_require_as_file_path(#[string] file_or_url: String) -> String {
|
||||||
if let Ok(url) = Url::parse(&file_or_url) {
|
if let Ok(url) = Url::parse(&file_or_url) {
|
||||||
if let Ok(p) = url.to_file_path() {
|
if let Ok(p) = url.to_file_path() {
|
||||||
return p.to_string_lossy().to_string();
|
return p.to_string_lossy().into_owned();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +464,7 @@ pub fn op_require_as_file_path(#[string] file_or_url: String) -> String {
|
||||||
pub fn op_require_resolve_exports<P>(
|
pub fn op_require_resolve_exports<P>(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
uses_local_node_modules_dir: bool,
|
uses_local_node_modules_dir: bool,
|
||||||
#[string] modules_path: String,
|
#[string] modules_path_str: String,
|
||||||
#[string] _request: String,
|
#[string] _request: String,
|
||||||
#[string] name: String,
|
#[string] name: String,
|
||||||
#[string] expansion: String,
|
#[string] expansion: String,
|
||||||
|
@ -482,22 +477,22 @@ where
|
||||||
let npm_resolver = state.borrow::<NpmResolverRc>();
|
let npm_resolver = state.borrow::<NpmResolverRc>();
|
||||||
let node_resolver = state.borrow::<NodeResolverRc>();
|
let node_resolver = state.borrow::<NodeResolverRc>();
|
||||||
|
|
||||||
let pkg_path = if npm_resolver
|
let modules_path = PathBuf::from(&modules_path_str);
|
||||||
.in_npm_package_at_file_path(&PathBuf::from(&modules_path))
|
let pkg_path = if npm_resolver.in_npm_package_at_file_path(&modules_path)
|
||||||
&& !uses_local_node_modules_dir
|
&& !uses_local_node_modules_dir
|
||||||
{
|
{
|
||||||
modules_path
|
modules_path
|
||||||
} else {
|
} else {
|
||||||
let original = modules_path.clone();
|
let mod_dir =
|
||||||
let mod_dir = path_resolve(vec![modules_path, name]);
|
path_resolve([modules_path_str.as_str(), name.as_str()].into_iter());
|
||||||
if fs.is_dir_sync(Path::new(&mod_dir)) {
|
if fs.is_dir_sync(&mod_dir) {
|
||||||
mod_dir
|
mod_dir
|
||||||
} else {
|
} else {
|
||||||
original
|
modules_path
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let Some(pkg) = node_resolver
|
let Some(pkg) =
|
||||||
.load_package_json(&PathBuf::from(&pkg_path).join("package.json"))?
|
node_resolver.load_package_json(&pkg_path.join("package.json"))?
|
||||||
else {
|
else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
@ -527,18 +522,15 @@ where
|
||||||
pub fn op_require_read_closest_package_json<P>(
|
pub fn op_require_read_closest_package_json<P>(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[string] filename: String,
|
#[string] filename: String,
|
||||||
) -> Result<Option<PackageJson>, AnyError>
|
) -> Result<Option<PackageJsonRc>, AnyError>
|
||||||
where
|
where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
ensure_read_permission::<P>(
|
let filename = PathBuf::from(filename);
|
||||||
state,
|
ensure_read_permission::<P>(state, filename.parent().unwrap())?;
|
||||||
PathBuf::from(&filename).parent().unwrap(),
|
|
||||||
)?;
|
|
||||||
let node_resolver = state.borrow::<NodeResolverRc>().clone();
|
let node_resolver = state.borrow::<NodeResolverRc>().clone();
|
||||||
node_resolver
|
node_resolver
|
||||||
.get_closest_package_json(&Url::from_file_path(filename).unwrap())
|
.get_closest_package_json_from_path(&filename)
|
||||||
.map(|maybe_pkg| maybe_pkg.map(|pkg| (*pkg).clone()))
|
|
||||||
.map_err(AnyError::from)
|
.map_err(AnyError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +539,7 @@ where
|
||||||
pub fn op_require_read_package_scope<P>(
|
pub fn op_require_read_package_scope<P>(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[string] package_json_path: String,
|
#[string] package_json_path: String,
|
||||||
) -> Option<PackageJson>
|
) -> Option<PackageJsonRc>
|
||||||
where
|
where
|
||||||
P: NodePermissions + 'static,
|
P: NodePermissions + 'static,
|
||||||
{
|
{
|
||||||
|
@ -561,7 +553,6 @@ where
|
||||||
.load_package_json(&package_json_path)
|
.load_package_json(&package_json_path)
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.map(|pkg| (*pkg).clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
|
@ -610,7 +601,7 @@ pub fn op_require_break_on_next_statement(state: &mut OpState) {
|
||||||
|
|
||||||
fn url_to_file_path_string(url: &Url) -> Result<String, AnyError> {
|
fn url_to_file_path_string(url: &Url) -> Result<String, AnyError> {
|
||||||
let file_path = url_to_file_path(url)?;
|
let file_path = url_to_file_path(url)?;
|
||||||
Ok(file_path.to_string_lossy().to_string())
|
Ok(file_path.to_string_lossy().into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn url_to_file_path(url: &Url) -> Result<PathBuf, AnyError> {
|
fn url_to_file_path(url: &Url) -> Result<PathBuf, AnyError> {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -583,9 +584,16 @@ fn not_found(path: &str, referrer: &Path) -> AnyError {
|
||||||
std::io::Error::new(std::io::ErrorKind::NotFound, msg).into()
|
std::io::Error::new(std::io::ErrorKind::NotFound, msg).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn escape_for_double_quote_string(text: &str) -> String {
|
fn escape_for_double_quote_string(text: &str) -> Cow<str> {
|
||||||
text.replace('\\', "\\\\").replace('"', "\\\"")
|
// this should be rare, so doing a scan first before allocating is ok
|
||||||
|
if text.chars().any(|c| matches!(c, '"' | '\\')) {
|
||||||
|
// don't bother making this more complex for perf because it's rare
|
||||||
|
Cow::Owned(text.replace('\\', "\\\\").replace('"', "\\\""))
|
||||||
|
} else {
|
||||||
|
Cow::Borrowed(text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in a new issue