diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 20e085974c87..bb8729d696cf 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -d9189ebc139ff739af956094626ccc5eb92c3091 +bc5ad6d10092d6238495357468ee093f7caf39f9 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 534a7b225c46..1e2384690c88 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -1052,6 +1052,14 @@ runtime_internal_atomic_lo_check_GOCFLAGS = -fgo-compiling-runtime runtime_internal_sys_lo_GOCFLAGS = -fgo-compiling-runtime runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime +# If libffi is supported (the normal case) use the ffi build tag for +# the runtime package. +if USE_LIBFFI +matchargs_runtime = --tag=libffi +else +matchargs_runtime = +endif + # At least for now, we need -static-libgo for this test, because # otherwise we can't get the line numbers. # Also use -fno-inline to get better results from the memory profiler. diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 9edcf37011b5..08ba210e0b0f 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -1154,6 +1154,11 @@ runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime runtime_internal_atomic_lo_check_GOCFLAGS = -fgo-compiling-runtime runtime_internal_sys_lo_GOCFLAGS = -fgo-compiling-runtime runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime +@USE_LIBFFI_FALSE@matchargs_runtime = + +# If libffi is supported (the normal case) use the ffi build tag for +# the runtime package. +@USE_LIBFFI_TRUE@matchargs_runtime = --tag=libffi # At least for now, we need -static-libgo for this test, because # otherwise we can't get the line numbers. diff --git a/libgo/configure b/libgo/configure index d4ed950838e2..868adcd48814 100755 --- a/libgo/configure +++ b/libgo/configure @@ -665,6 +665,8 @@ LIBGO_IS_DARWIN_FALSE LIBGO_IS_DARWIN_TRUE go_include LIBATOMIC +USE_LIBFFI_FALSE +USE_LIBFFI_TRUE LIBFFIINCS LIBFFI nover_glibgo_toolexeclibdir @@ -11098,7 +11100,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11101 "configure" +#line 11106 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -13466,6 +13468,14 @@ $as_echo "#define USE_LIBFFI 1" >>confdefs.h fi + if test "$with_liffi" != "no"; then + USE_LIBFFI_TRUE= + USE_LIBFFI_FALSE='#' +else + USE_LIBFFI_TRUE='#' + USE_LIBFFI_FALSE= +fi + # See if the user wants to configure without libatomic. This is useful if we are # on an architecture for which libgo does not need an atomic support library and @@ -15596,6 +15606,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${USE_LIBFFI_TRUE}" && test -z "${USE_LIBFFI_FALSE}"; then + as_fn_error "conditional \"USE_LIBFFI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${LIBGO_IS_DARWIN_TRUE}" && test -z "${LIBGO_IS_DARWIN_FALSE}"; then as_fn_error "conditional \"LIBGO_IS_DARWIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 diff --git a/libgo/configure.ac b/libgo/configure.ac index 09add8d136bf..9e765404739e 100644 --- a/libgo/configure.ac +++ b/libgo/configure.ac @@ -121,6 +121,7 @@ if test "$with_libffi" != no; then fi AC_SUBST(LIBFFI) AC_SUBST(LIBFFIINCS) +AM_CONDITIONAL(USE_LIBFFI, test "$with_liffi" != "no") # See if the user wants to configure without libatomic. This is useful if we are # on an architecture for which libgo does not need an atomic support library and diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go index 543a335d8417..3a9fd2897b73 100644 --- a/libgo/go/reflect/makefunc.go +++ b/libgo/go/reflect/makefunc.go @@ -63,7 +63,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { method: -1, } - makeFuncFFI(ftyp, unsafe.Pointer(impl)) + makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl)) return Value{t, unsafe.Pointer(&impl), flag(Func) | flagIndir} } @@ -102,7 +102,7 @@ func makeMethodValue(op string, v Value) Value { rcvr: rcvr, } - makeFuncFFI(ftyp, unsafe.Pointer(fv)) + makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(fv)) return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func) | flagIndir} } @@ -128,7 +128,7 @@ func makeValueMethod(v Value) Value { rcvr: v, } - makeFuncFFI(ftyp, unsafe.Pointer(impl)) + makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl)) return Value{t, unsafe.Pointer(&impl), v.flag&flagRO | flag(Func) | flagIndir} } diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go index c821131bab7a..2acf7bb887a2 100644 --- a/libgo/go/reflect/makefunc_ffi.go +++ b/libgo/go/reflect/makefunc_ffi.go @@ -10,7 +10,10 @@ import ( // The makeFuncFFI function, written in C, fills in an FFI closure. // It arranges for ffiCall to be invoked directly from FFI. -func makeFuncFFI(ftyp *funcType, impl unsafe.Pointer) +func makeFuncFFI(cif unsafe.Pointer, impl unsafe.Pointer) + +// The makeCIF function, implemented in the runtime package, allocates a CIF. +func makeCIF(ft *funcType) unsafe.Pointer // FFICallbackGo implements the Go side of the libffi callback. // It is exported so that C code can call it. diff --git a/libgo/go/reflect/makefunc_ffi_c.c b/libgo/go/reflect/makefunc_ffi_c.c index 06a41ef2ecd5..d3935eb0b731 100644 --- a/libgo/go/reflect/makefunc_ffi_c.c +++ b/libgo/go/reflect/makefunc_ffi_c.c @@ -8,7 +8,7 @@ #ifdef USE_LIBFFI -#include "go-ffi.h" +#include "ffi.h" #if FFI_GO_CLOSURES #define USE_LIBFFI_CLOSURES @@ -18,7 +18,7 @@ /* Declare C functions with the names used to call from Go. */ -void makeFuncFFI(const struct __go_func_type *ftyp, void *impl) +void makeFuncFFI(void *cif, void *impl) __asm__ (GOSYM_PREFIX "reflect.makeFuncFFI"); #ifdef USE_LIBFFI_CLOSURES @@ -70,20 +70,15 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results, /* Allocate an FFI closure and arrange to call ffi_callback. */ void -makeFuncFFI(const struct __go_func_type *ftyp, void *impl) +makeFuncFFI(void *cif, void *impl) { - ffi_cif *cif; - - cif = (ffi_cif *) __go_alloc (sizeof (ffi_cif)); - __go_func_to_cif (ftyp, 0, 0, cif); - - ffi_prep_go_closure(impl, cif, ffi_callback); + ffi_prep_go_closure(impl, (ffi_cif*)cif, ffi_callback); } #else /* !defined(USE_LIBFFI_CLOSURES) */ void -makeFuncFFI(const struct __go_func_type *ftyp __attribute__ ((unused)), +makeFuncFFI(void *cif __attribute__ ((unused)), void *impl __attribute__ ((unused))) { runtime_panicstring ("libgo built without FFI does not support " diff --git a/libgo/go/runtime/ffi.go b/libgo/go/runtime/ffi.go new file mode 100644 index 000000000000..164e1770ea2b --- /dev/null +++ b/libgo/go/runtime/ffi.go @@ -0,0 +1,315 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Only build this file if libffi is supported. + +// +build libffi + +package runtime + +import "unsafe" + +// This file contains the code that converts a Go type to an FFI type. +// This has to be written in Go because it allocates memory in the Go heap. + +// C functions to return pointers to libffi variables. + +func ffi_type_pointer() *__ffi_type +func ffi_type_sint8() *__ffi_type +func ffi_type_sint16() *__ffi_type +func ffi_type_sint32() *__ffi_type +func ffi_type_sint64() *__ffi_type +func ffi_type_uint8() *__ffi_type +func ffi_type_uint16() *__ffi_type +func ffi_type_uint32() *__ffi_type +func ffi_type_uint64() *__ffi_type +func ffi_type_float() *__ffi_type +func ffi_type_double() *__ffi_type +func ffi_supports_complex() bool +func ffi_type_complex_float() *__ffi_type +func ffi_type_complex_double() *__ffi_type +func ffi_type_void() *__ffi_type + +// C functions defined in libffi. + +//extern ffi_prep_cif +func ffi_prep_cif(*_ffi_cif, _ffi_abi, uint32, *__ffi_type, **__ffi_type) _ffi_status + +// ffiFuncToCIF is called from C code. +//go:linkname ffiFuncToCIF runtime.ffiFuncToCIF + +// ffiFuncToCIF builds an _ffi_cif struct for function described by ft. +func ffiFuncToCIF(ft *functype, isInterface bool, isMethod bool, cif *_ffi_cif) { + nparams := len(ft.in) + nargs := nparams + if isInterface { + nargs++ + } + args := make([]*__ffi_type, nargs) + i := 0 + off := 0 + if isInterface { + args[0] = ffi_type_pointer() + off = 1 + } else if isMethod { + args[0] = ffi_type_pointer() + i = 1 + } + for ; i < nparams; i++ { + args[i+off] = typeToFFI(ft.in[i]) + } + + rettype := funcReturnFFI(ft) + + var pargs **__ffi_type + if len(args) > 0 { + pargs = &args[0] + } + status := ffi_prep_cif(cif, _FFI_DEFAULT_ABI, uint32(nargs), rettype, pargs) + if status != _FFI_OK { + throw("ffi_prep_cif failed") + } +} + +// funcReturnFFI returns the FFI definition of the return type of ft. +func funcReturnFFI(ft *functype) *__ffi_type { + c := len(ft.out) + if c == 0 { + return ffi_type_void() + } + + // Compile a function that returns a zero-sized value as + // though it returns void. This works around a problem in + // libffi: it can't represent a zero-sized value. + var size uintptr + for _, v := range ft.out { + size += v.size + } + if size == 0 { + return ffi_type_void() + } + + if c == 1 { + return typeToFFI(ft.out[0]) + } + + elements := make([]*__ffi_type, c+1) + for i, v := range ft.out { + elements[i] = typeToFFI(v) + } + elements[c] = nil + + return &__ffi_type{ + _type: _FFI_TYPE_STRUCT, + elements: &elements[0], + } +} + +// typeToFFI returns the __ffi_type for a Go type. +func typeToFFI(typ *_type) *__ffi_type { + switch typ.kind & kindMask { + case kindBool: + switch unsafe.Sizeof(false) { + case 1: + return ffi_type_uint8() + case 4: + return ffi_type_uint32() + default: + throw("bad bool size") + return nil + } + case kindInt: + return intToFFI() + case kindInt8: + return ffi_type_sint8() + case kindInt16: + return ffi_type_sint16() + case kindInt32: + return ffi_type_sint32() + case kindInt64: + return ffi_type_sint64() + case kindUint: + switch unsafe.Sizeof(uint(0)) { + case 4: + return ffi_type_uint32() + case 8: + return ffi_type_uint64() + default: + throw("bad uint size") + return nil + } + case kindUint8: + return ffi_type_uint8() + case kindUint16: + return ffi_type_uint16() + case kindUint32: + return ffi_type_uint32() + case kindUint64: + return ffi_type_uint64() + case kindUintptr: + switch unsafe.Sizeof(uintptr(0)) { + case 4: + return ffi_type_uint32() + case 8: + return ffi_type_uint64() + default: + throw("bad uinptr size") + return nil + } + case kindFloat32: + return ffi_type_float() + case kindFloat64: + return ffi_type_double() + case kindComplex64: + if ffi_supports_complex() { + return ffi_type_complex_float() + } else { + return complexToFFI(ffi_type_float()) + } + case kindComplex128: + if ffi_supports_complex() { + return ffi_type_complex_double() + } else { + return complexToFFI(ffi_type_double()) + } + case kindArray: + return arrayToFFI((*arraytype)(unsafe.Pointer(typ))) + case kindChan, kindFunc, kindMap, kindPtr, kindUnsafePointer: + // These types are always simple pointers, and for FFI + // purposes nothing else matters. + return ffi_type_pointer() + case kindInterface: + return interfaceToFFI() + case kindSlice: + return sliceToFFI((*slicetype)(unsafe.Pointer(typ))) + case kindString: + return stringToFFI() + case kindStruct: + return structToFFI((*structtype)(unsafe.Pointer(typ))) + default: + throw("unknown type kind") + return nil + } +} + +// interfaceToFFI returns an ffi_type for a Go interface type. +// This is used for both empty and non-empty interface types. +func interfaceToFFI() *__ffi_type { + elements := make([]*__ffi_type, 3) + elements[0] = ffi_type_pointer() + elements[1] = elements[0] + elements[2] = nil + return &__ffi_type{ + _type: _FFI_TYPE_STRUCT, + elements: &elements[0], + } +} + +// stringToFFI returns an ffi_type for a Go string type. +func stringToFFI() *__ffi_type { + elements := make([]*__ffi_type, 3) + elements[0] = ffi_type_pointer() + elements[1] = intToFFI() + elements[2] = nil + return &__ffi_type{ + _type: _FFI_TYPE_STRUCT, + elements: &elements[0], + } +} + +// structToFFI returns an ffi_type for a Go struct type. +func structToFFI(typ *structtype) *__ffi_type { + c := len(typ.fields) + if c == 0 { + return emptyStructToFFI() + } + + fields := make([]*__ffi_type, c+1) + for i, v := range typ.fields { + fields[i] = typeToFFI(v.typ) + } + fields[c] = nil + return &__ffi_type{ + _type: _FFI_TYPE_STRUCT, + elements: &fields[0], + } +} + +// sliceToFFI returns an ffi_type for a Go slice type. +func sliceToFFI(typ *slicetype) *__ffi_type { + elements := make([]*__ffi_type, 4) + elements[0] = ffi_type_pointer() + elements[1] = intToFFI() + elements[2] = elements[1] + elements[3] = nil + return &__ffi_type{ + _type: _FFI_TYPE_STRUCT, + elements: &elements[0], + } +} + +// complexToFFI returns an ffi_type for a Go complex type. +// This is only used if libffi does not support complex types internally +// for this target. +func complexToFFI(ffiFloatType *__ffi_type) *__ffi_type { + elements := make([]*__ffi_type, 3) + elements[0] = ffiFloatType + elements[1] = ffiFloatType + elements[2] = nil + return &__ffi_type{ + _type: _FFI_TYPE_STRUCT, + elements: &elements[0], + } +} + +// arrayToFFI returns an ffi_type for a Go array type. +func arrayToFFI(typ *arraytype) *__ffi_type { + if typ.len == 0 { + return emptyStructToFFI() + } + elements := make([]*__ffi_type, typ.len+1) + et := typeToFFI(typ.elem) + for i := uintptr(0); i < typ.len; i++ { + elements[i] = et + } + elements[typ.len] = nil + return &__ffi_type{ + _type: _FFI_TYPE_STRUCT, + elements: &elements[0], + } +} + +// intToFFI returns an ffi_type for the Go int type. +func intToFFI() *__ffi_type { + switch unsafe.Sizeof(0) { + case 4: + return ffi_type_sint32() + case 8: + return ffi_type_sint64() + default: + throw("bad int size") + return nil + } +} + +// emptyStructToFFI returns an ffi_type for an empty struct. +// The libffi library won't accept a struct with no fields. +func emptyStructToFFI() *__ffi_type { + elements := make([]*__ffi_type, 2) + elements[0] = ffi_type_void() + elements[1] = nil + return &__ffi_type{ + _type: _FFI_TYPE_STRUCT, + elements: &elements[0], + } +} + +//go:linkname makeCIF reflect.makeCIF + +// makeCIF is used by the reflect package to allocate a CIF. +func makeCIF(ft *functype) *_ffi_cif { + cif := new(_ffi_cif) + ffiFuncToCIF(ft, false, false, cif) + return cif +} diff --git a/libgo/mkrsysinfo.sh b/libgo/mkrsysinfo.sh index 1ab4ea40f715..af1859450108 100755 --- a/libgo/mkrsysinfo.sh +++ b/libgo/mkrsysinfo.sh @@ -18,6 +18,7 @@ echo 'package runtime' > ${OUT} # will all have a leading underscore. grep -v '^// ' gen-sysinfo.go | \ grep -v '^func' | \ + grep -v '^var ' | \ grep -v '^type _timeval ' | \ grep -v '^type _timespec_t ' | \ grep -v '^type _timespec ' | \ diff --git a/libgo/runtime/go-ffi.c b/libgo/runtime/go-ffi.c index 8817080c5951..b030f5e918ed 100644 --- a/libgo/runtime/go-ffi.c +++ b/libgo/runtime/go-ffi.c @@ -1,357 +1,152 @@ -/* go-ffi.c -- convert Go type description to libffi. +/* go-ffi.c -- libffi support functions. Copyright 2009 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ -#include -#include #include #include "runtime.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "go-type.h" #ifdef USE_LIBFFI #include "ffi.h" -/* The functions in this file are only called from reflect_call and - reflect.ffi. As these functions call libffi functions, which will - be compiled without -fsplit-stack, they will always run with a - large stack. */ +/* The functions in this file are called by the Go runtime code to get + the libffi type values. */ -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_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)); +ffi_type *go_ffi_type_pointer(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_pointer(void) __asm__ ("runtime.ffi_type_pointer"); +ffi_type *go_ffi_type_sint8(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_sint8(void) __asm__ ("runtime.ffi_type_sint8"); +ffi_type *go_ffi_type_sint16(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_sint16(void) __asm__ ("runtime.ffi_type_sint16"); +ffi_type *go_ffi_type_sint32(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_sint32(void) __asm__ ("runtime.ffi_type_sint32"); +ffi_type *go_ffi_type_sint64(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_sint64(void) __asm__ ("runtime.ffi_type_sint64"); +ffi_type *go_ffi_type_uint8(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_uint8(void) __asm__ ("runtime.ffi_type_uint8"); +ffi_type *go_ffi_type_uint16(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_uint16(void) __asm__ ("runtime.ffi_type_uint16"); +ffi_type *go_ffi_type_uint32(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_uint32(void) __asm__ ("runtime.ffi_type_uint32"); +ffi_type *go_ffi_type_uint64(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_uint64(void) __asm__ ("runtime.ffi_type_uint64"); +ffi_type *go_ffi_type_float(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_float(void) __asm__ ("runtime.ffi_type_float"); +ffi_type *go_ffi_type_double(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_double(void) __asm__ ("runtime.ffi_type_double"); +ffi_type *go_ffi_type_complex_float(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_complex_float(void) __asm__ ("runtime.ffi_type_complex_float"); +ffi_type *go_ffi_type_complex_double(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_complex_double(void) __asm__ ("runtime.ffi_type_complex_double"); +ffi_type *go_ffi_type_void(void) __attribute__ ((no_split_stack)); +ffi_type *go_ffi_type_void(void) __asm__ ("runtime.ffi_type_void"); -/* 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. */ +_Bool go_ffi_supports_complex(void) __attribute__ ((no_split_stack)); +_Bool go_ffi_supports_complex(void) __asm__ ("runtime.ffi_supports_complex"); -static ffi_type * -go_array_to_ffi (const struct __go_array_type *descriptor) +ffi_type * +go_ffi_type_pointer(void) { - 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; - if (len == 0) - { - /* The libffi library won't accept an empty struct. */ - ret->elements = (ffi_type **) __go_alloc (2 * sizeof (ffi_type *)); - ret->elements[0] = &ffi_type_void; - ret->elements[1] = NULL; - return ret; - } - 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 &ffi_type_pointer; } -/* 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 * +go_ffi_type_sint8(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 (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 &ffi_type_sint8; } -/* Return an ffi_type for a Go struct type. */ - -static ffi_type * -go_struct_to_ffi (const struct __go_struct_type *descriptor) +ffi_type * +go_ffi_type_sint16(void) { - ffi_type *ret; - int field_count; - const struct __go_struct_field *fields; - int i; - - field_count = descriptor->__fields.__count; - ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - ret->type = FFI_TYPE_STRUCT; - if (field_count == 0) - { - /* The libffi library won't accept an empty struct. */ - ret->elements = (ffi_type **) __go_alloc (2 * sizeof (ffi_type *)); - ret->elements[0] = &ffi_type_void; - ret->elements[1] = NULL; - return ret; - } - 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 &ffi_type_sint16; } -/* Return an ffi_type for a Go string type. This describes the String - struct. */ - -static ffi_type * -go_string_to_ffi (void) +ffi_type * +go_ffi_type_sint32(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 &ffi_type_sint32; } -/* 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 * +go_ffi_type_sint64(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 &ffi_type_sint64; } - -#ifndef FFI_TARGET_HAS_COMPLEX_TYPE -/* If libffi hasn't been updated for this target to support complex, - pretend complex is a structure. Warning: This does not work for - all ABIs. Eventually libffi should be updated for all targets - and this should go away. */ - -static ffi_type *go_complex_to_ffi (ffi_type *) - __attribute__ ((no_split_stack)); - -static ffi_type * -go_complex_to_ffi (ffi_type *float_type) +ffi_type * +go_ffi_type_uint8(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] = float_type; - ret->elements[1] = float_type; - ret->elements[2] = NULL; - return ret; -} -#endif - -/* 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: - if (sizeof (float) == 4) - { -#ifdef FFI_TARGET_HAS_COMPLEX_TYPE - return &ffi_type_complex_float; -#else - return go_complex_to_ffi (&ffi_type_float); -#endif - } - abort (); - case GO_COMPLEX128: - if (sizeof (double) == 8) - { -#ifdef FFI_TARGET_HAS_COMPLEX_TYPE - return &ffi_type_complex_double; -#else - return go_complex_to_ffi (&ffi_type_double); -#endif - } - abort (); - 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) +} + +ffi_type * +go_ffi_type_uint16(void) +{ return &ffi_type_uint16; - else if (sizeof (void *) == 4) +} + +ffi_type * +go_ffi_type_uint32(void) +{ return &ffi_type_uint32; - else if (sizeof (void *) == 8) +} + +ffi_type * +go_ffi_type_uint64(void) +{ 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) +ffi_type * +go_ffi_type_float(void) { - 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; - - // We compile a function that returns a zero-sized value as though - // it returns void. This works around a problem in libffi: it can't - // represent a zero-sized value. - for (i = 0; i < count; ++i) - { - if (types[i]->__size > 0) - break; - } - if (i == count) - return &ffi_type_void; - - if (count == 1) - 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; + return &ffi_type_float; } -/* Build an ffi_cif structure for a function described by a - __go_func_type structure. */ - -void -__go_func_to_cif (const struct __go_func_type *func, _Bool is_interface, - _Bool is_method, ffi_cif *cif) +ffi_type * +go_ffi_type_double(void) { - 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; + return &ffi_type_double; +} - num_params = func->__in.__count; - in_types = ((const struct __go_type_descriptor **) - func->__in.__values); +_Bool +go_ffi_supports_complex(void) +{ +#ifdef FFI_TARGET_HAS_COMPLEX_TYPE + return true; +#else + return false; +#endif +} - 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]); +ffi_type * +go_ffi_type_complex_float(void) +{ +#ifdef FFI_TARGET_HAS_COMPLEX_TYPE + return &ffi_type_complex_float; +#else + abort(); +#endif +} - rettype = go_func_return_ffi (func); +ffi_type * +go_ffi_type_complex_double(void) +{ +#ifdef FFI_TARGET_HAS_COMPLEX_TYPE + return &ffi_type_complex_double; +#else + abort(); +#endif +} - status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args); - __go_assert (status == FFI_OK); +ffi_type * +go_ffi_type_void(void) +{ + return &ffi_type_void; } #endif /* defined(USE_LIBFFI) */ diff --git a/libgo/runtime/go-ffi.h b/libgo/runtime/go-ffi.h deleted file mode 100644 index afae4b6d6ed8..000000000000 --- a/libgo/runtime/go-ffi.h +++ /dev/null @@ -1,16 +0,0 @@ -/* go-ffi.c -- convert Go type description to libffi. - - Copyright 2014 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include "config.h" -#include "go-type.h" - -#ifdef USE_LIBFFI - -#include "ffi.h" - -void __go_func_to_cif (const struct __go_func_type *, _Bool, _Bool, ffi_cif *); - -#endif diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c index 2a14d6c6addd..dc2f60575ece 100644 --- a/libgo/runtime/go-reflect-call.c +++ b/libgo/runtime/go-reflect-call.c @@ -12,7 +12,10 @@ #include "go-alloc.h" #include "go-assert.h" #include "go-type.h" -#include "go-ffi.h" + +#ifdef USE_LIBFFI +#include "ffi.h" +#endif #if defined(USE_LIBFFI) && FFI_GO_CLOSURES @@ -197,6 +200,11 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result, } } +/* The code that converts the Go type to an FFI type is written in Go, + so that it can allocate Go heap memory. */ +extern void ffiFuncToCIF(const struct __go_func_type*, _Bool, _Bool, ffi_cif*) + __asm__ ("runtime.ffiFuncToCIF"); + /* Call a function. The type of the function is FUNC_TYPE, and the closure is FUNC_VAL. PARAMS is an array of parameter addresses. RESULTS is an array of result addresses. @@ -218,7 +226,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); + ffiFuncToCIF (func_type, is_interface, is_method, &cif); call_result = (unsigned char *) malloc (go_results_size (func_type)); diff --git a/libgo/sysinfo.c b/libgo/sysinfo.c index 56790c604159..235941b62115 100644 --- a/libgo/sysinfo.c +++ b/libgo/sysinfo.c @@ -163,6 +163,10 @@ #include #endif +#ifdef USE_LIBFFI +#include "ffi.h" +#endif + /* Constants that may only be defined as expressions on some systems, expressions too complex for -fdump-go-spec to handle. These are handled specially below. */