2022-01-20 09:27:25 -05:00
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
2021-08-06 17:28:10 -04:00
2022-06-20 07:06:04 -04:00
use core ::ptr ::NonNull ;
use deno_core ::anyhow ::anyhow ;
2022-01-05 02:25:31 -05:00
use deno_core ::error ::generic_error ;
2021-12-15 09:41:49 -05:00
use deno_core ::error ::range_error ;
2022-01-05 02:25:31 -05:00
use deno_core ::error ::type_error ;
2021-08-06 17:28:10 -04:00
use deno_core ::error ::AnyError ;
2022-06-28 05:23:36 -04:00
use deno_core ::futures ::channel ::mpsc ;
2022-06-20 07:06:04 -04:00
use deno_core ::futures ::Future ;
2021-08-06 17:28:10 -04:00
use deno_core ::include_js_files ;
2022-03-14 13:44:15 -04:00
use deno_core ::op ;
2021-08-06 17:28:10 -04:00
use deno_core ::serde_json ::json ;
use deno_core ::serde_json ::Value ;
2022-06-20 07:06:04 -04:00
use deno_core ::serde_v8 ;
use deno_core ::v8 ;
2022-07-24 09:08:13 -04:00
use deno_core ::v8 ::fast_api ;
2021-08-06 17:28:10 -04:00
use deno_core ::Extension ;
use deno_core ::OpState ;
use deno_core ::Resource ;
use deno_core ::ResourceId ;
2021-10-05 18:27:05 -04:00
use deno_core ::ZeroCopyBuf ;
2021-08-06 17:28:10 -04:00
use dlopen ::raw ::Library ;
use libffi ::middle ::Arg ;
2022-06-20 07:06:04 -04:00
use libffi ::middle ::Cif ;
use libffi ::raw ::* ;
2021-08-06 17:28:10 -04:00
use serde ::Deserialize ;
2021-12-15 09:41:49 -05:00
use serde ::Serialize ;
2021-08-06 17:28:10 -04:00
use std ::borrow ::Cow ;
2021-10-05 08:50:00 -04:00
use std ::cell ::RefCell ;
2021-08-06 17:28:10 -04:00
use std ::collections ::HashMap ;
use std ::ffi ::c_void ;
2021-12-15 09:41:49 -05:00
use std ::ffi ::CStr ;
2022-07-24 09:08:13 -04:00
use std ::mem ::size_of ;
2021-12-17 04:42:45 -05:00
use std ::os ::raw ::c_char ;
2022-07-24 09:08:13 -04:00
use std ::os ::raw ::c_short ;
2021-10-13 13:04:44 -04:00
use std ::path ::Path ;
use std ::path ::PathBuf ;
2021-12-15 09:41:49 -05:00
use std ::ptr ;
2021-08-06 17:28:10 -04:00
use std ::rc ::Rc ;
2022-07-24 09:08:13 -04:00
use std ::sync ::mpsc ::sync_channel ;
2021-08-06 17:28:10 -04:00
2022-07-11 21:03:05 -04:00
#[ cfg(not(target_os = " windows " )) ]
mod jit_trampoline ;
#[ cfg(not(target_os = " windows " )) ]
mod tcc ;
2022-07-24 09:08:13 -04:00
#[ cfg(not(target_pointer_width = " 64 " )) ]
compile_error! ( " platform not supported " ) ;
// Assert assumptions made in `prelude.h`
const _ : ( ) = {
assert! ( size_of ::< c_char > ( ) = = 1 ) ;
assert! ( size_of ::< c_short > ( ) = = 2 ) ;
assert! ( size_of ::< * const ( ) > ( ) = = 8 ) ;
} ;
2022-06-20 07:06:04 -04:00
thread_local! {
2022-06-28 05:23:36 -04:00
static LOCAL_ISOLATE_POINTER : RefCell < * const v8 ::Isolate > = RefCell ::new ( ptr ::null ( ) ) ;
2022-06-20 07:06:04 -04:00
}
2022-07-24 06:41:11 -04:00
const MAX_SAFE_INTEGER : isize = 9007199254740991 ;
const MIN_SAFE_INTEGER : isize = - 9007199254740991 ;
2021-08-06 17:28:10 -04:00
pub struct Unstable ( pub bool ) ;
fn check_unstable ( state : & OpState , api_name : & str ) {
let unstable = state . borrow ::< Unstable > ( ) ;
if ! unstable . 0 {
eprintln! (
" Unstable API '{}'. The --unstable flag must be provided. " ,
api_name
) ;
std ::process ::exit ( 70 ) ;
}
}
2022-03-25 07:29:54 -04:00
pub fn check_unstable2 ( state : & Rc < RefCell < OpState > > , api_name : & str ) {
let state = state . borrow ( ) ;
check_unstable ( & state , api_name )
}
2021-08-06 17:28:10 -04:00
pub trait FfiPermissions {
2021-12-15 09:41:49 -05:00
fn check ( & mut self , path : Option < & Path > ) -> Result < ( ) , AnyError > ;
2021-08-06 17:28:10 -04:00
}
2021-10-05 08:50:00 -04:00
#[ derive(Clone) ]
2021-08-06 17:28:10 -04:00
struct Symbol {
cif : libffi ::middle ::Cif ,
ptr : libffi ::middle ::CodePtr ,
parameter_types : Vec < NativeType > ,
result_type : NativeType ,
2022-07-11 21:03:05 -04:00
// This is dead code only on Windows
#[ allow(dead_code) ]
2022-07-09 09:11:07 -04:00
can_callback : bool ,
2021-08-06 17:28:10 -04:00
}
2022-01-15 01:10:12 -05:00
#[ allow(clippy::non_send_fields_in_send_ty) ]
2022-08-21 13:31:14 -04:00
// SAFETY: unsafe trait must have unsafe implementation
2021-10-05 08:50:00 -04:00
unsafe impl Send for Symbol { }
2022-08-21 13:31:14 -04:00
// SAFETY: unsafe trait must have unsafe implementation
2021-10-05 08:50:00 -04:00
unsafe impl Sync for Symbol { }
2022-06-20 07:06:04 -04:00
#[ derive(Clone) ]
struct PtrSymbol {
cif : libffi ::middle ::Cif ,
ptr : libffi ::middle ::CodePtr ,
}
impl PtrSymbol {
2022-07-24 06:41:11 -04:00
fn new ( fn_ptr : usize , def : & ForeignFunction ) -> Self {
2022-06-20 07:06:04 -04:00
let ptr = libffi ::middle ::CodePtr ::from_ptr ( fn_ptr as _ ) ;
let cif = libffi ::middle ::Cif ::new (
def
. parameters
. clone ( )
. into_iter ( )
. map ( libffi ::middle ::Type ::from ) ,
def . result . into ( ) ,
) ;
Self { cif , ptr }
}
}
#[ allow(clippy::non_send_fields_in_send_ty) ]
2022-08-21 13:31:14 -04:00
// SAFETY: unsafe trait must have unsafe implementation
2022-06-20 07:06:04 -04:00
unsafe impl Send for PtrSymbol { }
2022-08-21 13:31:14 -04:00
// SAFETY: unsafe trait must have unsafe implementation
2022-06-20 07:06:04 -04:00
unsafe impl Sync for PtrSymbol { }
2021-08-06 17:28:10 -04:00
struct DynamicLibraryResource {
lib : Library ,
2022-06-29 04:13:33 -04:00
symbols : HashMap < String , Box < Symbol > > ,
2021-08-06 17:28:10 -04:00
}
impl Resource for DynamicLibraryResource {
fn name ( & self ) -> Cow < str > {
" dynamicLibrary " . into ( )
}
fn close ( self : Rc < Self > ) {
drop ( self )
}
}
impl DynamicLibraryResource {
2022-02-18 07:21:19 -05:00
fn get_static ( & self , symbol : String ) -> Result < * const c_void , AnyError > {
// By default, Err returned by this function does not tell
// which symbol wasn't exported. So we'll modify the error
// message to include the name of symbol.
2022-06-25 18:13:24 -04:00
//
// SAFETY: The obtained T symbol is the size of a pointer.
2022-02-18 07:21:19 -05:00
match unsafe { self . lib . symbol ::< * const c_void > ( & symbol ) } {
Ok ( value ) = > Ok ( Ok ( value ) ) ,
Err ( err ) = > Err ( generic_error ( format! (
" Failed to register symbol {}: {} " ,
symbol , err
) ) ) ,
} ?
}
2021-08-06 17:28:10 -04:00
}
2022-06-28 05:23:36 -04:00
type PendingFfiAsyncWork = Box < dyn FnOnce ( ) > ;
struct FfiState {
async_work_sender : mpsc ::UnboundedSender < PendingFfiAsyncWork > ,
async_work_receiver : mpsc ::UnboundedReceiver < PendingFfiAsyncWork > ,
active_refed_functions : usize ,
}
2021-08-06 17:28:10 -04:00
pub fn init < P : FfiPermissions + 'static > ( unstable : bool ) -> Extension {
Extension ::builder ( )
. js ( include_js_files! (
2021-08-11 06:27:05 -04:00
prefix " deno:ext/ffi " ,
2021-08-06 17:28:10 -04:00
" 00_ffi.js " ,
) )
. ops ( vec! [
2022-03-14 13:44:15 -04:00
op_ffi_load ::decl ::< P > ( ) ,
op_ffi_get_static ::decl ( ) ,
op_ffi_call_nonblocking ::decl ( ) ,
2022-03-25 07:29:54 -04:00
op_ffi_call_ptr ::decl ::< P > ( ) ,
op_ffi_call_ptr_nonblocking ::decl ::< P > ( ) ,
2022-03-14 13:44:15 -04:00
op_ffi_ptr_of ::decl ::< P > ( ) ,
2022-07-23 13:11:06 -04:00
op_ffi_get_buf ::decl ::< P > ( ) ,
2022-03-14 13:44:15 -04:00
op_ffi_buf_copy_into ::decl ::< P > ( ) ,
op_ffi_cstr_read ::decl ::< P > ( ) ,
op_ffi_read_u8 ::decl ::< P > ( ) ,
op_ffi_read_i8 ::decl ::< P > ( ) ,
op_ffi_read_u16 ::decl ::< P > ( ) ,
op_ffi_read_i16 ::decl ::< P > ( ) ,
op_ffi_read_u32 ::decl ::< P > ( ) ,
op_ffi_read_i32 ::decl ::< P > ( ) ,
op_ffi_read_u64 ::decl ::< P > ( ) ,
2022-07-24 06:41:11 -04:00
op_ffi_read_i64 ::decl ::< P > ( ) ,
2022-03-14 13:44:15 -04:00
op_ffi_read_f32 ::decl ::< P > ( ) ,
op_ffi_read_f64 ::decl ::< P > ( ) ,
2022-06-20 07:06:04 -04:00
op_ffi_unsafe_callback_create ::decl ::< P > ( ) ,
2022-06-28 05:23:36 -04:00
op_ffi_unsafe_callback_ref ::decl ( ) ,
2021-08-06 17:28:10 -04:00
] )
2022-06-28 05:23:36 -04:00
. event_loop_middleware ( | op_state_rc , _cx | {
// FFI callbacks coming in from other threads will call in and get queued.
let mut maybe_scheduling = false ;
let mut work_items : Vec < PendingFfiAsyncWork > = vec! [ ] ;
{
let mut op_state = op_state_rc . borrow_mut ( ) ;
let ffi_state = op_state . borrow_mut ::< FfiState > ( ) ;
while let Ok ( Some ( async_work_fut ) ) =
ffi_state . async_work_receiver . try_next ( )
{
// Move received items to a temporary vector so that we can drop the `op_state` borrow before we do the work.
work_items . push ( async_work_fut ) ;
maybe_scheduling = true ;
}
if ffi_state . active_refed_functions > 0 {
maybe_scheduling = true ;
}
drop ( op_state ) ;
}
while let Some ( async_work_fut ) = work_items . pop ( ) {
async_work_fut ( ) ;
}
maybe_scheduling
} )
2021-08-06 17:28:10 -04:00
. state ( move | state | {
// Stolen from deno_webgpu, is there a better option?
state . put ( Unstable ( unstable ) ) ;
2022-06-28 05:23:36 -04:00
let ( async_work_sender , async_work_receiver ) =
mpsc ::unbounded ::< PendingFfiAsyncWork > ( ) ;
state . put ( FfiState {
active_refed_functions : 0 ,
async_work_receiver ,
async_work_sender ,
} ) ;
2021-08-06 17:28:10 -04:00
Ok ( ( ) )
} )
. build ( )
}
2022-06-20 07:06:04 -04:00
/// Defines the accepted types that can be used as
/// parameters and return values in FFI.
2021-08-06 17:28:10 -04:00
#[ derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq) ]
#[ serde(rename_all = " lowercase " ) ]
enum NativeType {
Void ,
U8 ,
I8 ,
U16 ,
I16 ,
U32 ,
I32 ,
U64 ,
I64 ,
USize ,
ISize ,
F32 ,
F64 ,
2021-12-15 09:41:49 -05:00
Pointer ,
2022-08-22 23:46:43 -04:00
Buffer ,
2022-06-20 22:50:33 -04:00
Function ,
2021-08-06 17:28:10 -04:00
}
impl From < NativeType > for libffi ::middle ::Type {
fn from ( native_type : NativeType ) -> Self {
match native_type {
NativeType ::Void = > libffi ::middle ::Type ::void ( ) ,
NativeType ::U8 = > libffi ::middle ::Type ::u8 ( ) ,
NativeType ::I8 = > libffi ::middle ::Type ::i8 ( ) ,
NativeType ::U16 = > libffi ::middle ::Type ::u16 ( ) ,
NativeType ::I16 = > libffi ::middle ::Type ::i16 ( ) ,
NativeType ::U32 = > libffi ::middle ::Type ::u32 ( ) ,
NativeType ::I32 = > libffi ::middle ::Type ::i32 ( ) ,
NativeType ::U64 = > libffi ::middle ::Type ::u64 ( ) ,
NativeType ::I64 = > libffi ::middle ::Type ::i64 ( ) ,
NativeType ::USize = > libffi ::middle ::Type ::usize ( ) ,
NativeType ::ISize = > libffi ::middle ::Type ::isize ( ) ,
NativeType ::F32 = > libffi ::middle ::Type ::f32 ( ) ,
NativeType ::F64 = > libffi ::middle ::Type ::f64 ( ) ,
2022-08-22 23:46:43 -04:00
NativeType ::Pointer | NativeType ::Buffer | NativeType ::Function = > {
libffi ::middle ::Type ::pointer ( )
}
2021-08-06 17:28:10 -04:00
}
}
}
2022-06-20 07:06:04 -04:00
/// Intermediate format for easy translation from NativeType + V8 value
/// to libffi argument types.
2021-08-06 17:28:10 -04:00
#[ repr(C) ]
union NativeValue {
void_value : ( ) ,
u8_value : u8 ,
i8_value : i8 ,
u16_value : u16 ,
i16_value : i16 ,
u32_value : u32 ,
i32_value : i32 ,
u64_value : u64 ,
i64_value : i64 ,
usize_value : usize ,
isize_value : isize ,
f32_value : f32 ,
f64_value : f64 ,
2021-12-15 09:41:49 -05:00
pointer : * const u8 ,
2021-08-06 17:28:10 -04:00
}
impl NativeValue {
unsafe fn as_arg ( & self , native_type : NativeType ) -> Arg {
match native_type {
2022-06-20 07:06:04 -04:00
NativeType ::Void = > unreachable! ( ) ,
2021-08-06 17:28:10 -04:00
NativeType ::U8 = > Arg ::new ( & self . u8_value ) ,
NativeType ::I8 = > Arg ::new ( & self . i8_value ) ,
NativeType ::U16 = > Arg ::new ( & self . u16_value ) ,
NativeType ::I16 = > Arg ::new ( & self . i16_value ) ,
NativeType ::U32 = > Arg ::new ( & self . u32_value ) ,
NativeType ::I32 = > Arg ::new ( & self . i32_value ) ,
NativeType ::U64 = > Arg ::new ( & self . u64_value ) ,
NativeType ::I64 = > Arg ::new ( & self . i64_value ) ,
NativeType ::USize = > Arg ::new ( & self . usize_value ) ,
NativeType ::ISize = > Arg ::new ( & self . isize_value ) ,
NativeType ::F32 = > Arg ::new ( & self . f32_value ) ,
NativeType ::F64 = > Arg ::new ( & self . f64_value ) ,
2022-08-22 23:46:43 -04:00
NativeType ::Pointer | NativeType ::Buffer | NativeType ::Function = > {
Arg ::new ( & self . pointer )
}
2021-08-06 17:28:10 -04:00
}
}
2022-06-20 07:06:04 -04:00
// SAFETY: native_type must correspond to the type of value represented by the union field
unsafe fn to_value ( & self , native_type : NativeType ) -> Value {
match native_type {
NativeType ::Void = > Value ::Null ,
NativeType ::U8 = > Value ::from ( self . u8_value ) ,
NativeType ::I8 = > Value ::from ( self . i8_value ) ,
NativeType ::U16 = > Value ::from ( self . u16_value ) ,
NativeType ::I16 = > Value ::from ( self . i16_value ) ,
NativeType ::U32 = > Value ::from ( self . u32_value ) ,
NativeType ::I32 = > Value ::from ( self . i32_value ) ,
NativeType ::U64 = > {
2022-07-24 06:41:11 -04:00
let value = self . u64_value ;
if value > MAX_SAFE_INTEGER as u64 {
json! ( U32x2 ::from ( self . u64_value ) )
} else {
Value ::from ( value )
}
2022-06-20 07:06:04 -04:00
}
NativeType ::I64 = > {
2022-07-24 06:41:11 -04:00
let value = self . i64_value ;
if value > MAX_SAFE_INTEGER as i64 | | value < MIN_SAFE_INTEGER as i64 {
json! ( U32x2 ::from ( self . i64_value as u64 ) )
} else {
Value ::from ( value )
}
2022-06-20 07:06:04 -04:00
}
NativeType ::USize = > {
2022-07-24 06:41:11 -04:00
let value = self . usize_value ;
if value > MAX_SAFE_INTEGER as usize {
json! ( U32x2 ::from ( self . usize_value as u64 ) )
} else {
Value ::from ( value )
}
2022-06-20 07:06:04 -04:00
}
NativeType ::ISize = > {
2022-07-24 06:41:11 -04:00
let value = self . isize_value ;
2022-08-21 13:31:14 -04:00
if ! ( MIN_SAFE_INTEGER ..= MAX_SAFE_INTEGER ) . contains ( & value ) {
2022-07-24 06:41:11 -04:00
json! ( U32x2 ::from ( self . isize_value as u64 ) )
} else {
Value ::from ( value )
}
2022-06-20 07:06:04 -04:00
}
NativeType ::F32 = > Value ::from ( self . f32_value ) ,
NativeType ::F64 = > Value ::from ( self . f64_value ) ,
2022-08-22 23:46:43 -04:00
NativeType ::Pointer | NativeType ::Function | NativeType ::Buffer = > {
2022-07-24 06:41:11 -04:00
let value = self . pointer as usize ;
if value > MAX_SAFE_INTEGER as usize {
json! ( U32x2 ::from ( value as u64 ) )
} else {
Value ::from ( value )
}
2022-06-20 07:06:04 -04:00
}
}
2022-06-08 07:13:10 -04:00
}
2022-06-20 07:06:04 -04:00
// SAFETY: native_type must correspond to the type of value represented by the union field
2022-06-29 04:13:33 -04:00
#[ inline ]
2022-06-20 07:06:04 -04:00
unsafe fn to_v8 < ' scope > (
& self ,
scope : & mut v8 ::HandleScope < ' scope > ,
native_type : NativeType ,
) -> serde_v8 ::Value < ' scope > {
match native_type {
NativeType ::Void = > {
let local_value : v8 ::Local < v8 ::Value > = v8 ::undefined ( scope ) . into ( ) ;
local_value . into ( )
}
NativeType ::U8 = > {
let local_value : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new_from_unsigned ( scope , self . u8_value as u32 ) . into ( ) ;
local_value . into ( )
}
NativeType ::I8 = > {
let local_value : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new ( scope , self . i8_value as i32 ) . into ( ) ;
local_value . into ( )
}
NativeType ::U16 = > {
let local_value : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new_from_unsigned ( scope , self . u16_value as u32 ) . into ( ) ;
local_value . into ( )
}
NativeType ::I16 = > {
let local_value : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new ( scope , self . i16_value as i32 ) . into ( ) ;
local_value . into ( )
}
NativeType ::U32 = > {
let local_value : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new_from_unsigned ( scope , self . u32_value ) . into ( ) ;
local_value . into ( )
}
NativeType ::I32 = > {
let local_value : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new ( scope , self . i32_value ) . into ( ) ;
local_value . into ( )
}
NativeType ::U64 = > {
2022-07-24 06:41:11 -04:00
let value = self . u64_value ;
2022-06-20 07:06:04 -04:00
let local_value : v8 ::Local < v8 ::Value > =
2022-07-24 06:41:11 -04:00
if value > MAX_SAFE_INTEGER as u64 {
v8 ::BigInt ::new_from_u64 ( scope , value ) . into ( )
} else {
v8 ::Number ::new ( scope , value as f64 ) . into ( )
} ;
2022-06-20 07:06:04 -04:00
local_value . into ( )
}
NativeType ::I64 = > {
2022-07-24 06:41:11 -04:00
let value = self . i64_value ;
2022-06-20 07:06:04 -04:00
let local_value : v8 ::Local < v8 ::Value > =
2022-07-24 06:41:11 -04:00
if value > MAX_SAFE_INTEGER as i64 | | value < MIN_SAFE_INTEGER as i64
{
v8 ::BigInt ::new_from_i64 ( scope , self . i64_value ) . into ( )
} else {
v8 ::Number ::new ( scope , value as f64 ) . into ( )
} ;
2022-06-20 07:06:04 -04:00
local_value . into ( )
}
NativeType ::USize = > {
2022-07-24 06:41:11 -04:00
let value = self . usize_value ;
2022-06-20 07:06:04 -04:00
let local_value : v8 ::Local < v8 ::Value > =
2022-07-24 06:41:11 -04:00
if value > MAX_SAFE_INTEGER as usize {
v8 ::BigInt ::new_from_u64 ( scope , value as u64 ) . into ( )
} else {
v8 ::Number ::new ( scope , value as f64 ) . into ( )
} ;
2022-06-20 07:06:04 -04:00
local_value . into ( )
}
NativeType ::ISize = > {
2022-07-24 06:41:11 -04:00
let value = self . isize_value ;
2022-06-20 07:06:04 -04:00
let local_value : v8 ::Local < v8 ::Value > =
2022-08-21 13:31:14 -04:00
if ! ( MIN_SAFE_INTEGER ..= MAX_SAFE_INTEGER ) . contains ( & value ) {
2022-07-24 06:41:11 -04:00
v8 ::BigInt ::new_from_i64 ( scope , self . isize_value as i64 ) . into ( )
} else {
v8 ::Number ::new ( scope , value as f64 ) . into ( )
} ;
2022-06-20 07:06:04 -04:00
local_value . into ( )
}
NativeType ::F32 = > {
let local_value : v8 ::Local < v8 ::Value > =
v8 ::Number ::new ( scope , self . f32_value as f64 ) . into ( ) ;
local_value . into ( )
}
NativeType ::F64 = > {
let local_value : v8 ::Local < v8 ::Value > =
v8 ::Number ::new ( scope , self . f64_value ) . into ( ) ;
local_value . into ( )
}
2022-08-22 23:46:43 -04:00
NativeType ::Pointer | NativeType ::Buffer | NativeType ::Function = > {
2022-07-24 06:41:11 -04:00
let value = self . pointer as u64 ;
2022-06-20 07:06:04 -04:00
let local_value : v8 ::Local < v8 ::Value > =
2022-07-24 06:41:11 -04:00
if value > MAX_SAFE_INTEGER as u64 {
v8 ::BigInt ::new_from_u64 ( scope , value ) . into ( )
} else {
v8 ::Number ::new ( scope , value as f64 ) . into ( )
} ;
2022-06-20 07:06:04 -04:00
local_value . into ( )
}
}
2022-01-05 02:25:31 -05:00
}
2021-08-06 17:28:10 -04:00
}
2022-08-21 13:31:14 -04:00
// SAFETY: unsafe trait must have unsafe implementation
2022-06-20 07:06:04 -04:00
unsafe impl Send for NativeValue { }
2021-08-06 17:28:10 -04:00
2022-06-20 07:06:04 -04:00
#[ derive(Serialize, Debug, Clone, Copy) ]
2021-12-15 09:41:49 -05:00
struct U32x2 ( u32 , u32 ) ;
impl From < u64 > for U32x2 {
fn from ( value : u64 ) -> Self {
Self ( ( value > > 32 ) as u32 , value as u32 )
}
}
2021-08-06 17:28:10 -04:00
#[ derive(Deserialize, Debug) ]
2021-10-05 18:27:05 -04:00
#[ serde(rename_all = " camelCase " ) ]
2021-08-06 17:28:10 -04:00
struct ForeignFunction {
2022-01-11 01:21:16 -05:00
name : Option < String > ,
2021-08-23 12:31:19 -04:00
parameters : Vec < NativeType > ,
result : NativeType ,
2022-06-29 04:13:33 -04:00
#[ serde(rename = " nonblocking " ) ]
non_blocking : Option < bool > ,
2022-07-09 09:11:07 -04:00
#[ serde(rename = " callback " ) ]
#[ serde(default = " default_callback " ) ]
callback : bool ,
}
fn default_callback ( ) -> bool {
false
2021-08-06 17:28:10 -04:00
}
2022-02-18 07:21:19 -05:00
// ForeignStatic's name and type fields are read and used by
// serde_v8 to determine which variant a ForeignSymbol is.
// They are not used beyond that and are thus marked with underscores.
#[ derive(Deserialize, Debug) ]
struct ForeignStatic {
#[ serde(rename(deserialize = " name " )) ]
_name : Option < String > ,
#[ serde(rename(deserialize = " type " )) ]
_type : String ,
}
#[ derive(Deserialize, Debug) ]
#[ serde(untagged) ]
enum ForeignSymbol {
ForeignFunction ( ForeignFunction ) ,
ForeignStatic ( ForeignStatic ) ,
}
2021-08-06 17:28:10 -04:00
#[ derive(Deserialize, Debug) ]
struct FfiLoadArgs {
path : String ,
2022-02-18 07:21:19 -05:00
symbols : HashMap < String , ForeignSymbol > ,
2021-08-06 17:28:10 -04:00
}
2021-10-05 20:13:56 -04:00
// `path` is only used on Windows.
#[ allow(unused_variables) ]
pub ( crate ) fn format_error ( e : dlopen ::Error , path : String ) -> String {
match e {
#[ cfg(target_os = " windows " ) ]
// This calls FormatMessageW with library path
// as replacement for the insert sequences.
// Unlike libstd which passes the FORMAT_MESSAGE_IGNORE_INSERTS
// flag without any arguments.
//
// https://github.com/denoland/deno/issues/11632
dlopen ::Error ::OpeningLibraryError ( e ) = > {
use std ::ffi ::OsStr ;
use std ::os ::windows ::ffi ::OsStrExt ;
use winapi ::shared ::minwindef ::DWORD ;
use winapi ::shared ::winerror ::ERROR_INSUFFICIENT_BUFFER ;
use winapi ::um ::errhandlingapi ::GetLastError ;
use winapi ::um ::winbase ::FormatMessageW ;
use winapi ::um ::winbase ::FORMAT_MESSAGE_ARGUMENT_ARRAY ;
use winapi ::um ::winbase ::FORMAT_MESSAGE_FROM_SYSTEM ;
use winapi ::um ::winnt ::LANG_SYSTEM_DEFAULT ;
use winapi ::um ::winnt ::MAKELANGID ;
use winapi ::um ::winnt ::SUBLANG_SYS_DEFAULT ;
let err_num = match e . raw_os_error ( ) {
Some ( err_num ) = > err_num ,
// This should never hit unless dlopen changes its error type.
None = > return e . to_string ( ) ,
} ;
// Language ID (0x0800)
let lang_id =
MAKELANGID ( LANG_SYSTEM_DEFAULT , SUBLANG_SYS_DEFAULT ) as DWORD ;
2021-10-12 09:58:04 -04:00
let mut buf = vec! [ 0 ; 500 ] ;
2021-10-05 20:13:56 -04:00
let path = OsStr ::new ( & path )
. encode_wide ( )
. chain ( Some ( 0 ) . into_iter ( ) )
. collect ::< Vec < _ > > ( ) ;
let arguments = [ path . as_ptr ( ) ] ;
loop {
2022-07-15 12:30:25 -04:00
// SAFETY:
// winapi call to format the error message
let length = unsafe {
FormatMessageW (
2021-10-05 20:13:56 -04:00
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY ,
std ::ptr ::null_mut ( ) ,
err_num as DWORD ,
lang_id as DWORD ,
buf . as_mut_ptr ( ) ,
buf . len ( ) as DWORD ,
arguments . as_ptr ( ) as _ ,
2022-07-15 12:30:25 -04:00
)
} ;
if length = = 0 {
// SAFETY:
// winapi call to get the last error message
let err_num = unsafe { GetLastError ( ) } ;
if err_num = = ERROR_INSUFFICIENT_BUFFER {
buf . resize ( buf . len ( ) * 2 , 0 ) ;
continue ;
2021-10-05 20:13:56 -04:00
}
2022-07-15 12:30:25 -04:00
// Something went wrong, just return the original error.
return e . to_string ( ) ;
2021-10-05 20:13:56 -04:00
}
2022-07-15 12:30:25 -04:00
let msg = String ::from_utf16_lossy ( & buf [ .. length as usize ] ) ;
return msg ;
2021-10-05 20:13:56 -04:00
}
}
_ = > e . to_string ( ) ,
}
}
2022-06-29 04:13:33 -04:00
#[ op(v8) ]
fn op_ffi_load < FP , ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
2021-08-06 17:28:10 -04:00
state : & mut deno_core ::OpState ,
args : FfiLoadArgs ,
2022-06-29 04:13:33 -04:00
) -> Result < ( ResourceId , serde_v8 ::Value < ' scope > ) , AnyError >
2021-08-06 17:28:10 -04:00
where
FP : FfiPermissions + 'static ,
{
2021-10-05 20:13:56 -04:00
let path = args . path ;
2021-08-06 17:28:10 -04:00
check_unstable ( state , " Deno.dlopen " ) ;
let permissions = state . borrow_mut ::< FP > ( ) ;
2021-12-15 09:41:49 -05:00
permissions . check ( Some ( & PathBuf ::from ( & path ) ) ) ? ;
2021-10-05 20:13:56 -04:00
2021-10-07 11:03:00 -04:00
let lib = Library ::open ( & path ) . map_err ( | e | {
dlopen ::Error ::OpeningLibraryError ( std ::io ::Error ::new (
std ::io ::ErrorKind ::Other ,
format_error ( e , path ) ,
) )
} ) ? ;
2021-08-06 17:28:10 -04:00
let mut resource = DynamicLibraryResource {
lib ,
symbols : HashMap ::new ( ) ,
} ;
2022-06-29 04:13:33 -04:00
let obj = v8 ::Object ::new ( scope ) ;
2021-08-06 17:28:10 -04:00
2022-06-29 04:13:33 -04:00
for ( symbol_key , foreign_symbol ) in args . symbols {
2022-02-18 07:21:19 -05:00
match foreign_symbol {
ForeignSymbol ::ForeignStatic ( _ ) = > {
// No-op: Statics will be handled separately and are not part of the Rust-side resource.
}
ForeignSymbol ::ForeignFunction ( foreign_fn ) = > {
2022-06-29 04:13:33 -04:00
let symbol = match & foreign_fn . name {
Some ( symbol ) = > symbol ,
None = > & symbol_key ,
} ;
// By default, Err returned by this function does not tell
// which symbol wasn't exported. So we'll modify the error
// message to include the name of symbol.
let fn_ptr =
2022-07-01 09:28:06 -04:00
// SAFETY: The obtained T symbol is the size of a pointer.
2022-06-29 04:13:33 -04:00
match unsafe { resource . lib . symbol ::< * const c_void > ( symbol ) } {
Ok ( value ) = > Ok ( value ) ,
Err ( err ) = > Err ( generic_error ( format! (
" Failed to register symbol {}: {} " ,
symbol , err
) ) ) ,
} ? ;
let ptr = libffi ::middle ::CodePtr ::from_ptr ( fn_ptr as _ ) ;
let cif = libffi ::middle ::Cif ::new (
foreign_fn
. parameters
. clone ( )
. into_iter ( )
. map ( libffi ::middle ::Type ::from ) ,
foreign_fn . result . into ( ) ,
) ;
let func_key = v8 ::String ::new ( scope , & symbol_key ) . unwrap ( ) ;
let sym = Box ::new ( Symbol {
cif ,
ptr ,
parameter_types : foreign_fn . parameters ,
result_type : foreign_fn . result ,
2022-07-09 09:11:07 -04:00
can_callback : foreign_fn . callback ,
2022-06-29 04:13:33 -04:00
} ) ;
resource . symbols . insert ( symbol_key , sym . clone ( ) ) ;
match foreign_fn . non_blocking {
// Generate functions for synchronous calls.
Some ( false ) | None = > {
2022-07-08 13:49:09 -04:00
let function = make_sync_fn ( scope , sym ) ;
2022-06-29 04:13:33 -04:00
obj . set ( scope , func_key . into ( ) , function . into ( ) ) ;
}
// This optimization is not yet supported for non-blocking calls.
_ = > { }
} ;
2022-02-18 07:21:19 -05:00
}
}
2021-08-06 17:28:10 -04:00
}
2022-06-29 04:13:33 -04:00
let rid = state . resource_table . add ( resource ) ;
Ok ( (
rid ,
serde_v8 ::Value {
v8_value : obj . into ( ) ,
} ,
) )
}
2022-07-08 13:49:09 -04:00
pub struct FfiFastCallTemplate {
args : Box < [ fast_api ::Type ] > ,
ret : fast_api ::CType ,
symbol_ptr : * const c_void ,
}
impl fast_api ::FastFunction for FfiFastCallTemplate {
2022-07-19 15:36:15 -04:00
fn function ( & self ) -> * const c_void {
2022-07-08 13:49:09 -04:00
self . symbol_ptr
}
2022-07-19 15:36:15 -04:00
2022-07-08 13:49:09 -04:00
fn args ( & self ) -> & 'static [ fast_api ::Type ] {
Box ::leak ( self . args . clone ( ) )
}
2022-07-19 15:36:15 -04:00
2022-07-08 13:49:09 -04:00
fn return_type ( & self ) -> fast_api ::CType {
self . ret
}
}
impl From < & NativeType > for fast_api ::Type {
fn from ( native_type : & NativeType ) -> Self {
match native_type {
NativeType ::U8 | NativeType ::U16 | NativeType ::U32 = > {
fast_api ::Type ::Uint32
}
NativeType ::I8 | NativeType ::I16 | NativeType ::I32 = > {
fast_api ::Type ::Int32
}
NativeType ::F32 = > fast_api ::Type ::Float32 ,
NativeType ::F64 = > fast_api ::Type ::Float64 ,
NativeType ::Void = > fast_api ::Type ::Void ,
2022-07-24 06:41:11 -04:00
NativeType ::I64 = > fast_api ::Type ::Int64 ,
NativeType ::U64 = > fast_api ::Type ::Uint64 ,
NativeType ::ISize = > fast_api ::Type ::Int64 ,
2022-08-22 23:46:43 -04:00
NativeType ::USize | NativeType ::Pointer | NativeType ::Function = > {
fast_api ::Type ::Uint64
}
NativeType ::Buffer = > fast_api ::Type ::TypedArray ( fast_api ::CType ::Uint8 ) ,
2022-07-08 13:49:09 -04:00
}
}
}
2022-07-28 08:38:22 -04:00
fn needs_unwrap ( rv : NativeType ) -> bool {
matches! (
2022-07-08 13:49:09 -04:00
rv ,
NativeType ::Function
| NativeType ::Pointer
2022-08-22 23:46:43 -04:00
| NativeType ::Buffer
2022-07-08 13:49:09 -04:00
| NativeType ::I64
| NativeType ::ISize
| NativeType ::U64
| NativeType ::USize
)
}
2022-07-28 08:38:22 -04:00
fn is_i64 ( rv : NativeType ) -> bool {
matches! ( rv , NativeType ::I64 | NativeType ::ISize )
}
2022-06-29 04:13:33 -04:00
// Create a JavaScript function for synchronous FFI call to
// the given symbol.
fn make_sync_fn < ' s > (
scope : & mut v8 ::HandleScope < ' s > ,
2022-07-08 13:49:09 -04:00
sym : Box < Symbol > ,
2022-06-29 04:13:33 -04:00
) -> v8 ::Local < ' s , v8 ::Function > {
2022-07-11 21:03:05 -04:00
#[ cfg(not(target_os = " windows " )) ]
let mut fast_ffi_templ : Option < FfiFastCallTemplate > = None ;
#[ cfg(target_os = " windows " ) ]
let fast_ffi_templ : Option < FfiFastCallTemplate > = None ;
2022-07-08 13:49:09 -04:00
2022-07-11 21:03:05 -04:00
#[ cfg(not(target_os = " windows " )) ]
let mut fast_allocations : Option < * mut ( ) > = None ;
#[ cfg(not(target_os = " windows " )) ]
2022-07-28 08:38:22 -04:00
if ! sym . can_callback {
let needs_unwrap = needs_unwrap ( sym . result_type ) ;
let ret = match needs_unwrap {
true = > fast_api ::Type ::Void ,
false = > fast_api ::Type ::from ( & sym . result_type ) ,
} ;
2022-07-11 21:03:05 -04:00
2022-07-08 13:49:09 -04:00
let mut args = sym
. parameter_types
. iter ( )
. map ( | t | t . into ( ) )
. collect ::< Vec < _ > > ( ) ;
2022-07-11 21:03:05 -04:00
// recv
args . insert ( 0 , fast_api ::Type ::V8Value ) ;
2022-07-28 08:38:22 -04:00
if needs_unwrap {
args . push ( fast_api ::Type ::TypedArray ( fast_api ::CType ::Int32 ) ) ;
}
2022-07-11 21:03:05 -04:00
let symbol_trampoline =
jit_trampoline ::gen_trampoline ( sym . clone ( ) ) . expect ( " gen_trampoline " ) ;
2022-07-08 13:49:09 -04:00
fast_ffi_templ = Some ( FfiFastCallTemplate {
args : args . into_boxed_slice ( ) ,
2022-07-11 21:03:05 -04:00
ret : ( & ret ) . into ( ) ,
symbol_ptr : symbol_trampoline . addr ,
2022-07-08 13:49:09 -04:00
} ) ;
2022-07-11 21:03:05 -04:00
fast_allocations = Some ( Box ::into_raw ( symbol_trampoline ) as * mut ( ) ) ;
2022-07-08 13:49:09 -04:00
}
let sym = Box ::leak ( sym ) ;
let builder = v8 ::FunctionTemplate ::builder (
2022-06-29 04:13:33 -04:00
| scope : & mut v8 ::HandleScope ,
args : v8 ::FunctionCallbackArguments ,
mut rv : v8 ::ReturnValue | {
let external : v8 ::Local < v8 ::External > =
args . data ( ) . unwrap ( ) . try_into ( ) . unwrap ( ) ;
// SAFETY: The pointer will not be deallocated until the function is
// garbage collected.
let symbol = unsafe { & * ( external . value ( ) as * const Symbol ) } ;
2022-07-28 08:38:22 -04:00
let needs_unwrap = match needs_unwrap ( symbol . result_type ) {
true = > Some ( args . get ( symbol . parameter_types . len ( ) as i32 ) ) ,
false = > None ,
} ;
2022-06-29 04:13:33 -04:00
match ffi_call_sync ( scope , args , symbol ) {
Ok ( result ) = > {
2022-07-28 08:38:22 -04:00
match needs_unwrap {
Some ( v ) = > {
let view : v8 ::Local < v8 ::ArrayBufferView > = v . try_into ( ) . unwrap ( ) ;
let backing_store =
view . buffer ( scope ) . unwrap ( ) . get_backing_store ( ) ;
if is_i64 ( symbol . result_type ) {
// SAFETY: v8::SharedRef<v8::BackingStore> is similar to Arc<[u8]>,
// it points to a fixed continuous slice of bytes on the heap.
let bs = unsafe {
& mut * ( & backing_store [ .. ] as * const _ as * mut [ u8 ]
as * mut i64 )
} ;
// SAFETY: We already checked that type == I64
let value = unsafe { result . i64_value } ;
* bs = value ;
} else {
// SAFETY: v8::SharedRef<v8::BackingStore> is similar to Arc<[u8]>,
// it points to a fixed continuous slice of bytes on the heap.
let bs = unsafe {
& mut * ( & backing_store [ .. ] as * const _ as * mut [ u8 ]
as * mut u64 )
} ;
// SAFETY: We checked that type == U64
let value = unsafe { result . u64_value } ;
* bs = value ;
}
}
None = > {
// SAFETY: Same return type declared to libffi; trust user to have it right beyond that.
let result = unsafe { result . to_v8 ( scope , symbol . result_type ) } ;
rv . set ( result . v8_value ) ;
}
}
2022-06-29 04:13:33 -04:00
}
Err ( err ) = > {
deno_core ::_ops ::throw_type_error ( scope , err . to_string ( ) ) ;
}
} ;
} ,
)
2022-07-08 13:49:09 -04:00
. data ( v8 ::External ::new ( scope , sym as * mut Symbol as * mut _ ) . into ( ) ) ;
let func = if let Some ( fast_ffi_templ ) = fast_ffi_templ {
2022-07-19 15:36:15 -04:00
builder . build_fast ( scope , & fast_ffi_templ , None )
2022-07-08 13:49:09 -04:00
} else {
builder . build ( scope )
} ;
let func = func . get_function ( scope ) . unwrap ( ) ;
2022-06-29 04:13:33 -04:00
let weak = v8 ::Weak ::with_finalizer (
scope ,
func ,
Box ::new ( move | _ | {
// SAFETY: This is never called twice. pointer obtained
// from Box::into_raw, hence, satisfies memory layout requirements.
2022-07-11 21:03:05 -04:00
unsafe {
Box ::from_raw ( sym ) ;
#[ cfg(not(target_os = " windows " )) ]
if let Some ( fast_allocations ) = fast_allocations {
Box ::from_raw ( fast_allocations as * mut jit_trampoline ::Allocation ) ;
}
}
2022-06-29 04:13:33 -04:00
} ) ,
) ;
weak . to_local ( scope ) . unwrap ( )
2021-08-06 17:28:10 -04:00
}
2022-07-24 06:41:11 -04:00
#[ inline ]
fn ffi_parse_u8_arg (
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
let u8_value = v8 ::Local ::< v8 ::Uint32 > ::try_from ( arg )
. map_err ( | _ | type_error ( " Invalid FFI u8 type, expected unsigned integer " ) ) ?
. value ( ) as u8 ;
Ok ( NativeValue { u8_value } )
}
#[ inline ]
fn ffi_parse_i8_arg (
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
let i8_value = v8 ::Local ::< v8 ::Int32 > ::try_from ( arg )
. map_err ( | _ | type_error ( " Invalid FFI i8 type, expected integer " ) ) ?
. value ( ) as i8 ;
Ok ( NativeValue { i8_value } )
}
#[ inline ]
fn ffi_parse_u16_arg (
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
let u16_value = v8 ::Local ::< v8 ::Uint32 > ::try_from ( arg )
. map_err ( | _ | type_error ( " Invalid FFI u16 type, expected unsigned integer " ) ) ?
. value ( ) as u16 ;
Ok ( NativeValue { u16_value } )
}
#[ inline ]
fn ffi_parse_i16_arg (
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
let i16_value = v8 ::Local ::< v8 ::Int32 > ::try_from ( arg )
. map_err ( | _ | type_error ( " Invalid FFI i16 type, expected integer " ) ) ?
. value ( ) as i16 ;
Ok ( NativeValue { i16_value } )
}
#[ inline ]
fn ffi_parse_u32_arg (
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
let u32_value = v8 ::Local ::< v8 ::Uint32 > ::try_from ( arg )
. map_err ( | _ | type_error ( " Invalid FFI u32 type, expected unsigned integer " ) ) ?
. value ( ) as u32 ;
Ok ( NativeValue { u32_value } )
}
#[ inline ]
fn ffi_parse_i32_arg (
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
let i32_value = v8 ::Local ::< v8 ::Int32 > ::try_from ( arg )
. map_err ( | _ | type_error ( " Invalid FFI i32 type, expected integer " ) ) ?
. value ( ) as i32 ;
Ok ( NativeValue { i32_value } )
}
#[ inline ]
fn ffi_parse_u64_arg (
scope : & mut v8 ::HandleScope ,
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
// Order of checking:
// 1. BigInt: Uncommon and not supported by Fast API, so optimise slow call for this case.
// 2. Number: Common, supported by Fast API, so let that be the optimal case.
let u64_value : u64 = if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( arg )
{
value . u64_value ( ) . 0
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( arg ) {
value . integer_value ( scope ) . unwrap ( ) as u64
} else {
return Err ( type_error (
" Invalid FFI u64 type, expected unsigned integer " ,
) ) ;
} ;
Ok ( NativeValue { u64_value } )
}
#[ inline ]
fn ffi_parse_i64_arg (
scope : & mut v8 ::HandleScope ,
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
// Order of checking:
// 1. BigInt: Uncommon and not supported by Fast API, so optimise slow call for this case.
// 2. Number: Common, supported by Fast API, so let that be the optimal case.
let i64_value : i64 = if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( arg )
{
value . i64_value ( ) . 0
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( arg ) {
value . integer_value ( scope ) . unwrap ( ) as i64
} else {
return Err ( type_error ( " Invalid FFI i64 type, expected integer " ) ) ;
} ;
Ok ( NativeValue { i64_value } )
}
#[ inline ]
fn ffi_parse_usize_arg (
scope : & mut v8 ::HandleScope ,
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
// Order of checking:
// 1. BigInt: Uncommon and not supported by Fast API, so optimise slow call for this case.
// 2. Number: Common, supported by Fast API, so let that be the optimal case.
let usize_value : usize =
if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( arg ) {
value . u64_value ( ) . 0 as usize
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( arg ) {
value . integer_value ( scope ) . unwrap ( ) as usize
} else {
return Err ( type_error ( " Invalid FFI usize type, expected integer " ) ) ;
} ;
Ok ( NativeValue { usize_value } )
}
#[ inline ]
fn ffi_parse_isize_arg (
scope : & mut v8 ::HandleScope ,
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
// Order of checking:
// 1. BigInt: Uncommon and not supported by Fast API, so optimise slow call for this case.
// 2. Number: Common, supported by Fast API, so let that be the optimal case.
let isize_value : isize =
if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( arg ) {
value . i64_value ( ) . 0 as isize
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( arg ) {
value . integer_value ( scope ) . unwrap ( ) as isize
} else {
return Err ( type_error ( " Invalid FFI isize type, expected integer " ) ) ;
} ;
Ok ( NativeValue { isize_value } )
}
#[ inline ]
fn ffi_parse_f32_arg (
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
let f32_value = v8 ::Local ::< v8 ::Number > ::try_from ( arg )
. map_err ( | _ | type_error ( " Invalid FFI f32 type, expected number " ) ) ?
. value ( ) as f32 ;
Ok ( NativeValue { f32_value } )
}
#[ inline ]
fn ffi_parse_f64_arg (
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
let f64_value = v8 ::Local ::< v8 ::Number > ::try_from ( arg )
. map_err ( | _ | type_error ( " Invalid FFI f64 type, expected number " ) ) ?
. value ( ) as f64 ;
Ok ( NativeValue { f64_value } )
}
#[ inline ]
fn ffi_parse_pointer_arg (
scope : & mut v8 ::HandleScope ,
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
// Order of checking:
2022-08-22 23:46:43 -04:00
// 1. BigInt: Uncommon and not supported by Fast API, optimise this case.
// 2. Number: Common and supported by Fast API.
// 3. Null: Very uncommon / can be represented by a 0.
let pointer = if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( arg ) {
value . u64_value ( ) . 0 as usize as * const u8
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( arg ) {
value . integer_value ( scope ) . unwrap ( ) as usize as * const u8
} else if arg . is_null ( ) {
ptr ::null ( )
} else {
return Err ( type_error (
" Invalid FFI pointer type, expected null, integer or BigInt " ,
) ) ;
} ;
Ok ( NativeValue { pointer } )
}
#[ inline ]
fn ffi_parse_buffer_arg (
scope : & mut v8 ::HandleScope ,
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
// Order of checking:
// 1. ArrayBuffer: Fairly common and not supported by Fast API, optimise this case.
// 2. ArrayBufferView: Common and supported by Fast API
2022-07-24 06:41:11 -04:00
// 5. Null: Very uncommon / can be represented by a 0.
2022-08-22 23:46:43 -04:00
let pointer = if let Ok ( value ) = v8 ::Local ::< v8 ::ArrayBuffer > ::try_from ( arg ) {
let backing_store = value . get_backing_store ( ) ;
& backing_store [ .. ] as * const _ as * const u8
} else if let Ok ( value ) = v8 ::Local ::< v8 ::ArrayBufferView > ::try_from ( arg ) {
2022-07-24 06:41:11 -04:00
let byte_offset = value . byte_offset ( ) ;
let backing_store = value
. buffer ( scope )
. ok_or_else ( | | {
type_error ( " Invalid FFI ArrayBufferView, expected data in the buffer " )
} ) ?
. get_backing_store ( ) ;
2022-07-27 01:43:30 -04:00
& backing_store [ byte_offset .. ] as * const _ as * const u8
2022-07-24 06:41:11 -04:00
} else if arg . is_null ( ) {
ptr ::null ( )
} else {
2022-08-22 23:46:43 -04:00
return Err ( type_error (
" Invalid FFI buffer type, expected null, ArrayBuffer, or ArrayBufferView " ,
) ) ;
2022-07-24 06:41:11 -04:00
} ;
Ok ( NativeValue { pointer } )
}
#[ inline ]
fn ffi_parse_function_arg (
scope : & mut v8 ::HandleScope ,
arg : v8 ::Local < v8 ::Value > ,
) -> Result < NativeValue , AnyError > {
// Order of checking:
// 1. BigInt: Uncommon and not supported by Fast API, optimise this case.
// 2. Number: Common and supported by Fast API, optimise this case as second.
// 3. Null: Very uncommon / can be represented by a 0.
let pointer = if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( arg ) {
value . u64_value ( ) . 0 as usize as * const u8
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( arg ) {
value . integer_value ( scope ) . unwrap ( ) as usize as * const u8
} else if arg . is_null ( ) {
ptr ::null ( )
} else {
return Err ( type_error (
" Invalid FFI function type, expected null, integer, or BigInt " ,
) ) ;
} ;
Ok ( NativeValue { pointer } )
}
2022-06-20 07:06:04 -04:00
fn ffi_parse_args < ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
args : serde_v8 ::Value < ' scope > ,
parameter_types : & [ NativeType ] ,
) -> Result < Vec < NativeValue > , AnyError >
where
' scope : ' scope ,
{
if parameter_types . is_empty ( ) {
return Ok ( vec! [ ] ) ;
}
2021-08-06 17:28:10 -04:00
2022-06-20 07:06:04 -04:00
let args = v8 ::Local ::< v8 ::Array > ::try_from ( args . v8_value )
. map_err ( | _ | type_error ( " Invalid FFI parameters, expected Array " ) ) ? ;
let mut ffi_args : Vec < NativeValue > =
Vec ::with_capacity ( parameter_types . len ( ) ) ;
2022-01-12 06:38:26 -05:00
2022-06-20 07:06:04 -04:00
for ( index , native_type ) in parameter_types . iter ( ) . enumerate ( ) {
let value = args . get_index ( scope , index as u32 ) . unwrap ( ) ;
match native_type {
NativeType ::U8 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_u8_arg ( value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::I8 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_i8_arg ( value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::U16 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_u16_arg ( value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::I16 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_i16_arg ( value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::U32 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_u32_arg ( value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::I32 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_i32_arg ( value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::U64 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_u64_arg ( scope , value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::I64 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_i64_arg ( scope , value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::USize = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_usize_arg ( scope , value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::ISize = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_isize_arg ( scope , value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::F32 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_f32_arg ( value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
NativeType ::F64 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_f64_arg ( value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
2022-08-22 23:46:43 -04:00
NativeType ::Buffer = > {
ffi_args . push ( ffi_parse_buffer_arg ( scope , value ) ? ) ;
}
2022-06-20 07:06:04 -04:00
NativeType ::Pointer = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_pointer_arg ( scope , value ) ? ) ;
2022-06-20 07:06:04 -04:00
}
2022-06-20 22:50:33 -04:00
NativeType ::Function = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_function_arg ( scope , value ) ? ) ;
}
NativeType ::Void = > {
unreachable! ( ) ;
2022-06-20 07:06:04 -04:00
}
2022-01-12 06:38:26 -05:00
}
}
2022-06-20 07:06:04 -04:00
Ok ( ffi_args )
2022-01-12 06:38:26 -05:00
}
2022-06-29 04:13:33 -04:00
// A one-off synchronous FFI call.
fn ffi_call_sync < ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
args : v8 ::FunctionCallbackArguments ,
symbol : & Symbol ,
) -> Result < NativeValue , AnyError >
where
' scope : ' scope ,
{
let Symbol {
parameter_types ,
result_type ,
cif ,
ptr : fun_ptr ,
2022-07-09 09:11:07 -04:00
..
2022-06-29 04:13:33 -04:00
} = symbol ;
let mut ffi_args : Vec < NativeValue > =
Vec ::with_capacity ( parameter_types . len ( ) ) ;
for ( index , native_type ) in parameter_types . iter ( ) . enumerate ( ) {
let value = args . get ( index as i32 ) ;
match native_type {
NativeType ::U8 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_u8_arg ( value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::I8 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_i8_arg ( value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::U16 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_u16_arg ( value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::I16 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_i16_arg ( value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::U32 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_u32_arg ( value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::I32 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_i32_arg ( value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::U64 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_u64_arg ( scope , value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::I64 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_i64_arg ( scope , value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::USize = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_usize_arg ( scope , value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::ISize = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_isize_arg ( scope , value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::F32 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_f32_arg ( value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::F64 = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_f64_arg ( value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
2022-08-22 23:46:43 -04:00
NativeType ::Buffer = > {
ffi_args . push ( ffi_parse_buffer_arg ( scope , value ) ? ) ;
}
2022-06-29 04:13:33 -04:00
NativeType ::Pointer = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_pointer_arg ( scope , value ) ? ) ;
2022-06-29 04:13:33 -04:00
}
NativeType ::Function = > {
2022-07-24 06:41:11 -04:00
ffi_args . push ( ffi_parse_function_arg ( scope , value ) ? ) ;
}
NativeType ::Void = > {
unreachable! ( ) ;
2022-06-29 04:13:33 -04:00
}
}
}
let call_args : Vec < Arg > = ffi_args . iter ( ) . map ( Arg ::new ) . collect ( ) ;
// SAFETY: types in the `Cif` match the actual calling convention and
// types of symbol.
unsafe {
Ok ( match result_type {
NativeType ::Void = > NativeValue {
void_value : cif . call ::< ( ) > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::U8 = > NativeValue {
u8_value : cif . call ::< u8 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::I8 = > NativeValue {
i8_value : cif . call ::< i8 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::U16 = > NativeValue {
u16_value : cif . call ::< u16 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::I16 = > NativeValue {
i16_value : cif . call ::< i16 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::U32 = > NativeValue {
u32_value : cif . call ::< u32 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::I32 = > NativeValue {
i32_value : cif . call ::< i32 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::U64 = > NativeValue {
u64_value : cif . call ::< u64 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::I64 = > NativeValue {
i64_value : cif . call ::< i64 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::USize = > NativeValue {
usize_value : cif . call ::< usize > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::ISize = > NativeValue {
isize_value : cif . call ::< isize > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::F32 = > NativeValue {
f32_value : cif . call ::< f32 > ( * fun_ptr , & call_args ) ,
} ,
NativeType ::F64 = > NativeValue {
f64_value : cif . call ::< f64 > ( * fun_ptr , & call_args ) ,
} ,
2022-08-22 23:46:43 -04:00
NativeType ::Pointer | NativeType ::Function | NativeType ::Buffer = > {
NativeValue {
pointer : cif . call ::< * const u8 > ( * fun_ptr , & call_args ) ,
}
}
2022-06-29 04:13:33 -04:00
} )
}
}
2022-06-20 07:06:04 -04:00
fn ffi_call (
call_args : Vec < NativeValue > ,
cif : & libffi ::middle ::Cif ,
fun_ptr : libffi ::middle ::CodePtr ,
parameter_types : & [ NativeType ] ,
result_type : NativeType ,
) -> Result < NativeValue , AnyError > {
let call_args : Vec < Arg > = call_args
. iter ( )
. enumerate ( )
2022-06-25 18:13:24 -04:00
. map ( | ( index , ffi_arg ) | {
// SAFETY: the union field is initialized
unsafe { ffi_arg . as_arg ( * parameter_types . get ( index ) . unwrap ( ) ) }
2022-06-20 07:06:04 -04:00
} )
. collect ( ) ;
2022-01-12 06:38:26 -05:00
2022-06-25 18:13:24 -04:00
// SAFETY: types in the `Cif` match the actual calling convention and
// types of symbol.
unsafe {
Ok ( match result_type {
NativeType ::Void = > NativeValue {
void_value : cif . call ::< ( ) > ( fun_ptr , & call_args ) ,
} ,
NativeType ::U8 = > NativeValue {
u8_value : cif . call ::< u8 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::I8 = > NativeValue {
i8_value : cif . call ::< i8 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::U16 = > NativeValue {
u16_value : cif . call ::< u16 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::I16 = > NativeValue {
i16_value : cif . call ::< i16 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::U32 = > NativeValue {
u32_value : cif . call ::< u32 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::I32 = > NativeValue {
i32_value : cif . call ::< i32 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::U64 = > NativeValue {
u64_value : cif . call ::< u64 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::I64 = > NativeValue {
i64_value : cif . call ::< i64 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::USize = > NativeValue {
usize_value : cif . call ::< usize > ( fun_ptr , & call_args ) ,
} ,
NativeType ::ISize = > NativeValue {
isize_value : cif . call ::< isize > ( fun_ptr , & call_args ) ,
} ,
NativeType ::F32 = > NativeValue {
f32_value : cif . call ::< f32 > ( fun_ptr , & call_args ) ,
} ,
NativeType ::F64 = > NativeValue {
f64_value : cif . call ::< f64 > ( fun_ptr , & call_args ) ,
} ,
2022-08-22 23:46:43 -04:00
NativeType ::Pointer | NativeType ::Function | NativeType ::Buffer = > {
NativeValue {
pointer : cif . call ::< * const u8 > ( fun_ptr , & call_args ) ,
}
}
2022-06-25 18:13:24 -04:00
} )
}
2022-06-20 07:06:04 -04:00
}
struct UnsafeCallbackResource {
// Closure is never directly touched, but it keeps the C callback alive
// until `close()` method is called.
#[ allow(dead_code) ]
closure : libffi ::middle ::Closure < 'static > ,
info : * const CallbackInfo ,
}
impl Resource for UnsafeCallbackResource {
fn name ( & self ) -> Cow < str > {
" unsafecallback " . into ( )
}
fn close ( self : Rc < Self > ) {
// SAFETY: This drops the closure and the callback info associated with it.
// Any retained function pointers to the closure become dangling pointers.
// It is up to the user to know that it is safe to call the `close()` on the
// UnsafeCallback instance.
unsafe {
let info = Box ::from_raw ( self . info as * mut CallbackInfo ) ;
let isolate = info . isolate . as_mut ( ) . unwrap ( ) ;
v8 ::Global ::from_raw ( isolate , info . callback ) ;
v8 ::Global ::from_raw ( isolate , info . context ) ;
2022-01-12 06:38:26 -05:00
}
}
}
2022-06-20 07:06:04 -04:00
struct CallbackInfo {
2022-06-28 05:23:36 -04:00
pub async_work_sender : mpsc ::UnboundedSender < PendingFfiAsyncWork > ,
2022-06-20 07:06:04 -04:00
pub callback : NonNull < v8 ::Function > ,
pub context : NonNull < v8 ::Context > ,
pub isolate : * mut v8 ::Isolate ,
}
2022-01-05 02:25:31 -05:00
2022-06-20 07:06:04 -04:00
unsafe extern " C " fn deno_ffi_callback (
cif : & libffi ::low ::ffi_cif ,
result : & mut c_void ,
args : * const * const c_void ,
info : & CallbackInfo ,
) {
2022-06-28 05:23:36 -04:00
LOCAL_ISOLATE_POINTER . with ( | s | {
if ptr ::eq ( * s . borrow ( ) , info . isolate ) {
// Own isolate thread, okay to call directly
do_ffi_callback (
cif ,
result ,
args ,
info . callback ,
info . context ,
info . isolate ,
2022-06-20 07:06:04 -04:00
) ;
2022-06-28 05:23:36 -04:00
} else {
let async_work_sender = & info . async_work_sender ;
// SAFETY: Safe as this function blocks until `do_ffi_callback` completes and a response message is received.
let cif : & 'static libffi ::low ::ffi_cif = std ::mem ::transmute ( cif ) ;
let result : & 'static mut c_void = std ::mem ::transmute ( result ) ;
let info : & 'static CallbackInfo = std ::mem ::transmute ( info ) ;
let ( response_sender , response_receiver ) = sync_channel ::< ( ) > ( 0 ) ;
let fut = Box ::new ( move | | {
do_ffi_callback (
cif ,
result ,
args ,
info . callback ,
info . context ,
info . isolate ,
) ;
response_sender . send ( ( ) ) . unwrap ( ) ;
} ) ;
async_work_sender . unbounded_send ( fut ) . unwrap ( ) ;
response_receiver . recv ( ) . unwrap ( ) ;
2022-06-20 07:06:04 -04:00
}
} ) ;
2022-06-28 05:23:36 -04:00
}
unsafe fn do_ffi_callback (
cif : & libffi ::low ::ffi_cif ,
result : & mut c_void ,
args : * const * const c_void ,
callback : NonNull < v8 ::Function > ,
context : NonNull < v8 ::Context > ,
isolate : * mut v8 ::Isolate ,
) {
let isolate = & mut * isolate ;
let callback = v8 ::Global ::from_raw ( isolate , callback ) ;
let context = std ::mem ::transmute ::<
NonNull < v8 ::Context > ,
v8 ::Local < v8 ::Context > ,
> ( context ) ;
2022-06-20 07:06:04 -04:00
// Call from main thread. If this callback is being triggered due to a
// function call coming from Deno itself, then this callback will build
// ontop of that stack.
// If this callback is being triggered outside of Deno (for example from a
// signal handler) then this will either create an empty new stack if
// Deno currently has nothing running and is waiting for promises to resolve,
// or will (very incorrectly) build ontop of whatever stack exists.
// The callback will even be called through from a `while (true)` liveloop, but
// it somehow cannot change the values that the loop sees, even if they both
// refer the same `let bool_value`.
let mut cb_scope = v8 ::CallbackScope ::new ( context ) ;
2022-07-24 06:41:11 -04:00
let scope = & mut v8 ::HandleScope ::new ( & mut cb_scope ) ;
let func = callback . open ( scope ) ;
2022-06-20 07:06:04 -04:00
let result = result as * mut c_void ;
let repr : & [ * mut ffi_type ] =
std ::slice ::from_raw_parts ( cif . arg_types , cif . nargs as usize ) ;
let vals : & [ * const c_void ] =
std ::slice ::from_raw_parts ( args , cif . nargs as usize ) ;
let mut params : Vec < v8 ::Local < v8 ::Value > > = vec! [ ] ;
for ( repr , val ) in repr . iter ( ) . zip ( vals ) {
let value : v8 ::Local < v8 ::Value > = match ( * ( * repr ) ) . type_ as _ {
FFI_TYPE_FLOAT = > {
let value = * ( ( * val ) as * const f32 ) ;
2022-07-24 06:41:11 -04:00
v8 ::Number ::new ( scope , value as f64 ) . into ( )
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_DOUBLE = > {
let value = * ( ( * val ) as * const f64 ) ;
2022-07-24 06:41:11 -04:00
v8 ::Number ::new ( scope , value ) . into ( )
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_SINT8 = > {
let value = * ( ( * val ) as * const i8 ) ;
2022-07-24 06:41:11 -04:00
v8 ::Integer ::new ( scope , value as i32 ) . into ( )
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_UINT8 = > {
let value = * ( ( * val ) as * const u8 ) ;
2022-07-24 06:41:11 -04:00
v8 ::Integer ::new_from_unsigned ( scope , value as u32 ) . into ( )
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_SINT16 = > {
let value = * ( ( * val ) as * const i16 ) ;
2022-07-24 06:41:11 -04:00
v8 ::Integer ::new ( scope , value as i32 ) . into ( )
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_UINT16 = > {
let value = * ( ( * val ) as * const u16 ) ;
2022-07-24 06:41:11 -04:00
v8 ::Integer ::new_from_unsigned ( scope , value as u32 ) . into ( )
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_INT | FFI_TYPE_SINT32 = > {
let value = * ( ( * val ) as * const i32 ) ;
2022-07-24 06:41:11 -04:00
v8 ::Integer ::new ( scope , value ) . into ( )
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_UINT32 = > {
let value = * ( ( * val ) as * const u32 ) ;
2022-07-24 06:41:11 -04:00
v8 ::Integer ::new_from_unsigned ( scope , value ) . into ( )
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_SINT64 = > {
let result = * ( ( * val ) as * const i64 ) ;
2022-07-24 06:41:11 -04:00
if result > MAX_SAFE_INTEGER as i64 | | result < MIN_SAFE_INTEGER as i64
{
v8 ::BigInt ::new_from_i64 ( scope , result ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
}
2022-06-20 07:06:04 -04:00
}
2022-07-24 06:41:11 -04:00
FFI_TYPE_UINT64 = > {
2022-06-20 07:06:04 -04:00
let result = * ( ( * val ) as * const u64 ) ;
2022-07-24 06:41:11 -04:00
if result > MAX_SAFE_INTEGER as u64 {
v8 ::BigInt ::new_from_u64 ( scope , result ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
}
2022-06-20 07:06:04 -04:00
}
2022-07-24 06:41:11 -04:00
FFI_TYPE_POINTER | FFI_TYPE_STRUCT = > {
let result = * ( ( * val ) as * const u64 ) ;
if result > MAX_SAFE_INTEGER as u64 {
v8 ::BigInt ::new_from_u64 ( scope , result ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
}
}
FFI_TYPE_VOID = > v8 ::undefined ( scope ) . into ( ) ,
2022-01-05 02:25:31 -05:00
_ = > {
2022-06-20 07:06:04 -04:00
unreachable! ( )
2021-10-05 18:27:05 -04:00
}
2022-06-20 07:06:04 -04:00
} ;
params . push ( value ) ;
2022-01-05 02:25:31 -05:00
}
2021-08-06 17:28:10 -04:00
2022-07-24 06:41:11 -04:00
let recv = v8 ::undefined ( scope ) ;
let call_result = func . call ( scope , recv . into ( ) , & params ) ;
2022-06-20 07:06:04 -04:00
std ::mem ::forget ( callback ) ;
if call_result . is_none ( ) {
// JS function threw an exception. Set the return value to zero and return.
// The exception continue propagating up the call chain when the event loop
// resumes.
match ( * cif . rtype ) . type_ as _ {
FFI_TYPE_INT | FFI_TYPE_SINT32 | FFI_TYPE_UINT32 = > {
// zero is equal for signed and unsigned alike
* ( result as * mut u32 ) = 0 ;
}
FFI_TYPE_FLOAT = > {
* ( result as * mut f32 ) = 0.0 ;
}
FFI_TYPE_DOUBLE = > {
* ( result as * mut f64 ) = 0.0 ;
}
FFI_TYPE_SINT8 | FFI_TYPE_UINT8 = > {
// zero is equal for signed and unsigned alike
* ( result as * mut u8 ) = 0 ;
}
FFI_TYPE_SINT16 | FFI_TYPE_UINT16 = > {
// zero is equal for signed and unsigned alike
* ( result as * mut u16 ) = 0 ;
}
FFI_TYPE_POINTER | FFI_TYPE_STRUCT | FFI_TYPE_UINT64
| FFI_TYPE_SINT64 = > {
2022-07-24 06:41:11 -04:00
* ( result as * mut usize ) = 0 ;
2022-06-20 07:06:04 -04:00
}
FFI_TYPE_VOID = > {
// nop
}
_ = > {
unreachable! ( ) ;
}
} ;
2021-08-06 17:28:10 -04:00
2022-06-20 07:06:04 -04:00
return ;
}
let value = call_result . unwrap ( ) ;
match ( * cif . rtype ) . type_ as _ {
FFI_TYPE_INT | FFI_TYPE_SINT32 = > {
2022-07-24 06:41:11 -04:00
let value = if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
value . value ( ) as i32
} else {
// Fallthrough, probably UB.
value
. int32_value ( scope )
. expect ( " Unable to deserialize result parameter. " ) as i32
} ;
* ( result as * mut i32 ) = value ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_FLOAT = > {
2022-07-24 06:41:11 -04:00
let value = if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( value ) {
value . value ( ) as f32
} else {
// Fallthrough, probably UB.
value
. number_value ( scope )
. expect ( " Unable to deserialize result parameter. " ) as f32
} ;
* ( result as * mut f32 ) = value ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_DOUBLE = > {
2022-07-24 06:41:11 -04:00
let value = if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( value ) {
value . value ( )
} else {
// Fallthrough, probably UB.
value
. number_value ( scope )
. expect ( " Unable to deserialize result parameter. " )
} ;
* ( result as * mut f64 ) = value ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_POINTER | FFI_TYPE_STRUCT = > {
2022-07-24 06:41:11 -04:00
let pointer = if let Ok ( value ) =
v8 ::Local ::< v8 ::ArrayBufferView > ::try_from ( value )
{
2022-06-20 23:46:59 -04:00
let byte_offset = value . byte_offset ( ) ;
let backing_store = value
2022-07-24 06:41:11 -04:00
. buffer ( scope )
2022-06-20 23:46:59 -04:00
. expect ( " Unable to deserialize result parameter. " )
. get_backing_store ( ) ;
2022-07-27 01:43:30 -04:00
& backing_store [ byte_offset .. ] as * const _ as * const u8
2022-07-24 06:41:11 -04:00
} else if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( value ) {
value . u64_value ( ) . 0 as usize as * const u8
2022-06-20 23:46:59 -04:00
} else if let Ok ( value ) = v8 ::Local ::< v8 ::ArrayBuffer > ::try_from ( value ) {
let backing_store = value . get_backing_store ( ) ;
2022-07-24 06:41:11 -04:00
& backing_store [ .. ] as * const _ as * const u8
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
value . value ( ) as usize as * const u8
2022-06-20 07:06:04 -04:00
} else if value . is_null ( ) {
2022-07-24 06:41:11 -04:00
ptr ::null ( )
2022-06-20 07:06:04 -04:00
} else {
// Fallthrough: Probably someone returned a number but this could
// also be eg. a string. This is essentially UB.
2022-07-24 06:41:11 -04:00
value
. integer_value ( scope )
. expect ( " Unable to deserialize result parameter. " ) as usize
as * const u8
} ;
* ( result as * mut * const u8 ) = pointer ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_SINT8 = > {
2022-07-24 06:41:11 -04:00
let value = if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
value . value ( ) as i8
} else {
// Fallthrough, essentially UB.
value
. int32_value ( scope )
. expect ( " Unable to deserialize result parameter. " ) as i8
} ;
* ( result as * mut i8 ) = value ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_UINT8 = > {
2022-07-24 06:41:11 -04:00
let value = if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
value . value ( ) as u8
} else {
// Fallthrough, essentially UB.
value
. uint32_value ( scope )
. expect ( " Unable to deserialize result parameter. " ) as u8
} ;
* ( result as * mut u8 ) = value ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_SINT16 = > {
2022-07-24 06:41:11 -04:00
let value = if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
value . value ( ) as i16
} else {
// Fallthrough, essentially UB.
value
. int32_value ( scope )
. expect ( " Unable to deserialize result parameter. " ) as i16
} ;
* ( result as * mut i16 ) = value ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_UINT16 = > {
2022-07-24 06:41:11 -04:00
let value = if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
value . value ( ) as u16
} else {
// Fallthrough, essentially UB.
value
. uint32_value ( scope )
. expect ( " Unable to deserialize result parameter. " ) as u16
} ;
* ( result as * mut u16 ) = value ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_UINT32 = > {
2022-07-24 06:41:11 -04:00
let value = if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
value . value ( ) as u32
} else {
// Fallthrough, essentially UB.
value
. uint32_value ( scope )
. expect ( " Unable to deserialize result parameter. " )
} ;
* ( result as * mut u32 ) = value ;
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_SINT64 = > {
2022-06-20 23:46:59 -04:00
if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( value ) {
2022-06-20 07:06:04 -04:00
* ( result as * mut i64 ) = value . i64_value ( ) . 0 ;
2022-07-24 06:41:11 -04:00
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
* ( result as * mut i64 ) = value . value ( ) ;
2022-06-20 07:06:04 -04:00
} else {
* ( result as * mut i64 ) = value
2022-07-24 06:41:11 -04:00
. integer_value ( scope )
2022-06-20 07:06:04 -04:00
. expect ( " Unable to deserialize result parameter. " )
as i64 ;
}
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_UINT64 = > {
2022-06-20 23:46:59 -04:00
if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( value ) {
2022-06-20 07:06:04 -04:00
* ( result as * mut u64 ) = value . u64_value ( ) . 0 ;
2022-07-24 06:41:11 -04:00
} else if let Ok ( value ) = v8 ::Local ::< v8 ::Integer > ::try_from ( value ) {
* ( result as * mut u64 ) = value . value ( ) as u64 ;
2022-06-20 07:06:04 -04:00
} else {
* ( result as * mut u64 ) = value
2022-07-24 06:41:11 -04:00
. integer_value ( scope )
2022-06-20 07:06:04 -04:00
. expect ( " Unable to deserialize result parameter. " )
as u64 ;
}
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
FFI_TYPE_VOID = > {
// nop
2021-08-06 17:28:10 -04:00
}
2022-06-20 07:06:04 -04:00
_ = > {
unreachable! ( ) ;
2021-12-15 09:41:49 -05:00
}
2022-06-20 07:06:04 -04:00
} ;
2021-08-06 17:28:10 -04:00
}
2021-10-05 08:50:00 -04:00
2022-06-20 07:06:04 -04:00
#[ derive(Deserialize) ]
struct RegisterCallbackArgs {
parameters : Vec < NativeType > ,
result : NativeType ,
}
#[ op(v8) ]
fn op_ffi_unsafe_callback_create < FP , ' scope > (
2022-03-25 07:29:54 -04:00
state : & mut deno_core ::OpState ,
2022-06-20 07:06:04 -04:00
scope : & mut v8 ::HandleScope < ' scope > ,
args : RegisterCallbackArgs ,
cb : serde_v8 ::Value < ' scope > ,
) -> Result < serde_v8 ::Value < ' scope > , AnyError >
2022-03-25 07:29:54 -04:00
where
FP : FfiPermissions + 'static ,
{
2022-06-20 07:06:04 -04:00
check_unstable ( state , " Deno.UnsafeCallback " ) ;
2022-03-25 07:29:54 -04:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-20 07:06:04 -04:00
let v8_value = cb . v8_value ;
let cb = v8 ::Local ::< v8 ::Function > ::try_from ( v8_value ) ? ;
let isolate : * mut v8 ::Isolate = & mut * scope as & mut v8 ::Isolate ;
2022-06-28 05:23:36 -04:00
LOCAL_ISOLATE_POINTER . with ( | s | {
if s . borrow ( ) . is_null ( ) {
s . replace ( isolate ) ;
}
} ) ;
let async_work_sender =
state . borrow_mut ::< FfiState > ( ) . async_work_sender . clone ( ) ;
2022-06-20 07:06:04 -04:00
let callback = v8 ::Global ::new ( scope , cb ) . into_raw ( ) ;
let current_context = scope . get_current_context ( ) ;
let context = v8 ::Global ::new ( scope , current_context ) . into_raw ( ) ;
let info = Box ::leak ( Box ::new ( CallbackInfo {
2022-06-28 05:23:36 -04:00
async_work_sender ,
2022-06-20 07:06:04 -04:00
callback ,
context ,
isolate ,
} ) ) ;
let cif = Cif ::new (
args . parameters . into_iter ( ) . map ( libffi ::middle ::Type ::from ) ,
libffi ::middle ::Type ::from ( args . result ) ,
) ;
let closure = libffi ::middle ::Closure ::new ( cif , deno_ffi_callback , info ) ;
2022-07-24 06:41:11 -04:00
let ptr = * closure . code_ptr ( ) as usize ;
2022-06-20 07:06:04 -04:00
let resource = UnsafeCallbackResource { closure , info } ;
let rid = state . resource_table . add ( resource ) ;
let rid_local = v8 ::Integer ::new_from_unsigned ( scope , rid ) ;
2022-07-24 06:41:11 -04:00
let ptr_local : v8 ::Local < v8 ::Value > = if ptr > MAX_SAFE_INTEGER as usize {
v8 ::BigInt ::new_from_u64 ( scope , ptr as u64 ) . into ( )
} else {
v8 ::Number ::new ( scope , ptr as f64 ) . into ( )
} ;
2022-06-20 07:06:04 -04:00
let array = v8 ::Array ::new ( scope , 2 ) ;
array . set_index ( scope , 0 , rid_local . into ( ) ) ;
2022-07-24 06:41:11 -04:00
array . set_index ( scope , 1 , ptr_local ) ;
2022-06-20 07:06:04 -04:00
let array_value : v8 ::Local < v8 ::Value > = array . into ( ) ;
Ok ( array_value . into ( ) )
2022-01-12 06:38:26 -05:00
}
2022-06-20 07:06:04 -04:00
#[ op(v8) ]
fn op_ffi_call_ptr < FP , ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
2022-03-25 07:29:54 -04:00
state : Rc < RefCell < deno_core ::OpState > > ,
2022-07-24 06:41:11 -04:00
pointer : usize ,
2022-06-20 07:06:04 -04:00
def : ForeignFunction ,
parameters : serde_v8 ::Value < ' scope > ,
) -> Result < serde_v8 ::Value < ' scope > , AnyError >
2022-03-25 07:29:54 -04:00
where
FP : FfiPermissions + 'static ,
{
check_unstable2 ( & state , " Deno.UnsafeFnPointer#call " ) ;
{
let mut state = state . borrow_mut ( ) ;
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-20 07:06:04 -04:00
} ;
2022-03-25 07:29:54 -04:00
2022-06-20 07:06:04 -04:00
let symbol = PtrSymbol ::new ( pointer , & def ) ;
let call_args = ffi_parse_args ( scope , parameters , & def . parameters ) ? ;
let result = ffi_call (
call_args ,
& symbol . cif ,
symbol . ptr ,
& def . parameters ,
def . result ,
) ? ;
// SAFETY: Same return type declared to libffi; trust user to have it right beyond that.
let result = unsafe { result . to_v8 ( scope , def . result ) } ;
Ok ( result )
2022-01-12 06:38:26 -05:00
}
2022-06-28 05:23:36 -04:00
#[ op ]
fn op_ffi_unsafe_callback_ref ( state : & mut deno_core ::OpState , inc_dec : bool ) {
2022-08-09 23:09:45 -04:00
check_unstable ( state , " Deno.dlopen " ) ;
2022-06-28 05:23:36 -04:00
let ffi_state = state . borrow_mut ::< FfiState > ( ) ;
if inc_dec {
ffi_state . active_refed_functions + = 1 ;
} else {
ffi_state . active_refed_functions - = 1 ;
}
}
2022-06-20 07:06:04 -04:00
#[ op(v8) ]
fn op_ffi_call_ptr_nonblocking < ' scope , FP > (
scope : & mut v8 ::HandleScope < ' scope > ,
state : Rc < RefCell < deno_core ::OpState > > ,
2022-07-24 06:41:11 -04:00
pointer : usize ,
2022-06-20 07:06:04 -04:00
def : ForeignFunction ,
parameters : serde_v8 ::Value < ' scope > ,
) -> Result < impl Future < Output = Result < Value , AnyError > > , AnyError >
where
FP : FfiPermissions + 'static ,
{
check_unstable2 ( & state , " Deno.UnsafeFnPointer#call " ) ;
{
let mut state = state . borrow_mut ( ) ;
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
} ;
let symbol = PtrSymbol ::new ( pointer , & def ) ;
let call_args = ffi_parse_args ( scope , parameters , & def . parameters ) ? ;
let join_handle = tokio ::task ::spawn_blocking ( move | | {
let PtrSymbol { cif , ptr } = symbol . clone ( ) ;
ffi_call ( call_args , & cif , ptr , & def . parameters , def . result )
} ) ;
Ok ( async move {
let result = join_handle
. await
. map_err ( | err | anyhow! ( " Nonblocking FFI call failed: {} " , err ) ) ? ? ;
// SAFETY: Same return type declared to libffi; trust user to have it right beyond that.
Ok ( unsafe { result . to_value ( def . result ) } )
} )
2022-02-18 07:21:19 -05:00
}
2022-06-20 07:06:04 -04:00
#[ op(v8) ]
fn op_ffi_get_static < ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
2022-02-18 07:21:19 -05:00
state : & mut deno_core ::OpState ,
2022-06-20 07:06:04 -04:00
rid : ResourceId ,
name : String ,
static_type : NativeType ,
) -> Result < serde_v8 ::Value < ' scope > , AnyError > {
let resource = state . resource_table . get ::< DynamicLibraryResource > ( rid ) ? ;
2022-02-18 07:21:19 -05:00
2022-06-22 22:49:07 -04:00
let data_ptr = resource . get_static ( name ) ? ;
2022-02-18 07:21:19 -05:00
2022-06-20 07:06:04 -04:00
Ok ( match static_type {
2022-02-18 07:21:19 -05:00
NativeType ::Void = > {
2022-06-20 07:06:04 -04:00
return Err ( type_error ( " Invalid FFI static type 'void' " ) ) ;
2022-02-18 07:21:19 -05:00
}
NativeType ::U8 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const u8 ) } ;
2022-06-22 22:49:07 -04:00
let number : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new_from_unsigned ( scope , result as u32 ) . into ( ) ;
number . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::I8 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const i8 ) } ;
2022-06-22 22:49:07 -04:00
let number : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new ( scope , result as i32 ) . into ( ) ;
number . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::U16 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const u16 ) } ;
2022-06-22 22:49:07 -04:00
let number : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new_from_unsigned ( scope , result as u32 ) . into ( ) ;
number . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::I16 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const i16 ) } ;
2022-06-22 22:49:07 -04:00
let number : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new ( scope , result as i32 ) . into ( ) ;
number . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::U32 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const u32 ) } ;
2022-06-22 22:49:07 -04:00
let number : v8 ::Local < v8 ::Value > =
v8 ::Integer ::new_from_unsigned ( scope , result ) . into ( ) ;
number . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::I32 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const i32 ) } ;
2022-06-22 22:49:07 -04:00
let number : v8 ::Local < v8 ::Value > = v8 ::Integer ::new ( scope , result ) . into ( ) ;
number . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::U64 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const u64 ) } ;
2022-07-24 06:41:11 -04:00
let integer : v8 ::Local < v8 ::Value > = if result > MAX_SAFE_INTEGER as u64 {
v8 ::BigInt ::new_from_u64 ( scope , result ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
} ;
integer . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::I64 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const i64 ) } ;
2022-07-24 06:41:11 -04:00
let integer : v8 ::Local < v8 ::Value > = if result > MAX_SAFE_INTEGER as i64
| | result < MIN_SAFE_INTEGER as i64
{
v8 ::BigInt ::new_from_i64 ( scope , result ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
} ;
integer . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::USize = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const usize ) } ;
2022-07-24 06:41:11 -04:00
let integer : v8 ::Local < v8 ::Value > = if result > MAX_SAFE_INTEGER as usize
{
v8 ::BigInt ::new_from_u64 ( scope , result as u64 ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
} ;
integer . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::ISize = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const isize ) } ;
2022-07-24 06:41:11 -04:00
let integer : v8 ::Local < v8 ::Value > =
2022-08-21 13:31:14 -04:00
if ! ( MIN_SAFE_INTEGER ..= MAX_SAFE_INTEGER ) . contains ( & result ) {
2022-07-24 06:41:11 -04:00
v8 ::BigInt ::new_from_i64 ( scope , result as i64 ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
} ;
integer . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::F32 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const f32 ) } ;
2022-06-22 22:49:07 -04:00
let number : v8 ::Local < v8 ::Value > =
v8 ::Number ::new ( scope , result as f64 ) . into ( ) ;
number . into ( )
2022-02-18 07:21:19 -05:00
}
NativeType ::F64 = > {
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( data_ptr as * const f64 ) } ;
2022-06-22 22:49:07 -04:00
let number : v8 ::Local < v8 ::Value > = v8 ::Number ::new ( scope , result ) . into ( ) ;
number . into ( )
2022-02-18 07:21:19 -05:00
}
2022-08-22 23:46:43 -04:00
NativeType ::Pointer | NativeType ::Function | NativeType ::Buffer = > {
2022-06-22 22:49:07 -04:00
let result = data_ptr as u64 ;
2022-07-24 06:41:11 -04:00
let integer : v8 ::Local < v8 ::Value > = if result > MAX_SAFE_INTEGER as u64 {
v8 ::BigInt ::new_from_u64 ( scope , result ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
} ;
integer . into ( )
2022-02-18 07:21:19 -05:00
}
} )
}
2021-10-05 08:50:00 -04:00
/// A non-blocking FFI call.
2022-06-20 07:06:04 -04:00
#[ op(v8) ]
fn op_ffi_call_nonblocking < ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
2021-10-05 08:50:00 -04:00
state : Rc < RefCell < deno_core ::OpState > > ,
2022-06-20 07:06:04 -04:00
rid : ResourceId ,
symbol : String ,
parameters : serde_v8 ::Value < ' scope > ,
) -> Result < impl Future < Output = Result < Value , AnyError > > + 'static , AnyError > {
let symbol = {
let state = state . borrow ( ) ;
let resource = state . resource_table . get ::< DynamicLibraryResource > ( rid ) ? ;
let symbols = & resource . symbols ;
2022-06-29 04:13:33 -04:00
* symbols
2022-06-20 07:06:04 -04:00
. get ( & symbol )
. ok_or_else ( | | type_error ( " Invalid FFI symbol name " ) ) ?
. clone ( )
} ;
let call_args = ffi_parse_args ( scope , parameters , & symbol . parameter_types ) ? ;
let result_type = symbol . result_type ;
let join_handle = tokio ::task ::spawn_blocking ( move | | {
let Symbol {
cif ,
ptr ,
parameter_types ,
2022-06-25 18:13:24 -04:00
result_type ,
2022-07-09 09:11:07 -04:00
..
2022-06-20 07:06:04 -04:00
} = symbol . clone ( ) ;
ffi_call ( call_args , & cif , ptr , & parameter_types , result_type )
} ) ;
Ok ( async move {
let result = join_handle
. await
. map_err ( | err | anyhow! ( " Nonblocking FFI call failed: {} " , err ) ) ? ? ;
// SAFETY: Same return type declared to libffi; trust user to have it right beyond that.
Ok ( unsafe { result . to_value ( result_type ) } )
} )
2021-10-05 08:50:00 -04:00
}
2021-10-05 20:13:56 -04:00
2022-06-20 07:06:04 -04:00
#[ op(v8) ]
fn op_ffi_ptr_of < FP , ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
2021-12-15 09:41:49 -05:00
state : & mut deno_core ::OpState ,
2022-07-22 07:07:35 -04:00
buf : serde_v8 ::Value < ' scope > ,
2022-06-20 07:06:04 -04:00
) -> Result < serde_v8 ::Value < ' scope > , AnyError >
2021-12-15 09:41:49 -05:00
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointer#of " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-07-22 07:07:35 -04:00
let pointer = if let Ok ( value ) =
v8 ::Local ::< v8 ::ArrayBufferView > ::try_from ( buf . v8_value )
{
let backing_store = value
. buffer ( scope )
. ok_or_else ( | | {
type_error ( " Invalid FFI ArrayBufferView, expected data in the buffer " )
} ) ?
. get_backing_store ( ) ;
let byte_offset = value . byte_offset ( ) ;
2022-07-27 01:43:30 -04:00
& backing_store [ byte_offset .. ] as * const _ as * const u8
2022-07-22 07:07:35 -04:00
} else if let Ok ( value ) = v8 ::Local ::< v8 ::ArrayBuffer > ::try_from ( buf . v8_value )
{
let backing_store = value . get_backing_store ( ) ;
& backing_store [ .. ] as * const _ as * const u8
} else {
return Err ( type_error (
" Invalid FFI buffer, expected ArrayBuffer, or ArrayBufferView " ,
) ) ;
} ;
2022-07-24 06:41:11 -04:00
let integer : v8 ::Local < v8 ::Value > =
if pointer as usize > MAX_SAFE_INTEGER as usize {
v8 ::BigInt ::new_from_u64 ( scope , pointer as u64 ) . into ( )
} else {
v8 ::Number ::new ( scope , pointer as usize as f64 ) . into ( )
} ;
Ok ( integer . into ( ) )
2021-12-15 09:41:49 -05:00
}
2022-07-23 13:11:06 -04:00
unsafe extern " C " fn noop_deleter_callback (
_data : * mut c_void ,
_byte_length : usize ,
_deleter_data : * mut c_void ,
) {
}
#[ op(v8) ]
fn op_ffi_get_buf < FP , ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
state : & mut deno_core ::OpState ,
src : serde_v8 ::Value < ' scope > ,
len : usize ,
) -> Result < serde_v8 ::Value < ' scope > , AnyError >
where
FP : FfiPermissions + 'static ,
{
check_unstable ( state , " Deno.UnsafePointerView#arrayBuffer " ) ;
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-07-24 06:41:11 -04:00
let ptr = if let Ok ( value ) = v8 ::Local ::< v8 ::Number > ::try_from ( src . v8_value ) {
value . value ( ) as usize as * mut c_void
} else if let Ok ( value ) = v8 ::Local ::< v8 ::BigInt > ::try_from ( src . v8_value ) {
value . u64_value ( ) . 0 as usize as * mut c_void
} else {
return Err ( type_error ( " Invalid FFI pointer value, expected BigInt " ) ) ;
} ;
2022-07-23 13:11:06 -04:00
if std ::ptr ::eq ( ptr , std ::ptr ::null ( ) ) {
return Err ( type_error ( " Invalid FFI pointer value, got nullptr " ) ) ;
}
// SAFETY: Trust the user to have provided a real pointer, and a valid matching size to it. Since this is a foreign pointer, we should not do any deletion.
let backing_store = unsafe {
v8 ::ArrayBuffer ::new_backing_store_from_ptr (
ptr ,
len ,
noop_deleter_callback ,
std ::ptr ::null_mut ( ) ,
)
}
. make_shared ( ) ;
let array_buffer : v8 ::Local < v8 ::Value > =
v8 ::ArrayBuffer ::with_backing_store ( scope , & backing_store ) . into ( ) ;
Ok ( array_buffer . into ( ) )
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_buf_copy_into < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
src : usize ,
2022-06-20 07:06:04 -04:00
mut dst : ZeroCopyBuf ,
len : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < ( ) , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#copyInto " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
if dst . len ( ) < len {
Err ( range_error (
" Destination length is smaller than source length " ,
) )
} else {
2022-06-20 07:06:04 -04:00
let src = src as * const u8 ;
2022-06-25 18:13:24 -04:00
// SAFETY: src is user defined.
// dest is properly aligned and is valid for writes of len * size_of::<T>() bytes.
2021-12-15 09:41:49 -05:00
unsafe { ptr ::copy ( src , dst . as_mut_ptr ( ) , len ) } ;
Ok ( ( ) )
}
}
2022-07-22 07:07:35 -04:00
#[ op(v8) ]
fn op_ffi_cstr_read < FP , ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
2021-12-15 09:41:49 -05:00
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2022-07-22 07:07:35 -04:00
) -> Result < serde_v8 ::Value < ' scope > , AnyError >
2021-12-15 09:41:49 -05:00
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getCString " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-07-22 07:07:35 -04:00
// SAFETY: Pointer is user provided.
2022-08-05 12:26:54 -04:00
let cstr = unsafe { CStr ::from_ptr ( ptr as * const c_char ) }
. to_str ( )
. map_err ( | _ | type_error ( " Invalid CString pointer, not valid UTF-8 " ) ) ? ;
let value : v8 ::Local < v8 ::Value > = v8 ::String ::new ( scope , cstr )
. ok_or_else ( | | {
type_error ( " Invalid CString pointer, string exceeds max length " )
} ) ?
. into ( ) ;
2022-07-22 07:07:35 -04:00
Ok ( value . into ( ) )
2021-12-15 09:41:49 -05:00
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_read_u8 < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < u8 , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getUint8 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
Ok ( unsafe { ptr ::read_unaligned ( ptr as * const u8 ) } )
2021-12-15 09:41:49 -05:00
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_read_i8 < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < i8 , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getInt8 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
Ok ( unsafe { ptr ::read_unaligned ( ptr as * const i8 ) } )
2021-12-15 09:41:49 -05:00
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_read_u16 < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < u16 , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getUint16 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
Ok ( unsafe { ptr ::read_unaligned ( ptr as * const u16 ) } )
2021-12-15 09:41:49 -05:00
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_read_i16 < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < i16 , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getInt16 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
Ok ( unsafe { ptr ::read_unaligned ( ptr as * const i16 ) } )
2021-12-15 09:41:49 -05:00
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_read_u32 < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < u32 , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getUint32 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
Ok ( unsafe { ptr ::read_unaligned ( ptr as * const u32 ) } )
2021-12-15 09:41:49 -05:00
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_read_i32 < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < i32 , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getInt32 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
Ok ( unsafe { ptr ::read_unaligned ( ptr as * const i32 ) } )
2021-12-15 09:41:49 -05:00
}
2022-06-20 07:06:04 -04:00
#[ op(v8) ]
fn op_ffi_read_u64 < FP , ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
2021-12-15 09:41:49 -05:00
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2022-06-20 07:06:04 -04:00
) -> Result < serde_v8 ::Value < ' scope > , AnyError >
2021-12-15 09:41:49 -05:00
where
FP : FfiPermissions + 'static ,
2022-06-20 07:06:04 -04:00
' scope : ' scope ,
2021-12-15 09:41:49 -05:00
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getBigUint64 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
let result = unsafe { ptr ::read_unaligned ( ptr as * const u64 ) } ;
2022-07-24 06:41:11 -04:00
let integer : v8 ::Local < v8 ::Value > = if result > MAX_SAFE_INTEGER as u64 {
v8 ::BigInt ::new_from_u64 ( scope , result ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
} ;
Ok ( integer . into ( ) )
}
#[ op(v8) ]
fn op_ffi_read_i64 < FP , ' scope > (
scope : & mut v8 ::HandleScope < ' scope > ,
state : & mut deno_core ::OpState ,
ptr : usize ,
) -> Result < serde_v8 ::Value < ' scope > , AnyError >
where
FP : FfiPermissions + 'static ,
' scope : ' scope ,
{
check_unstable ( state , " Deno.UnsafePointerView#getBigUint64 " ) ;
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
// SAFETY: ptr is user provided.
let result = unsafe { ptr ::read_unaligned ( ptr as * const i64 ) } ;
let integer : v8 ::Local < v8 ::Value > =
if result > MAX_SAFE_INTEGER as i64 | | result < MIN_SAFE_INTEGER as i64 {
v8 ::BigInt ::new_from_i64 ( scope , result ) . into ( )
} else {
v8 ::Number ::new ( scope , result as f64 ) . into ( )
} ;
Ok ( integer . into ( ) )
2021-12-15 09:41:49 -05:00
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_read_f32 < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < f32 , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getFloat32 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
Ok ( unsafe { ptr ::read_unaligned ( ptr as * const f32 ) } )
2021-12-15 09:41:49 -05:00
}
2022-03-14 13:44:15 -04:00
#[ op ]
2021-12-15 09:41:49 -05:00
fn op_ffi_read_f64 < FP > (
state : & mut deno_core ::OpState ,
2022-07-24 06:41:11 -04:00
ptr : usize ,
2021-12-15 09:41:49 -05:00
) -> Result < f64 , AnyError >
where
FP : FfiPermissions + 'static ,
{
2022-03-25 07:29:54 -04:00
check_unstable ( state , " Deno.UnsafePointerView#getFloat64 " ) ;
2021-12-15 09:41:49 -05:00
let permissions = state . borrow_mut ::< FP > ( ) ;
permissions . check ( None ) ? ;
2022-06-25 18:13:24 -04:00
// SAFETY: ptr is user provided.
2022-06-20 07:06:04 -04:00
Ok ( unsafe { ptr ::read_unaligned ( ptr as * const f64 ) } )
2021-12-15 09:41:49 -05:00
}
2021-10-05 20:13:56 -04:00
#[ cfg(test) ]
mod tests {
#[ cfg(target_os = " windows " ) ]
#[ test ]
fn test_format_error ( ) {
use super ::format_error ;
// BAD_EXE_FORMAT
let err = dlopen ::Error ::OpeningLibraryError (
std ::io ::Error ::from_raw_os_error ( 0x000000C1 ) ,
) ;
assert_eq! (
format_error ( err , " foo.dll " . to_string ( ) ) ,
" foo.dll is not a valid Win32 application. \r \n " . to_string ( ) ,
) ;
}
}