github.com/golang/gofrontend@v0.0.0-20240429183944-60f985a78526/libgo/runtime/go-reflect-call.c (about) 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 14 #ifdef USE_LIBFFI 15 #include "ffi.h" 16 #endif 17 18 #if defined(USE_LIBFFI) && FFI_GO_CLOSURES 19 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 24 static size_t go_results_size (const struct functype *) 25 __attribute__ ((no_split_stack)); 26 static void go_set_results (const struct functype *, unsigned char *, 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 33 go_results_size (const struct functype *func) 34 { 35 int count; 36 const struct _type **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 _type **) func->out.__values; 46 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.*/ 49 if (count == 1) 50 { 51 switch (types[0]->kind & kindMask) 52 { 53 case kindBool: 54 case kindInt8: 55 case kindInt16: 56 case kindInt32: 57 case kindUint8: 58 case kindUint16: 59 case kindUint32: 60 return sizeof (ffi_arg); 61 62 default: 63 break; 64 } 65 } 66 67 off = 0; 68 maxalign = 0; 69 for (i = 0; i < count; ++i) 70 { 71 size_t align; 72 73 align = types[i]->fieldAlign; 74 if (align > maxalign) 75 maxalign = align; 76 off = (off + align - 1) & ~ (align - 1); 77 off += types[i]->size; 78 } 79 80 off = (off + maxalign - 1) & ~ (maxalign - 1); 81 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 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 95 go_set_results (const struct functype *func, unsigned char *call_result, 96 void **results) 97 { 98 int count; 99 const struct _type **types; 100 size_t off; 101 int i; 102 103 count = func->out.__count; 104 if (count == 0) 105 return; 106 107 types = (const struct _type **) func->out.__values; 108 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.*/ 111 if (count == 1) 112 { 113 switch (types[0]->kind & kindMask) 114 { 115 case kindBool: 116 case kindInt8: 117 case kindInt16: 118 case kindInt32: 119 case kindUint8: 120 case kindUint16: 121 case kindUint32: 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 133 switch (types[0]->size) 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 182 off = 0; 183 for (i = 0; i < count; ++i) 184 { 185 size_t align; 186 size_t size; 187 188 align = types[i]->fieldAlign; 189 size = types[i]->size; 190 off = (off + align - 1) & ~ (align - 1); 191 __builtin_memcpy (results[i], call_result + off, size); 192 off += size; 193 } 194 } 195 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. */ 198 extern void ffiFuncToCIF(const struct functype*, _Bool, _Bool, ffi_cif*) 199 __asm__ ("runtime.ffiFuncToCIF"); 200 201 /* Call a function. The type of the function is FUNC_TYPE, and the 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 211 regardless of FUNC_TYPE, it is passed as a pointer. */ 212 213 void 214 reflect_call (const struct functype *func_type, FuncVal *func_val, 215 _Bool is_interface, _Bool is_method, void **params, 216 void **results) 217 { 218 ffi_cif cif; 219 unsigned char *call_result; 220 221 __go_assert ((func_type->typ.kind & kindMask) == kindFunc); 222 ffiFuncToCIF (func_type, is_interface, is_method, &cif); 223 224 call_result = (unsigned char *) malloc (go_results_size (func_type)); 225 226 ffi_call_go (&cif, (void (*)(void)) func_val->fn, call_result, params, 227 func_val); 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 } 236 237 #else /* !defined(USE_LIBFFI) */ 238 239 void 240 reflect_call (const struct functype *func_type __attribute__ ((unused)), 241 FuncVal *func_val __attribute__ ((unused)), 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) */