libstdc++: Avoid -Wmaybe-uninitialized warnings in text_encoding.cc
[official-gcc.git] / libgo / go / runtime / ffi.go
blob86ce5b85d046aee89c9de2c4f72fa3309f82252b
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.
7 //go:build libffi
8 // +build libffi
10 package runtime
12 import "unsafe"
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.
37 //extern ffi_prep_cif
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) {
45 nparams := len(ft.in)
46 nargs := nparams
47 if isInterface {
48 nargs++
50 args := make([]*__ffi_type, nargs)
51 i := 0
52 off := 0
53 if isInterface {
54 args[0] = ffi_type_pointer()
55 off = 1
56 } else if isMethod {
57 args[0] = ffi_type_pointer()
58 i = 1
60 for ; i < nparams; i++ {
61 args[i+off] = typeToFFI(ft.in[i])
64 rettype := funcReturnFFI(ft)
66 var pargs **__ffi_type
67 if len(args) > 0 {
68 pargs = &args[0]
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 {
78 c := len(ft.out)
79 if c == 0 {
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.
86 var size uintptr
87 for _, v := range ft.out {
88 size += v.size
90 if size == 0 {
91 return ffi_type_void()
94 if c == 1 {
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)
102 elements[c] = nil
104 return &__ffi_type{
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 {
113 case kindBool:
114 switch unsafe.Sizeof(false) {
115 case 1:
116 return ffi_type_uint8()
117 case 4:
118 return ffi_type_uint32()
119 default:
120 throw("bad bool size")
121 return nil
123 case kindInt:
124 return intToFFI()
125 case kindInt8:
126 return ffi_type_sint8()
127 case kindInt16:
128 return ffi_type_sint16()
129 case kindInt32:
130 return ffi_type_sint32()
131 case kindInt64:
132 return ffi_type_sint64()
133 case kindUint:
134 switch unsafe.Sizeof(uint(0)) {
135 case 4:
136 return ffi_type_uint32()
137 case 8:
138 return ffi_type_uint64()
139 default:
140 throw("bad uint size")
141 return nil
143 case kindUint8:
144 return ffi_type_uint8()
145 case kindUint16:
146 return ffi_type_uint16()
147 case kindUint32:
148 return ffi_type_uint32()
149 case kindUint64:
150 return ffi_type_uint64()
151 case kindUintptr:
152 switch unsafe.Sizeof(uintptr(0)) {
153 case 4:
154 return ffi_type_uint32()
155 case 8:
156 return ffi_type_uint64()
157 default:
158 throw("bad uinptr size")
159 return nil
161 case kindFloat32:
162 return ffi_type_float()
163 case kindFloat64:
164 return ffi_type_double()
165 case kindComplex64:
166 if ffi_supports_complex() {
167 return ffi_type_complex_float()
168 } else {
169 return complexToFFI(ffi_type_float())
171 case kindComplex128:
172 if ffi_supports_complex() {
173 return ffi_type_complex_double()
174 } else {
175 return complexToFFI(ffi_type_double())
177 case kindArray:
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()
183 case kindInterface:
184 return interfaceToFFI()
185 case kindSlice:
186 return sliceToFFI((*slicetype)(unsafe.Pointer(typ)))
187 case kindString:
188 return stringToFFI()
189 case kindStruct:
190 return structToFFI((*structtype)(unsafe.Pointer(typ)))
191 default:
192 throw("unknown type kind")
193 return nil
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]
203 elements[2] = nil
204 return &__ffi_type{
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()
215 elements[2] = nil
216 return &__ffi_type{
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 {
224 c := len(typ.fields)
225 if typ.typ.kind&kindDirectIface != 0 {
226 return ffi_type_pointer()
229 fields := make([]*__ffi_type, 0, c+1)
230 checkPad := false
231 lastzero := false
232 sawnonzero := false
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
238 // next field.
239 if v.typ.size == 0 {
240 checkPad = true
241 if v.name == nil || *v.name != "_" {
242 lastzero = true
244 continue
246 lastzero = false
247 sawnonzero = true
249 if checkPad {
250 off := uintptr(0)
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
254 break
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))
262 checkPad = false
265 fields = append(fields, typeToFFI(v.typ))
268 if !sawnonzero {
269 return emptyStructToFFI()
272 if lastzero {
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)
281 return &__ffi_type{
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]
293 elements[3] = nil
294 return &__ffi_type{
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
302 // for this target.
303 func complexToFFI(ffiFloatType *__ffi_type) *__ffi_type {
304 elements := make([]*__ffi_type, 3)
305 elements[0] = ffiFloatType
306 elements[1] = ffiFloatType
307 elements[2] = nil
308 return &__ffi_type{
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 {
316 if typ.len == 0 {
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++ {
325 elements[i] = et
327 elements[typ.len] = nil
328 return &__ffi_type{
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) {
337 case 4:
338 return ffi_type_sint32()
339 case 8:
340 return ffi_type_sint64()
341 default:
342 throw("bad int size")
343 return nil
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()
352 elements[1] = nil
353 return &__ffi_type{
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()
365 elements[size] = nil
366 return &__ffi_type{
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 {
376 cif := new(_ffi_cif)
377 ffiFuncToCIF(ft, false, false, cif)
378 return cif