diff options
Diffstat (limited to 'core/isolate.rs')
-rw-r--r-- | core/isolate.rs | 148 |
1 files changed, 84 insertions, 64 deletions
diff --git a/core/isolate.rs b/core/isolate.rs index 2e6406e56..38f7b7987 100644 --- a/core/isolate.rs +++ b/core/isolate.rs @@ -4,7 +4,9 @@ // isolate to keep the Isolate struct from becoming too bloating for users who // do not need asynchronous module loading. -use crate::js_errors::JSError; +use crate::any_error::ErrBox; +use crate::js_errors::CoreJSError; +use crate::js_errors::V8Exception; use crate::libdeno; use crate::libdeno::deno_buf; use crate::libdeno::deno_dyn_import_id; @@ -81,6 +83,8 @@ type CoreDispatchFn = dyn Fn(&[u8], Option<PinnedBuf>) -> CoreOp; pub type DynImportFuture = Box<dyn Future<Item = deno_mod, Error = ()> + Send>; type DynImportFn = dyn Fn(&str, &str) -> DynImportFuture; +type JSErrorCreateFn = dyn Fn(V8Exception) -> ErrBox; + /// Wraps DynImportFuture to include the deno_dyn_import_id, so that it doesn't /// need to be exposed. struct DynImport { @@ -114,6 +118,7 @@ pub struct Isolate { shared_libdeno_isolate: Arc<Mutex<Option<*const libdeno::isolate>>>, dispatch: Option<Arc<CoreDispatchFn>>, dyn_import: Option<Arc<DynImportFn>>, + js_error_create: Arc<JSErrorCreateFn>, needs_init: bool, shared: SharedQueue, pending_ops: FuturesUnordered<CoreOpAsyncFuture>, @@ -178,6 +183,7 @@ impl Isolate { shared_libdeno_isolate: Arc::new(Mutex::new(Some(libdeno_isolate))), dispatch: None, dyn_import: None, + js_error_create: Arc::new(CoreJSError::from_v8_exception), shared, needs_init, pending_ops: FuturesUnordered::new(), @@ -204,6 +210,16 @@ impl Isolate { self.dyn_import = Some(Arc::new(f)); } + /// Allows a callback to be set whenever a V8 exception is made. This allows + /// the caller to wrap the V8Exception into an error. By default this callback + /// is set to CoreJSError::from_v8_exception. + pub fn set_js_error_create<F>(&mut self, f: F) + where + F: Fn(V8Exception) -> ErrBox + 'static, + { + self.js_error_create = Arc::new(f); + } + /// Get a thread safe handle on the isolate. pub fn shared_isolate_handle(&mut self) -> IsolateHandle { IsolateHandle { @@ -307,11 +323,16 @@ impl Isolate { self as *const _ as *const c_void } + /// Executes traditional JavaScript code (traditional = not ES modules) + /// + /// ErrBox can be downcast to a type that exposes additional information about + /// the V8 exception. By default this type is CoreJSError, however it may be a + /// different type if Isolate::set_js_error_create() has been used. pub fn execute( &mut self, js_filename: &str, js_source: &str, - ) -> Result<(), JSError> { + ) -> Result<(), ErrBox> { self.shared_init(); let filename = CString::new(js_filename).unwrap(); let source = CString::new(js_source).unwrap(); @@ -323,22 +344,20 @@ impl Isolate { source.as_ptr(), ) }; - if let Some(err) = self.last_exception() { - return Err(err); - } - Ok(()) + self.check_last_exception() } - fn last_exception(&self) -> Option<JSError> { + fn check_last_exception(&self) -> Result<(), ErrBox> { let ptr = unsafe { libdeno::deno_last_exception(self.libdeno_isolate) }; if ptr.is_null() { - None + Ok(()) } else { + let js_error_create = &*self.js_error_create; let cstr = unsafe { CStr::from_ptr(ptr) }; - let v8_exception = cstr.to_str().unwrap(); - debug!("v8_exception\n{}\n", v8_exception); - let js_error = JSError::from_v8_exception(v8_exception).unwrap(); - Some(js_error) + let json_str = cstr.to_str().unwrap(); + let v8_exception = V8Exception::from_json(json_str).unwrap(); + let js_error = js_error_create(v8_exception); + Err(js_error) } } @@ -348,7 +367,7 @@ impl Isolate { } } - fn respond(&mut self, maybe_buf: Option<&[u8]>) -> Result<(), JSError> { + fn respond(&mut self, maybe_buf: Option<&[u8]>) -> Result<(), ErrBox> { let buf = match maybe_buf { None => deno_buf::empty(), Some(r) => deno_buf::from(r), @@ -356,11 +375,7 @@ impl Isolate { unsafe { libdeno::deno_respond(self.libdeno_isolate, self.as_raw_ptr(), buf) } - if let Some(err) = self.last_exception() { - Err(err) - } else { - Ok(()) - } + self.check_last_exception() } /// Low-level module creation. @@ -369,7 +384,7 @@ impl Isolate { main: bool, name: &str, source: &str, - ) -> Result<deno_mod, JSError> { + ) -> Result<deno_mod, ErrBox> { let name_ = CString::new(name.to_string()).unwrap(); let name_ptr = name_.as_ptr() as *const libc::c_char; @@ -379,12 +394,11 @@ impl Isolate { let id = unsafe { libdeno::deno_mod_new(self.libdeno_isolate, main, name_ptr, source_ptr) }; - if let Some(js_error) = self.last_exception() { - assert_eq!(id, 0); - return Err(js_error); - } - Ok(id) + self.check_last_exception().map(|_| id).map_err(|err| { + assert_eq!(id, 0); + err + }) } pub fn mod_get_imports(&self, id: deno_mod) -> Vec<String> { @@ -402,23 +416,29 @@ impl Isolate { out } - pub fn snapshot(&self) -> Result<Snapshot1<'static>, JSError> { + /// Takes a snapshot. The isolate should have been created with will_snapshot + /// set to true. + /// + /// ErrBox can be downcast to a type that exposes additional information about + /// the V8 exception. By default this type is CoreJSError, however it may be a + /// different type if Isolate::set_js_error_create() has been used. + pub fn snapshot(&self) -> Result<Snapshot1<'static>, ErrBox> { let snapshot = unsafe { libdeno::deno_snapshot_new(self.libdeno_isolate) }; - if let Some(js_error) = self.last_exception() { - assert_eq!(snapshot.data_ptr, null()); - assert_eq!(snapshot.data_len, 0); - return Err(js_error); + match self.check_last_exception() { + Ok(..) => Ok(snapshot), + Err(err) => { + assert_eq!(snapshot.data_ptr, null()); + assert_eq!(snapshot.data_len, 0); + Err(err) + } } - assert_ne!(snapshot.data_ptr, null()); - assert_ne!(snapshot.data_len, 0); - Ok(snapshot) } fn dyn_import_done( &self, id: libdeno::deno_dyn_import_id, mod_id: deno_mod, - ) -> Result<(), JSError> { + ) -> Result<(), ErrBox> { debug!("dyn_import_done {} {}", id, mod_id); unsafe { libdeno::deno_dyn_import( @@ -428,11 +448,10 @@ impl Isolate { mod_id, ) }; - if let Some(js_error) = self.last_exception() { + self.check_last_exception().map_err(|err| { assert_eq!(id, 0); - return Err(js_error); - } - Ok(()) + err + }) } } @@ -458,11 +477,16 @@ impl<'a> ResolveContext<'a> { } impl Isolate { + /// Instanciates a ES module + /// + /// ErrBox can be downcast to a type that exposes additional information about + /// the V8 exception. By default this type is CoreJSError, however it may be a + /// different type if Isolate::set_js_error_create() has been used. pub fn mod_instantiate( &mut self, id: deno_mod, resolve_fn: &mut ResolveFn, - ) -> Result<(), JSError> { + ) -> Result<(), ErrBox> { let libdeno_isolate = self.libdeno_isolate; let mut ctx = ResolveContext { resolve_fn }; unsafe { @@ -473,11 +497,7 @@ impl Isolate { Self::resolve_cb, ) }; - - if let Some(js_error) = self.last_exception() { - return Err(js_error); - } - Ok(()) + self.check_last_exception() } /// Called during mod_instantiate() only. @@ -494,15 +514,17 @@ impl Isolate { resolve_fn(specifier, referrer) } - pub fn mod_evaluate(&mut self, id: deno_mod) -> Result<(), JSError> { + /// Evaluates an already instantiated ES module. + /// + /// ErrBox can be downcast to a type that exposes additional information about + /// the V8 exception. By default this type is CoreJSError, however it may be a + /// different type if Isolate::set_js_error_create() has been used. + pub fn mod_evaluate(&mut self, id: deno_mod) -> Result<(), ErrBox> { self.shared_init(); unsafe { libdeno::deno_mod_evaluate(self.libdeno_isolate, self.as_raw_ptr(), id) }; - if let Some(js_error) = self.last_exception() { - return Err(js_error); - } - Ok(()) + self.check_last_exception() } } @@ -525,9 +547,9 @@ impl Drop for LockerScope { impl Future for Isolate { type Item = (); - type Error = JSError; + type Error = ErrBox; - fn poll(&mut self) -> Poll<(), JSError> { + fn poll(&mut self) -> Poll<(), ErrBox> { // Lock the current thread for V8. let _locker = LockerScope::new(self.libdeno_isolate); @@ -579,9 +601,7 @@ impl Future for Isolate { } self.check_promise_errors(); - if let Some(err) = self.last_exception() { - return Err(err); - } + self.check_last_exception()?; // We're idle if pending_ops is empty. if self.pending_ops.is_empty() { @@ -616,7 +636,7 @@ impl IsolateHandle { } } -pub fn js_check(r: Result<(), JSError>) { +pub fn js_check(r: Result<(), ErrBox>) { if let Err(e) = r { panic!(e.to_string()); } @@ -814,7 +834,7 @@ pub mod tests { "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); - assert_eq!(Ok(Async::Ready(())), isolate.poll()); + assert_eq!(Async::Ready(()), isolate.poll().unwrap()); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); js_check(isolate.execute( "check2.js", @@ -825,11 +845,11 @@ pub mod tests { "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 2); - assert_eq!(Ok(Async::Ready(())), isolate.poll()); + assert_eq!(Async::Ready(()), isolate.poll().unwrap()); js_check(isolate.execute("check3.js", "assert(nrecv == 2)")); assert_eq!(dispatch_count.load(Ordering::Relaxed), 2); // We are idle, so the next poll should be the last. - assert_eq!(Ok(Async::Ready(())), isolate.poll()); + assert_eq!(Async::Ready(()), isolate.poll().unwrap()); }); } @@ -865,7 +885,7 @@ pub mod tests { "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 2); - assert_eq!(Ok(Async::Ready(())), isolate.poll()); + assert_eq!(Async::Ready(()), isolate.poll().unwrap()); js_check(isolate.execute("send1.js", "assert(nrecv === 2);")); }); } @@ -949,9 +969,9 @@ pub mod tests { )); assert_eq!(count.load(Ordering::Relaxed), 1); - assert_eq!(Ok(Ready(())), isolate.poll()); + assert_eq!(Ready(()), isolate.poll().unwrap()); assert_eq!(count.load(Ordering::Relaxed), 2); - assert_eq!(Ok(Ready(())), isolate.poll()); + assert_eq!(Ready(()), isolate.poll().unwrap()); assert_eq!(count.load(Ordering::Relaxed), 2); }) } @@ -1090,7 +1110,7 @@ pub mod tests { "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); - assert_eq!(Ok(Async::Ready(())), isolate.poll()); + assert_eq!(Async::Ready(()), isolate.poll().unwrap()); js_check(isolate.execute("check.js", "assert(asyncRecv == 1);")); }); } @@ -1118,7 +1138,7 @@ pub mod tests { "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); - assert_eq!(Ok(()), poll_until_ready(&mut isolate, 3)); + poll_until_ready(&mut isolate, 3).unwrap(); js_check(isolate.execute("check.js", "assert(asyncRecv == 1);")); }); } @@ -1149,7 +1169,7 @@ pub mod tests { "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 2); - assert_eq!(Ok(()), poll_until_ready(&mut isolate, 3)); + poll_until_ready(&mut isolate, 3).unwrap(); js_check(isolate.execute("check.js", "assert(asyncRecv == 2);")); }); } @@ -1164,7 +1184,7 @@ pub mod tests { include_str!("shared_queue_test.js"), ), ); - assert_eq!(Ok(Async::Ready(())), isolate.poll()); + assert_eq!(Async::Ready(()), isolate.poll().unwrap()); }); } |