1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Only build this file if libffi is supported.
13 // This file contains the code that converts a Go type to an FFI type.
14 // This has to be written in Go because it allocates memory in the Go heap.
16 // C functions to return pointers to libffi variables.
18 func ffi_type_pointer() *__ffi_type
19 func ffi_type_sint8() *__ffi_type
20 func ffi_type_sint16() *__ffi_type
21 func ffi_type_sint32() *__ffi_type
22 func ffi_type_sint64() *__ffi_type
23 func ffi_type_uint8() *__ffi_type
24 func ffi_type_uint16() *__ffi_type
25 func ffi_type_uint32() *__ffi_type
26 func ffi_type_uint64() *__ffi_type
27 func ffi_type_float() *__ffi_type
28 func ffi_type_double() *__ffi_type
29 func ffi_supports_complex() bool
30 func ffi_type_complex_float() *__ffi_type
31 func ffi_type_complex_double() *__ffi_type
32 func ffi_type_void() *__ffi_type
34 // C functions defined in libffi.
37 func ffi_prep_cif(*_ffi_cif
, _ffi_abi
, uint32, *__ffi_type
, **__ffi_type
) _ffi_status
39 // ffiFuncToCIF is called from C code.
40 //go:linkname ffiFuncToCIF runtime.ffiFuncToCIF
42 // ffiFuncToCIF builds an _ffi_cif struct for function described by ft.
43 func ffiFuncToCIF(ft
*functype
, isInterface
bool, isMethod
bool, cif
*_ffi_cif
) {
49 args
:= make([]*__ffi_type
, nargs
)
53 args
[0] = ffi_type_pointer()
56 args
[0] = ffi_type_pointer()
59 for ; i
< nparams
; i
++ {
60 args
[i
+off
] = typeToFFI(ft
.in
[i
])
63 rettype
:= funcReturnFFI(ft
)
65 var pargs
**__ffi_type
69 status
:= ffi_prep_cif(cif
, _FFI_DEFAULT_ABI
, uint32(nargs
), rettype
, pargs
)
70 if status
!= _FFI_OK
{
71 throw("ffi_prep_cif failed")
75 // funcReturnFFI returns the FFI definition of the return type of ft.
76 func funcReturnFFI(ft
*functype
) *__ffi_type
{
79 return ffi_type_void()
82 // Compile a function that returns a zero-sized value as
83 // though it returns void. This works around a problem in
84 // libffi: it can't represent a zero-sized value.
86 for _
, v
:= range ft
.out
{
90 return ffi_type_void()
94 return typeToFFI(ft
.out
[0])
97 elements
:= make([]*__ffi_type
, c
+1)
98 for i
, v
:= range ft
.out
{
99 elements
[i
] = typeToFFI(v
)
104 _type
: _FFI_TYPE_STRUCT
,
105 elements
: &elements
[0],
109 // typeToFFI returns the __ffi_type for a Go type.
110 func typeToFFI(typ
*_type
) *__ffi_type
{
111 switch typ
.kind
& kindMask
{
113 switch unsafe
.Sizeof(false) {
115 return ffi_type_uint8()
117 return ffi_type_uint32()
119 throw("bad bool size")
125 return ffi_type_sint8()
127 return ffi_type_sint16()
129 return ffi_type_sint32()
131 return ffi_type_sint64()
133 switch unsafe
.Sizeof(uint(0)) {
135 return ffi_type_uint32()
137 return ffi_type_uint64()
139 throw("bad uint size")
143 return ffi_type_uint8()
145 return ffi_type_uint16()
147 return ffi_type_uint32()
149 return ffi_type_uint64()
151 switch unsafe
.Sizeof(uintptr(0)) {
153 return ffi_type_uint32()
155 return ffi_type_uint64()
157 throw("bad uinptr size")
161 return ffi_type_float()
163 return ffi_type_double()
165 if ffi_supports_complex() {
166 return ffi_type_complex_float()
168 return complexToFFI(ffi_type_float())
171 if ffi_supports_complex() {
172 return ffi_type_complex_double()
174 return complexToFFI(ffi_type_double())
177 return arrayToFFI((*arraytype
)(unsafe
.Pointer(typ
)))
178 case kindChan
, kindFunc
, kindMap
, kindPtr
, kindUnsafePointer
:
179 // These types are always simple pointers, and for FFI
180 // purposes nothing else matters.
181 return ffi_type_pointer()
183 return interfaceToFFI()
185 return sliceToFFI((*slicetype
)(unsafe
.Pointer(typ
)))
189 return structToFFI((*structtype
)(unsafe
.Pointer(typ
)))
191 throw("unknown type kind")
196 // interfaceToFFI returns an ffi_type for a Go interface type.
197 // This is used for both empty and non-empty interface types.
198 func interfaceToFFI() *__ffi_type
{
199 elements
:= make([]*__ffi_type
, 3)
200 elements
[0] = ffi_type_pointer()
201 elements
[1] = elements
[0]
204 _type
: _FFI_TYPE_STRUCT
,
205 elements
: &elements
[0],
209 // stringToFFI returns an ffi_type for a Go string type.
210 func stringToFFI() *__ffi_type
{
211 elements
:= make([]*__ffi_type
, 3)
212 elements
[0] = ffi_type_pointer()
213 elements
[1] = intToFFI()
216 _type
: _FFI_TYPE_STRUCT
,
217 elements
: &elements
[0],
221 // structToFFI returns an ffi_type for a Go struct type.
222 func structToFFI(typ
*structtype
) *__ffi_type
{
225 return emptyStructToFFI()
228 fields
:= make([]*__ffi_type
, c
+1)
229 for i
, v
:= range typ
.fields
{
230 fields
[i
] = typeToFFI(v
.typ
)
234 _type
: _FFI_TYPE_STRUCT
,
235 elements
: &fields
[0],
239 // sliceToFFI returns an ffi_type for a Go slice type.
240 func sliceToFFI(typ
*slicetype
) *__ffi_type
{
241 elements
:= make([]*__ffi_type
, 4)
242 elements
[0] = ffi_type_pointer()
243 elements
[1] = intToFFI()
244 elements
[2] = elements
[1]
247 _type
: _FFI_TYPE_STRUCT
,
248 elements
: &elements
[0],
252 // complexToFFI returns an ffi_type for a Go complex type.
253 // This is only used if libffi does not support complex types internally
255 func complexToFFI(ffiFloatType
*__ffi_type
) *__ffi_type
{
256 elements
:= make([]*__ffi_type
, 3)
257 elements
[0] = ffiFloatType
258 elements
[1] = ffiFloatType
261 _type
: _FFI_TYPE_STRUCT
,
262 elements
: &elements
[0],
266 // arrayToFFI returns an ffi_type for a Go array type.
267 func arrayToFFI(typ
*arraytype
) *__ffi_type
{
269 return emptyStructToFFI()
271 elements
:= make([]*__ffi_type
, typ
.len+1)
272 et
:= typeToFFI(typ
.elem
)
273 for i
:= uintptr(0); i
< typ
.len; i
++ {
276 elements
[typ
.len] = nil
278 _type
: _FFI_TYPE_STRUCT
,
279 elements
: &elements
[0],
283 // intToFFI returns an ffi_type for the Go int type.
284 func intToFFI() *__ffi_type
{
285 switch unsafe
.Sizeof(0) {
287 return ffi_type_sint32()
289 return ffi_type_sint64()
291 throw("bad int size")
296 // emptyStructToFFI returns an ffi_type for an empty struct.
297 // The libffi library won't accept a struct with no fields.
298 func emptyStructToFFI() *__ffi_type
{
299 elements
:= make([]*__ffi_type
, 2)
300 elements
[0] = ffi_type_void()
303 _type
: _FFI_TYPE_STRUCT
,
304 elements
: &elements
[0],
308 //go:linkname makeCIF reflect.makeCIF
310 // makeCIF is used by the reflect package to allocate a CIF.
311 func makeCIF(ft
*functype
) *_ffi_cif
{
313 ffiFuncToCIF(ft
, false, false, cif
)