mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-28 16:21:04 -05:00
V8 Fast API Calls (#1021)
Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
parent
e6b443a6e8
commit
1d0a4c1792
6 changed files with 280 additions and 6 deletions
|
@ -1760,6 +1760,37 @@ const v8::Signature* v8__Signature__New(v8::Isolate* isolate,
|
|||
return local_to_ptr(v8::Signature::New(isolate, ptr_to_local(templ)));
|
||||
}
|
||||
|
||||
v8::CTypeInfo* v8__CTypeInfo__New(v8::CTypeInfo::Type ty) {
|
||||
std::unique_ptr<v8::CTypeInfo> u = std::make_unique<v8::CTypeInfo>(v8::CTypeInfo(ty));
|
||||
return u.release();
|
||||
}
|
||||
|
||||
struct CTypeSequenceType {
|
||||
v8::CTypeInfo::Type c_type;
|
||||
v8::CTypeInfo::SequenceType sequence_type;
|
||||
};
|
||||
|
||||
v8::CTypeInfo* v8__CTypeInfo__New__From__Slice(unsigned int len,
|
||||
CTypeSequenceType* ty) {
|
||||
v8::CTypeInfo* v = (v8::CTypeInfo*)malloc(sizeof(v8::CTypeInfo) * len);
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
v[i] = v8::CTypeInfo(ty[i].c_type, ty[i].sequence_type);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
v8::CFunction* v8__CFunction__New(void* func_ptr, const v8::CFunctionInfo* info) {
|
||||
std::unique_ptr<v8::CFunction> c_function = std::make_unique<v8::CFunction>(v8::CFunction(func_ptr, info));
|
||||
return c_function.release();
|
||||
}
|
||||
|
||||
v8::CFunctionInfo* v8__CFunctionInfo__New(const v8::CTypeInfo& return_info,
|
||||
unsigned int args_len,
|
||||
v8::CTypeInfo* args_info) {
|
||||
std::unique_ptr<v8::CFunctionInfo> info = std::make_unique<v8::CFunctionInfo>(v8::CFunctionInfo(return_info, args_len, args_info));
|
||||
return info.release();
|
||||
}
|
||||
|
||||
const v8::FunctionTemplate* v8__FunctionTemplate__New(
|
||||
v8::Isolate* isolate, v8::FunctionCallback callback,
|
||||
const v8::Value* data_or_null, const v8::Signature* signature_or_null,
|
||||
|
|
150
src/fast_api.rs
Normal file
150
src/fast_api.rs
Normal file
|
@ -0,0 +1,150 @@
|
|||
use crate::support::Opaque;
|
||||
use libc::c_void;
|
||||
use std::mem::transmute_copy;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
extern "C" {
|
||||
fn v8__CTypeInfo__New(ty: CType) -> *mut CTypeInfo;
|
||||
fn v8__CTypeInfo__New__From__Slice(
|
||||
len: usize,
|
||||
tys: *const CTypeSequenceInfo,
|
||||
) -> *mut CTypeInfo;
|
||||
fn v8__CFunctionInfo__New(
|
||||
return_info: *const CTypeInfo,
|
||||
args_len: usize,
|
||||
args_info: *const CTypeInfo,
|
||||
) -> *mut CFunctionInfo;
|
||||
fn v8__CFunction__New(
|
||||
func_ptr: *const c_void,
|
||||
info: *const CFunctionInfo,
|
||||
) -> *mut CFunction;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct CFunctionInfo(Opaque);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct CFunction(Opaque);
|
||||
|
||||
impl CFunction {
|
||||
pub(crate) unsafe fn new(
|
||||
func_ptr: *const c_void,
|
||||
args: *const CTypeInfo,
|
||||
args_len: usize,
|
||||
return_type: *const CTypeInfo,
|
||||
) -> NonNull<CFunction> {
|
||||
let info = v8__CFunctionInfo__New(return_type, args_len, args);
|
||||
NonNull::new_unchecked(v8__CFunction__New(func_ptr, info))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct CTypeInfo(Opaque);
|
||||
|
||||
impl CTypeInfo {
|
||||
pub(crate) fn new(ty: CType) -> NonNull<CTypeInfo> {
|
||||
unsafe { NonNull::new_unchecked(v8__CTypeInfo__New(ty)) }
|
||||
}
|
||||
|
||||
pub(crate) fn new_from_slice(types: &[Type]) -> NonNull<CTypeInfo> {
|
||||
let mut structs = vec![];
|
||||
|
||||
for type_ in types.iter() {
|
||||
structs.push(type_.into())
|
||||
}
|
||||
|
||||
unsafe {
|
||||
NonNull::new_unchecked(v8__CTypeInfo__New__From__Slice(
|
||||
structs.len(),
|
||||
structs.as_ptr(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum SequenceType {
|
||||
Scalar,
|
||||
/// sequence<T>
|
||||
IsSequence,
|
||||
/// TypedArray of T or any ArrayBufferView if T is void
|
||||
IsTypedArray,
|
||||
/// ArrayBuffer
|
||||
IsArrayBuffer,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum CType {
|
||||
Void = 0,
|
||||
Bool,
|
||||
Int32,
|
||||
Uint32,
|
||||
Int64,
|
||||
Uint64,
|
||||
Float32,
|
||||
Float64,
|
||||
V8Value,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Type {
|
||||
Void,
|
||||
Bool,
|
||||
Int32,
|
||||
Uint32,
|
||||
Int64,
|
||||
Uint64,
|
||||
Float32,
|
||||
Float64,
|
||||
V8Value,
|
||||
}
|
||||
|
||||
impl From<&Type> for CType {
|
||||
fn from(ty: &Type) -> CType {
|
||||
match ty {
|
||||
Type::Void => CType::Void,
|
||||
Type::Bool => CType::Bool,
|
||||
Type::Int32 => CType::Int32,
|
||||
Type::Uint32 => CType::Uint32,
|
||||
Type::Int64 => CType::Int64,
|
||||
Type::Uint64 => CType::Uint64,
|
||||
Type::Float32 => CType::Float32,
|
||||
Type::Float64 => CType::Float64,
|
||||
Type::V8Value => CType::V8Value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Type> for CTypeSequenceInfo {
|
||||
fn from(ty: &Type) -> CTypeSequenceInfo {
|
||||
CTypeSequenceInfo {
|
||||
c_type: ty.into(),
|
||||
sequence_type: SequenceType::Scalar,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct CTypeSequenceInfo {
|
||||
c_type: CType,
|
||||
sequence_type: SequenceType,
|
||||
}
|
||||
|
||||
pub trait FastFunction {
|
||||
type Signature;
|
||||
fn args(&self) -> &'static [Type] {
|
||||
&[]
|
||||
}
|
||||
fn return_type(&self) -> CType {
|
||||
CType::Void
|
||||
}
|
||||
fn function(&self) -> Self::Signature;
|
||||
fn raw(&self) -> *const c_void {
|
||||
unsafe { transmute_copy(&self.function()) }
|
||||
}
|
||||
}
|
|
@ -117,10 +117,6 @@ pub enum SideEffectType {
|
|||
HasSideEffectToReceiver,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub(crate) struct CFunction([usize; 2]);
|
||||
|
||||
// Note: the 'cb lifetime is required because the ReturnValue object must not
|
||||
// outlive the FunctionCallbackInfo/PropertyCallbackInfo object from which it
|
||||
// is derived.
|
||||
|
|
|
@ -38,6 +38,7 @@ mod date;
|
|||
mod exception;
|
||||
mod external;
|
||||
mod external_references;
|
||||
pub mod fast_api;
|
||||
mod fixed_array;
|
||||
mod function;
|
||||
mod handle;
|
||||
|
|
|
@ -3,12 +3,14 @@ use crate::data::FunctionTemplate;
|
|||
use crate::data::Name;
|
||||
use crate::data::ObjectTemplate;
|
||||
use crate::data::Template;
|
||||
use crate::fast_api::CFunction;
|
||||
use crate::fast_api::CTypeInfo;
|
||||
use crate::fast_api::FastFunction;
|
||||
use crate::isolate::Isolate;
|
||||
use crate::support::int;
|
||||
use crate::support::MapFnTo;
|
||||
use crate::AccessorNameGetterCallback;
|
||||
use crate::AccessorNameSetterCallback;
|
||||
use crate::CFunction;
|
||||
use crate::ConstructorBehavior;
|
||||
use crate::Context;
|
||||
use crate::Function;
|
||||
|
@ -149,6 +151,36 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> {
|
|||
}
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn build_fast(
|
||||
self,
|
||||
scope: &mut HandleScope<'s, ()>,
|
||||
fast_function: impl FastFunction,
|
||||
) -> Local<'s, FunctionTemplate> {
|
||||
unsafe {
|
||||
let args = CTypeInfo::new_from_slice(fast_function.args());
|
||||
let ret = CTypeInfo::new(fast_function.return_type());
|
||||
let c_fn = CFunction::new(
|
||||
fast_function.raw(),
|
||||
args.as_ptr(),
|
||||
fast_function.args().len(),
|
||||
ret.as_ptr(),
|
||||
);
|
||||
scope.cast_local(|sd| {
|
||||
v8__FunctionTemplate__New(
|
||||
sd.get_isolate_ptr(),
|
||||
self.callback,
|
||||
self.data.map_or_else(null, |p| &*p),
|
||||
self.signature.map_or_else(null, |p| &*p),
|
||||
self.length,
|
||||
ConstructorBehavior::Throw,
|
||||
self.side_effect_type,
|
||||
c_fn.as_ptr() as _,
|
||||
)
|
||||
})
|
||||
}
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// A Signature specifies which receiver is valid for a function.
|
||||
|
|
|
@ -14,6 +14,7 @@ use std::ptr::NonNull;
|
|||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use v8::fast_api;
|
||||
|
||||
// TODO(piscisaureus): Ideally there would be no need to import this trait.
|
||||
use v8::MapFnTo;
|
||||
|
@ -36,7 +37,7 @@ fn setup() -> SetupGuard {
|
|||
))
|
||||
.is_ok());
|
||||
v8::V8::set_flags_from_string(
|
||||
"--expose_gc --harmony-import-assertions --harmony-shadow-realm",
|
||||
"--expose_gc --harmony-import-assertions --harmony-shadow-realm --allow_natives_syntax --turbo_fast_api_calls",
|
||||
);
|
||||
v8::V8::initialize_platform(
|
||||
v8::new_default_platform(0, false).make_shared(),
|
||||
|
@ -7014,3 +7015,66 @@ fn host_create_shadow_realm_context_callback() {
|
|||
assert_eq!(value.uint32_value(scope), Some(42));
|
||||
assert!(scope.get_slot::<CheckData>().unwrap().callback_called);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fast_calls() {
|
||||
static mut WHO: &str = "none";
|
||||
fn fast_fn(a: u32, b: u32) -> u32 {
|
||||
unsafe { WHO = "fast" };
|
||||
a + b
|
||||
}
|
||||
|
||||
pub struct FastTest;
|
||||
impl fast_api::FastFunction for FastTest {
|
||||
fn args(&self) -> &'static [fast_api::Type] {
|
||||
&[fast_api::Type::Uint32, fast_api::Type::Uint32]
|
||||
}
|
||||
|
||||
fn return_type(&self) -> fast_api::CType {
|
||||
fast_api::CType::Uint32
|
||||
}
|
||||
|
||||
type Signature = fn(a: u32, b: u32) -> u32;
|
||||
fn function(&self) -> Self::Signature {
|
||||
fast_fn
|
||||
}
|
||||
}
|
||||
|
||||
fn slow_fn(
|
||||
scope: &mut v8::HandleScope,
|
||||
_: v8::FunctionCallbackArguments,
|
||||
mut rv: v8::ReturnValue,
|
||||
) {
|
||||
unsafe { WHO = "slow" };
|
||||
rv.set(v8::Boolean::new(scope, false).into());
|
||||
}
|
||||
|
||||
let _setup_guard = setup();
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
|
||||
let global = context.global(scope);
|
||||
|
||||
let template =
|
||||
v8::FunctionTemplate::builder(slow_fn).build_fast(scope, FastTest);
|
||||
|
||||
let name = v8::String::new(scope, "func").unwrap();
|
||||
let value = template.get_function(scope).unwrap();
|
||||
global.set(scope, name.into(), value.into()).unwrap();
|
||||
let source = r#"
|
||||
function f(x, y) { return func(x, y); }
|
||||
%PrepareFunctionForOptimization(f);
|
||||
f(1, 2);
|
||||
"#;
|
||||
eval(scope, source).unwrap();
|
||||
assert_eq!("slow", unsafe { WHO });
|
||||
|
||||
let source = r#"
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
f(1, 2);
|
||||
"#;
|
||||
eval(scope, source).unwrap();
|
||||
assert_eq!("fast", unsafe { WHO });
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue