summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/benches/op_baseline.rs7
-rw-r--r--core/lib.rs1
-rw-r--r--core/minvalue.rs95
-rw-r--r--core/ops.rs27
-rw-r--r--core/runtime.rs15
5 files changed, 127 insertions, 18 deletions
diff --git a/core/benches/op_baseline.rs b/core/benches/op_baseline.rs
index 5287a7a8b..132d92f00 100644
--- a/core/benches/op_baseline.rs
+++ b/core/benches/op_baseline.rs
@@ -3,10 +3,10 @@ use bencher::{benchmark_group, benchmark_main, Bencher};
use deno_core::error::AnyError;
use deno_core::op_async;
use deno_core::op_sync;
+use deno_core::serialize_op_result;
use deno_core::v8;
use deno_core::JsRuntime;
use deno_core::Op;
-use deno_core::OpResponse;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
@@ -17,8 +17,9 @@ fn create_js_runtime() -> JsRuntime {
let mut runtime = JsRuntime::new(Default::default());
runtime.register_op("pi_json", op_sync(|_, _: (), _| Ok(314159)));
runtime.register_op("pi_async", op_async(op_pi_async));
- runtime
- .register_op("nop", |_, _, _| Op::Sync(OpResponse::Value(Box::new(9))));
+ runtime.register_op("nop", |state, _, _| {
+ Op::Sync(serialize_op_result(Ok(9), state))
+ });
// Init ops
runtime
diff --git a/core/lib.rs b/core/lib.rs
index b49de3b7b..bc9d50e3f 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -5,6 +5,7 @@ mod bindings;
pub mod error;
mod flags;
mod gotham_state;
+mod minvalue;
mod module_specifier;
mod modules;
mod normalize_path;
diff --git a/core/minvalue.rs b/core/minvalue.rs
new file mode 100644
index 000000000..1c9059c12
--- /dev/null
+++ b/core/minvalue.rs
@@ -0,0 +1,95 @@
+use rusty_v8 as v8;
+use std::any::TypeId;
+
+/// SerializablePkg exists to provide a fast path for op returns,
+/// allowing them to avoid boxing primtives (ints/floats/bool/unit/...)
+pub enum SerializablePkg {
+ MinValue(MinValue),
+ Serializable(Box<dyn serde_v8::Serializable>),
+}
+
+impl SerializablePkg {
+ pub fn to_v8<'a>(
+ &self,
+ scope: &mut v8::HandleScope<'a>,
+ ) -> Result<v8::Local<'a, v8::Value>, serde_v8::Error> {
+ match &*self {
+ Self::MinValue(x) => serde_v8::to_v8(scope, x),
+ Self::Serializable(x) => x.to_v8(scope),
+ }
+ }
+}
+
+/// MinValue serves as a lightweight serializable wrapper around primitives
+/// so that we can use them for async values
+#[derive(Clone, Copy)]
+pub enum MinValue {
+ Unit(()),
+ Bool(bool),
+ Int8(i8),
+ Int16(i16),
+ Int32(i32),
+ Int64(i64),
+ UInt8(u8),
+ UInt16(u16),
+ UInt32(u32),
+ UInt64(u64),
+ Float32(f32),
+ Float64(f64),
+}
+
+impl serde::Serialize for MinValue {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ match *self {
+ Self::Unit(_) => serializer.serialize_unit(),
+ Self::Bool(x) => serializer.serialize_bool(x),
+ Self::Int8(x) => serializer.serialize_i8(x),
+ Self::Int16(x) => serializer.serialize_i16(x),
+ Self::Int32(x) => serializer.serialize_i32(x),
+ Self::Int64(x) => serializer.serialize_i64(x),
+ Self::UInt8(x) => serializer.serialize_u8(x),
+ Self::UInt16(x) => serializer.serialize_u16(x),
+ Self::UInt32(x) => serializer.serialize_u32(x),
+ Self::UInt64(x) => serializer.serialize_u64(x),
+ Self::Float32(x) => serializer.serialize_f32(x),
+ Self::Float64(x) => serializer.serialize_f64(x),
+ }
+ }
+}
+
+impl<T: serde::Serialize + 'static> From<T> for SerializablePkg {
+ fn from(x: T) -> Self {
+ let tid = TypeId::of::<T>();
+
+ if tid == TypeId::of::<()>() {
+ Self::MinValue(MinValue::Unit(()))
+ } else if tid == TypeId::of::<bool>() {
+ Self::MinValue(MinValue::Bool(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<i8>() {
+ Self::MinValue(MinValue::Int8(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<i16>() {
+ Self::MinValue(MinValue::Int16(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<i32>() {
+ Self::MinValue(MinValue::Int32(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<i64>() {
+ Self::MinValue(MinValue::Int64(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<u8>() {
+ Self::MinValue(MinValue::UInt8(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<u16>() {
+ Self::MinValue(MinValue::UInt16(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<u32>() {
+ Self::MinValue(MinValue::UInt32(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<u64>() {
+ Self::MinValue(MinValue::UInt64(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<f32>() {
+ Self::MinValue(MinValue::Float32(unsafe { std::mem::transmute_copy(&x) }))
+ } else if tid == TypeId::of::<f64>() {
+ Self::MinValue(MinValue::Float64(unsafe { std::mem::transmute_copy(&x) }))
+ } else {
+ Self::Serializable(Box::new(x))
+ }
+ }
+}
diff --git a/core/ops.rs b/core/ops.rs
index 3cc24c8cc..0c9e19292 100644
--- a/core/ops.rs
+++ b/core/ops.rs
@@ -4,6 +4,7 @@ use crate::error::bad_resource_id;
use crate::error::type_error;
use crate::error::AnyError;
use crate::gotham_state::GothamState;
+use crate::minvalue::SerializablePkg;
use crate::resources::ResourceId;
use crate::resources::ResourceTable;
use crate::runtime::GetErrorClassFn;
@@ -61,7 +62,7 @@ impl<'a, 'b, 'c> OpPayload<'a, 'b, 'c> {
}
pub enum OpResponse {
- Value(Box<dyn serde_v8::Serializable>),
+ Value(OpResult),
Buffer(Box<[u8]>),
}
@@ -74,13 +75,23 @@ pub enum Op {
NotFound,
}
-#[derive(Serialize)]
-#[serde(untagged)]
-pub enum OpResult<R> {
- Ok(R),
+pub enum OpResult {
+ Ok(SerializablePkg),
Err(OpError),
}
+impl OpResult {
+ pub fn to_v8<'a>(
+ &self,
+ scope: &mut v8::HandleScope<'a>,
+ ) -> Result<v8::Local<'a, v8::Value>, serde_v8::Error> {
+ match self {
+ Self::Ok(x) => x.to_v8(scope),
+ Self::Err(err) => serde_v8::to_v8(scope, err),
+ }
+ }
+}
+
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct OpError {
@@ -93,13 +104,13 @@ pub fn serialize_op_result<R: Serialize + 'static>(
result: Result<R, AnyError>,
state: Rc<RefCell<OpState>>,
) -> OpResponse {
- OpResponse::Value(Box::new(match result {
- Ok(v) => OpResult::Ok(v),
+ OpResponse::Value(match result {
+ Ok(v) => OpResult::Ok(v.into()),
Err(err) => OpResult::Err(OpError {
class_name: (state.borrow().get_error_class_fn)(&err),
message: err.to_string(),
}),
- }))
+ })
}
/// Maintains the resources and ops inside a JS runtime.
diff --git a/core/runtime.rs b/core/runtime.rs
index 98bcc018a..e974bdbb2 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -1501,18 +1501,19 @@ pub mod tests {
}
fn dispatch(
- op_state: Rc<RefCell<OpState>>,
+ rc_op_state: Rc<RefCell<OpState>>,
payload: OpPayload,
buf: Option<ZeroCopyBuf>,
) -> Op {
- let op_state_ = op_state.borrow();
+ let rc_op_state2 = rc_op_state.clone();
+ let op_state_ = rc_op_state2.borrow();
let test_state = op_state_.borrow::<TestState>();
test_state.dispatch_count.fetch_add(1, Ordering::Relaxed);
match test_state.mode {
Mode::Async => {
let control: u8 = payload.deserialize().unwrap();
assert_eq!(control, 42);
- let resp = (0, OpResponse::Value(Box::new(43)));
+ let resp = (0, serialize_op_result(Ok(43), rc_op_state));
Op::Async(Box::pin(futures::future::ready(resp)))
}
Mode::AsyncUnref => {
@@ -1521,7 +1522,7 @@ pub mod tests {
let fut = async {
// This future never finish.
futures::future::pending::<()>().await;
- (0, OpResponse::Value(Box::new(43)))
+ (0, serialize_op_result(Ok(43), rc_op_state))
};
Op::AsyncUnref(Box::pin(fut))
}
@@ -1531,7 +1532,7 @@ pub mod tests {
assert_eq!(buf.len(), 1);
}
- let resp = OpResponse::Value(Box::new(43));
+ let resp = serialize_op_result(Ok(43), rc_op_state);
Op::Async(Box::pin(futures::future::ready((0, resp))))
}
}
@@ -1972,11 +1973,11 @@ pub mod tests {
let dispatch_count = Arc::new(AtomicUsize::new(0));
let dispatch_count_ = dispatch_count.clone();
- let dispatcher = move |_state, payload: OpPayload, _buf| -> Op {
+ let dispatcher = move |state, payload: OpPayload, _buf| -> Op {
dispatch_count_.fetch_add(1, Ordering::Relaxed);
let control: u8 = payload.deserialize().unwrap();
assert_eq!(control, 42);
- let resp = (0, OpResponse::Value(Box::new(43)));
+ let resp = (0, serialize_op_result(Ok(43), state));
Op::Async(Box::pin(futures::future::ready(resp)))
};