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

Reply via email to