From 7ce5be248f13a15e383d286015fbd0518db89340 Mon Sep 17 00:00:00 2001 From: qwreey Date: Mon, 14 Oct 2024 03:15:16 +0000 Subject: [PATCH] Add uninit ref and Implement Callable (#243) --- crates/lune-std-ffi/src/c/c_fn.rs | 75 ++++++++++++---- crates/lune-std-ffi/src/c/mod.rs | 4 + crates/lune-std-ffi/src/ffi/ffi_callable.rs | 88 +++++-------------- crates/lune-std-ffi/src/ffi/ffi_native/arg.rs | 2 +- crates/lune-std-ffi/src/ffi/ffi_native/mod.rs | 12 ++- .../lune-std-ffi/src/ffi/ffi_native/result.rs | 12 +-- crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs | 30 +++++-- crates/lune-std-ffi/src/ffi/mod.rs | 3 +- 8 files changed, 126 insertions(+), 100 deletions(-) diff --git a/crates/lune-std-ffi/src/c/c_fn.rs b/crates/lune-std-ffi/src/c/c_fn.rs index dd6e2fc..d6cfbbf 100644 --- a/crates/lune-std-ffi/src/c/c_fn.rs +++ b/crates/lune-std-ffi/src/c/c_fn.rs @@ -1,13 +1,20 @@ +use std::ptr; + use libffi::low::ffi_cif; use libffi::middle::{Cif, Type}; use mlua::prelude::*; -use super::c_helper::{ - get_conv, get_conv_list_from_table, libffi_type_from_userdata, libffi_type_list_from_table, +use super::{ + association_names::{CALLABLE_CFN, CALLABLE_REF, CFN_ARGS, CFN_RESULT}, + c_helper::{ + get_conv, get_conv_list_from_table, libffi_type_from_userdata, libffi_type_list_from_table, + }, }; +use crate::ffi::bit_mask::u8_test_not; use crate::ffi::{ - FfiClosure, NativeArgInfo, NativeArgType, NativeConvert, NativeResultInfo, NativeResultType, + ffi_association::set_association, FfiClosure, NativeArgInfo, NativeConvert, NativeResultInfo, }; +use crate::ffi::{FfiCallable, FfiRef, FfiRefFlag, NativeData}; // cfn is a type declaration for a function. // Basically, when calling an external function, this type declaration @@ -47,31 +54,67 @@ impl CFn { } } - pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { + pub fn new_from_lua_table<'lua>( + lua: &'lua Lua, + args: LuaTable, + ret: LuaAnyUserData, + ) -> LuaResult> { let args_types = libffi_type_list_from_table(lua, &args)?; let ret_type = libffi_type_from_userdata(lua, &ret)?; - let len = args.raw_len(); - let mut arg_info_list = Vec::::with_capacity(len); - + let mut arg_info_list = Vec::::with_capacity(args.raw_len()); for conv in unsafe { get_conv_list_from_table(&args)? } { arg_info_list.push(NativeArgInfo { conv }) } - // get_conv_list_from_table(&args)?.iter().map(|conv| { - // conv.to_owned() - // }).collect() + let result_info = NativeResultInfo { + conv: unsafe { get_conv(&ret)? }, + }; - Ok(Self::new(args_types, ret_type, unsafe {}, unsafe { - get_conv(&ret)? - })) + let cfn = + lua.create_userdata(Self::new(args_types, ret_type, arg_info_list, result_info))?; + + // Create association to hold argument and result type + set_association(lua, CFN_ARGS, &cfn, args)?; + set_association(lua, CFN_ARGS, &cfn, ret)?; + + Ok(cfn) } } impl LuaUserData for CFn { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method("closure", |lua, this, func: LuaFunction| { - lua.create_userdata(FfiClosure::new(this.cif, userdata)) - }) + // methods.add_method("closure", |lua, this, func: LuaFunction| { + // lua.create_userdata(FfiClosure::new(this.cif, userdata)) + // }) + methods.add_function( + "func", + |lua, (cfn, function_ref): (LuaAnyUserData, LuaAnyUserData)| { + let this = cfn.borrow::()?; + + if !function_ref.is::() { + return Err(LuaError::external("")); + } + + let ffi_ref = function_ref.borrow::()?; + if u8_test_not(ffi_ref.flags, FfiRefFlag::Function.value()) { + return Err(LuaError::external("")); + } + + let callable = lua.create_userdata(unsafe { + FfiCallable::new( + this.cif, + ptr::from_ref(&this.arg_info_list), + ptr::from_ref(&this.result_info), + ffi_ref.get_pointer(0), + ) + })?; + + set_association(lua, CALLABLE_CFN, &callable, cfn.clone())?; + set_association(lua, CALLABLE_REF, &callable, function_ref.clone())?; + + Ok(callable) + }, + ); } } diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs index 2d7d618..151ed73 100644 --- a/crates/lune-std-ffi/src/c/mod.rs +++ b/crates/lune-std-ffi/src/c/mod.rs @@ -24,4 +24,8 @@ mod association_names { pub const CARR_INNER: &str = "__carr_inner"; pub const CSTRUCT_INNER: &str = "__cstruct_inner"; pub const CTYPE_STATIC: &str = "__ctype_static"; + pub const CFN_RESULT: &str = "__cfn_result"; + pub const CFN_ARGS: &str = "__cfn_args"; + pub const CALLABLE_REF: &str = "__callable_ref"; + pub const CALLABLE_CFN: &str = "__callable_cfn"; } diff --git a/crates/lune-std-ffi/src/ffi/ffi_callable.rs b/crates/lune-std-ffi/src/ffi/ffi_callable.rs index b9752e8..abf94d2 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_callable.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_callable.rs @@ -10,62 +10,34 @@ use libffi::{ }; use mlua::prelude::*; -use super::{ - bit_mask::u8_test_not, ffi_native::NativeArgInfo, FfiRef, FfiRefFlag, GetNativeData, - NativeConvert, NativeData, -}; - -// unsafe extern "C" fn callback() { -// _cif: ffi_cif, -// result: &mut -// } - -// pub type RawCallback = unsafe extern "C" fn(cif: *mut ffi_cif, result: *mut c_void, args: *mut *mut c_void, userdata: *mut c_void); -// pub unsafe extern "C" fn ffi_prep_raw_closure( -// arg1: *mut ffi_raw_closure, -// cif: *mut ffi_cif, -// fun: Option, -// user_data: *mut c_void -// ) -> u32 - -// pub fn ffi_prep_raw_closure_loc( -// arg1: *mut ffi_raw_closure, -// cif: *mut ffi_cif, -// fun: Option< -// unsafe extern "C" fn( -// arg1: *mut ffi_cif, -// arg2: *mut c_void, -// arg3: *mut ffi_raw, -// arg4: *mut c_void, -// ), -// >, -// user_data: *mut c_void, -// codeloc: *mut c_void, -// ) -> ffi_status; +use super::{GetNativeData, NativeArgInfo, NativeData, NativeResultInfo}; pub struct FfiCallable { cif: *mut ffi_cif, - arg_type_list: Vec, - result_size: usize, + arg_info: *const Vec, + result_info: *const NativeResultInfo, code: CodePtr, + + // Caching for better performance + result_size: usize, } impl FfiCallable { pub unsafe fn new( cif: *mut ffi_cif, - arg_type_list: Vec, - result_size: usize, - function_ref: FfiRef, - ) -> LuaResult { - if u8_test_not(function_ref.flags, FfiRefFlag::Function.value()) { - return Err(LuaError::external("ref is not function pointer")); - } - Ok(Self { + arg_info: *const Vec, + result_info: *const NativeResultInfo, + function_pointer: *const (), + ) -> Self { + let result_size = (*(*result_info).conv).get_size(); + Self { cif, - arg_type_list, + arg_info, + result_info, + code: CodePtr::from_ptr(function_pointer.cast::()), + result_size, - code: CodePtr::from_ptr(function_ref.get_pointer(0).cast::()), - }) + } } pub unsafe fn call(&self, result: &Ref, args: LuaMultiValue) -> LuaResult<()> { @@ -74,20 +46,6 @@ impl FfiCallable { .then_some(()) .ok_or_else(|| LuaError::external("result boundary check failed")) } - // pub fn new_from_lua_table(lua: &Lua, args: LuaTable, ret: LuaAnyUserData) -> LuaResult { - // let args_types = libffi_type_list_from_table(lua, &args)?; - // let ret_type = libffi_type_from_userdata(lua, &ret)?; - - // Ok(Self::new( - // args_types, - // ret_type, - // unsafe { get_conv_list_from_table(&args)? }, - // unsafe { get_conv(&ret)? }, - // )) - // } - // pub fn call() { - - // } } impl LuaUserData for FfiCallable { @@ -95,15 +53,15 @@ impl LuaUserData for FfiCallable { methods.add_method( "call", |_lua, this: &FfiCallable, mut args: LuaMultiValue| { - let LuaValue::UserData(result) = args.pop_front().ok_or_else(|| { + let result_userdata = args.pop_front().ok_or_else(|| { LuaError::external("first argument must be result data handle") - })? - else { + })?; + let LuaValue::UserData(result) = result_userdata else { return Err(LuaError::external("")); }; - let call_result = unsafe { this.call(&result.get_data_handle()?, args) }; - call_result + // FIXME: clone + unsafe { this.call(&result.clone().get_data_handle()?, args) } }, - ) + ); } } diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs b/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs index c324f2d..108495d 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/arg.rs @@ -11,5 +11,5 @@ pub enum NativeArgType { pub struct NativeArgInfo { pub conv: *const dyn NativeConvert, - pub kind: NativeArgType, + // pub kind: NativeArgType, } diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs index c835deb..a089a8b 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs @@ -15,7 +15,13 @@ pub trait NativeSignedness { } pub use self::{ - arg::FfiArgRefOption, arg::NativeArgInfo, arg::NativeArgType, cast::native_num_cast, - convert::NativeConvert, data::GetNativeData, data::NativeData, result::NativeResultInfo, - result::NativeResultType, + arg::FfiArgRefOption, + arg::NativeArgInfo, + arg::NativeArgType, + cast::native_num_cast, + convert::NativeConvert, + data::GetNativeData, + data::NativeData, + result::NativeResultInfo, + // result::NativeResultType, }; diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/result.rs b/crates/lune-std-ffi/src/ffi/ffi_native/result.rs index b25995f..0a34f52 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_native/result.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_native/result.rs @@ -1,11 +1,11 @@ use super::NativeConvert; -pub enum NativeResultType { - FfiBox, - FfiRef, -} +// pub enum NativeResultType { +// FfiBox, +// FfiRef, +// } pub struct NativeResultInfo { - conv: *const dyn NativeConvert, - kind: NativeResultType, + pub conv: *const dyn NativeConvert, + // kind: NativeResultType, } diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs index d0a5404..c107b73 100644 --- a/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs +++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs @@ -1,10 +1,10 @@ -use std::ptr; +use std::{mem::ManuallyDrop, ptr}; use mlua::prelude::*; use super::{ association_names::REF_INNER, - bit_mask::u8_test, + bit_mask::{u8_test, u8_test_not}, ffi_association::{get_association, set_association}, NativeData, }; @@ -19,6 +19,12 @@ pub use self::{ // Box:ref():ref() should not be able to modify, Only for external const BOX_REF_REF_FLAGS: u8 = 0; +const UNINIT_REF_FLAGS: u8 = FfiRefFlag::Uninit.value() + | FfiRefFlag::Writable.value() + | FfiRefFlag::Readable.value() + | FfiRefFlag::Dereferenceable.value() + | FfiRefFlag::Offsetable.value() + | FfiRefFlag::Function.value(); // A referenced space. It is possible to read and write through types. // This operation is not safe. This may cause a memory error in Lua @@ -27,7 +33,7 @@ const BOX_REF_REF_FLAGS: u8 = 0; // the box will remain as long as this reference is alive. pub struct FfiRef { - ptr: *mut (), + ptr: ManuallyDrop>, pub flags: u8, pub boundary: FfiRefBounds, } @@ -35,7 +41,7 @@ pub struct FfiRef { impl FfiRef { pub fn new(ptr: *mut (), flags: u8, boundary: FfiRefBounds) -> Self { Self { - ptr, + ptr: ManuallyDrop::new(Box::new(ptr)), flags, boundary, } @@ -43,8 +49,8 @@ impl FfiRef { pub fn new_uninit() -> Self { Self { - ptr: ptr::null_mut(), - flags: FfiRefFlag::Uninit.value(), + ptr: ManuallyDrop::new(Box::new(ptr::null_mut())), + flags: UNINIT_REF_FLAGS, boundary: UNSIZED_BOUNDS, } } @@ -92,7 +98,9 @@ impl FfiRef { } pub fn is_nullptr(&self) -> bool { - self.ptr as usize == 0 + // * ManuallyDrop wrapper + // * Box wrapper + (**self.ptr) as usize == 0 } pub unsafe fn offset(&self, offset: isize) -> LuaResult { @@ -122,6 +130,14 @@ impl FfiRef { } } +impl Drop for FfiRef { + fn drop(&mut self) { + if u8_test_not(self.flags, FfiRefFlag::Leaked.value()) { + unsafe { ManuallyDrop::drop(&mut self.ptr) }; + } + } +} + impl NativeData for FfiRef { fn check_boundary(&self, offset: isize, size: usize) -> bool { self.boundary.check_sized(offset, size) diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs index 4196bce..f186e99 100644 --- a/crates/lune-std-ffi/src/ffi/mod.rs +++ b/crates/lune-std-ffi/src/ffi/mod.rs @@ -16,8 +16,7 @@ pub use self::{ ffi_lib::FfiLib, ffi_native::{ native_num_cast, FfiArgRefOption, GetNativeData, NativeArgInfo, NativeArgType, - NativeConvert, NativeData, NativeResultInfo, NativeResultType, NativeSignedness, - NativeSize, + NativeConvert, NativeData, NativeResultInfo, NativeSignedness, NativeSize, }, ffi_raw::FfiRaw, ffi_ref::{create_nullptr, FfiRef, FfiRefFlag},