github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/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-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 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 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 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 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) */