1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-24 15:19:26 -05:00

feat(core): Ability to create snapshots from existing snapshots (#16597)

Co-authored-by: crowlkats <crowlkats@toaxl.com>
This commit is contained in:
Bartek Iwańczuk 2022-11-21 14:36:26 +01:00 committed by GitHub
parent fedeea6dde
commit d232746928
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1144 additions and 991 deletions

13
Cargo.lock generated
View file

@ -781,25 +781,13 @@ dependencies = [
"data-url",
"deno_ast 0.21.0",
"deno_bench_util",
"deno_broadcast_channel",
"deno_cache",
"deno_console",
"deno_core",
"deno_crypto",
"deno_doc",
"deno_emit",
"deno_fetch",
"deno_graph",
"deno_lint",
"deno_net",
"deno_node",
"deno_runtime",
"deno_task_shell",
"deno_url",
"deno_web",
"deno_webgpu",
"deno_websocket",
"deno_webstorage",
"dissimilar",
"dotenv",
"dprint-plugin-json",
@ -822,6 +810,7 @@ dependencies = [
"libc",
"log",
"lsp-types",
"lzzzz",
"mitata",
"monch",
"napi_sym",

View file

@ -26,25 +26,16 @@ harness = false
path = "./bench/lsp_bench_standalone.rs"
[build-dependencies]
deno_broadcast_channel = { version = "0.72.0", path = "../ext/broadcast_channel" }
deno_cache = { version = "0.10.0", path = "../ext/cache" }
deno_console = { version = "0.78.0", path = "../ext/console" }
deno_runtime = { version = "0.86.0", path = "../runtime" }
deno_core = { version = "0.160.0", path = "../core" }
deno_crypto = { version = "0.92.0", path = "../ext/crypto" }
deno_fetch = { version = "0.101.0", path = "../ext/fetch" }
deno_net = { version = "0.70.0", path = "../ext/net" }
deno_node = { version = "0.15.0", path = "../ext/node" }
deno_url = { version = "0.78.0", path = "../ext/url" }
deno_web = { version = "0.109.0", path = "../ext/web" }
deno_webgpu = { version = "0.79.0", path = "../ext/webgpu" }
deno_websocket = { version = "0.83.0", path = "../ext/websocket" }
deno_webstorage = { version = "0.73.0", path = "../ext/webstorage" }
regex = "=1.6.0"
serde = { version = "=1.0.144", features = ["derive"] }
serde_json = "1.0.64"
zstd = '=0.11.2'
glibc_version = "0.1.2"
lzzzz = '1.0'
[target.'cfg(windows)'.build-dependencies]
winapi = "=0.3.9"
winres = "=0.1.12"
@ -86,6 +77,7 @@ jsonc-parser = { version = "=0.21.0", features = ["serde"] }
libc = "=0.2.126"
log = { version = "=0.4.17", features = ["serde"] }
lsp-types = "=0.93.2" # used by tower-lsp and "proposed" feature is unstable in patch releases
lzzzz = '1.0'
mitata = "=0.0.7"
monch = "=0.4.0"
notify = "=5.0.0"

View file

@ -1,72 +1,29 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::serde::Deserialize;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::OpState;
use deno_core::RuntimeOptions;
use regex::Regex;
use std::collections::HashMap;
use std::env;
use std::path::Path;
use std::path::PathBuf;
// TODO(bartlomieju): this module contains a lot of duplicated
// logic with `runtime/build.rs`, factor out to `deno_core`.
fn create_snapshot(
mut js_runtime: JsRuntime,
snapshot_path: &Path,
files: Vec<PathBuf>,
) {
// TODO(nayeemrmn): https://github.com/rust-lang/cargo/issues/3946 to get the
// workspace root.
let display_root = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap();
for file in files {
println!("cargo:rerun-if-changed={}", file.display());
let display_path = file.strip_prefix(display_root).unwrap();
let display_path_str = display_path.display().to_string();
js_runtime
.execute_script(
&("deno:".to_string() + &display_path_str.replace('\\', "/")),
&std::fs::read_to_string(&file).unwrap(),
)
.unwrap();
}
use deno_core::snapshot_util::*;
use deno_runtime::deno_cache::SqliteBackedCache;
use deno_runtime::permissions::Permissions;
use deno_runtime::*;
let snapshot = js_runtime.snapshot();
let snapshot_slice: &[u8] = &snapshot;
println!("Snapshot size: {}", snapshot_slice.len());
let compressed_snapshot_with_size = {
let mut vec = vec![];
vec.extend_from_slice(
&u32::try_from(snapshot.len())
.expect("snapshot larger than 4gb")
.to_le_bytes(),
);
vec.extend_from_slice(
&zstd::bulk::compress(snapshot_slice, 22)
.expect("snapshot compression failed"),
);
vec
};
println!(
"Snapshot compressed size: {}",
compressed_snapshot_with_size.len()
);
std::fs::write(snapshot_path, compressed_snapshot_with_size).unwrap();
println!("Snapshot written to: {} ", snapshot_path.display());
}
mod ts {
use super::*;
use crate::deno_webgpu_get_declaration;
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::OpState;
use regex::Regex;
use serde::Deserialize;
use serde_json::json;
use serde_json::Value;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
#[derive(Debug, Deserialize)]
struct LoadArgs {
@ -74,8 +31,8 @@ struct LoadArgs {
specifier: String,
}
fn create_compiler_snapshot(
snapshot_path: &Path,
pub fn create_compiler_snapshot(
snapshot_path: PathBuf,
files: Vec<PathBuf>,
cwd: &Path,
) {
@ -264,8 +221,11 @@ fn create_compiler_snapshot(
))
}
}
let js_runtime = JsRuntime::new(RuntimeOptions {
will_snapshot: true,
create_snapshot(CreateSnapshotOptions {
cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
snapshot_path,
startup_snapshot: None,
extensions: vec![Extension::builder()
.ops(vec![
op_build_info::decl(),
@ -283,13 +243,17 @@ fn create_compiler_snapshot(
Ok(())
})
.build()],
..Default::default()
additional_files: files,
compression_cb: Some(Box::new(|vec, snapshot_slice| {
vec.extend_from_slice(
&zstd::bulk::compress(snapshot_slice, 22)
.expect("snapshot compression failed"),
);
})),
});
create_snapshot(js_runtime, snapshot_path, files);
}
fn ts_version() -> String {
pub(crate) fn version() -> String {
std::fs::read_to_string("tsc/00_typescript.js")
.unwrap()
.lines()
@ -302,6 +266,55 @@ fn ts_version() -> String {
.take_while(|c| *c != '"')
.collect::<String>()
}
}
fn create_cli_snapshot(snapshot_path: PathBuf, files: Vec<PathBuf>) {
let extensions: Vec<Extension> = vec![
deno_webidl::init(),
deno_console::init(),
deno_url::init(),
deno_tls::init(),
deno_web::init::<Permissions>(
deno_web::BlobStore::default(),
Default::default(),
),
deno_fetch::init::<Permissions>(Default::default()),
deno_cache::init::<SqliteBackedCache>(None),
deno_websocket::init::<Permissions>("".to_owned(), None, None),
deno_webstorage::init(None),
deno_crypto::init(None),
deno_webgpu::init(false),
deno_broadcast_channel::init(
deno_broadcast_channel::InMemoryBroadcastChannel::default(),
false, // No --unstable.
),
deno_node::init::<Permissions>(None), // No --unstable.
deno_ffi::init::<Permissions>(false),
deno_net::init::<Permissions>(
None, false, // No --unstable.
None,
),
deno_napi::init::<Permissions>(false),
deno_http::init(),
deno_flash::init::<Permissions>(false), // No --unstable
];
create_snapshot(CreateSnapshotOptions {
cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
snapshot_path,
startup_snapshot: Some(deno_runtime::js::deno_isolate_init()),
extensions,
additional_files: files,
compression_cb: Some(Box::new(|vec, snapshot_slice| {
lzzzz::lz4_hc::compress_to_vec(
snapshot_slice,
vec,
lzzzz::lz4_hc::CLEVEL_MAX,
)
.expect("snapshot compression failed");
})),
})
}
fn git_commit_hash() -> String {
if let Ok(output) = std::process::Command::new("git")
@ -386,7 +399,7 @@ fn main() {
println!("cargo:rustc-env=GIT_COMMIT_HASH={}", git_commit_hash());
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH");
println!("cargo:rustc-env=TS_VERSION={}", ts_version());
println!("cargo:rustc-env=TS_VERSION={}", ts::version());
println!("cargo:rerun-if-env-changed=TS_VERSION");
println!(
@ -440,11 +453,14 @@ fn main() {
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
// Main snapshot
let compiler_snapshot_path = o.join("COMPILER_SNAPSHOT.bin");
let js_files = get_js_files(env!("CARGO_MANIFEST_DIR"), "tsc");
ts::create_compiler_snapshot(compiler_snapshot_path, js_files, &c);
let js_files = get_js_files("tsc");
create_compiler_snapshot(&compiler_snapshot_path, js_files, &c);
let cli_snapshot_path = o.join("CLI_SNAPSHOT.bin");
let mut js_files = get_js_files(env!("CARGO_MANIFEST_DIR"), "js");
js_files.push(deno_runtime::js::get_99_main());
create_cli_snapshot(cli_snapshot_path, js_files);
#[cfg(target_os = "windows")]
{
@ -462,17 +478,3 @@ fn deno_webgpu_get_declaration() -> PathBuf {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
manifest_dir.join("dts").join("lib.deno_webgpu.d.ts")
}
fn get_js_files(d: &str) -> Vec<PathBuf> {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let mut js_files = std::fs::read_dir(d)
.unwrap()
.map(|dir_entry| {
let file = dir_entry.unwrap();
manifest_dir.join(file.path())
})
.filter(|path| path.extension().unwrap_or_default() == "js")
.collect::<Vec<PathBuf>>();
js_files.sort();
js_files
}

57
cli/js.rs Normal file
View file

@ -0,0 +1,57 @@
use deno_core::Snapshot;
use log::debug;
use once_cell::sync::Lazy;
pub static CLI_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
#[allow(clippy::uninit_vec)]
#[cold]
#[inline(never)]
|| {
static COMPRESSED_CLI_SNAPSHOT: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/CLI_SNAPSHOT.bin"));
let size =
u32::from_le_bytes(COMPRESSED_CLI_SNAPSHOT[0..4].try_into().unwrap())
as usize;
let mut vec = Vec::with_capacity(size);
// SAFETY: vec is allocated with exact snapshot size (+ alignment)
// SAFETY: non zeroed bytes are overwritten with decompressed snapshot
unsafe {
vec.set_len(size);
}
lzzzz::lz4::decompress(&COMPRESSED_CLI_SNAPSHOT[4..], &mut vec).unwrap();
vec.into_boxed_slice()
},
);
pub fn deno_isolate_init() -> Snapshot {
debug!("Deno isolate init with snapshots.");
Snapshot::Static(&CLI_SNAPSHOT)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn runtime_snapshot() {
let mut js_runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
startup_snapshot: Some(deno_isolate_init()),
..Default::default()
});
js_runtime
.execute_script(
"<anon>",
r#"
if (!(bootstrap.mainRuntime && bootstrap.workerRuntime)) {
throw Error("bad");
}
console.log("we have console.log!!!");
"#,
)
.unwrap();
}
}

View file

@ -1397,12 +1397,16 @@
return testFn;
}
window.__bootstrap.testing = {
bench,
enableBench,
enableTest,
runBenchmarks,
window.__bootstrap.internals = {
...window.__bootstrap.internals ?? {},
testing: {
runTests,
test,
runBenchmarks,
enableTest,
enableBench,
},
};
window.__bootstrap.denoNs.bench = bench;
window.__bootstrap.denoNs.test = test;
})(this);

View file

@ -7,7 +7,6 @@ use super::lsp_custom;
use crate::args::flags_from_vec;
use crate::args::DenoSubcommand;
use crate::checksum;
use crate::create_main_worker;
use crate::lsp::client::Client;
use crate::lsp::client::TestingNotification;
use crate::lsp::config;
@ -16,6 +15,7 @@ use crate::ops;
use crate::proc_state;
use crate::tools::test;
use crate::tools::test::TestEventSender;
use crate::worker::create_main_worker_for_test_or_bench;
use deno_core::anyhow::anyhow;
use deno_core::error::AnyError;
@ -154,7 +154,7 @@ async fn test_specifier(
filter: test::TestFilter,
) -> Result<(), AnyError> {
if !token.is_cancelled() {
let mut worker = create_main_worker(
let mut worker = create_main_worker_for_test_or_bench(
&ps,
specifier.clone(),
permissions,

View file

@ -18,6 +18,7 @@ mod fs_util;
mod graph_util;
mod http_cache;
mod http_util;
mod js;
mod lockfile;
mod logger;
mod lsp;
@ -289,14 +290,8 @@ async fn eval_command(
resolve_url_or_path(&format!("./$deno$eval.{}", eval_flags.ext))?;
let permissions = Permissions::from_options(&flags.permissions_options())?;
let ps = ProcState::build(flags).await?;
let mut worker = create_main_worker(
&ps,
main_module.clone(),
permissions,
vec![],
Default::default(),
)
.await?;
let mut worker =
create_main_worker(&ps, main_module.clone(), permissions).await?;
// Create a dummy source file.
let source_code = if eval_flags.print {
format!("console.log({})", eval_flags.code)
@ -602,8 +597,6 @@ async fn repl_command(
&ps,
main_module.clone(),
Permissions::from_options(&ps.options.permissions_options())?,
vec![],
Default::default(),
)
.await?;
worker.setup_repl().await?;
@ -623,8 +616,6 @@ async fn run_from_stdin(flags: Flags) -> Result<i32, AnyError> {
&ps.clone(),
main_module.clone(),
Permissions::from_options(&ps.options.permissions_options())?,
vec![],
Default::default(),
)
.await?;
@ -664,14 +655,8 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<i32, AnyError> {
let ps =
ProcState::build_for_file_watcher((*flags).clone(), sender.clone())
.await?;
let worker = create_main_worker(
&ps,
main_module.clone(),
permissions,
vec![],
Default::default(),
)
.await?;
let worker =
create_main_worker(&ps, main_module.clone(), permissions).await?;
worker.run_for_watcher().await?;
Ok(())
@ -722,14 +707,8 @@ async fn run_command(
};
let permissions =
Permissions::from_options(&ps.options.permissions_options())?;
let mut worker = create_main_worker(
&ps,
main_module.clone(),
permissions,
vec![],
Default::default(),
)
.await?;
let mut worker =
create_main_worker(&ps, main_module.clone(), permissions).await?;
let exit_code = worker.run().await?;
Ok(exit_code)

View file

@ -287,7 +287,7 @@ pub async fn run(
inspect: ps.options.is_inspecting(),
},
extensions: ops::cli_exts(ps.clone()),
startup_snapshot: None,
startup_snapshot: Some(crate::js::deno_isolate_init()),
unsafely_ignore_certificate_errors: metadata
.unsafely_ignore_certificate_errors,
root_cert_store: Some(root_cert_store),

View file

@ -37,13 +37,13 @@ failing step in failing test ... FAILED ([WILDCARD])
nested failure => ./test/steps/failing_steps.ts:[WILDCARD]
error: Error: 1 test step failed.
at runTest (deno:runtime/js/40_testing.js:[WILDCARD])
at async runTests (deno:runtime/js/40_testing.js:[WILDCARD])
at runTest (deno:cli/js/40_testing.js:[WILDCARD])
at async runTests (deno:cli/js/40_testing.js:[WILDCARD])
multiple test step failures => ./test/steps/failing_steps.ts:[WILDCARD]
error: Error: 2 test steps failed.
at runTest (deno:runtime/js/40_testing.js:[WILDCARD])
at async runTests (deno:runtime/js/40_testing.js:[WILDCARD])
at runTest (deno:cli/js/40_testing.js:[WILDCARD])
at async runTests (deno:cli/js/40_testing.js:[WILDCARD])
failing step in failing test => ./test/steps/failing_steps.ts:[WILDCARD]
error: Error: Fail test.

View file

@ -4,7 +4,6 @@ use crate::args::BenchFlags;
use crate::args::Flags;
use crate::args::TypeCheckMode;
use crate::colors;
use crate::create_main_worker;
use crate::file_watcher;
use crate::file_watcher::ResolutionResult;
use crate::fs_util::collect_specifiers;
@ -15,6 +14,7 @@ use crate::ops;
use crate::proc_state::ProcState;
use crate::tools::test::format_test_error;
use crate::tools::test::TestFilter;
use crate::worker::create_main_worker_for_test_or_bench;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
@ -352,7 +352,7 @@ async fn bench_specifier(
options: BenchSpecifierOptions,
) -> Result<(), AnyError> {
let filter = TestFilter::from_flag(&options.filter);
let mut worker = create_main_worker(
let mut worker = create_main_worker_for_test_or_bench(
&ps,
specifier.clone(),
permissions,

View file

@ -5,7 +5,6 @@ use crate::args::TestFlags;
use crate::args::TypeCheckMode;
use crate::checksum;
use crate::colors;
use crate::create_main_worker;
use crate::display;
use crate::file_fetcher::File;
use crate::file_watcher;
@ -18,6 +17,7 @@ use crate::graph_util::contains_specifier;
use crate::graph_util::graph_valid;
use crate::ops;
use crate::proc_state::ProcState;
use crate::worker::create_main_worker_for_test_or_bench;
use deno_ast::swc::common::comments::CommentKind;
use deno_ast::MediaType;
@ -715,7 +715,7 @@ async fn test_specifier(
sender: &TestEventSender,
options: TestSpecifierOptions,
) -> Result<(), AnyError> {
let mut worker = create_main_worker(
let mut worker = create_main_worker_for_test_or_bench(
&ps,
specifier.clone(),
permissions,

View file

@ -7,6 +7,9 @@ use deno_core::error::AnyError;
use deno_core::futures::task::LocalFutureObj;
use deno_core::futures::FutureExt;
use deno_core::located_script_name;
use deno_core::serde_json::json;
use deno_core::serde_v8;
use deno_core::v8;
use deno_core::Extension;
use deno_core::ModuleId;
use deno_runtime::colors;
@ -38,6 +41,11 @@ pub struct CliMainWorker {
is_main_cjs: bool,
worker: MainWorker,
ps: ProcState,
js_run_tests_callback: Option<v8::Global<v8::Function>>,
js_run_benchmarks_callback: Option<v8::Global<v8::Function>>,
js_enable_test_callback: Option<v8::Global<v8::Function>>,
js_enable_bench_callback: Option<v8::Global<v8::Function>>,
}
impl CliMainWorker {
@ -168,7 +176,7 @@ impl CliMainWorker {
&mut self,
mode: TestMode,
) -> Result<(), AnyError> {
self.worker.enable_test();
self.enable_test();
// Enable op call tracing in core to enable better debugging of op sanitizer
// failures.
@ -194,10 +202,7 @@ impl CliMainWorker {
}
self.worker.dispatch_load_event(&located_script_name!())?;
self
.worker
.run_tests(&self.ps.options.shuffle_tests())
.await?;
self.run_tests(&self.ps.options.shuffle_tests()).await?;
loop {
if !self
.worker
@ -223,7 +228,7 @@ impl CliMainWorker {
&mut self,
mode: TestMode,
) -> Result<(), AnyError> {
self.worker.enable_test();
self.enable_test();
self
.worker
@ -239,7 +244,7 @@ impl CliMainWorker {
}
self.worker.dispatch_load_event(&located_script_name!())?;
self.worker.run_tests(&None).await?;
self.run_tests(&None).await?;
loop {
if !self
.worker
@ -254,13 +259,13 @@ impl CliMainWorker {
}
pub async fn run_bench_specifier(&mut self) -> Result<(), AnyError> {
self.worker.enable_bench();
self.enable_bench();
// We execute the module module as a side module so that import.meta.main is not set.
self.execute_side_module_possibly_with_npm().await?;
self.worker.dispatch_load_event(&located_script_name!())?;
self.worker.run_benchmarks().await?;
self.run_benchmarks().await?;
loop {
if !self
.worker
@ -340,14 +345,104 @@ impl CliMainWorker {
Ok(None)
}
}
/// Run tests declared with `Deno.test()`. Test events will be dispatched
/// by calling ops which are currently only implemented in the CLI crate.
pub async fn run_tests(
&mut self,
shuffle: &Option<u64>,
) -> Result<(), AnyError> {
let promise = {
let scope = &mut self.worker.js_runtime.handle_scope();
let cb = self.js_run_tests_callback.as_ref().unwrap().open(scope);
let this = v8::undefined(scope).into();
let options =
serde_v8::to_v8(scope, json!({ "shuffle": shuffle })).unwrap();
let promise = cb.call(scope, this, &[options]).unwrap();
v8::Global::new(scope, promise)
};
self.worker.js_runtime.resolve_value(promise).await?;
Ok(())
}
/// Run benches declared with `Deno.bench()`. Bench events will be dispatched
/// by calling ops which are currently only implemented in the CLI crate.
pub async fn run_benchmarks(&mut self) -> Result<(), AnyError> {
let promise = {
let scope = &mut self.worker.js_runtime.handle_scope();
let cb = self
.js_run_benchmarks_callback
.as_ref()
.unwrap()
.open(scope);
let this = v8::undefined(scope).into();
let promise = cb.call(scope, this, &[]).unwrap();
v8::Global::new(scope, promise)
};
self.worker.js_runtime.resolve_value(promise).await?;
Ok(())
}
/// Enable `Deno.test()`. If this isn't called before executing user code,
/// `Deno.test()` calls will noop.
pub fn enable_test(&mut self) {
let scope = &mut self.worker.js_runtime.handle_scope();
let cb = self.js_enable_test_callback.as_ref().unwrap().open(scope);
let this = v8::undefined(scope).into();
cb.call(scope, this, &[]).unwrap();
}
/// Enable `Deno.bench()`. If this isn't called before executing user code,
/// `Deno.bench()` calls will noop.
pub fn enable_bench(&mut self) {
let scope = &mut self.worker.js_runtime.handle_scope();
let cb = self.js_enable_bench_callback.as_ref().unwrap().open(scope);
let this = v8::undefined(scope).into();
cb.call(scope, this, &[]).unwrap();
}
}
pub async fn create_main_worker(
ps: &ProcState,
main_module: ModuleSpecifier,
permissions: Permissions,
) -> Result<CliMainWorker, AnyError> {
create_main_worker_internal(
ps,
main_module,
permissions,
vec![],
Default::default(),
false,
)
.await
}
pub async fn create_main_worker_for_test_or_bench(
ps: &ProcState,
main_module: ModuleSpecifier,
permissions: Permissions,
custom_extensions: Vec<Extension>,
stdio: deno_runtime::ops::io::Stdio,
) -> Result<CliMainWorker, AnyError> {
create_main_worker_internal(
ps,
main_module,
permissions,
custom_extensions,
stdio,
true,
)
.await
}
async fn create_main_worker_internal(
ps: &ProcState,
main_module: ModuleSpecifier,
permissions: Permissions,
mut custom_extensions: Vec<Extension>,
stdio: deno_runtime::ops::io::Stdio,
bench_or_test: bool,
) -> Result<CliMainWorker, AnyError> {
let (main_module, is_main_cjs) = if let Ok(package_ref) =
NpmPackageReference::from_specifier(&main_module)
@ -426,7 +521,7 @@ pub async fn create_main_worker(
inspect: ps.options.is_inspecting(),
},
extensions,
startup_snapshot: None,
startup_snapshot: Some(crate::js::deno_isolate_init()),
unsafely_ignore_certificate_errors: ps
.options
.unsafely_ignore_certificate_errors()
@ -452,16 +547,59 @@ pub async fn create_main_worker(
stdio,
};
let worker = MainWorker::bootstrap_from_options(
let mut worker = MainWorker::bootstrap_from_options(
main_module.clone(),
permissions,
options,
);
let (
js_run_tests_callback,
js_run_benchmarks_callback,
js_enable_test_callback,
js_enable_bench_callback,
) = if bench_or_test {
let scope = &mut worker.js_runtime.handle_scope();
let js_run_tests_callback = deno_core::JsRuntime::eval::<v8::Function>(
scope,
"Deno[Deno.internal].testing.runTests",
)
.unwrap();
let js_run_benchmarks_callback =
deno_core::JsRuntime::eval::<v8::Function>(
scope,
"Deno[Deno.internal].testing.runBenchmarks",
)
.unwrap();
let js_enable_tests_callback = deno_core::JsRuntime::eval::<v8::Function>(
scope,
"Deno[Deno.internal].testing.enableTest",
)
.unwrap();
let js_enable_bench_callback = deno_core::JsRuntime::eval::<v8::Function>(
scope,
"Deno[Deno.internal].testing.enableBench",
)
.unwrap();
(
Some(v8::Global::new(scope, js_run_tests_callback)),
Some(v8::Global::new(scope, js_run_benchmarks_callback)),
Some(v8::Global::new(scope, js_enable_tests_callback)),
Some(v8::Global::new(scope, js_enable_bench_callback)),
)
} else {
(None, None, None, None)
};
Ok(CliMainWorker {
main_module,
is_main_cjs,
worker,
ps: ps.clone(),
js_run_tests_callback,
js_run_benchmarks_callback,
js_enable_test_callback,
js_enable_bench_callback,
})
}
@ -544,6 +682,7 @@ fn create_web_worker_callback(
inspect: ps.options.is_inspecting(),
},
extensions,
startup_snapshot: Some(crate::js::deno_isolate_init()),
unsafely_ignore_certificate_errors: ps
.options
.unsafely_ignore_certificate_errors()
@ -577,3 +716,109 @@ fn create_web_worker_callback(
)
})
}
#[cfg(test)]
mod tests {
use super::*;
use deno_core::{resolve_url_or_path, FsModuleLoader};
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
use deno_runtime::deno_web::BlobStore;
fn create_test_worker() -> MainWorker {
let main_module = resolve_url_or_path("./hello.js").unwrap();
let permissions = Permissions::default();
let options = WorkerOptions {
bootstrap: BootstrapOptions {
args: vec![],
cpu_count: 1,
debug_flag: false,
enable_testing_features: false,
locale: deno_core::v8::icu::get_language_tag(),
location: None,
no_color: true,
is_tty: false,
runtime_version: "x".to_string(),
ts_version: "x".to_string(),
unstable: false,
user_agent: "x".to_string(),
inspect: false,
},
extensions: vec![],
startup_snapshot: Some(crate::js::deno_isolate_init()),
unsafely_ignore_certificate_errors: None,
root_cert_store: None,
seed: None,
format_js_error_fn: None,
source_map_getter: None,
web_worker_preload_module_cb: Arc::new(|_| unreachable!()),
web_worker_pre_execute_module_cb: Arc::new(|_| unreachable!()),
create_web_worker_cb: Arc::new(|_| unreachable!()),
maybe_inspector_server: None,
should_break_on_first_statement: false,
module_loader: Rc::new(FsModuleLoader),
npm_resolver: None,
get_error_class_fn: None,
cache_storage_dir: None,
origin_storage_dir: None,
blob_store: BlobStore::default(),
broadcast_channel: InMemoryBroadcastChannel::default(),
shared_array_buffer_store: None,
compiled_wasm_module_store: None,
stdio: Default::default(),
};
MainWorker::bootstrap_from_options(main_module, permissions, options)
}
#[tokio::test]
async fn execute_mod_esm_imports_a() {
let p = test_util::testdata_path().join("runtime/esm_imports_a.js");
let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
let mut worker = create_test_worker();
let result = worker.execute_main_module(&module_specifier).await;
if let Err(err) = result {
eprintln!("execute_mod err {:?}", err);
}
if let Err(e) = worker.run_event_loop(false).await {
panic!("Future got unexpected error: {:?}", e);
}
}
#[tokio::test]
async fn execute_mod_circular() {
let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.join("tests/circular1.js");
let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
let mut worker = create_test_worker();
let result = worker.execute_main_module(&module_specifier).await;
if let Err(err) = result {
eprintln!("execute_mod err {:?}", err);
}
if let Err(e) = worker.run_event_loop(false).await {
panic!("Future got unexpected error: {:?}", e);
}
}
#[tokio::test]
async fn execute_mod_resolve_error() {
// "foo" is not a valid module specifier so this should return an error.
let mut worker = create_test_worker();
let module_specifier = resolve_url_or_path("does-not-exist").unwrap();
let result = worker.execute_main_module(&module_specifier).await;
assert!(result.is_err());
}
#[tokio::test]
async fn execute_mod_002_hello() {
// This assumes cwd is project root (an assumption made throughout the
// tests).
let mut worker = create_test_worker();
let p = test_util::testdata_path().join("run/001_hello.js");
let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
let result = worker.execute_main_module(&module_specifier).await;
assert!(result.is_ok());
}
}

View file

@ -18,6 +18,7 @@ mod ops_builtin_v8;
mod ops_metrics;
mod resources;
mod runtime;
pub mod snapshot_util;
mod source_map;
// Re-exports

95
core/snapshot_util.rs Normal file
View file

@ -0,0 +1,95 @@
use crate::Extension;
use crate::JsRuntime;
use crate::RuntimeOptions;
use crate::Snapshot;
use std::path::Path;
use std::path::PathBuf;
pub type CompressionCb = dyn Fn(&mut Vec<u8>, &[u8]);
pub struct CreateSnapshotOptions {
pub cargo_manifest_dir: &'static str,
pub snapshot_path: PathBuf,
pub startup_snapshot: Option<Snapshot>,
pub extensions: Vec<Extension>,
pub additional_files: Vec<PathBuf>,
pub compression_cb: Option<Box<CompressionCb>>,
}
pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) {
let mut js_runtime = JsRuntime::new(RuntimeOptions {
will_snapshot: true,
startup_snapshot: create_snapshot_options.startup_snapshot,
extensions: create_snapshot_options.extensions,
..Default::default()
});
// TODO(nayeemrmn): https://github.com/rust-lang/cargo/issues/3946 to get the
// workspace root.
let display_root = Path::new(create_snapshot_options.cargo_manifest_dir)
.parent()
.unwrap();
for file in create_snapshot_options.additional_files {
let display_path = file.strip_prefix(display_root).unwrap_or(&file);
let display_path_str = display_path.display().to_string();
js_runtime
.execute_script(
&("deno:".to_string() + &display_path_str.replace('\\', "/")),
&std::fs::read_to_string(&file).unwrap(),
)
.unwrap();
}
let snapshot = js_runtime.snapshot();
let snapshot_slice: &[u8] = &snapshot;
println!("Snapshot size: {}", snapshot_slice.len());
let maybe_compressed_snapshot: Box<dyn AsRef<[u8]>> =
if let Some(compression_cb) = create_snapshot_options.compression_cb {
let mut vec = vec![];
vec.extend_from_slice(
&u32::try_from(snapshot.len())
.expect("snapshot larger than 4gb")
.to_le_bytes(),
);
(compression_cb)(&mut vec, snapshot_slice);
println!("Snapshot compressed size: {}", vec.len());
Box::new(vec)
} else {
Box::new(snapshot_slice)
};
std::fs::write(
&create_snapshot_options.snapshot_path,
&*maybe_compressed_snapshot,
)
.unwrap();
println!(
"Snapshot written to: {} ",
create_snapshot_options.snapshot_path.display()
);
}
pub fn get_js_files(
cargo_manifest_dir: &'static str,
directory: &str,
) -> Vec<PathBuf> {
let manifest_dir = Path::new(cargo_manifest_dir);
let mut js_files = std::fs::read_dir(directory)
.unwrap()
.map(|dir_entry| {
let file = dir_entry.unwrap();
manifest_dir.join(file.path())
})
.filter(|path| {
path.extension().unwrap_or_default() == "js"
&& !path.ends_with("99_main.js")
})
.collect::<Vec<PathBuf>>();
js_files.sort();
js_files
}

View file

@ -9,63 +9,8 @@ use std::path::PathBuf;
mod not_docs {
use super::*;
use deno_cache::SqliteBackedCache;
use deno_core::snapshot_util::*;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::RuntimeOptions;
// TODO(bartlomieju): this module contains a lot of duplicated
// logic with `cli/build.rs`, factor out to `deno_core`.
fn create_snapshot(
mut js_runtime: JsRuntime,
snapshot_path: &Path,
files: Vec<PathBuf>,
) {
// TODO(nayeemrmn): https://github.com/rust-lang/cargo/issues/3946 to get the
// workspace root.
let display_root = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap();
for file in files {
println!("cargo:rerun-if-changed={}", file.display());
let display_path = file.strip_prefix(display_root).unwrap();
let display_path_str = display_path.display().to_string();
js_runtime
.execute_script(
&("deno:".to_string() + &display_path_str.replace('\\', "/")),
&std::fs::read_to_string(&file).unwrap(),
)
.unwrap();
}
let snapshot = js_runtime.snapshot();
let snapshot_slice: &[u8] = &snapshot;
println!("Snapshot size: {}", snapshot_slice.len());
let compressed_snapshot_with_size = {
let mut vec = vec![];
vec.extend_from_slice(
&u32::try_from(snapshot.len())
.expect("snapshot larger than 4gb")
.to_le_bytes(),
);
lzzzz::lz4_hc::compress_to_vec(
snapshot_slice,
&mut vec,
lzzzz::lz4_hc::CLEVEL_MAX,
)
.expect("snapshot compression failed");
vec
};
println!(
"Snapshot compressed size: {}",
compressed_snapshot_with_size.len()
);
std::fs::write(snapshot_path, compressed_snapshot_with_size).unwrap();
println!("Snapshot written to: {} ", snapshot_path.display());
}
struct Permissions;
@ -174,7 +119,7 @@ mod not_docs {
}
}
fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<PathBuf>) {
fn create_runtime_snapshot(snapshot_path: PathBuf, files: Vec<PathBuf>) {
let extensions: Vec<Extension> = vec![
deno_webidl::init(),
deno_console::init(),
@ -205,31 +150,26 @@ mod not_docs {
deno_flash::init::<Permissions>(false), // No --unstable
];
let js_runtime = JsRuntime::new(RuntimeOptions {
will_snapshot: true,
create_snapshot(CreateSnapshotOptions {
cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
snapshot_path,
startup_snapshot: None,
extensions,
..Default::default()
additional_files: files,
compression_cb: Some(Box::new(|vec, snapshot_slice| {
lzzzz::lz4_hc::compress_to_vec(
snapshot_slice,
vec,
lzzzz::lz4_hc::CLEVEL_MAX,
)
.expect("snapshot compression failed");
})),
});
create_snapshot(js_runtime, snapshot_path, files);
}
fn get_js_files(d: &str) -> Vec<PathBuf> {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let mut js_files = std::fs::read_dir(d)
.unwrap()
.map(|dir_entry| {
let file = dir_entry.unwrap();
manifest_dir.join(file.path())
})
.filter(|path| path.extension().unwrap_or_default() == "js")
.collect::<Vec<PathBuf>>();
js_files.sort();
js_files
}
pub fn build_snapshot(runtime_snapshot_path: PathBuf) {
let js_files = get_js_files("js");
create_runtime_snapshot(&runtime_snapshot_path, js_files);
let js_files = get_js_files(env!("CARGO_MANIFEST_DIR"), "js");
create_runtime_snapshot(runtime_snapshot_path, js_files);
}
}
@ -242,7 +182,7 @@ fn main() {
let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
// Main snapshot
let runtime_snapshot_path = o.join("CLI_SNAPSHOT.bin");
let runtime_snapshot_path = o.join("RUNTIME_SNAPSHOT.bin");
// If we're building on docs.rs we just create
// and empty snapshot file and return, because `rusty_v8`

View file

@ -2,17 +2,18 @@
use deno_core::Snapshot;
use log::debug;
use once_cell::sync::Lazy;
use std::path::PathBuf;
pub static CLI_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
pub static RUNTIME_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
#[allow(clippy::uninit_vec)]
#[cold]
#[inline(never)]
|| {
static COMPRESSED_CLI_SNAPSHOT: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/CLI_SNAPSHOT.bin"));
static COMPRESSED_RUNTIME_SNAPSHOT: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/RUNTIME_SNAPSHOT.bin"));
let size =
u32::from_le_bytes(COMPRESSED_CLI_SNAPSHOT[0..4].try_into().unwrap())
u32::from_le_bytes(COMPRESSED_RUNTIME_SNAPSHOT[0..4].try_into().unwrap())
as usize;
let mut vec = Vec::with_capacity(size);
@ -22,7 +23,8 @@ pub static CLI_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
vec.set_len(size);
}
lzzzz::lz4::decompress(&COMPRESSED_CLI_SNAPSHOT[4..], &mut vec).unwrap();
lzzzz::lz4::decompress(&COMPRESSED_RUNTIME_SNAPSHOT[4..], &mut vec)
.unwrap();
vec.into_boxed_slice()
},
@ -30,29 +32,11 @@ pub static CLI_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
pub fn deno_isolate_init() -> Snapshot {
debug!("Deno isolate init with snapshots.");
Snapshot::Static(&CLI_SNAPSHOT)
Snapshot::Static(&RUNTIME_SNAPSHOT)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cli_snapshot() {
let mut js_runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
startup_snapshot: Some(deno_isolate_init()),
..Default::default()
});
js_runtime
.execute_script(
"<anon>",
r#"
if (!(bootstrap.mainRuntime && bootstrap.workerRuntime)) {
throw Error("bad");
}
console.log("we have console.log!!!");
"#,
)
.unwrap();
}
pub fn get_99_main() -> PathBuf {
let manifest = env!("CARGO_MANIFEST_DIR");
let path = PathBuf::from(manifest);
path.join("js").join("99_main.js")
}

View file

@ -7,8 +7,6 @@
__bootstrap.denoNs = {
metrics: core.metrics,
test: __bootstrap.testing.test,
bench: __bootstrap.testing.bench,
Process: __bootstrap.process.Process,
run: __bootstrap.process.run,
isatty: __bootstrap.tty.isatty,

View file

@ -0,0 +1,352 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
"use strict";
((window) => {
const core = Deno.core;
const {
ObjectDefineProperties,
SymbolFor,
} = window.__bootstrap.primordials;
const util = window.__bootstrap.util;
const location = window.__bootstrap.location;
const event = window.__bootstrap.event;
const eventTarget = window.__bootstrap.eventTarget;
const timers = window.__bootstrap.timers;
const base64 = window.__bootstrap.base64;
const encoding = window.__bootstrap.encoding;
const Console = window.__bootstrap.console.Console;
const caches = window.__bootstrap.caches;
const compression = window.__bootstrap.compression;
const worker = window.__bootstrap.worker;
const performance = window.__bootstrap.performance;
const crypto = window.__bootstrap.crypto;
const url = window.__bootstrap.url;
const urlPattern = window.__bootstrap.urlPattern;
const headers = window.__bootstrap.headers;
const streams = window.__bootstrap.streams;
const fileReader = window.__bootstrap.fileReader;
const webgpu = window.__bootstrap.webgpu;
const webSocket = window.__bootstrap.webSocket;
const broadcastChannel = window.__bootstrap.broadcastChannel;
const file = window.__bootstrap.file;
const formData = window.__bootstrap.formData;
const fetch = window.__bootstrap.fetch;
const messagePort = window.__bootstrap.messagePort;
const webidl = window.__bootstrap.webidl;
const domException = window.__bootstrap.domException;
const abortSignal = window.__bootstrap.abortSignal;
const globalInterfaces = window.__bootstrap.globalInterfaces;
const webStorage = window.__bootstrap.webStorage;
const prompt = window.__bootstrap.prompt;
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
const windowOrWorkerGlobalScope = {
AbortController: util.nonEnumerable(abortSignal.AbortController),
AbortSignal: util.nonEnumerable(abortSignal.AbortSignal),
Blob: util.nonEnumerable(file.Blob),
ByteLengthQueuingStrategy: util.nonEnumerable(
streams.ByteLengthQueuingStrategy,
),
CloseEvent: util.nonEnumerable(event.CloseEvent),
CompressionStream: util.nonEnumerable(compression.CompressionStream),
CountQueuingStrategy: util.nonEnumerable(
streams.CountQueuingStrategy,
),
CryptoKey: util.nonEnumerable(crypto.CryptoKey),
CustomEvent: util.nonEnumerable(event.CustomEvent),
DecompressionStream: util.nonEnumerable(compression.DecompressionStream),
DOMException: util.nonEnumerable(domException.DOMException),
ErrorEvent: util.nonEnumerable(event.ErrorEvent),
Event: util.nonEnumerable(event.Event),
EventTarget: util.nonEnumerable(eventTarget.EventTarget),
File: util.nonEnumerable(file.File),
FileReader: util.nonEnumerable(fileReader.FileReader),
FormData: util.nonEnumerable(formData.FormData),
Headers: util.nonEnumerable(headers.Headers),
MessageEvent: util.nonEnumerable(event.MessageEvent),
Performance: util.nonEnumerable(performance.Performance),
PerformanceEntry: util.nonEnumerable(performance.PerformanceEntry),
PerformanceMark: util.nonEnumerable(performance.PerformanceMark),
PerformanceMeasure: util.nonEnumerable(performance.PerformanceMeasure),
PromiseRejectionEvent: util.nonEnumerable(event.PromiseRejectionEvent),
ProgressEvent: util.nonEnumerable(event.ProgressEvent),
ReadableStream: util.nonEnumerable(streams.ReadableStream),
ReadableStreamDefaultReader: util.nonEnumerable(
streams.ReadableStreamDefaultReader,
),
Request: util.nonEnumerable(fetch.Request),
Response: util.nonEnumerable(fetch.Response),
TextDecoder: util.nonEnumerable(encoding.TextDecoder),
TextEncoder: util.nonEnumerable(encoding.TextEncoder),
TextDecoderStream: util.nonEnumerable(encoding.TextDecoderStream),
TextEncoderStream: util.nonEnumerable(encoding.TextEncoderStream),
TransformStream: util.nonEnumerable(streams.TransformStream),
URL: util.nonEnumerable(url.URL),
URLPattern: util.nonEnumerable(urlPattern.URLPattern),
URLSearchParams: util.nonEnumerable(url.URLSearchParams),
WebSocket: util.nonEnumerable(webSocket.WebSocket),
MessageChannel: util.nonEnumerable(messagePort.MessageChannel),
MessagePort: util.nonEnumerable(messagePort.MessagePort),
Worker: util.nonEnumerable(worker.Worker),
WritableStream: util.nonEnumerable(streams.WritableStream),
WritableStreamDefaultWriter: util.nonEnumerable(
streams.WritableStreamDefaultWriter,
),
WritableStreamDefaultController: util.nonEnumerable(
streams.WritableStreamDefaultController,
),
ReadableByteStreamController: util.nonEnumerable(
streams.ReadableByteStreamController,
),
ReadableStreamBYOBReader: util.nonEnumerable(
streams.ReadableStreamBYOBReader,
),
ReadableStreamBYOBRequest: util.nonEnumerable(
streams.ReadableStreamBYOBRequest,
),
ReadableStreamDefaultController: util.nonEnumerable(
streams.ReadableStreamDefaultController,
),
TransformStreamDefaultController: util.nonEnumerable(
streams.TransformStreamDefaultController,
),
atob: util.writable(base64.atob),
btoa: util.writable(base64.btoa),
clearInterval: util.writable(timers.clearInterval),
clearTimeout: util.writable(timers.clearTimeout),
caches: {
enumerable: true,
configurable: true,
get: caches.cacheStorage,
},
CacheStorage: util.nonEnumerable(caches.CacheStorage),
Cache: util.nonEnumerable(caches.Cache),
console: util.nonEnumerable(
new Console((msg, level) => core.print(msg, level > 1)),
),
crypto: util.readOnly(crypto.crypto),
Crypto: util.nonEnumerable(crypto.Crypto),
SubtleCrypto: util.nonEnumerable(crypto.SubtleCrypto),
fetch: util.writable(fetch.fetch),
performance: util.writable(performance.performance),
reportError: util.writable(event.reportError),
setInterval: util.writable(timers.setInterval),
setTimeout: util.writable(timers.setTimeout),
structuredClone: util.writable(messagePort.structuredClone),
// Branding as a WebIDL object
[webidl.brand]: util.nonEnumerable(webidl.brand),
};
const unstableWindowOrWorkerGlobalScope = {
BroadcastChannel: util.nonEnumerable(broadcastChannel.BroadcastChannel),
WebSocketStream: util.nonEnumerable(webSocket.WebSocketStream),
GPU: util.nonEnumerable(webgpu.GPU),
GPUAdapter: util.nonEnumerable(webgpu.GPUAdapter),
GPUSupportedLimits: util.nonEnumerable(webgpu.GPUSupportedLimits),
GPUSupportedFeatures: util.nonEnumerable(webgpu.GPUSupportedFeatures),
GPUDevice: util.nonEnumerable(webgpu.GPUDevice),
GPUQueue: util.nonEnumerable(webgpu.GPUQueue),
GPUBuffer: util.nonEnumerable(webgpu.GPUBuffer),
GPUBufferUsage: util.nonEnumerable(webgpu.GPUBufferUsage),
GPUMapMode: util.nonEnumerable(webgpu.GPUMapMode),
GPUTexture: util.nonEnumerable(webgpu.GPUTexture),
GPUTextureUsage: util.nonEnumerable(webgpu.GPUTextureUsage),
GPUTextureView: util.nonEnumerable(webgpu.GPUTextureView),
GPUSampler: util.nonEnumerable(webgpu.GPUSampler),
GPUBindGroupLayout: util.nonEnumerable(webgpu.GPUBindGroupLayout),
GPUPipelineLayout: util.nonEnumerable(webgpu.GPUPipelineLayout),
GPUBindGroup: util.nonEnumerable(webgpu.GPUBindGroup),
GPUShaderModule: util.nonEnumerable(webgpu.GPUShaderModule),
GPUShaderStage: util.nonEnumerable(webgpu.GPUShaderStage),
GPUComputePipeline: util.nonEnumerable(webgpu.GPUComputePipeline),
GPURenderPipeline: util.nonEnumerable(webgpu.GPURenderPipeline),
GPUColorWrite: util.nonEnumerable(webgpu.GPUColorWrite),
GPUCommandEncoder: util.nonEnumerable(webgpu.GPUCommandEncoder),
GPURenderPassEncoder: util.nonEnumerable(webgpu.GPURenderPassEncoder),
GPUComputePassEncoder: util.nonEnumerable(webgpu.GPUComputePassEncoder),
GPUCommandBuffer: util.nonEnumerable(webgpu.GPUCommandBuffer),
GPURenderBundleEncoder: util.nonEnumerable(webgpu.GPURenderBundleEncoder),
GPURenderBundle: util.nonEnumerable(webgpu.GPURenderBundle),
GPUQuerySet: util.nonEnumerable(webgpu.GPUQuerySet),
GPUOutOfMemoryError: util.nonEnumerable(webgpu.GPUOutOfMemoryError),
GPUValidationError: util.nonEnumerable(webgpu.GPUValidationError),
};
class Navigator {
constructor() {
webidl.illegalConstructor();
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${inspect({})}`;
}
}
const navigator = webidl.createBranded(Navigator);
let numCpus, userAgent, language;
function setNumCpus(val) {
numCpus = val;
}
function setUserAgent(val) {
userAgent = val;
}
function setLanguage(val) {
language = val;
}
ObjectDefineProperties(Navigator.prototype, {
gpu: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return webgpu.gpu;
},
},
hardwareConcurrency: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return numCpus;
},
},
userAgent: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return userAgent;
},
},
language: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return language;
},
},
languages: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return [language];
},
},
});
const NavigatorPrototype = Navigator.prototype;
class WorkerNavigator {
constructor() {
webidl.illegalConstructor();
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${inspect({})}`;
}
}
const workerNavigator = webidl.createBranded(WorkerNavigator);
ObjectDefineProperties(WorkerNavigator.prototype, {
gpu: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, WorkerNavigatorPrototype);
return webgpu.gpu;
},
},
hardwareConcurrency: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, WorkerNavigatorPrototype);
return numCpus;
},
language: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, WorkerNavigatorPrototype);
return language;
},
},
languages: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, WorkerNavigatorPrototype);
return [language];
},
},
},
});
const WorkerNavigatorPrototype = WorkerNavigator.prototype;
const mainRuntimeGlobalProperties = {
Location: location.locationConstructorDescriptor,
location: location.locationDescriptor,
Window: globalInterfaces.windowConstructorDescriptor,
window: util.readOnly(globalThis),
self: util.writable(globalThis),
Navigator: util.nonEnumerable(Navigator),
navigator: {
configurable: true,
enumerable: true,
get: () => navigator,
},
alert: util.writable(prompt.alert),
confirm: util.writable(prompt.confirm),
prompt: util.writable(prompt.prompt),
localStorage: {
configurable: true,
enumerable: true,
get: webStorage.localStorage,
// Makes this reassignable to make astro work
set: () => {},
},
sessionStorage: {
configurable: true,
enumerable: true,
get: webStorage.sessionStorage,
// Makes this reassignable to make astro work
set: () => {},
},
Storage: util.nonEnumerable(webStorage.Storage),
};
const workerRuntimeGlobalProperties = {
WorkerLocation: location.workerLocationConstructorDescriptor,
location: location.workerLocationDescriptor,
WorkerGlobalScope: globalInterfaces.workerGlobalScopeConstructorDescriptor,
DedicatedWorkerGlobalScope:
globalInterfaces.dedicatedWorkerGlobalScopeConstructorDescriptor,
WorkerNavigator: util.nonEnumerable(WorkerNavigator),
navigator: {
configurable: true,
enumerable: true,
get: () => workerNavigator,
},
self: util.readOnly(globalThis),
};
window.__bootstrap.globalScope = {
windowOrWorkerGlobalScope,
unstableWindowOrWorkerGlobalScope,
mainRuntimeGlobalProperties,
workerRuntimeGlobalProperties,
setNumCpus,
setUserAgent,
setLanguage,
};
})(this);

View file

@ -41,48 +41,37 @@ delete Intl.v8BreakIterator;
const util = window.__bootstrap.util;
const event = window.__bootstrap.event;
const eventTarget = window.__bootstrap.eventTarget;
const globalInterfaces = window.__bootstrap.globalInterfaces;
const location = window.__bootstrap.location;
const build = window.__bootstrap.build;
const version = window.__bootstrap.version;
const os = window.__bootstrap.os;
const timers = window.__bootstrap.timers;
const base64 = window.__bootstrap.base64;
const encoding = window.__bootstrap.encoding;
const colors = window.__bootstrap.colors;
const Console = window.__bootstrap.console.Console;
const caches = window.__bootstrap.caches;
const inspectArgs = window.__bootstrap.console.inspectArgs;
const quoteString = window.__bootstrap.console.quoteString;
const compression = window.__bootstrap.compression;
const worker = window.__bootstrap.worker;
const internals = window.__bootstrap.internals;
const performance = window.__bootstrap.performance;
const net = window.__bootstrap.net;
const crypto = window.__bootstrap.crypto;
const url = window.__bootstrap.url;
const urlPattern = window.__bootstrap.urlPattern;
const headers = window.__bootstrap.headers;
const streams = window.__bootstrap.streams;
const fileReader = window.__bootstrap.fileReader;
const webgpu = window.__bootstrap.webgpu;
const webSocket = window.__bootstrap.webSocket;
const webStorage = window.__bootstrap.webStorage;
const broadcastChannel = window.__bootstrap.broadcastChannel;
const file = window.__bootstrap.file;
const formData = window.__bootstrap.formData;
const fetch = window.__bootstrap.fetch;
const prompt = window.__bootstrap.prompt;
const messagePort = window.__bootstrap.messagePort;
const denoNs = window.__bootstrap.denoNs;
const denoNsUnstable = window.__bootstrap.denoNsUnstable;
const errors = window.__bootstrap.errors.errors;
const webidl = window.__bootstrap.webidl;
const domException = window.__bootstrap.domException;
const abortSignal = window.__bootstrap.abortSignal;
const { defineEventHandler, reportException } = window.__bootstrap.event;
const { deserializeJsMessageData, serializeJsMessageData } =
window.__bootstrap.messagePort;
const {
windowOrWorkerGlobalScope,
unstableWindowOrWorkerGlobalScope,
workerRuntimeGlobalProperties,
mainRuntimeGlobalProperties,
setNumCpus,
setUserAgent,
setLanguage,
} = window.__bootstrap.globalScope;
let windowIsClosing = false;
@ -326,298 +315,6 @@ delete Intl.v8BreakIterator;
);
}
class Navigator {
constructor() {
webidl.illegalConstructor();
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${inspect({})}`;
}
}
const navigator = webidl.createBranded(Navigator);
let numCpus, userAgent, language;
ObjectDefineProperties(Navigator.prototype, {
gpu: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return webgpu.gpu;
},
},
hardwareConcurrency: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return numCpus;
},
},
userAgent: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return userAgent;
},
},
language: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return language;
},
},
languages: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, NavigatorPrototype);
return [language];
},
},
});
const NavigatorPrototype = Navigator.prototype;
class WorkerNavigator {
constructor() {
webidl.illegalConstructor();
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${inspect({})}`;
}
}
const workerNavigator = webidl.createBranded(WorkerNavigator);
ObjectDefineProperties(WorkerNavigator.prototype, {
gpu: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, WorkerNavigatorPrototype);
return webgpu.gpu;
},
},
hardwareConcurrency: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, WorkerNavigatorPrototype);
return numCpus;
},
language: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, WorkerNavigatorPrototype);
return language;
},
},
languages: {
configurable: true,
enumerable: true,
get() {
webidl.assertBranded(this, WorkerNavigatorPrototype);
return [language];
},
},
},
});
const WorkerNavigatorPrototype = WorkerNavigator.prototype;
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
const windowOrWorkerGlobalScope = {
AbortController: util.nonEnumerable(abortSignal.AbortController),
AbortSignal: util.nonEnumerable(abortSignal.AbortSignal),
Blob: util.nonEnumerable(file.Blob),
ByteLengthQueuingStrategy: util.nonEnumerable(
streams.ByteLengthQueuingStrategy,
),
CloseEvent: util.nonEnumerable(event.CloseEvent),
CompressionStream: util.nonEnumerable(compression.CompressionStream),
CountQueuingStrategy: util.nonEnumerable(
streams.CountQueuingStrategy,
),
CryptoKey: util.nonEnumerable(crypto.CryptoKey),
CustomEvent: util.nonEnumerable(event.CustomEvent),
DecompressionStream: util.nonEnumerable(compression.DecompressionStream),
DOMException: util.nonEnumerable(domException.DOMException),
ErrorEvent: util.nonEnumerable(event.ErrorEvent),
Event: util.nonEnumerable(event.Event),
EventTarget: util.nonEnumerable(eventTarget.EventTarget),
File: util.nonEnumerable(file.File),
FileReader: util.nonEnumerable(fileReader.FileReader),
FormData: util.nonEnumerable(formData.FormData),
Headers: util.nonEnumerable(headers.Headers),
MessageEvent: util.nonEnumerable(event.MessageEvent),
Performance: util.nonEnumerable(performance.Performance),
PerformanceEntry: util.nonEnumerable(performance.PerformanceEntry),
PerformanceMark: util.nonEnumerable(performance.PerformanceMark),
PerformanceMeasure: util.nonEnumerable(performance.PerformanceMeasure),
PromiseRejectionEvent: util.nonEnumerable(event.PromiseRejectionEvent),
ProgressEvent: util.nonEnumerable(event.ProgressEvent),
ReadableStream: util.nonEnumerable(streams.ReadableStream),
ReadableStreamDefaultReader: util.nonEnumerable(
streams.ReadableStreamDefaultReader,
),
Request: util.nonEnumerable(fetch.Request),
Response: util.nonEnumerable(fetch.Response),
TextDecoder: util.nonEnumerable(encoding.TextDecoder),
TextEncoder: util.nonEnumerable(encoding.TextEncoder),
TextDecoderStream: util.nonEnumerable(encoding.TextDecoderStream),
TextEncoderStream: util.nonEnumerable(encoding.TextEncoderStream),
TransformStream: util.nonEnumerable(streams.TransformStream),
URL: util.nonEnumerable(url.URL),
URLPattern: util.nonEnumerable(urlPattern.URLPattern),
URLSearchParams: util.nonEnumerable(url.URLSearchParams),
WebSocket: util.nonEnumerable(webSocket.WebSocket),
MessageChannel: util.nonEnumerable(messagePort.MessageChannel),
MessagePort: util.nonEnumerable(messagePort.MessagePort),
Worker: util.nonEnumerable(worker.Worker),
WritableStream: util.nonEnumerable(streams.WritableStream),
WritableStreamDefaultWriter: util.nonEnumerable(
streams.WritableStreamDefaultWriter,
),
WritableStreamDefaultController: util.nonEnumerable(
streams.WritableStreamDefaultController,
),
ReadableByteStreamController: util.nonEnumerable(
streams.ReadableByteStreamController,
),
ReadableStreamBYOBReader: util.nonEnumerable(
streams.ReadableStreamBYOBReader,
),
ReadableStreamBYOBRequest: util.nonEnumerable(
streams.ReadableStreamBYOBRequest,
),
ReadableStreamDefaultController: util.nonEnumerable(
streams.ReadableStreamDefaultController,
),
TransformStreamDefaultController: util.nonEnumerable(
streams.TransformStreamDefaultController,
),
atob: util.writable(base64.atob),
btoa: util.writable(base64.btoa),
clearInterval: util.writable(timers.clearInterval),
clearTimeout: util.writable(timers.clearTimeout),
caches: {
enumerable: true,
configurable: true,
get: caches.cacheStorage,
},
CacheStorage: util.nonEnumerable(caches.CacheStorage),
Cache: util.nonEnumerable(caches.Cache),
console: util.nonEnumerable(
new Console((msg, level) => core.print(msg, level > 1)),
),
crypto: util.readOnly(crypto.crypto),
Crypto: util.nonEnumerable(crypto.Crypto),
SubtleCrypto: util.nonEnumerable(crypto.SubtleCrypto),
fetch: util.writable(fetch.fetch),
performance: util.writable(performance.performance),
reportError: util.writable(event.reportError),
setInterval: util.writable(timers.setInterval),
setTimeout: util.writable(timers.setTimeout),
structuredClone: util.writable(messagePort.structuredClone),
// Branding as a WebIDL object
[webidl.brand]: util.nonEnumerable(webidl.brand),
};
const unstableWindowOrWorkerGlobalScope = {
BroadcastChannel: util.nonEnumerable(broadcastChannel.BroadcastChannel),
WebSocketStream: util.nonEnumerable(webSocket.WebSocketStream),
GPU: util.nonEnumerable(webgpu.GPU),
GPUAdapter: util.nonEnumerable(webgpu.GPUAdapter),
GPUSupportedLimits: util.nonEnumerable(webgpu.GPUSupportedLimits),
GPUSupportedFeatures: util.nonEnumerable(webgpu.GPUSupportedFeatures),
GPUDevice: util.nonEnumerable(webgpu.GPUDevice),
GPUQueue: util.nonEnumerable(webgpu.GPUQueue),
GPUBuffer: util.nonEnumerable(webgpu.GPUBuffer),
GPUBufferUsage: util.nonEnumerable(webgpu.GPUBufferUsage),
GPUMapMode: util.nonEnumerable(webgpu.GPUMapMode),
GPUTexture: util.nonEnumerable(webgpu.GPUTexture),
GPUTextureUsage: util.nonEnumerable(webgpu.GPUTextureUsage),
GPUTextureView: util.nonEnumerable(webgpu.GPUTextureView),
GPUSampler: util.nonEnumerable(webgpu.GPUSampler),
GPUBindGroupLayout: util.nonEnumerable(webgpu.GPUBindGroupLayout),
GPUPipelineLayout: util.nonEnumerable(webgpu.GPUPipelineLayout),
GPUBindGroup: util.nonEnumerable(webgpu.GPUBindGroup),
GPUShaderModule: util.nonEnumerable(webgpu.GPUShaderModule),
GPUShaderStage: util.nonEnumerable(webgpu.GPUShaderStage),
GPUComputePipeline: util.nonEnumerable(webgpu.GPUComputePipeline),
GPURenderPipeline: util.nonEnumerable(webgpu.GPURenderPipeline),
GPUColorWrite: util.nonEnumerable(webgpu.GPUColorWrite),
GPUCommandEncoder: util.nonEnumerable(webgpu.GPUCommandEncoder),
GPURenderPassEncoder: util.nonEnumerable(webgpu.GPURenderPassEncoder),
GPUComputePassEncoder: util.nonEnumerable(webgpu.GPUComputePassEncoder),
GPUCommandBuffer: util.nonEnumerable(webgpu.GPUCommandBuffer),
GPURenderBundleEncoder: util.nonEnumerable(webgpu.GPURenderBundleEncoder),
GPURenderBundle: util.nonEnumerable(webgpu.GPURenderBundle),
GPUQuerySet: util.nonEnumerable(webgpu.GPUQuerySet),
GPUOutOfMemoryError: util.nonEnumerable(webgpu.GPUOutOfMemoryError),
GPUValidationError: util.nonEnumerable(webgpu.GPUValidationError),
};
const mainRuntimeGlobalProperties = {
Location: location.locationConstructorDescriptor,
location: location.locationDescriptor,
Window: globalInterfaces.windowConstructorDescriptor,
window: util.readOnly(globalThis),
self: util.writable(globalThis),
Navigator: util.nonEnumerable(Navigator),
navigator: {
configurable: true,
enumerable: true,
get: () => navigator,
},
close: util.writable(windowClose),
closed: util.getterOnly(() => windowIsClosing),
alert: util.writable(prompt.alert),
confirm: util.writable(prompt.confirm),
prompt: util.writable(prompt.prompt),
localStorage: {
configurable: true,
enumerable: true,
get: webStorage.localStorage,
// Makes this reassignable to make astro work
set: () => {},
},
sessionStorage: {
configurable: true,
enumerable: true,
get: webStorage.sessionStorage,
// Makes this reassignable to make astro work
set: () => {},
},
Storage: util.nonEnumerable(webStorage.Storage),
};
const workerRuntimeGlobalProperties = {
WorkerLocation: location.workerLocationConstructorDescriptor,
location: location.workerLocationDescriptor,
WorkerGlobalScope: globalInterfaces.workerGlobalScopeConstructorDescriptor,
DedicatedWorkerGlobalScope:
globalInterfaces.dedicatedWorkerGlobalScopeConstructorDescriptor,
WorkerNavigator: util.nonEnumerable(WorkerNavigator),
navigator: {
configurable: true,
enumerable: true,
get: () => workerNavigator,
},
self: util.readOnly(globalThis),
// TODO(bartlomieju): should be readonly?
close: util.nonEnumerable(workerClose),
postMessage: util.writable(postMessage),
};
const pendingRejections = [];
const pendingRejectionsReasons = new SafeWeakMap();
@ -726,6 +423,10 @@ delete Intl.v8BreakIterator;
ObjectDefineProperties(globalThis, unstableWindowOrWorkerGlobalScope);
}
ObjectDefineProperties(globalThis, mainRuntimeGlobalProperties);
ObjectDefineProperties(globalThis, {
close: util.writable(windowClose),
closed: util.getterOnly(() => windowIsClosing),
});
ObjectSetPrototypeOf(globalThis, Window.prototype);
if (runtimeOptions.inspectFlag) {
@ -754,9 +455,9 @@ delete Intl.v8BreakIterator;
runtimeStart(runtimeOptions);
numCpus = runtimeOptions.cpuCount;
userAgent = runtimeOptions.userAgent;
language = runtimeOptions.locale;
setNumCpus(runtimeOptions.cpuCount);
setUserAgent(runtimeOptions.userAgent);
setLanguage(runtimeOptions.locale);
const internalSymbol = Symbol("Deno.internal");
@ -849,7 +550,12 @@ delete Intl.v8BreakIterator;
ObjectDefineProperties(globalThis, unstableWindowOrWorkerGlobalScope);
}
ObjectDefineProperties(globalThis, workerRuntimeGlobalProperties);
ObjectDefineProperties(globalThis, { name: util.writable(name) });
ObjectDefineProperties(globalThis, {
name: util.writable(name),
// TODO(bartlomieju): should be readonly?
close: util.nonEnumerable(workerClose),
postMessage: util.writable(postMessage),
});
if (runtimeOptions.enableTestingFeaturesFlag) {
ObjectDefineProperty(
globalThis,
@ -882,8 +588,9 @@ delete Intl.v8BreakIterator;
);
location.setLocationHref(runtimeOptions.location);
numCpus = runtimeOptions.cpuCount;
language = runtimeOptions.locale;
setNumCpus(runtimeOptions.cpuCount);
setLanguage(runtimeOptions.locale);
globalThis.pollForMessages = pollForMessages;

View file

@ -7,6 +7,7 @@ pub use deno_core;
pub use deno_crypto;
pub use deno_fetch;
pub use deno_ffi;
pub use deno_flash;
pub use deno_http;
pub use deno_napi;
pub use deno_net;

View file

@ -17,7 +17,6 @@ use deno_core::futures::channel::mpsc;
use deno_core::futures::future::poll_fn;
use deno_core::futures::stream::StreamExt;
use deno_core::futures::task::AtomicWaker;
use deno_core::located_script_name;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde_json::json;
@ -33,6 +32,7 @@ use deno_core::ModuleSpecifier;
use deno_core::RuntimeOptions;
use deno_core::SharedArrayBufferStore;
use deno_core::SourceMapGetter;
use deno_core::{located_script_name, Snapshot};
use deno_node::RequireNpmResolver;
use deno_tls::rustls::RootCertStore;
use deno_web::create_entangled_message_port;
@ -322,6 +322,7 @@ pub struct WebWorker {
pub struct WebWorkerOptions {
pub bootstrap: BootstrapOptions,
pub extensions: Vec<Extension>,
pub startup_snapshot: Option<Snapshot>,
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
pub root_cert_store: Option<RootCertStore>,
pub seed: Option<u64>,
@ -451,7 +452,11 @@ impl WebWorker {
let mut js_runtime = JsRuntime::new(RuntimeOptions {
module_loader: Some(options.module_loader.clone()),
startup_snapshot: Some(js::deno_isolate_init()),
startup_snapshot: Some(
options
.startup_snapshot
.unwrap_or_else(js::deno_isolate_init),
),
source_map_getter: options.source_map_getter,
get_error_class_fn: options.get_error_class_fn,
shared_array_buffer_store: options.shared_array_buffer_store.clone(),

View file

@ -13,9 +13,6 @@ use deno_core::error::AnyError;
use deno_core::error::JsError;
use deno_core::futures::Future;
use deno_core::located_script_name;
use deno_core::serde_json::json;
use deno_core::serde_v8;
use deno_core::v8;
use deno_core::CompiledWasmModuleStore;
use deno_core::Extension;
use deno_core::FsModuleLoader;
@ -66,10 +63,6 @@ pub struct MainWorker {
pub js_runtime: JsRuntime,
should_break_on_first_statement: bool,
exit_code: ExitCode,
js_run_tests_callback: v8::Global<v8::Function>,
js_run_benchmarks_callback: v8::Global<v8::Function>,
js_enable_test_callback: v8::Global<v8::Function>,
js_enable_bench_callback: v8::Global<v8::Function>,
}
pub struct WorkerOptions {
@ -99,15 +92,6 @@ pub struct WorkerOptions {
pub stdio: Stdio,
}
fn grab_cb(
scope: &mut v8::HandleScope,
path: &str,
) -> v8::Global<v8::Function> {
let cb = JsRuntime::eval::<v8::Function>(scope, path)
.unwrap_or_else(|| panic!("{} must be defined", path));
v8::Global::new(scope, cb)
}
impl Default for WorkerOptions {
fn default() -> Self {
Self {
@ -267,29 +251,10 @@ impl MainWorker {
);
}
let (
js_run_tests_callback,
js_run_benchmarks_callback,
js_enable_test_callback,
js_enable_bench_callback,
) = {
let scope = &mut js_runtime.handle_scope();
(
grab_cb(scope, "__bootstrap.testing.runTests"),
grab_cb(scope, "__bootstrap.testing.runBenchmarks"),
grab_cb(scope, "__bootstrap.testing.enableTest"),
grab_cb(scope, "__bootstrap.testing.enableBench"),
)
};
Self {
js_runtime,
should_break_on_first_statement: options.should_break_on_first_statement,
exit_code,
js_run_tests_callback,
js_run_benchmarks_callback,
js_enable_test_callback,
js_enable_bench_callback,
}
}
@ -377,65 +342,6 @@ impl MainWorker {
self.evaluate_module(id).await
}
/// Run tests declared with `Deno.test()`. Test events will be dispatched
/// by calling ops which are currently only implemented in the CLI crate.
// TODO(nayeemrmn): Move testing ops to deno_runtime and redesign/unhide.
#[doc(hidden)]
pub async fn run_tests(
&mut self,
shuffle: &Option<u64>,
) -> Result<(), AnyError> {
let promise = {
let scope = &mut self.js_runtime.handle_scope();
let cb = self.js_run_tests_callback.open(scope);
let this = v8::undefined(scope).into();
let options =
serde_v8::to_v8(scope, json!({ "shuffle": shuffle })).unwrap();
let promise = cb.call(scope, this, &[options]).unwrap();
v8::Global::new(scope, promise)
};
self.js_runtime.resolve_value(promise).await?;
Ok(())
}
/// Run benches declared with `Deno.bench()`. Bench events will be dispatched
/// by calling ops which are currently only implemented in the CLI crate.
// TODO(nayeemrmn): Move benchmark ops to deno_runtime and redesign/unhide.
#[doc(hidden)]
pub async fn run_benchmarks(&mut self) -> Result<(), AnyError> {
let promise = {
let scope = &mut self.js_runtime.handle_scope();
let cb = self.js_run_benchmarks_callback.open(scope);
let this = v8::undefined(scope).into();
let promise = cb.call(scope, this, &[]).unwrap();
v8::Global::new(scope, promise)
};
self.js_runtime.resolve_value(promise).await?;
Ok(())
}
/// Enable `Deno.test()`. If this isn't called before executing user code,
/// `Deno.test()` calls will noop.
// TODO(nayeemrmn): Move testing ops to deno_runtime and redesign/unhide.
#[doc(hidden)]
pub fn enable_test(&mut self) {
let scope = &mut self.js_runtime.handle_scope();
let cb = self.js_enable_test_callback.open(scope);
let this = v8::undefined(scope).into();
cb.call(scope, this, &[]).unwrap();
}
/// Enable `Deno.bench()`. If this isn't called before executing user code,
/// `Deno.bench()` calls will noop.
// TODO(nayeemrmn): Move benchmark ops to deno_runtime and redesign/unhide.
#[doc(hidden)]
pub fn enable_bench(&mut self) {
let scope = &mut self.js_runtime.handle_scope();
let cb = self.js_enable_bench_callback.open(scope);
let this = v8::undefined(scope).into();
cb.call(scope, this, &[]).unwrap();
}
fn wait_for_inspector_session(&mut self) {
if self.should_break_on_first_statement {
self
@ -542,107 +448,3 @@ impl MainWorker {
Ok(local_value.is_false())
}
}
#[cfg(test)]
mod tests {
use super::*;
use deno_core::resolve_url_or_path;
fn create_test_worker() -> MainWorker {
let main_module = resolve_url_or_path("./hello.js").unwrap();
let permissions = Permissions::default();
let options = WorkerOptions {
bootstrap: BootstrapOptions {
args: vec![],
cpu_count: 1,
debug_flag: false,
enable_testing_features: false,
locale: deno_core::v8::icu::get_language_tag(),
location: None,
no_color: true,
is_tty: false,
runtime_version: "x".to_string(),
ts_version: "x".to_string(),
unstable: false,
user_agent: "x".to_string(),
inspect: false,
},
extensions: vec![],
startup_snapshot: None,
unsafely_ignore_certificate_errors: None,
root_cert_store: None,
seed: None,
format_js_error_fn: None,
source_map_getter: None,
web_worker_preload_module_cb: Arc::new(|_| unreachable!()),
web_worker_pre_execute_module_cb: Arc::new(|_| unreachable!()),
create_web_worker_cb: Arc::new(|_| unreachable!()),
maybe_inspector_server: None,
should_break_on_first_statement: false,
module_loader: Rc::new(FsModuleLoader),
npm_resolver: None,
get_error_class_fn: None,
cache_storage_dir: None,
origin_storage_dir: None,
blob_store: BlobStore::default(),
broadcast_channel: InMemoryBroadcastChannel::default(),
shared_array_buffer_store: None,
compiled_wasm_module_store: None,
stdio: Default::default(),
};
MainWorker::bootstrap_from_options(main_module, permissions, options)
}
#[tokio::test]
async fn execute_mod_esm_imports_a() {
let p = test_util::testdata_path().join("runtime/esm_imports_a.js");
let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
let mut worker = create_test_worker();
let result = worker.execute_main_module(&module_specifier).await;
if let Err(err) = result {
eprintln!("execute_mod err {:?}", err);
}
if let Err(e) = worker.run_event_loop(false).await {
panic!("Future got unexpected error: {:?}", e);
}
}
#[tokio::test]
async fn execute_mod_circular() {
let p = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.join("tests/circular1.js");
let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
let mut worker = create_test_worker();
let result = worker.execute_main_module(&module_specifier).await;
if let Err(err) = result {
eprintln!("execute_mod err {:?}", err);
}
if let Err(e) = worker.run_event_loop(false).await {
panic!("Future got unexpected error: {:?}", e);
}
}
#[tokio::test]
async fn execute_mod_resolve_error() {
// "foo" is not a valid module specifier so this should return an error.
let mut worker = create_test_worker();
let module_specifier = resolve_url_or_path("does-not-exist").unwrap();
let result = worker.execute_main_module(&module_specifier).await;
assert!(result.is_err());
}
#[tokio::test]
async fn execute_mod_002_hello() {
// This assumes cwd is project root (an assumption made throughout the
// tests).
let mut worker = create_test_worker();
let p = test_util::testdata_path().join("run/001_hello.js");
let module_specifier = resolve_url_or_path(&p.to_string_lossy()).unwrap();
let result = worker.execute_main_module(&module_specifier).await;
assert!(result.is_ok());
}
}