diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2022-08-21 17:37:53 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-21 17:37:53 +0530 |
commit | 906aa78af33c8405a47d5446d2a6fb3348c275bb (patch) | |
tree | c444e42b6bdfe4bad35634925829a1b1d190fa75 /core | |
parent | e39d4e3e7fb9815bf094e7321d1d73d00275831a (diff) |
feat(ops): V8 Fast Calls (#15291)
Diffstat (limited to 'core')
-rw-r--r-- | core/bindings.rs | 100 | ||||
-rw-r--r-- | core/extensions.rs | 5 | ||||
-rw-r--r-- | core/lib.rs | 2 | ||||
-rw-r--r-- | core/ops_builtin.rs | 8 | ||||
-rw-r--r-- | core/runtime.rs | 9 |
5 files changed, 103 insertions, 21 deletions
diff --git a/core/bindings.rs b/core/bindings.rs index f3c16acbf..f75f6c7f3 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -9,17 +9,39 @@ use crate::modules::ModuleMap; use crate::ops::OpCtx; use crate::JsRuntime; use log::debug; -use once_cell::sync::Lazy; use std::option::Option; use std::os::raw::c_void; +use v8::fast_api::FastFunction; use v8::MapFnTo; -pub static EXTERNAL_REFERENCES: Lazy<v8::ExternalReferences> = - Lazy::new(|| { - v8::ExternalReferences::new(&[v8::ExternalReference { - function: call_console.map_fn_to(), - }]) - }); +pub fn external_references( + ops: &[OpCtx], + snapshot_loaded: bool, +) -> v8::ExternalReferences { + let mut references = vec![v8::ExternalReference { + function: call_console.map_fn_to(), + }]; + + for ctx in ops { + let ctx_ptr = ctx as *const OpCtx as _; + references.push(v8::ExternalReference { pointer: ctx_ptr }); + references.push(v8::ExternalReference { + function: ctx.decl.v8_fn_ptr, + }); + if snapshot_loaded { + if let Some(fast_fn) = &ctx.decl.fast_fn { + references.push(v8::ExternalReference { + pointer: fast_fn.function() as _, + }); + } + } + } + + let refs = v8::ExternalReferences::new(&references); + // Leak, V8 takes ownership of the references. + std::mem::forget(references); + refs +} // TODO(nayeemrmn): Move to runtime and/or make `pub(crate)`. pub fn script_origin<'a>( @@ -82,7 +104,8 @@ pub fn initialize_context<'s>( // Grab the Deno.core.ops object & init it let ops_obj = JsRuntime::grab_global::<v8::Object>(scope, "Deno.core.ops") .expect("Deno.core.ops to exist"); - initialize_ops(scope, ops_obj, op_ctxs); + initialize_ops(scope, ops_obj, op_ctxs, snapshot_loaded); + return scope.escape(context); } @@ -94,7 +117,8 @@ pub fn initialize_context<'s>( // Bind functions to Deno.core.ops.* let ops_obj = JsRuntime::ensure_objs(scope, global, "Deno.core.ops").unwrap(); - initialize_ops(scope, ops_obj, op_ctxs); + + initialize_ops(scope, ops_obj, op_ctxs, snapshot_loaded); scope.escape(context) } @@ -102,10 +126,46 @@ fn initialize_ops( scope: &mut v8::HandleScope, ops_obj: v8::Local<v8::Object>, op_ctxs: &[OpCtx], + snapshot_loaded: bool, ) { for ctx in op_ctxs { let ctx_ptr = ctx as *const OpCtx as *const c_void; - set_func_raw(scope, ops_obj, ctx.decl.name, ctx.decl.v8_fn_ptr, ctx_ptr); + + // If this is a fast op, we don't want it to be in the snapshot. + // Only initialize once snapshot is loaded. + if ctx.decl.fast_fn.is_some() && snapshot_loaded { + let object_template = v8::ObjectTemplate::new(scope); + assert!(object_template.set_internal_field_count( + (crate::runtime::V8_WRAPPER_OBJECT_INDEX + 1) as usize + )); + + let method_obj = object_template.new_instance(scope).unwrap(); + method_obj.set_aligned_pointer_in_internal_field( + crate::runtime::V8_WRAPPER_OBJECT_INDEX, + ctx_ptr, + ); + set_func_raw( + scope, + method_obj, + "fast", + ctx.decl.v8_fn_ptr, + ctx_ptr, + &ctx.decl.fast_fn, + snapshot_loaded, + ); + let method_key = v8::String::new(scope, ctx.decl.name).unwrap(); + ops_obj.set(scope, method_key.into(), method_obj.into()); + } else { + set_func_raw( + scope, + ops_obj, + ctx.decl.name, + ctx.decl.v8_fn_ptr, + ctx_ptr, + &None, + snapshot_loaded, + ); + } } } @@ -129,13 +189,25 @@ pub fn set_func_raw( name: &'static str, callback: v8::FunctionCallback, external_data: *const c_void, + fast_function: &Option<Box<dyn FastFunction>>, + snapshot_loaded: bool, ) { let key = v8::String::new(scope, name).unwrap(); let external = v8::External::new(scope, external_data as *mut c_void); - let val = v8::Function::builder_raw(callback) - .data(external.into()) - .build(scope) - .unwrap(); + let builder = + v8::FunctionTemplate::builder_raw(callback).data(external.into()); + let templ = if let Some(fast_function) = fast_function { + // Don't initialize fast ops when snapshotting, the external references count mismatch. + if !snapshot_loaded { + builder.build(scope) + } else { + // TODO(@littledivy): Support fast api overloads in ops. + builder.build_fast(scope, &**fast_function, None) + } + } else { + builder.build(scope) + }; + let val = templ.get_function(scope).unwrap(); val.set_name(key); obj.set(scope, key.into(), val.into()); } diff --git a/core/extensions.rs b/core/extensions.rs index ce6957875..846770d1f 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -2,6 +2,7 @@ use crate::OpState; use anyhow::Error; use std::{cell::RefCell, rc::Rc, task::Context}; +use v8::fast_api::FastFunction; pub type SourcePair = (&'static str, &'static str); pub type OpFnRef = v8::FunctionCallback; @@ -9,14 +10,14 @@ pub type OpMiddlewareFn = dyn Fn(OpDecl) -> OpDecl; pub type OpStateFn = dyn Fn(&mut OpState) -> Result<(), Error>; pub type OpEventLoopFn = dyn Fn(Rc<RefCell<OpState>>, &mut Context) -> bool; -#[derive(Clone, Copy)] pub struct OpDecl { pub name: &'static str, pub v8_fn_ptr: OpFnRef, pub enabled: bool, - pub is_async: bool, // TODO(@AaronO): enum sync/async/fast ? + pub is_async: bool, pub is_unstable: bool, pub is_v8: bool, + pub fast_fn: Option<Box<dyn FastFunction>>, } impl OpDecl { diff --git a/core/lib.rs b/core/lib.rs index 57e81ee7a..8043b5e95 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -118,6 +118,8 @@ pub mod _ops { pub use super::ops::to_op_result; pub use super::ops::OpCtx; pub use super::runtime::queue_async_op; + pub use super::runtime::V8_WRAPPER_OBJECT_INDEX; + pub use super::runtime::V8_WRAPPER_TYPE_INDEX; } /// A helper macro that will return a call site in Rust code. Should be diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs index a42c0bae8..2e911e415 100644 --- a/core/ops_builtin.rs +++ b/core/ops_builtin.rs @@ -31,6 +31,7 @@ pub(crate) fn init_builtins() -> Extension { op_wasm_streaming_set_url::decl(), op_void_sync::decl(), op_void_async::decl(), + op_add::decl(), // // TODO(@AaronO): track IO metrics for builtin streams op_read::decl(), op_write::decl(), @@ -54,7 +55,12 @@ pub fn op_resources(state: &mut OpState) -> Vec<(ResourceId, String)> { .collect() } -#[op] +#[op(fast)] +fn op_add(a: i32, b: i32) -> i32 { + a + b +} + +#[op(fast)] pub fn op_void_sync() {} #[op] diff --git a/core/runtime.rs b/core/runtime.rs index 68c3ab002..06c777687 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -328,7 +328,6 @@ impl JsRuntime { if let Some(get_error_class_fn) = options.get_error_class_fn { op_state.get_error_class_fn = get_error_class_fn; } - let op_state = Rc::new(RefCell::new(op_state)); let op_ctxs = ops .into_iter() @@ -341,12 +340,14 @@ impl JsRuntime { .collect::<Vec<_>>() .into_boxed_slice(); + let refs = bindings::external_references(&op_ctxs, !options.will_snapshot); + // V8 takes ownership of external_references. + let refs: &'static v8::ExternalReferences = Box::leak(Box::new(refs)); let global_context; let (mut isolate, maybe_snapshot_creator) = if options.will_snapshot { // TODO(ry) Support loading snapshots before snapshotting. assert!(options.startup_snapshot.is_none()); - let mut creator = - v8::SnapshotCreator::new(Some(&bindings::EXTERNAL_REFERENCES)); + let mut creator = v8::SnapshotCreator::new(Some(refs)); // SAFETY: `get_owned_isolate` is unsafe because it may only be called // once. This is the only place we call this function, so this call is // safe. @@ -369,7 +370,7 @@ impl JsRuntime { V8_WRAPPER_OBJECT_INDEX, ) }) - .external_references(&**bindings::EXTERNAL_REFERENCES); + .external_references(&**refs); let snapshot_loaded = if let Some(snapshot) = options.startup_snapshot { params = match snapshot { Snapshot::Static(data) => params.snapshot_blob(data), |