diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/http_bench.js | 26 | ||||
-rw-r--r-- | core/http_bench.rs | 4 | ||||
-rw-r--r-- | core/isolate.rs | 307 | ||||
-rw-r--r-- | core/lib.rs | 2 | ||||
-rwxr-xr-x[l---------] | core/libdeno.rs | 189 | ||||
-rw-r--r-- | core/shared_queue.js | 40 | ||||
-rw-r--r-- | core/shared_queue.rs | 59 | ||||
-rw-r--r-- | core/shared_queue_test.js | 2 | ||||
-rw-r--r-- | core/test_util.rs | 51 |
9 files changed, 505 insertions, 175 deletions
diff --git a/core/http_bench.js b/core/http_bench.js index e5598c06f..d7cffcb75 100644 --- a/core/http_bench.js +++ b/core/http_bench.js @@ -37,21 +37,12 @@ const scratchBytes = new Uint8Array( ); assert(scratchBytes.byteLength === 4 * 4); -// Toggle what method we send with. false = legacy. -// AFAICT This has no effect on performance. -const sendWithShared = true; - function send(promiseId, opId, arg, zeroCopy = null) { scratch32[0] = promiseId; scratch32[1] = opId; scratch32[2] = arg; scratch32[3] = -1; - if (sendWithShared) { - Deno._sharedQueue.push(scratchBytes); - libdeno.send(null, zeroCopy); - } else { - libdeno.send(scratchBytes, zeroCopy); - } + return DenoCore.dispatch(scratchBytes, zeroCopy); } /** Returns Promise<number> */ @@ -74,19 +65,10 @@ function recordFromBuf(buf) { }; } -function recv() { - const buf = Deno._sharedQueue.shift(); - if (!buf) { - return null; - } - return recordFromBuf(buf); -} - /** Returns i32 number */ function sendSync(opId, arg) { - send(0, opId, arg); - const record = recv(); - assert(recv() == null); + const buf = send(0, opId, arg); + const record = recordFromBuf(buf); return record.result; } @@ -141,7 +123,7 @@ async function serve(rid) { } async function main() { - Deno._setAsyncHandler(handleAsyncMsgFromRust); + DenoCore.setAsyncHandler(handleAsyncMsgFromRust); libdeno.print("http_bench.js start\n"); diff --git a/core/http_bench.rs b/core/http_bench.rs index ed3792d6a..eb7acc379 100644 --- a/core/http_bench.rs +++ b/core/http_bench.rs @@ -167,9 +167,7 @@ fn main() { let js_source = include_str!("http_bench.js"); let main_future = lazy(move || { - let isolate = deno_core::Isolate::new(HttpBench()); - - isolate.shared_init(); + let mut isolate = deno_core::Isolate::new(HttpBench()); // TODO currently isolate.execute() must be run inside tokio, hence the // lazy(). It would be nice to not have that contraint. Probably requires diff --git a/core/isolate.rs b/core/isolate.rs index ef2da2a68..99e88f553 100644 --- a/core/isolate.rs +++ b/core/isolate.rs @@ -71,6 +71,7 @@ pub trait Behavior { pub struct Isolate<B: Behavior> { libdeno_isolate: *const libdeno::isolate, behavior: B, + needs_init: bool, shared: SharedQueue, pending_ops: Vec<PendingOp>, polled_recently: bool, @@ -94,6 +95,7 @@ impl<B: Behavior> Isolate<B> { let shared = SharedQueue::new(RECOMMENDED_SIZE); + let needs_init = true; let config = libdeno::deno_config { will_snapshot: 0, load_snapshot: match behavior.startup_snapshot() { @@ -109,14 +111,20 @@ impl<B: Behavior> Isolate<B> { libdeno_isolate, behavior, shared, + needs_init, pending_ops: Vec::new(), polled_recently: false, } } /// Executes a bit of built-in JavaScript to provide Deno._sharedQueue. - pub fn shared_init(&self) { - js_check(self.execute("shared_queue.js", include_str!("shared_queue.js"))); + pub fn shared_init(&mut self) { + if self.needs_init { + self.needs_init = false; + js_check( + self.execute("shared_queue.js", include_str!("shared_queue.js")), + ); + } } extern "C" fn pre_dispatch( @@ -151,11 +159,11 @@ impl<B: Behavior> Isolate<B> { if is_sync { let res_record = op.wait().unwrap(); - let push_success = isolate.shared.push(res_record); - assert!(push_success); - // TODO check that if JSError thrown during respond(), that it will be + // For sync messages, we always return the response via libdeno.send's + // return value. + // TODO(ry) check that if JSError thrown during respond(), that it will be // picked up. - let _ = isolate.respond(); + let _ = isolate.respond(Some(&res_record)); } else { isolate.pending_ops.push(PendingOp { op, @@ -184,10 +192,11 @@ impl<B: Behavior> Isolate<B> { } pub fn execute( - &self, + &mut self, js_filename: &str, js_source: &str, ) -> Result<(), JSError> { + self.shared_init(); let filename = CString::new(js_filename).unwrap(); let source = CString::new(js_source).unwrap(); unsafe { @@ -223,8 +232,11 @@ impl<B: Behavior> Isolate<B> { } } - fn respond(&mut self) -> Result<(), JSError> { - let buf = deno_buf::empty(); + fn respond(&mut self, maybe_buf: Option<&[u8]>) -> Result<(), JSError> { + let buf = match maybe_buf { + None => deno_buf::empty(), + Some(r) => deno_buf::from(r), + }; unsafe { libdeno::deno_respond(self.libdeno_isolate, self.as_raw_ptr(), buf) } @@ -290,7 +302,8 @@ impl<B: Behavior> Isolate<B> { Ok(()) } - pub fn mod_evaluate(&self, id: deno_mod) -> Result<(), JSError> { + pub fn mod_evaluate(&mut self, id: deno_mod) -> Result<(), JSError> { + self.shared_init(); unsafe { libdeno::deno_mod_evaluate(self.libdeno_isolate, self.as_raw_ptr(), id) }; @@ -350,8 +363,11 @@ impl<B: Behavior> Future for Isolate<B> { self.polled_recently = true; assert_eq!(self.shared.size(), 0); + let mut overflow_response: Option<Buf> = None; + let mut i = 0; while i < self.pending_ops.len() { + assert!(overflow_response.is_none()); let pending = &mut self.pending_ops[i]; match pending.poll() { Err(()) => panic!("unexpected error"), @@ -360,22 +376,35 @@ impl<B: Behavior> Future for Isolate<B> { } Ok(Async::Ready(buf)) => { let completed = self.pending_ops.remove(i); - completed_count += 1; if completed.zero_copy_id > 0 { self.zero_copy_release(completed.zero_copy_id); } - self.shared.push(buf); + let successful_push = self.shared.push(&buf); + if !successful_push { + // If we couldn't push the response to the shared queue, because + // there wasn't enough size, we will return the buffer via the + // legacy route, using the argument of deno_respond. + overflow_response = Some(buf); + break; + } + + completed_count += 1; } } } if completed_count > 0 { - self.respond()?; + self.respond(None)?; // The other side should have shifted off all the messages. assert_eq!(self.shared.size(), 0); } + + if overflow_response.is_some() { + let buf = overflow_response.take().unwrap(); + self.respond(Some(&buf))?; + } } self.check_promise_errors(); @@ -401,12 +430,111 @@ pub fn js_check(r: Result<(), JSError>) { #[cfg(test)] mod tests { use super::*; - use crate::test_util::*; + use std::collections::HashMap; + + pub enum TestBehaviorMode { + AsyncImmediate, + OverflowReqSync, + OverflowResSync, + OverflowReqAsync, + OverflowResAsync, + } + + pub struct TestBehavior { + pub dispatch_count: usize, + pub resolve_count: usize, + pub mod_map: HashMap<String, deno_mod>, + mode: TestBehaviorMode, + } + + impl TestBehavior { + pub fn setup(mode: TestBehaviorMode) -> Isolate<Self> { + let mut isolate = Isolate::new(TestBehavior { + dispatch_count: 0, + resolve_count: 0, + mode, + mod_map: HashMap::new(), + }); + js_check(isolate.execute( + "setup.js", + r#" + function assert(cond) { + if (!cond) { + throw Error("assert"); + } + } + "#, + )); + assert_eq!(isolate.behavior.dispatch_count, 0); + isolate + } + + pub fn register(&mut self, name: &str, id: deno_mod) { + self.mod_map.insert(name.to_string(), id); + } + } + + impl Behavior for TestBehavior { + fn startup_snapshot(&mut self) -> Option<deno_buf> { + None + } + + fn resolve(&mut self, specifier: &str, _referrer: deno_mod) -> deno_mod { + self.resolve_count += 1; + match self.mod_map.get(specifier) { + Some(id) => *id, + None => 0, + } + } + + fn dispatch( + &mut self, + control: &[u8], + _zero_copy_buf: deno_buf, + ) -> (bool, Box<Op>) { + self.dispatch_count += 1; + match self.mode { + TestBehaviorMode::AsyncImmediate => { + assert_eq!(control.len(), 1); + assert_eq!(control[0], 42); + let buf = vec![43u8].into_boxed_slice(); + (false, Box::new(futures::future::ok(buf))) + } + TestBehaviorMode::OverflowReqSync => { + assert_eq!(control.len(), 100 * 1024 * 1024); + let buf = vec![43u8].into_boxed_slice(); + (true, Box::new(futures::future::ok(buf))) + } + TestBehaviorMode::OverflowResSync => { + assert_eq!(control.len(), 1); + assert_eq!(control[0], 42); + let mut vec = Vec::<u8>::new(); + vec.resize(100 * 1024 * 1024, 0); + vec[0] = 99; + let buf = vec.into_boxed_slice(); + (true, Box::new(futures::future::ok(buf))) + } + TestBehaviorMode::OverflowReqAsync => { + assert_eq!(control.len(), 100 * 1024 * 1024); + let buf = vec![43u8].into_boxed_slice(); + (false, Box::new(futures::future::ok(buf))) + } + TestBehaviorMode::OverflowResAsync => { + assert_eq!(control.len(), 1); + assert_eq!(control[0], 42); + let mut vec = Vec::<u8>::new(); + vec.resize(100 * 1024 * 1024, 0); + vec[0] = 4; + let buf = vec.into_boxed_slice(); + (false, Box::new(futures::future::ok(buf))) + } + } + } + } #[test] fn test_dispatch() { - let behavior = TestBehavior::new(); - let isolate = Isolate::new(behavior); + let mut isolate = TestBehavior::setup(TestBehaviorMode::AsyncImmediate); js_check(isolate.execute( "filename.js", r#" @@ -423,8 +551,7 @@ mod tests { #[test] fn test_mods() { - let behavior = TestBehavior::new(); - let mut isolate = Isolate::new(behavior); + let mut isolate = TestBehavior::setup(TestBehaviorMode::AsyncImmediate); let mod_a = isolate .mod_new( true, @@ -464,33 +591,25 @@ mod tests { #[test] fn test_poll_async_immediate_ops() { - let behavior = TestBehavior::new(); - let mut isolate = Isolate::new(behavior); - - isolate.shared_init(); + let mut isolate = TestBehavior::setup(TestBehaviorMode::AsyncImmediate); js_check(isolate.execute( - "setup.js", + "setup2.js", r#" let nrecv = 0; - Deno._setAsyncHandler((buf) => { + DenoCore.setAsyncHandler((buf) => { nrecv++; }); - function assertEq(actual, expected) { - if (expected != actual) { - throw Error(`actual ${actual} expected ${expected} `); - } - } "#, )); assert_eq!(isolate.behavior.dispatch_count, 0); js_check(isolate.execute( "check1.js", r#" - assertEq(nrecv, 0); + assert(nrecv == 0); let control = new Uint8Array([42]); libdeno.send(control); - assertEq(nrecv, 0); + assert(nrecv == 0); "#, )); assert_eq!(isolate.behavior.dispatch_count, 1); @@ -499,14 +618,14 @@ mod tests { js_check(isolate.execute( "check2.js", r#" - assertEq(nrecv, 1); + assert(nrecv == 1); libdeno.send(control); - assertEq(nrecv, 1); + assert(nrecv == 1); "#, )); assert_eq!(isolate.behavior.dispatch_count, 2); assert_eq!(Ok(Async::Ready(())), isolate.poll()); - js_check(isolate.execute("check3.js", "assertEq(nrecv, 2)")); + js_check(isolate.execute("check3.js", "assert(nrecv == 2)")); assert_eq!(isolate.behavior.dispatch_count, 2); // We are idle, so the next poll should be the last. assert_eq!(Ok(Async::Ready(())), isolate.poll()); @@ -514,25 +633,17 @@ mod tests { #[test] fn test_shared() { - let behavior = TestBehavior::new(); - let mut isolate = Isolate::new(behavior); - - isolate.shared_init(); + let mut isolate = TestBehavior::setup(TestBehaviorMode::AsyncImmediate); js_check(isolate.execute( - "setup.js", + "setup2.js", r#" let nrecv = 0; - Deno._setAsyncHandler((buf) => { + DenoCore.setAsyncHandler((buf) => { assert(buf.byteLength === 1); assert(buf[0] === 43); nrecv++; }); - function assert(cond) { - if (!cond) { - throw Error("assert"); - } - } "#, )); assert_eq!(isolate.behavior.dispatch_count, 0); @@ -541,11 +652,11 @@ mod tests { "send1.js", r#" let control = new Uint8Array([42]); - Deno._sharedQueue.push(control); + DenoCore.shared.push(control); libdeno.send(); assert(nrecv === 0); - Deno._sharedQueue.push(control); + DenoCore.shared.push(control); libdeno.send(); assert(nrecv === 0); "#, @@ -556,4 +667,106 @@ mod tests { js_check(isolate.execute("send1.js", "assert(nrecv === 2);")); } + #[test] + fn overflow_req_sync() { + let mut isolate = TestBehavior::setup(TestBehaviorMode::OverflowReqSync); + js_check(isolate.execute( + "overflow_req_sync.js", + r#" + let asyncRecv = 0; + DenoCore.setAsyncHandler((buf) => { asyncRecv++ }); + // Large message that will overflow the shared space. + let control = new Uint8Array(100 * 1024 * 1024); + let response = DenoCore.dispatch(control); + assert(response instanceof Uint8Array); + assert(response.length == 1); + assert(response[0] == 43); + assert(asyncRecv == 0); + "#, + )); + assert_eq!(isolate.behavior.dispatch_count, 1); + } + + #[test] + fn overflow_res_sync() { + // TODO(ry) This test is quite slow due to memcpy-ing 100MB into JS. We + // should optimize this. + let mut isolate = TestBehavior::setup(TestBehaviorMode::OverflowResSync); + js_check(isolate.execute( + "overflow_res_sync.js", + r#" + let asyncRecv = 0; + DenoCore.setAsyncHandler((buf) => { asyncRecv++ }); + // Large message that will overflow the shared space. + let control = new Uint8Array([42]); + let response = DenoCore.dispatch(control); + assert(response instanceof Uint8Array); + assert(response.length == 100 * 1024 * 1024); + assert(response[0] == 99); + assert(asyncRecv == 0); + "#, + )); + assert_eq!(isolate.behavior.dispatch_count, 1); + } + + #[test] + fn overflow_req_async() { + let mut isolate = TestBehavior::setup(TestBehaviorMode::OverflowReqAsync); + js_check(isolate.execute( + "overflow_req_async.js", + r#" + let asyncRecv = 0; + DenoCore.setAsyncHandler((buf) => { + assert(buf.byteLength === 1); + assert(buf[0] === 43); + asyncRecv++; + }); + // Large message that will overflow the shared space. + let control = new Uint8Array(100 * 1024 * 1024); + let response = DenoCore.dispatch(control); + // Async messages always have null response. + assert(response == null); + assert(asyncRecv == 0); + "#, + )); + assert_eq!(isolate.behavior.dispatch_count, 1); + assert_eq!(Ok(Async::Ready(())), isolate.poll()); + js_check(isolate.execute("check.js", "assert(asyncRecv == 1);")); + } + + #[test] + fn overflow_res_async() { + // TODO(ry) This test is quite slow due to memcpy-ing 100MB into JS. We + // should optimize this. + let mut isolate = TestBehavior::setup(TestBehaviorMode::OverflowResAsync); + js_check(isolate.execute( + "overflow_res_async.js", + r#" + let asyncRecv = 0; + DenoCore.setAsyncHandler((buf) => { + assert(buf.byteLength === 100 * 1024 * 1024); + assert(buf[0] === 4); + asyncRecv++; + }); + // Large message that will overflow the shared space. + let control = new Uint8Array([42]); + let response = DenoCore.dispatch(control); + assert(response == null); + assert(asyncRecv == 0); + "#, + )); + assert_eq!(isolate.behavior.dispatch_count, 1); + assert_eq!(Ok(Async::Ready(())), isolate.poll()); + js_check(isolate.execute("check.js", "assert(asyncRecv == 1);")); + } + + #[test] + fn test_js() { + let mut isolate = TestBehavior::setup(TestBehaviorMode::AsyncImmediate); + js_check( + isolate + .execute("shared_queue_test.js", include_str!("shared_queue_test.js")), + ); + assert_eq!(Ok(Async::Ready(())), isolate.poll()); + } } diff --git a/core/lib.rs b/core/lib.rs index d044f60b5..90c4448f3 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -9,8 +9,6 @@ mod isolate; mod js_errors; mod libdeno; mod shared_queue; -#[cfg(test)] -mod test_util; pub use crate::flags::v8_set_flags; pub use crate::isolate::*; diff --git a/core/libdeno.rs b/core/libdeno.rs index 32688906e..7b6f07a9b 120000..100755 --- a/core/libdeno.rs +++ b/core/libdeno.rs @@ -1 +1,188 @@ -../src/libdeno.rs
\ No newline at end of file +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +use libc::c_char; +use libc::c_int; +use libc::c_void; +use libc::size_t; +use std::ops::{Deref, DerefMut}; +use std::ptr::null; + +// TODO(F001): change this definition to `extern { pub type isolate; }` +// After RFC 1861 is stablized. See https://github.com/rust-lang/rust/issues/43467. +#[repr(C)] +pub struct isolate { + _unused: [u8; 0], +} + +/// If "alloc_ptr" is not null, this type represents a buffer which is created +/// in C side, and then passed to Rust side by `deno_recv_cb`. Finally it should +/// be moved back to C side by `deno_respond`. If it is not passed to +/// `deno_respond` in the end, it will be leaked. +/// +/// If "alloc_ptr" is null, this type represents a borrowed slice. +#[repr(C)] +pub struct deno_buf { + alloc_ptr: *const u8, + alloc_len: usize, + data_ptr: *const u8, + data_len: usize, + pub zero_copy_id: usize, +} + +/// `deno_buf` can not clone, and there is no interior mutability. +/// This type satisfies Send bound. +unsafe impl Send for deno_buf {} + +impl deno_buf { + #[inline] + pub fn empty() -> Self { + Self { + alloc_ptr: null(), + alloc_len: 0, + data_ptr: null(), + data_len: 0, + zero_copy_id: 0, + } + } + + #[inline] + pub unsafe fn from_raw_parts(ptr: *const u8, len: usize) -> Self { + Self { + alloc_ptr: null(), + alloc_len: 0, + data_ptr: ptr, + data_len: len, + zero_copy_id: 0, + } + } +} + +/// Converts Rust &Buf to libdeno `deno_buf`. +impl<'a> From<&'a [u8]> for deno_buf { + #[inline] + fn from(x: &'a [u8]) -> Self { + Self { + alloc_ptr: null(), + alloc_len: 0, + data_ptr: x.as_ref().as_ptr(), + data_len: x.len(), + zero_copy_id: 0, + } + } +} + +impl Deref for deno_buf { + type Target = [u8]; + #[inline] + fn deref(&self) -> &[u8] { + unsafe { std::slice::from_raw_parts(self.data_ptr, self.data_len) } + } +} + +impl DerefMut for deno_buf { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + if self.alloc_ptr.is_null() { + panic!("Can't modify the buf"); + } + std::slice::from_raw_parts_mut(self.data_ptr as *mut u8, self.data_len) + } + } +} + +impl AsRef<[u8]> for deno_buf { + #[inline] + fn as_ref(&self) -> &[u8] { + &*self + } +} + +impl AsMut<[u8]> for deno_buf { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + if self.alloc_ptr.is_null() { + panic!("Can't modify the buf"); + } + &mut *self + } +} + +#[allow(non_camel_case_types)] +type deno_recv_cb = unsafe extern "C" fn( + user_data: *mut c_void, + control_buf: deno_buf, // deprecated + zero_copy_buf: deno_buf, +); + +#[allow(non_camel_case_types)] +pub type deno_mod = i32; + +#[allow(non_camel_case_types)] +type deno_resolve_cb = unsafe extern "C" fn( + user_data: *mut c_void, + specifier: *const c_char, + referrer: deno_mod, +) -> deno_mod; + +#[repr(C)] +pub struct deno_config { + pub will_snapshot: c_int, + pub load_snapshot: deno_buf, + pub shared: deno_buf, + pub recv_cb: deno_recv_cb, +} + +extern "C" { + pub fn deno_init(); + pub fn deno_v8_version() -> *const c_char; + pub fn deno_set_v8_flags(argc: *mut c_int, argv: *mut *mut c_char); + pub fn deno_new(config: deno_config) -> *const isolate; + pub fn deno_delete(i: *const isolate); + pub fn deno_last_exception(i: *const isolate) -> *const c_char; + pub fn deno_check_promise_errors(i: *const isolate); + pub fn deno_lock(i: *const isolate); + pub fn deno_unlock(i: *const isolate); + pub fn deno_respond( + i: *const isolate, + user_data: *const c_void, + buf: deno_buf, + ); + pub fn deno_zero_copy_release(i: *const isolate, zero_copy_id: usize); + pub fn deno_execute( + i: *const isolate, + user_data: *const c_void, + js_filename: *const c_char, + js_source: *const c_char, + ); + + // Modules + + pub fn deno_mod_new( + i: *const isolate, + main: bool, + name: *const c_char, + source: *const c_char, + ) -> deno_mod; + + pub fn deno_mod_imports_len(i: *const isolate, id: deno_mod) -> size_t; + + pub fn deno_mod_imports_get( + i: *const isolate, + id: deno_mod, + index: size_t, + ) -> *const c_char; + + pub fn deno_mod_instantiate( + i: *const isolate, + user_data: *const c_void, + id: deno_mod, + resolve_cb: deno_resolve_cb, + ); + + pub fn deno_mod_evaluate( + i: *const isolate, + user_data: *const c_void, + id: deno_mod, + ); +} diff --git a/core/shared_queue.js b/core/shared_queue.js index 756f86e72..6c9a0326f 100644 --- a/core/shared_queue.js +++ b/core/shared_queue.js @@ -11,10 +11,6 @@ let sharedBytes = null; let shared32 = null; - if (!window["Deno"]) { - window["Deno"] = {}; - } - function assert(cond) { if (!cond) { throw Error("assert"); @@ -105,10 +101,13 @@ asyncHandler = cb; } - function handleAsyncMsgFromRust() { - let buf; - while ((buf = shift()) != null) { + function handleAsyncMsgFromRust(buf) { + if (buf) { asyncHandler(buf); + } else { + while ((buf = shift()) != null) { + asyncHandler(buf); + } } } @@ -122,13 +121,26 @@ libdeno.recv(handleAsyncMsgFromRust); } - window.Deno._setAsyncHandler = setAsyncHandler; - window.Deno._sharedQueue = { - head, - numRecords, - size, - push, - shift + function dispatch(control, zeroCopy = null) { + // First try to push control to shared. + const success = push(control); + // If successful, don't use first argument of libdeno.send. + const arg0 = success ? null : control; + return libdeno.send(arg0, zeroCopy); + } + + assert(!window["DenoCore"]); + window["DenoCore"] = { + setAsyncHandler, + dispatch, + shared: { + head, + numRecords, + size, + push, + reset, + shift + } }; init(libdeno.shared); diff --git a/core/shared_queue.rs b/core/shared_queue.rs index 1a8692b5f..9070253b9 100644 --- a/core/shared_queue.rs +++ b/core/shared_queue.rs @@ -1,5 +1,4 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. -use crate::isolate::Buf; use crate::libdeno::deno_buf; const MAX_RECORDS: usize = 100; @@ -43,14 +42,22 @@ impl SharedQueue { s[INDEX_HEAD] = HEAD_INIT as u32; } - fn as_u32_slice<'a>(&'a self) -> &'a [u32] { - let p = self.bytes.as_ptr() as *const u32; - unsafe { std::slice::from_raw_parts(p, self.bytes.len() / 4) } + fn as_u32_slice(&self) -> &[u32] { + let p = self.bytes.as_ptr(); + // Assert pointer is 32 bit aligned before casting. + assert_eq!((p as usize) % std::mem::align_of::<u32>(), 0); + #[allow(clippy::cast_ptr_alignment)] + let p32 = p as *const u32; + unsafe { std::slice::from_raw_parts(p32, self.bytes.len() / 4) } } - fn as_u32_slice_mut<'a>(&'a mut self) -> &'a mut [u32] { - let p = self.bytes.as_mut_ptr() as *mut u32; - unsafe { std::slice::from_raw_parts_mut(p, self.bytes.len() / 4) } + fn as_u32_slice_mut(&mut self) -> &mut [u32] { + let p = self.bytes.as_mut_ptr(); + // Assert pointer is 32 bit aligned before casting. + assert_eq!((p as usize) % std::mem::align_of::<u32>(), 0); + #[allow(clippy::cast_ptr_alignment)] + let p32 = p as *mut u32; + unsafe { std::slice::from_raw_parts_mut(p32, self.bytes.len() / 4) } } pub fn size(&self) -> usize { @@ -96,7 +103,7 @@ impl SharedQueue { } /// Returns none if empty. - pub fn shift<'a>(&'a mut self) -> Option<&'a [u8]> { + pub fn shift(&mut self) -> Option<&[u8]> { let u32_slice = self.as_u32_slice(); let i = u32_slice[INDEX_NUM_SHIFTED_OFF] as usize; if self.size() == 0 { @@ -117,7 +124,7 @@ impl SharedQueue { Some(&self.bytes[off..end]) } - pub fn push(&mut self, record: Buf) -> bool { + pub fn push(&mut self, record: &[u8]) -> bool { let off = self.head(); let end = off + record.len(); let index = self.num_records(); @@ -127,7 +134,7 @@ impl SharedQueue { } self.set_end(index, end); assert_eq!(end - off, record.len()); - self.bytes[off..end].copy_from_slice(&record); + self.bytes[off..end].copy_from_slice(record); let u32_slice = self.as_u32_slice_mut(); u32_slice[INDEX_NUM_RECORDS] += 1; u32_slice[INDEX_HEAD] = end as u32; @@ -138,11 +145,7 @@ impl SharedQueue { #[cfg(test)] mod tests { use super::*; - use crate::isolate::js_check; - use crate::isolate::Isolate; - use crate::test_util::*; - use futures::Async; - use futures::Future; + use crate::isolate::Buf; #[test] fn basic() { @@ -153,14 +156,14 @@ mod tests { let r = vec![1u8, 2, 3, 4, 5].into_boxed_slice(); let len = r.len() + h; - assert!(q.push(r)); + assert!(q.push(&r)); assert_eq!(q.head(), len); let r = vec![6, 7].into_boxed_slice(); - assert!(q.push(r)); + assert!(q.push(&r)); let r = vec![8, 9, 10, 11].into_boxed_slice(); - assert!(q.push(r)); + assert!(q.push(&r)); assert_eq!(q.num_records(), 3); assert_eq!(q.size(), 3); @@ -195,31 +198,19 @@ mod tests { #[test] fn overflow() { let mut q = SharedQueue::new(RECOMMENDED_SIZE); - assert!(q.push(alloc_buf(RECOMMENDED_SIZE - 1))); + assert!(q.push(&alloc_buf(RECOMMENDED_SIZE - 1))); assert_eq!(q.size(), 1); - assert!(!q.push(alloc_buf(2))); + assert!(!q.push(&alloc_buf(2))); assert_eq!(q.size(), 1); - assert!(q.push(alloc_buf(1))); + assert!(q.push(&alloc_buf(1))); assert_eq!(q.size(), 2); assert_eq!(q.shift().unwrap().len(), RECOMMENDED_SIZE - 1); assert_eq!(q.size(), 1); - assert!(!q.push(alloc_buf(1))); + assert!(!q.push(&alloc_buf(1))); assert_eq!(q.shift().unwrap().len(), 1); assert_eq!(q.size(), 0); } - - #[test] - fn test_js() { - let behavior = TestBehavior::new(); - let mut isolate = Isolate::new(behavior); - isolate.shared_init(); - js_check( - isolate - .execute("shared_queue_test.js", include_str!("shared_queue_test.js")), - ); - assert_eq!(Ok(Async::Ready(())), isolate.poll()); - } } diff --git a/core/shared_queue_test.js b/core/shared_queue_test.js index e1e4c9987..817bb3bcd 100644 --- a/core/shared_queue_test.js +++ b/core/shared_queue_test.js @@ -7,7 +7,7 @@ function assert(cond) { } function main() { - const q = Deno._sharedQueue; + const q = DenoCore.shared; let h = q.head(); assert(h > 0); diff --git a/core/test_util.rs b/core/test_util.rs deleted file mode 100644 index 80025c2be..000000000 --- a/core/test_util.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::isolate::Behavior; -use crate::isolate::Op; -use crate::libdeno::deno_buf; -use crate::libdeno::deno_mod; -use std::collections::HashMap; - -pub struct TestBehavior { - pub dispatch_count: usize, - pub resolve_count: usize, - pub mod_map: HashMap<String, deno_mod>, -} - -impl TestBehavior { - pub fn new() -> Self { - Self { - dispatch_count: 0, - resolve_count: 0, - mod_map: HashMap::new(), - } - } - - pub fn register(&mut self, name: &str, id: deno_mod) { - self.mod_map.insert(name.to_string(), id); - } -} - -impl Behavior for TestBehavior { - fn startup_snapshot(&mut self) -> Option<deno_buf> { - None - } - - fn dispatch( - &mut self, - control: &[u8], - _zero_copy_buf: deno_buf, - ) -> (bool, Box<Op>) { - assert_eq!(control.len(), 1); - assert_eq!(control[0], 42); - self.dispatch_count += 1; - let buf = vec![43u8].into_boxed_slice(); - (false, Box::new(futures::future::ok(buf))) - } - - fn resolve(&mut self, specifier: &str, _referrer: deno_mod) -> deno_mod { - self.resolve_count += 1; - match self.mod_map.get(specifier) { - Some(id) => *id, - None => 0, - } - } -} |