Fix closure error (#243)

This commit is contained in:
qwreey 2024-10-21 15:10:12 +00:00
parent 658b5ef75c
commit 5002088240
No known key found for this signature in database
GPG key ID: D28DB79297A214BD
19 changed files with 78 additions and 107 deletions

View file

@ -4,6 +4,25 @@
See [tests/ffi](../../tests/ffi/README.md) See [tests/ffi](../../tests/ffi/README.md)
## TODO
- CString
- Add buffer for owned data support
- Add math operation.
> `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow`
> Luau cannot handle f64, i64 or i128, so we should provide math operation for it
- Add bit operation
> Luau only supports 32bit bit operations
- Add wchar and wstring support
> For windows API
## Code structure ## Code structure
### /c ### /c
@ -84,22 +103,3 @@ Implememt type-casting for all CTypes
- **Const `FFI_STATUS_NAMES`:** Used for ffi_status stringify - **Const `FFI_STATUS_NAMES`:** Used for ffi_status stringify
- **Function `get_ensured_size`:** Returns ensured ffi_type size - **Function `get_ensured_size`:** Returns ensured ffi_type size
- **Const `SIEE_OF_POINTER`:** Platform specific pointer size (Compile time known) - **Const `SIEE_OF_POINTER`:** Platform specific pointer size (Compile time known)
## TODO
- CString
- Add buffer for owned data support
- Add math operation.
> `CTypeInfo:add(target, from1, from2, ...)` and `:sub` `:mul` `:div` `:mod` `:pow`
> Luau cannot handle f64, i64 or i128, so we should provide math operation for it
- Add bit operation
> Luau only supports 32bit bit operations
- Add wchar and wstring support
> For windows API

View file

@ -198,7 +198,7 @@ impl CFnInfo {
} }
pub fn get_middle_type() -> Type { pub fn get_middle_type() -> Type {
Type::void() Type::pointer()
} }
} }

View file

