diff options
78 files changed, 1484 insertions, 2196 deletions
diff --git a/Cargo.lock b/Cargo.lock index c91f7a2ff..63f6c50e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -453,6 +453,7 @@ version = "0.56.0" dependencies = [ "downcast-rs", "futures", + "indexmap", "lazy_static", "libc", "log", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index f67158310..224373053 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -45,7 +45,7 @@ futures = "0.3.5" filetime = "0.2.12" http = "0.2.1" idna = "0.2.0" -indexmap = "1.5.1" +indexmap = "1.5.2" jsonc-parser = "0.14.0" lazy_static = "1.4.0" libc = "0.2.74" diff --git a/cli/bench/main.rs b/cli/bench/main.rs index b2ae59d4f..e8d4b298d 100644 --- a/cli/bench/main.rs +++ b/cli/bench/main.rs @@ -11,12 +11,12 @@ use std::{ mod http; mod throughput; -fn read_json(filename: &str) -> Result<serde_json::Value> { +fn read_json(filename: &str) -> Result<Value> { let f = fs::File::open(filename)?; Ok(serde_json::from_reader(f)?) } -fn write_json(filename: &str, value: &serde_json::Value) -> Result<()> { +fn write_json(filename: &str, value: &Value) -> Result<()> { let f = fs::File::create(filename)?; serde_json::to_writer(f, value)?; Ok(()) diff --git a/cli/build.rs b/cli/build.rs index 4b26a24b0..40b803979 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,8 +1,11 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + mod op_fetch_asset; use deno_core::js_check; +use deno_core::BasicState; use deno_core::CoreIsolate; +use deno_core::OpRegistry; use deno_core::StartupData; use std::collections::HashMap; use std::env; @@ -28,8 +31,9 @@ fn create_snapshot( } fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<String>) { - let runtime_isolate = CoreIsolate::new(StartupData::None, true); - create_snapshot(runtime_isolate, snapshot_path, files); + let state = BasicState::new(); + let isolate = CoreIsolate::new(state, StartupData::None, true); + create_snapshot(isolate, snapshot_path, files); } fn create_compiler_snapshot( @@ -37,7 +41,6 @@ fn create_compiler_snapshot( files: Vec<String>, cwd: &Path, ) { - let mut runtime_isolate = CoreIsolate::new(StartupData::None, true); let mut custom_libs: HashMap<String, PathBuf> = HashMap::new(); custom_libs .insert("lib.deno.web.d.ts".to_string(), deno_web::get_declaration()); @@ -61,11 +64,15 @@ fn create_compiler_snapshot( "lib.deno.unstable.d.ts".to_string(), cwd.join("dts/lib.deno.unstable.d.ts"), ); - runtime_isolate.register_op( + + let state = BasicState::new(); + state.register_op( "op_fetch_asset", op_fetch_asset::op_fetch_asset(custom_libs), ); - create_snapshot(runtime_isolate, snapshot_path, files); + + let isolate = CoreIsolate::new(state, StartupData::None, true); + create_snapshot(isolate, snapshot_path, files); } fn ts_version() -> String { diff --git a/cli/colors.rs b/cli/colors.rs index 870f7f435..35e9bb5ca 100644 --- a/cli/colors.rs +++ b/cli/colors.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use regex::Regex; use std::env; use std::fmt; diff --git a/cli/deno_dir.rs b/cli/deno_dir.rs index 49f76c7d2..5bc05f549 100644 --- a/cli/deno_dir.rs +++ b/cli/deno_dir.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::disk_cache::DiskCache; use std::path::PathBuf; diff --git a/cli/diff.rs b/cli/diff.rs index 121e319f4..cc516d94c 100644 --- a/cli/diff.rs +++ b/cli/diff.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::colors; use dissimilar::{diff as difference, Chunk}; use std::fmt; diff --git a/cli/errors.rs b/cli/errors.rs index 2d7bb1cd6..327bcfb58 100644 --- a/cli/errors.rs +++ b/cli/errors.rs @@ -168,7 +168,7 @@ fn get_nix_error_class(error: &nix::Error) -> &'static str { } } -pub fn get_error_class(e: &ErrBox) -> &'static str { +pub(crate) fn get_error_class_name(e: &ErrBox) -> &'static str { use ErrBox::*; match e { Simple { class, .. } => Some(*class), diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index c5fd78897..8b3ca46a0 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::colors; use crate::http_cache::HttpCache; use crate::http_util; diff --git a/cli/flags.rs b/cli/flags.rs index c5d0532a3..835be0041 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use clap::App; use clap::AppSettings; use clap::Arg; @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + pub use deno_core::normalize_path; use deno_core::ErrBox; use std::env::current_dir; diff --git a/cli/global_state.rs b/cli/global_state.rs index daabcf519..cb265d9e5 100644 --- a/cli/global_state.rs +++ b/cli/global_state.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::deno_dir; use crate::file_fetcher::SourceFileFetcher; use crate::flags; diff --git a/cli/http_util.rs b/cli/http_util.rs index 9fb4ab914..8436b600b 100644 --- a/cli/http_util.rs +++ b/cli/http_util.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::version; use bytes::Bytes; use deno_core::ErrBox; diff --git a/cli/inspector.rs b/cli/inspector.rs index b4d377cef..9a8693ec7 100644 --- a/cli/inspector.rs +++ b/cli/inspector.rs @@ -17,6 +17,7 @@ use futures::stream::FuturesUnordered; use futures::task; use futures::task::Context; use futures::task::Poll; +use serde_json::Value; use std::cell::BorrowMutError; use std::cell::RefCell; use std::collections::HashMap; @@ -95,7 +96,7 @@ struct InspectorInfo { } impl InspectorInfo { - fn get_json_metadata(&self) -> serde_json::Value { + fn get_json_metadata(&self) -> Value { json!({ "description": "deno", "devtoolsFrontendUrl": self.get_frontend_url(), diff --git a/cli/installer.rs b/cli/installer.rs index 2c2e54248..ac51d75f7 100644 --- a/cli/installer.rs +++ b/cli/installer.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::flags::Flags; use crate::global_state::GlobalState; use deno_core::ErrBox; @@ -14,6 +14,7 @@ pub static UNSTABLE_NS_LIB: &str = include_str!("dts/lib.deno.unstable.d.ts"); #[test] fn cli_snapshot() { let mut isolate = deno_core::CoreIsolate::new( + deno_core::BasicState::new(), deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(CLI_SNAPSHOT)), false, ); @@ -31,6 +32,7 @@ fn cli_snapshot() { #[test] fn compiler_snapshot() { let mut isolate = deno_core::CoreIsolate::new( + deno_core::BasicState::new(), deno_core::StartupData::Snapshot(deno_core::Snapshot::Static( COMPILER_SNAPSHOT, )), diff --git a/cli/lockfile.rs b/cli/lockfile.rs index 0192c08df..4ac893030 100644 --- a/cli/lockfile.rs +++ b/cli/lockfile.rs @@ -1,5 +1,4 @@ use serde_json::json; -pub use serde_json::Value; use std::collections::BTreeMap; use std::io::Result; diff --git a/cli/main.rs b/cli/main.rs index e6fab71c8..49efbfed5 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -1,5 +1,4 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -#![deny(warnings)] extern crate dissimilar; #[macro_use] diff --git a/cli/metrics.rs b/cli/metrics.rs index ea3f90164..43f11cd36 100644 --- a/cli/metrics.rs +++ b/cli/metrics.rs @@ -16,22 +16,26 @@ pub struct Metrics { } impl Metrics { - fn op_dispatched(&mut self, bytes_sent_control: u64, bytes_sent_data: u64) { + fn op_dispatched( + &mut self, + bytes_sent_control: usize, + bytes_sent_data: usize, + ) { self.ops_dispatched += 1; - self.bytes_sent_control += bytes_sent_control; - self.bytes_sent_data += bytes_sent_data; + self.bytes_sent_control += bytes_sent_control as u64; + self.bytes_sent_data += bytes_sent_data as u64; } - fn op_completed(&mut self, bytes_received: u64) { + fn op_completed(&mut self, bytes_received: usize) { self.ops_completed += 1; - self.bytes_received += bytes_received; + self.bytes_received += bytes_received as u64; } pub fn op_sync( &mut self, - bytes_sent_control: u64, - bytes_sent_data: u64, - bytes_received: u64, + bytes_sent_control: usize, + bytes_sent_data: usize, + bytes_received: usize, ) { self.ops_dispatched_sync += 1; self.op_dispatched(bytes_sent_control, bytes_sent_data); @@ -41,8 +45,8 @@ impl Metrics { pub fn op_dispatched_async( &mut self, - bytes_sent_control: u64, - bytes_sent_data: u64, + bytes_sent_control: usize, + bytes_sent_data: usize, ) { self.ops_dispatched_async += 1; self.op_dispatched(bytes_sent_control, bytes_sent_data) @@ -50,19 +54,19 @@ impl Metrics { pub fn op_dispatched_async_unref( &mut self, - bytes_sent_control: u64, - bytes_sent_data: u64, + bytes_sent_control: usize, + bytes_sent_data: usize, ) { self.ops_dispatched_async_unref += 1; self.op_dispatched(bytes_sent_control, bytes_sent_data) } - pub fn op_completed_async(&mut self, bytes_received: u64) { + pub fn op_completed_async(&mut self, bytes_received: usize) { self.ops_completed_async += 1; self.op_completed(bytes_received); } - pub fn op_completed_async_unref(&mut self, bytes_received: u64) { + pub fn op_completed_async_unref(&mut self, bytes_received: usize) { self.ops_completed_async_unref += 1; self.op_completed(bytes_received); } diff --git a/cli/module_graph.rs b/cli/module_graph.rs index f7cfe4226..331f45241 100644 --- a/cli/module_graph.rs +++ b/cli/module_graph.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::checksum; use crate::file_fetcher::map_file_extension; use crate::file_fetcher::SourceFile; diff --git a/cli/op_fetch_asset.rs b/cli/op_fetch_asset.rs index cca085db7..3becc43d7 100644 --- a/cli/op_fetch_asset.rs +++ b/cli/op_fetch_asset.rs @@ -2,11 +2,11 @@ // Note: this module is used both in build.rs and main.rs. pub use deno_core::v8_set_flags; -use deno_core::CoreIsolateState; +use deno_core::BufVec; use deno_core::Op; -use deno_core::ZeroCopyBuf; use std::collections::HashMap; use std::path::PathBuf; +use std::rc::Rc; fn get_asset(name: &str) -> Option<&'static str> { macro_rules! inc { @@ -82,17 +82,15 @@ fn get_asset(name: &str) -> Option<&'static str> { /// Warning: Returns a non-JSON op dispatcher. Must be manually attached to /// CoreIsolate. -pub fn op_fetch_asset<S: ::std::hash::BuildHasher>( - custom_assets: HashMap<String, PathBuf, S>, -) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op { +pub fn op_fetch_asset<H: std::hash::BuildHasher, S>( + custom_assets: HashMap<String, PathBuf, H>, +) -> impl Fn(Rc<S>, BufVec) -> Op { for (_, path) in custom_assets.iter() { println!("cargo:rerun-if-changed={}", path.display()); } - move |_state: &mut CoreIsolateState, - zero_copy_bufs: &mut [ZeroCopyBuf]| - -> Op { - assert_eq!(zero_copy_bufs.len(), 1, "Invalid number of arguments"); - let name = std::str::from_utf8(&zero_copy_bufs[0]).unwrap(); + move |_state: Rc<S>, bufs: BufVec| -> Op { + assert_eq!(bufs.len(), 1, "Invalid number of arguments"); + let name = std::str::from_utf8(&bufs[0]).unwrap(); let asset_code = if let Some(source_code) = get_asset(name) { source_code.to_string() diff --git a/cli/ops/compiler.rs b/cli/ops/compiler.rs index c35043e2d..0b8379fa3 100644 --- a/cli/ops/compiler.rs +++ b/cli/ops/compiler.rs @@ -1,67 +1,27 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{JsonOp, Value}; -use crate::ops::json_op; + use crate::state::State; -use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; -use deno_core::ErrBox; -use deno_core::ZeroCopyBuf; +use deno_core::OpRegistry; use std::rc::Rc; use std::sync::Arc; use std::sync::Mutex; -pub fn init( - i: &mut CoreIsolate, - _s: &Rc<State>, - response: Arc<Mutex<Option<String>>>, -) { +pub fn init(s: &Rc<State>, response: Arc<Mutex<Option<String>>>) { let custom_assets = std::collections::HashMap::new(); // TODO(ry) use None. // TODO(bartlomieju): is this op even required? - i.register_op( + s.register_op( "op_fetch_asset", crate::op_fetch_asset::op_fetch_asset(custom_assets), ); - i.register_op( - "op_compiler_respond", - json_op(compiler_op(response, op_compiler_respond)), - ); -} - -pub fn compiler_op<D>( - response: Arc<Mutex<Option<String>>>, - dispatcher: D, -) -> impl Fn( - &mut deno_core::CoreIsolateState, - Value, - &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> -where - D: Fn( - Arc<Mutex<Option<String>>>, - Value, - &mut [ZeroCopyBuf], - ) -> Result<JsonOp, ErrBox>, -{ - move |_isolate_state: &mut CoreIsolateState, - args: Value, - zero_copy: &mut [ZeroCopyBuf]| - -> Result<JsonOp, ErrBox> { - dispatcher(response.clone(), args, zero_copy) - } -} - -fn op_compiler_respond( - response: Arc<Mutex<Option<String>>>, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { - let mut r = response.lock().unwrap(); - assert!( - r.is_none(), - "op_compiler_respond found unexpected existing compiler output" - ); - *r = Some(args.to_string()); - Ok(JsonOp::Sync(json!({}))) + s.register_op_json_sync("op_compiler_respond", move |_state, args, _bufs| { + let mut response_slot = response.lock().unwrap(); + let replaced_value = response_slot.replace(args.to_string()); + assert!( + replaced_value.is_none(), + "op_compiler_respond found unexpected existing compiler output", + ); + Ok(json!({})) + }); } diff --git a/cli/ops/dispatch_json.rs b/cli/ops/dispatch_json.rs deleted file mode 100644 index e28c32382..000000000 --- a/cli/ops/dispatch_json.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use deno_core::Buf; -use deno_core::CoreIsolateState; -use deno_core::ErrBox; -use deno_core::Op; -use deno_core::ZeroCopyBuf; -use futures::future::FutureExt; -pub use serde_derive::Deserialize; -use serde_json::json; -pub use serde_json::Value; -use std::future::Future; -use std::pin::Pin; - -pub type JsonResult = Result<Value, ErrBox>; - -pub type AsyncJsonOp = Pin<Box<dyn Future<Output = JsonResult>>>; - -pub enum JsonOp { - Sync(Value), - Async(AsyncJsonOp), - /// AsyncUnref is the variation of Async, which doesn't block the program - /// exiting. - AsyncUnref(AsyncJsonOp), -} - -pub fn serialize_result( - promise_id: Option<u64>, - result: JsonResult, - get_error_class_fn: deno_core::GetErrorClassFn, -) -> Buf { - let value = match result { - Ok(v) => json!({ "ok": v, "promiseId": promise_id }), - Err(err) => json!({ - "err": { - "className": (get_error_class_fn)(&err), - "message": err.to_string() - }, - "promiseId": promise_id - }), - }; - serde_json::to_vec(&value).unwrap().into_boxed_slice() -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct AsyncArgs { - promise_id: Option<u64>, -} - -pub fn json_op<D>( - d: D, -) -> impl Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op -where - D: Fn( - &mut CoreIsolateState, - Value, - &mut [ZeroCopyBuf], - ) -> Result<JsonOp, ErrBox>, -{ - move |isolate_state: &mut CoreIsolateState, zero_copy: &mut [ZeroCopyBuf]| { - let get_error_class_fn = isolate_state.get_error_class_fn; - - assert!(!zero_copy.is_empty(), "Expected JSON string at position 0"); - let async_args: AsyncArgs = match serde_json::from_slice(&zero_copy[0]) { - Ok(args) => args, - Err(e) => { - let buf = serialize_result(None, Err(e.into()), get_error_class_fn); - return Op::Sync(buf); - } - }; - let promise_id = async_args.promise_id; - let is_sync = promise_id.is_none(); - - let result = serde_json::from_slice(&zero_copy[0]) - .map_err(ErrBox::from) - .and_then(|args| d(isolate_state, args, &mut zero_copy[1..])); - - // Convert to Op - match result { - Ok(JsonOp::Sync(sync_value)) => { - assert!(promise_id.is_none()); - Op::Sync(serialize_result( - promise_id, - Ok(sync_value), - get_error_class_fn, - )) - } - Ok(JsonOp::Async(fut)) => { - assert!(promise_id.is_some()); - let fut2 = fut.then(move |result| { - futures::future::ready(serialize_result( - promise_id, - result, - get_error_class_fn, - )) - }); - Op::Async(fut2.boxed_local()) - } - Ok(JsonOp::AsyncUnref(fut)) => { - assert!(promise_id.is_some()); - let fut2 = fut.then(move |result| { - futures::future::ready(serialize_result( - promise_id, - result, - get_error_class_fn, - )) - }); - Op::AsyncUnref(fut2.boxed_local()) - } - Err(sync_err) => { - let buf = - serialize_result(promise_id, Err(sync_err), get_error_class_fn); - if is_sync { - Op::Sync(buf) - } else { - Op::Async(futures::future::ready(buf).boxed_local()) - } - } - } - } -} diff --git a/cli/ops/dispatch_minimal.rs b/cli/ops/dispatch_minimal.rs index 20e8160ff..9d941682d 100644 --- a/cli/ops/dispatch_minimal.rs +++ b/cli/ops/dispatch_minimal.rs @@ -1,20 +1,17 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -// Do not add flatbuffer dependencies to this module. -//! Connects to js/dispatch_minimal.ts sendAsyncMinimal This acts as a faster -//! alternative to flatbuffers using a very simple list of int32s to lay out -//! messages. The first i32 is used to determine if a message a flatbuffer -//! message or a "minimal" message. -use crate::errors::get_error_class; -use deno_core::Buf; -use deno_core::CoreIsolateState; + +use crate::state::State; +use deno_core::BufVec; use deno_core::ErrBox; use deno_core::Op; -use deno_core::ZeroCopyBuf; +use deno_core::OpId; +use deno_core::OpRegistry; use futures::future::FutureExt; use std::future::Future; use std::iter::repeat; use std::mem::size_of_val; use std::pin::Pin; +use std::rc::Rc; use std::slice; pub enum MinimalOp { @@ -30,8 +27,8 @@ pub struct Record { pub result: i32, } -impl Into<Buf> for Record { - fn into(self) -> Buf { +impl Into<Box<[u8]>> for Record { + fn into(self) -> Box<[u8]> { let vec = vec![self.promise_id, self.arg, self.result]; let buf32 = vec.into_boxed_slice(); let ptr = Box::into_raw(buf32) as *mut [u8; 3 * 4]; @@ -47,8 +44,8 @@ pub struct ErrorRecord { pub error_message: Vec<u8>, } -impl Into<Buf> for ErrorRecord { - fn into(self) -> Buf { +impl Into<Box<[u8]>> for ErrorRecord { + fn into(self) -> Box<[u8]> { let Self { promise_id, arg, @@ -91,7 +88,7 @@ fn test_error_record() { error_class: b"BadResource", error_message: b"Error".to_vec(), }; - let buf: Buf = err_record.into(); + let buf: Box<[u8]> = err_record.into(); assert_eq!(buf, expected.into_boxed_slice()); } @@ -124,7 +121,7 @@ fn test_parse_min_record() { Some(Record { promise_id: 1, arg: 3, - result: 4, + result: 4 }) ); @@ -135,73 +132,78 @@ fn test_parse_min_record() { assert_eq!(parse_min_record(&buf), None); } -pub fn minimal_op<D>( - d: D, -) -> impl Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op -where - D: Fn(&mut CoreIsolateState, bool, i32, &mut [ZeroCopyBuf]) -> MinimalOp, -{ - move |isolate_state: &mut CoreIsolateState, zero_copy: &mut [ZeroCopyBuf]| { - assert!(!zero_copy.is_empty(), "Expected record at position 0"); - let mut record = match parse_min_record(&zero_copy[0]) { - Some(r) => r, - None => { - let error = ErrBox::type_error("Unparsable control buffer"); - let error_class = get_error_class(&error); - let error_record = ErrorRecord { - promise_id: 0, - arg: -1, - error_len: error_class.len() as i32, - error_class: error_class.as_bytes(), - error_message: error.to_string().as_bytes().to_owned(), - }; - return Op::Sync(error_record.into()); - } - }; - let is_sync = record.promise_id == 0; - let rid = record.arg; - let min_op = d(isolate_state, is_sync, rid, &mut zero_copy[1..]); - - match min_op { - MinimalOp::Sync(sync_result) => Op::Sync(match sync_result { - Ok(r) => { - record.result = r; - record.into() - } - Err(err) => { - let error_class = get_error_class(&err); +impl State { + pub fn register_op_minimal<F>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId + where + F: Fn(Rc<Self>, bool, i32, BufVec) -> MinimalOp + 'static, + { + let base_op_fn = move |state: Rc<Self>, bufs: BufVec| { + let mut bufs_iter = bufs.into_iter(); + let record_buf = bufs_iter.next().expect("Expected record at position 0"); + let zero_copy = bufs_iter.collect::<BufVec>(); + + let mut record = match parse_min_record(&record_buf) { + Some(r) => r, + None => { + let error = ErrBox::type_error("Unparsable control buffer"); + let error_class = state.get_error_class_name(&error); let error_record = ErrorRecord { - promise_id: record.promise_id, + promise_id: 0, arg: -1, error_len: error_class.len() as i32, error_class: error_class.as_bytes(), - error_message: err.to_string().as_bytes().to_owned(), + error_message: error.to_string().as_bytes().to_owned(), }; - error_record.into() + return Op::Sync(error_record.into()); } - }), - MinimalOp::Async(min_fut) => { - let fut = async move { - match min_fut.await { - Ok(r) => { - record.result = r; - record.into() - } - Err(err) => { - let error_class = get_error_class(&err); - let error_record = ErrorRecord { - promise_id: record.promise_id, - arg: -1, - error_len: error_class.len() as i32, - error_class: error_class.as_bytes(), - error_message: err.to_string().as_bytes().to_owned(), - }; - error_record.into() - } + }; + let is_sync = record.promise_id == 0; + let rid = record.arg; + let min_op = op_fn(state.clone(), is_sync, rid, zero_copy); + + match min_op { + MinimalOp::Sync(sync_result) => Op::Sync(match sync_result { + Ok(r) => { + record.result = r; + record.into() + } + Err(err) => { + let error_class = state.get_error_class_name(&err); + let error_record = ErrorRecord { + promise_id: record.promise_id, + arg: -1, + error_len: error_class.len() as i32, + error_class: error_class.as_bytes(), + error_message: err.to_string().as_bytes().to_owned(), + }; + error_record.into() } - }; - Op::Async(fut.boxed_local()) + }), + MinimalOp::Async(min_fut) => { + let fut = async move { + match min_fut.await { + Ok(r) => { + record.result = r; + record.into() + } + Err(err) => { + let error_class = state.get_error_class_name(&err); + let error_record = ErrorRecord { + promise_id: record.promise_id, + arg: -1, + error_len: error_class.len() as i32, + error_class: error_class.as_bytes(), + error_message: err.to_string().as_bytes().to_owned(), + }; + error_record.into() + } + } + }; + Op::Async(fut.boxed_local()) + } } - } + }; + + self.register_op(name, base_op_fn) } } diff --git a/cli/ops/errors.rs b/cli/ops/errors.rs index 558f9af2a..a4f4665e2 100644 --- a/cli/ops/errors.rs +++ b/cli/ops/errors.rs @@ -1,27 +1,20 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::diagnostics::Diagnostic; use crate::source_maps::get_orig_position; use crate::source_maps::CachedMaps; use crate::state::State; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; +use serde_derive::Deserialize; +use serde_json::Value; use std::collections::HashMap; use std::rc::Rc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op( - "op_apply_source_map", - s.stateful_json_op_sync(t, op_apply_source_map), - ); - i.register_op( - "op_format_diagnostic", - s.stateful_json_op_sync(t, op_format_diagnostic), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_apply_source_map", op_apply_source_map); + s.register_op_json_sync("op_format_diagnostic", op_format_diagnostic); } #[derive(Deserialize)] @@ -34,7 +27,6 @@ struct ApplySourceMap { fn op_apply_source_map( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -59,7 +51,6 @@ fn op_apply_source_map( fn op_format_diagnostic( _state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/fetch.rs b/cli/ops/fetch.rs index aea7bc7fc..690cbc592 100644 --- a/cli/ops/fetch.rs +++ b/cli/ops/fetch.rs @@ -1,30 +1,25 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use super::io::{StreamResource, StreamResourceHolder}; use crate::http_util::{create_http_client, HttpBody}; use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use http::header::HeaderName; use http::header::HeaderValue; use http::Method; use reqwest::Client; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::convert::From; use std::path::PathBuf; use std::rc::Rc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_fetch", s.stateful_json_op_async(t, op_fetch)); - i.register_op( - "op_create_http_client", - s.stateful_json_op_sync(t, op_create_http_client), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_async("op_fetch", op_fetch); + s.register_op_json_sync("op_create_http_client", op_create_http_client); } #[derive(Deserialize)] @@ -38,16 +33,14 @@ struct FetchArgs { async fn op_fetch( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, data: BufVec, ) -> Result<Value, ErrBox> { let args: FetchArgs = serde_json::from_value(args)?; let url = args.url; - let resource_table2 = resource_table.clone(); let client = if let Some(rid) = args.client_rid { - let resource_table_ = resource_table.borrow(); + let resource_table_ = state.resource_table.borrow(); let r = resource_table_ .get::<HttpClientResource>(rid) .ok_or_else(ErrBox::bad_resource_id)?; @@ -100,8 +93,7 @@ async fn op_fetch( } let body = HttpBody::from(res); - let mut resource_table = resource_table2.borrow_mut(); - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "httpBody", Box::new(StreamResourceHolder::new(StreamResource::HttpBody( Box::new(body), @@ -137,7 +129,6 @@ struct CreateHttpClientOptions { fn op_create_http_client( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -149,7 +140,9 @@ fn op_create_http_client( let client = create_http_client(args.ca_file.as_deref()).unwrap(); - let rid = - resource_table.add("httpClient", Box::new(HttpClientResource::new(client))); + let rid = state + .resource_table + .borrow_mut() + .add("httpClient", Box::new(HttpClientResource::new(client))); Ok(json!(rid)) } diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs index 490ecd52f..e281f947e 100644 --- a/cli/ops/fs.rs +++ b/cli/ops/fs.rs @@ -1,16 +1,16 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Some deserializer fields are only used on Unix and Windows build fails without it -use super::dispatch_json::{Deserialize, Value}; use super::io::std_file_resource; use super::io::{FileMetadata, StreamResource, StreamResourceHolder}; -use crate::ops::dispatch_json::JsonResult; use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; -use std::cell::RefCell; +use rand::thread_rng; +use rand::Rng; +use serde_derive::Deserialize; +use serde_json::Value; use std::convert::From; use std::env::{current_dir, set_current_dir, temp_dir}; use std::io; @@ -20,171 +20,80 @@ use std::rc::Rc; use std::time::SystemTime; use std::time::UNIX_EPOCH; -use rand::{thread_rng, Rng}; +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_open_sync", op_open_sync); + s.register_op_json_async("op_open_async", op_open_async); -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + s.register_op_json_sync("op_seek_sync", op_seek_sync); + s.register_op_json_async("op_seek_async", op_seek_async); - i.register_op("op_open_sync", s.stateful_json_op_sync(t, op_open_sync)); - i.register_op("op_open_async", s.stateful_json_op_async(t, op_open_async)); + s.register_op_json_sync("op_fdatasync_sync", op_fdatasync_sync); + s.register_op_json_async("op_fdatasync_async", op_fdatasync_async); - i.register_op("op_seek_sync", s.stateful_json_op_sync(t, op_seek_sync)); - i.register_op("op_seek_async", s.stateful_json_op_async(t, op_seek_async)); + s.register_op_json_sync("op_fsync_sync", op_fsync_sync); + s.register_op_json_async("op_fsync_async", op_fsync_async); - i.register_op( - "op_fdatasync_sync", - s.stateful_json_op_sync(t, op_fdatasync_sync), - ); - i.register_op( - "op_fdatasync_async", - s.stateful_json_op_async(t, op_fdatasync_async), - ); + s.register_op_json_sync("op_fstat_sync", op_fstat_sync); + s.register_op_json_async("op_fstat_async", op_fstat_async); - i.register_op("op_fsync_sync", s.stateful_json_op_sync(t, op_fsync_sync)); - i.register_op( - "op_fsync_async", - s.stateful_json_op_async(t, op_fsync_async), - ); + s.register_op_json_sync("op_umask", op_umask); + s.register_op_json_sync("op_chdir", op_chdir); - i.register_op("op_fstat_sync", s.stateful_json_op_sync(t, op_fstat_sync)); - i.register_op( - "op_fstat_async", - s.stateful_json_op_async(t, op_fstat_async), - ); + s.register_op_json_sync("op_mkdir_sync", op_mkdir_sync); + s.register_op_json_async("op_mkdir_async", op_mkdir_async); - i.register_op("op_umask", s.stateful_json_op_sync(t, op_umask)); - i.register_op("op_chdir", s.stateful_json_op_sync(t, op_chdir)); + s.register_op_json_sync("op_chmod_sync", op_chmod_sync); + s.register_op_json_async("op_chmod_async", op_chmod_async); - i.register_op("op_mkdir_sync", s.stateful_json_op_sync(t, op_mkdir_sync)); - i.register_op( - "op_mkdir_async", - s.stateful_json_op_async(t, op_mkdir_async), - ); + s.register_op_json_sync("op_chown_sync", op_chown_sync); + s.register_op_json_async("op_chown_async", op_chown_async); - i.register_op("op_chmod_sync", s.stateful_json_op_sync(t, op_chmod_sync)); - i.register_op( - "op_chmod_async", - s.stateful_json_op_async(t, op_chmod_async), - ); + s.register_op_json_sync("op_remove_sync", op_remove_sync); + s.register_op_json_async("op_remove_async", op_remove_async); - i.register_op("op_chown_sync", s.stateful_json_op_sync(t, op_chown_sync)); - i.register_op( - "op_chown_async", - s.stateful_json_op_async(t, op_chown_async), - ); + s.register_op_json_sync("op_copy_file_sync", op_copy_file_sync); + s.register_op_json_async("op_copy_file_async", op_copy_file_async); - i.register_op("op_remove_sync", s.stateful_json_op_sync(t, op_remove_sync)); - i.register_op( - "op_remove_async", - s.stateful_json_op_async(t, op_remove_async), - ); + s.register_op_json_sync("op_stat_sync", op_stat_sync); + s.register_op_json_async("op_stat_async", op_stat_async); - i.register_op( - "op_copy_file_sync", - s.stateful_json_op_sync(t, op_copy_file_sync), - ); - i.register_op( - "op_copy_file_async", - s.stateful_json_op_async(t, op_copy_file_async), - ); + s.register_op_json_sync("op_realpath_sync", op_realpath_sync); + s.register_op_json_async("op_realpath_async", op_realpath_async); - i.register_op("op_stat_sync", s.stateful_json_op_sync(t, op_stat_sync)); - i.register_op("op_stat_async", s.stateful_json_op_async(t, op_stat_async)); + s.register_op_json_sync("op_read_dir_sync", op_read_dir_sync); + s.register_op_json_async("op_read_dir_async", op_read_dir_async); - i.register_op( - "op_realpath_sync", - s.stateful_json_op_sync(t, op_realpath_sync), - ); - i.register_op( - "op_realpath_async", - s.stateful_json_op_async(t, op_realpath_async), - ); + s.register_op_json_sync("op_rename_sync", op_rename_sync); + s.register_op_json_async("op_rename_async", op_rename_async); - i.register_op( - "op_read_dir_sync", - s.stateful_json_op_sync(t, op_read_dir_sync), - ); - i.register_op( - "op_read_dir_async", - s.stateful_json_op_async(t, op_read_dir_async), - ); + s.register_op_json_sync("op_link_sync", op_link_sync); + s.register_op_json_async("op_link_async", op_link_async); - i.register_op("op_rename_sync", s.stateful_json_op_sync(t, op_rename_sync)); - i.register_op( - "op_rename_async", - s.stateful_json_op_async(t, op_rename_async), - ); + s.register_op_json_sync("op_symlink_sync", op_symlink_sync); + s.register_op_json_async("op_symlink_async", op_symlink_async); - i.register_op("op_link_sync", s.stateful_json_op_sync(t, op_link_sync)); - i.register_op("op_link_async", s.stateful_json_op_async(t, op_link_async)); + s.register_op_json_sync("op_read_link_sync", op_read_link_sync); + s.register_op_json_async("op_read_link_async", op_read_link_async); - i.register_op( - "op_symlink_sync", - s.stateful_json_op_sync(t, op_symlink_sync), - ); - i.register_op( - "op_symlink_async", - s.stateful_json_op_async(t, op_symlink_async), - ); + s.register_op_json_sync("op_ftruncate_sync", op_ftruncate_sync); + s.register_op_json_async("op_ftruncate_async", op_ftruncate_async); - i.register_op( - "op_read_link_sync", - s.stateful_json_op_sync(t, op_read_link_sync), - ); - i.register_op( - "op_read_link_async", - s.stateful_json_op_async(t, op_read_link_async), - ); - - i.register_op( - "op_ftruncate_sync", - s.stateful_json_op_sync(t, op_ftruncate_sync), - ); - i.register_op( - "op_ftruncate_async", - s.stateful_json_op_async(t, op_ftruncate_async), - ); - - i.register_op( - "op_truncate_sync", - s.stateful_json_op_sync(t, op_truncate_sync), - ); - i.register_op( - "op_truncate_async", - s.stateful_json_op_async(t, op_truncate_async), - ); + s.register_op_json_sync("op_truncate_sync", op_truncate_sync); + s.register_op_json_async("op_truncate_async", op_truncate_async); - i.register_op( - "op_make_temp_dir_sync", - s.stateful_json_op_sync(t, op_make_temp_dir_sync), - ); - i.register_op( - "op_make_temp_dir_async", - s.stateful_json_op_async(t, op_make_temp_dir_async), - ); + s.register_op_json_sync("op_make_temp_dir_sync", op_make_temp_dir_sync); + s.register_op_json_async("op_make_temp_dir_async", op_make_temp_dir_async); - i.register_op( - "op_make_temp_file_sync", - s.stateful_json_op_sync(t, op_make_temp_file_sync), - ); - i.register_op( - "op_make_temp_file_async", - s.stateful_json_op_async(t, op_make_temp_file_async), - ); + s.register_op_json_sync("op_make_temp_file_sync", op_make_temp_file_sync); + s.register_op_json_async("op_make_temp_file_async", op_make_temp_file_async); - i.register_op("op_cwd", s.stateful_json_op_sync(t, op_cwd)); + s.register_op_json_sync("op_cwd", op_cwd); - i.register_op("op_futime_sync", s.stateful_json_op_sync(t, op_futime_sync)); - i.register_op( - "op_futime_async", - s.stateful_json_op_async(t, op_futime_async), - ); + s.register_op_json_sync("op_futime_sync", op_futime_sync); + s.register_op_json_async("op_futime_async", op_futime_async); - i.register_op("op_utime_sync", s.stateful_json_op_sync(t, op_utime_sync)); - i.register_op( - "op_utime_async", - s.stateful_json_op_async(t, op_utime_async), - ); + s.register_op_json_sync("op_utime_sync", op_utime_sync); + s.register_op_json_async("op_utime_async", op_utime_async); } fn into_string(s: std::ffi::OsString) -> Result<String, ErrBox> { @@ -257,14 +166,13 @@ fn open_helper( fn op_open_sync( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { let (path, open_options) = open_helper(state, args)?; let std_file = open_options.open(path)?; let tokio_file = tokio::fs::File::from_std(std_file); - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "fsFile", Box::new(StreamResourceHolder::new(StreamResource::FsFile(Some(( tokio_file, @@ -276,7 +184,6 @@ fn op_open_sync( async fn op_open_async( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -284,7 +191,7 @@ async fn op_open_async( let tokio_file = tokio::fs::OpenOptions::from(open_options) .open(path) .await?; - let rid = resource_table.borrow_mut().add( + let rid = state.resource_table.borrow_mut().add( "fsFile", Box::new(StreamResourceHolder::new(StreamResource::FsFile(Some(( tokio_file, @@ -321,13 +228,12 @@ fn seek_helper(args: Value) -> Result<(u32, SeekFrom), ErrBox> { } fn op_seek_sync( - _state: &State, - resource_table: &mut ResourceTable, + state: &State, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { let (rid, seek_from) = seek_helper(args)?; - let pos = std_file_resource(resource_table, rid, |r| match r { + let pos = std_file_resource(state, rid, |r| match r { Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error( "cannot seek on this type of resource".to_string(), @@ -337,16 +243,14 @@ fn op_seek_sync( } async fn op_seek_async( - _state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<State>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { let (rid, seek_from) = seek_helper(args)?; // TODO(ry) This is a fake async op. We need to use poll_fn, // tokio::fs::File::start_seek and tokio::fs::File::poll_complete - let mut resource_table = resource_table.borrow_mut(); - let pos = std_file_resource(&mut resource_table, rid, |r| match r { + let pos = std_file_resource(&state, rid, |r| match r { Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error( "cannot seek on this type of resource".to_string(), @@ -363,14 +267,13 @@ struct FdatasyncArgs { fn op_fdatasync_sync( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { state.check_unstable("Deno.fdatasync"); let args: FdatasyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - std_file_resource(resource_table, rid, |r| match r { + std_file_resource(state, rid, |r| match r { Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error( "cannot sync this type of resource".to_string(), @@ -381,15 +284,13 @@ fn op_fdatasync_sync( async fn op_fdatasync_async( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { state.check_unstable("Deno.fdatasync"); let args: FdatasyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { + std_file_resource(&state, rid, |r| match r { Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error( "cannot sync this type of resource".to_string(), @@ -406,14 +307,13 @@ struct FsyncArgs { fn op_fsync_sync( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { state.check_unstable("Deno.fsync"); let args: FsyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - std_file_resource(resource_table, rid, |r| match r { + std_file_resource(state, rid, |r| match r { Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error( "cannot sync this type of resource".to_string(), @@ -424,15 +324,13 @@ fn op_fsync_sync( async fn op_fsync_async( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { state.check_unstable("Deno.fsync"); let args: FsyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { + std_file_resource(&state, rid, |r| match r { Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error( "cannot sync this type of resource".to_string(), @@ -449,14 +347,13 @@ struct FstatArgs { fn op_fstat_sync( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { state.check_unstable("Deno.fstat"); let args: FstatArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - let metadata = std_file_resource(resource_table, rid, |r| match r { + let metadata = std_file_resource(state, rid, |r| match r { Ok(std_file) => std_file.metadata().map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error( "cannot stat this type of resource".to_string(), @@ -467,15 +364,13 @@ fn op_fstat_sync( async fn op_fstat_async( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { state.check_unstable("Deno.fstat"); let args: FstatArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - let mut resource_table = resource_table.borrow_mut(); - let metadata = std_file_resource(&mut resource_table, rid, |r| match r { + let metadata = std_file_resource(&state, rid, |r| match r { Ok(std_file) => std_file.metadata().map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error( "cannot stat this type of resource".to_string(), @@ -491,7 +386,6 @@ struct UmaskArgs { fn op_umask( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -530,7 +424,6 @@ struct ChdirArgs { fn op_chdir( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -551,7 +444,6 @@ struct MkdirArgs { fn op_mkdir_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -573,7 +465,6 @@ fn op_mkdir_sync( async fn op_mkdir_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -606,7 +497,6 @@ struct ChmodArgs { fn op_chmod_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -634,7 +524,6 @@ fn op_chmod_sync( async fn op_chmod_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -673,7 +562,6 @@ struct ChownArgs { fn op_chown_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -703,7 +591,6 @@ fn op_chown_sync( async fn op_chown_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -742,7 +629,6 @@ struct RemoveArgs { fn op_remove_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -786,7 +672,6 @@ fn op_remove_sync( async fn op_remove_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -841,7 +726,6 @@ struct CopyFileArgs { fn op_copy_file_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -867,7 +751,6 @@ fn op_copy_file_sync( async fn op_copy_file_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -895,7 +778,7 @@ async fn op_copy_file_async( .unwrap() } -fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> serde_json::Value { +fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> Value { match maybe_time { Ok(time) => { let msec = time @@ -903,18 +786,18 @@ fn to_msec(maybe_time: Result<SystemTime, io::Error>) -> serde_json::Value { .map(|t| t.as_secs_f64() * 1000f64) .unwrap_or_else(|err| err.duration().as_secs_f64() * -1000f64); serde_json::Number::from_f64(msec) - .map(serde_json::Value::Number) - .unwrap_or(serde_json::Value::Null) + .map(Value::Number) + .unwrap_or(Value::Null) } - Err(_) => serde_json::Value::Null, + Err(_) => Value::Null, } } #[inline(always)] -fn get_stat_json(metadata: std::fs::Metadata) -> JsonResult { +fn get_stat_json(metadata: std::fs::Metadata) -> Result<Value, ErrBox> { // Unix stat member (number types only). 0 if not on unix. macro_rules! usm { - ($member: ident) => {{ + ($member:ident) => {{ #[cfg(unix)] { metadata.$member() @@ -962,7 +845,6 @@ struct StatArgs { fn op_stat_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -981,7 +863,6 @@ fn op_stat_sync( async fn op_stat_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1012,7 +893,6 @@ struct RealpathArgs { fn op_realpath_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1038,7 +918,6 @@ fn op_realpath_sync( async fn op_realpath_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1074,7 +953,6 @@ struct ReadDirArgs { fn op_read_dir_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1107,7 +985,6 @@ fn op_read_dir_sync( async fn op_read_dir_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1151,7 +1028,6 @@ struct RenameArgs { fn op_rename_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1169,7 +1045,6 @@ fn op_rename_sync( async fn op_rename_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1203,7 +1078,6 @@ struct LinkArgs { fn op_link_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1222,7 +1096,6 @@ fn op_link_sync( async fn op_link_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1261,7 +1134,6 @@ struct SymlinkOptions { fn op_symlink_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1303,10 +1175,7 @@ fn op_symlink_sync( symlink_dir(&oldpath, &newpath)? } } - Err(_) => return Err(ErrBox::type_error( - "you must pass a `options` argument for non-existent target path in windows" - .to_string(), - )), + Err(_) => return Err(ErrBox::type_error("you must pass a `options` argument for non-existent target path in windows".to_string())), } } }; @@ -1316,7 +1185,6 @@ fn op_symlink_sync( async fn op_symlink_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1355,10 +1223,7 @@ async fn op_symlink_async( symlink_dir(&oldpath, &newpath)? } } - Err(_) => return Err(ErrBox::type_error( - "you must pass a `options` argument for non-existent target path in windows" - .to_string(), - )), + Err(_) => return Err(ErrBox::type_error("you must pass a `options` argument for non-existent target path in windows".to_string())), } } }; @@ -1377,7 +1242,6 @@ struct ReadLinkArgs { fn op_read_link_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1394,7 +1258,6 @@ fn op_read_link_sync( async fn op_read_link_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1422,7 +1285,6 @@ struct FtruncateArgs { fn op_ftruncate_sync( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1430,7 +1292,7 @@ fn op_ftruncate_sync( let args: FtruncateArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let len = args.len as u64; - std_file_resource(resource_table, rid, |r| match r { + std_file_resource(state, rid, |r| match r { Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error("cannot truncate this type of resource")), })?; @@ -1439,7 +1301,6 @@ fn op_ftruncate_sync( async fn op_ftruncate_async( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1447,8 +1308,7 @@ async fn op_ftruncate_async( let args: FtruncateArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let len = args.len as u64; - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { + std_file_resource(&state, rid, |r| match r { Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), Err(_) => Err(ErrBox::type_error("cannot truncate this type of resource")), })?; @@ -1464,7 +1324,6 @@ struct TruncateArgs { fn op_truncate_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1482,7 +1341,6 @@ fn op_truncate_sync( async fn op_truncate_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1557,7 +1415,6 @@ struct MakeTempArgs { fn op_make_temp_dir_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1586,7 +1443,6 @@ fn op_make_temp_dir_sync( async fn op_make_temp_dir_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1619,7 +1475,6 @@ async fn op_make_temp_dir_async( fn op_make_temp_file_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1648,7 +1503,6 @@ fn op_make_temp_file_sync( async fn op_make_temp_file_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1689,7 +1543,6 @@ struct FutimeArgs { fn op_futime_sync( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1699,7 +1552,7 @@ fn op_futime_sync( let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - std_file_resource(resource_table, rid, |r| match r { + std_file_resource(state, rid, |r| match r { Ok(std_file) => { filetime::set_file_handle_times(std_file, Some(atime), Some(mtime)) .map_err(ErrBox::from) @@ -1714,7 +1567,6 @@ fn op_futime_sync( async fn op_futime_async( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1724,8 +1576,7 @@ async fn op_futime_async( let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { + std_file_resource(&state, rid, |r| match r { Ok(std_file) => { filetime::set_file_handle_times(std_file, Some(atime), Some(mtime)) .map_err(ErrBox::from) @@ -1748,7 +1599,6 @@ struct UtimeArgs { fn op_utime_sync( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -1766,7 +1616,6 @@ fn op_utime_sync( async fn op_utime_async( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -1789,7 +1638,6 @@ async fn op_utime_async( fn op_cwd( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/fs_events.rs b/cli/ops/fs_events.rs index e1c98b8de..142aa3ccf 100644 --- a/cli/ops/fs_events.rs +++ b/cli/ops/fs_events.rs @@ -1,10 +1,9 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; use notify::event::Event as NotifyEvent; @@ -14,23 +13,16 @@ use notify::RecommendedWatcher; use notify::RecursiveMode; use notify::Watcher; use serde::Serialize; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::convert::From; use std::path::PathBuf; use std::rc::Rc; use tokio::sync::mpsc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op( - "op_fs_events_open", - s.stateful_json_op_sync(t, op_fs_events_open), - ); - i.register_op( - "op_fs_events_poll", - s.stateful_json_op_async(t, op_fs_events_poll), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_fs_events_open", op_fs_events_open); + s.register_op_json_async("op_fs_events_poll", op_fs_events_poll); } struct FsEventsResource { @@ -73,7 +65,6 @@ impl From<NotifyEvent> for FsEvent { fn op_fs_events_open( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -103,13 +94,15 @@ fn op_fs_events_open( watcher.watch(path, recursive_mode)?; } let resource = FsEventsResource { watcher, receiver }; - let rid = resource_table.add("fsEvents", Box::new(resource)); + let rid = state + .resource_table + .borrow_mut() + .add("fsEvents", Box::new(resource)); Ok(json!(rid)) } async fn op_fs_events_poll( - _state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<State>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -119,7 +112,7 @@ async fn op_fs_events_poll( } let PollArgs { rid } = serde_json::from_value(args)?; poll_fn(move |cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let watcher = resource_table .get_mut::<FsEventsResource>(rid) .ok_or_else(ErrBox::bad_resource_id)?; diff --git a/cli/ops/idna.rs b/cli/ops/idna.rs index 392eceb24..8e83a03ba 100644 --- a/cli/ops/idna.rs +++ b/cli/ops/idna.rs @@ -2,21 +2,18 @@ //! https://url.spec.whatwg.org/#idna -use super::dispatch_json::{Deserialize, Value}; use crate::state::State; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; -use idna::{domain_to_ascii, domain_to_ascii_strict}; +use idna::domain_to_ascii; +use idna::domain_to_ascii_strict; +use serde_derive::Deserialize; +use serde_json::Value; use std::rc::Rc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - i.register_op( - "op_domain_to_ascii", - s.stateful_json_op_sync(t, op_domain_to_ascii), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_domain_to_ascii", op_domain_to_ascii); } #[derive(Deserialize)] @@ -28,7 +25,6 @@ struct DomainToAscii { fn op_domain_to_ascii( _state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/io.rs b/cli/ops/io.rs index 14d32a39b..4a8f6d96d 100644 --- a/cli/ops/io.rs +++ b/cli/ops/io.rs @@ -1,11 +1,8 @@ use super::dispatch_minimal::MinimalOp; use crate::http_util::HttpBody; use crate::state::State; -use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; +use deno_core::BufVec; use deno_core::ErrBox; -use deno_core::ResourceTable; -use deno_core::ZeroCopyBuf; use futures::future::poll_fn; use futures::future::FutureExt; use futures::ready; @@ -85,9 +82,9 @@ lazy_static! { }; } -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - i.register_op("op_read", s.stateful_minimal_op2(op_read)); - i.register_op("op_write", s.stateful_minimal_op2(op_write)); +pub fn init(s: &Rc<State>) { + s.register_op_minimal("op_read", op_read); + s.register_op_minimal("op_write", op_write); } pub fn get_stdio() -> ( @@ -236,11 +233,10 @@ impl DenoAsyncRead for StreamResource { } pub fn op_read( - isolate_state: &mut CoreIsolateState, - _state: &Rc<State>, + state: Rc<State>, is_sync: bool, rid: i32, - zero_copy: &mut [ZeroCopyBuf], + mut zero_copy: BufVec, ) -> MinimalOp { debug!("read rid={}", rid); match zero_copy.len() { @@ -248,13 +244,11 @@ pub fn op_read( 1 => {} _ => panic!("Invalid number of arguments"), } - let resource_table = isolate_state.resource_table.clone(); if is_sync { MinimalOp::Sync({ // First we look up the rid in the resource table. - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid as u32, move |r| match r { + std_file_resource(&state, rid as u32, move |r| match r { Ok(std_file) => { use std::io::Read; std_file @@ -271,7 +265,7 @@ pub fn op_read( let mut zero_copy = zero_copy[0].clone(); MinimalOp::Async( poll_fn(move |cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let resource_holder = resource_table .get_mut::<StreamResourceHolder>(rid as u32) .ok_or_else(ErrBox::bad_resource_id)?; @@ -358,11 +352,10 @@ impl DenoAsyncWrite for StreamResource { } pub fn op_write( - isolate_state: &mut CoreIsolateState, - _state: &Rc<State>, + state: Rc<State>, is_sync: bool, rid: i32, - zero_copy: &mut [ZeroCopyBuf], + zero_copy: BufVec, ) -> MinimalOp { debug!("write rid={}", rid); match zero_copy.len() { @@ -374,8 +367,7 @@ pub fn op_write( if is_sync { MinimalOp::Sync({ // First we look up the rid in the resource table. - let mut resource_table = isolate_state.resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid as u32, move |r| match r { + std_file_resource(&state, rid as u32, move |r| match r { Ok(std_file) => { use std::io::Write; std_file @@ -390,11 +382,10 @@ pub fn op_write( }) } else { let zero_copy = zero_copy[0].clone(); - let resource_table = isolate_state.resource_table.clone(); MinimalOp::Async( async move { let nwritten = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let resource_holder = resource_table .get_mut::<StreamResourceHolder>(rid as u32) .ok_or_else(ErrBox::bad_resource_id)?; @@ -407,7 +398,7 @@ pub fn op_write( // Figure out why it's needed and preferably remove it. // https://github.com/denoland/deno/issues/3565 poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let resource_holder = resource_table .get_mut::<StreamResourceHolder>(rid as u32) .ok_or_else(ErrBox::bad_resource_id)?; @@ -430,7 +421,7 @@ pub fn op_write( /// /// Returns ErrorKind::Busy if the resource is being used by another op. pub fn std_file_resource<F, T>( - resource_table: &mut ResourceTable, + state: &State, rid: u32, mut f: F, ) -> Result<T, ErrBox> @@ -439,6 +430,7 @@ where FnMut(Result<&mut std::fs::File, &mut StreamResource>) -> Result<T, ErrBox>, { // First we look up the rid in the resource table. + let mut resource_table = state.resource_table.borrow_mut(); let mut r = resource_table.get_mut::<StreamResourceHolder>(rid); if let Some(ref mut resource_holder) = r { // Sync write only works for FsFile. It doesn't make sense to do this diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index bc6b4f377..06a55bade 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -1,12 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -mod dispatch_json; -mod dispatch_minimal; -pub use dispatch_json::json_op; -pub use dispatch_json::serialize_result; -pub use dispatch_json::JsonOp; -pub use dispatch_json::JsonResult; -pub use dispatch_minimal::minimal_op; +mod dispatch_minimal; pub use dispatch_minimal::MinimalOp; pub mod compiler; diff --git a/cli/ops/net.rs b/cli/ops/net.rs index 9cb6eb79d..91a9079d4 100644 --- a/cli/ops/net.rs +++ b/cli/ops/net.rs @@ -1,15 +1,15 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; -use super::io::{StreamResource, StreamResourceHolder}; + +use crate::ops::io::{StreamResource, StreamResourceHolder}; use crate::resolve_addr::resolve_addr; use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::net::Shutdown; use std::net::SocketAddr; use std::rc::Rc; @@ -22,38 +22,30 @@ use tokio::net::UdpSocket; #[cfg(unix)] use super::net_unix; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_accept", s.stateful_json_op_async(t, op_accept)); - i.register_op("op_connect", s.stateful_json_op_async(t, op_connect)); - i.register_op("op_shutdown", s.stateful_json_op_sync(t, op_shutdown)); - i.register_op("op_listen", s.stateful_json_op_sync(t, op_listen)); - i.register_op( - "op_datagram_receive", - s.stateful_json_op_async(t, op_datagram_receive), - ); - i.register_op( - "op_datagram_send", - s.stateful_json_op_async(t, op_datagram_send), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_async("op_accept", op_accept); + s.register_op_json_async("op_connect", op_connect); + s.register_op_json_sync("op_shutdown", op_shutdown); + s.register_op_json_sync("op_listen", op_listen); + s.register_op_json_async("op_datagram_receive", op_datagram_receive); + s.register_op_json_async("op_datagram_send", op_datagram_send); } #[derive(Deserialize)] -struct AcceptArgs { - rid: i32, - transport: String, +pub(crate) struct AcceptArgs { + pub rid: i32, + pub transport: String, } async fn accept_tcp( - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<State>, args: AcceptArgs, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { let rid = args.rid as u32; let accept_fut = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let listener_resource = resource_table .get_mut::<TcpListenerResource>(rid) .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?; @@ -76,8 +68,7 @@ async fn accept_tcp( let (tcp_stream, _socket_addr) = accept_fut.await?; let local_addr = tcp_stream.local_addr()?; let remote_addr = tcp_stream.peer_addr()?; - let mut resource_table = resource_table.borrow_mut(); - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "tcpStream", Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some( tcp_stream, @@ -99,18 +90,15 @@ async fn accept_tcp( } async fn op_accept( - _state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<State>, args: Value, - zero_copy: BufVec, + bufs: BufVec, ) -> Result<Value, ErrBox> { let args: AcceptArgs = serde_json::from_value(args)?; match args.transport.as_str() { - "tcp" => accept_tcp(resource_table, args, zero_copy).await, + "tcp" => accept_tcp(state, args, bufs).await, #[cfg(unix)] - "unix" => { - net_unix::accept_unix(resource_table, args.rid as u32, zero_copy).await - } + "unix" => net_unix::accept_unix(state, args, bufs).await, _ => Err(ErrBox::error(format!( "Unsupported transport protocol {}", args.transport @@ -119,14 +107,13 @@ async fn op_accept( } #[derive(Deserialize)] -struct ReceiveArgs { - rid: i32, - transport: String, +pub(crate) struct ReceiveArgs { + pub rid: i32, + pub transport: String, } async fn receive_udp( - resource_table: Rc<RefCell<ResourceTable>>, - _state: &Rc<State>, + state: Rc<State>, args: ReceiveArgs, zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -136,7 +123,7 @@ async fn receive_udp( let rid = args.rid as u32; let receive_fut = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let resource = resource_table .get_mut::<UdpSocketResource>(rid) .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; @@ -158,7 +145,6 @@ async fn receive_udp( async fn op_datagram_receive( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -166,12 +152,9 @@ async fn op_datagram_receive( let args: ReceiveArgs = serde_json::from_value(args)?; match args.transport.as_str() { - "udp" => receive_udp(resource_table, &state, args, zero_copy).await, + "udp" => receive_udp(state, args, zero_copy).await, #[cfg(unix)] - "unixpacket" => { - net_unix::receive_unix_packet(resource_table, args.rid as u32, zero_copy) - .await - } + "unixpacket" => net_unix::receive_unix_packet(state, args, zero_copy).await, _ => Err(ErrBox::error(format!( "Unsupported transport protocol {}", args.transport @@ -189,7 +172,6 @@ struct SendArgs { async fn op_datagram_send( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -205,7 +187,7 @@ async fn op_datagram_send( state.check_net(&args.hostname, args.port)?; let addr = resolve_addr(&args.hostname, args.port)?; poll_fn(move |cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let resource = resource_table .get_mut::<UdpSocketResource>(rid as u32) .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; @@ -225,7 +207,7 @@ async fn op_datagram_send( } if transport == "unixpacket" => { let address_path = net_unix::Path::new(&args.path); state.check_read(&address_path)?; - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let resource = resource_table .get_mut::<net_unix::UnixDatagramResource>(rid as u32) .ok_or_else(|| ErrBox::new("NotConnected", "Socket has been closed"))?; @@ -249,7 +231,6 @@ struct ConnectArgs { async fn op_connect( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -263,8 +244,7 @@ async fn op_connect( let tcp_stream = TcpStream::connect(&addr).await?; let local_addr = tcp_stream.local_addr()?; let remote_addr = tcp_stream.peer_addr()?; - let mut resource_table = resource_table.borrow_mut(); - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "tcpStream", Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some( tcp_stream, @@ -297,8 +277,7 @@ async fn op_connect( net_unix::UnixStream::connect(net_unix::Path::new(&path)).await?; let local_addr = unix_stream.local_addr()?; let remote_addr = unix_stream.peer_addr()?; - let mut resource_table = resource_table.borrow_mut(); - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "unixStream", Box::new(StreamResourceHolder::new(StreamResource::UnixStream( unix_stream, @@ -328,7 +307,6 @@ struct ShutdownArgs { fn op_shutdown( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -345,6 +323,7 @@ fn op_shutdown( _ => unimplemented!(), }; + let mut resource_table = state.resource_table.borrow_mut(); let resource_holder = resource_table .get_mut::<StreamResourceHolder>(rid) .ok_or_else(ErrBox::bad_resource_id)?; @@ -437,7 +416,7 @@ struct ListenArgs { } fn listen_tcp( - resource_table: &mut ResourceTable, + state: &State, addr: SocketAddr, ) -> Result<(u32, SocketAddr), ErrBox> { let std_listener = std::net::TcpListener::bind(&addr)?; @@ -448,27 +427,32 @@ fn listen_tcp( waker: None, local_addr, }; - let rid = resource_table.add("tcpListener", Box::new(listener_resource)); + let rid = state + .resource_table + .borrow_mut() + .add("tcpListener", Box::new(listener_resource)); Ok((rid, local_addr)) } fn listen_udp( - resource_table: &mut ResourceTable, + state: &State, addr: SocketAddr, ) -> Result<(u32, SocketAddr), ErrBox> { let std_socket = std::net::UdpSocket::bind(&addr)?; let socket = UdpSocket::from_std(std_socket)?; let local_addr = socket.local_addr()?; let socket_resource = UdpSocketResource { socket }; - let rid = resource_table.add("udpSocket", Box::new(socket_resource)); + let rid = state + .resource_table + .borrow_mut() + .add("udpSocket", Box::new(socket_resource)); Ok((rid, local_addr)) } fn op_listen( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -483,9 +467,9 @@ fn op_listen( state.check_net(&args.hostname, args.port)?; let addr = resolve_addr(&args.hostname, args.port)?; let (rid, local_addr) = if transport == "tcp" { - listen_tcp(resource_table, addr)? + listen_tcp(state, addr)? } else { - listen_udp(resource_table, addr)? + listen_udp(state, addr)? }; debug!( "New listener {} {}:{}", @@ -517,9 +501,9 @@ fn op_listen( state.check_read(&address_path)?; state.check_write(&address_path)?; let (rid, local_addr) = if transport == "unix" { - net_unix::listen_unix(resource_table, &address_path)? + net_unix::listen_unix(state, &address_path)? } else { - net_unix::listen_unix_packet(resource_table, &address_path)? + net_unix::listen_unix_packet(state, &address_path)? }; debug!( "New listener {} {}", diff --git a/cli/ops/net_unix.rs b/cli/ops/net_unix.rs index 29851b093..a73db89b2 100644 --- a/cli/ops/net_unix.rs +++ b/cli/ops/net_unix.rs @@ -1,9 +1,12 @@ -use super::dispatch_json::{Deserialize, Value}; -use super::io::{StreamResource, StreamResourceHolder}; +use crate::ops::io::StreamResource; +use crate::ops::io::StreamResourceHolder; +use crate::ops::net::AcceptArgs; +use crate::ops::net::ReceiveArgs; +use crate::state::State; use deno_core::BufVec; use deno_core::ErrBox; -use deno_core::ResourceTable; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::fs::remove_file; use std::os::unix; pub use std::path::Path; @@ -26,24 +29,25 @@ pub struct UnixListenArgs { pub path: String, } -pub async fn accept_unix( - resource_table: Rc<RefCell<ResourceTable>>, - rid: u32, - _zero_copy: BufVec, +pub(crate) async fn accept_unix( + state: Rc<State>, + args: AcceptArgs, + _bufs: BufVec, ) -> Result<Value, ErrBox> { - let mut resource_table_ = resource_table.borrow_mut(); + let rid = args.rid as u32; + + let mut resource_table_ = state.resource_table.borrow_mut(); let listener_resource = { resource_table_ .get_mut::<UnixListenerResource>(rid) .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))? }; - let (unix_stream, _socket_addr) = listener_resource.listener.accept().await?; drop(resource_table_); let local_addr = unix_stream.local_addr()?; let remote_addr = unix_stream.peer_addr()?; - let mut resource_table_ = resource_table.borrow_mut(); + let mut resource_table_ = state.resource_table.borrow_mut(); let rid = resource_table_.add( "unixStream", Box::new(StreamResourceHolder::new(StreamResource::UnixStream( @@ -63,19 +67,21 @@ pub async fn accept_unix( })) } -pub async fn receive_unix_packet( - resource_table: Rc<RefCell<ResourceTable>>, - rid: u32, - zero_copy: BufVec, +pub(crate) async fn receive_unix_packet( + state: Rc<State>, + args: ReceiveArgs, + bufs: BufVec, ) -> Result<Value, ErrBox> { - assert_eq!(zero_copy.len(), 1, "Invalid number of arguments"); - let mut zero_copy = zero_copy[0].clone(); + assert_eq!(bufs.len(), 1, "Invalid number of arguments"); + + let rid = args.rid as u32; + let mut buf = bufs.into_iter().next().unwrap(); - let mut resource_table_ = resource_table.borrow_mut(); + let mut resource_table_ = state.resource_table.borrow_mut(); let resource = resource_table_ .get_mut::<UnixDatagramResource>(rid) .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; - let (size, remote_addr) = resource.socket.recv_from(&mut zero_copy).await?; + let (size, remote_addr) = resource.socket.recv_from(&mut buf).await?; Ok(json!({ "size": size, "remoteAddr": { @@ -86,7 +92,7 @@ pub async fn receive_unix_packet( } pub fn listen_unix( - resource_table: &mut ResourceTable, + state: &State, addr: &Path, ) -> Result<(u32, unix::net::SocketAddr), ErrBox> { if addr.exists() { @@ -95,13 +101,16 @@ pub fn listen_unix( let listener = UnixListener::bind(&addr)?; let local_addr = listener.local_addr()?; let listener_resource = UnixListenerResource { listener }; - let rid = resource_table.add("unixListener", Box::new(listener_resource)); + let rid = state + .resource_table + .borrow_mut() + .add("unixListener", Box::new(listener_resource)); Ok((rid, local_addr)) } pub fn listen_unix_packet( - resource_table: &mut ResourceTable, + state: &State, addr: &Path, ) -> Result<(u32, unix::net::SocketAddr), ErrBox> { if addr.exists() { @@ -113,7 +122,10 @@ pub fn listen_unix_packet( socket, local_addr: local_addr.clone(), }; - let rid = resource_table.add("unixDatagram", Box::new(datagram_resource)); + let rid = state + .resource_table + .borrow_mut() + .add("unixDatagram", Box::new(datagram_resource)); Ok((rid, local_addr)) } diff --git a/cli/ops/os.rs b/cli/ops/os.rs index 7a2a7155e..4778d49a4 100644 --- a/cli/ops/os.rs +++ b/cli/ops/os.rs @@ -1,32 +1,30 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::state::State; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; +use serde_derive::Deserialize; +use serde_json::Value; use std::collections::HashMap; use std::env; use std::rc::Rc; use url::Url; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_exit", s.stateful_json_op_sync(t, op_exit)); - i.register_op("op_env", s.stateful_json_op_sync(t, op_env)); - i.register_op("op_exec_path", s.stateful_json_op_sync(t, op_exec_path)); - i.register_op("op_set_env", s.stateful_json_op_sync(t, op_set_env)); - i.register_op("op_get_env", s.stateful_json_op_sync(t, op_get_env)); - i.register_op("op_delete_env", s.stateful_json_op_sync(t, op_delete_env)); - i.register_op("op_hostname", s.stateful_json_op_sync(t, op_hostname)); - i.register_op("op_loadavg", s.stateful_json_op_sync(t, op_loadavg)); - i.register_op("op_os_release", s.stateful_json_op_sync(t, op_os_release)); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_exit", op_exit); + s.register_op_json_sync("op_env", op_env); + s.register_op_json_sync("op_exec_path", op_exec_path); + s.register_op_json_sync("op_set_env", op_set_env); + s.register_op_json_sync("op_get_env", op_get_env); + s.register_op_json_sync("op_delete_env", op_delete_env); + s.register_op_json_sync("op_hostname", op_hostname); + s.register_op_json_sync("op_loadavg", op_loadavg); + s.register_op_json_sync("op_os_release", op_os_release); } fn op_exec_path( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -47,7 +45,6 @@ struct SetEnv { fn op_set_env( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -59,7 +56,6 @@ fn op_set_env( fn op_env( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -75,7 +71,6 @@ struct GetEnv { fn op_get_env( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -95,7 +90,6 @@ struct DeleteEnv { fn op_delete_env( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -112,7 +106,6 @@ struct Exit { fn op_exit( _state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -122,7 +115,6 @@ fn op_exit( fn op_loadavg( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -136,7 +128,6 @@ fn op_loadavg( fn op_hostname( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -148,7 +139,6 @@ fn op_hostname( fn op_os_release( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/permissions.rs b/cli/ops/permissions.rs index 1d19f91d4..90d21a726 100644 --- a/cli/ops/permissions.rs +++ b/cli/ops/permissions.rs @@ -1,28 +1,18 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::state::State; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; +use serde_derive::Deserialize; +use serde_json::Value; use std::path::Path; use std::rc::Rc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op( - "op_query_permission", - s.stateful_json_op_sync(t, op_query_permission), - ); - i.register_op( - "op_revoke_permission", - s.stateful_json_op_sync(t, op_revoke_permission), - ); - i.register_op( - "op_request_permission", - s.stateful_json_op_sync(t, op_request_permission), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_query_permission", op_query_permission); + s.register_op_json_sync("op_revoke_permission", op_revoke_permission); + s.register_op_json_sync("op_request_permission", op_request_permission); } #[derive(Deserialize)] @@ -34,7 +24,6 @@ struct PermissionArgs { pub fn op_query_permission( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -61,7 +50,6 @@ pub fn op_query_permission( pub fn op_revoke_permission( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -88,7 +76,6 @@ pub fn op_revoke_permission( pub fn op_request_permission( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/plugin.rs b/cli/ops/plugin.rs index bd1a0a002..9cab05011 100644 --- a/cli/ops/plugin.rs +++ b/cli/ops/plugin.rs @@ -1,26 +1,26 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::ops::dispatch_json::Deserialize; -use crate::ops::dispatch_json::JsonOp; -use crate::ops::dispatch_json::Value; + use crate::state::State; use deno_core::plugin_api; -use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; +use deno_core::BufVec; use deno_core::ErrBox; use deno_core::Op; use deno_core::OpAsyncFuture; use deno_core::OpId; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use dlopen::symbor::Library; use futures::prelude::*; +use serde_derive::Deserialize; +use serde_json::Value; use std::path::PathBuf; use std::pin::Pin; use std::rc::Rc; use std::task::Context; use std::task::Poll; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - i.register_op("op_open_plugin", s.stateful_json_op2(op_open_plugin)); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_open_plugin", op_open_plugin); } #[derive(Deserialize)] @@ -30,12 +30,12 @@ struct OpenPluginArgs { } pub fn op_open_plugin( - isolate_state: &mut CoreIsolateState, - state: &Rc<State>, + state: &State, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { +) -> Result<Value, ErrBox> { state.check_unstable("Deno.openPlugin"); + let args: OpenPluginArgs = serde_json::from_value(args).unwrap(); let filename = PathBuf::from(&args.filename); @@ -45,22 +45,25 @@ pub fn op_open_plugin( let plugin_lib = Library::open(filename).map(Rc::new)?; let plugin_resource = PluginResource::new(&plugin_lib); - let mut resource_table = isolate_state.resource_table.borrow_mut(); - let rid = resource_table.add("plugin", Box::new(plugin_resource)); - let plugin_resource = resource_table.get::<PluginResource>(rid).unwrap(); - - let deno_plugin_init = *unsafe { - plugin_resource - .lib - .symbol::<plugin_api::InitFn>("deno_plugin_init") + let rid; + let deno_plugin_init; + { + let mut resource_table = state.resource_table.borrow_mut(); + rid = resource_table.add("plugin", Box::new(plugin_resource)); + deno_plugin_init = *unsafe { + resource_table + .get::<PluginResource>(rid) + .unwrap() + .lib + .symbol::<plugin_api::InitFn>("deno_plugin_init") + .unwrap() + }; } - .unwrap(); - drop(resource_table); - let mut interface = PluginInterface::new(isolate_state, &plugin_lib); + let mut interface = PluginInterface::new(state, &plugin_lib); deno_plugin_init(&mut interface); - Ok(JsonOp::Sync(json!(rid))) + Ok(json!(rid)) } struct PluginResource { @@ -74,19 +77,13 @@ impl PluginResource { } struct PluginInterface<'a> { - isolate_state: &'a mut CoreIsolateState, + state: &'a State, plugin_lib: &'a Rc<Library>, } impl<'a> PluginInterface<'a> { - fn new( - isolate_state: &'a mut CoreIsolateState, - plugin_lib: &'a Rc<Library>, - ) -> Self { - Self { - isolate_state, - plugin_lib, - } + fn new(state: &'a State, plugin_lib: &'a Rc<Library>) -> Self { + Self { state, plugin_lib } } } @@ -102,11 +99,11 @@ impl<'a> plugin_api::Interface for PluginInterface<'a> { dispatch_op_fn: plugin_api::DispatchOpFn, ) -> OpId { let plugin_lib = self.plugin_lib.clone(); - self.isolate_state.op_registry.register( + self.state.register_op( name, - move |isolate_state, zero_copy| { - let mut interface = PluginInterface::new(isolate_state, &plugin_lib); - let op = dispatch_op_fn(&mut interface, zero_copy); + move |state: Rc<State>, mut zero_copy: BufVec| { + let mut interface = PluginInterface::new(&state, &plugin_lib); + let op = dispatch_op_fn(&mut interface, &mut zero_copy); match op { sync_op @ Op::Sync(..) => sync_op, Op::Async(fut) => { @@ -115,6 +112,7 @@ impl<'a> plugin_api::Interface for PluginInterface<'a> { Op::AsyncUnref(fut) => { Op::AsyncUnref(PluginOpAsyncFuture::new(&plugin_lib, fut)) } + _ => unreachable!(), } }, ) diff --git a/cli/ops/process.rs b/cli/ops/process.rs index 836db08cd..fb8675db9 100644 --- a/cli/ops/process.rs +++ b/cli/ops/process.rs @@ -1,35 +1,30 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use super::io::{std_file_resource, StreamResource, StreamResourceHolder}; use crate::signal::kill; use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; use futures::future::FutureExt; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::rc::Rc; use tokio::process::Command; #[cfg(unix)] use std::os::unix::process::ExitStatusExt; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_run", s.stateful_json_op_sync(t, op_run)); - i.register_op("op_run_status", s.stateful_json_op_async(t, op_run_status)); - i.register_op("op_kill", s.stateful_json_op_sync(t, op_kill)); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_run", op_run); + s.register_op_json_async("op_run_status", op_run_status); + s.register_op_json_sync("op_kill", op_kill); } -fn clone_file( - rid: u32, - resource_table: &mut ResourceTable, -) -> Result<std::fs::File, ErrBox> { - std_file_resource(resource_table, rid, move |r| match r { +fn clone_file(state: &State, rid: u32) -> Result<std::fs::File, ErrBox> { + std_file_resource(state, rid, move |r| match r { Ok(std_file) => std_file.try_clone().map_err(ErrBox::from), Err(_) => Err(ErrBox::bad_resource_id()), }) @@ -64,7 +59,6 @@ struct ChildResource { fn op_run( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -90,21 +84,21 @@ fn op_run( if run_args.stdin != "" { c.stdin(subprocess_stdio_map(run_args.stdin.as_ref())?); } else { - let file = clone_file(run_args.stdin_rid, resource_table)?; + let file = clone_file(state, run_args.stdin_rid)?; c.stdin(file); } if run_args.stdout != "" { c.stdout(subprocess_stdio_map(run_args.stdout.as_ref())?); } else { - let file = clone_file(run_args.stdout_rid, resource_table)?; + let file = clone_file(state, run_args.stdout_rid)?; c.stdout(file); } if run_args.stderr != "" { c.stderr(subprocess_stdio_map(run_args.stderr.as_ref())?); } else { - let file = clone_file(run_args.stderr_rid, resource_table)?; + let file = clone_file(state, run_args.stderr_rid)?; c.stderr(file); } @@ -117,7 +111,7 @@ fn op_run( let stdin_rid = match child.stdin.take() { Some(child_stdin) => { - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "childStdin", Box::new(StreamResourceHolder::new(StreamResource::ChildStdin( child_stdin, @@ -130,7 +124,7 @@ fn op_run( let stdout_rid = match child.stdout.take() { Some(child_stdout) => { - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "childStdout", Box::new(StreamResourceHolder::new(StreamResource::ChildStdout( child_stdout, @@ -143,7 +137,7 @@ fn op_run( let stderr_rid = match child.stderr.take() { Some(child_stderr) => { - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "childStderr", Box::new(StreamResourceHolder::new(StreamResource::ChildStderr( child_stderr, @@ -155,7 +149,10 @@ fn op_run( }; let child_resource = ChildResource { child }; - let child_rid = resource_table.add("child", Box::new(child_resource)); + let child_rid = state + .resource_table + .borrow_mut() + .add("child", Box::new(child_resource)); Ok(json!({ "rid": child_rid, @@ -174,7 +171,6 @@ struct RunStatusArgs { async fn op_run_status( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -184,7 +180,7 @@ async fn op_run_status( state.check_run()?; let run_status = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let child_resource = resource_table .get_mut::<ChildResource>(rid) .ok_or_else(ErrBox::bad_resource_id)?; @@ -220,7 +216,6 @@ struct KillArgs { fn op_kill( state: &State, - _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/random.rs b/cli/ops/random.rs index fb2286116..4ce1411b8 100644 --- a/cli/ops/random.rs +++ b/cli/ops/random.rs @@ -1,26 +1,20 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::Value; + use crate::state::State; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use rand::thread_rng; use rand::Rng; +use serde_json::Value; use std::rc::Rc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op( - "op_get_random_values", - s.stateful_json_op_sync(t, op_get_random_values), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_get_random_values", op_get_random_values); } fn op_get_random_values( state: &State, - _resource_table: &mut ResourceTable, _args: Value, zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/repl.rs b/cli/ops/repl.rs index 82fa3e23e..300432832 100644 --- a/cli/ops/repl.rs +++ b/cli/ops/repl.rs @@ -1,26 +1,21 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::repl; use crate::repl::Repl; use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::rc::Rc; use std::sync::Arc; use std::sync::Mutex; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_repl_start", s.stateful_json_op_sync(t, op_repl_start)); - i.register_op( - "op_repl_readline", - s.stateful_json_op_async(t, op_repl_readline), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_repl_start", op_repl_start); + s.register_op_json_async("op_repl_readline", op_repl_readline); } struct ReplResource(Arc<Mutex<Repl>>); @@ -33,7 +28,6 @@ struct ReplStartArgs { fn op_repl_start( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -43,7 +37,10 @@ fn op_repl_start( repl::history_path(&state.global_state.dir, &args.history_file); let repl = repl::Repl::new(history_path); let resource = ReplResource(Arc::new(Mutex::new(repl))); - let rid = resource_table.add("repl", Box::new(resource)); + let rid = state + .resource_table + .borrow_mut() + .add("repl", Box::new(resource)); Ok(json!(rid)) } @@ -54,8 +51,7 @@ struct ReplReadlineArgs { } async fn op_repl_readline( - _state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<State>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -63,7 +59,7 @@ async fn op_repl_readline( let rid = args.rid as u32; let prompt = args.prompt; debug!("op_repl_readline {} {}", rid, prompt); - let resource_table = resource_table.borrow(); + let resource_table = state.resource_table.borrow(); let resource = resource_table .get::<ReplResource>(rid) .ok_or_else(ErrBox::bad_resource_id)?; diff --git a/cli/ops/resources.rs b/cli/ops/resources.rs index 0493aeed3..d7c2fd142 100644 --- a/cli/ops/resources.rs +++ b/cli/ops/resources.rs @@ -1,33 +1,31 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::state::State; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; +use serde_derive::Deserialize; +use serde_json::Value; use std::rc::Rc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_resources", s.stateful_json_op_sync(t, op_resources)); - i.register_op("op_close", s.stateful_json_op_sync(t, op_close)); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_resources", op_resources); + s.register_op_json_sync("op_close", op_close); } fn op_resources( - _state: &State, - resource_table: &mut ResourceTable, + state: &State, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { + let resource_table = state.resource_table.borrow(); let serialized_resources = resource_table.entries(); Ok(json!(serialized_resources)) } /// op_close removes a resource from the resource table. fn op_close( - _state: &State, - resource_table: &mut ResourceTable, + state: &State, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -36,7 +34,9 @@ fn op_close( rid: i32, } let args: CloseArgs = serde_json::from_value(args)?; - resource_table + state + .resource_table + .borrow_mut() .close(args.rid as u32) .ok_or_else(ErrBox::bad_resource_id)?; Ok(json!({})) diff --git a/cli/ops/runtime.rs b/cli/ops/runtime.rs index 119e152c8..10aac11fa 100644 --- a/cli/ops/runtime.rs +++ b/cli/ops/runtime.rs @@ -1,28 +1,25 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::Value; + use crate::colors; use crate::state::State; use crate::version; use crate::DenoSubcommand; -use deno_core::CoreIsolate; use deno_core::ErrBox; use deno_core::ModuleSpecifier; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; +use serde_json::Value; use std::env; use std::rc::Rc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_start", s.stateful_json_op_sync(t, op_start)); - i.register_op("op_main_module", s.stateful_json_op_sync(t, op_main_module)); - i.register_op("op_metrics", s.stateful_json_op_sync(t, op_metrics)); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_start", op_start); + s.register_op_json_sync("op_main_module", op_main_module); + s.register_op_json_sync("op_metrics", op_metrics); } fn op_start( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -48,7 +45,6 @@ fn op_start( fn op_main_module( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -63,7 +59,6 @@ fn op_main_module( fn op_metrics( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index a5991dabf..71974e6da 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -1,23 +1,21 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::futures::FutureExt; use crate::state::State; use crate::tsc::runtime_bundle; use crate::tsc::runtime_compile; use crate::tsc::runtime_transpile; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; -use std::cell::RefCell; +use deno_core::OpRegistry; +use serde_derive::Deserialize; +use serde_json::Value; use std::collections::HashMap; use std::rc::Rc; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_compile", s.stateful_json_op_async(t, op_compile)); - i.register_op("op_transpile", s.stateful_json_op_async(t, op_transpile)); +pub fn init(s: &Rc<State>) { + s.register_op_json_async("op_compile", op_compile); + s.register_op_json_async("op_transpile", op_transpile); } #[derive(Deserialize, Debug)] @@ -31,7 +29,6 @@ struct CompileArgs { async fn op_compile( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _data: BufVec, ) -> Result<Value, ErrBox> { @@ -70,7 +67,6 @@ struct TranspileArgs { async fn op_transpile( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _data: BufVec, ) -> Result<Value, ErrBox> { diff --git a/cli/ops/signal.rs b/cli/ops/signal.rs index 8c0b338b3..c0b1220e0 100644 --- a/cli/ops/signal.rs +++ b/cli/ops/signal.rs @@ -1,35 +1,26 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::Value; + use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; -use std::cell::RefCell; +use serde_json::Value; use std::rc::Rc; #[cfg(unix)] -use super::dispatch_json::Deserialize; -#[cfg(unix)] use futures::future::poll_fn; #[cfg(unix)] +use serde_derive::Deserialize; +#[cfg(unix)] use std::task::Waker; #[cfg(unix)] use tokio::signal::unix::{signal, Signal, SignalKind}; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_signal_bind", s.stateful_json_op_sync(t, op_signal_bind)); - i.register_op( - "op_signal_unbind", - s.stateful_json_op_sync(t, op_signal_unbind), - ); - i.register_op( - "op_signal_poll", - s.stateful_json_op_async(t, op_signal_poll), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_signal_bind", op_signal_bind); + s.register_op_json_sync("op_signal_unbind", op_signal_unbind); + s.register_op_json_async("op_signal_poll", op_signal_poll); } #[cfg(unix)] @@ -52,13 +43,12 @@ struct SignalArgs { #[cfg(unix)] fn op_signal_bind( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { state.check_unstable("Deno.signal"); let args: BindSignalArgs = serde_json::from_value(args)?; - let rid = resource_table.add( + let rid = state.resource_table.borrow_mut().add( "signal", Box::new(SignalStreamResource( signal(SignalKind::from_raw(args.signo)).expect(""), @@ -73,7 +63,6 @@ fn op_signal_bind( #[cfg(unix)] async fn op_signal_poll( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -82,7 +71,7 @@ async fn op_signal_poll( let rid = args.rid as u32; let future = poll_fn(move |cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); if let Some(mut signal) = resource_table.get_mut::<SignalStreamResource>(rid) { @@ -98,14 +87,14 @@ async fn op_signal_poll( #[cfg(unix)] pub fn op_signal_unbind( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { state.check_unstable("Deno.signal"); + let mut resource_table = state.resource_table.borrow_mut(); let args: SignalArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - let resource = resource_table.get::<SignalStreamResource>(rid); + let resource = resource_table.get_mut::<SignalStreamResource>(rid); if let Some(signal) = resource { if let Some(waker) = &signal.1 { // Wakes up the pending poll if exists. @@ -122,7 +111,6 @@ pub fn op_signal_unbind( #[cfg(not(unix))] pub fn op_signal_bind( _state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -132,7 +120,6 @@ pub fn op_signal_bind( #[cfg(not(unix))] fn op_signal_unbind( _state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -142,7 +129,6 @@ fn op_signal_unbind( #[cfg(not(unix))] async fn op_signal_poll( _state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, _args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { diff --git a/cli/ops/timers.rs b/cli/ops/timers.rs index 66a9b007b..36d617a85 100644 --- a/cli/ops/timers.rs +++ b/cli/ops/timers.rs @@ -1,34 +1,25 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use futures::future::FutureExt; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::rc::Rc; use std::time::Duration; use std::time::Instant; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op( - "op_global_timer_stop", - s.stateful_json_op_sync(t, op_global_timer_stop), - ); - i.register_op( - "op_global_timer", - s.stateful_json_op_async(t, op_global_timer), - ); - i.register_op("op_now", s.stateful_json_op_sync(t, op_now)); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_global_timer_stop", op_global_timer_stop); + s.register_op_json_async("op_global_timer", op_global_timer); + s.register_op_json_sync("op_now", op_now); } fn op_global_timer_stop( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -43,7 +34,6 @@ struct GlobalTimerArgs { async fn op_global_timer( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -66,7 +56,6 @@ async fn op_global_timer( // nanoseconds are rounded on 2ms. fn op_now( state: &State, - _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/ops/tls.rs b/cli/ops/tls.rs index 4a7b9613e..3a478c3ad 100644 --- a/cli/ops/tls.rs +++ b/cli/ops/tls.rs @@ -1,15 +1,15 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use super::io::{StreamResource, StreamResourceHolder}; use crate::resolve_addr::resolve_addr; use crate::state::State; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::convert::From; use std::fs::File; use std::io::BufReader; @@ -31,16 +31,11 @@ use tokio_rustls::{ }; use webpki::DNSNameRef; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_start_tls", s.stateful_json_op_async(t, op_start_tls)); - i.register_op( - "op_connect_tls", - s.stateful_json_op_async(t, op_connect_tls), - ); - i.register_op("op_listen_tls", s.stateful_json_op_sync(t, op_listen_tls)); - i.register_op("op_accept_tls", s.stateful_json_op_async(t, op_accept_tls)); +pub fn init(s: &Rc<State>) { + s.register_op_json_async("op_start_tls", op_start_tls); + s.register_op_json_async("op_connect_tls", op_connect_tls); + s.register_op_json_sync("op_listen_tls", op_listen_tls); + s.register_op_json_async("op_accept_tls", op_accept_tls); } #[derive(Deserialize)] @@ -62,7 +57,6 @@ struct StartTLSArgs { async fn op_start_tls( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -82,8 +76,8 @@ async fn op_start_tls( } let mut resource_holder = { - let mut resource_table_ = resource_table.borrow_mut(); - match resource_table_.remove::<StreamResourceHolder>(rid) { + let mut resource_table = state.resource_table.borrow_mut(); + match resource_table.remove::<StreamResourceHolder>(rid) { Some(resource) => *resource, None => return Err(ErrBox::bad_resource_id()), } @@ -110,8 +104,8 @@ async fn op_start_tls( DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup"); let tls_stream = tls_connector.connect(dnsname, tcp_stream).await?; - let mut resource_table_ = resource_table.borrow_mut(); - let rid = resource_table_.add( + let mut resource_table = state.resource_table.borrow_mut(); + let rid = resource_table.add( "clientTlsStream", Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream( Box::new(tls_stream), @@ -137,7 +131,6 @@ async fn op_start_tls( async fn op_connect_tls( state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -170,8 +163,8 @@ async fn op_connect_tls( let dnsname = DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup"); let tls_stream = tls_connector.connect(dnsname, tcp_stream).await?; - let mut resource_table_ = resource_table.borrow_mut(); - let rid = resource_table_.add( + let mut resource_table = state.resource_table.borrow_mut(); + let rid = resource_table.add( "clientTlsStream", Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream( Box::new(tls_stream), @@ -306,7 +299,6 @@ struct ListenTlsArgs { fn op_listen_tls( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -336,7 +328,10 @@ fn op_listen_tls( local_addr, }; - let rid = resource_table.add("tlsListener", Box::new(tls_listener_resource)); + let rid = state + .resource_table + .borrow_mut() + .add("tlsListener", Box::new(tls_listener_resource)); Ok(json!({ "rid": rid, @@ -354,15 +349,14 @@ struct AcceptTlsArgs { } async fn op_accept_tls( - _state: Rc<State>, - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<State>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { let args: AcceptTlsArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let accept_fut = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); let listener_resource = resource_table .get_mut::<TlsListenerResource>(rid) .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?; @@ -386,7 +380,7 @@ async fn op_accept_tls( let local_addr = tcp_stream.local_addr()?; let remote_addr = tcp_stream.peer_addr()?; let tls_acceptor = { - let resource_table = resource_table.borrow(); + let resource_table = state.resource_table.borrow(); let resource = resource_table .get::<TlsListenerResource>(rid) .ok_or_else(ErrBox::bad_resource_id) @@ -395,7 +389,7 @@ async fn op_accept_tls( }; let tls_stream = tls_acceptor.accept(tcp_stream).await?; let rid = { - let mut resource_table = resource_table.borrow_mut(); + let mut resource_table = state.resource_table.borrow_mut(); resource_table.add( "serverTlsStream", Box::new(StreamResourceHolder::new(StreamResource::ServerTlsStream( diff --git a/cli/ops/tty.rs b/cli/ops/tty.rs index bb8ad8714..9079ca57e 100644 --- a/cli/ops/tty.rs +++ b/cli/ops/tty.rs @@ -1,10 +1,10 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use super::io::std_file_resource; use super::io::{StreamResource, StreamResourceHolder}; use crate::state::State; -use deno_core::CoreIsolate; use deno_core::ErrBox; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; #[cfg(unix)] use nix::sys::termios; @@ -36,15 +36,10 @@ fn get_windows_handle( Ok(handle) } -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op("op_set_raw", s.stateful_json_op_sync(t, op_set_raw)); - i.register_op("op_isatty", s.stateful_json_op_sync(t, op_isatty)); - i.register_op( - "op_console_size", - s.stateful_json_op_sync(t, op_console_size), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_set_raw", op_set_raw); + s.register_op_json_sync("op_isatty", op_isatty); + s.register_op_json_sync("op_console_size", op_console_size); } #[derive(Deserialize)] @@ -55,7 +50,6 @@ struct SetRawArgs { fn op_set_raw( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -75,6 +69,7 @@ fn op_set_raw( use winapi::shared::minwindef::FALSE; use winapi::um::{consoleapi, handleapi}; + let mut resource_table = state.resource_table.borrow_mut(); let resource_holder = resource_table.get_mut::<StreamResourceHolder>(rid); if resource_holder.is_none() { return Err(ErrBox::bad_resource_id()); @@ -140,6 +135,7 @@ fn op_set_raw( { use std::os::unix::io::AsRawFd; + let mut resource_table = state.resource_table.borrow_mut(); let resource_holder = resource_table.get_mut::<StreamResourceHolder>(rid); if resource_holder.is_none() { return Err(ErrBox::bad_resource_id()); @@ -221,37 +217,35 @@ struct IsattyArgs { } fn op_isatty( - _state: &State, - resource_table: &mut ResourceTable, + state: &State, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { let args: IsattyArgs = serde_json::from_value(args)?; let rid = args.rid; - let isatty: bool = - std_file_resource(resource_table, rid as u32, move |r| match r { - Ok(std_file) => { - #[cfg(windows)] - { - use winapi::um::consoleapi; - - let handle = get_windows_handle(&std_file)?; - let mut test_mode: DWORD = 0; - // If I cannot get mode out of console, it is not a console. - Ok(unsafe { consoleapi::GetConsoleMode(handle, &mut test_mode) != 0 }) - } - #[cfg(unix)] - { - use std::os::unix::io::AsRawFd; - let raw_fd = std_file.as_raw_fd(); - Ok(unsafe { libc::isatty(raw_fd as libc::c_int) == 1 }) - } + let isatty: bool = std_file_resource(state, rid as u32, move |r| match r { + Ok(std_file) => { + #[cfg(windows)] + { + use winapi::um::consoleapi; + + let handle = get_windows_handle(&std_file)?; + let mut test_mode: DWORD = 0; + // If I cannot get mode out of console, it is not a console. + Ok(unsafe { consoleapi::GetConsoleMode(handle, &mut test_mode) != 0 }) } - Err(StreamResource::FsFile(_)) => unreachable!(), - Err(StreamResource::Stdin(..)) => Ok(atty::is(atty::Stream::Stdin)), - _ => Ok(false), - })?; + #[cfg(unix)] + { + use std::os::unix::io::AsRawFd; + let raw_fd = std_file.as_raw_fd(); + Ok(unsafe { libc::isatty(raw_fd as libc::c_int) == 1 }) + } + } + Err(StreamResource::FsFile(_)) => unreachable!(), + Err(StreamResource::Stdin(..)) => Ok(atty::is(atty::Stream::Stdin)), + _ => Ok(false), + })?; Ok(json!(isatty)) } @@ -268,7 +262,6 @@ struct ConsoleSize { fn op_console_size( state: &State, - resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -276,7 +269,7 @@ fn op_console_size( let args: ConsoleSizeArgs = serde_json::from_value(args)?; let rid = args.rid; - let size = std_file_resource(resource_table, rid as u32, move |r| match r { + let size = std_file_resource(state, rid as u32, move |r| match r { Ok(std_file) => { #[cfg(windows)] { diff --git a/cli/ops/web_worker.rs b/cli/ops/web_worker.rs index 023a4708c..9d8140d7b 100644 --- a/cli/ops/web_worker.rs +++ b/cli/ops/web_worker.rs @@ -1,112 +1,39 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{JsonOp, Value}; -use crate::ops::json_op; + use crate::state::State; use crate::web_worker::WebWorkerHandle; use crate::worker::WorkerEvent; -use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; -use deno_core::ErrBox; -use deno_core::ZeroCopyBuf; +use deno_core::OpRegistry; use futures::channel::mpsc; -use std::convert::From; use std::rc::Rc; -pub fn web_worker_op<D>( - sender: mpsc::Sender<WorkerEvent>, - dispatcher: D, -) -> impl Fn( - &mut CoreIsolateState, - Value, - &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> -where - D: Fn( - &mpsc::Sender<WorkerEvent>, - Value, - &mut [ZeroCopyBuf], - ) -> Result<JsonOp, ErrBox>, -{ - move |_isolate_state: &mut CoreIsolateState, - args: Value, - zero_copy: &mut [ZeroCopyBuf]| - -> Result<JsonOp, ErrBox> { dispatcher(&sender, args, zero_copy) } -} - -pub fn web_worker_op2<D>( - handle: WebWorkerHandle, - sender: mpsc::Sender<WorkerEvent>, - dispatcher: D, -) -> impl Fn( - &mut CoreIsolateState, - Value, - &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> -where - D: Fn( - WebWorkerHandle, - &mpsc::Sender<WorkerEvent>, - Value, - &mut [ZeroCopyBuf], - ) -> Result<JsonOp, ErrBox>, -{ - move |_isolate_state: &mut CoreIsolateState, - args: Value, - zero_copy: &mut [ZeroCopyBuf]| - -> Result<JsonOp, ErrBox> { - dispatcher(handle.clone(), &sender, args, zero_copy) - } -} - pub fn init( - i: &mut CoreIsolate, s: &Rc<State>, sender: &mpsc::Sender<WorkerEvent>, handle: WebWorkerHandle, ) { - i.register_op( + // Post message to host as guest worker. + let sender_ = sender.clone(); + s.register_op_json_sync( "op_worker_post_message", - s.core_op(json_op(web_worker_op( - sender.clone(), - op_worker_post_message, - ))), - ); - i.register_op( - "op_worker_close", - s.core_op(json_op(web_worker_op2( - handle, - sender.clone(), - op_worker_close, - ))), + move |_state, _args, bufs| { + assert_eq!(bufs.len(), 1, "Invalid number of arguments"); + let msg_buf: Box<[u8]> = (*bufs[0]).into(); + sender_ + .clone() + .try_send(WorkerEvent::Message(msg_buf)) + .expect("Failed to post message to host"); + Ok(json!({})) + }, ); -} - -/// Post message to host as guest worker -fn op_worker_post_message( - sender: &mpsc::Sender<WorkerEvent>, - _args: Value, - data: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { - assert_eq!(data.len(), 1, "Invalid number of arguments"); - let d = Vec::from(&*data[0]).into_boxed_slice(); - let mut sender = sender.clone(); - sender - .try_send(WorkerEvent::Message(d)) - .expect("Failed to post message to host"); - Ok(JsonOp::Sync(json!({}))) -} -/// Notify host that guest worker closes -fn op_worker_close( - handle: WebWorkerHandle, - sender: &mpsc::Sender<WorkerEvent>, - _args: Value, - _data: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { - let mut sender = sender.clone(); - // Notify parent that we're finished - sender.close_channel(); - // Terminate execution of current worker - handle.terminate(); - Ok(JsonOp::Sync(json!({}))) + // Notify host that guest worker closes. + let sender_ = sender.clone(); + s.register_op_json_sync("op_worker_close", move |_state, _args, _bufs| { + // Notify parent that we're finished + sender_.clone().close_channel(); + // Terminate execution of current worker + handle.terminate(); + Ok(json!({})) + }); } diff --git a/cli/ops/websocket.rs b/cli/ops/websocket.rs index 126d67861..131c52179 100644 --- a/cli/ops/websocket.rs +++ b/cli/ops/websocket.rs @@ -1,15 +1,16 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; use crate::state::State; use core::task::Poll; +use deno_core::BufVec; use deno_core::ErrBox; -use deno_core::ZeroCopyBuf; -use deno_core::{CoreIsolate, CoreIsolateState}; -use futures::future::{poll_fn, FutureExt}; +use deno_core::OpRegistry; +use futures::future::poll_fn; use futures::StreamExt; use futures::{ready, SinkExt}; use http::{Method, Request, Uri}; +use serde_derive::Deserialize; +use serde_json::Value; use std::borrow::Cow; use std::fs::File; use std::io::BufReader; @@ -25,11 +26,11 @@ use tokio_tungstenite::tungstenite::{ use tokio_tungstenite::{client_async, WebSocketStream}; use webpki::DNSNameRef; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - i.register_op("op_ws_create", s.stateful_json_op2(op_ws_create)); - i.register_op("op_ws_send", s.stateful_json_op2(op_ws_send)); - i.register_op("op_ws_close", s.stateful_json_op2(op_ws_close)); - i.register_op("op_ws_next_event", s.stateful_json_op2(op_ws_next_event)); +pub fn init(s: &Rc<State>) { + s.register_op_json_async("op_ws_create", op_ws_create); + s.register_op_json_async("op_ws_send", op_ws_send); + s.register_op_json_async("op_ws_close", op_ws_close); + s.register_op_json_async("op_ws_next_event", op_ws_next_event); } type MaybeTlsStream = @@ -44,86 +45,81 @@ struct CreateArgs { protocols: String, } -pub fn op_ws_create( - isolate_state: &mut CoreIsolateState, - state: &Rc<State>, +pub async fn op_ws_create( + state: Rc<State>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { + _bufs: BufVec, +) -> Result<Value, ErrBox> { let args: CreateArgs = serde_json::from_value(args)?; state.check_net_url(&url::Url::parse(&args.url)?)?; - let resource_table = isolate_state.resource_table.clone(); let ca_file = state.global_state.flags.ca_file.clone(); - let future = async move { - let uri: Uri = args.url.parse().unwrap(); - let request = Request::builder() - .method(Method::GET) - .uri(&uri) - .header("Sec-WebSocket-Protocol", args.protocols) - .body(()) - .unwrap(); - let domain = &uri.host().unwrap().to_string(); - let port = &uri.port_u16().unwrap_or(match uri.scheme_str() { - Some("wss") => 443, - Some("ws") => 80, - _ => unreachable!(), - }); - let addr = format!("{}:{}", domain, port); - let try_socket = TcpStream::connect(addr).await; - let tcp_socket = match try_socket.map_err(Error::Io) { - Ok(socket) => socket, - Err(_) => return Ok(json!({"success": false})), - }; + let uri: Uri = args.url.parse().unwrap(); + let request = Request::builder() + .method(Method::GET) + .uri(&uri) + .header("Sec-WebSocket-Protocol", args.protocols) + .body(()) + .unwrap(); + let domain = &uri.host().unwrap().to_string(); + let port = &uri.port_u16().unwrap_or(match uri.scheme_str() { + Some("wss") => 443, + Some("ws") => 80, + _ => unreachable!(), + }); + let addr = format!("{}:{}", domain, port); + let try_socket = TcpStream::connect(addr).await; + let tcp_socket = match try_socket.map_err(Error::Io) { + Ok(socket) => socket, + Err(_) => return Ok(json!({"success": false})), + }; - let socket: MaybeTlsStream = match uri.scheme_str() { - Some("ws") => StreamSwitcher::Plain(tcp_socket), - Some("wss") => { - let mut config = ClientConfig::new(); - config - .root_store - .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); + let socket: MaybeTlsStream = match uri.scheme_str() { + Some("ws") => StreamSwitcher::Plain(tcp_socket), + Some("wss") => { + let mut config = ClientConfig::new(); + config + .root_store + .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); - if let Some(path) = ca_file { - let key_file = File::open(path)?; - let reader = &mut BufReader::new(key_file); - config.root_store.add_pem_file(reader).unwrap(); - } - - let tls_connector = TlsConnector::from(Arc::new(config)); - let dnsname = - DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup"); - let tls_socket = tls_connector.connect(dnsname, tcp_socket).await?; - StreamSwitcher::Tls(tls_socket) + if let Some(path) = ca_file { + let key_file = File::open(path)?; + let reader = &mut BufReader::new(key_file); + config.root_store.add_pem_file(reader).unwrap(); } - _ => unreachable!(), - }; - let (stream, response): (WsStream, Response) = - client_async(request, socket).await.unwrap(); + let tls_connector = TlsConnector::from(Arc::new(config)); + let dnsname = + DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup"); + let tls_socket = tls_connector.connect(dnsname, tcp_socket).await?; + StreamSwitcher::Tls(tls_socket) + } + _ => unreachable!(), + }; + + let (stream, response): (WsStream, Response) = + client_async(request, socket).await.unwrap(); - let rid = { - let mut resource_table = resource_table.borrow_mut(); - resource_table.add("webSocketStream", Box::new(stream)) - }; + let rid = state + .resource_table + .borrow_mut() + .add("webSocketStream", Box::new(stream)); - let protocol = match response.headers().get("Sec-WebSocket-Protocol") { - Some(header) => header.to_str().unwrap(), - None => "", - }; - let extensions = response - .headers() - .get_all("Sec-WebSocket-Extensions") - .iter() - .map(|header| header.to_str().unwrap()) - .collect::<String>(); - Ok(json!({ + let protocol = match response.headers().get("Sec-WebSocket-Protocol") { + Some(header) => header.to_str().unwrap(), + None => "", + }; + let extensions = response + .headers() + .get_all("Sec-WebSocket-Extensions") + .iter() + .map(|header| header.to_str().unwrap()) + .collect::<String>(); + Ok(json!({ "success": true, "rid": rid, "protocol": protocol, "extensions": extensions - })) - }; - Ok(JsonOp::Async(future.boxed_local())) + })) } #[derive(Deserialize)] @@ -133,23 +129,21 @@ struct SendArgs { text: Option<String>, } -pub fn op_ws_send( - isolate_state: &mut CoreIsolateState, - _state: &Rc<State>, +pub async fn op_ws_send( + state: Rc<State>, args: Value, - zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { + bufs: BufVec, +) -> Result<Value, ErrBox> { let args: SendArgs = serde_json::from_value(args)?; let mut maybe_msg = Some(match args.text { Some(text) => Message::Text(text), - None => Message::Binary(zero_copy[0].to_owned().to_vec()), + None => Message::Binary(bufs[0].to_vec()), }); - let resource_table = isolate_state.resource_table.clone(); let rid = args.rid; - let future = poll_fn(move |cx| { - let mut resource_table = resource_table.borrow_mut(); + poll_fn(move |cx| { + let mut resource_table = state.resource_table.borrow_mut(); let stream = resource_table .get_mut::<WsStream>(rid) .ok_or_else(ErrBox::bad_resource_id)?; @@ -164,8 +158,8 @@ pub fn op_ws_send( ready!(stream.poll_flush_unpin(cx)).unwrap(); Poll::Ready(Ok(json!({}))) - }); - Ok(JsonOp::Async(future.boxed_local())) + }) + .await } #[derive(Deserialize)] @@ -176,14 +170,12 @@ struct CloseArgs { reason: Option<String>, } -pub fn op_ws_close( - isolate_state: &mut CoreIsolateState, - _state: &Rc<State>, +pub async fn op_ws_close( + state: Rc<State>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { + _bufs: BufVec, +) -> Result<Value, ErrBox> { let args: CloseArgs = serde_json::from_value(args)?; - let resource_table = isolate_state.resource_table.clone(); let rid = args.rid; let mut maybe_msg = Some(Message::Close(args.code.map(|c| CloseFrame { code: CloseCode::from(c), @@ -193,8 +185,8 @@ pub fn op_ws_close( }, }))); - let future = poll_fn(move |cx| { - let mut resource_table = resource_table.borrow_mut(); + poll_fn(move |cx| { + let mut resource_table = state.resource_table.borrow_mut(); let stream = resource_table .get_mut::<WsStream>(rid) .ok_or_else(ErrBox::bad_resource_id)?; @@ -210,9 +202,8 @@ pub fn op_ws_close( ready!(stream.poll_close_unpin(cx)).unwrap(); Poll::Ready(Ok(json!({}))) - }); - - Ok(JsonOp::Async(future.boxed_local())) + }) + .await } #[derive(Deserialize)] @@ -221,68 +212,48 @@ struct NextEventArgs { rid: u32, } -pub fn op_ws_next_event( - isolate_state: &mut CoreIsolateState, - _state: &Rc<State>, +pub async fn op_ws_next_event( + state: Rc<State>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result<JsonOp, ErrBox> { + _bufs: BufVec, +) -> Result<Value, ErrBox> { let args: NextEventArgs = serde_json::from_value(args)?; - let resource_table = isolate_state.resource_table.clone(); - let future = poll_fn(move |cx| { - let mut resource_table = resource_table.borrow_mut(); + poll_fn(move |cx| { + let mut resource_table = state.resource_table.borrow_mut(); let stream = resource_table .get_mut::<WsStream>(args.rid) .ok_or_else(ErrBox::bad_resource_id)?; - - stream.poll_next_unpin(cx).map(|val| { - match val { - Some(val) => { - match val { - Ok(message) => { - match message { - Message::Text(text) => Ok(json!({ - "type": "string", - "data": text - })), - Message::Binary(data) => { - Ok(json!({ //TODO: don't use json to send binary data - "type": "binary", - "data": data - })) - } - Message::Close(frame) => { - if let Some(frame) = frame { - let code: u16 = frame.code.into(); - Ok(json!({ - "type": "close", - "code": code, - "reason": frame.reason.as_ref() - })) - } else { - Ok(json!({ "type": "close" })) - } - } - Message::Ping(_) => Ok(json!({"type": "ping"})), - Message::Pong(_) => Ok(json!({"type": "pong"})), - } - } - Err(_) => Ok(json!({ - "type": "error", - })), + stream + .poll_next_unpin(cx) + .map(|val| { + match val { + Some(Ok(Message::Text(text))) => json!({ + "type": "string", + "data": text + }), + Some(Ok(Message::Binary(data))) => { + // TODO(ry): don't use json to send binary data. + json!({ + "type": "binary", + "data": data + }) + } + Some(Ok(Message::Close(Some(frame)))) => json!({ + "type": "close", + "code": u16::from(frame.code), + "reason": frame.reason.as_ref() + }), + Some(Ok(Message::Close(None))) => json!({ "type": "close" }), + Some(Ok(Message::Ping(_))) => json!({"type": "ping"}), + Some(Ok(Message::Pong(_))) => json!({"type": "pong"}), + Some(Err(_)) => json!({"type": "error"}), + None => { + resource_table.close(args.rid).unwrap(); + json!({"type": "closed"}) } } - None => { - resource_table - .close(args.rid) - .ok_or_else(ErrBox::bad_resource_id)?; - Ok(json!({ - "type": "closed", - })) - } - } - }) - }); - - Ok(JsonOp::Async(future.boxed_local())) + }) + .map(Ok) + }) + .await } diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs index 35ec11223..d2c33f005 100644 --- a/cli/ops/worker_host.rs +++ b/cli/ops/worker_host.rs @@ -1,5 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, Value}; + use crate::fmt_errors::JSError; use crate::global_state::GlobalState; use crate::ops::io::get_stdio; @@ -11,37 +11,23 @@ use crate::web_worker::WebWorker; use crate::web_worker::WebWorkerHandle; use crate::worker::WorkerEvent; use deno_core::BufVec; -use deno_core::CoreIsolate; use deno_core::ErrBox; use deno_core::ModuleSpecifier; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::ZeroCopyBuf; use futures::future::FutureExt; -use std::cell::RefCell; +use serde_derive::Deserialize; +use serde_json::Value; use std::convert::From; use std::rc::Rc; use std::sync::Arc; use std::thread::JoinHandle; -pub fn init(i: &mut CoreIsolate, s: &Rc<State>) { - let t = &CoreIsolate::state(i).borrow().resource_table.clone(); - - i.register_op( - "op_create_worker", - s.stateful_json_op_sync(t, op_create_worker), - ); - i.register_op( - "op_host_terminate_worker", - s.stateful_json_op_sync(t, op_host_terminate_worker), - ); - i.register_op( - "op_host_post_message", - s.stateful_json_op_sync(t, op_host_post_message), - ); - i.register_op( - "op_host_get_message", - s.stateful_json_op_async(t, op_host_get_message), - ); +pub fn init(s: &Rc<State>) { + s.register_op_json_sync("op_create_worker", op_create_worker); + s.register_op_json_sync("op_host_terminate_worker", op_host_terminate_worker); + s.register_op_json_sync("op_host_post_message", op_host_post_message); + s.register_op_json_async("op_host_get_message", op_host_get_message); } fn create_web_worker( @@ -63,8 +49,6 @@ fn create_web_worker( ); if has_deno_namespace { - let state_rc = CoreIsolate::state(&worker.isolate); - let state = state_rc.borrow(); let mut resource_table = state.resource_table.borrow_mut(); let (stdin, stdout, stderr) = get_stdio(); if let Some(stream) = stdin { @@ -189,7 +173,6 @@ struct CreateWorkerArgs { /// Create worker as the host fn op_create_worker( state: &State, - _resource_table: &mut ResourceTable, args: Value, _data: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -240,7 +223,6 @@ struct WorkerArgs { fn op_host_terminate_worker( state: &State, - _resource_table: &mut ResourceTable, args: Value, _data: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { @@ -309,7 +291,6 @@ fn serialize_worker_event(event: WorkerEvent) -> Value { /// Get message from guest worker as host async fn op_host_get_message( state: Rc<State>, - _resource_table: Rc<RefCell<ResourceTable>>, args: Value, _zero_copy: BufVec, ) -> Result<Value, ErrBox> { @@ -358,7 +339,6 @@ async fn op_host_get_message( /// Post message to guest worker as host fn op_host_post_message( state: &State, - _resource_table: &mut ResourceTable, args: Value, data: &mut [ZeroCopyBuf], ) -> Result<Value, ErrBox> { diff --git a/cli/permissions.rs b/cli/permissions.rs index 577ebd40e..327b17267 100644 --- a/cli/permissions.rs +++ b/cli/permissions.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::colors; use crate::flags::Flags; use crate::fs::resolve_from_cwd; diff --git a/cli/repl.rs b/cli/repl.rs index 28b99cf07..8387de05f 100644 --- a/cli/repl.rs +++ b/cli/repl.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::deno_dir::DenoDir; use deno_core::ErrBox; use rustyline::Editor; diff --git a/cli/resolve_addr.rs b/cli/resolve_addr.rs index a25bf7454..66ee470c9 100644 --- a/cli/resolve_addr.rs +++ b/cli/resolve_addr.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use deno_core::ErrBox; use std::net::SocketAddr; use std::net::ToSocketAddrs; diff --git a/cli/signal.rs b/cli/signal.rs index 5c9a7d717..200f8f3bc 100644 --- a/cli/signal.rs +++ b/cli/signal.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use deno_core::ErrBox; #[cfg(not(unix))] diff --git a/cli/startup_data.rs b/cli/startup_data.rs index 2f209a378..1cdfb4188 100644 --- a/cli/startup_data.rs +++ b/cli/startup_data.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::js::CLI_SNAPSHOT; use crate::js::COMPILER_SNAPSHOT; use deno_core::Snapshot; diff --git a/cli/state.rs b/cli/state.rs index 9f225e522..c85701bac 100644 --- a/cli/state.rs +++ b/cli/state.rs @@ -1,31 +1,30 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +use crate::errors::get_error_class_name; use crate::file_fetcher::SourceFileFetcher; use crate::global_state::GlobalState; use crate::global_timer::GlobalTimer; use crate::http_util::create_http_client; use crate::import_map::ImportMap; use crate::metrics::Metrics; -use crate::ops::serialize_result; -use crate::ops::JsonOp; -use crate::ops::MinimalOp; use crate::permissions::Permissions; use crate::tsc::TargetLib; use crate::web_worker::WebWorkerHandle; -use deno_core::Buf; use deno_core::BufVec; -use deno_core::CoreIsolateState; use deno_core::ErrBox; use deno_core::ModuleLoadId; use deno_core::ModuleLoader; use deno_core::ModuleSpecifier; use deno_core::Op; +use deno_core::OpId; +use deno_core::OpRegistry; +use deno_core::OpRouter; +use deno_core::OpTable; use deno_core::ResourceTable; -use deno_core::ZeroCopyBuf; use futures::future::FutureExt; use futures::Future; use rand::rngs::StdRng; use rand::SeedableRng; -use serde_json::Value; use std::cell::Cell; use std::cell::RefCell; use std::collections::HashMap; @@ -55,266 +54,11 @@ pub struct State { pub is_main: bool, pub is_internal: bool, pub http_client: RefCell<reqwest::Client>, + pub resource_table: RefCell<ResourceTable>, + pub op_table: RefCell<OpTable<Self>>, } impl State { - pub fn stateful_json_op_sync<D>( - self: &Rc<Self>, - resource_table: &Rc<RefCell<ResourceTable>>, - dispatcher: D, - ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op - where - D: Fn( - &State, - &mut ResourceTable, - Value, - &mut [ZeroCopyBuf], - ) -> Result<Value, ErrBox>, - { - let state = self.clone(); - let resource_table = resource_table.clone(); - - let f = move |isolate_state: &mut CoreIsolateState, - bufs: &mut [ZeroCopyBuf]| { - let get_error_class_fn = isolate_state.get_error_class_fn; - - // The first buffer should contain JSON encoded op arguments; parse them. - let args: Value = match serde_json::from_slice(&bufs[0]) { - Ok(v) => v, - Err(e) => { - return Op::Sync(serialize_result( - None, - Err(e.into()), - get_error_class_fn, - )); - } - }; - - // Make a slice containing all buffers except for the first one. - let zero_copy = &mut bufs[1..]; - - let result = - dispatcher(&state, &mut *resource_table.borrow_mut(), args, zero_copy); - - // Convert to Op. - Op::Sync(serialize_result(None, result, get_error_class_fn)) - }; - self.core_op(f) - } - - pub fn stateful_json_op_async<D, F>( - self: &Rc<Self>, - resource_table: &Rc<RefCell<ResourceTable>>, - dispatcher: D, - ) -> impl Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op - where - D: - FnOnce(Rc<State>, Rc<RefCell<ResourceTable>>, Value, BufVec) -> F + Clone, - F: Future<Output = Result<Value, ErrBox>> + 'static, - { - let state = self.clone(); - let resource_table = resource_table.clone(); - - let f = move |isolate_state: &mut CoreIsolateState, - bufs: &mut [ZeroCopyBuf]| { - let get_error_class_fn = isolate_state.get_error_class_fn; - - // The first buffer should contain JSON encoded op arguments; parse them. - let args: Value = match serde_json::from_slice(&bufs[0]) { - Ok(v) => v, - Err(e) => { - let e = e.into(); - return Op::Sync(serialize_result(None, Err(e), get_error_class_fn)); - } - }; - - // `args` should have a `promiseId` property with positive integer value. - let promise_id = match args.get("promiseId").and_then(|v| v.as_u64()) { - Some(i) => i, - None => { - let e = ErrBox::new("TypeError", "`promiseId` invalid/missing"); - return Op::Sync(serialize_result(None, Err(e), get_error_class_fn)); - } - }; - - // Take ownership of all buffers after the first one. - let zero_copy: BufVec = bufs[1..].into(); - - // Call dispatcher to obtain op future. - let fut = (dispatcher.clone())( - state.clone(), - resource_table.clone(), - args, - zero_copy, - ); - - // Convert to Op. - Op::Async( - async move { - serialize_result(Some(promise_id), fut.await, get_error_class_fn) - } - .boxed_local(), - ) - }; - self.core_op(f) - } - - // TODO(bartlomieju): remove me - still used by `op_open_plugin` which - // needs access to isolate_state - pub fn stateful_json_op2<D>( - self: &Rc<Self>, - dispatcher: D, - ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op - where - D: Fn( - &mut deno_core::CoreIsolateState, - &Rc<State>, - Value, - &mut [ZeroCopyBuf], - ) -> Result<JsonOp, ErrBox>, - { - use crate::ops::json_op; - self.core_op(json_op(self.stateful_op2(dispatcher))) - } - - /// Wrap core `OpDispatcher` to collect metrics. - // TODO(ry) this should be private. Is called by stateful_json_op or - // stateful_minimal_op - pub(crate) fn core_op<D>( - self: &Rc<Self>, - dispatcher: D, - ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op - where - D: Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op, - { - let state = self.clone(); - - move |isolate_state: &mut deno_core::CoreIsolateState, - zero_copy: &mut [ZeroCopyBuf]| - -> Op { - let bytes_sent_control = - zero_copy.get(0).map(|s| s.len()).unwrap_or(0) as u64; - let bytes_sent_zero_copy = - zero_copy[1..].iter().map(|b| b.len()).sum::<usize>() as u64; - - let op = dispatcher(isolate_state, zero_copy); - - match op { - Op::Sync(buf) => { - state.metrics.borrow_mut().op_sync( - bytes_sent_control, - bytes_sent_zero_copy, - buf.len() as u64, - ); - Op::Sync(buf) - } - Op::Async(fut) => { - state - .metrics - .borrow_mut() - .op_dispatched_async(bytes_sent_control, bytes_sent_zero_copy); - let state = state.clone(); - let result_fut = fut.map(move |buf: Buf| { - state - .metrics - .borrow_mut() - .op_completed_async(buf.len() as u64); - buf - }); - Op::Async(result_fut.boxed_local()) - } - Op::AsyncUnref(fut) => { - state.metrics.borrow_mut().op_dispatched_async_unref( - bytes_sent_control, - bytes_sent_zero_copy, - ); - let state = state.clone(); - let result_fut = fut.map(move |buf: Buf| { - state - .metrics - .borrow_mut() - .op_completed_async_unref(buf.len() as u64); - buf - }); - Op::AsyncUnref(result_fut.boxed_local()) - } - } - } - } - - pub fn stateful_minimal_op2<D>( - self: &Rc<Self>, - dispatcher: D, - ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op - where - D: Fn( - &mut deno_core::CoreIsolateState, - &Rc<State>, - bool, - i32, - &mut [ZeroCopyBuf], - ) -> MinimalOp, - { - let state = self.clone(); - self.core_op(crate::ops::minimal_op( - move |isolate_state: &mut deno_core::CoreIsolateState, - is_sync: bool, - rid: i32, - zero_copy: &mut [ZeroCopyBuf]| - -> MinimalOp { - dispatcher(isolate_state, &state, is_sync, rid, zero_copy) - }, - )) - } - - /// This is a special function that provides `state` argument to dispatcher. - /// - /// NOTE: This only works with JSON dispatcher. - /// This is a band-aid for transition to `CoreIsolate.register_op` API as most of our - /// ops require `state` argument. - pub fn stateful_op<D>( - self: &Rc<Self>, - dispatcher: D, - ) -> impl Fn( - &mut deno_core::CoreIsolateState, - Value, - &mut [ZeroCopyBuf], - ) -> Result<JsonOp, ErrBox> - where - D: Fn(&Rc<State>, Value, &mut [ZeroCopyBuf]) -> Result<JsonOp, ErrBox>, - { - let state = self.clone(); - move |_isolate_state: &mut deno_core::CoreIsolateState, - args: Value, - zero_copy: &mut [ZeroCopyBuf]| - -> Result<JsonOp, ErrBox> { dispatcher(&state, args, zero_copy) } - } - - pub fn stateful_op2<D>( - self: &Rc<Self>, - dispatcher: D, - ) -> impl Fn( - &mut deno_core::CoreIsolateState, - Value, - &mut [ZeroCopyBuf], - ) -> Result<JsonOp, ErrBox> - where - D: Fn( - &mut deno_core::CoreIsolateState, - &Rc<State>, - Value, - &mut [ZeroCopyBuf], - ) -> Result<JsonOp, ErrBox>, - { - let state = self.clone(); - move |isolate_state: &mut deno_core::CoreIsolateState, - args: Value, - zero_copy: &mut [ZeroCopyBuf]| - -> Result<JsonOp, ErrBox> { - dispatcher(isolate_state, &state, args, zero_copy) - } - } - /// Quits the process if the --unstable flag was not provided. /// /// This is intentionally a non-recoverable check so that people cannot probe @@ -458,6 +202,8 @@ impl State { is_main: true, is_internal, http_client: create_http_client(fl.ca_file.as_deref())?.into(), + resource_table: Default::default(), + op_table: Default::default(), }; Ok(Rc::new(state)) } @@ -486,6 +232,8 @@ impl State { is_main: false, is_internal: false, http_client: create_http_client(fl.ca_file.as_deref())?.into(), + resource_table: Default::default(), + op_table: Default::default(), }; Ok(Rc::new(state)) } @@ -570,7 +318,7 @@ impl State { } #[cfg(test)] - pub fn mock(main_module: &str) -> Rc<State> { + pub fn mock(main_module: &str) -> Rc<Self> { let module_specifier = ModuleSpecifier::resolve_url_or_path(main_module) .expect("Invalid entry module"); State::new( @@ -583,3 +331,78 @@ impl State { .unwrap() } } + +impl OpRouter for State { + fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op { + // TODOs: + // * The 'bytes' metrics seem pretty useless, especially now that the + // distinction between 'control' and 'data' buffers has become blurry. + // * Tracking completion of async ops currently makes us put the boxed + // future into _another_ box. Keeping some counters may not be expensive + // in itself, but adding a heap allocation for every metric seems bad. + let mut buf_len_iter = bufs.iter().map(|buf| buf.len()); + let bytes_sent_control = buf_len_iter.next().unwrap_or(0); + let bytes_sent_data = buf_len_iter.sum(); + + let op_fn = self + .op_table + .borrow() + .get_index(op_id) + .map(|(_, op_fn)| op_fn.clone()) + .unwrap(); + + let self_ = self.clone(); + let op = (op_fn)(self_, bufs); + + let self_ = self.clone(); + let mut metrics = self_.metrics.borrow_mut(); + match op { + Op::Sync(buf) => { + metrics.op_sync(bytes_sent_control, bytes_sent_data, buf.len()); + Op::Sync(buf) + } + Op::Async(fut) => { + metrics.op_dispatched_async(bytes_sent_control, bytes_sent_data); + let fut = fut + .inspect(move |buf| { + self.metrics.borrow_mut().op_completed_async(buf.len()); + }) + .boxed_local(); + Op::Async(fut) + } + Op::AsyncUnref(fut) => { + metrics.op_dispatched_async_unref(bytes_sent_control, bytes_sent_data); + let fut = fut + .inspect(move |buf| { + self + .metrics + .borrow_mut() + .op_completed_async_unref(buf.len()); + }) + .boxed_local(); + Op::AsyncUnref(fut) + } + other => other, + } + } +} + +impl OpRegistry for State { + fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId> { + self.op_table.borrow().get_op_catalog() + } + + fn register_op<F>(&self, name: &str, op_fn: F) -> OpId + where + F: Fn(Rc<Self>, BufVec) -> Op + 'static, + { + let mut op_table = self.op_table.borrow_mut(); + let (op_id, prev) = op_table.insert_full(name.to_owned(), Rc::new(op_fn)); + assert!(prev.is_none()); + op_id + } + + fn get_error_class_name(&self, err: &ErrBox) -> &'static str { + get_error_class_name(err) + } +} diff --git a/cli/swc_util.rs b/cli/swc_util.rs index f354a0fe3..f54f187e3 100644 --- a/cli/swc_util.rs +++ b/cli/swc_util.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::msg::MediaType; use deno_core::ErrBox; use serde::Serialize; @@ -304,7 +305,7 @@ pub fn transpile( Optional::new(jsx_pass, options.transform_jsx), decorators::decorators(decorators::Config { legacy: true, - emit_metadata: options.emit_metadata, + emit_metadata: options.emit_metadata }), typescript::strip(), fixer(Some(&ast_parser.comments)), diff --git a/cli/text_encoding.rs b/cli/text_encoding.rs index 9d8e5bcc9..bf40f3a3c 100644 --- a/cli/text_encoding.rs +++ b/cli/text_encoding.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use encoding_rs::*; use std::{ borrow::Cow, diff --git a/cli/tsc.rs b/cli/tsc.rs index bf4e4fe5c..118dc86ae 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -139,14 +139,13 @@ impl CompilerWorker { startup_data: StartupData, state: &Rc<State>, ) -> Self { - let mut worker = Worker::new(name, startup_data, state); + let worker = Worker::new(name, startup_data, state); let response = Arc::new(Mutex::new(None)); { - let isolate = &mut worker.isolate; - ops::runtime::init(isolate, &state); - ops::errors::init(isolate, &state); - ops::timers::init(isolate, &state); - ops::compiler::init(isolate, &state, response.clone()); + ops::runtime::init(&state); + ops::errors::init(&state); + ops::timers::init(&state); + ops::compiler::init(&state, response.clone()); } Self { worker, response } @@ -1437,7 +1436,7 @@ pub async fn runtime_transpile( let json_str = execute_in_same_thread(global_state, permissions, req_msg) .await .map_err(js_error_to_errbox)?; - let v = serde_json::from_str::<serde_json::Value>(&json_str) + let v = serde_json::from_str::<Value>(&json_str) .expect("Error decoding JSON string."); Ok(v) } diff --git a/cli/version.rs b/cli/version.rs index b1ac42d39..6967d7435 100644 --- a/cli/version.rs +++ b/cli/version.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + pub const DENO: &str = env!("CARGO_PKG_VERSION"); pub const TYPESCRIPT: &str = crate::js::TS_VERSION; diff --git a/cli/web_worker.rs b/cli/web_worker.rs index 9b42ebe32..095d5b376 100644 --- a/cli/web_worker.rs +++ b/cli/web_worker.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use crate::ops; use crate::state::State; use crate::worker::Worker; @@ -101,7 +102,7 @@ impl WebWorker { terminate_tx, }; - let mut web_worker = Self { + let web_worker = Self { worker, event_loop_idle: false, terminate_rx, @@ -112,36 +113,34 @@ impl WebWorker { let handle = web_worker.thread_safe_handle(); { - let isolate = &mut web_worker.worker.isolate; - ops::runtime::init(isolate, &state); + ops::runtime::init(&state); ops::web_worker::init( - isolate, &state, &web_worker.worker.internal_channels.sender, handle, ); - ops::worker_host::init(isolate, &state); - ops::idna::init(isolate, &state); - ops::io::init(isolate, &state); - ops::resources::init(isolate, &state); - ops::errors::init(isolate, &state); - ops::timers::init(isolate, &state); - ops::fetch::init(isolate, &state); - ops::websocket::init(isolate, &state); + ops::worker_host::init(&state); + ops::idna::init(&state); + ops::io::init(&state); + ops::resources::init(&state); + ops::errors::init(&state); + ops::timers::init(&state); + ops::fetch::init(&state); + ops::websocket::init(&state); if has_deno_namespace { - ops::runtime_compiler::init(isolate, &state); - ops::fs::init(isolate, &state); - ops::fs_events::init(isolate, &state); - ops::plugin::init(isolate, &state); - ops::net::init(isolate, &state); - ops::tls::init(isolate, &state); - ops::os::init(isolate, &state); - ops::permissions::init(isolate, &state); - ops::process::init(isolate, &state); - ops::random::init(isolate, &state); - ops::signal::init(isolate, &state); - ops::tty::init(isolate, &state); + ops::runtime_compiler::init(&state); + ops::fs::init(&state); + ops::fs_events::init(&state); + ops::plugin::init(&state); + ops::net::init(&state); + ops::tls::init(&state); + ops::os::init(&state); + ops::permissions::init(&state); + ops::process::init(&state); + ops::random::init(&state); + ops::signal::init(&state); + ops::tty::init(&state); } } diff --git a/cli/worker.rs b/cli/worker.rs index 3773871dc..3aaf92f48 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -1,5 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::errors::get_error_class; + use crate::fmt_errors::JSError; use crate::global_state::GlobalState; use crate::inspector::DenoInspector; @@ -7,7 +7,6 @@ use crate::ops; use crate::ops::io::get_stdio; use crate::startup_data; use crate::state::State; -use deno_core::Buf; use deno_core::CoreIsolate; use deno_core::ErrBox; use deno_core::ModuleId; @@ -32,25 +31,25 @@ use url::Url; /// Events that are sent to host from child /// worker. pub enum WorkerEvent { - Message(Buf), + Message(Box<[u8]>), Error(ErrBox), TerminalError(ErrBox), } pub struct WorkerChannelsInternal { pub sender: mpsc::Sender<WorkerEvent>, - pub receiver: mpsc::Receiver<Buf>, + pub receiver: mpsc::Receiver<Box<[u8]>>, } #[derive(Clone)] pub struct WorkerHandle { - pub sender: mpsc::Sender<Buf>, + pub sender: mpsc::Sender<Box<[u8]>>, pub receiver: Arc<AsyncMutex<mpsc::Receiver<WorkerEvent>>>, } impl WorkerHandle { /// Post message to worker as a host. - pub fn post_message(&self, buf: Buf) -> Result<(), ErrBox> { + pub fn post_message(&self, buf: Box<[u8]>) -> Result<(), ErrBox> { let mut sender = self.sender.clone(); sender.try_send(buf)?; Ok(()) @@ -65,7 +64,7 @@ impl WorkerHandle { } fn create_channels() -> (WorkerChannelsInternal, WorkerHandle) { - let (in_tx, in_rx) = mpsc::channel::<Buf>(1); + let (in_tx, in_rx) = mpsc::channel::<Box<[u8]>>(1); let (out_tx, out_rx) = mpsc::channel::<WorkerEvent>(1); let internal_channels = WorkerChannelsInternal { sender: out_tx, @@ -106,8 +105,12 @@ impl Worker { startup_data: StartupData, state: &Rc<State>, ) -> Self { - let mut isolate = - deno_core::EsIsolate::new(state.clone(), startup_data, false); + let mut isolate = deno_core::EsIsolate::new( + state.clone(), + state.clone(), + startup_data, + false, + ); { let global_state = state.global_state.clone(); @@ -116,7 +119,6 @@ impl Worker { core_state.set_js_error_create_fn(move |core_js_error| { JSError::create(core_js_error, &global_state.ts_compiler) }); - core_state.set_get_error_class_fn(&get_error_class); } let inspector = { @@ -256,31 +258,30 @@ pub struct MainWorker(Worker); impl MainWorker { // TODO(ry) combine MainWorker::new and MainWorker::create. fn new(name: String, startup_data: StartupData, state: &Rc<State>) -> Self { - let mut worker = Worker::new(name, startup_data, state); + let worker = Worker::new(name, startup_data, state); { - let isolate = &mut worker.isolate; - ops::runtime::init(isolate, &state); - ops::runtime_compiler::init(isolate, &state); - ops::errors::init(isolate, &state); - ops::fetch::init(isolate, &state); - ops::websocket::init(isolate, &state); - ops::fs::init(isolate, &state); - ops::fs_events::init(isolate, &state); - ops::idna::init(isolate, &state); - ops::io::init(isolate, &state); - ops::plugin::init(isolate, &state); - ops::net::init(isolate, &state); - ops::tls::init(isolate, &state); - ops::os::init(isolate, &state); - ops::permissions::init(isolate, &state); - ops::process::init(isolate, &state); - ops::random::init(isolate, &state); - ops::repl::init(isolate, &state); - ops::resources::init(isolate, &state); - ops::signal::init(isolate, &state); - ops::timers::init(isolate, &state); - ops::tty::init(isolate, &state); - ops::worker_host::init(isolate, &state); + ops::runtime::init(&state); + ops::runtime_compiler::init(&state); + ops::errors::init(&state); + ops::fetch::init(&state); + ops::websocket::init(&state); + ops::fs::init(&state); + ops::fs_events::init(&state); + ops::idna::init(&state); + ops::io::init(&state); + ops::plugin::init(&state); + ops::net::init(&state); + ops::tls::init(&state); + ops::os::init(&state); + ops::permissions::init(&state); + ops::process::init(&state); + ops::random::init(&state); + ops::repl::init(&state); + ops::resources::init(&state); + ops::signal::init(&state); + ops::timers::init(&state); + ops::tty::init(&state); + ops::worker_host::init(&state); } Self(worker) } @@ -302,10 +303,8 @@ impl MainWorker { &state, ); { - let (stdin, stdout, stderr) = get_stdio(); - let state_rc = CoreIsolate::state(&worker.isolate); - let state = state_rc.borrow(); let mut t = state.resource_table.borrow_mut(); + let (stdin, stdout, stderr) = get_stdio(); if let Some(stream) = stdin { t.add("stdin", Box::new(stream)); } diff --git a/core/Cargo.toml b/core/Cargo.toml index 37d2f3268..94681cf7d 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -22,6 +22,7 @@ rusty_v8 = "0.9.1" serde_json = { version = "1.0.57", features = ["preserve_order"] } smallvec = "1.4.2" url = "2.1.1" +indexmap = "1.5.2" [[example]] name = "http_bench_bin_ops" diff --git a/core/basic_state.rs b/core/basic_state.rs new file mode 100644 index 000000000..54b9ee132 --- /dev/null +++ b/core/basic_state.rs @@ -0,0 +1,91 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +use crate::BufVec; +use crate::Op; +use crate::OpId; +use crate::OpRegistry; +use crate::OpRouter; +use crate::OpTable; +use crate::ResourceTable; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +/// A minimal state struct for use by tests, examples etc. It contains +/// an OpTable and ResourceTable, and implements the relevant traits +/// for working with ops in the most straightforward way possible. +#[derive(Default)] +pub struct BasicState { + pub op_table: RefCell<OpTable<Self>>, + pub resource_table: RefCell<ResourceTable>, +} + +impl BasicState { + pub fn new() -> Rc<Self> { + Default::default() + } +} + +impl OpRegistry for BasicState { + fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId> { + self.op_table.borrow().get_op_catalog() + } + + fn register_op<F>(&self, name: &str, op_fn: F) -> OpId + where + F: Fn(Rc<Self>, BufVec) -> Op + 'static, + { + let mut op_table = self.op_table.borrow_mut(); + let (op_id, prev) = op_table.insert_full(name.to_owned(), Rc::new(op_fn)); + assert!(prev.is_none()); + op_id + } +} + +impl OpRouter for BasicState { + fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op { + let op_fn = self + .op_table + .borrow() + .get_index(op_id) + .map(|(_, op_fn)| op_fn.clone()) + .unwrap(); + (op_fn)(self, bufs) + } +} + +#[test] +fn test_basic_state_ops() { + let state = BasicState::new(); + + let foo_id = state.register_op("foo", |_, _| Op::Sync(b"oof!"[..].into())); + assert_eq!(foo_id, 1); + + let bar_id = state.register_op("bar", |_, _| Op::Sync(b"rab!"[..].into())); + assert_eq!(bar_id, 2); + + let state_ = state.clone(); + let foo_res = state_.route_op(foo_id, Default::default()); + assert!(matches!(foo_res, Op::Sync(buf) if &*buf == b"oof!")); + + let state_ = state.clone(); + let bar_res = state_.route_op(bar_id, Default::default()); + assert!(matches!(bar_res, Op::Sync(buf) if &*buf == b"rab!")); + + let catalog_res = state.route_op(0, Default::default()); + let mut catalog_entries = match catalog_res { + Op::Sync(buf) => serde_json::from_slice::<HashMap<String, OpId>>(&buf) + .map(|map| map.into_iter().collect::<Vec<_>>()) + .unwrap(), + _ => panic!("unexpected `Op` variant"), + }; + catalog_entries.sort_by(|(_, id1), (_, id2)| id1.partial_cmp(id2).unwrap()); + assert_eq!( + catalog_entries, + vec![ + ("ops".to_owned(), 0), + ("foo".to_owned(), 1), + ("bar".to_owned(), 2) + ] + ) +} diff --git a/core/bindings.rs b/core/bindings.rs index f0181a227..166c0ee6e 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -2,18 +2,19 @@ use crate::CoreIsolate; use crate::CoreIsolateState; +use crate::ErrBox; use crate::EsIsolate; use crate::JSError; +use crate::Op; +use crate::OpId; use crate::ZeroCopyBuf; - +use futures::future::FutureExt; use rusty_v8 as v8; -use v8::MapFnTo; - -use smallvec::SmallVec; use std::cell::Cell; use std::convert::TryFrom; use std::option::Option; use url::Url; +use v8::MapFnTo; lazy_static! { pub static ref EXTERNAL_REFERENCES: v8::ExternalReferences = @@ -49,7 +50,7 @@ lazy_static! { function: decode.map_fn_to() }, v8::ExternalReference { - function: get_promise_details.map_fn_to(), + function: get_promise_details.map_fn_to() } ]); } @@ -371,13 +372,19 @@ fn recv( slot.replace(v8::Global::new(scope, cb)); } -fn send( - scope: &mut v8::HandleScope, +fn send<'s>( + scope: &mut v8::HandleScope<'s>, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { - let op_id = match v8::Local::<v8::Uint32>::try_from(args.get(0)) { - Ok(op_id) => op_id.value() as u32, + let state_rc = CoreIsolate::state(scope); + let state = state_rc.borrow_mut(); + + let op_id = match v8::Local::<v8::Integer>::try_from(args.get(0)) + .map_err(ErrBox::from) + .and_then(|l| OpId::try_from(l.value()).map_err(ErrBox::from)) + { + Ok(op_id) => op_id, Err(err) => { let msg = format!("invalid op id: {}", err); let msg = v8::String::new(scope, &msg).unwrap(); @@ -387,9 +394,6 @@ fn send( } }; - let state_rc = CoreIsolate::state(scope); - let mut state = state_rc.borrow_mut(); - let buf_iter = (1..args.length()).map(|idx| { v8::Local::<v8::ArrayBufferView>::try_from(args.get(idx)) .map(|view| ZeroCopyBuf::new(scope, view)) @@ -400,24 +404,37 @@ fn send( }) }); - // 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; - } - }; - - 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; + let bufs = match buf_iter.collect::<Result<_, _>>() { + Ok(bufs) => bufs, + Err(exc) => { + scope.throw_exception(exc); + return; + } + }; - if !buf.is_empty() { - let ui8 = boxed_slice_to_uint8array(scope, buf); - rv.set(ui8.into()); + let op_router = state.op_router.clone(); + let op = op_router.route_op(op_id, bufs); + assert_eq!(state.shared.size(), 0); + match op { + Op::Sync(buf) if !buf.is_empty() => { + rv.set(boxed_slice_to_uint8array(scope, buf).into()); + } + Op::Sync(_) => {} + Op::Async(fut) => { + let fut2 = fut.map(move |buf| (op_id, buf)); + state.pending_ops.push(fut2.boxed_local()); + state.have_unpolled_ops.set(true); + } + Op::AsyncUnref(fut) => { + let fut2 = fut.map(move |buf| (op_id, buf)); + state.pending_unref_ops.push(fut2.boxed_local()); + state.have_unpolled_ops.set(true); + } + Op::NotFound => { + let msg = format!("Unknown op id: {}", op_id); + let msg = v8::String::new(scope, &msg).unwrap(); + let exc = v8::Exception::type_error(scope, msg); + scope.throw_exception(exc); } } } diff --git a/core/core_isolate.rs b/core/core_isolate.rs index a60ce6a82..52e856174 100644 --- a/core/core_isolate.rs +++ b/core/core_isolate.rs @@ -13,16 +13,12 @@ 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::FuturesUnordered; use futures::stream::StreamExt; use futures::task::AtomicWaker; use futures::Future; -use serde_json::json; -use serde_json::Value; use std::any::Any; +use std::cell::Cell; use std::cell::RefCell; use std::collections::HashMap; use std::convert::From; @@ -37,7 +33,7 @@ use std::sync::Once; use std::task::Context; use std::task::Poll; -type PendingOpFuture = Pin<Box<dyn Future<Output = (OpId, Buf)>>>; +type PendingOpFuture = Pin<Box<dyn Future<Output = (OpId, Box<[u8]>)>>>; /// Stores a script used to initialize a Isolate pub struct Script<'a> { @@ -87,7 +83,7 @@ impl StartupData<'_> { type JSErrorCreateFn = dyn Fn(JSError) -> ErrBox; -pub type GetErrorClassFn = &'static dyn for<'e> Fn(&'e ErrBox) -> &'static str; +pub type GetErrorClassFn = dyn for<'e> Fn(&'e ErrBox) -> &'static str; /// Objects that need to live as long as the isolate #[derive(Default)] @@ -118,19 +114,17 @@ pub struct CoreIsolate { /// Internal state for CoreIsolate which is stored in one of v8::Isolate's /// embedder slots. pub struct CoreIsolateState { - pub resource_table: Rc<RefCell<ResourceTable>>, pub global_context: Option<v8::Global<v8::Context>>, pub(crate) shared_ab: Option<v8::Global<v8::SharedArrayBuffer>>, pub(crate) js_recv_cb: Option<v8::Global<v8::Function>>, pub(crate) js_macrotask_cb: Option<v8::Global<v8::Function>>, pub(crate) pending_promise_exceptions: HashMap<i32, v8::Global<v8::Value>>, pub(crate) js_error_create_fn: Box<JSErrorCreateFn>, - pub get_error_class_fn: GetErrorClassFn, pub(crate) shared: SharedQueue, - pending_ops: FuturesUnordered<PendingOpFuture>, - pending_unref_ops: FuturesUnordered<PendingOpFuture>, - have_unpolled_ops: bool, - pub op_registry: OpRegistry, + pub(crate) pending_ops: FuturesUnordered<PendingOpFuture>, + pub(crate) pending_unref_ops: FuturesUnordered<PendingOpFuture>, + pub(crate) have_unpolled_ops: Cell<bool>, + pub(crate) op_router: Rc<dyn OpRouter>, waker: AtomicWaker, } @@ -205,21 +199,27 @@ pub struct HeapLimits { } pub(crate) struct IsolateOptions { - will_snapshot: bool, + op_router: Rc<dyn OpRouter>, startup_script: Option<OwnedScript>, startup_snapshot: Option<Snapshot>, + will_snapshot: bool, heap_limits: Option<HeapLimits>, } impl CoreIsolate { /// startup_data defines the snapshot or script used at startup to initialize /// the isolate. - pub fn new(startup_data: StartupData, will_snapshot: bool) -> Self { + pub fn new( + op_router: Rc<dyn OpRouter>, + startup_data: StartupData, + will_snapshot: bool, + ) -> Self { let (startup_script, startup_snapshot) = startup_data.into_options(); let options = IsolateOptions { - will_snapshot, + op_router, startup_script, startup_snapshot, + will_snapshot, heap_limits: None, }; @@ -233,14 +233,16 @@ impl CoreIsolate { /// Make sure to use [`add_near_heap_limit_callback`](#method.add_near_heap_limit_callback) /// to prevent v8 from crashing when reaching the upper limit. pub fn with_heap_limits( + op_router: Rc<dyn OpRouter>, startup_data: StartupData, heap_limits: HeapLimits, ) -> Self { let (startup_script, startup_snapshot) = startup_data.into_options(); let options = IsolateOptions { - will_snapshot: false, + op_router, startup_script, startup_snapshot, + will_snapshot: false, heap_limits: Some(heap_limits), }; @@ -304,18 +306,16 @@ impl CoreIsolate { isolate.set_slot(Rc::new(RefCell::new(CoreIsolateState { global_context: Some(global_context), - resource_table: Rc::new(RefCell::new(ResourceTable::default())), pending_promise_exceptions: HashMap::new(), shared_ab: None, js_recv_cb: None, js_macrotask_cb: None, js_error_create_fn: Box::new(JSError::create), - get_error_class_fn: &|_| "Error", shared: SharedQueue::new(RECOMMENDED_SIZE), pending_ops: FuturesUnordered::new(), pending_unref_ops: FuturesUnordered::new(), - have_unpolled_ops: false, - op_registry: OpRegistry::new(), + have_unpolled_ops: Cell::new(false), + op_router: options.op_router, waker: AtomicWaker::new(), }))); @@ -421,66 +421,6 @@ impl CoreIsolate { snapshot } - /// Defines the how Deno.core.dispatch() acts. - /// Called whenever Deno.core.dispatch() is called in JavaScript. zero_copy_buf - /// corresponds to the second argument of Deno.core.dispatch(). - /// - /// 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, &mut [ZeroCopyBuf]) -> Op + 'static, - { - let state_rc = Self::state(self); - let mut state = state_rc.borrow_mut(); - state.op_registry.register(name, op) - } - - pub fn register_op_json_sync<F>(&mut self, name: &str, op: F) -> OpId - where - F: 'static - + Fn( - &mut CoreIsolateState, - serde_json::Value, - &mut [ZeroCopyBuf], - ) -> Result<serde_json::Value, ErrBox>, - { - let core_op = - move |state: &mut CoreIsolateState, bufs: &mut [ZeroCopyBuf]| -> Op { - let value = serde_json::from_slice(&bufs[0]).unwrap(); - let result = op(state, value, &mut bufs[1..]); - let buf = serialize_result(None, result, state.get_error_class_fn); - Op::Sync(buf) - }; - - let state_rc = Self::state(self); - let mut state = state_rc.borrow_mut(); - state.op_registry.register(name, core_op) - } - - pub fn register_op_json_async<F, Fut>(&mut self, name: &str, op: F) -> OpId - where - Fut: 'static + Future<Output = Result<serde_json::Value, ErrBox>>, - F: 'static - + Fn(&mut CoreIsolateState, serde_json::Value, &mut [ZeroCopyBuf]) -> Fut, - { - let core_op = move |state: &mut CoreIsolateState, - bufs: &mut [ZeroCopyBuf]| - -> Op { - let get_error_class_fn = state.get_error_class_fn; - let value: serde_json::Value = serde_json::from_slice(&bufs[0]).unwrap(); - let promise_id = value.get("promiseId").unwrap().as_u64().unwrap(); - let fut = op(state, value, &mut bufs[1..]); - let fut2 = fut.map(move |result| { - serialize_result(Some(promise_id), result, get_error_class_fn) - }); - Op::Async(Box::pin(fut2)) - }; - - let state_rc = Self::state(self); - let mut state = state_rc.borrow_mut(); - state.op_registry.register(name, core_op) - } - /// Registers a callback on the isolate when the memory limits are approached. /// Use this to prevent V8 from crashing the process when reaching the limit. /// @@ -536,24 +476,6 @@ where callback(current_heap_limit, initial_heap_limit) } -fn serialize_result( - promise_id: Option<u64>, - result: Result<Value, ErrBox>, - get_error_class_fn: GetErrorClassFn, -) -> Buf { - let value = match result { - Ok(v) => json!({ "ok": v, "promiseId": promise_id }), - Err(err) => json!({ - "promiseId": promise_id , - "err": { - "className": (get_error_class_fn)(&err), - "message": err.to_string(), - } - }), - }; - serde_json::to_vec(&value).unwrap().into_boxed_slice() -} - impl Future for CoreIsolate { type Output = Result<(), ErrBox>; @@ -574,12 +496,12 @@ impl Future for CoreIsolate { check_promise_exceptions(scope)?; - let mut overflow_response: Option<(OpId, Buf)> = None; + let mut overflow_response: Option<(OpId, Box<[u8]>)> = None; loop { let mut state = state_rc.borrow_mut(); // Now handle actual ops. - state.have_unpolled_ops = false; + state.have_unpolled_ops.set(false); let pending_r = state.pending_ops.poll_next_unpin(cx); match pending_r { @@ -644,7 +566,7 @@ impl Future for CoreIsolate { if state.pending_ops.is_empty() { Poll::Ready(Ok(())) } else { - if state.have_unpolled_ops { + if state.have_unpolled_ops.get() { state.waker.wake(); } Poll::Pending @@ -653,18 +575,6 @@ impl Future for CoreIsolate { } impl CoreIsolateState { - /// Defines the how Deno.core.dispatch() acts. - /// Called whenever Deno.core.dispatch() is called in JavaScript. zero_copy_buf - /// corresponds to the second argument of Deno.core.dispatch(). - /// - /// 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, &mut [ZeroCopyBuf]) -> Op + 'static, - { - self.op_registry.register(name, op) - } - /// Allows a callback to be set whenever a V8 exception is made. This allows /// the caller to wrap the JSError into an error. By default this callback /// is set to JSError::create. @@ -674,49 +584,6 @@ impl CoreIsolateState { ) { self.js_error_create_fn = Box::new(f); } - - pub fn set_get_error_class_fn(&mut self, f: GetErrorClassFn) { - self.get_error_class_fn = f; - } - - pub fn dispatch_op<'s>( - &mut self, - scope: &mut v8::HandleScope<'s>, - op_id: OpId, - zero_copy_bufs: &mut [ZeroCopyBuf], - ) -> Option<(OpId, Box<[u8]>)> { - let op = if let Some(dispatcher) = self.op_registry.get(op_id) { - dispatcher(self, zero_copy_bufs) - } else { - let message = - v8::String::new(scope, &format!("Unknown op id: {}", op_id)).unwrap(); - let exception = v8::Exception::type_error(scope, message); - scope.throw_exception(exception); - return None; - }; - - debug_assert_eq!(self.shared.size(), 0); - match op { - Op::Sync(buf) => { - // 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; - Some((op_id, buf)) - } - Op::Async(fut) => { - let fut2 = fut.map(move |buf| (op_id, buf)); - self.pending_ops.push(fut2.boxed_local()); - self.have_unpolled_ops = true; - None - } - Op::AsyncUnref(fut) => { - let fut2 = fut.map(move |buf| (op_id, buf)); - self.pending_unref_ops.push(fut2.boxed_local()); - self.have_unpolled_ops = true; - None - } - } - } } fn async_op_response<'s>( @@ -739,7 +606,7 @@ fn async_op_response<'s>( let op_id: v8::Local<v8::Value> = v8::Integer::new(tc_scope, op_id as i32).into(); let ui8: v8::Local<v8::Value> = - bindings::boxed_slice_to_uint8array(tc_scope, buf).into(); + boxed_slice_to_uint8array(tc_scope, buf).into(); js_recv_cb.call(tc_scope, global, &[op_id, ui8]) } None => js_recv_cb.call(tc_scope, global, &[]), @@ -848,11 +715,28 @@ pub fn js_check<T>(r: Result<T, ErrBox>) -> T { r.unwrap() } +fn boxed_slice_to_uint8array<'sc>( + scope: &mut v8::HandleScope<'sc>, + buf: Box<[u8]>, +) -> v8::Local<'sc, v8::Uint8Array> { + assert!(!buf.is_empty()); + let buf_len = buf.len(); + let backing_store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(buf); + let backing_store_shared = backing_store.make_shared(); + let ab = v8::ArrayBuffer::with_backing_store(scope, &backing_store_shared); + v8::Uint8Array::new(scope, ab, 0, buf_len) + .expect("Failed to create UintArray8") +} + #[cfg(test)] pub mod tests { use super::*; + use crate::BasicState; + use crate::BufVec; use futures::future::lazy; + use futures::FutureExt; use std::ops::FnOnce; + use std::rc::Rc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -880,7 +764,7 @@ pub mod tests { ) } - pub enum Mode { + enum Mode { Async, AsyncUnref, AsyncZeroCopy(u8), @@ -890,28 +774,29 @@ pub mod tests { OverflowResAsync, } - pub fn setup(mode: Mode) -> (CoreIsolate, Arc<AtomicUsize>) { - let dispatch_count = Arc::new(AtomicUsize::new(0)); - let dispatch_count_ = dispatch_count.clone(); - - let mut isolate = CoreIsolate::new(StartupData::None, false); + struct TestOpRouter { + mode: Mode, + dispatch_count: Arc<AtomicUsize>, + } - let dispatcher = move |_state: &mut CoreIsolateState, - zero_copy: &mut [ZeroCopyBuf]| - -> Op { - dispatch_count_.fetch_add(1, Ordering::Relaxed); - match mode { + impl OpRouter for TestOpRouter { + fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op { + if op_id != 1 { + return Op::NotFound; + } + self.dispatch_count.fetch_add(1, Ordering::Relaxed); + match self.mode { Mode::Async => { - assert_eq!(zero_copy.len(), 1); - assert_eq!(zero_copy[0].len(), 1); - assert_eq!(zero_copy[0][0], 42); + assert_eq!(bufs.len(), 1); + assert_eq!(bufs[0].len(), 1); + assert_eq!(bufs[0][0], 42); let buf = vec![43u8].into_boxed_slice(); Op::Async(futures::future::ready(buf).boxed()) } Mode::AsyncUnref => { - assert_eq!(zero_copy.len(), 1); - assert_eq!(zero_copy[0].len(), 1); - assert_eq!(zero_copy[0][0], 42); + assert_eq!(bufs.len(), 1); + assert_eq!(bufs[0].len(), 1); + assert_eq!(bufs[0][0], 42); let fut = async { // This future never finish. futures::future::pending::<()>().await; @@ -920,8 +805,8 @@ pub mod tests { Op::AsyncUnref(fut.boxed()) } Mode::AsyncZeroCopy(count) => { - assert_eq!(zero_copy.len(), count as usize); - zero_copy.iter().enumerate().for_each(|(idx, buf)| { + assert_eq!(bufs.len(), count as usize); + bufs.iter().enumerate().for_each(|(idx, buf)| { assert_eq!(buf.len(), 1); assert_eq!(idx, buf[0] as usize); }); @@ -930,15 +815,15 @@ pub mod tests { Op::Async(futures::future::ready(buf).boxed()) } Mode::OverflowReqSync => { - assert_eq!(zero_copy.len(), 1); - assert_eq!(zero_copy[0].len(), 100 * 1024 * 1024); + assert_eq!(bufs.len(), 1); + assert_eq!(bufs[0].len(), 100 * 1024 * 1024); let buf = vec![43u8].into_boxed_slice(); Op::Sync(buf) } Mode::OverflowResSync => { - assert_eq!(zero_copy.len(), 1); - assert_eq!(zero_copy[0].len(), 1); - assert_eq!(zero_copy[0][0], 42); + assert_eq!(bufs.len(), 1); + assert_eq!(bufs[0].len(), 1); + assert_eq!(bufs[0][0], 42); let mut vec = Vec::<u8>::new(); vec.resize(100 * 1024 * 1024, 0); vec[0] = 99; @@ -946,15 +831,15 @@ pub mod tests { Op::Sync(buf) } Mode::OverflowReqAsync => { - assert_eq!(zero_copy.len(), 1); - assert_eq!(zero_copy[0].len(), 100 * 1024 * 1024); + assert_eq!(bufs.len(), 1); + assert_eq!(bufs[0].len(), 100 * 1024 * 1024); let buf = vec![43u8].into_boxed_slice(); Op::Async(futures::future::ready(buf).boxed()) } Mode::OverflowResAsync => { - assert_eq!(zero_copy.len(), 1); - assert_eq!(zero_copy[0].len(), 1); - assert_eq!(zero_copy[0][0], 42); + assert_eq!(bufs.len(), 1); + assert_eq!(bufs[0].len(), 1); + assert_eq!(bufs[0][0], 42); let mut vec = Vec::<u8>::new(); vec.resize(100 * 1024 * 1024, 0); vec[0] = 4; @@ -962,9 +847,16 @@ pub mod tests { Op::Async(futures::future::ready(buf).boxed()) } } - }; + } + } - isolate.register_op("test", dispatcher); + fn setup(mode: Mode) -> (CoreIsolate, Arc<AtomicUsize>) { + let dispatch_count = Arc::new(AtomicUsize::new(0)); + let test_state = Rc::new(TestOpRouter { + mode, + dispatch_count: dispatch_count.clone(), + }); + let mut isolate = CoreIsolate::new(test_state, StartupData::None, false); js_check(isolate.execute( "setup.js", @@ -1328,7 +1220,8 @@ pub mod tests { #[test] fn syntax_error() { - let mut isolate = CoreIsolate::new(StartupData::None, false); + let mut isolate = + CoreIsolate::new(BasicState::new(), StartupData::None, false); let src = "hocuspocus("; let r = isolate.execute("i.js", src); let e = r.unwrap_err(); @@ -1353,27 +1246,29 @@ pub mod tests { #[test] fn will_snapshot() { let snapshot = { - let mut isolate = CoreIsolate::new(StartupData::None, true); + let mut isolate = + CoreIsolate::new(BasicState::new(), StartupData::None, true); js_check(isolate.execute("a.js", "a = 1 + 2")); isolate.snapshot() }; let startup_data = StartupData::Snapshot(Snapshot::JustCreated(snapshot)); - let mut isolate2 = CoreIsolate::new(startup_data, false); + let mut isolate2 = CoreIsolate::new(BasicState::new(), startup_data, false); js_check(isolate2.execute("check.js", "if (a != 3) throw Error('x')")); } #[test] fn test_from_boxed_snapshot() { let snapshot = { - let mut isolate = CoreIsolate::new(StartupData::None, true); + let mut isolate = + CoreIsolate::new(BasicState::new(), StartupData::None, true); js_check(isolate.execute("a.js", "a = 1 + 2")); let snap: &[u8] = &*isolate.snapshot(); Vec::from(snap).into_boxed_slice() }; let startup_data = StartupData::Snapshot(Snapshot::Boxed(snapshot)); - let mut isolate2 = CoreIsolate::new(startup_data, false); + let mut isolate2 = CoreIsolate::new(BasicState::new(), startup_data, false); js_check(isolate2.execute("check.js", "if (a != 3) throw Error('x')")); } @@ -1383,8 +1278,11 @@ pub mod tests { initial: 0, max: 20 * 1024, // 20 kB }; - let mut isolate = - CoreIsolate::with_heap_limits(StartupData::None, heap_limits); + let mut isolate = CoreIsolate::with_heap_limits( + BasicState::new(), + StartupData::None, + heap_limits, + ); let cb_handle = isolate.thread_safe_handle(); let callback_invoke_count = Rc::new(AtomicUsize::default()); @@ -1412,7 +1310,8 @@ pub mod tests { #[test] fn test_heap_limit_cb_remove() { - let mut isolate = CoreIsolate::new(StartupData::None, false); + let mut isolate = + CoreIsolate::new(BasicState::new(), StartupData::None, false); isolate.add_near_heap_limit_callback(|current_limit, _initial_limit| { current_limit * 2 @@ -1427,8 +1326,11 @@ pub mod tests { initial: 0, max: 20 * 1024, // 20 kB }; - let mut isolate = - CoreIsolate::with_heap_limits(StartupData::None, heap_limits); + let mut isolate = CoreIsolate::with_heap_limits( + BasicState::new(), + StartupData::None, + heap_limits, + ); let cb_handle = isolate.thread_safe_handle(); let callback_invoke_count_first = Rc::new(AtomicUsize::default()); diff --git a/core/errors.rs b/core/errors.rs index 8fdcca059..2ce12689a 100644 --- a/core/errors.rs +++ b/core/errors.rs @@ -446,19 +446,21 @@ impl fmt::Debug for ErrWithV8Handle { } } -#[cfg(tests)] +#[cfg(test)] mod tests { + use super::*; + #[test] fn test_bad_resource() { let err = ErrBox::bad_resource("Resource has been closed"); - assert_eq!(err.1, "BadResource"); + assert!(matches!(err, ErrBox::Simple { class: "BadResource", .. })); assert_eq!(err.to_string(), "Resource has been closed"); } #[test] fn test_bad_resource_id() { let err = ErrBox::bad_resource_id(); - assert_eq!(err.1, "BadResource"); + assert!(matches!(err, ErrBox::Simple { class: "BadResource", .. })); assert_eq!(err.to_string(), "Bad resource ID"); } } diff --git a/core/es_isolate.rs b/core/es_isolate.rs index f2e2460ba..194f1adfa 100644 --- a/core/es_isolate.rs +++ b/core/es_isolate.rs @@ -10,6 +10,7 @@ use crate::bindings; use crate::errors::ErrBox; use crate::errors::ErrWithV8Handle; use crate::futures::FutureExt; +use crate::OpRouter; use futures::ready; use futures::stream::FuturesUnordered; use futures::stream::StreamExt; @@ -76,10 +77,12 @@ impl DerefMut for EsIsolate { impl EsIsolate { pub fn new( loader: Rc<dyn ModuleLoader>, + op_router: Rc<dyn OpRouter>, startup_data: StartupData, will_snapshot: bool, ) -> Self { - let mut core_isolate = CoreIsolate::new(startup_data, will_snapshot); + let mut core_isolate = + CoreIsolate::new(op_router, startup_data, will_snapshot); { core_isolate.set_host_initialize_import_meta_object_callback( bindings::host_initialize_import_meta_object_callback, @@ -640,11 +643,11 @@ impl EsIsolateState { pub mod tests { use super::*; use crate::core_isolate::tests::run_in_task; - use crate::core_isolate::CoreIsolateState; use crate::js_check; use crate::modules::ModuleSourceFuture; use crate::ops::*; - use crate::ZeroCopyBuf; + use crate::BasicState; + use crate::BufVec; use std::io; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -681,24 +684,23 @@ pub mod tests { } let loader = Rc::new(ModsLoader::default()); + let state = BasicState::new(); + let resolve_count = loader.count.clone(); let dispatch_count = Arc::new(AtomicUsize::new(0)); let dispatch_count_ = dispatch_count.clone(); - let mut isolate = EsIsolate::new(loader, StartupData::None, false); - - let dispatcher = move |_state: &mut CoreIsolateState, - zero_copy: &mut [ZeroCopyBuf]| - -> Op { + let dispatcher = move |_state: Rc<BasicState>, bufs: BufVec| -> Op { dispatch_count_.fetch_add(1, Ordering::Relaxed); - 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(); + assert_eq!(bufs.len(), 1); + assert_eq!(bufs[0].len(), 1); + assert_eq!(bufs[0][0], 42); + let buf = [43u8, 0, 0, 0][..].into(); Op::Async(futures::future::ready(buf).boxed()) }; + state.register_op("test", dispatcher); - isolate.register_op("test", dispatcher); + let mut isolate = EsIsolate::new(loader, state, StartupData::None, false); js_check(isolate.execute( "setup.js", @@ -792,7 +794,8 @@ pub mod tests { run_in_task(|cx| { let loader = Rc::new(DynImportErrLoader::default()); let count = loader.count.clone(); - let mut isolate = EsIsolate::new(loader, StartupData::None, false); + let mut isolate = + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); js_check(isolate.execute( "file:///dyn_import2.js", @@ -869,7 +872,8 @@ pub mod tests { let prepare_load_count = loader.prepare_load_count.clone(); let resolve_count = loader.resolve_count.clone(); let load_count = loader.load_count.clone(); - let mut isolate = EsIsolate::new(loader, StartupData::None, false); + let mut isolate = + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); // Dynamically import mod_b js_check(isolate.execute( @@ -909,7 +913,8 @@ pub mod tests { run_in_task(|cx| { let loader = Rc::new(DynImportOkLoader::default()); let prepare_load_count = loader.prepare_load_count.clone(); - let mut isolate = EsIsolate::new(loader, StartupData::None, false); + let mut isolate = + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); js_check(isolate.execute( "file:///dyn_import3.js", r#" @@ -960,7 +965,8 @@ pub mod tests { } let loader = std::rc::Rc::new(ModsLoader::default()); - let mut runtime_isolate = EsIsolate::new(loader, StartupData::None, true); + let mut runtime_isolate = + EsIsolate::new(loader, BasicState::new(), StartupData::None, true); let specifier = ModuleSpecifier::resolve_url("file:///main.js").unwrap(); let source_code = "Deno.core.print('hello\\n')".to_string(); diff --git a/core/examples/http_bench_bin_ops.rs b/core/examples/http_bench_bin_ops.rs index 366779e8c..f93b8b079 100644 --- a/core/examples/http_bench_bin_ops.rs +++ b/core/examples/http_bench_bin_ops.rs @@ -1,10 +1,12 @@ #[macro_use] extern crate log; +use deno_core::js_check; +use deno_core::BasicState; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::Op; -use deno_core::ResourceTable; +use deno_core::OpRegistry; use deno_core::Script; use deno_core::StartupData; use deno_core::ZeroCopyBuf; @@ -12,7 +14,6 @@ use futures::future::poll_fn; use futures::future::FutureExt; use futures::future::TryFuture; use futures::future::TryFutureExt; -use std::cell::RefCell; use std::convert::TryInto; use std::env; use std::fmt::Debug; @@ -27,6 +28,7 @@ use tokio::io::AsyncRead; use tokio::io::AsyncWrite; use tokio::net::TcpListener; use tokio::net::TcpStream; +use tokio::runtime; struct Logger; @@ -46,9 +48,9 @@ impl log::Log for Logger { #[derive(Copy, Clone, Debug, PartialEq)] struct Record { - pub promise_id: u32, - pub rid: u32, - pub result: i32, + promise_id: u32, + rid: u32, + result: i32, } type RecordBuf = [u8; size_of::<Record>()]; @@ -75,131 +77,64 @@ impl From<Record> for RecordBuf { } } -pub fn isolate_new() -> CoreIsolate { +fn create_isolate() -> CoreIsolate { + let state = BasicState::new(); + register_op_bin_sync(&state, "listen", op_listen); + register_op_bin_sync(&state, "close", op_close); + register_op_bin_async(&state, "accept", op_accept); + register_op_bin_async(&state, "read", op_read); + register_op_bin_async(&state, "write", op_write); + let startup_data = StartupData::Script(Script { source: include_str!("http_bench_bin_ops.js"), filename: "http_bench_bin_ops.js", }); - let mut isolate = CoreIsolate::new(startup_data, false); - - fn register_sync_op<F>( - isolate: &mut CoreIsolate, - name: &'static str, - handler: F, - ) where - F: 'static - + Fn( - Rc<RefCell<ResourceTable>>, - u32, - &mut [ZeroCopyBuf], - ) -> Result<u32, Error>, - { - let core_handler = move |state: &mut CoreIsolateState, - zero_copy_bufs: &mut [ZeroCopyBuf]| - -> Op { - assert!(!zero_copy_bufs.is_empty()); - let record = Record::from(zero_copy_bufs[0].as_ref()); - let is_sync = record.promise_id == 0; - assert!(is_sync); - - let resource_table = state.resource_table.clone(); - let result: i32 = - match handler(resource_table, 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) - }; - - isolate.register_op(name, core_handler); - } - - fn register_async_op<F>( - isolate: &mut CoreIsolate, - name: &'static str, - handler: impl Fn(Rc<RefCell<ResourceTable>>, u32, &mut [ZeroCopyBuf]) -> F - + Copy - + 'static, - ) where - F: TryFuture, - F::Ok: TryInto<i32>, - <F::Ok as TryInto<i32>>::Error: Debug, - { - let core_handler = move |state: &mut CoreIsolateState, - zero_copy_bufs: &mut [ZeroCopyBuf]| - -> Op { - assert!(!zero_copy_bufs.is_empty()); - 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[1..].to_vec(); - let resource_table = state.resource_table.clone(); - let fut = async move { - let op = handler(resource_table, record.rid, &mut zero_copy); - let result = op - .map_ok(|r| r.try_into().expect("op result does not fit in i32")) - .unwrap_or_else(|_| -1) - .await; - RecordBuf::from(Record { result, ..record })[..].into() - }; - - Op::Async(fut.boxed_local()) - }; - - isolate.register_op(name, core_handler); - } - - register_sync_op(&mut isolate, "listen", op_listen); - register_async_op(&mut isolate, "accept", op_accept); - register_async_op(&mut isolate, "read", op_read); - register_async_op(&mut isolate, "write", op_write); - register_sync_op(&mut isolate, "close", op_close); - - isolate -} - -fn op_close( - resource_table: Rc<RefCell<ResourceTable>>, - rid: u32, - _buf: &mut [ZeroCopyBuf], -) -> Result<u32, Error> { - debug!("close rid={}", rid); - let resource_table = &mut resource_table.borrow_mut(); - resource_table - .close(rid) - .map(|_| 0) - .ok_or_else(bad_resource) + CoreIsolate::new(state, startup_data, false) } fn op_listen( - resource_table: Rc<RefCell<ResourceTable>>, + state: &BasicState, _rid: u32, - _buf: &mut [ZeroCopyBuf], + _bufs: &mut [ZeroCopyBuf], ) -> Result<u32, Error> { debug!("listen"); let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap(); let std_listener = std::net::TcpListener::bind(&addr)?; let listener = TcpListener::from_std(std_listener)?; - let resource_table = &mut resource_table.borrow_mut(); - let rid = resource_table.add("tcpListener", Box::new(listener)); + let rid = state + .resource_table + .borrow_mut() + .add("tcpListener", Box::new(listener)); Ok(rid) } +fn op_close( + state: &BasicState, + rid: u32, + _bufs: &mut [ZeroCopyBuf], +) -> Result<u32, Error> { + debug!("close rid={}", rid); + state + .resource_table + .borrow_mut() + .close(rid) + .map(|_| 0) + .ok_or_else(bad_resource_id) +} + fn op_accept( - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<BasicState>, rid: u32, - _buf: &mut [ZeroCopyBuf], + _bufs: BufVec, ) -> impl TryFuture<Ok = u32, Error = Error> { debug!("accept rid={}", rid); poll_fn(move |cx| { - let resource_table = &mut resource_table.borrow_mut(); + let resource_table = &mut state.resource_table.borrow_mut(); let listener = resource_table .get_mut::<TcpListener>(rid) - .ok_or_else(bad_resource)?; + .ok_or_else(bad_resource_id)?; listener.poll_accept(cx).map_ok(|(stream, _addr)| { resource_table.add("tcpStream", Box::new(stream)) }) @@ -207,9 +142,9 @@ fn op_accept( } fn op_read( - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<BasicState>, rid: u32, - bufs: &mut [ZeroCopyBuf], + bufs: BufVec, ) -> impl TryFuture<Ok = usize, Error = Error> { assert_eq!(bufs.len(), 1, "Invalid number of arguments"); let mut buf = bufs[0].clone(); @@ -217,33 +152,85 @@ fn op_read( debug!("read rid={}", rid); poll_fn(move |cx| { - let resource_table = &mut resource_table.borrow_mut(); + let resource_table = &mut state.resource_table.borrow_mut(); let stream = resource_table .get_mut::<TcpStream>(rid) - .ok_or_else(bad_resource)?; + .ok_or_else(bad_resource_id)?; Pin::new(stream).poll_read(cx, &mut buf) }) } fn op_write( - resource_table: Rc<RefCell<ResourceTable>>, + state: Rc<BasicState>, rid: u32, - bufs: &mut [ZeroCopyBuf], + bufs: BufVec, ) -> impl TryFuture<Ok = usize, Error = Error> { assert_eq!(bufs.len(), 1, "Invalid number of arguments"); let buf = bufs[0].clone(); debug!("write rid={}", rid); poll_fn(move |cx| { - let resource_table = &mut resource_table.borrow_mut(); + let resource_table = &mut state.resource_table.borrow_mut(); let stream = resource_table .get_mut::<TcpStream>(rid) - .ok_or_else(bad_resource)?; + .ok_or_else(bad_resource_id)?; Pin::new(stream).poll_write(cx, &buf) }) } -fn bad_resource() -> Error { +fn register_op_bin_sync<F>(state: &BasicState, name: &'static str, op_fn: F) +where + F: Fn(&BasicState, u32, &mut [ZeroCopyBuf]) -> Result<u32, Error> + 'static, +{ + let base_op_fn = move |state: Rc<BasicState>, mut bufs: BufVec| -> Op { + let record = Record::from(bufs[0].as_ref()); + let is_sync = record.promise_id == 0; + assert!(is_sync); + + let zero_copy_bufs = &mut bufs[1..]; + let result: i32 = match op_fn(&state, record.rid, zero_copy_bufs) { + Ok(r) => r as i32, + Err(_) => -1, + }; + let buf = RecordBuf::from(Record { result, ..record })[..].into(); + Op::Sync(buf) + }; + + state.register_op(name, base_op_fn); +} + +fn register_op_bin_async<F, R>(state: &BasicState, name: &'static str, op_fn: F) +where + F: Fn(Rc<BasicState>, u32, BufVec) -> R + Copy + 'static, + R: TryFuture, + R::Ok: TryInto<i32>, + <R::Ok as TryInto<i32>>::Error: Debug, +{ + let base_op_fn = move |state: Rc<BasicState>, bufs: BufVec| -> Op { + let mut bufs_iter = bufs.into_iter(); + let record_buf = bufs_iter.next().unwrap(); + let zero_copy_bufs = bufs_iter.collect::<BufVec>(); + + let record = Record::from(record_buf.as_ref()); + let is_sync = record.promise_id == 0; + assert!(!is_sync); + + let fut = async move { + let op = op_fn(state, record.rid, zero_copy_bufs); + let result = op + .map_ok(|r| r.try_into().expect("op result does not fit in i32")) + .unwrap_or_else(|_| -1) + .await; + RecordBuf::from(Record { result, ..record })[..].into() + }; + + Op::Async(fut.boxed_local()) + }; + + state.register_op(name, base_op_fn); +} + +fn bad_resource_id() -> Error { Error::new(ErrorKind::NotFound, "bad resource id") } @@ -259,13 +246,13 @@ fn main() { // NOTE: `--help` arg will display V8 help and exit deno_core::v8_set_flags(env::args().collect()); - let isolate = isolate_new(); - let mut runtime = tokio::runtime::Builder::new() + let isolate = create_isolate(); + let mut runtime = runtime::Builder::new() .basic_scheduler() .enable_all() .build() .unwrap(); - runtime.block_on(isolate).expect("unexpected isolate error"); + js_check(runtime.block_on(isolate)); } #[test] diff --git a/core/examples/http_bench_json_ops.rs b/core/examples/http_bench_json_ops.rs index f0fc5f94c..6e3063a0f 100644 --- a/core/examples/http_bench_json_ops.rs +++ b/core/examples/http_bench_json_ops.rs @@ -1,25 +1,29 @@ #[macro_use] extern crate log; -use deno_core::serde_json; +use deno_core::js_check; +use deno_core::BasicState; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; +use deno_core::OpRegistry; use deno_core::Script; use deno_core::StartupData; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; use futures::future::Future; +use serde_json::Value; +use std::convert::TryInto; use std::env; -use std::io::Error; -use std::io::ErrorKind; use std::net::SocketAddr; use std::pin::Pin; +use std::rc::Rc; use std::task::Poll; use tokio::io::AsyncRead; use tokio::io::AsyncWrite; use tokio::net::TcpListener; use tokio::net::TcpStream; +use tokio::runtime; struct Logger; @@ -37,66 +41,79 @@ impl log::Log for Logger { fn flush(&self) {} } -pub fn isolate_new() -> CoreIsolate { +fn create_isolate() -> CoreIsolate { + let state = BasicState::new(); + state.register_op_json_sync("listen", op_listen); + state.register_op_json_sync("close", op_close); + state.register_op_json_async("accept", op_accept); + state.register_op_json_async("read", op_read); + state.register_op_json_async("write", op_write); + let startup_data = StartupData::Script(Script { source: include_str!("http_bench_json_ops.js"), filename: "http_bench_json_ops.js", }); - let mut isolate = CoreIsolate::new(startup_data, false); - - isolate.register_op_json_sync("listen", op_listen); - isolate.register_op_json_async("accept", op_accept); - isolate.register_op_json_async("read", op_read); - isolate.register_op_json_async("write", op_write); - isolate.register_op_json_sync("close", op_close); + CoreIsolate::new(state, startup_data, false) +} - isolate +fn op_listen( + state: &BasicState, + _args: Value, + _bufs: &mut [ZeroCopyBuf], +) -> Result<Value, ErrBox> { + debug!("listen"); + let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap(); + let std_listener = std::net::TcpListener::bind(&addr)?; + let listener = TcpListener::from_std(std_listener)?; + let rid = state + .resource_table + .borrow_mut() + .add("tcpListener", Box::new(listener)); + Ok(serde_json::json!({ "rid": rid })) } fn op_close( - state: &mut CoreIsolateState, - args: serde_json::Value, + state: &BasicState, + args: Value, _buf: &mut [ZeroCopyBuf], -) -> Result<serde_json::Value, ErrBox> { - let rid = args.get("rid").unwrap().as_u64().unwrap() as u32; +) -> Result<Value, ErrBox> { + let rid: u32 = args + .get("rid") + .unwrap() + .as_u64() + .unwrap() + .try_into() + .unwrap(); debug!("close rid={}", rid); - let resource_table = &mut state.resource_table.borrow_mut(); - resource_table + state + .resource_table + .borrow_mut() .close(rid) .map(|_| serde_json::json!(())) - .ok_or_else(bad_resource) -} - -fn op_listen( - state: &mut CoreIsolateState, - _args: serde_json::Value, - _buf: &mut [ZeroCopyBuf], -) -> Result<serde_json::Value, ErrBox> { - debug!("listen"); - let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap(); - let std_listener = std::net::TcpListener::bind(&addr)?; - let listener = TcpListener::from_std(std_listener)?; - let resource_table = &mut state.resource_table.borrow_mut(); - let rid = resource_table.add("tcpListener", Box::new(listener)); - Ok(serde_json::json!({ "rid": rid })) + .ok_or_else(ErrBox::bad_resource_id) } fn op_accept( - state: &mut CoreIsolateState, - args: serde_json::Value, - _buf: &mut [ZeroCopyBuf], -) -> impl Future<Output = Result<serde_json::Value, ErrBox>> { - let rid = args.get("rid").unwrap().as_u64().unwrap() as u32; + state: Rc<BasicState>, + args: Value, + _bufs: BufVec, +) -> impl Future<Output = Result<Value, ErrBox>> { + let rid: u32 = args + .get("rid") + .unwrap() + .as_u64() + .unwrap() + .try_into() + .unwrap(); debug!("accept rid={}", rid); - let resource_table = state.resource_table.clone(); poll_fn(move |cx| { - let resource_table = &mut resource_table.borrow_mut(); + let resource_table = &mut state.resource_table.borrow_mut(); let listener = resource_table .get_mut::<TcpListener>(rid) - .ok_or_else(bad_resource)?; + .ok_or_else(ErrBox::bad_resource_id)?; listener.poll_accept(cx)?.map(|(stream, _addr)| { let rid = resource_table.add("tcpStream", Box::new(stream)); Ok(serde_json::json!({ "rid": rid })) @@ -105,57 +122,59 @@ fn op_accept( } fn op_read( - state: &mut CoreIsolateState, - args: serde_json::Value, - bufs: &mut [ZeroCopyBuf], -) -> impl Future<Output = Result<serde_json::Value, ErrBox>> { + state: Rc<BasicState>, + args: Value, + mut bufs: BufVec, +) -> impl Future<Output = Result<Value, ErrBox>> { assert_eq!(bufs.len(), 1, "Invalid number of arguments"); - let rid = args.get("rid").unwrap().as_u64().unwrap() as u32; + let rid: u32 = args + .get("rid") + .unwrap() + .as_u64() + .unwrap() + .try_into() + .unwrap(); debug!("read rid={}", rid); - let mut buf = bufs[0].clone(); - let resource_table = state.resource_table.clone(); - - poll_fn(move |cx| -> Poll<Result<serde_json::Value, ErrBox>> { - let resource_table = &mut resource_table.borrow_mut(); + poll_fn(move |cx| -> Poll<Result<Value, ErrBox>> { + let resource_table = &mut state.resource_table.borrow_mut(); let stream = resource_table .get_mut::<TcpStream>(rid) - .ok_or_else(bad_resource)?; + .ok_or_else(ErrBox::bad_resource_id)?; Pin::new(stream) - .poll_read(cx, &mut buf)? + .poll_read(cx, &mut bufs[0])? .map(|nread| Ok(serde_json::json!({ "nread": nread }))) }) } fn op_write( - state: &mut CoreIsolateState, - args: serde_json::Value, - bufs: &mut [ZeroCopyBuf], -) -> impl Future<Output = Result<serde_json::Value, ErrBox>> { + state: Rc<BasicState>, + args: Value, + bufs: BufVec, +) -> impl Future<Output = Result<Value, ErrBox>> { assert_eq!(bufs.len(), 1, "Invalid number of arguments"); - let rid = args.get("rid").unwrap().as_u64().unwrap() as u32; + let rid: u32 = args + .get("rid") + .unwrap() + .as_u64() + .unwrap() + .try_into() + .unwrap(); debug!("write rid={}", rid); - let buf = bufs[0].clone(); - let resource_table = state.resource_table.clone(); - poll_fn(move |cx| { - let resource_table = &mut resource_table.borrow_mut(); + let resource_table = &mut state.resource_table.borrow_mut(); let stream = resource_table .get_mut::<TcpStream>(rid) - .ok_or_else(bad_resource)?; + .ok_or_else(ErrBox::bad_resource_id)?; Pin::new(stream) - .poll_write(cx, &buf)? + .poll_write(cx, &bufs[0])? .map(|nwritten| Ok(serde_json::json!({ "nwritten": nwritten }))) }) } -fn bad_resource() -> ErrBox { - Error::new(ErrorKind::NotFound, "bad resource id").into() -} - fn main() { log::set_logger(&Logger).unwrap(); log::set_max_level( @@ -168,11 +187,11 @@ fn main() { // NOTE: `--help` arg will display V8 help and exit deno_core::v8_set_flags(env::args().collect()); - let isolate = isolate_new(); - let mut runtime = tokio::runtime::Builder::new() + let isolate = create_isolate(); + let mut runtime = runtime::Builder::new() .basic_scheduler() .enable_all() .build() .unwrap(); - deno_core::js_check(runtime.block_on(isolate)); + js_check(runtime.block_on(isolate)); } diff --git a/core/flags.rs b/core/flags.rs index 7c1f5c449..b69abab6f 100644 --- a/core/flags.rs +++ b/core/flags.rs @@ -1,4 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + use rusty_v8 as v8; /// Pass the command line arguments to v8. /// Returns a vector of command line arguments that V8 did not understand. diff --git a/core/lib.rs b/core/lib.rs index d4a348f63..647c91aa4 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -8,6 +8,7 @@ extern crate lazy_static; #[macro_use] extern crate log; +mod basic_state; mod bindings; mod core_isolate; mod errors; @@ -24,6 +25,7 @@ mod zero_copy_buf; pub use rusty_v8 as v8; +pub use crate::basic_state::BasicState; pub use crate::core_isolate::js_check; pub use crate::core_isolate::CoreIsolate; pub use crate::core_isolate::CoreIsolateState; @@ -32,6 +34,7 @@ pub use crate::core_isolate::HeapLimits; pub use crate::core_isolate::Script; pub use crate::core_isolate::Snapshot; pub use crate::core_isolate::StartupData; +pub use crate::errors::AnyError; pub use crate::errors::ErrBox; pub use crate::errors::JSError; pub use crate::es_isolate::EsIsolate; @@ -47,10 +50,13 @@ pub use crate::modules::ModuleSource; pub use crate::modules::ModuleSourceFuture; pub use crate::modules::RecursiveModuleLoad; pub use crate::normalize_path::normalize_path; -pub use crate::ops::Buf; pub use crate::ops::Op; pub use crate::ops::OpAsyncFuture; +pub use crate::ops::OpFn; pub use crate::ops::OpId; +pub use crate::ops::OpRegistry; +pub use crate::ops::OpRouter; +pub use crate::ops::OpTable; pub use crate::resources::ResourceTable; pub use crate::zero_copy_buf::BufVec; pub use crate::zero_copy_buf::ZeroCopyBuf; diff --git a/core/modules.rs b/core/modules.rs index 516440bc0..817e1f25e 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -8,6 +8,7 @@ use futures::future::FutureExt; use futures::stream::FuturesUnordered; use futures::stream::Stream; use futures::stream::TryStreamExt; +use serde_json::Value; use std::collections::HashMap; use std::collections::HashSet; use std::fmt; @@ -481,7 +482,7 @@ impl Deps { } } - pub fn to_json(&self) -> serde_json::Value { + pub fn to_json(&self) -> Value { let children; if let Some(deps) = &self.deps { children = deps.iter().map(|c| c.to_json()).collect(); @@ -521,6 +522,7 @@ mod tests { use super::*; use crate::es_isolate::EsIsolate; use crate::js_check; + use crate::BasicState; use crate::StartupData; use futures::future::FutureExt; use std::error::Error; @@ -535,15 +537,14 @@ mod tests { // removed in the future. use crate::core_isolate::tests::run_in_task; + #[derive(Default)] struct MockLoader { pub loads: Arc<Mutex<Vec<String>>>, } impl MockLoader { - fn new() -> Self { - Self { - loads: Arc::new(Mutex::new(Vec::new())), - } + fn new() -> Rc<Self> { + Default::default() } } @@ -699,7 +700,8 @@ mod tests { fn test_recursive_load() { let loader = MockLoader::new(); let loads = loader.loads.clone(); - let mut isolate = EsIsolate::new(Rc::new(loader), StartupData::None, false); + let mut isolate = + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); let spec = ModuleSpecifier::resolve_url("file:///a.js").unwrap(); let a_id_fut = isolate.load_module(&spec, None); let a_id = futures::executor::block_on(a_id_fut).expect("Failed to load"); @@ -761,7 +763,8 @@ mod tests { fn test_circular_load() { let loader = MockLoader::new(); let loads = loader.loads.clone(); - let mut isolate = EsIsolate::new(Rc::new(loader), StartupData::None, false); + let mut isolate = + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); let fut = async move { let spec = ModuleSpecifier::resolve_url("file:///circular1.js").unwrap(); @@ -834,7 +837,8 @@ mod tests { fn test_redirect_load() { let loader = MockLoader::new(); let loads = loader.loads.clone(); - let mut isolate = EsIsolate::new(Rc::new(loader), StartupData::None, false); + let mut isolate = + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); let fut = async move { let spec = ModuleSpecifier::resolve_url("file:///redirect1.js").unwrap(); @@ -899,7 +903,7 @@ mod tests { let loader = MockLoader::new(); let loads = loader.loads.clone(); let mut isolate = - EsIsolate::new(Rc::new(loader), StartupData::None, false); + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); let spec = ModuleSpecifier::resolve_url("file:///main.js").unwrap(); let mut recursive_load = isolate.load_module(&spec, None).boxed_local(); @@ -945,7 +949,7 @@ mod tests { run_in_task(|mut cx| { let loader = MockLoader::new(); let mut isolate = - EsIsolate::new(Rc::new(loader), StartupData::None, false); + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); let spec = ModuleSpecifier::resolve_url("file:///bad_import.js").unwrap(); let mut load_fut = isolate.load_module(&spec, None).boxed_local(); let result = load_fut.poll_unpin(&mut cx); @@ -973,7 +977,8 @@ mod tests { fn recursive_load_main_with_code() { let loader = MockLoader::new(); let loads = loader.loads.clone(); - let mut isolate = EsIsolate::new(Rc::new(loader), StartupData::None, false); + let mut isolate = + EsIsolate::new(loader, BasicState::new(), StartupData::None, false); // In default resolution code should be empty. // Instead we explicitly pass in our own code. // The behavior should be very similar to /a.js. diff --git a/core/ops.rs b/core/ops.rs index 65a0f325b..838596dc0 100644 --- a/core/ops.rs +++ b/core/ops.rs @@ -1,179 +1,146 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::core_isolate::CoreIsolateState; + +use crate::BufVec; +use crate::ErrBox; use crate::ZeroCopyBuf; use futures::Future; +use futures::FutureExt; +use indexmap::IndexMap; +use serde_json::json; +use serde_json::Value; use std::collections::HashMap; +use std::iter::once; +use std::ops::Deref; +use std::ops::DerefMut; use std::pin::Pin; use std::rc::Rc; -pub type OpId = u32; - -pub type Buf = Box<[u8]>; - -pub type OpAsyncFuture = Pin<Box<dyn Future<Output = Buf>>>; +pub type OpAsyncFuture = Pin<Box<dyn Future<Output = Box<[u8]>>>>; +pub type OpFn<S> = dyn Fn(Rc<S>, BufVec) -> Op + 'static; +pub type OpId = usize; pub enum Op { - Sync(Buf), + Sync(Box<[u8]>), Async(OpAsyncFuture), /// AsyncUnref is the variation of Async, which doesn't block the program /// exiting. AsyncUnref(OpAsyncFuture), + NotFound, } -/// Main type describing op -pub type OpDispatcher = - dyn Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op + 'static; - -#[derive(Default)] -pub struct OpRegistry { - dispatchers: Vec<Rc<OpDispatcher>>, - name_to_id: HashMap<String, OpId>, +pub trait OpRouter { + fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op; } -impl OpRegistry { - pub fn new() -> Self { - let mut registry = Self::default(); - let op_id = registry.register("ops", |state, _| { - let buf = state.op_registry.json_map(); +pub trait OpRegistry: OpRouter + 'static { + fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId>; + + fn register_op<F>(&self, name: &str, op_fn: F) -> OpId + where + F: Fn(Rc<Self>, BufVec) -> Op + 'static; + + fn register_op_json_sync<F>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId + where + F: Fn(&Self, Value, &mut [ZeroCopyBuf]) -> Result<Value, ErrBox> + 'static, + { + let base_op_fn = move |state: Rc<Self>, mut bufs: BufVec| -> Op { + let result = serde_json::from_slice(&bufs[0]) + .map_err(ErrBox::from) + .and_then(|args| op_fn(&state, args, &mut bufs[1..])); + let buf = state.json_serialize_op_result(None, result); Op::Sync(buf) - }); - assert_eq!(op_id, 0); - registry + }; + + self.register_op(name, base_op_fn) } - pub fn register<F>(&mut self, name: &str, op: F) -> OpId + fn register_op_json_async<F, R>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId where - F: Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op + 'static, + F: Fn(Rc<Self>, Value, BufVec) -> R + 'static, + R: Future<Output = Result<Value, ErrBox>> + 'static, { - let op_id = self.dispatchers.len() as u32; - - let existing = self.name_to_id.insert(name.to_string(), op_id); - assert!( - existing.is_none(), - format!("Op already registered: {}", name) - ); - self.dispatchers.push(Rc::new(op)); - op_id - } + let try_dispatch_op = move |state: Rc<Self>, + bufs: BufVec| + -> Result<Op, ErrBox> { + let args: Value = serde_json::from_slice(&bufs[0])?; + let promise_id = args + .get("promiseId") + .and_then(Value::as_u64) + .ok_or_else(|| ErrBox::type_error("missing or invalid `promiseId`"))?; + let bufs = bufs[1..].into(); + let fut = op_fn(state.clone(), args, bufs).map(move |result| { + state.json_serialize_op_result(Some(promise_id), result) + }); + Ok(Op::Async(Box::pin(fut))) + }; - fn json_map(&self) -> Buf { - let op_map_json = serde_json::to_string(&self.name_to_id).unwrap(); - op_map_json.as_bytes().to_owned().into_boxed_slice() - } + let base_op_fn = move |state: Rc<Self>, bufs: BufVec| -> Op { + match try_dispatch_op(state.clone(), bufs) { + Ok(op) => op, + Err(err) => Op::Sync(state.json_serialize_op_result(None, Err(err))), + } + }; - pub fn get(&self, op_id: OpId) -> Option<Rc<OpDispatcher>> { - self.dispatchers.get(op_id as usize).map(Rc::clone) + self.register_op(name, base_op_fn) } - pub fn unregister_op(&mut self, name: &str) { - let id = self.name_to_id.remove(name).unwrap(); - drop(self.dispatchers.remove(id as usize)); + fn json_serialize_op_result( + &self, + promise_id: Option<u64>, + result: Result<Value, ErrBox>, + ) -> Box<[u8]> { + let value = match result { + Ok(v) => json!({ "ok": v, "promiseId": promise_id }), + Err(err) => json!({ + "promiseId": promise_id , + "err": { + "className": self.get_error_class_name(&err), + "message": err.to_string(), + } + }), + }; + serde_json::to_vec(&value).unwrap().into_boxed_slice() } -} -#[test] -fn test_op_registry() { - use crate::CoreIsolate; - use std::sync::atomic; - use std::sync::Arc; - let mut op_registry = OpRegistry::new(); - - let c = Arc::new(atomic::AtomicUsize::new(0)); - let c_ = c.clone(); - - let test_id = op_registry.register("test", move |_, _| { - c_.fetch_add(1, atomic::Ordering::SeqCst); - Op::Sync(Box::new([])) - }); - assert!(test_id != 0); - - let mut expected = HashMap::new(); - expected.insert("ops".to_string(), 0); - expected.insert("test".to_string(), 1); - assert_eq!(op_registry.name_to_id, expected); - - let isolate = CoreIsolate::new(crate::StartupData::None, false); - - 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 []); - if let Op::Sync(buf) = res { - assert_eq!(buf.len(), 0); - } else { - unreachable!(); + fn get_error_class_name(&self, _err: &ErrBox) -> &'static str { + "Error" } - assert_eq!(c.load(atomic::Ordering::SeqCst), 1); - - assert!(op_registry.get(100).is_none()); - op_registry.unregister_op("test"); - expected.remove("test"); - assert_eq!(op_registry.name_to_id, expected); - assert!(op_registry.get(1).is_none()); } -#[test] -fn register_op_during_call() { - use crate::CoreIsolate; - use std::sync::atomic; - use std::sync::Arc; - use std::sync::Mutex; - let op_registry = Arc::new(Mutex::new(OpRegistry::new())); - - let c = Arc::new(atomic::AtomicUsize::new(0)); - let c_ = c.clone(); - - let op_registry_ = op_registry.clone(); - - let test_id = { - let mut g = op_registry.lock().unwrap(); - g.register("dynamic_register_op", move |_, _| { - let c__ = c_.clone(); - let mut g = op_registry_.lock().unwrap(); - g.register("test", move |_, _| { - c__.fetch_add(1, atomic::Ordering::SeqCst); - Op::Sync(Box::new([])) - }); - Op::Sync(Box::new([])) - }) - }; - assert!(test_id != 0); +/// Collection for storing registered ops. The special 'get_op_catalog' +/// op with OpId `0` is automatically added when the OpTable is created. +pub struct OpTable<S>(IndexMap<String, Rc<OpFn<S>>>); - let isolate = CoreIsolate::new(crate::StartupData::None, false); +impl<S: OpRegistry> OpTable<S> { + pub fn get_op_catalog(&self) -> HashMap<String, OpId> { + self.keys().cloned().zip(0..).collect() + } - let dispatcher1 = { - let g = op_registry.lock().unwrap(); - g.get(test_id).unwrap() - }; - { - let state_rc = CoreIsolate::state(&isolate); - let mut state = state_rc.borrow_mut(); - dispatcher1(&mut state, &mut []); + fn op_get_op_catalog(state: Rc<S>, _bufs: BufVec) -> Op { + let ops = state.get_op_catalog(); + let buf = serde_json::to_vec(&ops).map(Into::into).unwrap(); + Op::Sync(buf) } +} - let mut expected = HashMap::new(); - expected.insert("ops".to_string(), 0); - expected.insert("dynamic_register_op".to_string(), 1); - expected.insert("test".to_string(), 2); - { - let g = op_registry.lock().unwrap(); - assert_eq!(g.name_to_id, expected); +impl<S: OpRegistry> Default for OpTable<S> { + fn default() -> Self { + Self( + once(("ops".to_owned(), Rc::new(Self::op_get_op_catalog) as _)).collect(), + ) } +} - let dispatcher2 = { - let g = op_registry.lock().unwrap(); - g.get(2).unwrap() - }; - let state_rc = CoreIsolate::state(&isolate); - let mut state = state_rc.borrow_mut(); - let res = dispatcher2(&mut state, &mut []); - if let Op::Sync(buf) = res { - assert_eq!(buf.len(), 0); - } else { - unreachable!(); +impl<S> Deref for OpTable<S> { + type Target = IndexMap<String, Rc<OpFn<S>>>; + + fn deref(&self) -> &Self::Target { + &self.0 } - assert_eq!(c.load(atomic::Ordering::SeqCst), 1); +} - let g = op_registry.lock().unwrap(); - assert!(g.get(100).is_none()); +impl<S> DerefMut for OpTable<S> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } diff --git a/core/plugin_api.rs b/core/plugin_api.rs index 0cb9acaeb..d57a5b3b5 100644 --- a/core/plugin_api.rs +++ b/core/plugin_api.rs @@ -8,7 +8,6 @@ // shared library itself, which would cause segfaults when the plugin is // unloaded and all functions in the plugin library are unmapped from memory. -pub use crate::Buf; pub use crate::Op; pub use crate::OpId; pub use crate::ZeroCopyBuf; diff --git a/core/shared_queue.rs b/core/shared_queue.rs index f35fff012..e8ac30ebc 100644 --- a/core/shared_queue.rs +++ b/core/shared_queue.rs @@ -19,6 +19,7 @@ SharedQueue Binary Layout use crate::bindings; use crate::ops::OpId; use rusty_v8 as v8; +use std::convert::TryInto; const MAX_RECORDS: usize = 100; /// Total number of records added. @@ -121,7 +122,7 @@ impl SharedQueue { fn set_meta(&mut self, index: usize, end: usize, op_id: OpId) { let s = self.as_u32_slice_mut(); s[INDEX_OFFSETS + 2 * index] = end as u32; - s[INDEX_OFFSETS + 2 * index + 1] = op_id; + s[INDEX_OFFSETS + 2 * index + 1] = op_id.try_into().unwrap(); } #[cfg(test)] @@ -129,7 +130,7 @@ impl SharedQueue { if index < self.num_records() { let s = self.as_u32_slice(); let end = s[INDEX_OFFSETS + 2 * index] as usize; - let op_id = s[INDEX_OFFSETS + 2 * index + 1]; + let op_id = s[INDEX_OFFSETS + 2 * index + 1] as OpId; Some((op_id, end)) } else { None @@ -218,7 +219,6 @@ impl SharedQueue { #[cfg(test)] mod tests { use super::*; - use crate::ops::Buf; #[test] fn basic() { @@ -262,7 +262,7 @@ mod tests { assert_eq!(q.size(), 0); } - fn alloc_buf(byte_length: usize) -> Buf { + fn alloc_buf(byte_length: usize) -> Box<[u8]> { let mut v = Vec::new(); v.resize(byte_length, 0); v.into_boxed_slice() diff --git a/op_crates/web/lib.rs b/op_crates/web/lib.rs index 278748166..674eddbb2 100644 --- a/op_crates/web/lib.rs +++ b/op_crates/web/lib.rs @@ -31,6 +31,7 @@ fn get_path(file_name: &str) -> PathBuf { #[cfg(test)] mod tests { use deno_core::js_check; + use deno_core::BasicState; use deno_core::CoreIsolate; use deno_core::StartupData; use futures::future::lazy; @@ -46,7 +47,8 @@ mod tests { } fn setup() -> CoreIsolate { - let mut isolate = CoreIsolate::new(StartupData::None, false); + let mut isolate = + CoreIsolate::new(BasicState::new(), StartupData::None, false); crate::init(&mut isolate); isolate } diff --git a/test_plugin/src/lib.rs b/test_plugin/src/lib.rs index bb4c4d8ff..468fae491 100644 --- a/test_plugin/src/lib.rs +++ b/test_plugin/src/lib.rs @@ -1,4 +1,3 @@ -use deno_core::plugin_api::Buf; use deno_core::plugin_api::Interface; use deno_core::plugin_api::Op; use deno_core::plugin_api::ZeroCopyBuf; @@ -23,7 +22,7 @@ fn op_test_sync( println!("zero_copy[{}]: {}", idx, buf_str); } let result = b"test"; - let result_box: Buf = Box::new(*result); + let result_box: Box<[u8]> = Box::new(*result); Op::Sync(result_box) } @@ -47,7 +46,7 @@ fn op_test_async( }); assert!(rx.await.is_ok()); let result = b"test"; - let result_box: Buf = Box::new(*result); + let result_box: Box<[u8]> = Box::new(*result); result_box }; diff --git a/test_plugin/tests/test.js b/test_plugin/tests/test.js index 2c1913f92..c9d3c5f01 100644 --- a/test_plugin/tests/test.js +++ b/test_plugin/tests/test.js @@ -65,11 +65,11 @@ function runTestOpCount() { const end = Deno.metrics(); - if (end.opsCompleted - start.opsCompleted !== 1) { + if (end.opsCompleted - start.opsCompleted !== 2) { // one op for the plugin and one for Deno.metrics throw new Error("The opsCompleted metric is not correct!"); } - if (end.opsDispatched - start.opsDispatched !== 1) { + if (end.opsDispatched - start.opsDispatched !== 2) { // one op for the plugin and one for Deno.metrics throw new Error("The opsDispatched metric is not correct!"); } |