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