Skip to content

Commit

Permalink
Use gotham-like state for ops (#7385)
Browse files Browse the repository at this point in the history
Provides a concrete state type that can be dynamically added. This is necessary for op crates.
* renames BasicState to OpState
* async ops take `Rc<RefCell<OpState>>`
* sync ops take `&mut OpState`
* removes `OpRegistry`, `OpRouter` traits
* `get_error_class_fn` moved to OpState
* ResourceTable moved to OpState
  • Loading branch information
ry authored Sep 10, 2020
1 parent 6f70e6e commit 7c2e7c6
Show file tree
Hide file tree
Showing 44 changed files with 1,573 additions and 1,345 deletions.
11 changes: 3 additions & 8 deletions cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
mod op_fetch_asset;

use deno_core::js_check;
use deno_core::BasicState;
use deno_core::JsRuntime;
use deno_core::OpRegistry;
use deno_core::StartupData;
use std::collections::HashMap;
use std::env;
Expand Down Expand Up @@ -39,8 +37,7 @@ fn create_snapshot(
}

fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<PathBuf>) {
let state = BasicState::new();
let isolate = JsRuntime::new(state, StartupData::None, true);
let isolate = JsRuntime::new(StartupData::None, true);
create_snapshot(isolate, snapshot_path, files);
}

Expand Down Expand Up @@ -73,13 +70,11 @@ fn create_compiler_snapshot(
cwd.join("dts/lib.deno.unstable.d.ts"),
);

let state = BasicState::new();
state.register_op(
let mut isolate = JsRuntime::new(StartupData::None, true);
isolate.register_op(
"op_fetch_asset",
op_fetch_asset::op_fetch_asset(custom_libs),
);

let isolate = JsRuntime::new(state, StartupData::None, true);
create_snapshot(isolate, snapshot_path, files);
}

Expand Down
2 changes: 0 additions & 2 deletions cli/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ pub static UNSTABLE_NS_LIB: &str = include_str!("dts/lib.deno.unstable.d.ts");
#[test]
fn cli_snapshot() {
let mut isolate = deno_core::JsRuntime::new(
deno_core::BasicState::new(),
deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(CLI_SNAPSHOT)),
false,
);
Expand All @@ -32,7 +31,6 @@ fn cli_snapshot() {
#[test]
fn compiler_snapshot() {
let mut isolate = deno_core::JsRuntime::new(
deno_core::BasicState::new(),
deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(
COMPILER_SNAPSHOT,
)),
Expand Down
57 changes: 57 additions & 0 deletions cli/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,60 @@ impl Metrics {
self.op_completed(bytes_received);
}
}

use deno_core::BufVec;
use deno_core::Op;
use deno_core::OpFn;
use deno_core::OpState;
use std::cell::RefCell;
use std::rc::Rc;

pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
Box::new(move |op_state: Rc<RefCell<OpState>>, 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 = (op_fn)(op_state.clone(), bufs);

let cli_state = crate::ops::cli_state2(&op_state);
let cli_state_ = cli_state.clone();
let mut metrics = cli_state.metrics.borrow_mut();

use futures::future::FutureExt;

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| {
let mut metrics = cli_state_.metrics.borrow_mut();
metrics.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| {
let mut metrics = cli_state_.metrics.borrow_mut();
metrics.op_completed_async_unref(buf.len());
})
.boxed_local();
Op::AsyncUnref(fut)
}
other => other,
}
})
}
32 changes: 18 additions & 14 deletions cli/ops/compiler.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.

use crate::state::State;
use deno_core::OpRegistry;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::Mutex;

pub fn init(s: &Rc<State>, response: Arc<Mutex<Option<String>>>) {
pub fn init(
rt: &mut deno_core::JsRuntime,
response: Arc<Mutex<Option<String>>>,
) {
let custom_assets = std::collections::HashMap::new();
// TODO(ry) use None.
// TODO(bartlomieju): is this op even required?
s.register_op(
rt.register_op(
"op_fetch_asset",
crate::op_fetch_asset::op_fetch_asset(custom_assets),
);

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!({}))
});
super::reg_json_sync(
rt,
"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!({}))
},
);
}
134 changes: 65 additions & 69 deletions cli/ops/dispatch_minimal.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.

use crate::state::State;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::Op;
use deno_core::OpId;
use deno_core::OpRegistry;
use deno_core::OpFn;
use deno_core::OpState;
use futures::future::FutureExt;
use std::cell::RefCell;
use std::future::Future;
use std::iter::repeat;
use std::mem::size_of_val;
Expand Down Expand Up @@ -132,78 +132,74 @@ fn test_parse_min_record() {
assert_eq!(parse_min_record(&buf), None);
}

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);
pub fn minimal_op<F>(op_fn: F) -> Box<OpFn>
where
F: Fn(Rc<RefCell<OpState>>, bool, i32, BufVec) -> MinimalOp + 'static,
{
Box::new(move |state: Rc<RefCell<OpState>>, 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.borrow().get_error_class_fn)(&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 = 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.borrow().get_error_class_fn)(&err);
let error_record = ErrorRecord {
promise_id: 0,
promise_id: record.promise_id,
arg: -1,
error_len: error_class.len() as i32,
error_class: error_class.as_bytes(),
error_message: error.to_string().as_bytes().to_owned(),
error_message: err.to_string().as_bytes().to_owned(),
};
return Op::Sync(error_record.into());
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()
}
}),
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()
}
}),
MinimalOp::Async(min_fut) => {
let fut = async move {
match min_fut.await {
Ok(r) => {
record.result = r;
record.into()
}
};
Op::Async(fut.boxed_local())
}
Err(err) => {
let error_class = (state.borrow().get_error_class_fn)(&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)
}
}
})
}
16 changes: 7 additions & 9 deletions cli/ops/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@
use crate::diagnostics::Diagnostic;
use crate::source_maps::get_orig_position;
use crate::source_maps::CachedMaps;
use crate::state::State;
use deno_core::ErrBox;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use serde_derive::Deserialize;
use serde_json::Value;
use std::collections::HashMap;
use std::rc::Rc;

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);
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_apply_source_map", op_apply_source_map);
super::reg_json_sync(rt, "op_format_diagnostic", op_format_diagnostic);
}

#[derive(Deserialize)]
Expand All @@ -26,7 +24,7 @@ struct ApplySourceMap {
}

fn op_apply_source_map(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
Expand All @@ -39,7 +37,7 @@ fn op_apply_source_map(
args.line_number.into(),
args.column_number.into(),
&mut mappings_map,
&state.global_state.ts_compiler,
&super::cli_state(state).global_state.ts_compiler,
);

Ok(json!({
Expand All @@ -50,7 +48,7 @@ fn op_apply_source_map(
}

fn op_format_diagnostic(
_state: &State,
_state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
Expand Down
Loading

0 comments on commit 7c2e7c6

Please sign in to comment.