diff options
author | Dj <43033058+DjDeveloperr@users.noreply.github.com> | 2023-01-07 19:58:10 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-08 09:28:10 +0530 |
commit | ad82918f56b215a428ebe7c533ee825e1152d1b4 (patch) | |
tree | 2669f9d8d419a88e9d58b12b98579e884aec6988 /ext/ffi/callback.rs | |
parent | 84ef26ac9b5f0e1199d77837cd97cb203baa8729 (diff) |
feat(ext/ffi): structs by value (#15060)
Adds support for passing and returning structs as buffers to FFI. This does not implement fastapi support for structs. Needed for certain system APIs such as AppKit on macOS.
Diffstat (limited to 'ext/ffi/callback.rs')
-rw-r--r-- | ext/ffi/callback.rs | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/ext/ffi/callback.rs b/ext/ffi/callback.rs index b9398c790..d6ef51823 100644 --- a/ext/ffi/callback.rs +++ b/ext/ffi/callback.rs @@ -48,7 +48,7 @@ impl PtrSymbol { .clone() .into_iter() .map(libffi::middle::Type::from), - def.result.into(), + def.result.clone().into(), ); Self { cif, ptr } @@ -113,7 +113,7 @@ impl Future for CallbackInfo { } } unsafe extern "C" fn deno_ffi_callback( - _cif: &libffi::low::ffi_cif, + cif: &libffi::low::ffi_cif, result: &mut c_void, args: *const *const c_void, info: &CallbackInfo, @@ -121,15 +121,16 @@ unsafe extern "C" fn deno_ffi_callback( LOCAL_ISOLATE_POINTER.with(|s| { if ptr::eq(*s.borrow(), info.isolate) { // Own isolate thread, okay to call directly - do_ffi_callback(info, result, args); + do_ffi_callback(cif, info, result, args); } 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(info, result, args); + do_ffi_callback(cif, info, result, args); response_sender.send(()).unwrap(); }); async_work_sender.unbounded_send(fut).unwrap(); @@ -143,6 +144,7 @@ unsafe extern "C" fn deno_ffi_callback( } unsafe fn do_ffi_callback( + cif: &libffi::low::ffi_cif, info: &CallbackInfo, result: &mut c_void, args: *const *const c_void, @@ -172,9 +174,12 @@ unsafe fn do_ffi_callback( let result = result as *mut c_void; let vals: &[*const c_void] = std::slice::from_raw_parts(args, info.parameters.len()); + let arg_types = std::slice::from_raw_parts(cif.arg_types, cif.nargs as usize); let mut params: Vec<v8::Local<v8::Value>> = vec![]; - for (native_type, val) in info.parameters.iter().zip(vals) { + for ((index, native_type), val) in + info.parameters.iter().enumerate().zip(vals) + { let value: v8::Local<v8::Value> = match native_type { NativeType::Bool => { let value = *((*val) as *const bool); @@ -237,6 +242,20 @@ unsafe fn do_ffi_callback( v8::Number::new(scope, result as f64).into() } } + NativeType::Struct(_) => { + let size = arg_types[index].as_ref().unwrap().size; + let ptr = (*val) as *const u8; + let slice = std::slice::from_raw_parts(ptr, size); + let boxed = Box::from(slice); + let store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(boxed); + let ab = + v8::ArrayBuffer::with_backing_store(scope, &store.make_shared()); + let local_value: v8::Local<v8::Value> = + v8::Uint8Array::new(scope, ab, 0, ab.byte_length()) + .unwrap() + .into(); + local_value + } NativeType::Void => unreachable!(), }; params.push(value); @@ -440,6 +459,35 @@ unsafe fn do_ffi_callback( as u64; } } + NativeType::Struct(_) => { + let size; + let pointer = if let Ok(value) = + v8::Local::<v8::ArrayBufferView>::try_from(value) + { + let byte_offset = value.byte_offset(); + let ab = value + .buffer(scope) + .expect("Unable to deserialize result parameter."); + size = value.byte_length(); + ab.data() + .expect("Unable to deserialize result parameter.") + .as_ptr() + .add(byte_offset) + } else if let Ok(value) = v8::Local::<v8::ArrayBuffer>::try_from(value) { + size = value.byte_length(); + value + .data() + .expect("Unable to deserialize result parameter.") + .as_ptr() + } else { + panic!("Unable to deserialize result parameter."); + }; + std::ptr::copy_nonoverlapping( + pointer as *mut u8, + result as *mut u8, + std::cmp::min(size, (*cif.rtype).size), + ); + } NativeType::Void => { // nop } @@ -522,7 +570,7 @@ where let info: *mut CallbackInfo = Box::leak(Box::new(CallbackInfo { parameters: args.parameters.clone(), - result: args.result, + result: args.result.clone(), async_work_sender, callback, context, |