diff options
| author | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-19 21:36:26 +0000 |
|---|---|---|
| committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-19 21:36:26 +0000 |
| commit | dffa7328356257772dc7c00fe73aeb315229b373 (patch) | |
| tree | b56b22f6c7e733e05e3f634ca63f18e10bc1b304 /libgo/runtime/go-reflect-call.c | |
| parent | 0c92e4881a61a2483c2878f9953ff92188e9661e (diff) | |
| download | gcc-dffa7328356257772dc7c00fe73aeb315229b373.zip gcc-dffa7328356257772dc7c00fe73aeb315229b373.tar.gz gcc-dffa7328356257772dc7c00fe73aeb315229b373.tar.bz2 | |
reflect, runtime: Use libffi closures to implement reflect.MakeFunc.
Keep using the existing 386 and amd64 code on those archs,
since it is more efficient.
From-SVN: r212853
Diffstat (limited to 'libgo/runtime/go-reflect-call.c')
| -rw-r--r-- | libgo/runtime/go-reflect-call.c | 319 |
1 files changed, 2 insertions, 317 deletions
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c index 07b99d7..dfc703e 100644 --- a/libgo/runtime/go-reflect-call.c +++ b/libgo/runtime/go-reflect-call.c @@ -15,333 +15,18 @@ #ifdef USE_LIBFFI -#include "ffi.h" +#include "go-ffi.h" /* The functions in this file are only called from reflect_call. As reflect_call calls a libffi function, which will be compiled without -fsplit-stack, it will always run with a large stack. */ -static ffi_type *go_array_to_ffi (const struct __go_array_type *) - __attribute__ ((no_split_stack)); -static ffi_type *go_slice_to_ffi (const struct __go_slice_type *) - __attribute__ ((no_split_stack)); -static ffi_type *go_struct_to_ffi (const struct __go_struct_type *) - __attribute__ ((no_split_stack)); -static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack)); -static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack)); -static ffi_type *go_complex_to_ffi (ffi_type *) - __attribute__ ((no_split_stack, unused)); -static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *) - __attribute__ ((no_split_stack)); -static ffi_type *go_func_return_ffi (const struct __go_func_type *) - __attribute__ ((no_split_stack)); -static void go_func_to_cif (const struct __go_func_type *, _Bool, _Bool, - ffi_cif *) - __attribute__ ((no_split_stack)); static size_t go_results_size (const struct __go_func_type *) __attribute__ ((no_split_stack)); static void go_set_results (const struct __go_func_type *, unsigned char *, void **) __attribute__ ((no_split_stack)); -/* Return an ffi_type for a Go array type. The libffi library does - not have any builtin support for passing arrays as values. We work - around this by pretending that the array is a struct. */ - -static ffi_type * -go_array_to_ffi (const struct __go_array_type *descriptor) -{ - ffi_type *ret; - uintptr_t len; - ffi_type *element; - uintptr_t i; - - ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - ret->type = FFI_TYPE_STRUCT; - len = descriptor->__len; - ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *)); - element = go_type_to_ffi (descriptor->__element_type); - for (i = 0; i < len; ++i) - ret->elements[i] = element; - ret->elements[len] = NULL; - return ret; -} - -/* Return an ffi_type for a Go slice type. This describes the - __go_open_array type defines in array.h. */ - -static ffi_type * -go_slice_to_ffi ( - const struct __go_slice_type *descriptor __attribute__ ((unused))) -{ - ffi_type *ret; - ffi_type *ffi_intgo; - - ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - ret->type = FFI_TYPE_STRUCT; - ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *)); - ret->elements[0] = &ffi_type_pointer; - ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64; - ret->elements[1] = ffi_intgo; - ret->elements[2] = ffi_intgo; - ret->elements[3] = NULL; - return ret; -} - -/* Return an ffi_type for a Go struct type. */ - -static ffi_type * -go_struct_to_ffi (const struct __go_struct_type *descriptor) -{ - ffi_type *ret; - int field_count; - const struct __go_struct_field *fields; - int i; - - field_count = descriptor->__fields.__count; - if (field_count == 0) { - return &ffi_type_void; - } - ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - ret->type = FFI_TYPE_STRUCT; - fields = (const struct __go_struct_field *) descriptor->__fields.__values; - ret->elements = (ffi_type **) __go_alloc ((field_count + 1) - * sizeof (ffi_type *)); - for (i = 0; i < field_count; ++i) - ret->elements[i] = go_type_to_ffi (fields[i].__type); - ret->elements[field_count] = NULL; - return ret; -} - -/* Return an ffi_type for a Go string type. This describes the String - struct. */ - -static ffi_type * -go_string_to_ffi (void) -{ - ffi_type *ret; - ffi_type *ffi_intgo; - - ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - ret->type = FFI_TYPE_STRUCT; - ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *)); - ret->elements[0] = &ffi_type_pointer; - ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64; - ret->elements[1] = ffi_intgo; - ret->elements[2] = NULL; - return ret; -} - -/* Return an ffi_type for a Go interface type. This describes the - __go_interface and __go_empty_interface structs. */ - -static ffi_type * -go_interface_to_ffi (void) -{ - ffi_type *ret; - - ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - ret->type = FFI_TYPE_STRUCT; - ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *)); - ret->elements[0] = &ffi_type_pointer; - ret->elements[1] = &ffi_type_pointer; - ret->elements[2] = NULL; - return ret; -} - -/* Return an ffi_type for a Go complex type. */ - -static ffi_type * -go_complex_to_ffi (ffi_type *float_type) -{ - ffi_type *ret; - - ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - ret->type = FFI_TYPE_STRUCT; - ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *)); - ret->elements[0] = float_type; - ret->elements[1] = float_type; - ret->elements[2] = NULL; - return ret; -} - -/* Return an ffi_type for a type described by a - __go_type_descriptor. */ - -static ffi_type * -go_type_to_ffi (const struct __go_type_descriptor *descriptor) -{ - switch (descriptor->__code & GO_CODE_MASK) - { - case GO_BOOL: - if (sizeof (_Bool) == 1) - return &ffi_type_uint8; - else if (sizeof (_Bool) == sizeof (int)) - return &ffi_type_uint; - abort (); - case GO_FLOAT32: - if (sizeof (float) == 4) - return &ffi_type_float; - abort (); - case GO_FLOAT64: - if (sizeof (double) == 8) - return &ffi_type_double; - abort (); - case GO_COMPLEX64: -#ifdef __alpha__ - runtime_throw("the libffi library does not support Complex64 type with " - "reflect.Call or runtime.SetFinalizer"); -#else - if (sizeof (float) == 4) - return go_complex_to_ffi (&ffi_type_float); - abort (); -#endif - case GO_COMPLEX128: -#ifdef __alpha__ - runtime_throw("the libffi library does not support Complex128 type with " - "reflect.Call or runtime.SetFinalizer"); -#else - if (sizeof (double) == 8) - return go_complex_to_ffi (&ffi_type_double); - abort (); -#endif - case GO_INT16: - return &ffi_type_sint16; - case GO_INT32: - return &ffi_type_sint32; - case GO_INT64: - return &ffi_type_sint64; - case GO_INT8: - return &ffi_type_sint8; - case GO_INT: - return sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64; - case GO_UINT16: - return &ffi_type_uint16; - case GO_UINT32: - return &ffi_type_uint32; - case GO_UINT64: - return &ffi_type_uint64; - case GO_UINT8: - return &ffi_type_uint8; - case GO_UINT: - return sizeof (uintgo) == 4 ? &ffi_type_uint32 : &ffi_type_uint64; - case GO_UINTPTR: - if (sizeof (void *) == 2) - return &ffi_type_uint16; - else if (sizeof (void *) == 4) - return &ffi_type_uint32; - else if (sizeof (void *) == 8) - return &ffi_type_uint64; - abort (); - case GO_ARRAY: - return go_array_to_ffi ((const struct __go_array_type *) descriptor); - case GO_SLICE: - return go_slice_to_ffi ((const struct __go_slice_type *) descriptor); - case GO_STRUCT: - return go_struct_to_ffi ((const struct __go_struct_type *) descriptor); - case GO_STRING: - return go_string_to_ffi (); - case GO_INTERFACE: - return go_interface_to_ffi (); - case GO_CHAN: - case GO_FUNC: - case GO_MAP: - case GO_PTR: - case GO_UNSAFE_POINTER: - /* These types are always pointers, and for FFI purposes nothing - else matters. */ - return &ffi_type_pointer; - default: - abort (); - } -} - -/* Return the return type for a function, given the number of out - parameters and their types. */ - -static ffi_type * -go_func_return_ffi (const struct __go_func_type *func) -{ - int count; - const struct __go_type_descriptor **types; - ffi_type *ret; - int i; - - count = func->__out.__count; - if (count == 0) - return &ffi_type_void; - - types = (const struct __go_type_descriptor **) func->__out.__values; - - if (count == 1) - { - -#if defined (__i386__) && !defined (__x86_64__) - /* FFI does not support complex types. On 32-bit x86, a - complex64 will be returned in %eax/%edx. We normally tell - FFI that a complex64 is a struct of two floats. On 32-bit - x86 a struct of two floats is returned via a hidden first - pointer parameter. Fortunately we can make everything work - by pretending that complex64 is int64. */ - if ((types[0]->__code & GO_CODE_MASK) == GO_COMPLEX64) - return &ffi_type_sint64; -#endif - - return go_type_to_ffi (types[0]); - } - - ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - ret->type = FFI_TYPE_STRUCT; - ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *)); - for (i = 0; i < count; ++i) - ret->elements[i] = go_type_to_ffi (types[i]); - ret->elements[count] = NULL; - return ret; -} - -/* Build an ffi_cif structure for a function described by a - __go_func_type structure. */ - -static void -go_func_to_cif (const struct __go_func_type *func, _Bool is_interface, - _Bool is_method, ffi_cif *cif) -{ - int num_params; - const struct __go_type_descriptor **in_types; - size_t num_args; - ffi_type **args; - int off; - int i; - ffi_type *rettype; - ffi_status status; - - num_params = func->__in.__count; - in_types = ((const struct __go_type_descriptor **) - func->__in.__values); - - num_args = num_params + (is_interface ? 1 : 0); - args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *)); - i = 0; - off = 0; - if (is_interface) - { - args[0] = &ffi_type_pointer; - off = 1; - } - else if (is_method) - { - args[0] = &ffi_type_pointer; - i = 1; - } - for (; i < num_params; ++i) - args[i + off] = go_type_to_ffi (in_types[i]); - - rettype = go_func_return_ffi (func); - - status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args); - __go_assert (status == FFI_OK); -} - /* Get the total size required for the result parameters of a function. */ @@ -532,7 +217,7 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val, unsigned char *call_result; __go_assert ((func_type->__common.__code & GO_CODE_MASK) == GO_FUNC); - go_func_to_cif (func_type, is_interface, is_method, &cif); + __go_func_to_cif (func_type, is_interface, is_method, &cif); call_result = (unsigned char *) malloc (go_results_size (func_type)); |
