diff --git a/core/any_error.rs b/core/any_error.rs deleted file mode 100644 index 34709e77fc..0000000000 --- a/core/any_error.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -use std::any::Any; -use std::any::TypeId; -use std::convert::From; -use std::error::Error; -use std::fmt; -use std::ops::Deref; - -// The Send and Sync traits are required because deno is multithreaded and we -// need to be able to handle errors across threads. -pub trait AnyError: Any + Error + Send + Sync + 'static {} -impl AnyError for T where T: Any + Error + Send + Sync + Sized + 'static {} - -#[derive(Debug)] -pub struct ErrBox(Box); - -impl dyn AnyError { - pub fn downcast_ref(&self) -> Option<&T> { - if Any::type_id(self) == TypeId::of::() { - let target = self as *const Self as *const T; - let target = unsafe { &*target }; - Some(target) - } else { - None - } - } -} - -impl ErrBox { - pub fn downcast(self) -> Result { - if Any::type_id(&*self.0) == TypeId::of::() { - let target = Box::into_raw(self.0) as *mut T; - let target = unsafe { Box::from_raw(target) }; - Ok(*target) - } else { - Err(self) - } - } -} - -impl AsRef for ErrBox { - fn as_ref(&self) -> &dyn AnyError { - self.0.as_ref() - } -} - -impl Deref for ErrBox { - type Target = Box; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From for ErrBox { - fn from(error: T) -> Self { - Self(Box::new(error)) - } -} - -impl From> for ErrBox { - fn from(boxed: Box) -> Self { - Self(boxed) - } -} - -impl fmt::Display for ErrBox { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} diff --git a/core/bindings.rs b/core/bindings.rs index 16e78e368f..22f6767e85 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -1,9 +1,9 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::es_isolate::EsIsolate; -use crate::isolate::CoreIsolate; -use crate::isolate::ZeroCopyBuf; -use crate::js_errors::JSError; +use crate::CoreIsolate; +use crate::EsIsolate; +use crate::JSError; +use crate::ZeroCopyBuf; use rusty_v8 as v8; use v8::MapFnTo; diff --git a/core/isolate.rs b/core/core_isolate.rs similarity index 93% rename from core/isolate.rs rename to core/core_isolate.rs index 13892c2d9a..12495e2d22 100644 --- a/core/isolate.rs +++ b/core/core_isolate.rs @@ -7,13 +7,14 @@ use rusty_v8 as v8; -use crate::any_error::ErrBox; use crate::bindings; -use crate::js_errors::JSError; use crate::ops::*; use crate::shared_queue::SharedQueue; use crate::shared_queue::RECOMMENDED_SIZE; +use crate::ErrBox; +use crate::JSError; use crate::ResourceTable; +use crate::ZeroCopyBuf; use futures::future::FutureExt; use futures::stream::select; use futures::stream::FuturesUnordered; @@ -24,10 +25,7 @@ use libc::c_void; use std::cell::RefCell; use std::collections::HashMap; use std::convert::From; -use std::error::Error; -use std::fmt; use std::mem::forget; -use std::ops::{Deref, DerefMut}; use std::option::Option; use std::pin::Pin; use std::rc::Rc; @@ -37,69 +35,6 @@ use std::task::Poll; type PendingOpFuture = Pin>>; -/// A ZeroCopyBuf encapsulates a slice that's been borrowed from a JavaScript -/// ArrayBuffer object. JavaScript objects can normally be garbage collected, -/// but the existence of a ZeroCopyBuf inhibits this until it is dropped. It -/// behaves much like an Arc<[u8]>, although a ZeroCopyBuf currently can't be -/// cloned. -pub struct ZeroCopyBuf { - backing_store: v8::SharedRef, - byte_offset: usize, - byte_length: usize, -} - -unsafe impl Send for ZeroCopyBuf {} - -impl ZeroCopyBuf { - pub fn new(view: v8::Local) -> Self { - let backing_store = view.buffer().unwrap().get_backing_store(); - let byte_offset = view.byte_offset(); - let byte_length = view.byte_length(); - Self { - backing_store, - byte_offset, - byte_length, - } - } -} - -impl Deref for ZeroCopyBuf { - type Target = [u8]; - fn deref(&self) -> &[u8] { - 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] { - unsafe { - bindings::get_backing_store_slice_mut( - &self.backing_store, - self.byte_offset, - self.byte_length, - ) - } - } -} - -impl AsRef<[u8]> for ZeroCopyBuf { - fn as_ref(&self) -> &[u8] { - &*self - } -} - -impl AsMut<[u8]> for ZeroCopyBuf { - fn as_mut(&mut self) -> &mut [u8] { - &mut *self - } -} - /// Stores a script used to initialize a Isolate pub struct Script<'a> { pub source: &'a str, @@ -627,14 +562,6 @@ fn drain_macrotasks<'s>( Ok(()) } -pub(crate) fn attach_handle_to_error( - scope: &mut impl v8::InIsolate, - err: ErrBox, - handle: v8::Local, -) -> ErrBox { - ErrWithV8Handle::new(scope, err, handle).into() -} - pub(crate) fn exception_to_err_result<'s, T>( scope: &mut impl v8::ToLocal<'s>, exception: v8::Local, @@ -1183,42 +1110,3 @@ pub mod tests { js_check(isolate2.execute("check.js", "if (a != 3) throw Error('x')")); } } - -// TODO(piscisaureus): rusty_v8 should implement the Error trait on -// values of type v8::Global. -pub struct ErrWithV8Handle { - err: ErrBox, - handle: v8::Global, -} - -impl ErrWithV8Handle { - pub fn new( - scope: &mut impl v8::InIsolate, - err: ErrBox, - handle: v8::Local, - ) -> Self { - let handle = v8::Global::new_from(scope, handle); - Self { err, handle } - } - - pub fn get_handle(&self) -> &v8::Global { - &self.handle - } -} - -unsafe impl Send for ErrWithV8Handle {} -unsafe impl Sync for ErrWithV8Handle {} - -impl Error for ErrWithV8Handle {} - -impl fmt::Display for ErrWithV8Handle { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.err.fmt(f) - } -} - -impl fmt::Debug for ErrWithV8Handle { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.err.fmt(f) - } -} diff --git a/core/js_errors.rs b/core/errors.rs similarity index 81% rename from core/js_errors.rs rename to core/errors.rs index e8ea5a342f..bc821b266f 100644 --- a/core/js_errors.rs +++ b/core/errors.rs @@ -1,11 +1,76 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::ErrBox; use rusty_v8 as v8; +use std::any::Any; +use std::any::TypeId; use std::convert::TryFrom; use std::convert::TryInto; use std::error::Error; use std::fmt; +use std::ops::Deref; + +// The Send and Sync traits are required because deno is multithreaded and we +// need to be able to handle errors across threads. +pub trait AnyError: Any + Error + Send + Sync + 'static {} +impl AnyError for T where T: Any + Error + Send + Sync + Sized + 'static {} + +#[derive(Debug)] +pub struct ErrBox(Box); + +impl dyn AnyError { + pub fn downcast_ref(&self) -> Option<&T> { + if Any::type_id(self) == TypeId::of::() { + let target = self as *const Self as *const T; + let target = unsafe { &*target }; + Some(target) + } else { + None + } + } +} + +impl ErrBox { + pub fn downcast(self) -> Result { + if Any::type_id(&*self.0) == TypeId::of::() { + let target = Box::into_raw(self.0) as *mut T; + let target = unsafe { Box::from_raw(target) }; + Ok(*target) + } else { + Err(self) + } + } +} + +impl AsRef for ErrBox { + fn as_ref(&self) -> &dyn AnyError { + self.0.as_ref() + } +} + +impl Deref for ErrBox { + type Target = Box; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for ErrBox { + fn from(error: T) -> Self { + Self(Box::new(error)) + } +} + +impl From> for ErrBox { + fn from(boxed: Box) -> Self { + Self(boxed) + } +} + +impl fmt::Display for ErrBox { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} /// A `JSError` represents an exception coming from V8, with stack frames and /// line numbers. The deno_cli crate defines another `JSError` type, which wraps @@ -298,3 +363,50 @@ impl fmt::Display for JSError { Ok(()) } } + +pub(crate) fn attach_handle_to_error( + scope: &mut impl v8::InIsolate, + err: ErrBox, + handle: v8::Local, +) -> ErrBox { + ErrWithV8Handle::new(scope, err, handle).into() +} + +// TODO(piscisaureus): rusty_v8 should implement the Error trait on +// values of type v8::Global. +pub struct ErrWithV8Handle { + err: ErrBox, + handle: v8::Global, +} + +impl ErrWithV8Handle { + pub fn new( + scope: &mut impl v8::InIsolate, + err: ErrBox, + handle: v8::Local, + ) -> Self { + let handle = v8::Global::new_from(scope, handle); + Self { err, handle } + } + + pub fn get_handle(&self) -> &v8::Global { + &self.handle + } +} + +unsafe impl Send for ErrWithV8Handle {} +unsafe impl Sync for ErrWithV8Handle {} + +impl Error for ErrWithV8Handle {} + +impl fmt::Display for ErrWithV8Handle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.err.fmt(f) + } +} + +impl fmt::Debug for ErrWithV8Handle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.err.fmt(f) + } +} diff --git a/core/es_isolate.rs b/core/es_isolate.rs index 73ff1c388d..a3775c8a43 100644 --- a/core/es_isolate.rs +++ b/core/es_isolate.rs @@ -6,10 +6,10 @@ use rusty_v8 as v8; -use crate::any_error::ErrBox; use crate::bindings; +use crate::errors::ErrBox; +use crate::errors::ErrWithV8Handle; use crate::futures::FutureExt; -use crate::ErrWithV8Handle; use futures::ready; use futures::stream::FuturesUnordered; use futures::stream::StreamExt; @@ -26,20 +26,19 @@ use std::rc::Rc; use std::task::Context; use std::task::Poll; -use crate::isolate::attach_handle_to_error; -use crate::isolate::exception_to_err_result; -use crate::isolate::CoreIsolate; -use crate::isolate::StartupData; +use crate::core_isolate::exception_to_err_result; +use crate::errors::attach_handle_to_error; use crate::module_specifier::ModuleSpecifier; use crate::modules::LoadState; +use crate::modules::ModuleId; +use crate::modules::ModuleLoadId; use crate::modules::ModuleLoader; use crate::modules::ModuleSource; use crate::modules::Modules; use crate::modules::PrepareLoadFuture; use crate::modules::RecursiveModuleLoad; - -pub type ModuleId = i32; -pub type ModuleLoadId = i32; +use crate::CoreIsolate; +use crate::StartupData; /// More specialized version of `CoreIsolate` that provides loading /// and execution of ES Modules. @@ -597,11 +596,11 @@ impl Future for EsIsolate { #[cfg(test)] pub mod tests { use super::*; - use crate::isolate::js_check; - use crate::isolate::tests::run_in_task; - use crate::isolate::ZeroCopyBuf; + use crate::core_isolate::tests::run_in_task; + use crate::js_check; use crate::modules::ModuleSourceFuture; use crate::ops::*; + use crate::ZeroCopyBuf; use std::io; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; diff --git a/core/lib.rs b/core/lib.rs index ffccc8febb..49d49e19d8 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -8,30 +8,44 @@ extern crate lazy_static; #[macro_use] extern crate log; -mod any_error; mod bindings; +mod core_isolate; +mod errors; mod es_isolate; mod flags; -mod isolate; -mod js_errors; mod module_specifier; mod modules; mod ops; pub mod plugin_api; mod resources; mod shared_queue; +mod zero_copy_buf; pub use rusty_v8 as v8; -pub use crate::any_error::*; -pub use crate::es_isolate::*; +pub use crate::core_isolate::js_check; +pub use crate::core_isolate::CoreIsolate; +pub use crate::core_isolate::Script; +pub use crate::core_isolate::Snapshot; +pub use crate::core_isolate::StartupData; +pub use crate::errors::ErrBox; +pub use crate::errors::JSError; +pub use crate::es_isolate::EsIsolate; pub use crate::flags::v8_set_flags; -pub use crate::isolate::*; -pub use crate::js_errors::*; -pub use crate::module_specifier::*; -pub use crate::modules::*; -pub use crate::ops::*; -pub use crate::resources::*; +pub use crate::module_specifier::ModuleResolutionError; +pub use crate::module_specifier::ModuleSpecifier; +pub use crate::modules::ModuleId; +pub use crate::modules::ModuleLoadId; +pub use crate::modules::ModuleLoader; +pub use crate::modules::ModuleSource; +pub use crate::modules::ModuleSourceFuture; +pub use crate::modules::RecursiveModuleLoad; +pub use crate::ops::Buf; +pub use crate::ops::Op; +pub use crate::ops::OpAsyncFuture; +pub use crate::ops::OpId; +pub use crate::resources::ResourceTable; +pub use crate::zero_copy_buf::ZeroCopyBuf; pub fn v8_version() -> &'static str { v8::V8::get_version() diff --git a/core/modules.rs b/core/modules.rs index 632df2dd00..5a00d92cc2 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -2,10 +2,8 @@ use rusty_v8 as v8; -use crate::any_error::ErrBox; -use crate::es_isolate::ModuleId; -use crate::es_isolate::ModuleLoadId; use crate::module_specifier::ModuleSpecifier; +use crate::ErrBox; use futures::future::FutureExt; use futures::stream::FuturesUnordered; use futures::stream::Stream; @@ -25,6 +23,9 @@ lazy_static! { pub static ref NEXT_LOAD_ID: AtomicI32 = AtomicI32::new(0); } +pub type ModuleId = i32; +pub type ModuleLoadId = i32; + /// EsModule source code that will be loaded into V8. /// /// Users can implement `Into` for different file types that @@ -548,7 +549,8 @@ macro_rules! include_crate_modules { mod tests { use super::*; use crate::es_isolate::EsIsolate; - use crate::isolate::js_check; + use crate::js_check; + use crate::StartupData; use futures::future::FutureExt; use std::error::Error; use std::fmt; @@ -556,6 +558,12 @@ mod tests { use std::sync::Arc; use std::sync::Mutex; + // TODO(ry) Sadly FuturesUnordered requires the current task to be set. So + // even though we are only using poll() in these tests and not Tokio, we must + // nevertheless run it in the tokio executor. Ideally run_in_task can be + // removed in the future. + use crate::core_isolate::tests::run_in_task; + struct MockLoader { pub loads: Arc>>, } @@ -716,13 +724,6 @@ mod tests { if (import.meta.url != 'file:///d.js') throw Error(); "#; - // TODO(ry) Sadly FuturesUnordered requires the current task to be set. So - // even though we are only using poll() in these tests and not Tokio, we must - // nevertheless run it in the tokio executor. Ideally run_in_task can be - // removed in the future. - use crate::isolate::tests::run_in_task; - use crate::isolate::StartupData; - #[test] fn test_recursive_load() { let loader = MockLoader::new(); diff --git a/core/zero_copy_buf.rs b/core/zero_copy_buf.rs new file mode 100644 index 0000000000..b10c14045b --- /dev/null +++ b/core/zero_copy_buf.rs @@ -0,0 +1,67 @@ +use crate::bindings; +use rusty_v8 as v8; +use std::ops::Deref; +use std::ops::DerefMut; + +/// A ZeroCopyBuf encapsulates a slice that's been borrowed from a JavaScript +/// ArrayBuffer object. JavaScript objects can normally be garbage collected, +/// but the existence of a ZeroCopyBuf inhibits this until it is dropped. It +/// behaves much like an Arc<[u8]>, although a ZeroCopyBuf currently can't be +/// cloned. +pub struct ZeroCopyBuf { + backing_store: v8::SharedRef, + byte_offset: usize, + byte_length: usize, +} + +unsafe impl Send for ZeroCopyBuf {} + +impl ZeroCopyBuf { + pub fn new(view: v8::Local) -> Self { + let backing_store = view.buffer().unwrap().get_backing_store(); + let byte_offset = view.byte_offset(); + let byte_length = view.byte_length(); + Self { + backing_store, + byte_offset, + byte_length, + } + } +} + +impl Deref for ZeroCopyBuf { + type Target = [u8]; + fn deref(&self) -> &[u8] { + 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] { + unsafe { + bindings::get_backing_store_slice_mut( + &self.backing_store, + self.byte_offset, + self.byte_length, + ) + } + } +} + +impl AsRef<[u8]> for ZeroCopyBuf { + fn as_ref(&self) -> &[u8] { + &*self + } +} + +impl AsMut<[u8]> for ZeroCopyBuf { + fn as_mut(&mut self) -> &mut [u8] { + &mut *self + } +}