diff --git a/benches/function.rs b/benches/function.rs index ef8a3d34..3c6e906b 100644 --- a/benches/function.rs +++ b/benches/function.rs @@ -94,36 +94,74 @@ fn main() { global.set(scope, name.into(), value.into()).unwrap(); } + { + extern "C" fn callback(info: *const v8::FunctionCallbackInfo) { + let scope = unsafe { &mut v8::CallbackScope::new(&*info) }; + let mut rv = + unsafe { v8::ReturnValue::from_function_callback_info(info) }; + rv.set(v8::undefined(scope).into()); + } + let func = v8::Function::new_raw(scope, callback).unwrap(); + let name = v8::String::new(scope, "undefined_from_scope").unwrap(); + global.set(scope, name.into(), func.into()).unwrap(); + } + + { + extern "C" fn callback(info: *const v8::FunctionCallbackInfo) { + let mut rv = + unsafe { v8::ReturnValue::from_function_callback_info(info) }; + let mut info = unsafe { + v8::FunctionCallbackArguments::from_function_callback_info(info) + }; + rv.set(v8::undefined(unsafe { info.get_isolate() }).into()); + } + let func = v8::Function::new_raw(scope, callback).unwrap(); + let name = v8::String::new(scope, "undefined_from_isolate").unwrap(); + global.set(scope, name.into(), func.into()).unwrap(); + } + let runs = 100_000_000; - for x in [ - "new_", - "new_raw", - "new_set_uint32", - "new_raw_set_uint32", - "new_fast", + for (group_name, benches) in [ + ( + "function_overhead", + &[ + "new_", + "new_raw", + "new_set_uint32", + "new_raw_set_uint32", + "new_fast", + ][..], + ), + ( + "primitives", + &["undefined_from_scope", "undefined_from_isolate"][..], + ), ] { - let code = format!( - " - function bench() {{ return {}(); }}; - runs = {}; - start = Date.now(); - for (i = 0; i < runs; i++) bench(); - Date.now() - start; - ", - x, runs - ); + println!("Running {} ...", group_name); + for x in benches { + let code = format!( + " + function bench() {{ return {}(); }}; + runs = {}; + start = Date.now(); + for (i = 0; i < runs; i++) bench(); + Date.now() - start; + ", + x, runs + ); - let r = eval(scope, &code).unwrap(); - let number = r.to_number(scope).unwrap(); - let total_ms = number.number_value(scope).unwrap(); - let total_ns = 1e6 * total_ms; - let ns_per_run = total_ns / (runs as f64); - let mops_per_sec = (runs as f64) / (total_ms / 1000.0) / 1e6; - println!( - "{:.1} ns per run {:.1} million ops/sec → {}", - ns_per_run, mops_per_sec, x - ); + let r = eval(scope, &code).unwrap(); + let number = r.to_number(scope).unwrap(); + let total_ms = number.number_value(scope).unwrap(); + let total_ns = 1e6 * total_ms; + let ns_per_run = total_ns / (runs as f64); + let mops_per_sec = (runs as f64) / (total_ms / 1000.0) / 1e6; + println!( + " {:.1} ns per run {:.1} million ops/sec → {}", + ns_per_run, mops_per_sec, x + ); + } } } diff --git a/src/function.rs b/src/function.rs index 463a0bcf..8d159acc 100644 --- a/src/function.rs +++ b/src/function.rs @@ -12,6 +12,7 @@ use crate::support::{int, Opaque}; use crate::Context; use crate::Function; use crate::HandleScope; +use crate::Isolate; use crate::Local; use crate::Name; use crate::Object; @@ -69,6 +70,9 @@ extern "C" { fn v8__FunctionCallbackInfo__NewTarget( this: *const FunctionCallbackInfo, ) -> *const Value; + fn v8__FunctionCallbackInfo__GetIsolate( + this: *const FunctionCallbackInfo, + ) -> *mut Isolate; fn v8__PropertyCallbackInfo__GetReturnValue( this: *const PropertyCallbackInfo, @@ -233,6 +237,11 @@ impl<'s> FunctionCallbackArguments<'s> { } } + #[inline(always)] + pub unsafe fn get_isolate(&mut self) -> &mut Isolate { + &mut *v8__FunctionCallbackInfo__GetIsolate(self.info) + } + /// Returns the receiver. This corresponds to the "this" value. #[inline(always)] pub fn this(&self) -> Local<'s, Object> { diff --git a/src/handle.rs b/src/handle.rs index 34353669..8966fc85 100644 --- a/src/handle.rs +++ b/src/handle.rs @@ -107,6 +107,11 @@ impl<'s, T> Local<'s, T> { NonNull::new(ptr as *mut _).map(|nn| Self::from_non_null(nn)) } + #[inline(always)] + pub(crate) unsafe fn from_raw_unchecked(ptr: *const T) -> Self { + Self(NonNull::new_unchecked(ptr as *mut _), PhantomData) + } + #[inline(always)] pub(crate) unsafe fn from_non_null(nn: NonNull) -> Self { Self(nn, PhantomData) diff --git a/src/isolate.rs b/src/isolate.rs index 33d8db78..3bf75435 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -1123,6 +1123,18 @@ impl DerefMut for OwnedIsolate { } } +impl AsMut for OwnedIsolate { + fn as_mut(&mut self) -> &mut Isolate { + self + } +} + +impl AsMut for Isolate { + fn as_mut(&mut self) -> &mut Isolate { + self + } +} + impl HeapStatistics { #[inline(always)] pub fn total_heap_size(&self) -> usize { diff --git a/src/primitives.rs b/src/primitives.rs index e8a108c6..750ef349 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -1,6 +1,5 @@ use crate::isolate::Isolate; use crate::Boolean; -use crate::HandleScope; use crate::Local; use crate::Primitive; @@ -12,24 +11,29 @@ extern "C" { } #[inline(always)] -pub fn null<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, Primitive> { - unsafe { scope.cast_local(|sd| v8__Null(sd.get_isolate_ptr())) }.unwrap() +pub fn null<'a, R>(scope: &mut R) -> Local<'a, Primitive> +where + R: AsMut, +{ + unsafe { Local::from_raw_unchecked(v8__Null(scope.as_mut())) } } #[inline(always)] -pub fn undefined<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, Primitive> { - unsafe { scope.cast_local(|sd| v8__Undefined(sd.get_isolate_ptr())) }.unwrap() +pub fn undefined<'a, R>(scope: &mut R) -> Local<'a, Primitive> +where + R: AsMut, +{ + unsafe { Local::from_raw_unchecked(v8__Undefined(scope.as_mut())) } } impl Boolean { #[inline(always)] - pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, - value: bool, - ) -> Local<'s, Boolean> { + pub fn new<'a, R>(scope: &mut R, value: bool) -> Local<'a, Boolean> + where + R: AsMut, + { unsafe { - scope.cast_local(|sd| v8__Boolean__New(sd.get_isolate_ptr(), value)) + Local::from_raw_unchecked(v8__Boolean__New(scope.as_mut(), value)) } - .unwrap() } } diff --git a/tests/test_api.rs b/tests/test_api.rs index a1e83d06..dc024ab7 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -553,6 +553,15 @@ fn get_isolate_from_handle() { check_eval(scope, Some(false), "3.3 / 3.3"); } +#[test] +fn handles_from_isolate() { + let _setup_guard = setup(); + let isolate = &mut v8::Isolate::new(Default::default()); + let _ = v8::null(isolate); + let _ = v8::undefined(isolate); + let _ = v8::Boolean::new(isolate, true); +} + #[test] fn array_buffer() { let _setup_guard = setup();