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.
14 // This file contains the code that converts a Go type to an FFI type.
15 // This has to be written in Go because it allocates memory in the Go heap.
17 // C functions to return pointers to libffi variables.
19 func ffi_type_pointer() *__ffi_type
20 func ffi_type_sint8() *__ffi_type
21 func ffi_type_sint16() *__ffi_type
22 func ffi_type_sint32() *__ffi_type
23 func ffi_type_sint64() *__ffi_type
24 func ffi_type_uint8() *__ffi_type
25 func ffi_type_uint16() *__ffi_type
26 func ffi_type_uint32() *__ffi_type
27 func ffi_type_uint64() *__ffi_type
28 func ffi_type_float() *__ffi_type
29 func ffi_type_double() *__ffi_type
30 func ffi_supports_complex() bool
31 func ffi_type_complex_float() *__ffi_type
32 func ffi_type_complex_double() *__ffi_type
33 func ffi_type_void() *__ffi_type
35 // C functions defined in libffi.
38 func ffi_prep_cif(*_ffi_cif
, _ffi_abi
, uint32, *__ffi_type
, **__ffi_type
) _ffi_status
40 // ffiFuncToCIF is called from C code.
41 //go:linkname ffiFuncToCIF
43 // ffiFuncToCIF builds an _ffi_cif struct for function described by ft.
44 func ffiFuncToCIF(ft
*functype
, isInterface
bool, isMethod
bool, cif
*_ffi_cif
) {
50 args
:= make([]*__ffi_type
, nargs
)
54 args
[0] = ffi_type_pointer()
57 args
[0] = ffi_type_pointer()
60 for ; i
< nparams
; i
++ {
61 args
[i
+off
] = typeToFFI(ft
.in
[i
])
64 rettype
:= funcReturnFFI(ft
)
66 var pargs
**__ffi_type
70 status
:= ffi_prep_cif(cif
, _FFI_DEFAULT_ABI
, uint32(nargs
), rettype
, pargs
)
71 if status
!= _FFI_OK
{
72 throw("ffi_prep_cif failed")
76 // funcReturnFFI returns the FFI definition of the return type of ft.
77 func funcReturnFFI(ft
*functype
) *__ffi_type
{
80 return ffi_type_void()
83 // Compile a function that returns a zero-sized value as
84 // though it returns void. This works around a problem in
85 // libffi: it can't represent a zero-sized value.
87 for _
, v
:= range ft
.out
{
91 return ffi_type_void()
95 return typeToFFI(ft
.out
[0])
98 elements
:= make([]*__ffi_type
, c
+1)
99 for i
, v
:= range ft
.out
{
100 elements
[i
] = typeToFFI(v
)
105 _type
: _FFI_TYPE_STRUCT
,
106 elements
: &elements
[0],
110 // typeToFFI returns the __ffi_type for a Go type.
111 func typeToFFI(typ
*_type
) *__ffi_type
{
112 switch typ
.kind
& kindMask
{
114 switch unsafe
.Sizeof(false) {
116 return ffi_type_uint8()
118 return ffi_type_uint32()
120 throw("bad bool size")
126 return ffi_type_sint8()
128 return ffi_type_sint16()
130 return ffi_type_sint32()
132 return ffi_type_sint64()
134 switch unsafe
.Sizeof(uint(0)) {
136 return ffi_type_uint32()
138 return ffi_type_uint64()
140 throw("bad uint size")
144 return ffi_type_uint8()
146 return ffi_type_uint16()
148 return ffi_type_uint32()
150 return ffi_type_uint64()
152 switch unsafe
.Sizeof(uintptr(0)) {
154 return ffi_type_uint32()
156 return ffi_type_uint64()
158 throw("bad uinptr size")
162 return ffi_type_float()
164 return ffi_type_double()
166 if ffi_supports_complex() {
167 return ffi_type_complex_float()
169 return complexToFFI(ffi_type_float())
172 if ffi_supports_complex() {
173 return ffi_type_complex_double()
175 return complexToFFI(ffi_type_double())
178 return arrayToFFI((*arraytype
)(unsafe
.Pointer(typ
)))
179 case kindChan
, kindFunc
, kindMap
, kindPtr
, kindUnsafePointer
:
180 // These types are always simple pointers, and for FFI
181 // purposes nothing else matters.
182 return ffi_type_pointer()
184 return interfaceToFFI()
186 return sliceToFFI((*slicetype
)(unsafe
.Pointer(typ
)))
190 return structToFFI((*structtype
)(unsafe
.Pointer(typ
)))
192 throw("unknown type kind")
197 // interfaceToFFI returns an ffi_type for a Go interface type.
198 // This is used for both empty and non-empty interface types.
199 func interfaceToFFI() *__ffi_type
{
200 elements
:= make([]*__ffi_type
, 3)
201 elements
[0] = ffi_type_pointer()
202 elements
[1] = elements
[0]
205 _type
: _FFI_TYPE_STRUCT
,
206 elements
: &elements
[0],
210 // stringToFFI returns an ffi_type for a Go string type.
211 func stringToFFI() *__ffi_type
{
212 elements
:= make([]*__ffi_type
, 3)
213 elements
[0] = ffi_type_pointer()
214 elements
[1] = intToFFI()
217 _type
: _FFI_TYPE_STRUCT
,
218 elements
: &elements
[0],
222 // structToFFI returns an ffi_type for a Go struct type.
223 func structToFFI(typ
*structtype
) *__ffi_type
{
225 if typ
.typ
.kind
&kindDirectIface
!= 0 {
226 return ffi_type_pointer()
229 fields
:= make([]*__ffi_type
, 0, c
+1)
233 for i
, v
:= range typ
.fields
{
234 // Skip zero-sized fields; they confuse libffi,
235 // and there is no value to pass in any case.
236 // We do have to check whether the alignment of the
237 // zero-sized field introduces any padding for the
241 if v
.name
== nil ||
*v
.name
!= "_" {
251 for j
:= i
- 1; j
>= 0; j
-- {
252 if typ
.fields
[j
].typ
.size
> 0 {
253 off
= typ
.fields
[j
].offset() + typ
.fields
[j
].typ
.size
257 off
+= uintptr(v
.typ
.align
) - 1
258 off
&^= uintptr(v
.typ
.align
) - 1
259 if off
!= v
.offset() {
260 fields
= append(fields
, padFFI(v
.offset()-off
))
265 fields
= append(fields
, typeToFFI(v
.typ
))
269 return emptyStructToFFI()
273 // The compiler adds one byte padding to non-empty struct ending
274 // with a zero-sized field (types.cc:get_backend_struct_fields).
275 // Add this padding to the FFI type.
276 fields
= append(fields
, ffi_type_uint8())
279 fields
= append(fields
, nil)
282 _type
: _FFI_TYPE_STRUCT
,
283 elements
: &fields
[0],
287 // sliceToFFI returns an ffi_type for a Go slice type.
288 func sliceToFFI(typ
*slicetype
) *__ffi_type
{
289 elements
:= make([]*__ffi_type
, 4)
290 elements
[0] = ffi_type_pointer()
291 elements
[1] = intToFFI()
292 elements
[2] = elements
[1]
295 _type
: _FFI_TYPE_STRUCT
,
296 elements
: &elements
[0],
300 // complexToFFI returns an ffi_type for a Go complex type.
301 // This is only used if libffi does not support complex types internally
303 func complexToFFI(ffiFloatType
*__ffi_type
) *__ffi_type
{
304 elements
:= make([]*__ffi_type
, 3)
305 elements
[0] = ffiFloatType
306 elements
[1] = ffiFloatType
309 _type
: _FFI_TYPE_STRUCT
,
310 elements
: &elements
[0],
314 // arrayToFFI returns an ffi_type for a Go array type.
315 func arrayToFFI(typ
*arraytype
) *__ffi_type
{
317 return emptyStructToFFI()
319 if typ
.typ
.kind
&kindDirectIface
!= 0 {
320 return ffi_type_pointer()
322 elements
:= make([]*__ffi_type
, typ
.len+1)
323 et
:= typeToFFI(typ
.elem
)
324 for i
:= uintptr(0); i
< typ
.len; i
++ {
327 elements
[typ
.len] = nil
329 _type
: _FFI_TYPE_STRUCT
,
330 elements
: &elements
[0],
334 // intToFFI returns an ffi_type for the Go int type.
335 func intToFFI() *__ffi_type
{
336 switch unsafe
.Sizeof(0) {
338 return ffi_type_sint32()
340 return ffi_type_sint64()
342 throw("bad int size")
347 // emptyStructToFFI returns an ffi_type for an empty struct.
348 // The libffi library won't accept a struct with no fields.
349 func emptyStructToFFI() *__ffi_type
{
350 elements
:= make([]*__ffi_type
, 2)
351 elements
[0] = ffi_type_void()
354 _type
: _FFI_TYPE_STRUCT
,
355 elements
: &elements
[0],
359 // padFFI returns a padding field of the given size
360 func padFFI(size
uintptr) *__ffi_type
{
361 elements
:= make([]*__ffi_type
, size
+1)
362 for i
:= uintptr(0); i
< size
; i
++ {
363 elements
[i
] = ffi_type_uint8()
367 _type
: _FFI_TYPE_STRUCT
,
368 elements
: &elements
[0],
372 //go:linkname makeCIF reflect.makeCIF
374 // makeCIF is used by the reflect package to allocate a CIF.
375 func makeCIF(ft
*functype
) *_ffi_cif
{
377 ffiFuncToCIF(ft
, false, false, cif
)