1 /* go-reflect-call.c -- call reflection support for Go.
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. */
13 #include "go-assert.h"
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. */
24 static size_t go_results_size (const struct __go_func_type
*)
25 __attribute__ ((no_split_stack
));
26 static void go_set_results (const struct __go_func_type
*, unsigned char *,
28 __attribute__ ((no_split_stack
));
30 /* Get the total size required for the result parameters of a
34 go_results_size (const struct __go_func_type
*func
)
37 const struct __go_type_descriptor
**types
;
42 count
= func
->__out
.__count
;
46 types
= (const struct __go_type_descriptor
**) func
->__out
.__values
;
48 /* A single integer return value is always promoted to a full
52 switch (types
[0]->__code
& GO_CODE_MASK
)
63 return sizeof (ffi_arg
);
72 for (i
= 0; i
< count
; ++i
)
76 align
= types
[i
]->__field_align
;
79 off
= (off
+ align
- 1) & ~ (align
- 1);
80 off
+= types
[i
]->__size
;
83 off
= (off
+ maxalign
- 1) & ~ (maxalign
- 1);
88 /* Copy the results of calling a function via FFI from CALL_RESULT
89 into the addresses in RESULTS. */
92 go_set_results (const struct __go_func_type
*func
, unsigned char *call_result
,
96 const struct __go_type_descriptor
**types
;
100 count
= func
->__out
.__count
;
104 types
= (const struct __go_type_descriptor
**) func
->__out
.__values
;
106 /* A single integer return value is always promoted to a full
110 switch (types
[0]->__code
& GO_CODE_MASK
)
124 unsigned char buf
[sizeof (ffi_arg
)];
129 __builtin_memcpy (&u
.buf
, call_result
, sizeof (ffi_arg
));
132 switch (types
[0]->__size
)
139 __builtin_memcpy (results
[0], &b
, 1);
148 __builtin_memcpy (results
[0], &s
, 2);
157 __builtin_memcpy (results
[0], &w
, 4);
166 __builtin_memcpy (results
[0], &d
, 8);
182 for (i
= 0; i
< count
; ++i
)
187 align
= types
[i
]->__field_align
;
188 size
= types
[i
]->__size
;
189 off
= (off
+ align
- 1) & ~ (align
- 1);
190 __builtin_memcpy (results
[i
], call_result
+ off
, size
);
195 /* Call a function. The type of the function is FUNC_TYPE, and the
196 closure is FUNC_VAL. PARAMS is an array of parameter addresses.
197 RESULTS is an array of result addresses.
199 If IS_INTERFACE is true this is a call to an interface method and
200 the first argument is the receiver, which is always a pointer.
201 This argument, the receiver, is not described in FUNC_TYPE.
203 If IS_METHOD is true this is a call to a method expression. The
204 first argument is the receiver. It is described in FUNC_TYPE, but
205 regardless of FUNC_TYPE, it is passed as a pointer.
207 If neither IS_INTERFACE nor IS_METHOD is true then we are calling a
208 function indirectly, and we must pass a closure pointer via
209 __go_set_closure. The pointer to pass is simply FUNC_VAL. */
212 reflect_call (const struct __go_func_type
*func_type
, FuncVal
*func_val
,
213 _Bool is_interface
, _Bool is_method
, void **params
,
217 unsigned char *call_result
;
219 __go_assert ((func_type
->__common
.__code
& GO_CODE_MASK
) == GO_FUNC
);
220 __go_func_to_cif (func_type
, is_interface
, is_method
, &cif
);
222 call_result
= (unsigned char *) malloc (go_results_size (func_type
));
224 if (!is_interface
&& !is_method
)
225 __go_set_closure (func_val
);
226 ffi_call (&cif
, func_val
->fn
, call_result
, params
);
228 /* Some day we may need to free result values if RESULTS is
231 go_set_results (func_type
, call_result
, results
);
236 #else /* !defined(USE_LIBFFI) */
239 reflect_call (const struct __go_func_type
*func_type
__attribute__ ((unused
)),
240 FuncVal
*func_val
__attribute__ ((unused
)),
241 _Bool is_interface
__attribute__ ((unused
)),
242 _Bool is_method
__attribute__ ((unused
)),
243 void **params
__attribute__ ((unused
)),
244 void **results
__attribute__ ((unused
)))
246 /* Without FFI there is nothing we can do. */
247 runtime_throw("libgo built without FFI does not support "
248 "reflect.Call or runtime.SetFinalizer");
251 #endif /* !defined(USE_LIBFFI) */