]>
Commit | Line | Data |
---|---|---|
7a938933 ILT |
1 | /* go-reflect-call.c -- call reflection support for Go. |
2 | ||
3 | Copyright 2009 The Go Authors. All rights reserved. | |
4 | Use of this source code is governed by a BSD-style | |
5 | license that can be found in the LICENSE file. */ | |
6 | ||
7 | #include <stdio.h> | |
83a5c149 | 8 | #include <stdint.h> |
7a938933 ILT |
9 | #include <stdlib.h> |
10 | ||
776f27a6 | 11 | #include "runtime.h" |
7a938933 | 12 | #include "go-assert.h" |
5302cd02 ILT |
13 | |
14 | #ifdef USE_LIBFFI | |
15 | #include "ffi.h" | |
16 | #endif | |
35ea42eb | 17 | |
38bf819a RH |
18 | #if defined(USE_LIBFFI) && FFI_GO_CLOSURES |
19 | ||
9ff56c95 ILT |
20 | /* The functions in this file are only called from reflect_call. As |
21 | reflect_call calls a libffi function, which will be compiled | |
22 | without -fsplit-stack, it will always run with a large stack. */ | |
23 | ||
4a140826 | 24 | static size_t go_results_size (const struct functype *) |
9ff56c95 | 25 | __attribute__ ((no_split_stack)); |
4a140826 | 26 | static void go_set_results (const struct functype *, unsigned char *, void **) |
9ff56c95 | 27 | __attribute__ ((no_split_stack)); |
7a938933 | 28 | |
7a938933 ILT |
29 | /* Get the total size required for the result parameters of a |
30 | function. */ | |
31 | ||
32 | static size_t | |
4a140826 | 33 | go_results_size (const struct functype *func) |
7a938933 ILT |
34 | { |
35 | int count; | |
4a140826 | 36 | const struct _type **types; |
7a938933 ILT |
37 | size_t off; |
38 | size_t maxalign; | |
39 | int i; | |
40 | ||
4a140826 | 41 | count = func->out.__count; |
7a938933 ILT |
42 | if (count == 0) |
43 | return 0; | |
44 | ||
4a140826 | 45 | types = (const struct _type **) func->out.__values; |
7a938933 | 46 | |
033425d0 ILT |
47 | /* A single integer return value is always promoted to a full word. |
48 | There is similar code below and in libgo/go/reflect/makefunc_ffi.go.*/ | |
83a5c149 ILT |
49 | if (count == 1) |
50 | { | |
4a140826 | 51 | switch (types[0]->kind & kindMask) |
83a5c149 | 52 | { |
4a140826 ILT |
53 | case kindBool: |
54 | case kindInt8: | |
55 | case kindInt16: | |
56 | case kindInt32: | |
57 | case kindUint8: | |
58 | case kindUint16: | |
59 | case kindUint32: | |
83a5c149 ILT |
60 | return sizeof (ffi_arg); |
61 | ||
62 | default: | |
63 | break; | |
64 | } | |
65 | } | |
66 | ||
7a938933 ILT |
67 | off = 0; |
68 | maxalign = 0; | |
69 | for (i = 0; i < count; ++i) | |
70 | { | |
71 | size_t align; | |
72 | ||
4a140826 | 73 | align = types[i]->fieldAlign; |
7a938933 ILT |
74 | if (align > maxalign) |
75 | maxalign = align; | |
76 | off = (off + align - 1) & ~ (align - 1); | |
4a140826 | 77 | off += types[i]->size; |
7a938933 ILT |
78 | } |
79 | ||
80 | off = (off + maxalign - 1) & ~ (maxalign - 1); | |
81 | ||
8c612867 ILT |
82 | // The libffi library doesn't understand a struct with no fields. |
83 | // We generate a struct with a single field of type void. When used | |
84 | // as a return value, libffi will think that requires a byte. | |
85 | if (off == 0) | |
86 | off = 1; | |
87 | ||
7a938933 ILT |
88 | return off; |
89 | } | |
90 | ||
91 | /* Copy the results of calling a function via FFI from CALL_RESULT | |
92 | into the addresses in RESULTS. */ | |
93 | ||
94 | static void | |
4a140826 | 95 | go_set_results (const struct functype *func, unsigned char *call_result, |
7a938933 ILT |
96 | void **results) |
97 | { | |
98 | int count; | |
4a140826 | 99 | const struct _type **types; |
7a938933 ILT |
100 | size_t off; |
101 | int i; | |
102 | ||
4a140826 | 103 | count = func->out.__count; |
7a938933 ILT |
104 | if (count == 0) |
105 | return; | |
106 | ||
4a140826 | 107 | types = (const struct _type **) func->out.__values; |
7a938933 | 108 | |
033425d0 ILT |
109 | /* A single integer return value is always promoted to a full word. |
110 | There is similar code above and in libgo/go/reflect/makefunc_ffi.go.*/ | |
83a5c149 ILT |
111 | if (count == 1) |
112 | { | |
4a140826 | 113 | switch (types[0]->kind & kindMask) |
83a5c149 | 114 | { |
4a140826 ILT |
115 | case kindBool: |
116 | case kindInt8: | |
117 | case kindInt16: | |
118 | case kindInt32: | |
119 | case kindUint8: | |
120 | case kindUint16: | |
121 | case kindUint32: | |
83a5c149 ILT |
122 | { |
123 | union | |
124 | { | |
125 | unsigned char buf[sizeof (ffi_arg)]; | |
126 | ffi_arg v; | |
127 | } u; | |
128 | ffi_arg v; | |
129 | ||
130 | __builtin_memcpy (&u.buf, call_result, sizeof (ffi_arg)); | |
131 | v = u.v; | |
132 | ||
4a140826 | 133 | switch (types[0]->size) |
83a5c149 ILT |
134 | { |
135 | case 1: | |
136 | { | |
137 | uint8_t b; | |
138 | ||
139 | b = (uint8_t) v; | |
140 | __builtin_memcpy (results[0], &b, 1); | |
141 | } | |
142 | break; | |
143 | ||
144 | case 2: | |
145 | { | |
146 | uint16_t s; | |
147 | ||
148 | s = (uint16_t) v; | |
149 | __builtin_memcpy (results[0], &s, 2); | |
150 | } | |
151 | break; | |
152 | ||
153 | case 4: | |
154 | { | |
155 | uint32_t w; | |
156 | ||
157 | w = (uint32_t) v; | |
158 | __builtin_memcpy (results[0], &w, 4); | |
159 | } | |
160 | break; | |
161 | ||
162 | case 8: | |
163 | { | |
164 | uint64_t d; | |
165 | ||
166 | d = (uint64_t) v; | |
167 | __builtin_memcpy (results[0], &d, 8); | |
168 | } | |
169 | break; | |
170 | ||
171 | default: | |
172 | abort (); | |
173 | } | |
174 | } | |
175 | return; | |
176 | ||
177 | default: | |
178 | break; | |
179 | } | |
180 | } | |
181 | ||
7a938933 ILT |
182 | off = 0; |
183 | for (i = 0; i < count; ++i) | |
184 | { | |
185 | size_t align; | |
186 | size_t size; | |
187 | ||
4a140826 ILT |
188 | align = types[i]->fieldAlign; |
189 | size = types[i]->size; | |
7a938933 ILT |
190 | off = (off + align - 1) & ~ (align - 1); |
191 | __builtin_memcpy (results[i], call_result + off, size); | |
192 | off += size; | |
193 | } | |
194 | } | |
195 | ||
5302cd02 ILT |
196 | /* The code that converts the Go type to an FFI type is written in Go, |
197 | so that it can allocate Go heap memory. */ | |
4a140826 | 198 | extern void ffiFuncToCIF(const struct functype*, _Bool, _Bool, ffi_cif*) |
5302cd02 ILT |
199 | __asm__ ("runtime.ffiFuncToCIF"); |
200 | ||
7a938933 | 201 | /* Call a function. The type of the function is FUNC_TYPE, and the |
fdbc38a6 ILT |
202 | closure is FUNC_VAL. PARAMS is an array of parameter addresses. |
203 | RESULTS is an array of result addresses. | |
204 | ||
205 | If IS_INTERFACE is true this is a call to an interface method and | |
206 | the first argument is the receiver, which is always a pointer. | |
207 | This argument, the receiver, is not described in FUNC_TYPE. | |
208 | ||
209 | If IS_METHOD is true this is a call to a method expression. The | |
210 | first argument is the receiver. It is described in FUNC_TYPE, but | |
38bf819a | 211 | regardless of FUNC_TYPE, it is passed as a pointer. */ |
7a938933 ILT |
212 | |
213 | void | |
4a140826 | 214 | reflect_call (const struct functype *func_type, FuncVal *func_val, |
9ff56c95 ILT |
215 | _Bool is_interface, _Bool is_method, void **params, |
216 | void **results) | |
7a938933 ILT |
217 | { |
218 | ffi_cif cif; | |
219 | unsigned char *call_result; | |
220 | ||
4a140826 | 221 | __go_assert ((func_type->typ.kind & kindMask) == kindFunc); |
5302cd02 | 222 | ffiFuncToCIF (func_type, is_interface, is_method, &cif); |
7a938933 ILT |
223 | |
224 | call_result = (unsigned char *) malloc (go_results_size (func_type)); | |
225 | ||
8a9f2a6b ILT |
226 | ffi_call_go (&cif, (void (*)(void)) func_val->fn, call_result, params, |
227 | func_val); | |
7a938933 ILT |
228 | |
229 | /* Some day we may need to free result values if RESULTS is | |
230 | NULL. */ | |
231 | if (results != NULL) | |
232 | go_set_results (func_type, call_result, results); | |
233 | ||
234 | free (call_result); | |
235 | } | |
35ea42eb ILT |
236 | |
237 | #else /* !defined(USE_LIBFFI) */ | |
238 | ||
239 | void | |
4a140826 | 240 | reflect_call (const struct functype *func_type __attribute__ ((unused)), |
fdbc38a6 | 241 | FuncVal *func_val __attribute__ ((unused)), |
35ea42eb ILT |
242 | _Bool is_interface __attribute__ ((unused)), |
243 | _Bool is_method __attribute__ ((unused)), | |
244 | void **params __attribute__ ((unused)), | |
245 | void **results __attribute__ ((unused))) | |
246 | { | |
247 | /* Without FFI there is nothing we can do. */ | |
248 | runtime_throw("libgo built without FFI does not support " | |
249 | "reflect.Call or runtime.SetFinalizer"); | |
250 | } | |
251 | ||
252 | #endif /* !defined(USE_LIBFFI) */ |