diff options
-rw-r--r-- | .github/workflows/ci.yml | 3 | ||||
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | cli/js.rs | 6 | ||||
-rw-r--r-- | cli/startup_data.rs | 5 | ||||
-rw-r--r-- | core/Cargo.toml | 2 | ||||
-rw-r--r-- | core/bindings.rs | 96 | ||||
-rw-r--r-- | core/es_isolate.rs | 6 | ||||
-rw-r--r-- | core/isolate.rs | 112 | ||||
-rw-r--r-- | core/shared_queue.rs | 13 |
9 files changed, 130 insertions, 117 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7381d9c4..d6b4658d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,13 +107,10 @@ jobs: target/*/.* target/*/build target/*/deps - target/*/gn_out key: ${{ matrix.config.os }}-${{ matrix.config.kind }}-${{ hashFiles('Cargo.lock') }} restore-keys: | - ${{ matrix.config.os }}-${{ matrix.config.kind }}-${{ hashFiles('Cargo.lock') }} ${{ matrix.config.os }}-${{ matrix.config.kind }}- - ${{ matrix.config.os }}- - name: lint.py if: matrix.config.kind == 'lint' diff --git a/Cargo.lock b/Cargo.lock index c79d4affe..3ec2b187f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2065,9 +2065,9 @@ dependencies = [ [[package]] name = "rusty_v8" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e2d68d8404b3902796736c0d3dec8073b35ba02413aa126e15ad09e9e70842" +checksum = "d7ccfa96e1b3ce6f807a93b58d38fc5e984e617506e52cb336888ab890cd884a" dependencies = [ "bitflags", "cargo_gn", @@ -24,7 +24,7 @@ pub static WINDOW_LIB: &str = include_str!("js/lib.deno.window.d.ts"); #[test] fn cli_snapshot() { let mut isolate = deno_core::Isolate::new( - deno_core::StartupData::Snapshot(CLI_SNAPSHOT), + deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(CLI_SNAPSHOT)), false, ); deno_core::js_check(isolate.execute( @@ -41,7 +41,9 @@ fn cli_snapshot() { #[test] fn compiler_snapshot() { let mut isolate = deno_core::Isolate::new( - deno_core::StartupData::Snapshot(COMPILER_SNAPSHOT), + deno_core::StartupData::Snapshot(deno_core::Snapshot::Static( + COMPILER_SNAPSHOT, + )), false, ); deno_core::js_check(isolate.execute( diff --git a/cli/startup_data.rs b/cli/startup_data.rs index a90a2377d..517165d11 100644 --- a/cli/startup_data.rs +++ b/cli/startup_data.rs @@ -4,6 +4,7 @@ use deno_core::Script; use crate::js::CLI_SNAPSHOT; use crate::js::COMPILER_SNAPSHOT; +use deno_core::Snapshot; use deno_core::StartupData; #[cfg(feature = "no-snapshot-init")] @@ -29,7 +30,7 @@ pub fn deno_isolate_init() -> StartupData<'static> { #[cfg(feature = "check-only")] let data = b""; - StartupData::Snapshot(data) + StartupData::Snapshot(Snapshot::Static(data)) } #[cfg(feature = "no-snapshot-init")] @@ -55,5 +56,5 @@ pub fn compiler_isolate_init() -> StartupData<'static> { #[cfg(feature = "check-only")] let data = b""; - StartupData::Snapshot(data) + StartupData::Snapshot(Snapshot::Static(data)) } diff --git a/core/Cargo.toml b/core/Cargo.toml index 7ea32df46..d05fdd333 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,7 +19,7 @@ futures = { version = "0.3.4", features = ["thread-pool", "compat"] } lazy_static = "1.4.0" libc = "0.2.68" log = "0.4.8" -rusty_v8 = "0.3.10" +rusty_v8 = "0.4.0" serde_json = "1.0.51" url = "2.1.1" diff --git a/core/bindings.rs b/core/bindings.rs index c89c68424..d34dfe834 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -8,6 +8,7 @@ use crate::js_errors::JSError; use rusty_v8 as v8; use v8::MapFnTo; +use std::cell::Cell; use std::convert::TryFrom; use std::option::Option; use url::Url; @@ -236,9 +237,8 @@ pub fn boxed_slice_to_uint8array<'sc>( assert!(!buf.is_empty()); let buf_len = buf.len(); let backing_store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(buf); - let mut backing_store_shared = backing_store.make_shared(); - let ab = - v8::ArrayBuffer::with_backing_store(scope, &mut backing_store_shared); + let backing_store_shared = backing_store.make_shared(); + let ab = v8::ArrayBuffer::with_backing_store(scope, &backing_store_shared); v8::Uint8Array::new(ab, 0, buf_len).expect("Failed to create UintArray8") } @@ -271,7 +271,7 @@ pub extern "C" fn host_import_module_dynamically_callback( let host_defined_options = referrer.get_host_defined_options(); assert_eq!(host_defined_options.length(), 0); - let mut resolver = v8::PromiseResolver::new(scope, context).unwrap(); + let resolver = v8::PromiseResolver::new(scope, context).unwrap(); let promise = resolver.get_promise(scope); let mut resolver_handle = v8::Global::new(); @@ -355,6 +355,29 @@ pub extern "C" fn promise_reject_callback(message: v8::PromiseRejectMessage) { }; } +pub(crate) unsafe fn get_backing_store_slice( + backing_store: &v8::SharedRef<v8::BackingStore>, + byte_offset: usize, + byte_length: usize, +) -> &[u8] { + let cells: *const [Cell<u8>] = + &backing_store[byte_offset..byte_offset + byte_length]; + let bytes = cells as *const [u8]; + &*bytes +} + +#[allow(clippy::mut_from_ref)] +pub(crate) unsafe fn get_backing_store_slice_mut( + backing_store: &v8::SharedRef<v8::BackingStore>, + byte_offset: usize, + byte_length: usize, +) -> &mut [u8] { + let cells: *const [Cell<u8>] = + &backing_store[byte_offset..byte_offset + byte_length]; + let bytes = cells as *const _ as *mut [u8]; + &mut *bytes +} + fn print( scope: v8::FunctionCallbackScope, args: v8::FunctionCallbackArguments, @@ -416,26 +439,27 @@ fn send( unsafe { &mut *(scope.isolate().get_data(0) as *mut Isolate) }; assert!(!deno_isolate.global_context.is_empty()); - let r = v8::Local::<v8::Uint32>::try_from(args.get(0)); - - if let Err(err) = r { - let s = format!("bad op id {}", err); - let msg = v8::String::new(scope, &s).unwrap(); - scope.isolate().throw_exception(msg.into()); - return; - } - - let op_id = r.unwrap().value() as u32; + let op_id = match v8::Local::<v8::Uint32>::try_from(args.get(0)) { + Ok(op_id) => op_id.value() as u32, + Err(err) => { + let msg = format!("invalid op id: {}", err); + let msg = v8::String::new(scope, &msg).unwrap(); + scope.isolate().throw_exception(msg.into()); + return; + } + }; + let control_backing_store: v8::SharedRef<v8::BackingStore>; let control = match v8::Local::<v8::ArrayBufferView>::try_from(args.get(1)) { - Ok(view) => { - let byte_offset = view.byte_offset(); - let byte_length = view.byte_length(); - let backing_store = view.buffer().unwrap().get_backing_store(); - let buf = unsafe { &**backing_store.get() }; - &buf[byte_offset..byte_offset + byte_length] - } - Err(..) => &[], + Ok(view) => unsafe { + control_backing_store = view.buffer().unwrap().get_backing_store(); + get_backing_store_slice( + &control_backing_store, + view.byte_offset(), + view.byte_length(), + ) + }, + Err(_) => &[], }; let zero_copy: Option<ZeroCopyBuf> = @@ -654,9 +678,8 @@ fn encode( let buf_len = text_bytes.len(); let backing_store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(text_bytes); - let mut backing_store_shared = backing_store.make_shared(); - let ab = - v8::ArrayBuffer::with_backing_store(scope, &mut backing_store_shared); + let backing_store_shared = backing_store.make_shared(); + let ab = v8::ArrayBuffer::with_backing_store(scope, &backing_store_shared); v8::Uint8Array::new(ab, 0, buf_len).expect("Failed to create UintArray8") }; @@ -668,15 +691,9 @@ fn decode( args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { - let buf = match v8::Local::<v8::ArrayBufferView>::try_from(args.get(0)) { - Ok(view) => { - let byte_offset = view.byte_offset(); - let byte_length = view.byte_length(); - let backing_store = view.buffer().unwrap().get_backing_store(); - let buf = unsafe { &**backing_store.get() }; - &buf[byte_offset..byte_offset + byte_length] - } - Err(..) => { + let view = match v8::Local::<v8::ArrayBufferView>::try_from(args.get(0)) { + Ok(view) => view, + Err(_) => { let msg = v8::String::new(scope, "Invalid argument").unwrap(); let exception = v8::Exception::type_error(scope, msg); scope.isolate().throw_exception(exception); @@ -684,6 +701,15 @@ fn decode( } }; + let backing_store = view.buffer().unwrap().get_backing_store(); + let buf = unsafe { + get_backing_store_slice( + &backing_store, + view.byte_offset(), + view.byte_length(), + ) + }; + let text_str = v8::String::new_from_utf8(scope, &buf, v8::NewStringType::Normal).unwrap(); rv.set(text_str.into()) @@ -791,7 +817,7 @@ fn get_promise_details( assert!(!deno_isolate.global_context.is_empty()); let context = deno_isolate.global_context.get(scope).unwrap(); - let mut promise = match v8::Local::<v8::Promise>::try_from(args.get(0)) { + let promise = match v8::Local::<v8::Promise>::try_from(args.get(0)) { Ok(val) => val, Err(_) => { let msg = v8::String::new(scope, "Invalid argument").unwrap(); diff --git a/core/es_isolate.rs b/core/es_isolate.rs index f50a3abb0..b847005f9 100644 --- a/core/es_isolate.rs +++ b/core/es_isolate.rs @@ -233,7 +233,7 @@ impl EsIsolate { let scope = cs.enter(); let info = self.modules.get_info(id).expect("ModuleInfo not found"); - let mut module = info.handle.get(scope).expect("Empty module handle"); + let module = info.handle.get(scope).expect("Empty module handle"); let mut status = module.get_status(); if status == v8::ModuleStatus::Instantiated { @@ -312,7 +312,7 @@ impl EsIsolate { .dyn_import_map .remove(&id) .expect("Invalid dyn import id"); - let mut resolver = resolver_handle.get(scope).unwrap(); + let resolver = resolver_handle.get(scope).unwrap(); resolver_handle.reset(scope); let exception = err @@ -348,7 +348,7 @@ impl EsIsolate { .dyn_import_map .remove(&id) .expect("Invalid dyn import id"); - let mut resolver = resolver_handle.get(scope).unwrap(); + let resolver = resolver_handle.get(scope).unwrap(); resolver_handle.reset(scope); let info = self .modules diff --git a/core/isolate.rs b/core/isolate.rs index 1bf7d650c..6e0728564 100644 --- a/core/isolate.rs +++ b/core/isolate.rs @@ -66,15 +66,25 @@ impl ZeroCopyBuf { impl Deref for ZeroCopyBuf { type Target = [u8]; fn deref(&self) -> &[u8] { - let buf = unsafe { &**self.backing_store.get() }; - &buf[self.byte_offset..self.byte_offset + self.byte_length] + unsafe { + bindings::get_backing_store_slice( + &self.backing_store, + self.byte_offset, + self.byte_length, + ) + } } } impl DerefMut for ZeroCopyBuf { fn deref_mut(&mut self) -> &mut [u8] { - let buf = unsafe { &mut **self.backing_store.get() }; - &mut buf[self.byte_offset..self.byte_offset + self.byte_length] + unsafe { + bindings::get_backing_store_slice_mut( + &self.backing_store, + self.byte_offset, + self.byte_length, + ) + } } } @@ -90,33 +100,6 @@ impl AsMut<[u8]> for ZeroCopyBuf { } } -pub enum SnapshotConfig { - Borrowed(v8::StartupData<'static>), - Owned(v8::OwnedStartupData), -} - -impl From<&'static [u8]> for SnapshotConfig { - fn from(sd: &'static [u8]) -> Self { - Self::Borrowed(v8::StartupData::new(sd)) - } -} - -impl From<v8::OwnedStartupData> for SnapshotConfig { - fn from(sd: v8::OwnedStartupData) -> Self { - Self::Owned(sd) - } -} - -impl Deref for SnapshotConfig { - type Target = v8::StartupData<'static>; - fn deref(&self) -> &Self::Target { - match self { - Self::Borrowed(sd) => sd, - Self::Owned(sd) => &*sd, - } - } -} - /// Stores a script used to initalize a Isolate pub struct Script<'a> { pub source: &'a str, @@ -139,13 +122,17 @@ impl From<Script<'_>> for OwnedScript { } } +pub enum Snapshot { + Static(&'static [u8]), + JustCreated(v8::StartupData), +} + /// Represents data used to initialize isolate at startup /// either a binary snapshot or a javascript source file /// in the form of the StartupScript struct. pub enum StartupData<'a> { Script(Script<'a>), - Snapshot(&'static [u8]), - OwnedSnapshot(v8::OwnedStartupData), + Snapshot(Snapshot), None, } @@ -165,7 +152,6 @@ pub struct Isolate { pub v8_isolate: Option<v8::OwnedIsolate>, snapshot_creator: Option<v8::SnapshotCreator>, has_snapshotted: bool, - snapshot: Option<SnapshotConfig>, pub resource_table: Rc<RefCell<ResourceTable>>, pub global_context: v8::Global<v8::Context>, pub(crate) shared_ab: v8::Global<v8::SharedArrayBuffer>, @@ -211,7 +197,7 @@ static DENO_INIT: Once = Once::new(); #[allow(clippy::missing_safety_doc)] pub unsafe fn v8_init() { - let platform = v8::new_default_platform(); + let platform = v8::new_default_platform().unwrap(); v8::V8::initialize_platform(platform); v8::V8::initialize(); // TODO(ry) This makes WASM compile synchronously. Eventually we should @@ -234,27 +220,16 @@ impl Isolate { unsafe { v8_init() }; }); - let mut load_snapshot: Option<SnapshotConfig> = None; - let mut startup_script: Option<OwnedScript> = None; - - // Separate into Option values for each startup type - match startup_data { - StartupData::Script(d) => { - startup_script = Some(d.into()); - } - StartupData::Snapshot(d) => { - load_snapshot = Some(d.into()); - } - StartupData::OwnedSnapshot(d) => { - load_snapshot = Some(d.into()); - } - StartupData::None => {} + let (startup_script, startup_snapshot) = match startup_data { + StartupData::Script(script) => (Some(script.into()), None), + StartupData::Snapshot(snapshot) => (None, Some(snapshot)), + StartupData::None => (None, None), }; let mut global_context = v8::Global::<v8::Context>::new(); let (mut isolate, maybe_snapshot_creator) = if will_snapshot { // TODO(ry) Support loading snapshots before snapshotting. - assert!(load_snapshot.is_none()); + assert!(startup_snapshot.is_none()); let mut creator = v8::SnapshotCreator::new(Some(&bindings::EXTERNAL_REFERENCES)); let isolate = unsafe { creator.get_owned_isolate() }; @@ -269,12 +244,17 @@ impl Isolate { (isolate, Some(creator)) } else { - let mut params = v8::Isolate::create_params(); - params.set_array_buffer_allocator(v8::new_default_allocator()); - params.set_external_references(&bindings::EXTERNAL_REFERENCES); - if let Some(ref mut snapshot) = load_snapshot { - params.set_snapshot_blob(snapshot); - } + let mut params = v8::Isolate::create_params() + .external_references(&**bindings::EXTERNAL_REFERENCES); + let snapshot_loaded = if let Some(snapshot) = startup_snapshot { + params = match snapshot { + Snapshot::Static(data) => params.snapshot_blob(data), + Snapshot::JustCreated(data) => params.snapshot_blob(data), + }; + true + } else { + false + }; let isolate = v8::Isolate::new(params); let mut isolate = Isolate::setup_isolate(isolate); @@ -282,13 +262,12 @@ impl Isolate { let mut hs = v8::HandleScope::new(&mut isolate); let scope = hs.enter(); - let context = match load_snapshot { - Some(_) => v8::Context::new(scope), - None => { - // If no snapshot is provided, we initialize the context with empty - // main source code and source maps. - bindings::initialize_context(scope) - } + let context = if snapshot_loaded { + v8::Context::new(scope) + } else { + // If no snapshot is provided, we initialize the context with empty + // main source code and source maps. + bindings::initialize_context(scope) }; global_context.set(scope, context); @@ -307,7 +286,6 @@ impl Isolate { js_recv_cb: v8::Global::<v8::Function>::new(), js_macrotask_cb: v8::Global::<v8::Function>::new(), snapshot_creator: maybe_snapshot_creator, - snapshot: load_snapshot, has_snapshotted: false, shared_isolate_handle: Arc::new(Mutex::new(None)), js_error_create_fn: Box::new(JSError::create), @@ -472,7 +450,7 @@ impl Isolate { /// ErrBox can be downcast to a type that exposes additional information about /// the V8 exception. By default this type is JSError, however it may be a /// different type if Isolate::set_js_error_create_fn() has been used. - pub fn snapshot(&mut self) -> v8::OwnedStartupData { + pub fn snapshot(&mut self) -> v8::StartupData { assert!(self.snapshot_creator.is_some()); // Note: create_blob() method must not be called from within a HandleScope. @@ -1193,7 +1171,7 @@ pub mod tests { isolate.snapshot() }; - let startup_data = StartupData::OwnedSnapshot(snapshot); + let startup_data = StartupData::Snapshot(Snapshot::JustCreated(snapshot)); let mut isolate2 = Isolate::new(startup_data, false); js_check(isolate2.execute("check.js", "if (a != 3) throw Error('x')")); } diff --git a/core/shared_queue.rs b/core/shared_queue.rs index 0f35d1310..f35fff012 100644 --- a/core/shared_queue.rs +++ b/core/shared_queue.rs @@ -16,6 +16,7 @@ SharedQueue Binary Layout +---------------------------------------------------------------+ */ +use crate::bindings; use crate::ops::OpId; use rusty_v8 as v8; @@ -56,11 +57,19 @@ impl SharedQueue { } pub fn bytes(&self) -> &[u8] { - unsafe { &*self.buf.get() } + unsafe { + bindings::get_backing_store_slice(&self.buf, 0, self.buf.byte_length()) + } } pub fn bytes_mut(&mut self) -> &mut [u8] { - unsafe { &mut *self.buf.get() } + unsafe { + bindings::get_backing_store_slice_mut( + &self.buf, + 0, + self.buf.byte_length(), + ) + } } fn reset(&mut self) { |