github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/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 return off; 85 } 86 87 /* Copy the results of calling a function via FFI from CALL_RESULT 88 into the addresses in RESULTS. */ 89 90 static void 91 go_set_results (const struct __go_func_type *func, unsigned char *call_result, 92 void **results) 93 { 94 int count; 95 const struct __go_type_descriptor **types; 96 size_t off; 97 int i; 98 99 count = func->__out.__count; 100 if (count == 0) 101 return; 102 103 types = (const struct __go_type_descriptor **) func->__out.__values; 104 105 /* A single integer return value is always promoted to a full 106 word. */ 107 if (count == 1) 108 { 109 switch (types[0]->__code & GO_CODE_MASK) 110 { 111 case GO_BOOL: 112 case GO_INT8: 113 case GO_INT16: 114 case GO_INT32: 115 case GO_UINT8: 116 case GO_UINT16: 117 case GO_UINT32: 118 case GO_INT: 119 case GO_UINT: 120 { 121 union 122 { 123 unsigned char buf[sizeof (ffi_arg)]; 124 ffi_arg v; 125 } u; 126 ffi_arg v; 127 128 __builtin_memcpy (&u.buf, call_result, sizeof (ffi_arg)); 129 v = u.v; 130 131 switch (types[0]->__size) 132 { 133 case 1: 134 { 135 uint8_t b; 136 137 b = (uint8_t) v; 138 __builtin_memcpy (results[0], &b, 1); 139 } 140 break; 141 142 case 2: 143 { 144 uint16_t s; 145 146 s = (uint16_t) v; 147 __builtin_memcpy (results[0], &s, 2); 148 } 149 break; 150 151 case 4: 152 { 153 uint32_t w; 154 155 w = (uint32_t) v; 156 __builtin_memcpy (results[0], &w, 4); 157 } 158 break; 159 160 case 8: 161 { 162 uint64_t d; 163 164 d = (uint64_t) v; 165 __builtin_memcpy (results[0], &d, 8); 166 } 167 break; 168 169 default: 170 abort (); 171 } 172 } 173 return; 174 175 default: 176 break; 177 } 178 } 179 180 off = 0; 181 for (i = 0; i < count; ++i) 182 { 183 size_t align; 184 size_t size; 185 186 align = types[i]->__field_align; 187 size = types[i]->__size; 188 off = (off + align - 1) & ~ (align - 1); 189 __builtin_memcpy (results[i], call_result + off, size); 190 off += size; 191 } 192 } 193 194 /* Call a function. The type of the function is FUNC_TYPE, and the 195 closure is FUNC_VAL. PARAMS is an array of parameter addresses. 196 RESULTS is an array of result addresses. 197 198 If IS_INTERFACE is true this is a call to an interface method and 199 the first argument is the receiver, which is always a pointer. 200 This argument, the receiver, is not described in FUNC_TYPE. 201 202 If IS_METHOD is true this is a call to a method expression. The 203 first argument is the receiver. It is described in FUNC_TYPE, but 204 regardless of FUNC_TYPE, it is passed as a pointer. */ 205 206 void 207 reflect_call (const struct __go_func_type *func_type, FuncVal *func_val, 208 _Bool is_interface, _Bool is_method, void **params, 209 void **results) 210 { 211 ffi_cif cif; 212 unsigned char *call_result; 213 214 __go_assert ((func_type->__common.__code & GO_CODE_MASK) == GO_FUNC); 215 __go_func_to_cif (func_type, is_interface, is_method, &cif); 216 217 call_result = (unsigned char *) malloc (go_results_size (func_type)); 218 219 ffi_call_go (&cif, func_val->fn, call_result, params, func_val); 220 221 /* Some day we may need to free result values if RESULTS is 222 NULL. */ 223 if (results != NULL) 224 go_set_results (func_type, call_result, results); 225 226 free (call_result); 227 } 228 229 #else /* !defined(USE_LIBFFI) */ 230 231 void 232 reflect_call (const struct __go_func_type *func_type __attribute__ ((unused)), 233 FuncVal *func_val __attribute__ ((unused)), 234 _Bool is_interface __attribute__ ((unused)), 235 _Bool is_method __attribute__ ((unused)), 236 void **params __attribute__ ((unused)), 237 void **results __attribute__ ((unused))) 238 { 239 /* Without FFI there is nothing we can do. */ 240 runtime_throw("libgo built without FFI does not support " 241 "reflect.Call or runtime.SetFinalizer"); 242 } 243 244 #endif /* !defined(USE_LIBFFI) */