| // 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 | 
 |  | 
 | // 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() | 
 | 	} | 
 | 	if typ.typ.kind&kindDirectIface != 0 { | 
 | 		return ffi_type_pointer() | 
 | 	} | 
 |  | 
 | 	fields := make([]*__ffi_type, 0, c+1) | 
 | 	checkPad := false | 
 | 	lastzero := false | 
 | 	for i, v := range typ.fields { | 
 | 		// Skip zero-sized fields; they confuse libffi, | 
 | 		// and there is no value to pass in any case. | 
 | 		// We do have to check whether the alignment of the | 
 | 		// zero-sized field introduces any padding for the | 
 | 		// next field. | 
 | 		if v.typ.size == 0 { | 
 | 			checkPad = true | 
 | 			lastzero = true | 
 | 			continue | 
 | 		} | 
 | 		lastzero = false | 
 |  | 
 | 		if checkPad { | 
 | 			off := uintptr(0) | 
 | 			for j := i - 1; j >= 0; j-- { | 
 | 				if typ.fields[j].typ.size > 0 { | 
 | 					off = typ.fields[j].offset() + typ.fields[j].typ.size | 
 | 					break | 
 | 				} | 
 | 			} | 
 | 			off += uintptr(v.typ.align) - 1 | 
 | 			off &^= uintptr(v.typ.align) - 1 | 
 | 			if off != v.offset() { | 
 | 				fields = append(fields, padFFI(v.offset()-off)) | 
 | 			} | 
 | 			checkPad = false | 
 | 		} | 
 |  | 
 | 		fields = append(fields, typeToFFI(v.typ)) | 
 | 	} | 
 |  | 
 | 	if lastzero { | 
 | 		// The compiler adds one byte padding to non-empty struct ending | 
 | 		// with a zero-sized field (types.cc:get_backend_struct_fields). | 
 | 		// Add this padding to the FFI type. | 
 | 		fields = append(fields, ffi_type_uint8()) | 
 | 	} | 
 |  | 
 | 	fields = append(fields, 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() | 
 | 	} | 
 | 	if typ.typ.kind&kindDirectIface != 0 { | 
 | 		return ffi_type_pointer() | 
 | 	} | 
 | 	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], | 
 | 	} | 
 | } | 
 |  | 
 | // padFFI returns a padding field of the given size | 
 | func padFFI(size uintptr) *__ffi_type { | 
 | 	elements := make([]*__ffi_type, size+1) | 
 | 	for i := uintptr(0); i < size; i++ { | 
 | 		elements[i] = ffi_type_uint8() | 
 | 	} | 
 | 	elements[size] = 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 | 
 | } |