diff --git a/build.rs b/build.rs index 72878fd5f0..98dd393c33 100644 --- a/build.rs +++ b/build.rs @@ -76,6 +76,13 @@ fn main() { } } + // Enable snapshots for x64 builds + if env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "x86_64" { + // Not related to v8_use_snapshot + // This only enables using pregenerated snapshots for isolate init + println!("cargo:rustc-cfg=feature=\"use-snapshot-init\""); + } + if !gn_out_path.join("build.ninja").exists() { let status = Command::new("python") .env("DENO_BUILD_PATH", &gn_out_dir) diff --git a/libdeno/api.cc b/libdeno/api.cc index 4cb7b846bd..ab87382c33 100644 --- a/libdeno/api.cc +++ b/libdeno/api.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "third_party/v8/include/libplatform/libplatform.h" @@ -10,6 +11,7 @@ #include "deno.h" #include "exceptions.h" +#include "file_util.h" #include "internal.h" extern "C" { @@ -106,10 +108,11 @@ deno_buf deno_get_snapshot(Deno* d_) { static std::unique_ptr platform; void deno_init() { - CHECK_NULL(platform.get()); - platform = v8::platform::NewDefaultPlatform(); - v8::V8::InitializePlatform(platform.get()); - v8::V8::Initialize(); + if (platform.get() == nullptr) { + platform = v8::platform::NewDefaultPlatform(); + v8::V8::InitializePlatform(platform.get()); + v8::V8::Initialize(); + } } const char* deno_v8_version() { return v8::V8::GetVersion(); } diff --git a/src/compiler.rs b/src/compiler.rs index 716a9bbeae..5fe335c551 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,6 +1,7 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. use crate::isolate::Buf; use crate::isolate::IsolateState; +use crate::isolate_init; use crate::msg; use crate::permissions::DenoPermissions; use crate::resources; @@ -50,6 +51,7 @@ impl ModuleMetaData { fn lazy_start(parent_state: &Arc) -> Resource { let mut cell = C_RID.lock().unwrap(); + let isolate_init = isolate_init::compiler_isolate_init(); let permissions = DenoPermissions { allow_read: AtomicBool::new(true), allow_write: AtomicBool::new(true), @@ -59,6 +61,7 @@ fn lazy_start(parent_state: &Arc) -> Resource { }; let rid = cell.get_or_insert_with(|| { let resource = workers::spawn( + isolate_init, parent_state.clone(), "compilerMain()".to_string(), permissions, diff --git a/src/isolate.rs b/src/isolate.rs index dac4f6d78e..05af3e6bcc 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -12,6 +12,7 @@ use crate::errors::DenoError; use crate::errors::DenoResult; use crate::errors::RustOrJsError; use crate::flags; +use crate::isolate_init::IsolateInit; use crate::js_errors::apply_source_map; use crate::libdeno; use crate::modules::Modules; @@ -166,7 +167,7 @@ static DENO_INIT: Once = ONCE_INIT; impl Isolate { pub fn new( - snapshot: libdeno::deno_buf, + init: IsolateInit, state: Arc, dispatch: Dispatch, permissions: DenoPermissions, @@ -176,7 +177,10 @@ impl Isolate { }); let config = libdeno::deno_config { will_snapshot: 0, - load_snapshot: snapshot, + load_snapshot: match init.snapshot { + Some(s) => s, + None => libdeno::deno_buf::empty(), + }, shared: libdeno::deno_buf::empty(), // TODO Use for message passing. recv_cb: pre_dispatch, }; @@ -184,7 +188,7 @@ impl Isolate { // This channel handles sending async messages back to the runtime. let (tx, rx) = mpsc::channel::<(usize, Buf)>(); - Self { + let new_isolate = Self { libdeno_isolate, dispatch, rx, @@ -194,7 +198,17 @@ impl Isolate { modules: RefCell::new(Modules::new()), state, permissions: Arc::new(permissions), - } + }; + + // Run init script if present. + match init.init_script { + Some(init_script) => new_isolate + .execute2(init_script.filename.as_str(), init_script.source.as_str()) + .unwrap(), + None => {} + }; + + new_isolate } #[inline] @@ -618,9 +632,12 @@ mod tests { #[test] fn test_dispatch_sync() { let state = IsolateState::mock(); - let snapshot = libdeno::deno_buf::empty(); - let permissions = DenoPermissions::default(); - let isolate = Isolate::new(snapshot, state, dispatch_sync, permissions); + let init = IsolateInit { + snapshot: None, + init_script: None, + }; + let isolate = + Isolate::new(init, state, dispatch_sync, DenoPermissions::default()); tokio_util::init(|| { isolate .execute( @@ -658,10 +675,16 @@ mod tests { #[test] fn test_metrics_sync() { let state = IsolateState::mock(); - let snapshot = libdeno::deno_buf::empty(); - let permissions = DenoPermissions::default(); - let isolate = - Isolate::new(snapshot, state, metrics_dispatch_sync, permissions); + let init = IsolateInit { + snapshot: None, + init_script: None, + }; + let isolate = Isolate::new( + init, + state, + metrics_dispatch_sync, + DenoPermissions::default(), + ); tokio_util::init(|| { // Verify that metrics have been properly initialized. { @@ -694,10 +717,16 @@ mod tests { #[test] fn test_metrics_async() { let state = IsolateState::mock(); - let snapshot = libdeno::deno_buf::empty(); - let permissions = DenoPermissions::default(); - let isolate = - Isolate::new(snapshot, state, metrics_dispatch_async, permissions); + let init = IsolateInit { + snapshot: None, + init_script: None, + }; + let isolate = Isolate::new( + init, + state, + metrics_dispatch_async, + DenoPermissions::default(), + ); tokio_util::init(|| { // Verify that metrics have been properly initialized. { @@ -784,9 +813,12 @@ mod tests { let (flags, rest_argv, _) = flags::set_flags(argv).unwrap(); let state = Arc::new(IsolateState::new(flags, rest_argv, None)); - let snapshot = libdeno::deno_buf::empty(); - let permissions = DenoPermissions::default(); - let mut isolate = Isolate::new(snapshot, state, dispatch_sync, permissions); + let init = IsolateInit { + snapshot: None, + init_script: None, + }; + let mut isolate = + Isolate::new(init, state, dispatch_sync, DenoPermissions::default()); tokio_util::init(|| { isolate .execute_mod(filename, false) @@ -807,9 +839,12 @@ mod tests { let (flags, rest_argv, _) = flags::set_flags(argv).unwrap(); let state = Arc::new(IsolateState::new(flags, rest_argv, None)); - let snapshot = libdeno::deno_buf::empty(); - let permissions = DenoPermissions::default(); - let mut isolate = Isolate::new(snapshot, state, dispatch_sync, permissions); + let init = IsolateInit { + snapshot: None, + init_script: None, + }; + let mut isolate = + Isolate::new(init, state, dispatch_sync, DenoPermissions::default()); tokio_util::init(|| { isolate .execute_mod(filename, false) diff --git a/src/isolate_init.rs b/src/isolate_init.rs new file mode 100644 index 0000000000..c77f0c9980 --- /dev/null +++ b/src/isolate_init.rs @@ -0,0 +1,86 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +use crate::libdeno::deno_buf; + +pub struct IsolateInitScript { + pub source: String, + pub filename: String, +} + +pub struct IsolateInit { + pub snapshot: Option, + pub init_script: Option, +} + +pub fn deno_isolate_init() -> IsolateInit { + if cfg!(not(feature = "check-only")) { + if cfg!(feature = "use-snapshot-init") { + let data = + include_bytes!(concat!(env!("GN_OUT_DIR"), "/gen/snapshot_deno.bin")); + + unsafe { + IsolateInit { + snapshot: Some(deno_buf::from_raw_parts(data.as_ptr(), data.len())), + init_script: None, + } + } + } else { + #[cfg(not(feature = "check-only"))] + let source_bytes = + include_bytes!(concat!(env!("GN_OUT_DIR"), "/gen/bundle/main.js")); + + #[cfg(feature = "check-only")] + let source_bytes = vec![]; + + IsolateInit { + snapshot: None, + init_script: Some(IsolateInitScript { + filename: "gen/bundle/main.js".to_string(), + source: std::str::from_utf8(source_bytes).unwrap().to_string(), + }), + } + } + } else { + IsolateInit { + snapshot: None, + init_script: None, + } + } +} + +pub fn compiler_isolate_init() -> IsolateInit { + if cfg!(not(feature = "check-only")) { + if cfg!(feature = "use-snapshot-init") { + let data = include_bytes!(concat!( + env!("GN_OUT_DIR"), + "/gen/snapshot_compiler.bin" + )); + + unsafe { + IsolateInit { + snapshot: Some(deno_buf::from_raw_parts(data.as_ptr(), data.len())), + init_script: None, + } + } + } else { + #[cfg(not(feature = "check-only"))] + let source_bytes = + include_bytes!(concat!(env!("GN_OUT_DIR"), "/gen/bundle/compiler.js")); + + #[cfg(feature = "check-only")] + let source_bytes = vec![]; + + IsolateInit { + snapshot: None, + init_script: Some(IsolateInitScript { + filename: "gen/bundle/compiler.js".to_string(), + source: std::str::from_utf8(source_bytes).unwrap().to_string(), + }), + } + } + } else { + IsolateInit { + snapshot: None, + init_script: None, + } + } +} diff --git a/src/main.rs b/src/main.rs index c8e7c90200..23efa50ee7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ mod fs; mod http_body; mod http_util; pub mod isolate; +pub mod isolate_init; pub mod js_errors; pub mod libdeno; pub mod modules; @@ -27,7 +28,6 @@ pub mod permissions; mod repl; pub mod resolve_addr; pub mod resources; -pub mod snapshot; mod tokio_util; mod tokio_write; pub mod version; @@ -95,10 +95,10 @@ fn main() { let should_display_info = flags.info; let state = Arc::new(isolate::IsolateState::new(flags, rest_argv, None)); - let snapshot = snapshot::deno_snapshot(); + let isolate_init = isolate_init::deno_isolate_init(); let permissions = permissions::DenoPermissions::from_flags(&state.flags); let mut isolate = - isolate::Isolate::new(snapshot, state, ops::dispatch, permissions); + isolate::Isolate::new(isolate_init, state, ops::dispatch, permissions); tokio_util::init(|| { // Setup runtime. diff --git a/src/ops.rs b/src/ops.rs index ba309ca7ab..5c5fc67fc4 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -1863,13 +1863,13 @@ fn op_worker_post_message( mod tests { use super::*; use crate::isolate::{Isolate, IsolateState}; + use crate::isolate_init::IsolateInit; use crate::permissions::DenoPermissions; use std::sync::atomic::AtomicBool; #[test] fn fetch_module_meta_fails_without_read() { let state = IsolateState::mock(); - let snapshot = libdeno::deno_buf::empty(); let permissions = DenoPermissions { allow_read: AtomicBool::new(false), allow_write: AtomicBool::new(true), @@ -1877,7 +1877,15 @@ mod tests { allow_net: AtomicBool::new(true), allow_run: AtomicBool::new(true), }; - let isolate = Isolate::new(snapshot, state, dispatch, permissions); + let isolate = Isolate::new( + IsolateInit { + snapshot: None, + init_script: None, + }, + state, + dispatch, + permissions, + ); let builder = &mut FlatBufferBuilder::new(); let fetch_msg_args = msg::FetchModuleMetaDataArgs { specifier: Some(builder.create_string("./somefile")), @@ -1907,7 +1915,6 @@ mod tests { #[test] fn fetch_module_meta_fails_without_write() { let state = IsolateState::mock(); - let snapshot = libdeno::deno_buf::empty(); let permissions = DenoPermissions { allow_read: AtomicBool::new(true), allow_write: AtomicBool::new(false), @@ -1915,7 +1922,15 @@ mod tests { allow_net: AtomicBool::new(true), allow_run: AtomicBool::new(true), }; - let isolate = Isolate::new(snapshot, state, dispatch, permissions); + let isolate = Isolate::new( + IsolateInit { + snapshot: None, + init_script: None, + }, + state, + dispatch, + permissions, + ); let builder = &mut FlatBufferBuilder::new(); let fetch_msg_args = msg::FetchModuleMetaDataArgs { specifier: Some(builder.create_string("./somefile")), @@ -1945,7 +1960,6 @@ mod tests { #[test] fn fetch_module_meta_fails_without_net() { let state = IsolateState::mock(); - let snapshot = libdeno::deno_buf::empty(); let permissions = DenoPermissions { allow_read: AtomicBool::new(true), allow_write: AtomicBool::new(true), @@ -1953,7 +1967,15 @@ mod tests { allow_net: AtomicBool::new(false), allow_run: AtomicBool::new(true), }; - let isolate = Isolate::new(snapshot, state, dispatch, permissions); + let isolate = Isolate::new( + IsolateInit { + snapshot: None, + init_script: None, + }, + state, + dispatch, + permissions, + ); let builder = &mut FlatBufferBuilder::new(); let fetch_msg_args = msg::FetchModuleMetaDataArgs { specifier: Some(builder.create_string("./somefile")), @@ -1983,7 +2005,6 @@ mod tests { #[test] fn fetch_module_meta_not_permission_denied_with_permissions() { let state = IsolateState::mock(); - let snapshot = libdeno::deno_buf::empty(); let permissions = DenoPermissions { allow_read: AtomicBool::new(true), allow_write: AtomicBool::new(true), @@ -1991,7 +2012,15 @@ mod tests { allow_net: AtomicBool::new(true), allow_run: AtomicBool::new(false), }; - let isolate = Isolate::new(snapshot, state, dispatch, permissions); + let isolate = Isolate::new( + IsolateInit { + snapshot: None, + init_script: None, + }, + state, + dispatch, + permissions, + ); let builder = &mut FlatBufferBuilder::new(); let fetch_msg_args = msg::FetchModuleMetaDataArgs { specifier: Some(builder.create_string("./somefile")), diff --git a/src/snapshot.rs b/src/snapshot.rs deleted file mode 100644 index ac1648e0cf..0000000000 --- a/src/snapshot.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -use crate::libdeno::deno_buf; - -pub fn deno_snapshot() -> deno_buf { - #[cfg(not(feature = "check-only"))] - let data = - include_bytes!(concat!(env!("GN_OUT_DIR"), "/gen/snapshot_deno.bin")); - // The snapshot blob is not available when the Rust Language Server runs - // 'cargo check'. - #[cfg(feature = "check-only")] - let data = vec![]; - - unsafe { deno_buf::from_raw_parts(data.as_ptr(), data.len()) } -} - -pub fn compiler_snapshot() -> deno_buf { - #[cfg(not(feature = "check-only"))] - let data = - include_bytes!(concat!(env!("GN_OUT_DIR"), "/gen/snapshot_compiler.bin")); - // The snapshot blob is not available when the Rust Language Server runs - // 'cargo check'. - #[cfg(feature = "check-only")] - let data = vec![]; - - unsafe { deno_buf::from_raw_parts(data.as_ptr(), data.len()) } -} diff --git a/src/workers.rs b/src/workers.rs index 6b85a97da5..3a3b690b27 100644 --- a/src/workers.rs +++ b/src/workers.rs @@ -3,11 +3,11 @@ use crate::isolate::Buf; use crate::isolate::Isolate; use crate::isolate::IsolateState; use crate::isolate::WorkerChannels; +use crate::isolate_init::IsolateInit; use crate::js_errors::JSErrorColor; use crate::ops; use crate::permissions::DenoPermissions; use crate::resources; -use crate::snapshot; use crate::tokio_util; use deno_core::JSError; @@ -24,6 +24,7 @@ pub struct Worker { impl Worker { pub fn new( + init: IsolateInit, parent_state: &Arc, permissions: DenoPermissions, ) -> (Self, WorkerChannels) { @@ -39,8 +40,7 @@ impl Worker { Some(internal_channels), )); - let snapshot = snapshot::compiler_snapshot(); - let isolate = Isolate::new(snapshot, state, ops::dispatch, permissions); + let isolate = Isolate::new(init, state, ops::dispatch, permissions); let worker = Worker { isolate }; (worker, external_channels) @@ -56,6 +56,7 @@ impl Worker { } pub fn spawn( + init: IsolateInit, state: Arc, js_source: String, permissions: DenoPermissions, @@ -68,7 +69,7 @@ pub fn spawn( let builder = thread::Builder::new().name("worker".to_string()); let _tid = builder .spawn(move || { - let (worker, external_channels) = Worker::new(&state, permissions); + let (worker, external_channels) = Worker::new(init, &state, permissions); let resource = resources::add_worker(external_channels); p.send(resource.clone()).unwrap(); @@ -95,10 +96,13 @@ pub fn spawn( #[cfg(test)] mod tests { use super::*; + use crate::isolate_init; #[test] fn test_spawn() { + let isolate_init = isolate_init::compiler_isolate_init(); let resource = spawn( + isolate_init, IsolateState::mock(), r#" onmessage = function(e) { @@ -133,7 +137,9 @@ mod tests { #[test] fn removed_from_resource_table_on_close() { + let isolate_init = isolate_init::compiler_isolate_init(); let resource = spawn( + isolate_init, IsolateState::mock(), "onmessage = () => close();".into(), DenoPermissions::default(),