-d9189ebc139ff739af956094626ccc5eb92c3091
+bc5ad6d10092d6238495357468ee093f7caf39f9
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
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.
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.
LIBGO_IS_DARWIN_TRUE
go_include
LIBATOMIC
+USE_LIBFFI_FALSE
+USE_LIBFFI_TRUE
LIBFFIINCS
LIBFFI
nover_glibgo_toolexeclibdir
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
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
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
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
method: -1,
}
- makeFuncFFI(ftyp, unsafe.Pointer(impl))
+ makeFuncFFI(makeCIF(ftyp), unsafe.Pointer(impl))
return Value{t, unsafe.Pointer(&impl), flag(Func) | flagIndir}
}
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}
}
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}
}
// 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.
#ifdef USE_LIBFFI
-#include "go-ffi.h"
+#include "ffi.h"
#if FFI_GO_CLOSURES
#define USE_LIBFFI_CLOSURES
/* 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
/* 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 "
--- /dev/null
+// 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
+}
# 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 ' | \
-/* 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 <stdio.h>
-#include <stdint.h>
#include <stdlib.h>
#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. */
-
-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));
-
-/* 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)
+/* The functions in this file are called by the Go runtime code to get
+ the libffi type values. */
+
+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");
+
+_Bool go_ffi_supports_complex(void) __attribute__ ((no_split_stack));
+_Bool go_ffi_supports_complex(void) __asm__ ("runtime.ffi_supports_complex");
+
+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;
}
+ffi_type *
+go_ffi_type_uint8(void)
+{
+ return &ffi_type_uint8;
+}
-#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_uint16(void)
{
- ffi_type *ret;
+ return &ffi_type_uint16;
+}
- 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;
+ffi_type *
+go_ffi_type_uint32(void)
+{
+ return &ffi_type_uint32;
}
-#endif
-/* Return an ffi_type for a type described by a
- __go_type_descriptor. */
+ffi_type *
+go_ffi_type_uint64(void)
+{
+ return &ffi_type_uint64;
+}
-static ffi_type *
-go_type_to_ffi (const struct __go_type_descriptor *descriptor)
+ffi_type *
+go_ffi_type_float(void)
{
- 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)
+}
+
+ffi_type *
+go_ffi_type_double(void)
+{
return &ffi_type_double;
- abort ();
- case GO_COMPLEX64:
- if (sizeof (float) == 4)
- {
+}
+
+_Bool
+go_ffi_supports_complex(void)
+{
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
- return &ffi_type_complex_float;
+ return true;
#else
- return go_complex_to_ffi (&ffi_type_float);
+ return false;
#endif
- }
- abort ();
- case GO_COMPLEX128:
- if (sizeof (double) == 8)
- {
+}
+
+ffi_type *
+go_ffi_type_complex_float(void)
+{
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
- return &ffi_type_complex_double;
+ return &ffi_type_complex_float;
#else
- return go_complex_to_ffi (&ffi_type_double);
+ abort();
#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)
- 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)
+ffi_type *
+go_ffi_type_complex_double(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;
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+ return &ffi_type_complex_double;
+#else
+ abort();
+#endif
}
-/* 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_void(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;
-
- 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);
+ return &ffi_type_void;
}
#endif /* defined(USE_LIBFFI) */
+++ /dev/null
-/* 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
#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
}
}
+/* 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.
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));
#include <port.h>
#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. */