diff options
Diffstat (limited to 'cli/state.rs')
-rw-r--r-- | cli/state.rs | 214 |
1 files changed, 91 insertions, 123 deletions
diff --git a/cli/state.rs b/cli/state.rs index 5754e8c9d..055c09916 100644 --- a/cli/state.rs +++ b/cli/state.rs @@ -27,60 +27,51 @@ 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; -use std::ops::Deref; use std::path::Path; use std::pin::Pin; use std::rc::Rc; use std::str; +use std::sync::Arc; use std::thread::JoinHandle; use std::time::Instant; -#[derive(Clone)] -pub struct State(Rc<RefCell<StateInner>>); - -impl Deref for State { - type Target = Rc<RefCell<StateInner>>; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - #[cfg_attr(feature = "cargo-clippy", allow(stutter))] -pub struct StateInner { - pub global_state: GlobalState, - pub permissions: Permissions, +pub struct State { + pub global_state: Arc<GlobalState>, + pub permissions: RefCell<Permissions>, pub main_module: ModuleSpecifier, /// When flags contains a `.import_map_path` option, the content of the /// import map file will be resolved and set. pub import_map: Option<ImportMap>, - pub metrics: Metrics, - pub global_timer: GlobalTimer, - pub workers: HashMap<u32, (JoinHandle<()>, WebWorkerHandle)>, - pub next_worker_id: u32, + pub metrics: RefCell<Metrics>, + pub global_timer: RefCell<GlobalTimer>, + pub workers: RefCell<HashMap<u32, (JoinHandle<()>, WebWorkerHandle)>>, + pub next_worker_id: Cell<u32>, pub start_time: Instant, - pub seeded_rng: Option<StdRng>, + pub seeded_rng: Option<RefCell<StdRng>>, pub target_lib: TargetLib, pub is_main: bool, pub is_internal: bool, - pub http_client: reqwest::Client, + pub http_client: RefCell<reqwest::Client>, } impl State { pub fn stateful_json_op<D>( - &self, + self: &Rc<Self>, dispatcher: D, ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op where - D: Fn(&State, Value, &mut [ZeroCopyBuf]) -> Result<JsonOp, OpError>, + D: Fn(&Rc<State>, Value, &mut [ZeroCopyBuf]) -> Result<JsonOp, OpError>, { use crate::ops::json_op; self.core_op(json_op(self.stateful_op(dispatcher))) } pub fn stateful_json_op_sync<D>( - &self, + self: &Rc<Self>, resource_table: &Rc<RefCell<ResourceTable>>, dispatcher: D, ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op @@ -117,12 +108,13 @@ impl State { } pub fn stateful_json_op_async<D, F>( - &self, + self: &Rc<Self>, resource_table: &Rc<RefCell<ResourceTable>>, dispatcher: D, ) -> impl Fn(&mut CoreIsolateState, &mut [ZeroCopyBuf]) -> Op where - D: FnOnce(State, Rc<RefCell<ResourceTable>>, Value, BufVec) -> F + Clone, + D: + FnOnce(Rc<State>, Rc<RefCell<ResourceTable>>, Value, BufVec) -> F + Clone, F: Future<Output = Result<Value, OpError>> + 'static, { let state = self.clone(); @@ -167,13 +159,13 @@ impl State { } pub fn stateful_json_op2<D>( - &self, + self: &Rc<Self>, dispatcher: D, ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op where D: Fn( &mut deno_core::CoreIsolateState, - &State, + &Rc<State>, Value, &mut [ZeroCopyBuf], ) -> Result<JsonOp, OpError>, @@ -186,7 +178,7 @@ impl State { // TODO(ry) this should be private. Is called by stateful_json_op or // stateful_minimal_op pub fn core_op<D>( - &self, + self: &Rc<Self>, dispatcher: D, ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op where @@ -206,8 +198,7 @@ impl State { match op { Op::Sync(buf) => { - let mut state_ = state.borrow_mut(); - state_.metrics.op_sync( + state.metrics.borrow_mut().op_sync( bytes_sent_control, bytes_sent_zero_copy, buf.len() as u64, @@ -215,28 +206,31 @@ impl State { Op::Sync(buf) } Op::Async(fut) => { - let mut state_ = state.borrow_mut(); - state_ + 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| { - let mut state_ = state.borrow_mut(); - state_.metrics.op_completed_async(buf.len() as u64); + state + .metrics + .borrow_mut() + .op_completed_async(buf.len() as u64); buf }); Op::Async(result_fut.boxed_local()) } Op::AsyncUnref(fut) => { - let mut state_ = state.borrow_mut(); - state_.metrics.op_dispatched_async_unref( + 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| { - let mut state_ = state.borrow_mut(); - state_.metrics.op_completed_async_unref(buf.len() as u64); + state + .metrics + .borrow_mut() + .op_completed_async_unref(buf.len() as u64); buf }); Op::AsyncUnref(result_fut.boxed_local()) @@ -246,13 +240,13 @@ impl State { } pub fn stateful_minimal_op2<D>( - &self, + self: &Rc<Self>, dispatcher: D, ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op where D: Fn( &mut deno_core::CoreIsolateState, - &State, + &Rc<State>, bool, i32, &mut [ZeroCopyBuf], @@ -276,7 +270,7 @@ impl State { /// 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, + self: &Rc<Self>, dispatcher: D, ) -> impl Fn( &mut deno_core::CoreIsolateState, @@ -284,7 +278,7 @@ impl State { &mut [ZeroCopyBuf], ) -> Result<JsonOp, OpError> where - D: Fn(&State, Value, &mut [ZeroCopyBuf]) -> Result<JsonOp, OpError>, + D: Fn(&Rc<State>, Value, &mut [ZeroCopyBuf]) -> Result<JsonOp, OpError>, { let state = self.clone(); move |_isolate_state: &mut deno_core::CoreIsolateState, @@ -294,7 +288,7 @@ impl State { } pub fn stateful_op2<D>( - &self, + self: &Rc<Self>, dispatcher: D, ) -> impl Fn( &mut deno_core::CoreIsolateState, @@ -304,7 +298,7 @@ impl State { where D: Fn( &mut deno_core::CoreIsolateState, - &State, + &Rc<State>, Value, &mut [ZeroCopyBuf], ) -> Result<JsonOp, OpError>, @@ -322,11 +316,10 @@ impl State { /// /// This is intentionally a non-recoverable check so that people cannot probe /// for unstable APIs from stable programs. - pub fn check_unstable(&self, api_name: &str) { + pub fn check_unstable(self: &Rc<Self>, api_name: &str) { // TODO(ry) Maybe use IsolateHandle::terminate_execution here to provide a // stack trace in JS. - let s = self.0.borrow(); - if !s.global_state.flags.unstable { + if !self.global_state.flags.unstable { exit_unstable(api_name); } } @@ -348,7 +341,7 @@ impl ModuleLoader for State { is_main: bool, ) -> Result<ModuleSpecifier, ErrBox> { if !is_main { - if let Some(import_map) = &self.borrow().import_map { + if let Some(import_map) = &self.import_map { let result = import_map.resolve(specifier, referrer)?; if let Some(r) = result { return Ok(r); @@ -368,11 +361,10 @@ impl ModuleLoader for State { _is_dyn_import: bool, ) -> Pin<Box<deno_core::ModuleSourceFuture>> { let module_specifier = module_specifier.to_owned(); - let mut state = self.borrow_mut(); // TODO(bartlomieju): incrementing resolve_count here has no sense... - state.metrics.resolve_count += 1; + self.metrics.borrow_mut().resolve_count += 1; let module_url_specified = module_specifier.to_string(); - let global_state = state.global_state.clone(); + let global_state = self.global_state.clone(); // TODO(bartlomieju): `fetch_compiled_module` should take `load_id` param let fut = async move { @@ -399,18 +391,17 @@ impl ModuleLoader for State { is_dyn_import: bool, ) -> Pin<Box<dyn Future<Output = Result<(), ErrBox>>>> { let module_specifier = module_specifier.clone(); - let state = self.borrow(); - let target_lib = state.target_lib.clone(); - let maybe_import_map = state.import_map.clone(); + let target_lib = self.target_lib.clone(); + let maybe_import_map = self.import_map.clone(); // Only "main" module is loaded without permission check, // ie. module that is associated with "is_main" state // and is not a dynamic import. - let permissions = if state.is_main && !is_dyn_import { + let permissions = if self.is_main && !is_dyn_import { Permissions::allow_all() } else { - state.permissions.clone() + self.permissions.borrow().clone() }; - let global_state = state.global_state.clone(); + let global_state = self.global_state.clone(); // TODO(bartlomieju): I'm not sure if it's correct to ignore // bad referrer - this is the case for `Deno.core.evalContext()` where // `ref_str` is `<unknown>`. @@ -419,7 +410,6 @@ impl ModuleLoader for State { } else { None }; - drop(state); // TODO(bartlomieju): `prepare_module_load` should take `load_id` param async move { @@ -441,87 +431,65 @@ impl ModuleLoader for State { impl State { /// If `shared_permission` is None then permissions from globa state are used. pub fn new( - global_state: GlobalState, + global_state: &Arc<GlobalState>, shared_permissions: Option<Permissions>, main_module: ModuleSpecifier, maybe_import_map: Option<ImportMap>, is_internal: bool, - ) -> Result<Self, ErrBox> { - let seeded_rng = match global_state.flags.seed { - Some(seed) => Some(StdRng::seed_from_u64(seed)), - None => None, - }; - - let permissions = if let Some(perm) = shared_permissions { - perm - } else { - global_state.permissions.clone() - }; - - let http_client = create_http_client(global_state.flags.ca_file.clone())?; - - let state = Rc::new(RefCell::new(StateInner { - global_state, + ) -> Result<Rc<Self>, ErrBox> { + let fl = &global_state.flags; + let state = State { + global_state: global_state.clone(), main_module, - permissions, + permissions: shared_permissions + .unwrap_or_else(|| global_state.permissions.clone()) + .into(), import_map: maybe_import_map, - metrics: Metrics::default(), - global_timer: GlobalTimer::new(), - workers: HashMap::new(), - next_worker_id: 0, + metrics: Default::default(), + global_timer: Default::default(), + workers: Default::default(), + next_worker_id: Default::default(), start_time: Instant::now(), - seeded_rng, + seeded_rng: fl.seed.map(|v| StdRng::seed_from_u64(v).into()), target_lib: TargetLib::Main, is_main: true, is_internal, - http_client, - })); - - Ok(Self(state)) + http_client: create_http_client(fl.ca_file.as_deref())?.into(), + }; + Ok(Rc::new(state)) } /// If `shared_permission` is None then permissions from globa state are used. pub fn new_for_worker( - global_state: GlobalState, + global_state: &Arc<GlobalState>, shared_permissions: Option<Permissions>, main_module: ModuleSpecifier, - ) -> Result<Self, ErrBox> { - let seeded_rng = match global_state.flags.seed { - Some(seed) => Some(StdRng::seed_from_u64(seed)), - None => None, - }; - - let permissions = if let Some(perm) = shared_permissions { - perm - } else { - global_state.permissions.clone() - }; - - let http_client = create_http_client(global_state.flags.ca_file.clone())?; - - let state = Rc::new(RefCell::new(StateInner { - global_state, + ) -> Result<Rc<Self>, ErrBox> { + let fl = &global_state.flags; + let state = State { + global_state: global_state.clone(), main_module, - permissions, + permissions: shared_permissions + .unwrap_or_else(|| global_state.permissions.clone()) + .into(), import_map: None, - metrics: Metrics::default(), - global_timer: GlobalTimer::new(), - workers: HashMap::new(), - next_worker_id: 0, + metrics: Default::default(), + global_timer: Default::default(), + workers: Default::default(), + next_worker_id: Default::default(), start_time: Instant::now(), - seeded_rng, + seeded_rng: fl.seed.map(|v| StdRng::seed_from_u64(v).into()), target_lib: TargetLib::Worker, is_main: false, is_internal: false, - http_client, - })); - - Ok(Self(state)) + http_client: create_http_client(fl.ca_file.as_deref())?.into(), + }; + Ok(Rc::new(state)) } #[inline] pub fn check_read(&self, path: &Path) -> Result<(), OpError> { - self.borrow().permissions.check_read(path) + self.permissions.borrow().check_read(path) } /// As `check_read()`, but permission error messages will anonymize the path @@ -532,42 +500,42 @@ impl State { path: &Path, display: &str, ) -> Result<(), OpError> { - self.borrow().permissions.check_read_blind(path, display) + self.permissions.borrow().check_read_blind(path, display) } #[inline] pub fn check_write(&self, path: &Path) -> Result<(), OpError> { - self.borrow().permissions.check_write(path) + self.permissions.borrow().check_write(path) } #[inline] pub fn check_env(&self) -> Result<(), OpError> { - self.borrow().permissions.check_env() + self.permissions.borrow().check_env() } #[inline] pub fn check_net(&self, hostname: &str, port: u16) -> Result<(), OpError> { - self.borrow().permissions.check_net(hostname, port) + self.permissions.borrow().check_net(hostname, port) } #[inline] pub fn check_net_url(&self, url: &url::Url) -> Result<(), OpError> { - self.borrow().permissions.check_net_url(url) + self.permissions.borrow().check_net_url(url) } #[inline] pub fn check_run(&self) -> Result<(), OpError> { - self.borrow().permissions.check_run() + self.permissions.borrow().check_run() } #[inline] pub fn check_hrtime(&self) -> Result<(), OpError> { - self.borrow().permissions.check_hrtime() + self.permissions.borrow().check_hrtime() } #[inline] pub fn check_plugin(&self, filename: &Path) -> Result<(), OpError> { - self.borrow().permissions.check_plugin(filename) + self.permissions.borrow().check_plugin(filename) } pub fn check_dyn_import( @@ -599,11 +567,11 @@ impl State { } #[cfg(test)] - pub fn mock(main_module: &str) -> State { + pub fn mock(main_module: &str) -> Rc<State> { let module_specifier = ModuleSpecifier::resolve_url_or_path(main_module) .expect("Invalid entry module"); State::new( - GlobalState::mock(vec!["deno".to_string()], None), + &GlobalState::mock(vec!["deno".to_string()], None), None, module_specifier, None, |