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.
4
5// Only build this file if libffi is supported.
6
7// +build libffi
8
9package runtime
10
11import "unsafe"
12
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.
15
16// C functions to return pointers to libffi variables.
17
18func ffi_type_pointer() *__ffi_type
19func ffi_type_sint8() *__ffi_type
20func ffi_type_sint16() *__ffi_type
21func ffi_type_sint32() *__ffi_type
22func ffi_type_sint64() *__ffi_type
23func ffi_type_uint8() *__ffi_type
24func ffi_type_uint16() *__ffi_type
25func ffi_type_uint32() *__ffi_type
26func ffi_type_uint64() *__ffi_type
27func ffi_type_float() *__ffi_type
28func ffi_type_double() *__ffi_type
29func ffi_supports_complex() bool
30func ffi_type_complex_float() *__ffi_type
31func ffi_type_complex_double() *__ffi_type
32func ffi_type_void() *__ffi_type
33
34// C functions defined in libffi.
35
36//extern ffi_prep_cif
37func ffi_prep_cif(*_ffi_cif, _ffi_abi, uint32, *__ffi_type, **__ffi_type) _ffi_status
38
39// ffiFuncToCIF is called from C code.
40//go:linkname ffiFuncToCIF
41
42// ffiFuncToCIF builds an _ffi_cif struct for function described by ft.
43func ffiFuncToCIF(ft *functype, isInterface bool, isMethod bool, cif *_ffi_cif) {
44	nparams := len(ft.in)
45	nargs := nparams
46	if isInterface {
47		nargs++
48	}
49	args := make([]*__ffi_type, nargs)
50	i := 0
51	off := 0
52	if isInterface {
53		args[0] = ffi_type_pointer()
54		off = 1
55	} else if isMethod {
56		args[0] = ffi_type_pointer()
57		i = 1
58	}
59	for ; i < nparams; i++ {
60		args[i+off] = typeToFFI(ft.in[i])
61	}
62
63	rettype := funcReturnFFI(ft)
64
65	var pargs **__ffi_type
66	if len(args) > 0 {
67		pargs = &args[0]
68	}
69	status := ffi_prep_cif(cif, _FFI_DEFAULT_ABI, uint32(nargs), rettype, pargs)
70	if status != _FFI_OK {
71		throw("ffi_prep_cif failed")
72	}
73}
74
75// funcReturnFFI returns the FFI definition of the return type of ft.
76func funcReturnFFI(ft *functype) *__ffi_type {
77	c := len(ft.out)
78	if c == 0 {
79		return ffi_type_void()
80	}
81
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.
85	var size uintptr
86	for _, v := range ft.out {
87		size += v.size
88	}
89	if size == 0 {
90		return ffi_type_void()
91	}
92
93	if c == 1 {
94		return typeToFFI(ft.out[0])
95	}
96
97	elements := make([]*__ffi_type, c+1)
98	for i, v := range ft.out {
99		elements[i] = typeToFFI(v)
100	}
101	elements[c] = nil
102
103	return &__ffi_type{
104		_type:    _FFI_TYPE_STRUCT,
105		elements: &elements[0],
106	}
107}
108
109// typeToFFI returns the __ffi_type for a Go type.
110func typeToFFI(typ *_type) *__ffi_type {
111	switch typ.kind & kindMask {
112	case kindBool:
113		switch unsafe.Sizeof(false) {
114		case 1:
115			return ffi_type_uint8()
116		case 4:
117			return ffi_type_uint32()
118		default:
119			throw("bad bool size")
120			return nil
121		}
122	case kindInt:
123		return intToFFI()
124	case kindInt8:
125		return ffi_type_sint8()
126	case kindInt16:
127		return ffi_type_sint16()
128	case kindInt32:
129		return ffi_type_sint32()
130	case kindInt64:
131		return ffi_type_sint64()
132	case kindUint:
133		switch unsafe.Sizeof(uint(0)) {
134		case 4:
135			return ffi_type_uint32()
136		case 8:
137			return ffi_type_uint64()
138		default:
139			throw("bad uint size")
140			return nil
141		}
142	case kindUint8:
143		return ffi_type_uint8()
144	case kindUint16:
145		return ffi_type_uint16()
146	case kindUint32:
147		return ffi_type_uint32()
148	case kindUint64:
149		return ffi_type_uint64()
150	case kindUintptr:
151		switch unsafe.Sizeof(uintptr(0)) {
152		case 4:
153			return ffi_type_uint32()
154		case 8:
155			return ffi_type_uint64()
156		default:
157			throw("bad uinptr size")
158			return nil
159		}
160	case kindFloat32:
161		return ffi_type_float()
162	case kindFloat64:
163		return ffi_type_double()
164	case kindComplex64:
165		if ffi_supports_complex() {
166			return ffi_type_complex_float()
167		} else {
168			return complexToFFI(ffi_type_float())
169		}
170	case kindComplex128:
171		if ffi_supports_complex() {
172			return ffi_type_complex_double()
173		} else {
174			return complexToFFI(ffi_type_double())
175		}
176	case kindArray:
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()
182	case kindInterface:
183		return interfaceToFFI()
184	case kindSlice:
185		return sliceToFFI((*slicetype)(unsafe.Pointer(typ)))
186	case kindString:
187		return stringToFFI()
188	case kindStruct:
189		return structToFFI((*structtype)(unsafe.Pointer(typ)))
190	default:
191		throw("unknown type kind")
192		return nil
193	}
194}
195
196// interfaceToFFI returns an ffi_type for a Go interface type.
197// This is used for both empty and non-empty interface types.
198func interfaceToFFI() *__ffi_type {
199	elements := make([]*__ffi_type, 3)
200	elements[0] = ffi_type_pointer()
201	elements[1] = elements[0]
202	elements[2] = nil
203	return &__ffi_type{
204		_type:    _FFI_TYPE_STRUCT,
205		elements: &elements[0],
206	}
207}
208
209// stringToFFI returns an ffi_type for a Go string type.
210func stringToFFI() *__ffi_type {
211	elements := make([]*__ffi_type, 3)
212	elements[0] = ffi_type_pointer()
213	elements[1] = intToFFI()
214	elements[2] = nil
215	return &__ffi_type{
216		_type:    _FFI_TYPE_STRUCT,
217		elements: &elements[0],
218	}
219}
220
221// structToFFI returns an ffi_type for a Go struct type.
222func structToFFI(typ *structtype) *__ffi_type {
223	c := len(typ.fields)
224	if c == 0 {
225		return emptyStructToFFI()
226	}
227	if typ.typ.kind&kindDirectIface != 0 {
228		return ffi_type_pointer()
229	}
230
231	fields := make([]*__ffi_type, 0, c+1)
232	checkPad := false
233	lastzero := false
234	for i, v := range typ.fields {
235		// Skip zero-sized fields; they confuse libffi,
236		// and there is no value to pass in any case.
237		// We do have to check whether the alignment of the
238		// zero-sized field introduces any padding for the
239		// next field.
240		if v.typ.size == 0 {
241			checkPad = true
242			lastzero = true
243			continue
244		}
245		lastzero = false
246
247		if checkPad {
248			off := uintptr(0)
249			for j := i - 1; j >= 0; j-- {
250				if typ.fields[j].typ.size > 0 {
251					off = typ.fields[j].offset() + typ.fields[j].typ.size
252					break
253				}
254			}
255			off += uintptr(v.typ.align) - 1
256			off &^= uintptr(v.typ.align) - 1
257			if off != v.offset() {
258				fields = append(fields, padFFI(v.offset()-off))
259			}
260			checkPad = false
261		}
262
263		fields = append(fields, typeToFFI(v.typ))
264	}
265
266	if lastzero {
267		// The compiler adds one byte padding to non-empty struct ending
268		// with a zero-sized field (types.cc:get_backend_struct_fields).
269		// Add this padding to the FFI type.
270		fields = append(fields, ffi_type_uint8())
271	}
272
273	fields = append(fields, nil)
274
275	return &__ffi_type{
276		_type:    _FFI_TYPE_STRUCT,
277		elements: &fields[0],
278	}
279}
280
281// sliceToFFI returns an ffi_type for a Go slice type.
282func sliceToFFI(typ *slicetype) *__ffi_type {
283	elements := make([]*__ffi_type, 4)
284	elements[0] = ffi_type_pointer()
285	elements[1] = intToFFI()
286	elements[2] = elements[1]
287	elements[3] = nil
288	return &__ffi_type{
289		_type:    _FFI_TYPE_STRUCT,
290		elements: &elements[0],
291	}
292}
293
294// complexToFFI returns an ffi_type for a Go complex type.
295// This is only used if libffi does not support complex types internally
296// for this target.
297func complexToFFI(ffiFloatType *__ffi_type) *__ffi_type {
298	elements := make([]*__ffi_type, 3)
299	elements[0] = ffiFloatType
300	elements[1] = ffiFloatType
301	elements[2] = nil
302	return &__ffi_type{
303		_type:    _FFI_TYPE_STRUCT,
304		elements: &elements[0],
305	}
306}
307
308// arrayToFFI returns an ffi_type for a Go array type.
309func arrayToFFI(typ *arraytype) *__ffi_type {
310	if typ.len == 0 {
311		return emptyStructToFFI()
312	}
313	if typ.typ.kind&kindDirectIface != 0 {
314		return ffi_type_pointer()
315	}
316	elements := make([]*__ffi_type, typ.len+1)
317	et := typeToFFI(typ.elem)
318	for i := uintptr(0); i < typ.len; i++ {
319		elements[i] = et
320	}
321	elements[typ.len] = nil
322	return &__ffi_type{
323		_type:    _FFI_TYPE_STRUCT,
324		elements: &elements[0],
325	}
326}
327
328// intToFFI returns an ffi_type for the Go int type.
329func intToFFI() *__ffi_type {
330	switch unsafe.Sizeof(0) {
331	case 4:
332		return ffi_type_sint32()
333	case 8:
334		return ffi_type_sint64()
335	default:
336		throw("bad int size")
337		return nil
338	}
339}
340
341// emptyStructToFFI returns an ffi_type for an empty struct.
342// The libffi library won't accept a struct with no fields.
343func emptyStructToFFI() *__ffi_type {
344	elements := make([]*__ffi_type, 2)
345	elements[0] = ffi_type_void()
346	elements[1] = nil
347	return &__ffi_type{
348		_type:    _FFI_TYPE_STRUCT,
349		elements: &elements[0],
350	}
351}
352
353// padFFI returns a padding field of the given size
354func padFFI(size uintptr) *__ffi_type {
355	elements := make([]*__ffi_type, size+1)
356	for i := uintptr(0); i < size; i++ {
357		elements[i] = ffi_type_uint8()
358	}
359	elements[size] = nil
360	return &__ffi_type{
361		_type:    _FFI_TYPE_STRUCT,
362		elements: &elements[0],
363	}
364}
365
366//go:linkname makeCIF reflect.makeCIF
367
368// makeCIF is used by the reflect package to allocate a CIF.
369func makeCIF(ft *functype) *_ffi_cif {
370	cif := new(_ffi_cif)
371	ffiFuncToCIF(ft, false, false, cif)
372	return cif
373}
374