1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 #include "runtime.h"
6
7 #ifdef USE_LIBFFI
8
9 #include "ffi.h"
10
11 #if FFI_GO_CLOSURES
12 #define USE_LIBFFI_CLOSURES
13 #endif
14
15 #endif /* defined(USE_LIBFFI) */
16
17 /* Declare C functions with the names used to call from Go. */
18
19 void makeFuncFFI(void *cif, void *impl)
20 __asm__ (GOSYM_PREFIX "reflect.makeFuncFFI");
21
22 #ifdef USE_LIBFFI_CLOSURES
23
24 /* The function that we pass to ffi_prep_closure_loc. This calls the Go
25 function ffiCall with the pointer to the arguments, the results area,
26 and the closure structure. */
27
28 extern void ffiCallbackGo(void *result, void **args, ffi_go_closure *closure,
29 int32 wordsize, _Bool big_endian)
30 __asm__ (GOSYM_PREFIX "reflect.ffiCallbackGo");
31
32 extern void makefuncfficanrecover(Slice)
33 __asm__ (GOSYM_PREFIX "runtime.makefuncfficanrecover");
34
35 extern void makefuncreturning(void)
36 __asm__ (GOSYM_PREFIX "runtime.makefuncreturning");
37
38 static void ffi_callback (ffi_cif *, void *, void **, void *)
39 __asm__ ("reflect.ffi_callback");
40
41 static void
42 ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
43 void **args, void *closure)
44 {
45 Location locs[8];
46 int n;
47 int i;
48
49 /* This function is called from some series of FFI closure functions
50 called by a Go function. We want to see whether the caller of
51 the closure functions can recover. Look up the stack and skip
52 the FFI functions. */
53 n = runtime_callers (1, &locs[0], sizeof locs / sizeof locs[0], true);
54 for (i = 0; i < n; i++)
55 {
56 const byte *name;
57
58 if (locs[i].function.len == 0)
59 continue;
60 if (locs[i].function.len < 4)
61 break;
62 name = locs[i].function.str;
63 if (name[0] != 'f' || name[1] != 'f' || name[2] != 'i' || name[3] != '_')
64 break;
65 }
66 if (i < n)
67 {
68 Slice s;
69
70 s.__values = (void *) &locs[i];
71 s.__count = n - i;
72 s.__capacity = n - i;
73 makefuncfficanrecover (s);
74 }
75
76 ffiCallbackGo(results, args, closure, sizeof(ffi_arg),
77 __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
78
79 if (i < n)
80 makefuncreturning ();
81 }
82
83 /* Allocate an FFI closure and arrange to call ffi_callback. */
84
85 void
86 makeFuncFFI(void *cif, void *impl)
87 {
88 ffi_prep_go_closure(impl, (ffi_cif*)cif, ffi_callback);
89 }
90
91 #else /* !defined(USE_LIBFFI_CLOSURES) */
92
93 void
94 makeFuncFFI(void *cif __attribute__ ((unused)),
95 void *impl __attribute__ ((unused)))
96 {
97 runtime_panicstring ("libgo built without FFI does not support "
98 "reflect.MakeFunc");
99 }
100
101 #endif