diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/Cargo.toml | 1 | ||||
-rw-r--r-- | core/bindings.rs | 53 | ||||
-rw-r--r-- | core/core_isolate.rs | 61 | ||||
-rw-r--r-- | core/es_isolate.rs | 8 | ||||
-rw-r--r-- | core/examples/http_bench.rs | 19 | ||||
-rw-r--r-- | core/ops.rs | 18 | ||||
-rw-r--r-- | core/plugin_api.rs | 2 | ||||
-rw-r--r-- | core/zero_copy_buf.rs | 10 |
8 files changed, 75 insertions, 97 deletions
diff --git a/core/Cargo.toml b/core/Cargo.toml index 6b73cc02a..038b81580 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -21,6 +21,7 @@ libc = "0.2.71" log = "0.4.8" rusty_v8 = "0.6.0" serde_json = "1.0.55" +smallvec = "1.4.0" url = "2.1.1" [[example]] diff --git a/core/bindings.rs b/core/bindings.rs index 6407cb555..0d0a633a5 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -8,6 +8,7 @@ use crate::ZeroCopyBuf; use rusty_v8 as v8; use v8::MapFnTo; +use smallvec::SmallVec; use std::cell::Cell; use std::convert::TryFrom; use std::option::Option; @@ -388,24 +389,11 @@ fn send( } }; - let control_backing_store: v8::SharedRef<v8::BackingStore>; - let control = match v8::Local::<v8::ArrayBufferView>::try_from(args.get(1)) { - Ok(view) => unsafe { - control_backing_store = view.buffer(scope).unwrap().get_backing_store(); - get_backing_store_slice( - &control_backing_store, - view.byte_offset(), - view.byte_length(), - ) - }, - Err(_) => &[], - }; - let state_rc = CoreIsolate::state(scope); let mut state = state_rc.borrow_mut(); assert!(!state.global_context.is_empty()); - let mut buf_iter = (2..args.length()).map(|idx| { + let buf_iter = (1..args.length()).map(|idx| { v8::Local::<v8::ArrayBufferView>::try_from(args.get(idx)) .map(|view| ZeroCopyBuf::new(scope, view)) .map_err(|err| { @@ -415,36 +403,15 @@ fn send( }) }); - let mut buf_one: ZeroCopyBuf; - let mut buf_vec: Vec<ZeroCopyBuf>; - - // Collect all ArrayBufferView's - let buf_iter_result = match buf_iter.len() { - 0 => Ok(&mut [][..]), - 1 => match buf_iter.next().unwrap() { - Ok(buf) => { - buf_one = buf; - Ok(std::slice::from_mut(&mut buf_one)) + // If response is empty then it's either async op or exception was thrown. + let maybe_response = + match buf_iter.collect::<Result<SmallVec<[ZeroCopyBuf; 2]>, _>>() { + Ok(mut bufs) => state.dispatch_op(scope, op_id, &mut bufs), + Err(exc) => { + scope.throw_exception(exc); + return; } - Err(err) => Err(err), - }, - _ => match buf_iter.collect::<Result<Vec<_>, _>>() { - Ok(v) => { - buf_vec = v; - Ok(&mut buf_vec[..]) - } - Err(err) => Err(err), - }, - }; - - // If response is empty then it's either async op or exception was thrown - let maybe_response = match buf_iter_result { - Ok(bufs) => state.dispatch_op(scope, op_id, control, bufs), - Err(exc) => { - scope.throw_exception(exc); - return; - } - }; + }; if let Some(response) = maybe_response { // Synchronous response. diff --git a/core/core_isolate.rs b/core/core_isolate.rs index bb1807f62..ffe75c00c 100644 --- a/core/core_isolate.rs +++ b/core/core_isolate.rs @@ -350,7 +350,7 @@ impl CoreIsolate { /// Requires runtime to explicitly ask for op ids before using any of the ops. pub fn register_op<F>(&mut self, name: &str, op: F) -> OpId where - F: Fn(&mut CoreIsolateState, &[u8], &mut [ZeroCopyBuf]) -> Op + 'static, + F: Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op + 'static, { let state_rc = Self::state(self); let mut state = state_rc.borrow_mut(); @@ -466,7 +466,7 @@ impl CoreIsolateState { /// Requires runtime to explicitly ask for op ids before using any of the ops. pub fn register_op<F>(&mut self, name: &str, op: F) -> OpId where - F: Fn(&mut CoreIsolateState, &[u8], &mut [ZeroCopyBuf]) -> Op + 'static, + F: Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op + 'static, { self.op_registry.register(name, op) } @@ -485,11 +485,10 @@ impl CoreIsolateState { &mut self, scope: &mut v8::HandleScope<'s>, op_id: OpId, - control_buf: &[u8], zero_copy_bufs: &mut [ZeroCopyBuf], ) -> Option<(OpId, Box<[u8]>)> { let op = if let Some(dispatcher) = self.op_registry.get(op_id) { - dispatcher(self, control_buf, zero_copy_bufs) + dispatcher(self, zero_copy_bufs) } else { let message = v8::String::new(scope, &format!("Unknown op id: {}", op_id)).unwrap(); @@ -704,20 +703,21 @@ pub mod tests { let mut isolate = CoreIsolate::new(StartupData::None, false); let dispatcher = move |_state: &mut CoreIsolateState, - control: &[u8], zero_copy: &mut [ZeroCopyBuf]| -> Op { dispatch_count_.fetch_add(1, Ordering::Relaxed); match mode { Mode::Async => { - assert_eq!(control.len(), 1); - assert_eq!(control[0], 42); + assert_eq!(zero_copy.len(), 1); + assert_eq!(zero_copy[0].len(), 1); + assert_eq!(zero_copy[0][0], 42); let buf = vec![43u8].into_boxed_slice(); Op::Async(futures::future::ready(buf).boxed()) } Mode::AsyncUnref => { - assert_eq!(control.len(), 1); - assert_eq!(control[0], 42); + assert_eq!(zero_copy.len(), 1); + assert_eq!(zero_copy[0].len(), 1); + assert_eq!(zero_copy[0][0], 42); let fut = async { // This future never finish. futures::future::pending::<()>().await; @@ -726,8 +726,6 @@ pub mod tests { Op::AsyncUnref(fut.boxed()) } Mode::AsyncZeroCopy(count) => { - assert_eq!(control.len(), 1); - assert_eq!(control[0], 24); assert_eq!(zero_copy.len(), count as usize); zero_copy.iter().enumerate().for_each(|(idx, buf)| { assert_eq!(buf.len(), 1); @@ -738,13 +736,15 @@ pub mod tests { Op::Async(futures::future::ready(buf).boxed()) } Mode::OverflowReqSync => { - assert_eq!(control.len(), 100 * 1024 * 1024); + assert_eq!(zero_copy.len(), 1); + assert_eq!(zero_copy[0].len(), 100 * 1024 * 1024); let buf = vec![43u8].into_boxed_slice(); Op::Sync(buf) } Mode::OverflowResSync => { - assert_eq!(control.len(), 1); - assert_eq!(control[0], 42); + assert_eq!(zero_copy.len(), 1); + assert_eq!(zero_copy[0].len(), 1); + assert_eq!(zero_copy[0][0], 42); let mut vec = Vec::<u8>::new(); vec.resize(100 * 1024 * 1024, 0); vec[0] = 99; @@ -752,13 +752,15 @@ pub mod tests { Op::Sync(buf) } Mode::OverflowReqAsync => { - assert_eq!(control.len(), 100 * 1024 * 1024); + assert_eq!(zero_copy.len(), 1); + assert_eq!(zero_copy[0].len(), 100 * 1024 * 1024); let buf = vec![43u8].into_boxed_slice(); Op::Async(futures::future::ready(buf).boxed()) } Mode::OverflowResAsync => { - assert_eq!(control.len(), 1); - assert_eq!(control[0], 42); + assert_eq!(zero_copy.len(), 1); + assert_eq!(zero_copy[0].len(), 1); + assert_eq!(zero_copy[0][0], 42); let mut vec = Vec::<u8>::new(); vec.resize(100 * 1024 * 1024, 0); vec[0] = 4; @@ -807,37 +809,38 @@ pub mod tests { js_check(isolate.execute( "filename.js", r#" - let control = new Uint8Array([24]); - Deno.core.send(1, control); + Deno.core.send(1); "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); } #[test] - fn test_dispatch_one_zero_copy_buf() { - let (mut isolate, dispatch_count) = setup(Mode::AsyncZeroCopy(1)); + fn test_dispatch_stack_zero_copy_bufs() { + let (mut isolate, dispatch_count) = setup(Mode::AsyncZeroCopy(2)); js_check(isolate.execute( "filename.js", r#" - let control = new Uint8Array([24]); - let zero_copy = new Uint8Array([0]); - Deno.core.send(1, control, zero_copy); + let zero_copy_a = new Uint8Array([0]); + let zero_copy_b = new Uint8Array([1]); + Deno.core.send(1, zero_copy_a, zero_copy_b); "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); } #[test] - fn test_dispatch_two_zero_copy_bufs() { - let (mut isolate, dispatch_count) = setup(Mode::AsyncZeroCopy(2)); + fn test_dispatch_heap_zero_copy_bufs() { + let (mut isolate, dispatch_count) = setup(Mode::AsyncZeroCopy(5)); js_check(isolate.execute( "filename.js", r#" - let control = new Uint8Array([24]); let zero_copy_a = new Uint8Array([0]); let zero_copy_b = new Uint8Array([1]); - Deno.core.send(1, control, zero_copy_a, zero_copy_b); + let zero_copy_c = new Uint8Array([2]); + let zero_copy_d = new Uint8Array([3]); + let zero_copy_e = new Uint8Array([4]); + Deno.core.send(1, zero_copy_a, zero_copy_b, zero_copy_c, zero_copy_d, zero_copy_e); "#, )); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); @@ -1120,7 +1123,7 @@ pub mod tests { r#" let thrown; try { - Deno.core.dispatch(100, []); + Deno.core.dispatch(100); } catch (e) { thrown = e; } diff --git a/core/es_isolate.rs b/core/es_isolate.rs index 5bb1a55c0..a59ba7e92 100644 --- a/core/es_isolate.rs +++ b/core/es_isolate.rs @@ -708,12 +708,12 @@ pub mod tests { let mut isolate = EsIsolate::new(loader, StartupData::None, false); let dispatcher = move |_state: &mut CoreIsolateState, - control: &[u8], - _zero_copy: &mut [ZeroCopyBuf]| + zero_copy: &mut [ZeroCopyBuf]| -> Op { dispatch_count_.fetch_add(1, Ordering::Relaxed); - assert_eq!(control.len(), 1); - assert_eq!(control[0], 42); + assert_eq!(zero_copy.len(), 1); + assert_eq!(zero_copy[0].len(), 1); + assert_eq!(zero_copy[0][0], 42); let buf = vec![43u8, 0, 0, 0].into_boxed_slice(); Op::Async(futures::future::ready(buf).boxed()) }; diff --git a/core/examples/http_bench.rs b/core/examples/http_bench.rs index 233864fac..92e69d215 100644 --- a/core/examples/http_bench.rs +++ b/core/examples/http_bench.rs @@ -117,18 +117,19 @@ impl Isolate { { let state = self.state.clone(); let core_handler = move |_isolate_state: &mut CoreIsolateState, - control_buf: &[u8], zero_copy_bufs: &mut [ZeroCopyBuf]| -> Op { + assert!(!zero_copy_bufs.is_empty()); let state = state.clone(); - let record = Record::from(control_buf); + let record = Record::from(zero_copy_bufs[0].as_ref()); let is_sync = record.promise_id == 0; assert!(is_sync); - let result: i32 = match handler(state, record.rid, zero_copy_bufs) { - Ok(r) => r as i32, - Err(_) => -1, - }; + let result: i32 = + match handler(state, record.rid, &mut zero_copy_bufs[1..]) { + Ok(r) => r as i32, + Err(_) => -1, + }; let buf = RecordBuf::from(Record { result, ..record })[..].into(); Op::Sync(buf) }; @@ -147,15 +148,15 @@ impl Isolate { { let state = self.state.clone(); let core_handler = move |_isolate_state: &mut CoreIsolateState, - control_buf: &[u8], zero_copy_bufs: &mut [ZeroCopyBuf]| -> Op { + assert!(!zero_copy_bufs.is_empty()); let state = state.clone(); - let record = Record::from(control_buf); + let record = Record::from(zero_copy_bufs[0].as_ref()); let is_sync = record.promise_id == 0; assert!(!is_sync); - let mut zero_copy = zero_copy_bufs.to_vec(); + let mut zero_copy = zero_copy_bufs[1..].to_vec(); let fut = async move { let op = handler(state, record.rid, &mut zero_copy); let result = op diff --git a/core/ops.rs b/core/ops.rs index eb995df6e..65a0f325b 100644 --- a/core/ops.rs +++ b/core/ops.rs @@ -22,7 +22,7 @@ pub enum Op { /// Main type describing op pub type OpDispatcher = - dyn Fn(&mut CoreIsolateState, &[u8], &mut [ZeroCopyBuf]) -> Op + 'static; + dyn Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op + 'static; #[derive(Default)] pub struct OpRegistry { @@ -33,7 +33,7 @@ pub struct OpRegistry { impl OpRegistry { pub fn new() -> Self { let mut registry = Self::default(); - let op_id = registry.register("ops", |state, _, _| { + let op_id = registry.register("ops", |state, _| { let buf = state.op_registry.json_map(); Op::Sync(buf) }); @@ -43,7 +43,7 @@ impl OpRegistry { pub fn register<F>(&mut self, name: &str, op: F) -> OpId where - F: Fn(&mut CoreIsolateState, &[u8], &mut [ZeroCopyBuf]) -> Op + 'static, + F: Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op + 'static, { let op_id = self.dispatchers.len() as u32; @@ -81,7 +81,7 @@ fn test_op_registry() { let c = Arc::new(atomic::AtomicUsize::new(0)); let c_ = c.clone(); - let test_id = op_registry.register("test", move |_, _, _| { + let test_id = op_registry.register("test", move |_, _| { c_.fetch_add(1, atomic::Ordering::SeqCst); Op::Sync(Box::new([])) }); @@ -97,7 +97,7 @@ fn test_op_registry() { let dispatch = op_registry.get(test_id).unwrap(); let state_rc = CoreIsolate::state(&isolate); let mut state = state_rc.borrow_mut(); - let res = dispatch(&mut state, &[], &mut []); + let res = dispatch(&mut state, &mut []); if let Op::Sync(buf) = res { assert_eq!(buf.len(), 0); } else { @@ -127,10 +127,10 @@ fn register_op_during_call() { let test_id = { let mut g = op_registry.lock().unwrap(); - g.register("dynamic_register_op", move |_, _, _| { + g.register("dynamic_register_op", move |_, _| { let c__ = c_.clone(); let mut g = op_registry_.lock().unwrap(); - g.register("test", move |_, _, _| { + g.register("test", move |_, _| { c__.fetch_add(1, atomic::Ordering::SeqCst); Op::Sync(Box::new([])) }); @@ -148,7 +148,7 @@ fn register_op_during_call() { { let state_rc = CoreIsolate::state(&isolate); let mut state = state_rc.borrow_mut(); - dispatcher1(&mut state, &[], &mut []); + dispatcher1(&mut state, &mut []); } let mut expected = HashMap::new(); @@ -166,7 +166,7 @@ fn register_op_during_call() { }; let state_rc = CoreIsolate::state(&isolate); let mut state = state_rc.borrow_mut(); - let res = dispatcher2(&mut state, &[], &mut []); + let res = dispatcher2(&mut state, &mut []); if let Op::Sync(buf) = res { assert_eq!(buf.len(), 0); } else { diff --git a/core/plugin_api.rs b/core/plugin_api.rs index 16f5d4a36..0cb9acaeb 100644 --- a/core/plugin_api.rs +++ b/core/plugin_api.rs @@ -15,7 +15,7 @@ pub use crate::ZeroCopyBuf; pub type InitFn = fn(&mut dyn Interface); -pub type DispatchOpFn = fn(&mut dyn Interface, &[u8], &mut [ZeroCopyBuf]) -> Op; +pub type DispatchOpFn = fn(&mut dyn Interface, &mut [ZeroCopyBuf]) -> Op; pub trait Interface { fn register_op(&mut self, name: &str, dispatcher: DispatchOpFn) -> OpId; diff --git a/core/zero_copy_buf.rs b/core/zero_copy_buf.rs index a458e12ff..a2625b8aa 100644 --- a/core/zero_copy_buf.rs +++ b/core/zero_copy_buf.rs @@ -6,8 +6,14 @@ 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. +/// behaves much like an Arc<[u8]>. +/// +/// # Cloning +/// Cloning a ZeroCopyBuf does not clone the contents of the buffer, +/// it creates a new reference to that buffer. +/// +/// To actually clone the contents of the buffer do +/// `let copy = Vec::from(&*zero_copy_buf);` #[derive(Clone)] pub struct ZeroCopyBuf { backing_store: v8::SharedRef<v8::BackingStore>, |