summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/01_core.js4
-rw-r--r--core/bindings.rs80
-rw-r--r--core/extensions.rs9
-rw-r--r--core/lib.rs3
-rw-r--r--core/ops_builtin.rs8
-rw-r--r--core/runtime.rs19
6 files changed, 99 insertions, 24 deletions
diff --git a/core/01_core.js b/core/01_core.js
index 21376b695..354540fb7 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -147,7 +147,7 @@
function opAsync(opName, ...args) {
const promiseId = nextPromiseId++;
- const maybeError = ops[opName](promiseId, ...args);
+ const maybeError = ops[opName].call(promiseId, ...args);
// Handle sync error (e.g: error parsing args)
if (maybeError) return unwrapOpResult(maybeError);
let p = PromisePrototypeThen(setPromise(promiseId), unwrapOpResult);
@@ -167,7 +167,7 @@
}
function opSync(opName, ...args) {
- return unwrapOpResult(ops[opName](...args));
+ return unwrapOpResult(ops[opName].call(...args));
}
function refOp(promiseId) {
diff --git a/core/bindings.rs b/core/bindings.rs
index 6fa9f745b..afbbcee4e 100644
--- a/core/bindings.rs
+++ b/core/bindings.rs
@@ -9,17 +9,36 @@ 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 {
+pub fn external_references(ops: &[OpCtx]) -> v8::ExternalReferences {
+ let mut references = vec![
+ v8::ExternalReference {
function: call_console.map_fn_to(),
- }])
- });
+ },
+ v8::ExternalReference {
+ pointer: ops as *const _ as _,
+ },
+ ];
+
+ 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 let Some(fast_fn) = &ctx.decl.fast_fn {
+ references.push(v8::ExternalReference {
+ pointer: fast_fn.function() as _,
+ });
+ }
+ }
+
+ v8::ExternalReferences::new(&references)
+}
// TODO(nayeemrmn): Move to runtime and/or make `pub(crate)`.
pub fn script_origin<'a>(
@@ -82,7 +101,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 +114,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 +123,32 @@ 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);
+
+ 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,
+ "call",
+ 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());
}
}
@@ -129,13 +172,24 @@ 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 {
+ 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..39b4471bf 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,16 @@ 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 trait FastFunctionSignature {}
+
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 {
@@ -32,7 +35,7 @@ impl OpDecl {
#[derive(Default)]
pub struct Extension {
js_files: Option<Vec<SourcePair>>,
- ops: Option<Vec<OpDecl>>,
+ pub ops: Option<Vec<OpDecl>>,
opstate_fn: Option<Box<OpStateFn>>,
middleware_fn: Option<Box<OpMiddlewareFn>>,
event_loop_middleware: Option<Box<OpEventLoopFn>>,
diff --git a/core/lib.rs b/core/lib.rs
index ab22392c4..a77705ff3 100644
--- a/core/lib.rs
+++ b/core/lib.rs
@@ -113,9 +113,12 @@ pub fn v8_version() -> &'static str {
pub mod _ops {
pub use super::bindings::throw_type_error;
pub use super::error_codes::get_error_code;
+ pub use super::extensions::FastFunctionSignature;
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 64e7f635c..caadd0089 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -230,6 +230,7 @@ fn v8_init(
" --harmony-import-assertions",
" --no-validate-asm",
" --turbo_fast_api_calls",
+ " --allow-natives-syntax",
);
if predictable {
@@ -242,6 +243,9 @@ fn v8_init(
}
}
+pub const V8_WRAPPER_TYPE_INDEX: i32 = 0;
+pub const V8_WRAPPER_OBJECT_INDEX: i32 = 1;
+
#[derive(Default)]
pub struct RuntimeOptions {
/// Source map reference for errors.
@@ -317,7 +321,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()
@@ -330,12 +333,13 @@ impl JsRuntime {
.collect::<Vec<_>>()
.into_boxed_slice();
+ let refs = bindings::external_references(&op_ctxs);
+ 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.
@@ -352,8 +356,13 @@ impl JsRuntime {
let mut params = options
.create_params
.take()
- .unwrap_or_else(v8::Isolate::create_params)
- .external_references(&**bindings::EXTERNAL_REFERENCES);
+ .unwrap_or_else(|| {
+ v8::Isolate::create_params().embedder_wrapper_type_info_offsets(
+ V8_WRAPPER_TYPE_INDEX,
+ V8_WRAPPER_OBJECT_INDEX,
+ )
+ })
+ .external_references(&**refs);
let snapshot_loaded = if let Some(snapshot) = options.startup_snapshot {
params = match snapshot {
Snapshot::Static(data) => params.snapshot_blob(data),