| // 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" |
| |
| #ifdef USE_LIBFFI |
| |
| #include "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(void *cif, 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. */ |
| |
| extern void FFICallbackGo(void *result, void **args, ffi_go_closure *closure) |
| __asm__ (GOSYM_PREFIX "reflect.FFICallbackGo"); |
| |
| extern void makefuncfficanrecover(Slice) |
| __asm__ (GOSYM_PREFIX "runtime.makefuncfficanrecover"); |
| |
| extern void makefuncreturning(void) |
| __asm__ (GOSYM_PREFIX "runtime.makefuncreturning"); |
| |
| 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) |
| { |
| Slice s; |
| |
| s.__values = (void *) &locs[i]; |
| s.__count = n - i; |
| s.__capacity = n - i; |
| makefuncfficanrecover (s); |
| } |
| |
| FFICallbackGo(results, args, closure); |
| |
| if (i < n) |
| makefuncreturning (); |
| } |
| |
| /* Allocate an FFI closure and arrange to call ffi_callback. */ |
| |
| void |
| makeFuncFFI(void *cif, void *impl) |
| { |
| ffi_prep_go_closure(impl, (ffi_cif*)cif, ffi_callback); |
| } |
| |
| #else /* !defined(USE_LIBFFI_CLOSURES) */ |
| |
| void |
| makeFuncFFI(void *cif __attribute__ ((unused)), |
| void *impl __attribute__ ((unused))) |
| { |
| runtime_panicstring ("libgo built without FFI does not support " |
| "reflect.MakeFunc"); |
| } |
| |
| #endif |