| // 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" | 
 |  | 
 | #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, | 
 |                           int32 wordsize, _Bool big_endian) | 
 |   __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, sizeof(ffi_arg), | 
 |                 __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__); | 
 |  | 
 |   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 |