From b7d1ab61056bf8c0f8e76c412c697e3124a3c3a6 Mon Sep 17 00:00:00 2001 From: visualfc Date: Tue, 22 Oct 2024 20:28:08 +0800 Subject: [PATCH 1/3] c/ffi: import libffi --- c/ffi/abi.go | 7 +++ c/ffi/abi_amd64.go | 7 +++ c/ffi/ffi.go | 98 +++++++++++++++++++++++++++++++ c/ffi/ffi/_wrap/libffi.c | 5 ++ c/ffi/ffi/ffi.go | 117 ++++++++++++++++++++++++++++++++++++ c/ffi/type.go | 124 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 358 insertions(+) create mode 100644 c/ffi/abi.go create mode 100644 c/ffi/abi_amd64.go create mode 100644 c/ffi/ffi.go create mode 100644 c/ffi/ffi/_wrap/libffi.c create mode 100644 c/ffi/ffi/ffi.go create mode 100644 c/ffi/type.go diff --git a/c/ffi/abi.go b/c/ffi/abi.go new file mode 100644 index 00000000..6009fa50 --- /dev/null +++ b/c/ffi/abi.go @@ -0,0 +1,7 @@ +//go:build ((freebsd || linux || darwin) && arm64) || (windows && (amd64 || arm64)) + +package ffi + +const ( + DefaultAbi Abi = 1 +) diff --git a/c/ffi/abi_amd64.go b/c/ffi/abi_amd64.go new file mode 100644 index 00000000..24567609 --- /dev/null +++ b/c/ffi/abi_amd64.go @@ -0,0 +1,7 @@ +//go:build freebsd || linux || darwin + +package ffi + +const ( + DefaultAbi Abi = 2 +) diff --git a/c/ffi/ffi.go b/c/ffi/ffi.go new file mode 100644 index 00000000..9b2266b9 --- /dev/null +++ b/c/ffi/ffi.go @@ -0,0 +1,98 @@ +package ffi + +import ( + "fmt" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi/ffi" +) + +type Type = ffi.Type + +type Signature = ffi.Cif + +type Abi c.Uint + +type Error c.Uint + +const ( + OK Error = iota + BAD_TYPEDEF + BAD_ABI + BAD_ARGTYPE +) + +func (s Error) Error() string { + switch s { + case OK: + return "ok" + case BAD_TYPEDEF: + return "bad type def" + case BAD_ABI: + return "bad ABI" + case BAD_ARGTYPE: + return "bad argument type" + } + return fmt.Sprintf("invalid status: %v", int(s)) +} + +func NewSignature(ret *Type, args ...*Type) (*Signature, error) { + var cif ffi.Cif + var atype **Type + if len(args) > 0 { + atype = &args[0] + } + status := ffi.PrepCif(&cif, c.Uint(DefaultAbi), c.Uint(len(args)), ret, atype) + if status == 0 { + return &cif, nil + } + return nil, Error(status) +} + +func NewSignatureVar(ret *Type, fixed int, args ...*Type) (*Signature, error) { + var cif ffi.Cif + var atype **Type + if len(args) > 0 { + atype = &args[0] + } + status := ffi.PrepCifVar(&cif, c.Uint(DefaultAbi), c.Uint(fixed), c.Uint(len(args)), ret, atype) + if status == 0 { + return &cif, nil + } + return nil, Error(status) +} + +func Call(cif *Signature, fn unsafe.Pointer, ret unsafe.Pointer, args ...unsafe.Pointer) { + var avalues *unsafe.Pointer + if len(args) > 0 { + avalues = &args[0] + } + ffi.Call(cif, fn, ret, avalues) +} + +type Closure struct { + ptr unsafe.Pointer + Fn unsafe.Pointer +} + +func NewClosure() *Closure { + c := &Closure{} + c.ptr = ffi.ClosureAlloc(&c.Fn) + return c +} + +func (c *Closure) Free() { + if c != nil && c.ptr != nil { + ffi.ClosureFree(c.ptr) + c.ptr = nil + } +} + +func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Pointer) error { + status := ffi.PreClosureLoc(c.ptr, cif, fn, userdata, c.Fn) + if status == 0 { + return nil + } + return Error(status) +} diff --git a/c/ffi/ffi/_wrap/libffi.c b/c/ffi/ffi/_wrap/libffi.c new file mode 100644 index 00000000..53fa1c70 --- /dev/null +++ b/c/ffi/ffi/_wrap/libffi.c @@ -0,0 +1,5 @@ +#include + +void *llog_ffi_closure_alloc(void **code) { + return ffi_closure_alloc(sizeof(ffi_closure), code); +} diff --git a/c/ffi/ffi/ffi.go b/c/ffi/ffi/ffi.go new file mode 100644 index 00000000..b500075c --- /dev/null +++ b/c/ffi/ffi/ffi.go @@ -0,0 +1,117 @@ +package ffi + +import ( + "unsafe" + + "github.com/goplus/llgo/c" +) + +const ( + LLGoPackage = "link: $(pkg-config --libs libffi); -lffi" + LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c" +) + +const ( + Void = iota + Int + Float + Double + LongDouble + Uint8 + Sint8 + Uint16 + Sint16 + Uint32 + Sint32 + Uint64 + Sint64 + Struct + Pointer + Complex +) + +type Type struct { + Size uintptr + Alignment uint16 + Type uint16 + Elements **Type +} + +/*typedef struct { + ffi_abi abi; + unsigned nargs; + ffi_type **arg_types; + ffi_type *rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; +*/ + +type Cif struct { + Abi c.Uint + NArgs c.Uint + ArgTypes **Type + RType *Type + Bytes c.Uint + Flags c.Uint + //Extra c.Uint +} + +/* +ffi_status +ffi_prep_cif(ffi_cif *cif, + ffi_abi abi, + unsigned int nargs, + ffi_type *rtype, + ffi_type **atypes); +*/ +//go:linkname PrepCif C.ffi_prep_cif +func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint + +/* +ffi_status ffi_prep_cif_var(ffi_cif *cif, + ffi_abi abi, + unsigned int nfixedargs, + unsigned int ntotalargs, + ffi_type *rtype, + ffi_type **atypes); +*/ +//go:linkname PrepCifVar C.ffi_prep_cif_var +func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint + +/* +void ffi_call(ffi_cif *cif, + void (*fn)(void), + void *rvalue, + void **avalue); +*/ +//go:linkname Call C.ffi_call +func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer) + +// void *ffi_closure_alloc (size_t size, void **code); +// +//go:linkname ClosureAlloc C.llog_ffi_closure_alloc +func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer + +// void ffi_closure_free (void *); +// +//go:linkname ClosureFree C.ffi_closure_free +func ClosureFree(unsafe.Pointer) + +/* +ffi_status +ffi_prep_closure_loc (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc); +*/ + +//llgo:type C +type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) + +//go:linkname PreClosureLoc C.ffi_prep_closure_loc +func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint diff --git a/c/ffi/type.go b/c/ffi/type.go new file mode 100644 index 00000000..2ef77657 --- /dev/null +++ b/c/ffi/type.go @@ -0,0 +1,124 @@ +package ffi + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi/ffi" +) + +type BasicKind int + +const ( + Void BasicKind = iota // type is invalid + + // predeclared types + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + String + UnsafePointer + Interface + Slice + + // aliases + Byte = Uint8 + Rune = Int32 +) + +const ( + _64bit = 1 << (^uintptr(0) >> 63) / 2 + _Int = _64bit*ffi.Sint64 + (1-_64bit)*ffi.Sint32 + _Uint = _64bit*ffi.Uint64 + (1-_64bit)*ffi.Uint32 + _sizei = unsafe.Sizeof(0) + _aligni = uint16(unsafe.Alignof(0)) + _sizeci = unsafe.Sizeof(c.Int(0)) + _alignci = uint16(unsafe.Alignof(c.Int(0))) + _sizes = unsafe.Sizeof("") + _aligns = uint16(unsafe.Alignof("")) +) + +var ( + TypeVoid = &Type{1, 1, ffi.Void, nil} + TypeBool = &Type{1, 1, ffi.Uint8, nil} + TypeInt8 = &Type{1, 1, ffi.Sint8, nil} + TypeInt16 = &Type{2, 2, ffi.Sint16, nil} + TypeInt32 = &Type{4, 4, ffi.Sint32, nil} + TypeInt64 = &Type{8, 8, ffi.Sint64, nil} + TypeUint8 = &Type{1, 1, ffi.Uint8, nil} + TypeUint16 = &Type{2, 2, ffi.Uint16, nil} + TypeUint32 = &Type{4, 4, ffi.Uint32, nil} + TypeUint64 = &Type{8, 8, ffi.Uint64, nil} + TypeFloat32 = &Type{4, 4, ffi.Float, nil} + TypeFloat64 = &Type{8, 8, ffi.Double, nil} + TypeComplex64 = &Type{8, 4, ffi.Complex, &[]*Type{TypeFloat32, nil}[0]} + TypeComplex128 = &Type{16, 8, ffi.Complex, &[]*Type{TypeFloat64, nil}[0]} + TypeInt = &Type{_sizei, _aligni, _Int, nil} + TypeUint = &Type{_sizei, _aligni, _Uint, nil} + TypeUintptr = &Type{_sizei, _aligni, _Uint, nil} + TypePointer = &Type{_sizei, _aligni, ffi.Pointer, nil} + TypeString = StructOf(TypePointer, TypeInt) + TypeInterface = StructOf(TypePointer, TypePointer) + TypeSlice = StructOf(TypePointer, TypeInt, TypeInt) +) + +var Typ = []*Type{ + Void: TypeVoid, + Bool: TypeBool, + Int: TypeInt, + Int8: TypeInt8, + Int16: TypeInt16, + Int32: TypeInt32, + Int64: TypeInt64, + Uint: TypeUint, + Uint8: TypeUint8, + Uint16: TypeUint16, + Uint32: TypeUint32, + Uint64: TypeUint64, + Uintptr: TypeUintptr, + Float32: TypeFloat32, + Float64: TypeFloat64, + Complex64: TypeComplex64, + Complex128: TypeComplex128, + String: TypeString, + UnsafePointer: TypePointer, + Interface: TypeInterface, + Slice: TypeSlice, +} + +func ArrayOf(elem *Type, N int) *Type { + fs := make([]*Type, N+1) + for i := 0; i < N; i++ { + fs[i] = elem + } + return &Type{ + 0, + 0, + ffi.Struct, + &fs[0], + } +} + +func StructOf(fields ...*Type) *Type { + fs := make([]*Type, len(fields)+1) + copy(fs, fields) + return &Type{ + 0, + 0, + ffi.Struct, + &fs[0], + } +} From 92c267758e7c0de67fb594a2aa21d995fbe9ab78 Mon Sep 17 00:00:00 2001 From: visualfc Date: Tue, 22 Oct 2024 21:30:38 +0800 Subject: [PATCH 2/3] c/ffi: add _demo --- c/ffi/_demo/_wrap/wrap.c | 25 ++++++++++++ c/ffi/_demo/cfunc/main.go | 57 +++++++++++++++++++++++++++ c/ffi/_demo/closure/main.go | 78 +++++++++++++++++++++++++++++++++++++ c/ffi/_demo/gofunc/main.go | 62 +++++++++++++++++++++++++++++ c/ffi/_demo/printf/main.go | 20 ++++++++++ c/ffi/ffi.go | 8 ++++ 6 files changed, 250 insertions(+) create mode 100644 c/ffi/_demo/_wrap/wrap.c create mode 100644 c/ffi/_demo/cfunc/main.go create mode 100644 c/ffi/_demo/closure/main.go create mode 100644 c/ffi/_demo/gofunc/main.go create mode 100644 c/ffi/_demo/printf/main.go diff --git a/c/ffi/_demo/_wrap/wrap.c b/c/ffi/_demo/_wrap/wrap.c new file mode 100644 index 00000000..07f31c0a --- /dev/null +++ b/c/ffi/_demo/_wrap/wrap.c @@ -0,0 +1,25 @@ +#include + +struct array +{ + int x; + int y; + int z; + int k; +}; + +int demo1(struct array a) +{ + printf("c.demo1: %d %d %d %d\n",a.x,a.y,a.z,a.k); + return a.x+a.y+a.z+a.k; +} + +int demo2( int (*fn)(struct array)) { + printf("c.demo2: %p\n",fn); + struct array a; + a.x = 1; + a.y = 2; + a.z = 3; + a.k = 4; + return (*fn)(a); +} diff --git a/c/ffi/_demo/cfunc/main.go b/c/ffi/_demo/cfunc/main.go new file mode 100644 index 00000000..d9aa66f9 --- /dev/null +++ b/c/ffi/_demo/cfunc/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +const ( + LLGoPackage = "link" + LLGoFiles = "../_wrap/wrap.c" +) + +//llgo:type C +type Callback func(array) c.Int + +//go:linkname demo1 C.demo1 +func demo1(array) c.Int + +//go:linkname demo2 C.demo2 +func demo2(fn Callback) c.Int + +//llgo:type C +type array struct { + x c.Int + y c.Int + z c.Int + k c.Int +} + +func main() { + cdemo1() + cdemo2() +} + +func cdemo1() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.StructOf(ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32)) + if err != nil { + panic(err) + } + ar := array{1, 2, 3, 4} + var ret int32 + ffi.Call(sig, c.Func(demo1), unsafe.Pointer(&ret), unsafe.Pointer(&ar)) + c.Printf(c.Str("ret: %d\n"), ret) +} + +func cdemo2() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + var ret int32 + fn := c.Func(demo1) + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/c/ffi/_demo/closure/main.go b/c/ffi/_demo/closure/main.go new file mode 100644 index 00000000..e8c4be4f --- /dev/null +++ b/c/ffi/_demo/closure/main.go @@ -0,0 +1,78 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +const ( + LLGoPackage = "link" + LLGoFiles = "../_wrap/wrap.c" +) + +//llgo:type C +type Callback func(array) c.Int + +//go:linkname demo1 C.demo1 +func demo1(array) c.Int + +//go:linkname demo2 C.demo2 +func demo2(fn Callback) c.Int + +//llgo:type C +type array struct { + x c.Int + y c.Int + z c.Int + k c.Int +} + +func demo(a array) c.Int { + c.Printf(c.Str("go.demo %d %d %d %d\n"), a.x, a.y, a.z, a.k) + return a.x + a.y + a.z + a.k +} + +func main() { + gofn() + c.Printf(c.Str("\n")) + goclosure() +} + +func gofn() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + closure := ffi.NewClosure() + defer closure.Free() + err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + ar := *(*array)(ffi.Index(args, 0)) + *(*c.Int)(ret) = demo(ar) + }, nil) + var ret int32 + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} + +func goclosure() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + fn := func(ar array) c.Int { + c.Printf(c.Str("call closure %d\n"), sig.NArgs) + return demo(ar) + } + closure := ffi.NewClosure() + defer closure.Free() + err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + ar := *(*array)(ffi.Index(args, 0)) + fn := *(*func(array) c.Int)(userdata) + *(*c.Int)(ret) = fn(ar) + }, unsafe.Pointer(&fn)) + var ret int32 + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/c/ffi/_demo/gofunc/main.go b/c/ffi/_demo/gofunc/main.go new file mode 100644 index 00000000..10af70a8 --- /dev/null +++ b/c/ffi/_demo/gofunc/main.go @@ -0,0 +1,62 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c/ffi" +) + +type array struct { + x int + y int + z int + k int +} + +type Func func(ar array, i interface{}, s string, slice []int) (int, float64) + +func demo(p1 array, p2 interface{}, p3 string, p4 []int) (int, float64) { + println(p1.x, p1.y, p1.z, p1.k) + println(p2) + println(p3) + println(p4) + for _, v := range p4 { + println(v) + } + return 200, 3.14 +} + +func main() { + sig, err := ffi.NewSignature(ffi.StructOf(ffi.TypeInt, ffi.TypeFloat64), + ffi.StructOf(ffi.TypeInt, ffi.TypeInt, ffi.TypeInt, ffi.TypeInt), + ffi.TypeInterface, ffi.TypeString, ffi.TypeSlice) + if err != nil { + panic(err) + } + fn := demo + closure := ffi.NewClosure() + defer closure.Free() + err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + p1 := *(*array)(ffi.Index(args, 0)) + p2 := *(*any)(ffi.Index(args, 1)) + p3 := *(*string)(ffi.Index(args, 2)) + p4 := *(*[]int)(ffi.Index(args, 3)) + fn := *(*Func)(userdata) + p := (*struct { + i int + f float64 + })(ret) + p.i, p.f = fn(p1, p2, p3, p4) + }, unsafe.Pointer(&fn)) + var ret struct { + i int + f float64 + } + p1 := array{1, 2, 3, 4} + var p2 any = 100 + p3 := "hello world" + p4 := []int{100, 200, 300} + ffi.Call(sig, closure.Fn, unsafe.Pointer(&ret), + unsafe.Pointer(&p1), unsafe.Pointer(&p2), unsafe.Pointer(&p3), unsafe.Pointer(&p4)) + println("ret:", ret.i, ret.f) +} diff --git a/c/ffi/_demo/printf/main.go b/c/ffi/_demo/printf/main.go new file mode 100644 index 00000000..ac849d0b --- /dev/null +++ b/c/ffi/_demo/printf/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +func main() { + sig, err := ffi.NewSignatureVar(ffi.TypeInt32, 1, ffi.TypePointer, ffi.TypeInt32) + if err != nil { + panic(err) + } + var ret int32 + text := c.Str("hello world: %d\n") + var n int32 = 100 + ffi.Call(sig, c.Func(c.Printf), unsafe.Pointer(&ret), unsafe.Pointer(&text), unsafe.Pointer(&n)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/c/ffi/ffi.go b/c/ffi/ffi.go index 9b2266b9..586a50fc 100644 --- a/c/ffi/ffi.go +++ b/c/ffi/ffi.go @@ -96,3 +96,11 @@ func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Point } return Error(status) } + +func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer { + return unsafe.Pointer(uintptr(ptr) + offset) +} + +func Index(args *unsafe.Pointer, i uintptr) unsafe.Pointer { + return (*(*unsafe.Pointer)(add(unsafe.Pointer(args), i*unsafe.Sizeof(0)))) +} From 363be185991312098351c88dd2701bed730681a5 Mon Sep 17 00:00:00 2001 From: visualfc Date: Wed, 23 Oct 2024 11:44:34 +0800 Subject: [PATCH 3/3] x/ffi: wrap c/ffi --- c/ffi/_demo/cfunc/main.go | 24 +++-- c/ffi/_demo/closure/main.go | 49 ++++++--- c/ffi/_demo/printf/main.go | 14 ++- c/ffi/{ffi => }/_wrap/libffi.c | 0 c/ffi/abi.go | 2 +- c/ffi/abi_amd64.go | 2 +- c/ffi/ffi.go | 174 +++++++++++++++++------------- c/ffi/ffi/ffi.go | 117 -------------------- x/ffi/_demo/_wrap/wrap.c | 25 +++++ x/ffi/_demo/cfunc/main.go | 57 ++++++++++ x/ffi/_demo/closure/main.go | 78 ++++++++++++++ {c => x}/ffi/_demo/gofunc/main.go | 2 +- x/ffi/_demo/printf/main.go | 20 ++++ x/ffi/ffi.go | 93 ++++++++++++++++ {c => x}/ffi/type.go | 2 +- 15 files changed, 435 insertions(+), 224 deletions(-) rename c/ffi/{ffi => }/_wrap/libffi.c (100%) delete mode 100644 c/ffi/ffi/ffi.go create mode 100644 x/ffi/_demo/_wrap/wrap.c create mode 100644 x/ffi/_demo/cfunc/main.go create mode 100644 x/ffi/_demo/closure/main.go rename {c => x}/ffi/_demo/gofunc/main.go (97%) create mode 100644 x/ffi/_demo/printf/main.go create mode 100644 x/ffi/ffi.go rename {c => x}/ffi/type.go (98%) diff --git a/c/ffi/_demo/cfunc/main.go b/c/ffi/_demo/cfunc/main.go index d9aa66f9..59f5f118 100644 --- a/c/ffi/_demo/cfunc/main.go +++ b/c/ffi/_demo/cfunc/main.go @@ -29,29 +29,37 @@ type array struct { k c.Int } +var ( + typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil} + typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil} +) + func main() { cdemo1() cdemo2() } func cdemo1() { - sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.StructOf(ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32)) - if err != nil { - panic(err) + var cif ffi.Cif + tarray := &ffi.Type{0, 0, ffi.Struct, &[]*ffi.Type{typeInt32, typeInt32, typeInt32, typeInt32, nil}[0]} + status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{tarray}[0]) + if status != ffi.OK { + panic(status) } ar := array{1, 2, 3, 4} var ret int32 - ffi.Call(sig, c.Func(demo1), unsafe.Pointer(&ret), unsafe.Pointer(&ar)) + ffi.Call(&cif, c.Func(demo1), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&ar)}[0]) c.Printf(c.Str("ret: %d\n"), ret) } func cdemo2() { - sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) - if err != nil { - panic(err) + var cif ffi.Cif + status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0]) + if status != ffi.OK { + panic(status) } var ret int32 fn := c.Func(demo1) - ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&fn)) + ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fn)}[0]) c.Printf(c.Str("ret: %d\n"), ret) } diff --git a/c/ffi/_demo/closure/main.go b/c/ffi/_demo/closure/main.go index e8c4be4f..a85d0836 100644 --- a/c/ffi/_demo/closure/main.go +++ b/c/ffi/_demo/closure/main.go @@ -34,6 +34,11 @@ func demo(a array) c.Int { return a.x + a.y + a.z + a.k } +var ( + typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil} + typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil} +) + func main() { gofn() c.Printf(c.Str("\n")) @@ -41,38 +46,48 @@ func main() { } func gofn() { - sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) - if err != nil { - panic(err) + var cif ffi.Cif + status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0]) + if status != ffi.OK { + panic(status) } - closure := ffi.NewClosure() - defer closure.Free() - err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + var fncode unsafe.Pointer + closure := ffi.ClosureAlloc(&fncode) + defer ffi.ClosureFree(closure) + status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { ar := *(*array)(ffi.Index(args, 0)) *(*c.Int)(ret) = demo(ar) - }, nil) + }, nil, fncode) + if status != ffi.OK { + panic(status) + } var ret int32 - ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn)) + ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0]) c.Printf(c.Str("ret: %d\n"), ret) } func goclosure() { - sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) - if err != nil { - panic(err) + var cif ffi.Cif + status := ffi.PrepCif(&cif, ffi.DefaultAbi, 1, typeInt32, &[]*ffi.Type{typePointer}[0]) + if status != ffi.OK { + panic(status) } fn := func(ar array) c.Int { - c.Printf(c.Str("call closure %d\n"), sig.NArgs) + c.Printf(c.Str("call closure %d\n"), cif.NArgs) return demo(ar) } - closure := ffi.NewClosure() - defer closure.Free() - err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + var fncode unsafe.Pointer + closure := ffi.ClosureAlloc(&fncode) + defer ffi.ClosureFree(closure) + status = ffi.PreClosureLoc(closure, &cif, func(cif *ffi.Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { ar := *(*array)(ffi.Index(args, 0)) fn := *(*func(array) c.Int)(userdata) *(*c.Int)(ret) = fn(ar) - }, unsafe.Pointer(&fn)) + }, unsafe.Pointer(&fn), fncode) + if status != ffi.OK { + panic(status) + } var ret int32 - ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn)) + ffi.Call(&cif, c.Func(demo2), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&fncode)}[0]) c.Printf(c.Str("ret: %d\n"), ret) } diff --git a/c/ffi/_demo/printf/main.go b/c/ffi/_demo/printf/main.go index ac849d0b..cac40edd 100644 --- a/c/ffi/_demo/printf/main.go +++ b/c/ffi/_demo/printf/main.go @@ -7,14 +7,20 @@ import ( "github.com/goplus/llgo/c/ffi" ) +var ( + typeInt32 = &ffi.Type{4, 4, ffi.Sint32, nil} + typePointer = &ffi.Type{unsafe.Sizeof(0), uint16(unsafe.Alignof(0)), ffi.Pointer, nil} +) + func main() { - sig, err := ffi.NewSignatureVar(ffi.TypeInt32, 1, ffi.TypePointer, ffi.TypeInt32) - if err != nil { - panic(err) + var cif ffi.Cif + status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, 1, 2, typeInt32, &[]*ffi.Type{typePointer, typeInt32}[0]) + if status != ffi.OK { + panic(status) } var ret int32 text := c.Str("hello world: %d\n") var n int32 = 100 - ffi.Call(sig, c.Func(c.Printf), unsafe.Pointer(&ret), unsafe.Pointer(&text), unsafe.Pointer(&n)) + ffi.Call(&cif, c.Func(c.Printf), unsafe.Pointer(&ret), &[]unsafe.Pointer{unsafe.Pointer(&text), unsafe.Pointer(&n)}[0]) c.Printf(c.Str("ret: %d\n"), ret) } diff --git a/c/ffi/ffi/_wrap/libffi.c b/c/ffi/_wrap/libffi.c similarity index 100% rename from c/ffi/ffi/_wrap/libffi.c rename to c/ffi/_wrap/libffi.c diff --git a/c/ffi/abi.go b/c/ffi/abi.go index 6009fa50..a693166e 100644 --- a/c/ffi/abi.go +++ b/c/ffi/abi.go @@ -3,5 +3,5 @@ package ffi const ( - DefaultAbi Abi = 1 + DefaultAbi = 1 ) diff --git a/c/ffi/abi_amd64.go b/c/ffi/abi_amd64.go index 24567609..89078adb 100644 --- a/c/ffi/abi_amd64.go +++ b/c/ffi/abi_amd64.go @@ -3,5 +3,5 @@ package ffi const ( - DefaultAbi Abi = 2 + DefaultAbi = 2 ) diff --git a/c/ffi/ffi.go b/c/ffi/ffi.go index 586a50fc..f060d786 100644 --- a/c/ffi/ffi.go +++ b/c/ffi/ffi.go @@ -1,101 +1,127 @@ package ffi import ( - "fmt" "unsafe" "github.com/goplus/llgo/c" - "github.com/goplus/llgo/c/ffi/ffi" ) -type Type = ffi.Type - -type Signature = ffi.Cif - -type Abi c.Uint - -type Error c.Uint +const ( + LLGoPackage = "link: $(pkg-config --libs libffi); -lffi" + LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c" +) const ( - OK Error = iota + Void = iota + Int + Float + Double + LongDouble + Uint8 + Sint8 + Uint16 + Sint16 + Uint32 + Sint32 + Uint64 + Sint64 + Struct + Pointer + Complex +) + +const ( + OK = iota BAD_TYPEDEF BAD_ABI BAD_ARGTYPE ) -func (s Error) Error() string { - switch s { - case OK: - return "ok" - case BAD_TYPEDEF: - return "bad type def" - case BAD_ABI: - return "bad ABI" - case BAD_ARGTYPE: - return "bad argument type" - } - return fmt.Sprintf("invalid status: %v", int(s)) +type Type struct { + Size uintptr + Alignment uint16 + Type uint16 + Elements **Type } -func NewSignature(ret *Type, args ...*Type) (*Signature, error) { - var cif ffi.Cif - var atype **Type - if len(args) > 0 { - atype = &args[0] - } - status := ffi.PrepCif(&cif, c.Uint(DefaultAbi), c.Uint(len(args)), ret, atype) - if status == 0 { - return &cif, nil - } - return nil, Error(status) +/*typedef struct { + ffi_abi abi; + unsigned nargs; + ffi_type **arg_types; + ffi_type *rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; +*/ + +type Cif struct { + Abi c.Uint + NArgs c.Uint + ArgTypes **Type + RType *Type + Bytes c.Uint + Flags c.Uint + //Extra c.Uint } -func NewSignatureVar(ret *Type, fixed int, args ...*Type) (*Signature, error) { - var cif ffi.Cif - var atype **Type - if len(args) > 0 { - atype = &args[0] - } - status := ffi.PrepCifVar(&cif, c.Uint(DefaultAbi), c.Uint(fixed), c.Uint(len(args)), ret, atype) - if status == 0 { - return &cif, nil - } - return nil, Error(status) -} +/* +ffi_status +ffi_prep_cif(ffi_cif *cif, + ffi_abi abi, + unsigned int nargs, + ffi_type *rtype, + ffi_type **atypes); +*/ +//go:linkname PrepCif C.ffi_prep_cif +func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint -func Call(cif *Signature, fn unsafe.Pointer, ret unsafe.Pointer, args ...unsafe.Pointer) { - var avalues *unsafe.Pointer - if len(args) > 0 { - avalues = &args[0] - } - ffi.Call(cif, fn, ret, avalues) -} +/* +ffi_status ffi_prep_cif_var(ffi_cif *cif, + ffi_abi abi, + unsigned int nfixedargs, + unsigned int ntotalargs, + ffi_type *rtype, + ffi_type **atypes); +*/ +//go:linkname PrepCifVar C.ffi_prep_cif_var +func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint -type Closure struct { - ptr unsafe.Pointer - Fn unsafe.Pointer -} +/* +void ffi_call(ffi_cif *cif, + void (*fn)(void), + void *rvalue, + void **avalue); +*/ +//go:linkname Call C.ffi_call +func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer) -func NewClosure() *Closure { - c := &Closure{} - c.ptr = ffi.ClosureAlloc(&c.Fn) - return c -} +// void *ffi_closure_alloc (size_t size, void **code); +// +//go:linkname ClosureAlloc C.llog_ffi_closure_alloc +func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer -func (c *Closure) Free() { - if c != nil && c.ptr != nil { - ffi.ClosureFree(c.ptr) - c.ptr = nil - } -} +// void ffi_closure_free (void *); +// +//go:linkname ClosureFree C.ffi_closure_free +func ClosureFree(unsafe.Pointer) -func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Pointer) error { - status := ffi.PreClosureLoc(c.ptr, cif, fn, userdata, c.Fn) - if status == 0 { - return nil - } - return Error(status) -} +/* +ffi_status +ffi_prep_closure_loc (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc); +*/ + +//llgo:type C +type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) + +//go:linkname PreClosureLoc C.ffi_prep_closure_loc +func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer { return unsafe.Pointer(uintptr(ptr) + offset) diff --git a/c/ffi/ffi/ffi.go b/c/ffi/ffi/ffi.go deleted file mode 100644 index b500075c..00000000 --- a/c/ffi/ffi/ffi.go +++ /dev/null @@ -1,117 +0,0 @@ -package ffi - -import ( - "unsafe" - - "github.com/goplus/llgo/c" -) - -const ( - LLGoPackage = "link: $(pkg-config --libs libffi); -lffi" - LLGoFiles = "$(pkg-config --cflags libffi): _wrap/libffi.c" -) - -const ( - Void = iota - Int - Float - Double - LongDouble - Uint8 - Sint8 - Uint16 - Sint16 - Uint32 - Sint32 - Uint64 - Sint64 - Struct - Pointer - Complex -) - -type Type struct { - Size uintptr - Alignment uint16 - Type uint16 - Elements **Type -} - -/*typedef struct { - ffi_abi abi; - unsigned nargs; - ffi_type **arg_types; - ffi_type *rtype; - unsigned bytes; - unsigned flags; -#ifdef FFI_EXTRA_CIF_FIELDS - FFI_EXTRA_CIF_FIELDS; -#endif -} ffi_cif; -*/ - -type Cif struct { - Abi c.Uint - NArgs c.Uint - ArgTypes **Type - RType *Type - Bytes c.Uint - Flags c.Uint - //Extra c.Uint -} - -/* -ffi_status -ffi_prep_cif(ffi_cif *cif, - ffi_abi abi, - unsigned int nargs, - ffi_type *rtype, - ffi_type **atypes); -*/ -//go:linkname PrepCif C.ffi_prep_cif -func PrepCif(cif *Cif, abi c.Uint, nargs c.Uint, rtype *Type, atype **Type) c.Uint - -/* -ffi_status ffi_prep_cif_var(ffi_cif *cif, - ffi_abi abi, - unsigned int nfixedargs, - unsigned int ntotalargs, - ffi_type *rtype, - ffi_type **atypes); -*/ -//go:linkname PrepCifVar C.ffi_prep_cif_var -func PrepCifVar(cif *Cif, abi c.Uint, nfixedargs c.Uint, ntotalargs c.Uint, rtype *Type, atype **Type) c.Uint - -/* -void ffi_call(ffi_cif *cif, - void (*fn)(void), - void *rvalue, - void **avalue); -*/ -//go:linkname Call C.ffi_call -func Call(cif *Cif, fn unsafe.Pointer, rvalue unsafe.Pointer, avalue *unsafe.Pointer) - -// void *ffi_closure_alloc (size_t size, void **code); -// -//go:linkname ClosureAlloc C.llog_ffi_closure_alloc -func ClosureAlloc(code *unsafe.Pointer) unsafe.Pointer - -// void ffi_closure_free (void *); -// -//go:linkname ClosureFree C.ffi_closure_free -func ClosureFree(unsafe.Pointer) - -/* -ffi_status -ffi_prep_closure_loc (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc); -*/ - -//llgo:type C -type ClosureFunc func(cif *Cif, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) - -//go:linkname PreClosureLoc C.ffi_prep_closure_loc -func PreClosureLoc(closure unsafe.Pointer, cif *Cif, fn ClosureFunc, userdata unsafe.Pointer, codeloc unsafe.Pointer) c.Uint diff --git a/x/ffi/_demo/_wrap/wrap.c b/x/ffi/_demo/_wrap/wrap.c new file mode 100644 index 00000000..07f31c0a --- /dev/null +++ b/x/ffi/_demo/_wrap/wrap.c @@ -0,0 +1,25 @@ +#include + +struct array +{ + int x; + int y; + int z; + int k; +}; + +int demo1(struct array a) +{ + printf("c.demo1: %d %d %d %d\n",a.x,a.y,a.z,a.k); + return a.x+a.y+a.z+a.k; +} + +int demo2( int (*fn)(struct array)) { + printf("c.demo2: %p\n",fn); + struct array a; + a.x = 1; + a.y = 2; + a.z = 3; + a.k = 4; + return (*fn)(a); +} diff --git a/x/ffi/_demo/cfunc/main.go b/x/ffi/_demo/cfunc/main.go new file mode 100644 index 00000000..f2111dce --- /dev/null +++ b/x/ffi/_demo/cfunc/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/x/ffi" +) + +const ( + LLGoPackage = "link" + LLGoFiles = "../_wrap/wrap.c" +) + +//llgo:type C +type Callback func(array) c.Int + +//go:linkname demo1 C.demo1 +func demo1(array) c.Int + +//go:linkname demo2 C.demo2 +func demo2(fn Callback) c.Int + +//llgo:type C +type array struct { + x c.Int + y c.Int + z c.Int + k c.Int +} + +func main() { + cdemo1() + cdemo2() +} + +func cdemo1() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.StructOf(ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32, ffi.TypeInt32)) + if err != nil { + panic(err) + } + ar := array{1, 2, 3, 4} + var ret int32 + ffi.Call(sig, c.Func(demo1), unsafe.Pointer(&ret), unsafe.Pointer(&ar)) + c.Printf(c.Str("ret: %d\n"), ret) +} + +func cdemo2() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + var ret int32 + fn := c.Func(demo1) + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/x/ffi/_demo/closure/main.go b/x/ffi/_demo/closure/main.go new file mode 100644 index 00000000..f50f1879 --- /dev/null +++ b/x/ffi/_demo/closure/main.go @@ -0,0 +1,78 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/x/ffi" +) + +const ( + LLGoPackage = "link" + LLGoFiles = "../_wrap/wrap.c" +) + +//llgo:type C +type Callback func(array) c.Int + +//go:linkname demo1 C.demo1 +func demo1(array) c.Int + +//go:linkname demo2 C.demo2 +func demo2(fn Callback) c.Int + +//llgo:type C +type array struct { + x c.Int + y c.Int + z c.Int + k c.Int +} + +func demo(a array) c.Int { + c.Printf(c.Str("go.demo %d %d %d %d\n"), a.x, a.y, a.z, a.k) + return a.x + a.y + a.z + a.k +} + +func main() { + gofn() + c.Printf(c.Str("\n")) + goclosure() +} + +func gofn() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + closure := ffi.NewClosure() + defer closure.Free() + err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + ar := *(*array)(ffi.Index(args, 0)) + *(*c.Int)(ret) = demo(ar) + }, nil) + var ret int32 + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} + +func goclosure() { + sig, err := ffi.NewSignature(ffi.TypeInt32, ffi.TypePointer) + if err != nil { + panic(err) + } + fn := func(ar array) c.Int { + c.Printf(c.Str("call closure %d\n"), sig.NArgs) + return demo(ar) + } + closure := ffi.NewClosure() + defer closure.Free() + err = closure.Bind(sig, func(cif *ffi.Signature, ret unsafe.Pointer, args *unsafe.Pointer, userdata unsafe.Pointer) { + ar := *(*array)(ffi.Index(args, 0)) + fn := *(*func(array) c.Int)(userdata) + *(*c.Int)(ret) = fn(ar) + }, unsafe.Pointer(&fn)) + var ret int32 + ffi.Call(sig, c.Func(demo2), unsafe.Pointer(&ret), unsafe.Pointer(&closure.Fn)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/c/ffi/_demo/gofunc/main.go b/x/ffi/_demo/gofunc/main.go similarity index 97% rename from c/ffi/_demo/gofunc/main.go rename to x/ffi/_demo/gofunc/main.go index 10af70a8..b6bb486e 100644 --- a/c/ffi/_demo/gofunc/main.go +++ b/x/ffi/_demo/gofunc/main.go @@ -3,7 +3,7 @@ package main import ( "unsafe" - "github.com/goplus/llgo/c/ffi" + "github.com/goplus/llgo/x/ffi" ) type array struct { diff --git a/x/ffi/_demo/printf/main.go b/x/ffi/_demo/printf/main.go new file mode 100644 index 00000000..6fca035e --- /dev/null +++ b/x/ffi/_demo/printf/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/x/ffi" +) + +func main() { + sig, err := ffi.NewSignatureVar(ffi.TypeInt32, 1, ffi.TypePointer, ffi.TypeInt32) + if err != nil { + panic(err) + } + var ret int32 + text := c.Str("hello world: %d\n") + var n int32 = 100 + ffi.Call(sig, c.Func(c.Printf), unsafe.Pointer(&ret), unsafe.Pointer(&text), unsafe.Pointer(&n)) + c.Printf(c.Str("ret: %d\n"), ret) +} diff --git a/x/ffi/ffi.go b/x/ffi/ffi.go new file mode 100644 index 00000000..f07a6574 --- /dev/null +++ b/x/ffi/ffi.go @@ -0,0 +1,93 @@ +package ffi + +import ( + "fmt" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/ffi" +) + +type Type = ffi.Type + +type Signature = ffi.Cif + +type Error int + +func (s Error) Error() string { + switch s { + case ffi.OK: + return "ok" + case ffi.BAD_TYPEDEF: + return "bad type def" + case ffi.BAD_ABI: + return "bad ABI" + case ffi.BAD_ARGTYPE: + return "bad argument type" + } + return fmt.Sprintf("invalid status: %v", int(s)) +} + +func NewSignature(ret *Type, args ...*Type) (*Signature, error) { + var cif Signature + var atype **Type + if len(args) > 0 { + atype = &args[0] + } + status := ffi.PrepCif(&cif, ffi.DefaultAbi, c.Uint(len(args)), ret, atype) + if status == 0 { + return &cif, nil + } + return nil, Error(status) +} + +func NewSignatureVar(ret *Type, fixed int, args ...*Type) (*Signature, error) { + var cif Signature + var atype **Type + if len(args) > 0 { + atype = &args[0] + } + status := ffi.PrepCifVar(&cif, ffi.DefaultAbi, c.Uint(fixed), c.Uint(len(args)), ret, atype) + if status == ffi.OK { + return &cif, nil + } + return nil, Error(status) +} + +func Call(cif *Signature, fn unsafe.Pointer, ret unsafe.Pointer, args ...unsafe.Pointer) { + var avalues *unsafe.Pointer + if len(args) > 0 { + avalues = &args[0] + } + ffi.Call(cif, fn, ret, avalues) +} + +type Closure struct { + ptr unsafe.Pointer + Fn unsafe.Pointer +} + +func NewClosure() *Closure { + c := &Closure{} + c.ptr = ffi.ClosureAlloc(&c.Fn) + return c +} + +func (c *Closure) Free() { + if c != nil && c.ptr != nil { + ffi.ClosureFree(c.ptr) + c.ptr = nil + } +} + +func (c *Closure) Bind(cif *Signature, fn ffi.ClosureFunc, userdata unsafe.Pointer) error { + status := ffi.PreClosureLoc(c.ptr, cif, fn, userdata, c.Fn) + if status == ffi.OK { + return nil + } + return Error(status) +} + +func Index(args *unsafe.Pointer, i uintptr) unsafe.Pointer { + return ffi.Index(args, i) +} diff --git a/c/ffi/type.go b/x/ffi/type.go similarity index 98% rename from c/ffi/type.go rename to x/ffi/type.go index 2ef77657..e43a806c 100644 --- a/c/ffi/type.go +++ b/x/ffi/type.go @@ -4,7 +4,7 @@ import ( "unsafe" "github.com/goplus/llgo/c" - "github.com/goplus/llgo/c/ffi/ffi" + "github.com/goplus/llgo/c/ffi" ) type BasicKind int