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
go_results_size(const struct __go_func_type * func)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
go_set_results(const struct __go_func_type * func,unsigned char * call_result,void ** results)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
reflect_call(const struct __go_func_type * func_type,FuncVal * func_val,_Bool is_interface,_Bool is_method,void ** params,void ** results)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, func_val->fn, call_result, params, func_val);
233 
234   /* Some day we may need to free result values if RESULTS is
235      NULL.  */
236   if (results != NULL)
237     go_set_results (func_type, call_result, results);
238 
239   free (call_result);
240 }
241 
242 #else /* !defined(USE_LIBFFI) */
243 
244 void
reflect_call(const struct __go_func_type * func_type,FuncVal * func_val,_Bool is_interface,_Bool is_method,void ** params,void ** results)245 reflect_call (const struct __go_func_type *func_type __attribute__ ((unused)),
246 	      FuncVal *func_val __attribute__ ((unused)),
247 	      _Bool is_interface __attribute__ ((unused)),
248 	      _Bool is_method __attribute__ ((unused)),
249 	      void **params __attribute__ ((unused)),
250 	      void **results __attribute__ ((unused)))
251 {
252   /* Without FFI there is nothing we can do.  */
253   runtime_throw("libgo built without FFI does not support "
254 		"reflect.Call or runtime.SetFinalizer");
255 }
256 
257 #endif /* !defined(USE_LIBFFI) */
258