@ -32,10 +32,7 @@ impl CallableData {
} }
} }
// TODO? async call: if have no lua closure in arguments, fficallble can be called with async way
pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> { pub unsafe fn call(&self, result: LuaValue, args: LuaMultiValue) -> LuaResult<()> {
// cache Vec => unable to create async call but no allocation
let mut arg_list = Vec::<*mut c_void>::with_capacity(self.arg_info_list.len()); let mut arg_list = Vec::<*mut c_void>::with_capacity(self.arg_info_list.len());
let result_pointer = if self.result_info.size == 0 { let result_pointer = if self.result_info.size == 0 {
@ -50,7 +47,6 @@ impl CallableData {
.cast::<c_void>(); .cast::<c_void>();
for index in 0..self.arg_info_list.len() { for index in 0..self.arg_info_list.len() {
// let arg_info = self.arg_info_list.get(index).unwrap();
let arg_value = args let arg_value = args
.get(index) .get(index)
.ok_or_else(|| LuaError::external(format!("argument {index} required")))? .ok_or_else(|| LuaError::external(format!("argument {index} required")))?
@ -59,14 +55,6 @@ impl CallableData {
let arg_ref = arg_value.borrow::<RefData>()?; let arg_ref = arg_value.borrow::<RefData>()?;
// unsafe {
// let argp = arg_ref.get_inner_pointer();
// let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>(
// *argp.cast::<*mut c_void>(),
// );
// dbg!(fnr(1, 2));
// }
arg_list.push(arg_ref.get_inner_pointer().cast::<c_void>()); arg_list.push(arg_ref.get_inner_pointer().cast::<c_void>());
} }

View file

@ -1,5 +1,5 @@
use core::ffi::c_void; use core::ffi::c_void;
use std::{borrow::Borrow, mem::transmute, ptr}; use std::{borrow::Borrow, ptr};
use libffi::{ use libffi::{
low::{closure_alloc, closure_free, ffi_cif}, low::{closure_alloc, closure_free, ffi_cif},
@ -20,7 +20,7 @@ use crate::ffi::{
pub struct ClosureData { pub struct ClosureData {
lua: *const Lua, lua: *const Lua,
closure: *mut ffi_closure, closure: *mut ffi_closure,
code: *mut c_void, code: Box<*mut c_void>,
arg_info_list: Vec<FfiArg>, arg_info_list: Vec<FfiArg>,
result_info: FfiResult, result_info: FfiResult,
func: LuaRegistryKey, func: LuaRegistryKey,
@ -44,14 +44,11 @@ unsafe extern "C" fn callback(
arg_pointers: *mut *mut c_void, arg_pointers: *mut *mut c_void,
closure_data: *mut c_void, closure_data: *mut c_void,
) { ) {
dbg!("before ud");
let closure_data = closure_data.cast::<ClosureData>().as_ref().unwrap(); let closure_data = closure_data.cast::<ClosureData>().as_ref().unwrap();
let lua = closure_data.lua.as_ref().unwrap(); let lua = closure_data.lua.as_ref().unwrap();
let len = (*cif).nargs as usize; let len = (*cif).nargs as usize;
let mut args = Vec::<LuaValue>::with_capacity(len + 1); let mut args = Vec::<LuaValue>::with_capacity(len + 1);
dbg!("before result", closure_data.result_info.size);
// Push result pointer (ref) // Push result pointer (ref)
args.push(LuaValue::UserData( args.push(LuaValue::UserData(
lua.create_userdata(RefData::new( lua.create_userdata(RefData::new(
@ -62,8 +59,6 @@ unsafe extern "C" fn callback(
.unwrap(), .unwrap(),
)); ));
dbg!("before arg");
// Push arg pointer (ref) // Push arg pointer (ref)
for i in 0..len { for i in 0..len {
let arg_info = closure_data.arg_info_list.get(i).unwrap(); let arg_info = closure_data.arg_info_list.get(i).unwrap();
@ -77,8 +72,6 @@ unsafe extern "C" fn callback(
)); ));
} }
dbg!("before call");
closure_data closure_data
.func .func
.borrow() .borrow()
@ -101,51 +94,36 @@ impl ClosureData {
let (closure, code) = closure_alloc(); let (closure, code) = closure_alloc();
let code = code.as_mut_ptr(); let code = code.as_mut_ptr();
dbg!(result_info.size);
let closure_data = lua.create_userdata(ClosureData { let closure_data = lua.create_userdata(ClosureData {
lua: ptr::from_ref(lua), lua: ptr::from_ref(lua),
closure, closure,
code, code: Box::new(code),
arg_info_list, arg_info_list,
result_info, result_info,
func, func,
})?; })?;
dbg!(unsafe { let closure_data_ptr = ptr::from_ref(&*closure_data.borrow::<ClosureData>()?);
closure_data
.to_pointer()
.cast::<ClosureData>()
.as_ref()
.unwrap()
.result_info
.size
});
ffi_status_assert(unsafe { ffi_status_assert(unsafe {
ffi_prep_closure_loc( ffi_prep_closure_loc(
closure, closure,
cif, cif,
Some(callback), Some(callback),
closure_data.to_pointer().cast_mut(), closure_data_ptr.cast::<c_void>().cast_mut(),
code, code,
) )
})?; })?;
unsafe {
// let argp = closure_data.borrow::<ClosureData>()?.get_inner_pointer();
let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>(code);
dbg!(fnr(1, 2));
}
Ok(closure_data) Ok(closure_data)
} }
} }
impl FfiData for ClosureData { impl FfiData for ClosureData {
unsafe fn get_inner_pointer(&self) -> *mut () { unsafe fn get_inner_pointer(&self) -> *mut () {
ptr::from_ref(&self.code).cast_mut().cast::<()>() ptr::from_ref::<*mut c_void>(&*self.code)
// self.code.cast::<()>() .cast::<()>()
.cast_mut()
} }
fn check_inner_boundary(&self, offset: isize, size: usize) -> bool { fn check_inner_boundary(&self, offset: isize, size: usize) -> bool {
(offset as usize) + size <= SIZE_OF_POINTER (offset as usize) + size <= SIZE_OF_POINTER
@ -166,15 +144,6 @@ impl LuaUserData for ClosureData {
CLOSURE_REF_FLAGS, CLOSURE_REF_FLAGS,
UNSIZED_BOUNDS, UNSIZED_BOUNDS,
))?; ))?;
unsafe {
let mut b = this.borrow_mut::<ClosureData>()?;
b.lua = ptr::from_ref(lua);
let argp = b.get_inner_pointer();
let fnr = transmute::<*mut c_void, unsafe extern "C" fn(i32, i32) -> i32>(
*argp.cast::<*mut c_void>(),
);
dbg!(fnr(1, 2));
}
association::set(lua, CLSOURE_REF_INNER, &ref_data, &this)?; association::set(lua, CLSOURE_REF_INNER, &ref_data, &this)?;
Ok(ref_data) Ok(ref_data)
}); });

View file

@ -8,29 +8,29 @@ gcc for library compiling (for external-\*)
**External tests** **External tests**
- [x] tests/ffi/external-math - [x] [external_math](./external_math/init.luau)
- [x] tests/ffi/external-pointer - [x] [external_pointer](./external_pointer/init.luau)
- [x] tests/ffi/external-print - [x] [external_print](./external_print/init.luau)
- [x] tests/ffi/external-struct - [x] [external_struct](./external_struct/init.luau)
- [ ] tests/ffi/external-closure - [ ] [external_closure](./external_closure/init.luau)
> failed (segfault) > failed (segfault)
**Luau-side** **Luau-side**
- [ ] tests/ffi/pretty-print :white_check_mark: - [ ] [pretty_print](./pretty_print)
> need box, ref test > need box, ref test
- [x] tests/ffi/isInteger - [x] [isInteger](./isInteger)
- [ ] tests/ffi/into-boundary - [ ] [into_boundary](./into_boundary)
> need assertion > need assertion
- [ ] tests/ffi/from-boundary - [ ] [from_boundary](./from_boundary)
> need assertion > need assertion
- [ ] tests/ffi/cast - [ ] [cast](./cast)
> need assertion > need assertion

View file

@ -1,14 +0,0 @@
#include<stdio.h>
typedef int (*lua_callback_t)(int, int);
int closure_test(lua_callback_t callback) {
printf("%p\n", callback);
printf("%d\n", callback(12, 24));
return callback(12, 24) * 2;
}
int closure(int a, int b) {
return a+b;
}

View file

@ -1,6 +1,6 @@
local ffi = require("@lune/ffi") local ffi = require("@lune/ffi")
local testdir = "./tests/ffi/external-closure" local testdir = "./tests/ffi/external_closure"
local compile = require("../utility/compile") local compile = require("../utility/compile")
compile(`{testdir}/lib.c`, `{testdir}/lib.so`) compile(`{testdir}/lib.c`, `{testdir}/lib.so`)
@ -15,11 +15,27 @@ local function test_closure()
local closure_test_info = ffi.c.fn({ callback_info }, ffi.c.int) local closure_test_info = ffi.c.fn({ callback_info }, ffi.c.int)
local closure_test_callable = closure_test_info:callable(lib:find("closure_test")) local closure_test_callable = closure_test_info:callable(lib:find("closure"))
local result_box = ffi.box(ffi.c.int.size) local result_box = ffi.box(ffi.c.int.size)
closure_test_callable(result_box, callback_closure:ref()) closure_test_callable(result_box, callback_closure:ref())
print(callback_closure) local result = ffi.c.int:readData(result_box)
assert(result == 72, `test_closure failed. result expected 20000, got {result}`)
end end
test_closure() test_closure()
local function test_hello_world()
local callback_info = ffi.c.fn({}, ffi.c.void)
local callback_closure = callback_info:closure(function()
print("Hello world in lua closure!")
end)
local closure_test_info = ffi.c.fn({ callback_info }, ffi.c.void)
local closure_test_callable = closure_test_info:callable(lib:find("hello_world"))
closure_test_callable(nil, callback_closure:ref())
end
test_hello_world()

View file

@ -0,0 +1,12 @@
#include<stdio.h>
typedef int (*lua_callback_t)(int, int);
typedef void (*lua_hello_world_callback_t)();
int closure(lua_callback_t lua_closure) {
return lua_closure(12, 24) * 2;
}
void hello_world(lua_hello_world_callback_t lua_closure) {
lua_closure();
}

View file

@ -1,7 +1,7 @@
local ffi = require("@lune/ffi") local ffi = require("@lune/ffi")
local c = ffi.c local c = ffi.c
local testdir = "./tests/ffi/external-math" local testdir = "./tests/ffi/external_math"
local compile = require("../utility/compile") local compile = require("../utility/compile")
compile(`{testdir}/lib.c`, `{testdir}/lib.so`) compile(`{testdir}/lib.c`, `{testdir}/lib.so`)
local lib = ffi.open(`{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`)

View file

@ -1,23 +1,23 @@
local ffi = require("@lune/ffi") local ffi = require("@lune/ffi")
local c = ffi.c local c = ffi.c
local testdir = "./tests/ffi/external-pointer" local testdir = "./tests/ffi/external_pointer"
local compile = require("../utility/compile") local compile = require("../utility/compile")
compile(`{testdir}/lib.c`, `{testdir}/lib.so`) compile(`{testdir}/lib.c`, `{testdir}/lib.so`)
local lib = ffi.open(`{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`)
local function test_pointer() local function test_pointer_write()
local pointer_info = c.fn({ c.int:ptr() }, c.void) local pointer_write_info = c.fn({ c.int:ptr() }, c.void)
local pointer_callable = pointer_info:callable(lib:find("pointer")) local pointer_write_callable = pointer_write_info:callable(lib:find("pointer_write"))
local a = ffi.box(c.int.size) local a = ffi.box(c.int.size)
pointer_callable(nil, a:ref():ref()) pointer_write_callable(nil, a:ref():ref())
local result = c.int:readData(a) local result = c.int:readData(a)
assert(result == 123, `pointer failed. result expected 123, got {result}`) assert(result == 123, `pointer failed. result expected 123, got {result}`)
end end
test_pointer() test_pointer_write()

View file

@ -1,7 +1,7 @@
local ffi = require("@lune/ffi") local ffi = require("@lune/ffi")
local c = ffi.c local c = ffi.c
local testdir = "./tests/ffi/external-print" local testdir = "./tests/ffi/external_print"
local compile = require("../utility/compile") local compile = require("../utility/compile")
compile(`{testdir}/lib.c`, `{testdir}/lib.so`) compile(`{testdir}/lib.c`, `{testdir}/lib.so`)
local lib = ffi.open(`{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`)

View file

@ -1,7 +1,7 @@
local ffi = require("@lune/ffi") local ffi = require("@lune/ffi")
local c = ffi.c local c = ffi.c
local testdir = "./tests/ffi/external-struct" local testdir = "./tests/ffi/external_struct"
local compile = require("../utility/compile") local compile = require("../utility/compile")
compile(`{testdir}/lib.c`, `{testdir}/lib.so`) compile(`{testdir}/lib.c`, `{testdir}/lib.so`)
local lib = ffi.open(`{testdir}/lib.so`) local lib = ffi.open(`{testdir}/lib.so`)