| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| #include "runtime.h" |
| #include "go-type.h" |
| #include "go-panic.h" |
| |
| #ifdef USE_LIBFFI |
| |
| #include "go-ffi.h" |
| |
| #if FFI_GO_CLOSURES |
| #define USE_LIBFFI_CLOSURES |
| #endif |
| |
| #endif /* defined(USE_LIBFFI) */ |
| |
| /* Declare C functions with the names used to call from Go. */ |
| |
| void makeFuncFFI(const struct __go_func_type *ftyp, void *impl) |
| __asm__ (GOSYM_PREFIX "reflect.makeFuncFFI"); |
| |
| #ifdef USE_LIBFFI_CLOSURES |
| |
| /* 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 *closure) |
| { |
| Location locs[8]; |
| int n; |
| int i; |
| |
| /* This function is called from some series of FFI closure functions |
| called by a Go function. We want to see whether the caller of |
| the closure functions can recover. Look up the stack and skip |
| the FFI functions. */ |
| n = runtime_callers (1, &locs[0], sizeof locs / sizeof locs[0], true); |
| for (i = 0; i < n; i++) |
| { |
| const byte *name; |
| |
| if (locs[i].function.len == 0) |
| continue; |
| if (locs[i].function.len < 4) |
| break; |
| name = locs[i].function.str; |
| if (name[0] != 'f' || name[1] != 'f' || name[2] != 'i' || name[3] != '_') |
| break; |
| } |
| if (i < n) |
| __go_makefunc_ffi_can_recover (locs + i, n - i); |
| |
| FFICallbackGo(results, args, closure); |
| |
| if (i < n) |
| __go_makefunc_returning (); |
| } |
| |
| /* Allocate an FFI closure and arrange to call ffi_callback. */ |
| |
| void |
| makeFuncFFI(const struct __go_func_type *ftyp, void *impl) |
| { |
| ffi_cif *cif; |
| |
| cif = (ffi_cif *) __go_alloc (sizeof (ffi_cif)); |
| __go_func_to_cif (ftyp, 0, 0, cif); |
| |
| ffi_prep_go_closure(impl, cif, ffi_callback); |
| } |
| |
| #else /* !defined(USE_LIBFFI_CLOSURES) */ |
| |
| void |
| makeFuncFFI(const struct __go_func_type *ftyp __attribute__ ((unused)), |
| void *impl __attribute__ ((unused))) |
| { |
| runtime_panicstring ("libgo built without FFI does not support " |
| "reflect.MakeFunc"); |
| } |
| |
| #endif |