From b3d7df55357ea6fc6f5141b64a9638ddb39b0f63 Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Wed, 17 Apr 2024 07:19:55 -0700 Subject: perf: v8 code cache (#23081) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR enables V8 code cache for ES modules and for `require` scripts through `op_eval_context`. Code cache artifacts are transparently stored and fetched using sqlite db and are passed to V8. `--no-code-cache` can be used to disable. --------- Co-authored-by: Bartek IwaƄczuk --- runtime/fs_util.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'runtime/fs_util.rs') diff --git a/runtime/fs_util.rs b/runtime/fs_util.rs index f7c006a91..09b107300 100644 --- a/runtime/fs_util.rs +++ b/runtime/fs_util.rs @@ -1,6 +1,8 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use deno_ast::ModuleSpecifier; use deno_core::anyhow::Context; +use deno_core::error::uri_error; use deno_core::error::AnyError; pub use deno_core::normalize_path; use std::path::Path; @@ -18,6 +20,60 @@ pub fn resolve_from_cwd(path: &Path) -> Result { } } +/// Attempts to convert a specifier to a file path. By default, uses the Url +/// crate's `to_file_path()` method, but falls back to try and resolve unix-style +/// paths on Windows. +pub fn specifier_to_file_path( + specifier: &ModuleSpecifier, +) -> Result { + let result = if specifier.scheme() != "file" { + Err(()) + } else if cfg!(windows) { + match specifier.to_file_path() { + Ok(path) => Ok(path), + Err(()) => { + // This might be a unix-style path which is used in the tests even on Windows. + // Attempt to see if we can convert it to a `PathBuf`. This code should be removed + // once/if https://github.com/servo/rust-url/issues/730 is implemented. + if specifier.scheme() == "file" + && specifier.host().is_none() + && specifier.port().is_none() + && specifier.path_segments().is_some() + { + let path_str = specifier.path(); + match String::from_utf8( + percent_encoding::percent_decode(path_str.as_bytes()).collect(), + ) { + Ok(path_str) => Ok(PathBuf::from(path_str)), + Err(_) => Err(()), + } + } else { + Err(()) + } + } + } + } else { + specifier.to_file_path() + }; + match result { + Ok(path) => Ok(path), + Err(()) => Err(uri_error(format!( + "Invalid file path.\n Specifier: {specifier}" + ))), + } +} + +pub fn code_timestamp(specifier: &str) -> Result { + let specifier = ModuleSpecifier::parse(specifier)?; + let path = specifier_to_file_path(&specifier)?; + #[allow(clippy::disallowed_methods)] + let timestamp = std::fs::metadata(path)? + .modified()? + .duration_since(std::time::UNIX_EPOCH)? + .as_millis() as u64; + Ok(timestamp) +} + #[cfg(test)] mod tests { use super::*; @@ -69,4 +125,22 @@ mod tests { let absolute_expected = cwd.join(expected); assert_eq!(resolve_from_cwd(expected).unwrap(), absolute_expected); } + + #[test] + fn test_specifier_to_file_path() { + run_success_test("file:///", "/"); + run_success_test("file:///test", "/test"); + run_success_test("file:///dir/test/test.txt", "/dir/test/test.txt"); + run_success_test( + "file:///dir/test%20test/test.txt", + "/dir/test test/test.txt", + ); + + fn run_success_test(specifier: &str, expected_path: &str) { + let result = + specifier_to_file_path(&ModuleSpecifier::parse(specifier).unwrap()) + .unwrap(); + assert_eq!(result, PathBuf::from(expected_path)); + } + } } -- cgit v1.2.3