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