update fast calls api (#1564)

This commit is contained in:
snek 2024-08-13 18:15:34 +02:00 committed by GitHub
parent 0d57670bac
commit 70e18db2ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 359 additions and 475 deletions

View File

@ -65,12 +65,14 @@ fn main() {
fn fast_fn() -> i32 { fn fast_fn() -> i32 {
42 42
} }
const FAST_CALL: v8::fast_api::FastFunction = const FAST_CALL: v8::fast_api::CFunction = v8::fast_api::CFunction::new(
v8::fast_api::FastFunction::new( fast_fn as _,
&[v8::fast_api::Type::V8Value], &v8::fast_api::CFunctionInfo::new(
v8::fast_api::CType::Int32, v8::fast_api::Type::Int32.scalar(),
fast_fn as _, &[v8::fast_api::Type::V8Value.scalar()],
); v8::fast_api::Int64Representation::Number,
),
);
let template = v8::FunctionTemplate::builder( let template = v8::FunctionTemplate::builder(
|scope: &mut v8::HandleScope, |scope: &mut v8::HandleScope,
_: v8::FunctionCallbackArguments, _: v8::FunctionCallbackArguments,
@ -78,7 +80,7 @@ fn main() {
rv.set(v8::Integer::new(scope, 42).into()); rv.set(v8::Integer::new(scope, 42).into());
}, },
) )
.build_fast(scope, &FAST_CALL, None, None, None); .build_fast(scope, &[FAST_CALL]);
let name = v8::String::new(scope, "new_fast").unwrap(); let name = v8::String::new(scope, "new_fast").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();

View File

@ -2247,70 +2247,17 @@ const v8::Signature* v8__Signature__New(v8::Isolate* isolate,
return local_to_ptr(v8::Signature::New(isolate, ptr_to_local(templ))); 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();
}
void v8__CTypeInfo__DELETE(v8::CTypeInfo* self) { delete self; }
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::CFunctionInfo* v8__CFunctionInfo__New(
const v8::CTypeInfo& return_info, unsigned int args_len,
v8::CTypeInfo* args_info, v8::CFunctionInfo::Int64Representation repr) {
std::unique_ptr<v8::CFunctionInfo> info = std::make_unique<v8::CFunctionInfo>(
v8::CFunctionInfo(return_info, args_len, args_info, repr));
return info.release();
}
void v8__CFunctionInfo__DELETE(v8::CFunctionInfo* self) { delete self; }
const v8::FunctionTemplate* v8__FunctionTemplate__New( const v8::FunctionTemplate* v8__FunctionTemplate__New(
v8::Isolate* isolate, v8::FunctionCallback callback, v8::Isolate* isolate, v8::FunctionCallback callback,
const v8::Value* data_or_null, const v8::Signature* signature_or_null, const v8::Value* data_or_null, const v8::Signature* signature_or_null,
int length, v8::ConstructorBehavior constructor_behavior, int length, v8::ConstructorBehavior constructor_behavior,
v8::SideEffectType side_effect_type, void* func_ptr1, v8::SideEffectType side_effect_type, const v8::CFunction* c_functions,
const v8::CFunctionInfo* c_function_info1, void* func_ptr2, size_t c_functions_len) {
const v8::CFunctionInfo* c_function_info2) { v8::MemorySpan<const v8::CFunction> overloads{c_functions, c_functions_len};
// Support upto 2 overloads. V8 requires TypedArray to have a
// v8::Array overload.
if (func_ptr1) {
if (func_ptr2 == nullptr) {
const v8::CFunction o[] = {v8::CFunction(func_ptr1, c_function_info1)};
auto overload = v8::MemorySpan<const v8::CFunction>{o, 1};
return local_to_ptr(v8::FunctionTemplate::NewWithCFunctionOverloads(
isolate, callback, ptr_to_local(data_or_null),
ptr_to_local(signature_or_null), length, constructor_behavior,
side_effect_type, overload));
} else {
const v8::CFunction o[] = {v8::CFunction(func_ptr1, c_function_info1),
v8::CFunction(func_ptr2, c_function_info2)};
auto overload = v8::MemorySpan<const v8::CFunction>{o, 2};
return local_to_ptr(v8::FunctionTemplate::NewWithCFunctionOverloads(
isolate, callback, ptr_to_local(data_or_null),
ptr_to_local(signature_or_null), length, constructor_behavior,
side_effect_type, overload));
}
}
auto overload = v8::MemorySpan<const v8::CFunction>{};
return local_to_ptr(v8::FunctionTemplate::NewWithCFunctionOverloads( return local_to_ptr(v8::FunctionTemplate::NewWithCFunctionOverloads(
isolate, callback, ptr_to_local(data_or_null), isolate, callback, ptr_to_local(data_or_null),
ptr_to_local(signature_or_null), length, constructor_behavior, ptr_to_local(signature_or_null), length, constructor_behavior,
side_effect_type, overload)); side_effect_type, overloads));
} }
const v8::Function* v8__FunctionTemplate__GetFunction( const v8::Function* v8__FunctionTemplate__GetFunction(

View File

@ -1,4 +1,5 @@
#include <v8-cppgc.h> #include <v8-cppgc.h>
#include <v8-fast-api-calls.h>
#include <v8-message.h> #include <v8-message.h>
#include <v8-typed-array.h> #include <v8-typed-array.h>
@ -28,3 +29,6 @@ static size_t v8__TypedArray__kMaxByteLength = v8::TypedArray::kMaxByteLength;
static size_t v8__##name##__kMaxLength = v8::name::kMaxLength; static size_t v8__##name##__kMaxLength = v8::name::kMaxLength;
EACH_TYPED_ARRAY(TYPED_ARRAY_MAX_LENGTH) EACH_TYPED_ARRAY(TYPED_ARRAY_MAX_LENGTH)
#undef TYPED_ARRAY_MAX_LENGTH #undef TYPED_ARRAY_MAX_LENGTH
using v8__CFunction = v8::CFunction;
using v8__CFunctionInfo = v8::CFunctionInfo;

View File

@ -1,3 +1,4 @@
#![allow(unused)]
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(non_snake_case)] #![allow(non_snake_case)]

View File

@ -1,5 +1,6 @@
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
use crate::fast_api::CFunctionInfo;
use crate::support::intptr_t; use crate::support::intptr_t;
use crate::FunctionCallback; use crate::FunctionCallback;
use crate::IndexedDefinerCallback; use crate::IndexedDefinerCallback;
@ -33,6 +34,7 @@ pub union ExternalReference<'s> {
pub enumerator: PropertyEnumeratorCallback<'s>, pub enumerator: PropertyEnumeratorCallback<'s>,
pub message: MessageCallback, pub message: MessageCallback,
pub pointer: *mut c_void, pub pointer: *mut c_void,
pub type_info: *const CFunctionInfo,
} }
impl<'s> Debug for ExternalReference<'s> { impl<'s> Debug for ExternalReference<'s> {

View File

@ -1,205 +1,138 @@
use crate::support::Opaque; use std::ffi::c_void;
use crate::binding::*;
use crate::Isolate; use crate::Isolate;
use crate::Local; use crate::Local;
use crate::Value; use crate::Value;
use std::{
ffi::c_void,
mem::align_of,
ptr::{self, NonNull},
};
extern "C" { #[derive(Clone, Copy)]
fn v8__CTypeInfo__New(ty: CType) -> *mut CTypeInfo; #[repr(transparent)]
fn v8__CTypeInfo__New__From__Slice( pub struct CFunction(v8__CFunction);
len: usize,
tys: *const CTypeSequenceInfo, impl CFunction {
) -> *mut CTypeInfo; pub const fn new(address: *const c_void, type_info: &CFunctionInfo) -> Self {
fn v8__CTypeInfo__DELETE(this: *mut CTypeInfo); Self(v8__CFunction {
fn v8__CFunctionInfo__New( address_: address,
return_info: *const CTypeInfo, type_info_: &type_info.0,
args_len: usize, })
args_info: *const CTypeInfo, }
repr: Int64Representation,
) -> *mut CFunctionInfo; pub const fn address(&self) -> *const c_void {
fn v8__CFunctionInfo__DELETE(this: *mut CFunctionInfo); self.0.address_
}
pub const fn type_info(&self) -> &CFunctionInfo {
// SAFETY: We initialize this field with a reference. and
// the layout of CFunctionInfo is identical to v8_CFunctionInfo.
unsafe { &*(self.0.type_info_ as *const CFunctionInfo) }
}
} }
#[repr(C)] #[repr(transparent)]
#[derive(Default)] pub struct CFunctionInfo(v8__CFunctionInfo);
pub struct CFunctionInfo(Opaque);
#[repr(C)]
#[derive(Default)]
pub struct CFunction(Opaque);
impl CFunctionInfo { impl CFunctionInfo {
#[inline(always)] /// Construct a struct to hold a CFunction's type information.
pub unsafe fn new( /// |return_info| describes the function's return type.
args: *const CTypeInfo, /// |arg_info| is an array of |arg_count| CTypeInfos describing the
args_len: usize, /// arguments. Only the last argument may be of the special type
return_type: *const CTypeInfo, /// CTypeInfo::kCallbackOptionsType.
pub const fn new(
return_info: CTypeInfo,
arg_info: &[CTypeInfo],
repr: Int64Representation, repr: Int64Representation,
) -> NonNull<CFunctionInfo> { ) -> Self {
NonNull::new_unchecked(v8__CFunctionInfo__New( Self(v8__CFunctionInfo {
return_type, arg_count_: arg_info.len() as _,
args_len, arg_info_: arg_info.as_ptr() as _,
args, repr_: repr as _,
repr, return_info_: return_info.0,
)) })
} }
} }
impl Drop for CFunctionInfo { #[derive(Clone, Copy)]
fn drop(&mut self) { #[repr(u8)]
unsafe { v8__CFunctionInfo__DELETE(self) }; pub enum Int64Representation {
} /// Use numbers to represent 64 bit integers.
Number = v8_CFunctionInfo_Int64Representation_kNumber,
/// Use BigInts to represent 64 bit integers.
BigInt = v8_CFunctionInfo_Int64Representation_kBigInt,
} }
#[repr(C)] #[derive(Clone, Copy)]
#[derive(Debug)] #[repr(transparent)]
pub struct CTypeInfo(Opaque); pub struct CTypeInfo(v8_CTypeInfo);
impl CTypeInfo { impl CTypeInfo {
#[inline(always)] pub const fn new(
pub fn new(ty: CType) -> NonNull<CTypeInfo> { r#type: Type,
unsafe { NonNull::new_unchecked(v8__CTypeInfo__New(ty)) } sequence_type: SequenceType,
} flags: Flags,
) -> Self {
pub fn new_from_slice(types: &[Type]) -> NonNull<CTypeInfo> { Self(v8_CTypeInfo {
let mut structs = vec![]; flags_: flags.bits(),
sequence_type_: sequence_type as _,
for type_ in types.iter() { type_: r#type as _,
structs.push(type_.into()) })
}
unsafe {
NonNull::new_unchecked(v8__CTypeInfo__New__From__Slice(
structs.len(),
structs.as_ptr(),
))
}
} }
} }
impl Drop for CTypeInfo { #[derive(Clone, Copy)]
fn drop(&mut self) {
unsafe { v8__CTypeInfo__DELETE(self) };
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u8)] #[repr(u8)]
pub enum SequenceType { pub enum Type {
Scalar, Void = v8_CTypeInfo_Type_kVoid,
/// sequence<T> Bool = v8_CTypeInfo_Type_kBool,
IsSequence, Uint8 = v8_CTypeInfo_Type_kUint8,
/// TypedArray of T or any ArrayBufferView if T is void Int32 = v8_CTypeInfo_Type_kInt32,
IsTypedArray, Uint32 = v8_CTypeInfo_Type_kUint32,
/// ArrayBuffer Int64 = v8_CTypeInfo_Type_kInt64,
IsArrayBuffer, Uint64 = v8_CTypeInfo_Type_kUint64,
} Float32 = v8_CTypeInfo_Type_kFloat32,
Float64 = v8_CTypeInfo_Type_kFloat64,
#[derive(Clone, Copy, Debug)] Pointer = v8_CTypeInfo_Type_kPointer,
#[repr(u8)] V8Value = v8_CTypeInfo_Type_kV8Value,
#[non_exhaustive] SeqOneByteString = v8_CTypeInfo_Type_kSeqOneByteString,
pub enum CType { ApiObject = v8_CTypeInfo_Type_kApiObject,
Void = 0, Any = v8_CTypeInfo_Type_kAny,
Bool,
Uint8,
Int32,
Uint32,
Int64,
Uint64,
Float32,
Float64,
Pointer,
V8Value,
SeqOneByteString,
// https://github.com/v8/v8/blob/492a32943bc34a527f42df2ae15a77154b16cc84/include/v8-fast-api-calls.h#L264-L267
// kCallbackOptionsType is not part of the Type enum
// because it is only used internally. Use value 255 that is larger
// than any valid Type enum.
CallbackOptions = 255, CallbackOptions = 255,
} }
#[derive(Clone, Copy, Debug)] impl Type {
#[non_exhaustive] pub const fn scalar(self) -> CTypeInfo {
pub enum Type { CTypeInfo::new(self, SequenceType::Scalar, Flags::empty())
Void, }
Bool,
Uint8,
Int32,
Uint32,
Int64,
Uint64,
Float32,
Float64,
Pointer,
V8Value,
SeqOneByteString,
CallbackOptions,
Sequence(CType),
TypedArray(CType),
ArrayBuffer(CType),
}
impl From<&Type> for CType { pub const fn typed_array(self) -> CTypeInfo {
fn from(ty: &Type) -> CType { CTypeInfo::new(self, SequenceType::IsTypedArray, Flags::empty())
match ty {
Type::Void => CType::Void,
Type::Bool => CType::Bool,
Type::Uint8 => CType::Uint8,
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::Pointer => CType::Pointer,
Type::V8Value => CType::V8Value,
Type::SeqOneByteString => CType::SeqOneByteString,
Type::CallbackOptions => CType::CallbackOptions,
Type::Sequence(ty) => *ty,
Type::TypedArray(ty) => *ty,
Type::ArrayBuffer(ty) => *ty,
}
} }
} }
impl From<&Type> for SequenceType { #[derive(Clone, Copy)]
fn from(ty: &Type) -> SequenceType { #[repr(u8)]
match ty { pub enum SequenceType {
Type::Sequence(_) => SequenceType::IsSequence, Scalar = v8_CTypeInfo_SequenceType_kScalar,
Type::TypedArray(_) => SequenceType::IsTypedArray, /// sequence<T>
Type::ArrayBuffer(_) => SequenceType::IsArrayBuffer, IsSequence = v8_CTypeInfo_SequenceType_kIsSequence,
_ => SequenceType::Scalar, /// TypedArray of T or any ArrayBufferView if T is void
} IsTypedArray = v8_CTypeInfo_SequenceType_kIsTypedArray,
/// ArrayBuffer
IsArrayBuffer = v8_CTypeInfo_SequenceType_kIsArrayBuffer,
}
bitflags::bitflags! {
pub struct Flags: u8 {
/// Must be an ArrayBuffer or TypedArray
const AllowShared = v8_CTypeInfo_Flags_kAllowSharedBit;
/// T must be integral
const EnforceRange = v8_CTypeInfo_Flags_kEnforceRangeBit;
/// T must be integral
const Clamp = v8_CTypeInfo_Flags_kClampBit;
/// T must be float or double
const IsRestricted = v8_CTypeInfo_Flags_kIsRestrictedBit;
} }
} }
impl From<&Type> for CTypeSequenceInfo {
fn from(ty: &Type) -> CTypeSequenceInfo {
CTypeSequenceInfo {
c_type: ty.into(),
sequence_type: ty.into(),
}
}
}
#[repr(C)]
struct CTypeSequenceInfo {
c_type: CType,
sequence_type: SequenceType,
}
#[repr(C)]
pub union FastApiCallbackData<'a> {
/// `data_ptr` allows for default constructing FastApiCallbackOptions.
pub data_ptr: *mut c_void,
/// The `data` passed to the FunctionTemplate constructor, or `undefined`.
pub data: Local<'a, Value>,
}
/// A struct which may be passed to a fast call callback, like so /// A struct which may be passed to a fast call callback, like so
/// ```c /// ```c
/// void FastMethodWithOptions(int param, FastApiCallbackOptions& options); /// void FastMethodWithOptions(int param, FastApiCallbackOptions& options);
@ -217,7 +150,8 @@ pub struct FastApiCallbackOptions<'a> {
/// fallback conditions are checked, because otherwise executing the slow /// fallback conditions are checked, because otherwise executing the slow
/// callback might produce visible side-effects twice. /// callback might produce visible side-effects twice.
pub fallback: bool, pub fallback: bool,
pub data: FastApiCallbackData<'a>, /// The `data` passed to the FunctionTemplate constructor, or `undefined`.
pub data: Local<'a, Value>,
/// When called from WebAssembly, a view of the calling module's memory. /// When called from WebAssembly, a view of the calling module's memory.
pub wasm_memory: *const FastApiTypedArray<u8>, pub wasm_memory: *const FastApiTypedArray<u8>,
} }
@ -235,8 +169,45 @@ pub struct FastApiTypedArray<T: Default> {
data: *mut T, data: *mut T,
} }
impl<T: Default> FastApiTypedArray<T> {
/// Performs an unaligned-safe read of T from the underlying data.
#[inline(always)]
pub const fn get(&self, index: usize) -> T {
debug_assert!(index < self.length);
// SAFETY: src is valid for reads, and is a valid value for T
unsafe { std::ptr::read_unaligned(self.data.add(index)) }
}
/// Returns a slice pointing to the underlying data if safe to do so.
#[inline(always)]
pub fn get_storage_if_aligned(&self) -> Option<&mut [T]> {
// V8 may provide an invalid or null pointer when length is zero, so we just
// ignore that value completely and create an empty slice in this case.
if self.length == 0 {
return Some(&mut []);
}
// Ensure that we never return an unaligned or null buffer
if self.data.is_null() || (self.data as usize) % align_of::<T>() != 0 {
return None;
}
Some(unsafe { std::slice::from_raw_parts_mut(self.data, self.length) })
}
}
/// Any TypedArray. It uses kTypedArrayBit with base type void
/// Overloaded args of ArrayBufferView and TypedArray are not supported
/// (for now) because the generic “any” ArrayBufferView doesnt have its
/// own instance type. It could be supported if we specify that
/// TypedArray<T> always has precedence over the generic ArrayBufferView,
/// but this complicates overload resolution.
#[repr(C)]
pub struct FastApiArrayBufferView {
pub data: *mut c_void,
pub byte_length: usize,
}
// FastApiOneByteString is an alias for SeqOneByteString and the type is widely used in deno_core. // FastApiOneByteString is an alias for SeqOneByteString and the type is widely used in deno_core.
#[allow(dead_code)] #[allow(unused)]
#[repr(C)] #[repr(C)]
pub struct FastApiOneByteString { pub struct FastApiOneByteString {
data: *const u8, data: *const u8,
@ -256,88 +227,3 @@ impl FastApiOneByteString {
unsafe { std::slice::from_raw_parts(self.data, self.length as usize) } unsafe { std::slice::from_raw_parts(self.data, self.length as usize) }
} }
} }
impl<T: Default> FastApiTypedArray<T> {
/// Performs an unaligned-safe read of T from the underlying data.
#[inline(always)]
pub const fn get(&self, index: usize) -> T {
debug_assert!(index < self.length);
// SAFETY: src is valid for reads, and is a valid value for T
unsafe { ptr::read_unaligned(self.data.add(index)) }
}
/// Given a pointer to a `FastApiTypedArray`, returns a slice pointing to the
/// data if safe to do so.
///
/// # Safety
///
/// The pointer must not be null and the caller must choose a lifetime that is
/// safe.
#[inline(always)]
pub unsafe fn get_storage_from_pointer_if_aligned<'a>(
ptr: *mut Self,
) -> Option<&'a mut [T]> {
debug_assert!(!ptr.is_null());
let self_ref = ptr.as_mut().unwrap_unchecked();
self_ref.get_storage_if_aligned()
}
/// Returns a slice pointing to the underlying data if safe to do so.
#[inline(always)]
pub fn get_storage_if_aligned(&self) -> Option<&mut [T]> {
// V8 may provide an invalid or null pointer when length is zero, so we just
// ignore that value completely and create an empty slice in this case.
if self.length == 0 {
return Some(&mut []);
}
// Ensure that we never return an unaligned or null buffer
if self.data.is_null() || (self.data as usize) % align_of::<T>() != 0 {
return None;
}
Some(unsafe { std::slice::from_raw_parts_mut(self.data, self.length) })
}
}
#[derive(Copy, Clone)]
pub struct FastFunction {
pub args: &'static [Type],
pub function: *const c_void,
pub repr: Int64Representation,
pub return_type: CType,
}
impl FastFunction {
#[inline(always)]
pub const fn new(
args: &'static [Type],
return_type: CType,
function: *const c_void,
) -> Self {
Self {
args,
function,
repr: Int64Representation::Number,
return_type,
}
}
pub const fn new_with_bigint(
args: &'static [Type],
return_type: CType,
function: *const c_void,
) -> Self {
Self {
args,
function,
repr: Int64Representation::BigInt,
return_type,
}
}
}
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
pub enum Int64Representation {
Number = 0,
BigInt = 1,
}

