From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14323 invoked by alias); 10 Oct 2014 20:43:49 -0000 Mailing-List: contact libffi-discuss-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libffi-discuss-owner@sourceware.org Received: (qmail 14034 invoked by uid 89); 10 Oct 2014 20:43:45 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL,BAYES_00,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-qg0-f41.google.com Received: from mail-qg0-f41.google.com (HELO mail-qg0-f41.google.com) (209.85.192.41) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 10 Oct 2014 20:43:41 +0000 Received: by mail-qg0-f41.google.com with SMTP id f51so4523371qge.0 for ; Fri, 10 Oct 2014 13:43:38 -0700 (PDT) X-Received: by 10.224.46.133 with SMTP id j5mr12445832qaf.92.1412973818687; Fri, 10 Oct 2014 13:43:38 -0700 (PDT) Received: from anchor.com (50-194-63-110-static.hfc.comcastbusiness.net. [50.194.63.110]) by mx.google.com with ESMTPSA id s49sm5909008qge.15.2014.10.10.13.43.37 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Oct 2014 13:43:38 -0700 (PDT) From: Richard Henderson To: gcc-patches@gcc.gnu.org Cc: libffi-discuss@sourceware.org, gofrontend-dev@googlegroups.com Subject: [PATCH 08/13] libgo: Use the new libffi interfaces for Go Date: Fri, 10 Oct 2014 20:43:00 -0000 Message-Id: <1412973773-3942-9-git-send-email-rth@redhat.com> In-Reply-To: <1412973773-3942-1-git-send-email-rth@redhat.com> References: <1412973773-3942-1-git-send-email-rth@redhat.com> X-IsSubscribed: yes X-SW-Source: 2014/txt/msg00104.txt.bz2 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<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