This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 08/13] libgo: Use the new libffi interfaces for Go


This does drop support for targets whose libffi hasn't been updated,
but if we go this way that should be fairly easy to do.
---
 libgo/go/reflect/makefunc.go      | 49 ++++++++++------------------
 libgo/go/reflect/makefunc_ffi.go  | 67 ++++++++++++--------------------------
 libgo/go/reflect/makefunc_ffi_c.c | 68 +++++++++------------------------------
 libgo/go/reflect/value.go         |  3 ++
 libgo/runtime/go-reflect-call.c   | 10 ++----
 5 files changed, 59 insertions(+), 138 deletions(-)

diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 977aacf..23c63a7 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -14,7 +14,11 @@ import (
 // makeFuncImpl is the closure value implementing the function
 // returned by MakeFunc.
 type makeFuncImpl struct {
-	code uintptr
+	// These first three words are layed out like ffi_go_closure.
+	code	uintptr
+	ffi_cif	unsafe.Pointer
+	ffi_fun	func(unsafe.Pointer, unsafe.Pointer)
+
 	typ  *funcType
 	fn   func([]Value) []Value
 
@@ -22,10 +26,6 @@ type makeFuncImpl struct {
 	// method values.
 	method int
 	rcvr   Value
-
-	// When using FFI, hold onto the FFI closure for the garbage
-	// collector.
-	ffi *ffiData
 }
 
 // MakeFunc returns a new function of the given Type
@@ -58,25 +58,18 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 	t := typ.common()
 	ftyp := (*funcType)(unsafe.Pointer(t))
 
-	var code uintptr
-	var ffi *ffiData
-	switch runtime.GOARCH {
-	case "amd64", "386":
-		// Indirect Go func value (dummy) to obtain actual
-		// code address. (A Go func value is a pointer to a C
-		// function pointer. http://golang.org/s/go11func.)
-		dummy := makeFuncStub
-		code = **(**uintptr)(unsafe.Pointer(&dummy))
-	default:
-		code, ffi = makeFuncFFI(ftyp, fn)
-	}
-
 	impl := &makeFuncImpl{
-		code:   code,
 		typ:    ftyp,
 		fn:     fn,
 		method: -1,
-		ffi:    ffi,
+	}
+
+	switch runtime.GOARCH {
+	case "amd64", "386":
+		impl.code = makeFuncStubCode
+	default:
+		impl.fn = fn
+		makeFuncFFI(ftyp, impl)
 	}
 
 	return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
@@ -125,13 +118,9 @@ func makeMethodValue(op string, v Value) Value {
 
 	switch runtime.GOARCH {
 	case "amd64", "386":
-		// Indirect Go func value (dummy) to obtain actual
-		// code address. (A Go func value is a pointer to a C
-		// function pointer. http://golang.org/s/go11func.)
-		dummy := makeFuncStub
-		fv.code = **(**uintptr)(unsafe.Pointer(&dummy))
+		fv.code = makeFuncStubCode;
 	default:
-		fv.code, fv.ffi = makeFuncFFI(ftyp, fv.call)
+		makeFuncFFI(ftyp, fv)
 	}
 
 	return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func)<<flagKindShift | flagIndir}
@@ -160,13 +149,9 @@ func makeValueMethod(v Value) Value {
 
 	switch runtime.GOARCH {
 	case "amd64", "386":
-		// Indirect Go func value (dummy) to obtain actual
-		// code address. (A Go func value is a pointer to a C
-		// function pointer. http://golang.org/s/go11func.)
-		dummy := makeFuncStub
-		impl.code = **(**uintptr)(unsafe.Pointer(&dummy))
+		impl.code = makeFuncStubCode
 	default:
-		impl.code, impl.ffi = makeFuncFFI(ftyp, impl.call)
+		makeFuncFFI(ftyp, impl)
 	}
 
 	return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go
index a13ef17..5c764e3 100644
--- a/libgo/go/reflect/makefunc_ffi.go
+++ b/libgo/go/reflect/makefunc_ffi.go
@@ -5,52 +5,27 @@
 package reflect
 
 import (
-	"runtime"
 	"unsafe"
 )
 
-// The ffi function, written in C, allocates an FFI closure.  It
-// returns the code and data pointers.  When the code pointer is
-// called, it will call callback.  CIF is an FFI data structure
-// allocated as part of the closure, and is returned to ensure that
-// the GC retains it.
-func ffi(ftyp *funcType, callback func(unsafe.Pointer, unsafe.Pointer)) (code uintptr, data uintptr, cif unsafe.Pointer)
-
-// The ffiFree function, written in C, releases the FFI closure.
-func ffiFree(uintptr)
-
-// An ffiData holds the information needed to preserve an FFI closure
-// for the garbage collector.
-type ffiData struct {
-	code     uintptr
-	data     uintptr
-	cif      unsafe.Pointer
-	callback func(unsafe.Pointer, unsafe.Pointer)
-}
-
-// The makeFuncFFI function uses libffi closures to implement
-// reflect.MakeFunc.  This is used for processors for which we don't
-// have more efficient support.
-func makeFuncFFI(ftyp *funcType, fn func(args []Value) (results []Value)) (uintptr, *ffiData) {
-	callback := func(params, results unsafe.Pointer) {
-		ffiCall(ftyp, fn, params, results)
-	}
-
-	code, data, cif := ffi(ftyp, callback)
-
-	c := &ffiData{code: code, data: data, cif: cif, callback: callback}
-
-	runtime.SetFinalizer(c,
-		func(p *ffiData) {
-			ffiFree(p.data)
-		})
-
-	return code, c
-}
-
-// ffiCall takes pointers to the parameters, calls the function, and
-// stores the results back into memory.
-func ffiCall(ftyp *funcType, fn func([]Value) []Value, params unsafe.Pointer, results unsafe.Pointer) {
+// The makeFuncFFI function, written in C, fills in an FFI closure.
+// It arranges for ffiCall to be invoked directly from FFI.
+func makeFuncFFI(ftyp *funcType, impl *makeFuncImpl)
+
+// FFICallbackGo implements the Go side of the libffi callback.
+// It is exported so that C code can call it.
+//
+// The call chain arriving here looks like
+//   some_go_caller
+//   ->some_ffi_internals
+//     ->ffi_callback (in C)
+//       ->FFICallbackGo
+//
+// The ffi_callback handles __go_makefunc_can_recover, and
+// then passes off the data as received from ffi here.
+
+func FFICallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFuncImpl) {
+	ftyp := impl.typ
 	in := make([]Value, 0, len(ftyp.in))
 	ap := params
 	for _, rt := range ftyp.in {
@@ -61,18 +36,18 @@ func ffiCall(ftyp *funcType, fn func([]Value) []Value, params unsafe.Pointer, re
 		ap = (unsafe.Pointer)(uintptr(ap) + ptrSize)
 	}
 
-	out := fn(in)
+	out := impl.call(in)
 
 	off := uintptr(0)
 	for i, typ := range ftyp.out {
 		v := out[i]
 		if v.typ != typ {
-			panic("reflect: function created by MakeFunc using " + funcName(fn) +
+			panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
 				" returned wrong type: have " +
 				out[i].typ.String() + " for " + typ.String())
 		}
 		if v.flag&flagRO != 0 {
-			panic("reflect: function created by MakeFunc using " + funcName(fn) +
+			panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
 				" returned value obtained from unexported field")
 		}
 
diff --git a/libgo/go/reflect/makefunc_ffi_c.c b/libgo/go/reflect/makefunc_ffi_c.c
index a3dfd4a..727ae81 100644
--- a/libgo/go/reflect/makefunc_ffi_c.c
+++ b/libgo/go/reflect/makefunc_ffi_c.c
@@ -10,7 +10,7 @@
 
 #include "go-ffi.h"
 
-#if FFI_CLOSURES
+#if FFI_GO_CLOSURES
 #define USE_LIBFFI_CLOSURES
 #endif
 
@@ -18,36 +18,28 @@
 
 /* Declare C functions with the names used to call from Go.  */
 
-struct ffi_ret {
-  void *code;
-  void *data;
-  void *cif;
-};
-
-struct ffi_ret ffi(const struct __go_func_type *ftyp, FuncVal *callback)
-  __asm__ (GOSYM_PREFIX "reflect.ffi");
-
-void ffiFree(void *data)
-  __asm__ (GOSYM_PREFIX "reflect.ffiFree");
+void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
+  __asm__ (GOSYM_PREFIX "reflect.makeFuncFFI");
 
 #ifdef USE_LIBFFI_CLOSURES
 
-/* The function that we pass to ffi_prep_closure_loc.  This calls the
-   Go callback function (passed in user_data) with the pointer to the
-   arguments and the results area.  */
+/* The function that we pass to ffi_prep_closure_loc.  This calls the Go
+   function ffiCall with the pointer to the arguments, the results area,
+   and the closure structure.  */
+
+void FFICallbackGo(void *result, void **args, ffi_go_closure *closure)
+  __asm__ (GOSYM_PREFIX "reflect.FFICallbackGo");
 
 static void ffi_callback (ffi_cif *, void *, void **, void *)
   __asm__ ("reflect.ffi_callback");
 
 static void
 ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
-	      void **args, void *user_data)
+	      void **args, void *closure)
 {
   Location locs[8];
   int n;
   int i;
-  FuncVal *fv;
-  void (*f) (void *, void *);
 
   /* This function is called from some series of FFI closure functions
      called by a Go function.  We want to see whether the caller of
@@ -69,10 +61,7 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
   if (i < n)
     __go_makefunc_ffi_can_recover (locs + i, n - i);
 
-  fv = (FuncVal *) user_data;
-  __go_set_closure (fv);
-  f = (void *) fv->fn;
-  f (args, results);
+  FFICallbackGo(results, args, closure);
 
   if (i < n)
     __go_makefunc_returning ();
@@ -80,46 +69,21 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
 
 /* Allocate an FFI closure and arrange to call ffi_callback.  */
 
-struct ffi_ret
-ffi (const struct __go_func_type *ftyp, FuncVal *callback)
+void
+makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
 {
   ffi_cif *cif;
-  void *code;
-  void *data;
-  struct ffi_ret ret;
 
   cif = (ffi_cif *) __go_alloc (sizeof (ffi_cif));
   __go_func_to_cif (ftyp, 0, 0, cif);
-  data = ffi_closure_alloc (sizeof (ffi_closure), &code);
-  if (data == NULL)
-    runtime_panicstring ("ffi_closure_alloc failed");
-  if (ffi_prep_closure_loc (data, cif, ffi_callback, callback, code)
-      != FFI_OK)
-    runtime_panicstring ("ffi_prep_closure_loc failed");
-  ret.code = code;
-  ret.data = data;
-  ret.cif = cif;
-  return ret;
-}
-
-/* Free the FFI closure.  */
 
-void
-ffiFree (void *data)
-{
-  ffi_closure_free (data);
+  ffi_prep_go_closure(impl, cif, ffi_callback);
 }
 
 #else /* !defined(USE_LIBFFI_CLOSURES) */
 
-struct ffi_ret
-ffi(const struct __go_func_type *ftyp, FuncVal *callback)
-{
-  runtime_panicstring ("libgo built without FFI does not support "
-		       "reflect.MakeFunc");
-}
-
-void ffiFree(void *data)
+void
+makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
 {
   runtime_panicstring ("libgo built without FFI does not support "
 		       "reflect.MakeFunc");
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index c390b8e..1e0b537 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -427,6 +427,9 @@ func (v Value) CallSlice(in []Value) []Value {
 
 var callGC bool // for testing; see TestCallMethodJump
 
+// Indirect Go func value (dummy) to obtain actual
+// code address. (A Go func value is a pointer to a C
+// function pointer. http://golang.org/s/go11func.)
 var makeFuncStubFn = makeFuncStub
 var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn))
 
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
index dfc703e..692c8cc 100644
--- a/libgo/runtime/go-reflect-call.c
+++ b/libgo/runtime/go-reflect-call.c
@@ -202,11 +202,7 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result,
 
    If IS_METHOD is true this is a call to a method expression.  The
    first argument is the receiver.  It is described in FUNC_TYPE, but
-   regardless of FUNC_TYPE, it is passed as a pointer.
-
-   If neither IS_INTERFACE nor IS_METHOD is true then we are calling a
-   function indirectly, and we must pass a closure pointer via
-   __go_set_closure.  The pointer to pass is simply FUNC_VAL.  */
+   regardless of FUNC_TYPE, it is passed as a pointer.  */
 
 void
 reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
@@ -221,9 +217,7 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
 
   call_result = (unsigned char *) malloc (go_results_size (func_type));
 
-  if (!is_interface && !is_method)
-    __go_set_closure (func_val);
-  ffi_call (&cif, func_val->fn, call_result, params);
+  ffi_call_go (&cif, func_val->fn, call_result, params, func_val);
 
   /* Some day we may need to free result values if RESULTS is
      NULL.  */
-- 
1.9.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]