View File

@ -3,9 +3,7 @@ use crate::data::FunctionTemplate;
use crate::data::Name; use crate::data::Name;
use crate::data::ObjectTemplate; use crate::data::ObjectTemplate;
use crate::data::Template; use crate::data::Template;
use crate::fast_api::CFunctionInfo; use crate::fast_api::CFunction;
use crate::fast_api::CTypeInfo;
use crate::fast_api::FastFunction;
use crate::isolate::Isolate; use crate::isolate::Isolate;
use crate::support::int; use crate::support::int;
use crate::support::MapFnTo; use crate::support::MapFnTo;
@ -37,7 +35,6 @@ use crate::Signature;
use crate::String; use crate::String;
use crate::Value; use crate::Value;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::ffi::c_void;
use std::ptr::null; use std::ptr::null;
extern "C" { extern "C" {
@ -66,10 +63,8 @@ extern "C" {
length: i32, length: i32,
constructor_behavior: ConstructorBehavior, constructor_behavior: ConstructorBehavior,
side_effect_type: SideEffectType, side_effect_type: SideEffectType,
func_ptr1: *const c_void, c_functions: *const CFunction,
c_function1: *const CFunctionInfo, c_functions_len: usize,
func_ptr2: *const c_void,
c_function2: *const CFunctionInfo,
) -> *const FunctionTemplate; ) -> *const FunctionTemplate;
fn v8__FunctionTemplate__GetFunction( fn v8__FunctionTemplate__GetFunction(
this: *const FunctionTemplate, this: *const FunctionTemplate,
@ -700,9 +695,7 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> {
self.constructor_behavior, self.constructor_behavior,
self.side_effect_type, self.side_effect_type,
null(), null(),
null(), 0,
null(),
null(),
) )
}) })
} }
@ -717,47 +710,8 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> {
pub fn build_fast( pub fn build_fast(
self, self,
scope: &mut HandleScope<'s, ()>, scope: &mut HandleScope<'s, ()>,
overload1: &FastFunction, overloads: &[CFunction],
c_fn_info1: Option<*const CFunctionInfo>,
overload2: Option<&FastFunction>,
c_fn_info2: Option<*const CFunctionInfo>,
) -> Local<'s, FunctionTemplate> { ) -> Local<'s, FunctionTemplate> {
let c_fn1 = if let Some(fn_info) = c_fn_info1 {
fn_info
} else {
let args = CTypeInfo::new_from_slice(overload1.args);
let ret = CTypeInfo::new(overload1.return_type);
let fn_info = unsafe {
CFunctionInfo::new(
args.as_ptr(),
overload1.args.len(),
ret.as_ptr(),
overload1.repr,
)
};
fn_info.as_ptr()
};
let c_fn2 = if let Some(overload2) = overload2 {
if let Some(fn_info) = c_fn_info2 {
fn_info
} else {
let args = CTypeInfo::new_from_slice(overload2.args);
let ret = CTypeInfo::new(overload2.return_type);
let fn_info = unsafe {
CFunctionInfo::new(
args.as_ptr(),
overload2.args.len(),
ret.as_ptr(),
overload2.repr,
)
};
fn_info.as_ptr()
}
} else {
null()
};
unsafe { unsafe {
scope.cast_local(|sd| { scope.cast_local(|sd| {
v8__FunctionTemplate__New( v8__FunctionTemplate__New(
@ -768,10 +722,8 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> {
self.length, self.length,
ConstructorBehavior::Throw, ConstructorBehavior::Throw,
self.side_effect_type, self.side_effect_type,
overload1.function, overloads.as_ptr(),
c_fn1, overloads.len(),
overload2.map_or(null(), |f| f.function),
c_fn2,
) )
}) })
} }

View File

@ -15,10 +15,9 @@ use std::ptr::{addr_of, addr_of_mut, NonNull};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use v8::fast_api::Type::*; use v8::fast_api;
use v8::fast_api::{CType, FastApiTypedArray};
use v8::inspector::ChannelBase; use v8::inspector::ChannelBase;
use v8::{fast_api, AccessorConfiguration}; use v8::AccessorConfiguration;
// TODO(piscisaureus): Ideally there would be no need to import this trait. // TODO(piscisaureus): Ideally there would be no need to import this trait.
use v8::MapFnTo; use v8::MapFnTo;
@ -10456,10 +10455,17 @@ fn test_fast_calls() {
a + b a + b
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, Uint32, Uint32],
fast_api::CType::Uint32,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Uint32.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::Uint32.scalar(),
fast_api::Type::Uint32.scalar(),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -10481,8 +10487,8 @@ fn test_fast_calls() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -10508,16 +10514,11 @@ fn test_fast_calls_empty_buffer() {
static mut WHO: &str = "none"; static mut WHO: &str = "none";
unsafe fn fast_fn( unsafe fn fast_fn(
_recv: v8::Local<v8::Object>, _recv: v8::Local<v8::Object>,
buffer: *mut FastApiTypedArray<u8>, buffer: *mut fast_api::FastApiTypedArray<u8>,
) { ) {
assert_eq!(WHO, "slow"); assert_eq!(WHO, "slow");
WHO = "fast"; WHO = "fast";
assert_eq!( assert_eq!(0, (*buffer).get_storage_if_aligned().unwrap().len());
0,
FastApiTypedArray::get_storage_from_pointer_if_aligned(buffer)
.unwrap()
.len()
);
} }
fn slow_fn( fn slow_fn(
@ -10530,10 +10531,20 @@ fn test_fast_calls_empty_buffer() {
} }
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, TypedArray(CType::Uint8)],
fast_api::CType::Void,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Void.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::CTypeInfo::new(
fast_api::Type::Uint8,
fast_api::SequenceType::IsTypedArray,
fast_api::Flags::empty(),
),
],
fast_api::Int64Representation::Number,
),
); );
let _setup_guard = setup::parallel_test(); let _setup_guard = setup::parallel_test();
@ -10544,8 +10555,8 @@ fn test_fast_calls_empty_buffer() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -10575,10 +10586,22 @@ fn test_fast_calls_sequence() {
a + b + array.length() a + b + array.length()
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, Uint32, Uint32, Sequence(fast_api::CType::Void)],
fast_api::CType::Uint32,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Uint32.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::Uint32.scalar(),
fast_api::Type::Uint32.scalar(),
fast_api::CTypeInfo::new(
fast_api::Type::Void,
fast_api::SequenceType::IsSequence,
fast_api::Flags::empty(),
),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -10598,8 +10621,8 @@ fn test_fast_calls_sequence() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -10634,10 +10657,22 @@ fn test_fast_calls_arraybuffer() {
a + b + unsafe { &*data }.get(0) a + b + unsafe { &*data }.get(0)
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, Uint32, Uint32, TypedArray(fast_api::CType::Uint32)],
fast_api::CType::Uint32,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Uint32.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::Uint32.scalar(),
fast_api::Type::Uint32.scalar(),
fast_api::CTypeInfo::new(
fast_api::Type::Uint32,
fast_api::SequenceType::IsTypedArray,
fast_api::Flags::empty(),
),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -10657,8 +10692,8 @@ fn test_fast_calls_arraybuffer() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -10698,10 +10733,20 @@ fn test_fast_calls_typedarray() {
sum.into() sum.into()
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, TypedArray(fast_api::CType::Uint8)],
fast_api::CType::Uint32,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Uint32.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::CTypeInfo::new(
fast_api::Type::Uint8,
fast_api::SequenceType::IsTypedArray,
fast_api::Flags::empty(),
),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -10721,8 +10766,8 @@ fn test_fast_calls_typedarray() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -10765,10 +10810,13 @@ fn test_fast_calls_reciever() {
} }
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value],
fast_api::CType::Uint32,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Uint32.scalar(),
&[fast_api::Type::V8Value.scalar()],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -10802,8 +10850,8 @@ fn test_fast_calls_reciever() {
embedder_obj as _, embedder_obj as _,
); );
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "method").unwrap(); let name = v8::String::new(scope, "method").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -10848,16 +10896,36 @@ fn test_fast_calls_overload() {
assert_eq!(data.length(), 2); assert_eq!(data.length(), 2);
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, TypedArray(CType::Uint32)],
CType::Void,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Void.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::CTypeInfo::new(
fast_api::Type::Uint32,
fast_api::SequenceType::IsTypedArray,
fast_api::Flags::empty(),
),
],
fast_api::Int64Representation::Number,
),
); );
const FAST_TEST2: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST2: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, Sequence(CType::Void)],
CType::Void,
fast_fn2 as _, fast_fn2 as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Void.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::CTypeInfo::new(
fast_api::Type::Void,
fast_api::SequenceType::IsSequence,
fast_api::Flags::empty(),
),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -10877,13 +10945,8 @@ fn test_fast_calls_overload() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn).build_fast( let template = v8::FunctionTemplate::builder(slow_fn)
scope, .build_fast(scope, &[FAST_TEST, FAST_TEST2]);
&FAST_TEST,
None,
Some(&FAST_TEST2),
None,
);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -10928,10 +10991,16 @@ fn test_fast_calls_callback_options_fallback() {
} }
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, CallbackOptions],
CType::Void,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Void.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::CallbackOptions.scalar(),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -10951,8 +11020,8 @@ fn test_fast_calls_callback_options_fallback() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -10986,20 +11055,26 @@ fn test_fast_calls_callback_options_data() {
options: *mut fast_api::FastApiCallbackOptions, options: *mut fast_api::FastApiCallbackOptions,
) { ) {
let options = &mut *options; let options = &mut *options;
if !options.data.data.is_external() { if !options.data.is_external() {
options.fallback = true; options.fallback = true;
return; return;
} }
let data = v8::Local::<v8::External>::cast_unchecked(options.data.data); let data = v8::Local::<v8::External>::cast_unchecked(options.data);
let data = &mut *(data.value() as *mut bool); let data = &mut *(data.value() as *mut bool);
*data = true; *data = true;
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, CallbackOptions],
CType::Void,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Void.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::CallbackOptions.scalar(),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -11022,7 +11097,7 @@ fn test_fast_calls_callback_options_data() {
let template = v8::FunctionTemplate::builder(slow_fn) let template = v8::FunctionTemplate::builder(slow_fn)
.data(external.into()) .data(external.into())
.build_fast(scope, &FAST_TEST, None, None, None); .build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -11103,10 +11178,16 @@ fn test_fast_calls_onebytestring() {
data.len() as u32 data.len() as u32
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, SeqOneByteString],
CType::Uint32,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Uint32.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::SeqOneByteString.scalar(),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -11125,8 +11206,8 @@ fn test_fast_calls_onebytestring() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();
@ -11162,18 +11243,31 @@ fn test_fast_calls_i64representation() {
a * b a * b
} }
const FAST_TEST_NUMBER: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST_NUMBER: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, Uint64, Uint64],
CType::Uint64,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Uint64.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::Uint64.scalar(),
fast_api::Type::Uint64.scalar(),
],
fast_api::Int64Representation::Number,
),
); );
const FAST_TEST_BIGINT: fast_api::FastFunction = const FAST_TEST_BIGINT: fast_api::CFunction = fast_api::CFunction::new(
fast_api::FastFunction::new_with_bigint( fast_fn as _,
&[V8Value, Uint64, Uint64], &fast_api::CFunctionInfo::new(
CType::Uint64, fast_api::Type::Uint64.scalar(),
fast_fn as _, &[
); fast_api::Type::V8Value.scalar(),
fast_api::Type::Uint64.scalar(),
fast_api::Type::Uint64.scalar(),
],
fast_api::Int64Representation::BigInt,
),
);
fn slow_fn( fn slow_fn(
_: &mut v8::HandleScope, _: &mut v8::HandleScope,
@ -11191,20 +11285,10 @@ fn test_fast_calls_i64representation() {
let global = context.global(scope); let global = context.global(scope);
let template_number = v8::FunctionTemplate::builder(slow_fn).build_fast( let template_number = v8::FunctionTemplate::builder(slow_fn)
scope, .build_fast(scope, &[FAST_TEST_NUMBER]);
&FAST_TEST_NUMBER, let template_bigint = v8::FunctionTemplate::builder(slow_fn)
None, .build_fast(scope, &[FAST_TEST_BIGINT]);
None,
None,
);
let template_bigint = v8::FunctionTemplate::builder(slow_fn).build_fast(
scope,
&FAST_TEST_BIGINT,
None,
None,
None,
);
let name_number = v8::String::new(scope, "func_number").unwrap(); let name_number = v8::String::new(scope, "func_number").unwrap();
let name_bigint = v8::String::new(scope, "func_bigint").unwrap(); let name_bigint = v8::String::new(scope, "func_bigint").unwrap();
@ -11338,10 +11422,16 @@ fn test_fast_calls_pointer() {
std::ptr::null_mut() std::ptr::null_mut()
} }
const FAST_TEST: fast_api::FastFunction = fast_api::FastFunction::new( const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
&[V8Value, Pointer],
fast_api::CType::Pointer,
fast_fn as _, fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Pointer.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::Pointer.scalar(),
],
fast_api::Int64Representation::Number,
),
); );
fn slow_fn( fn slow_fn(
@ -11363,8 +11453,8 @@ fn test_fast_calls_pointer() {
let global = context.global(scope); let global = context.global(scope);
let template = v8::FunctionTemplate::builder(slow_fn) let template =
.build_fast(scope, &FAST_TEST, None, None, None); v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap(); let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap(); let value = template.get_function(scope).unwrap();