diff options
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, |