From 0d0ad360d32c55869ef0a4d89d97dd83f4628c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Sat, 11 Jan 2020 10:49:16 +0100 Subject: [PATCH] refactor: remove Isolate.current_send_cb_info and DenoBuf, port Isolate.shared_response_buf (#3643) * remove Isolate.current_send_cb_info * remove DenoBuf * remove Isolate.shared_ab * port Isolate.shared_response_buf (last bit not ported from libdeno) * add some docs for Isolate and EsIsolate --- core/bindings.rs | 113 ++++++++++++------------- core/es_isolate.rs | 159 ++++++++++++++++++++---------------- core/examples/http_bench.js | 28 +++---- core/isolate.rs | 151 ++++++---------------------------- core/shared_queue.rs | 9 +- 5 files changed, 178 insertions(+), 282 deletions(-) diff --git a/core/bindings.rs b/core/bindings.rs index 72b51814aa..0ac1919afd 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::DenoBuf; use crate::isolate::Isolate; use crate::isolate::PinnedBuf; +use crate::isolate::SHARED_RESPONSE_BUF_SIZE; use rusty_v8 as v8; use v8::InIsolate; @@ -11,6 +11,8 @@ use v8::InIsolate; use libc::c_void; use std::convert::TryFrom; use std::option::Option; +use std::ptr; +use std::slice; lazy_static! { pub static ref EXTERNAL_REFERENCES: v8::ExternalReferences = @@ -172,53 +174,39 @@ pub fn initialize_context<'a>( context.exit(); } -pub unsafe fn buf_to_uint8array<'sc>( +pub unsafe fn slice_to_uint8array<'sc>( + deno_isolate: &mut Isolate, scope: &mut impl v8::ToLocal<'sc>, - buf: DenoBuf, + buf: &[u8], ) -> v8::Local<'sc, v8::Uint8Array> { - if buf.data_ptr.is_null() { + if buf.is_empty() { let ab = v8::ArrayBuffer::new(scope, 0); return v8::Uint8Array::new(ab, 0, 0).expect("Failed to create UintArray8"); } - /* + let buf_len = buf.len(); + let buf_ptr = buf.as_ptr(); + // To avoid excessively allocating new ArrayBuffers, we try to reuse a single // global ArrayBuffer. The caveat is that users must extract data from it // before the next tick. We only do this for ArrayBuffers less than 1024 // bytes. - v8::Local ab; - void* data; - if (buf.data_len > GLOBAL_IMPORT_BUF_SIZE) { + let ab = if buf_len > SHARED_RESPONSE_BUF_SIZE { // Simple case. We allocate a new ArrayBuffer for this. - ab = v8::ArrayBuffer::New(d->isolate_, buf.data_len); - data = ab->GetBackingStore()->Data(); + v8::ArrayBuffer::new(scope, buf_len) + } else if deno_isolate.shared_response_buf.is_empty() { + let buf = v8::ArrayBuffer::new(scope, SHARED_RESPONSE_BUF_SIZE); + deno_isolate.shared_response_buf.set(scope, buf); + buf } else { - // Fast case. We reuse the global ArrayBuffer. - if (d->global_import_buf_.IsEmpty()) { - // Lazily initialize it. - DCHECK_NULL(d->global_import_buf_ptr_); - ab = v8::ArrayBuffer::New(d->isolate_, GLOBAL_IMPORT_BUF_SIZE); - d->global_import_buf_.Reset(d->isolate_, ab); - d->global_import_buf_ptr_ = ab->GetBackingStore()->Data(); - } else { - DCHECK(d->global_import_buf_ptr_); - ab = d->global_import_buf_.Get(d->isolate_); - } - data = d->global_import_buf_ptr_; - } - memcpy(data, buf.data_ptr, buf.data_len); - auto view = v8::Uint8Array::New(ab, 0, buf.data_len); - return view; - */ + deno_isolate.shared_response_buf.get(scope).unwrap() + }; - // TODO(bartlomieju): for now skipping part with `global_import_buf_` - // and always creating new buffer - let ab = v8::ArrayBuffer::new(scope, buf.data_len); let mut backing_store = ab.get_backing_store(); let data = backing_store.data(); let data: *mut u8 = data as *mut libc::c_void as *mut u8; - std::ptr::copy_nonoverlapping(buf.data_ptr, data, buf.data_len); - v8::Uint8Array::new(ab, 0, buf.data_len).expect("Failed to create UintArray8") + std::ptr::copy_nonoverlapping(buf_ptr, data, buf_len); + v8::Uint8Array::new(ab, 0, buf_len).expect("Failed to create UintArray8") } pub extern "C" fn host_import_module_dynamically_callback( @@ -423,11 +411,16 @@ pub extern "C" fn recv(info: &v8::FunctionCallbackInfo) { } pub extern "C" fn send(info: &v8::FunctionCallbackInfo) { + let rv = &mut info.get_return_value(); + #[allow(mutable_transmutes)] #[allow(clippy::transmute_ptr_to_ptr)] let info: &mut v8::FunctionCallbackInfo = unsafe { std::mem::transmute(info) }; + let arg0 = info.get_argument(0); + let arg1 = info.get_argument(1); + let arg2 = info.get_argument(2); let mut hs = v8::HandleScope::new(info); let scope = hs.enter(); let isolate = scope.isolate(); @@ -435,36 +428,36 @@ pub extern "C" fn send(info: &v8::FunctionCallbackInfo) { unsafe { &mut *(isolate.get_data(0) as *mut Isolate) }; assert!(!deno_isolate.global_context.is_empty()); - let op_id = v8::Local::::try_from(info.get_argument(0)) - .unwrap() - .value() as u32; + let op_id = v8::Local::::try_from(arg0).unwrap().value() as u32; - let control = - v8::Local::::try_from(info.get_argument(1)) - .map(|view| { - let mut backing_store = view.buffer().unwrap().get_backing_store(); - let backing_store_ptr = backing_store.data() as *mut _ as *mut u8; - let view_ptr = unsafe { backing_store_ptr.add(view.byte_offset()) }; - let view_len = view.byte_length(); - unsafe { DenoBuf::from_raw_parts(view_ptr, view_len) } - }) - .unwrap_or_else(|_| DenoBuf::empty()); + let control = match v8::Local::::try_from(arg1) { + Ok(view) => { + let mut backing_store = view.buffer().unwrap().get_backing_store(); + let backing_store_ptr = backing_store.data() as *mut _ as *mut u8; + let view_ptr = unsafe { backing_store_ptr.add(view.byte_offset()) }; + let view_len = view.byte_length(); + unsafe { slice::from_raw_parts(view_ptr, view_len) } + } + Err(..) => unsafe { slice::from_raw_parts(ptr::null(), 0) }, + }; let zero_copy: Option = - v8::Local::::try_from(info.get_argument(2)) + v8::Local::::try_from(arg2) .map(PinnedBuf::new) .ok(); - assert!(deno_isolate.current_send_cb_info.is_null()); - deno_isolate.current_send_cb_info = info; + // If response is empty then it's either async op or exception was thrown + let maybe_response = deno_isolate.dispatch_op(op_id, control, zero_copy); - deno_isolate.pre_dispatch(op_id, control, zero_copy); + if let Some(response) = maybe_response { + // Synchronous response. + // Note op_id is not passed back in the case of synchronous response. + let (_op_id, buf) = response; - if deno_isolate.current_send_cb_info.is_null() { - // This indicates that respond() was called already. - } else { - // Asynchronous. - deno_isolate.current_send_cb_info = std::ptr::null(); + if !buf.is_empty() { + let ab = unsafe { slice_to_uint8array(deno_isolate, scope, &buf) }; + rv.set(ab.into()) + } } } @@ -668,21 +661,15 @@ pub extern "C" fn shared_getter( let deno_isolate: &mut Isolate = unsafe { &mut *(isolate.get_data(0) as *mut Isolate) }; - if deno_isolate.shared_buf.data_ptr.is_null() { - return; - } - // Lazily initialize the persistent external ArrayBuffer. if deno_isolate.shared_ab.is_empty() { - #[allow(mutable_transmutes)] - #[allow(clippy::transmute_ptr_to_ptr)] - let data_ptr: *mut u8 = - unsafe { std::mem::transmute(deno_isolate.shared_buf.data_ptr) }; + let data_ptr = deno_isolate.shared.bytes.as_ptr(); + let data_len = deno_isolate.shared.bytes.len(); let ab = unsafe { v8::SharedArrayBuffer::new_DEPRECATED( scope, data_ptr as *mut c_void, - deno_isolate.shared_buf.data_len, + data_len, ) }; deno_isolate.shared_ab.set(scope, ab); diff --git a/core/es_isolate.rs b/core/es_isolate.rs index 655b42a066..a3231a90c2 100644 --- a/core/es_isolate.rs +++ b/core/es_isolate.rs @@ -47,14 +47,12 @@ pub struct SourceCodeInfo { pub module_url_found: String, } -/// A single execution context of JavaScript. Corresponds roughly to the "Web -/// Worker" concept in the DOM. An Isolate is a Future that can be used with -/// Tokio. The Isolate future complete when there is an error or when all -/// pending ops have completed. +/// More specialized version of `Isolate` that provides loading +/// and execution of ES Modules. /// -/// Ops are created in JavaScript by calling Deno.core.dispatch(), and in Rust -/// by implementing dispatcher function that takes control buffer and optional zero copy buffer -/// as arguments. An async Op corresponds exactly to a Promise in JavaScript. +/// Creating `EsIsolate` requires to pass `loader` argument +/// that implements `Loader` trait - that way actual resolution and +/// loading of modules can be customized by the implementor. pub struct EsIsolate { core_isolate: Box, loader: Arc>, @@ -190,7 +188,9 @@ impl EsIsolate { } /// Low-level module creation. - pub fn mod_new( + /// + /// Called during module loading or dynamic import loading. + fn mod_new( &mut self, main: bool, name: &str, @@ -200,18 +200,6 @@ impl EsIsolate { self.core_isolate.check_last_exception().map(|_| id) } - pub fn mod_get_imports(&self, id: ModuleId) -> Vec { - let info = self.modules.get_info(id).unwrap(); - let len = info.import_specifiers.len(); - let mut out = Vec::new(); - for i in 0..len { - let info = self.modules.get_info(id).unwrap(); - let specifier = info.import_specifiers.get(i).unwrap().to_string(); - out.push(specifier); - } - out - } - fn mod_instantiate2(&mut self, id: ModuleId) { let isolate = self.core_isolate.v8_isolate.as_ref().unwrap(); let mut locker = v8::Locker::new(isolate); @@ -319,6 +307,7 @@ impl EsIsolate { self.core_isolate.check_last_exception() } + // Called by V8 during `Isolate::mod_instantiate`. pub fn module_resolve_cb( &mut self, specifier: &str, @@ -334,6 +323,7 @@ impl EsIsolate { self.modules.get_id(specifier.as_str()).unwrap_or(0) } + // Called by V8 during `Isolate::mod_instantiate`. pub fn dyn_import_cb( &mut self, specifier: &str, @@ -352,24 +342,15 @@ impl EsIsolate { self.pending_dyn_imports.push(load.into_future()); } - fn dyn_import_done( + fn dyn_import_error( &mut self, id: DynImportId, - result: Result>, + error: Option, ) -> Result<(), ErrBox> { - debug!("dyn_import_done {} {:?}", id, result); - let (mod_id, maybe_err_str) = match result { - Ok(mod_id) => (mod_id, None), - Err(None) => (0, None), - Err(Some(err_str)) => (0, Some(err_str)), - }; - + debug!("dyn_import_error {} {:?}", id, error); assert!( - (mod_id == 0 && maybe_err_str.is_some()) - || (mod_id != 0 && maybe_err_str.is_none()) - || (mod_id == 0 && !self.core_isolate.last_exception_handle.is_empty()) + error.is_some() || !self.core_isolate.last_exception_handle.is_empty() ); - let isolate = self.core_isolate.v8_isolate.as_ref().unwrap(); let mut locker = v8::Locker::new(isolate); let mut hs = v8::HandleScope::new(&mut locker); @@ -377,40 +358,58 @@ impl EsIsolate { assert!(!self.core_isolate.global_context.is_empty()); let mut context = self.core_isolate.global_context.get(scope).unwrap(); context.enter(); - - // TODO(ry) error on bad import_id. - let mut resolver_handle = self.dyn_import_map.remove(&id).unwrap(); - // Resolve. + let mut resolver_handle = self + .dyn_import_map + .remove(&id) + .expect("Invalid dyn import id"); let mut resolver = resolver_handle.get(scope).unwrap(); resolver_handle.reset(scope); - - let maybe_info = self.modules.get_info(mod_id); - - if let Some(info) = maybe_info { - // Resolution success - let mut module = info.handle.get(scope).unwrap(); - assert_eq!(module.get_status(), v8::ModuleStatus::Evaluated); - let module_namespace = module.get_module_namespace(); - resolver.resolve(context, module_namespace).unwrap(); + // Resolution error. + if let Some(error_str) = error { + let msg = v8::String::new(scope, &error_str).unwrap(); + let e = v8::type_error(scope, msg); + resolver.reject(context, e).unwrap(); } else { - // Resolution error. - if let Some(error_str) = maybe_err_str { - let msg = v8::String::new(scope, &error_str).unwrap(); - let isolate = context.get_isolate(); - isolate.enter(); - let e = v8::type_error(scope, msg); - isolate.exit(); - resolver.reject(context, e).unwrap(); - } else { - let e = self.core_isolate.last_exception_handle.get(scope).unwrap(); - self.core_isolate.last_exception_handle.reset(scope); - self.core_isolate.last_exception.take(); - resolver.reject(context, e).unwrap(); - } + let e = self.core_isolate.last_exception_handle.get(scope).unwrap(); + self.core_isolate.last_exception_handle.reset(scope); + self.core_isolate.last_exception.take(); + resolver.reject(context, e).unwrap(); } - isolate.run_microtasks(); + context.exit(); + self.core_isolate.check_last_exception() + } + fn dyn_import_done( + &mut self, + id: DynImportId, + mod_id: ModuleId, + ) -> Result<(), ErrBox> { + debug!("dyn_import_done {} {:?}", id, mod_id); + assert!(mod_id != 0); + let isolate = self.core_isolate.v8_isolate.as_ref().unwrap(); + let mut locker = v8::Locker::new(isolate); + let mut hs = v8::HandleScope::new(&mut locker); + let scope = hs.enter(); + assert!(!self.core_isolate.global_context.is_empty()); + let mut context = self.core_isolate.global_context.get(scope).unwrap(); + context.enter(); + let mut resolver_handle = self + .dyn_import_map + .remove(&id) + .expect("Invalid dyn import id"); + let mut resolver = resolver_handle.get(scope).unwrap(); + resolver_handle.reset(scope); + let info = self + .modules + .get_info(mod_id) + .expect("Dyn import module info not found"); + // Resolution success + let mut module = info.handle.get(scope).unwrap(); + assert_eq!(module.get_status(), v8::ModuleStatus::Evaluated); + let module_namespace = module.get_module_namespace(); + resolver.resolve(context, module_namespace).unwrap(); + isolate.run_microtasks(); context.exit(); self.core_isolate.check_last_exception() } @@ -438,18 +437,15 @@ impl EsIsolate { // Keep importing until it's fully drained self.pending_dyn_imports.push(load.into_future()); } - Err(err) => self.dyn_import_done( - dyn_import_id, - Err(Some(err.to_string())), - )?, + Err(err) => self + .dyn_import_error(dyn_import_id, Some(err.to_string()))?, } } Err(err) => { // A non-javascript error occurred; this could be due to a an invalid // module specifier, or a problem with the source map, or a failure // to fetch the module source code. - self - .dyn_import_done(dyn_import_id, Err(Some(err.to_string())))? + self.dyn_import_error(dyn_import_id, Some(err.to_string()))? } } } else { @@ -458,9 +454,9 @@ impl EsIsolate { let module_id = load.root_module_id.unwrap(); self.mod_instantiate(module_id)?; if let Ok(()) = self.mod_evaluate(module_id) { - self.dyn_import_done(dyn_import_id, Ok(module_id))? + self.dyn_import_done(dyn_import_id, module_id)? } else { - self.dyn_import_done(dyn_import_id, Err(None))? + self.dyn_import_error(dyn_import_id, None)? } } } @@ -514,7 +510,12 @@ impl EsIsolate { }; // Now we must iterate over all imports of the module and load them. - let imports = self.mod_get_imports(module_id); + let imports = self + .modules + .get_info(module_id) + .unwrap() + .import_specifiers + .clone(); for import in imports { let module_specifier = self.loader.resolve( &import, @@ -545,6 +546,10 @@ impl EsIsolate { Ok(()) } + /// Asynchronously load specified module and all of it's dependencies + /// + /// User must call `Isolate::mod_evaluate` with returned `ModuleId` + /// manually after load is finished. pub async fn load_module( &mut self, specifier: &str, @@ -678,13 +683,23 @@ pub mod tests { .unwrap(); assert_eq!(dispatch_count.load(Ordering::Relaxed), 0); - let imports = isolate.mod_get_imports(mod_a); + let imports = isolate + .modules + .get_info(mod_a) + .unwrap() + .import_specifiers + .clone(); let specifier_b = "./b.js".to_string(); assert_eq!(imports, vec![specifier_b.clone()]); let mod_b = isolate .mod_new(false, "file:///b.js", "export function b() { return 'b' }") .unwrap(); - let imports = isolate.mod_get_imports(mod_b); + let imports = isolate + .modules + .get_info(mod_b) + .unwrap() + .import_specifiers + .clone(); assert_eq!(imports.len(), 0); let module_specifier = diff --git a/core/examples/http_bench.js b/core/examples/http_bench.js index f553d48007..db57401cce 100644 --- a/core/examples/http_bench.js +++ b/core/examples/http_bench.js @@ -17,11 +17,15 @@ function assert(cond) { } function createResolvable() { - let methods; - const promise = new Promise((resolve, reject) => { - methods = { resolve, reject }; + let resolve; + let reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; }); - return Object.assign(promise, methods); + promise.resolve = resolve; + promise.reject = reject; + return promise; } const scratch32 = new Int32Array(3); @@ -59,25 +63,19 @@ function sendAsync(opId, arg, zeroCopy = null) { function sendSync(opId, arg) { const buf = send(0, opId, arg); const record = recordFromBuf(buf); - return record.result; + return record[2]; } function recordFromBuf(buf) { assert(buf.byteLength === 3 * 4); - const buf32 = new Int32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4); - return { - promiseId: buf32[0], - arg: buf32[1], - result: buf32[2] - }; + return new Int32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4); } function handleAsyncMsgFromRust(opId, buf) { const record = recordFromBuf(buf); - const { promiseId, result } = record; - const p = promiseMap.get(promiseId); - promiseMap.delete(promiseId); - p.resolve(result); + const p = promiseMap.get(record[0]); + promiseMap.delete(record[0]); + p.resolve(record[2]); } /** Listens on 0.0.0.0:4500, returns rid. */ diff --git a/core/isolate.rs b/core/isolate.rs index 2ab639e00c..372ef185d5 100644 --- a/core/isolate.rs +++ b/core/isolate.rs @@ -26,79 +26,16 @@ use std::future::Future; use std::ops::{Deref, DerefMut}; use std::option::Option; use std::pin::Pin; -use std::ptr::null; use std::ptr::NonNull; use std::slice; use std::sync::{Arc, Mutex, Once}; use std::task::Context; use std::task::Poll; -// TODO(bartlomieju): get rid of DenoBuf -/// This type represents a borrowed slice. -#[repr(C)] -pub struct DenoBuf { - pub data_ptr: *const u8, - pub data_len: usize, -} - -/// `DenoBuf` can not clone, and there is no interior mutability. -/// This type satisfies Send bound. -unsafe impl Send for DenoBuf {} - -impl DenoBuf { - #[inline] - pub fn empty() -> Self { - Self { - data_ptr: null(), - data_len: 0, - } - } - - #[allow(clippy::missing_safety_doc)] - #[inline] - pub unsafe fn from_raw_parts(ptr: *const u8, len: usize) -> Self { - Self { - data_ptr: ptr, - data_len: len, - } - } -} - -/// Converts Rust &Buf to libdeno `DenoBuf`. -impl<'a> From<&'a [u8]> for DenoBuf { - #[inline] - fn from(x: &'a [u8]) -> Self { - Self { - data_ptr: x.as_ref().as_ptr(), - data_len: x.len(), - } - } -} - -impl<'a> From<&'a mut [u8]> for DenoBuf { - #[inline] - fn from(x: &'a mut [u8]) -> Self { - Self { - data_ptr: x.as_ref().as_ptr(), - data_len: x.len(), - } - } -} - -impl Deref for DenoBuf { - type Target = [u8]; - #[inline] - fn deref(&self) -> &[u8] { - unsafe { std::slice::from_raw_parts(self.data_ptr, self.data_len) } - } -} - -impl AsRef<[u8]> for DenoBuf { - #[inline] - fn as_ref(&self) -> &[u8] { - &*self - } -} +/// Size of `ArrayBuffer` that will be allocated and shared +/// between responses. If response is bigger a new one-off +/// `ArrayBuffer` will be allocated. +pub const SHARED_RESPONSE_BUF_SIZE: usize = 1024 * 1024; /// A PinnedBuf encapsulates a slice that's been borrowed from a JavaScript /// ArrayBuffer object. JavaScript objects can normally be garbage collected, @@ -232,19 +169,14 @@ pub struct Isolate { pub(crate) last_exception: Option, pub(crate) last_exception_handle: v8::Global, pub(crate) global_context: v8::Global, - pub(crate) shared_buf: DenoBuf, pub(crate) shared_ab: v8::Global, pub(crate) js_recv_cb: v8::Global, - pub(crate) current_send_cb_info: *const v8::FunctionCallbackInfo, pub(crate) pending_promise_map: HashMap>, - - // TODO: These two fields were not yet ported from libdeno - // void* global_import_buf_ptr_; - // v8::Persistent global_import_buf_; + pub(crate) shared_response_buf: v8::Global, shared_isolate_handle: Arc>>, js_error_create: Arc, needs_init: bool, - shared: SharedQueue, + pub(crate) shared: SharedQueue, pending_ops: FuturesUnordered, have_unpolled_ops: bool, startup_script: Option, @@ -271,6 +203,7 @@ impl Drop for Isolate { // self.global_context.reset(scope); self.shared_ab.reset(scope); + self.shared_response_buf.reset(scope); self.last_exception_handle.reset(scope); self.js_recv_cb.reset(scope); for (_key, handle) in self.pending_promise_map.iter_mut() { @@ -396,10 +329,9 @@ impl Isolate { last_exception_handle: v8::Global::::new(), global_context, pending_promise_map: HashMap::new(), - shared_buf: shared.as_deno_buf(), shared_ab: v8::Global::::new(), js_recv_cb: v8::Global::::new(), - current_send_cb_info: std::ptr::null(), + shared_response_buf: v8::Global::::new(), snapshot_creator: maybe_snapshot_creator, snapshot: load_snapshot, has_snapshotted: false, @@ -451,10 +383,7 @@ impl Isolate { // maybe make a new exception object let exception = if exception.is_null_or_undefined() { let exception_str = v8::String::new(s, "execution terminated").unwrap(); - isolate.enter(); - let e = v8::error(s, exception_str); - isolate.exit(); - e + v8::error(s, exception_str) } else { exception }; @@ -549,21 +478,19 @@ impl Isolate { } } - pub fn pre_dispatch( + pub fn dispatch_op( &mut self, op_id: OpId, - control_buf: DenoBuf, + control_buf: &[u8], zero_copy_buf: Option, - ) { - let maybe_op = - self - .op_registry - .call(op_id, control_buf.as_ref(), zero_copy_buf); + ) -> Option<(OpId, Box<[u8]>)> { + let maybe_op = self.op_registry.call(op_id, control_buf, zero_copy_buf); let op = match maybe_op { Some(op) => op, None => { - return self.throw_exception(&format!("Unknown op id: {}", op_id)) + self.throw_exception(&format!("Unknown op id: {}", op_id)); + return None; } }; @@ -573,16 +500,13 @@ impl Isolate { // For sync messages, we always return the response via Deno.core.send's // return value. Sync messages ignore the op_id. let op_id = 0; - self - .respond(Some((op_id, &buf))) - // Because this is a sync op, deno_respond() does not actually call - // into JavaScript. We should not get an error here. - .expect("unexpected error"); + Some((op_id, buf)) } Op::Async(fut) => { let fut2 = fut.map_ok(move |buf| (op_id, buf)); self.pending_ops.push(fut2.boxed()); self.have_unpolled_ops = true; + None } } } @@ -677,28 +601,7 @@ impl Isolate { isolate.throw_exception(msg.into()); } - fn respond2(&mut self, op_id: OpId, buf: DenoBuf) { - if !self.current_send_cb_info.is_null() { - // Synchronous response. - // Note op_id is not passed back in the case of synchronous response. - let isolate = self.v8_isolate.as_ref().unwrap(); - let mut locker = v8::Locker::new(isolate); - assert!(!self.global_context.is_empty()); - let mut hs = v8::HandleScope::new(&mut locker); - let scope = hs.enter(); - - if !buf.data_ptr.is_null() && buf.data_len > 0 { - let ab = unsafe { bindings::buf_to_uint8array(scope, buf) }; - let info: &v8::FunctionCallbackInfo = - unsafe { &*self.current_send_cb_info }; - let rv = &mut info.get_return_value(); - rv.set(ab.into()) - } - - self.current_send_cb_info = std::ptr::null(); - return; - } - + fn async_op_response2(&mut self, op_id: OpId, buf: Box<[u8]>) { let isolate = self.v8_isolate.as_ref().unwrap(); // println!("deno_execute -> Isolate ptr {:?}", isolate); let mut locker = v8::Locker::new(isolate); @@ -722,11 +625,11 @@ impl Isolate { let mut argc = 0; let mut args: Vec> = vec![]; - if !buf.data_ptr.is_null() { + if !buf.is_empty() { argc = 2; let op_id = v8::Integer::new(scope, op_id as i32); args.push(op_id.into()); - let buf = unsafe { bindings::buf_to_uint8array(scope, buf) }; + let buf = unsafe { bindings::slice_to_uint8array(self, scope, &buf) }; args.push(buf.into()); } @@ -743,15 +646,15 @@ impl Isolate { context.exit(); } - fn respond( + fn async_op_response( &mut self, - maybe_buf: Option<(OpId, &[u8])>, + maybe_buf: Option<(OpId, Box<[u8]>)>, ) -> Result<(), ErrBox> { let (op_id, buf) = match maybe_buf { - None => (0, DenoBuf::empty()), - Some((op_id, r)) => (op_id, DenoBuf::from(r)), + None => (0, Vec::with_capacity(0).into_boxed_slice()), + Some((op_id, r)) => (op_id, r), }; - self.respond2(op_id, buf); + self.async_op_response2(op_id, buf); self.check_last_exception() } @@ -816,14 +719,14 @@ impl Future for Isolate { } if inner.shared.size() > 0 { - inner.respond(None)?; + inner.async_op_response(None)?; // The other side should have shifted off all the messages. assert_eq!(inner.shared.size(), 0); } if overflow_response.is_some() { let (op_id, buf) = overflow_response.take().unwrap(); - inner.respond(Some((op_id, &buf)))?; + inner.async_op_response(Some((op_id, buf)))?; } inner.check_promise_errors(); diff --git a/core/shared_queue.rs b/core/shared_queue.rs index 566d7cb7fd..f449eb6b86 100644 --- a/core/shared_queue.rs +++ b/core/shared_queue.rs @@ -16,7 +16,6 @@ SharedQueue Binary Layout +---------------------------------------------------------------+ */ -use crate::isolate::DenoBuf; use crate::ops::OpId; const MAX_RECORDS: usize = 100; @@ -35,7 +34,7 @@ const HEAD_INIT: usize = 4 * INDEX_RECORDS; pub const RECOMMENDED_SIZE: usize = 128 * MAX_RECORDS; pub struct SharedQueue { - bytes: Vec, + pub bytes: Vec, } impl SharedQueue { @@ -47,12 +46,6 @@ impl SharedQueue { q } - pub fn as_deno_buf(&self) -> DenoBuf { - let ptr = self.bytes.as_ptr(); - let len = self.bytes.len(); - unsafe { DenoBuf::from_raw_parts(ptr, len) } - } - fn reset(&mut self) { debug!("rust:shared_queue:reset"); let s: &mut [u32] = self.as_u32_slice_mut();