mirror of
https://github.com/containers/podman.git
synced 2025-10-13 01:06:10 +08:00
191 lines
4.4 KiB
Go
191 lines
4.4 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
|
|
|
|
package purego
|
|
|
|
import (
|
|
"math"
|
|
"reflect"
|
|
"unsafe"
|
|
)
|
|
|
|
func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
|
|
outSize := outType.Size()
|
|
switch {
|
|
case outSize == 0:
|
|
return reflect.New(outType).Elem()
|
|
case outSize <= 8:
|
|
r1 := syscall.a1
|
|
if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
|
|
r1 = syscall.f1
|
|
if numFields == 2 {
|
|
r1 = syscall.f2<<32 | syscall.f1
|
|
}
|
|
}
|
|
return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{r1})).Elem()
|
|
case outSize <= 16:
|
|
r1, r2 := syscall.a1, syscall.a2
|
|
if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
|
|
switch numFields {
|
|
case 4:
|
|
r1 = syscall.f2<<32 | syscall.f1
|
|
r2 = syscall.f4<<32 | syscall.f3
|
|
case 3:
|
|
r1 = syscall.f2<<32 | syscall.f1
|
|
r2 = syscall.f3
|
|
case 2:
|
|
r1 = syscall.f1
|
|
r2 = syscall.f2
|
|
default:
|
|
panic("unreachable")
|
|
}
|
|
}
|
|
return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b uintptr }{r1, r2})).Elem()
|
|
default:
|
|
// create struct from the Go pointer created above
|
|
// weird pointer dereference to circumvent go vet
|
|
return reflect.NewAt(outType, *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))).Elem()
|
|
}
|
|
}
|
|
|
|
const (
|
|
_NO_CLASS = 0b00
|
|
_FLOAT = 0b01
|
|
_INT = 0b11
|
|
)
|
|
|
|
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
|
|
if v.Type().Size() == 0 {
|
|
return keepAlive
|
|
}
|
|
|
|
if size := v.Type().Size(); size <= 16 {
|
|
placeRegisters(v, addFloat, addInt)
|
|
} else {
|
|
keepAlive = placeStack(v, keepAlive, addInt)
|
|
}
|
|
return keepAlive // the struct was allocated so don't panic
|
|
}
|
|
|
|
func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
|
|
var val uint64
|
|
var shift byte
|
|
var flushed bool
|
|
class := _NO_CLASS
|
|
var place func(v reflect.Value)
|
|
place = func(v reflect.Value) {
|
|
var numFields int
|
|
if v.Kind() == reflect.Struct {
|
|
numFields = v.Type().NumField()
|
|
} else {
|
|
numFields = v.Type().Len()
|
|
}
|
|
for k := 0; k < numFields; k++ {
|
|
flushed = false
|
|
var f reflect.Value
|
|
if v.Kind() == reflect.Struct {
|
|
f = v.Field(k)
|
|
} else {
|
|
f = v.Index(k)
|
|
}
|
|
align := byte(f.Type().Align()*8 - 1)
|
|
shift = (shift + align) &^ align
|
|
if shift >= 64 {
|
|
shift = 0
|
|
flushed = true
|
|
if class == _FLOAT {
|
|
addFloat(uintptr(val))
|
|
} else {
|
|
addInt(uintptr(val))
|
|
}
|
|
}
|
|
switch f.Type().Kind() {
|
|
case reflect.Struct:
|
|
place(f)
|
|
case reflect.Bool:
|
|
if f.Bool() {
|
|
val |= 1
|
|
}
|
|
shift += 8
|
|
class |= _INT
|
|
case reflect.Uint8:
|
|
val |= f.Uint() << shift
|
|
shift += 8
|
|
class |= _INT
|
|
case reflect.Uint16:
|
|
val |= f.Uint() << shift
|
|
shift += 16
|
|
class |= _INT
|
|
case reflect.Uint32:
|
|
val |= f.Uint() << shift
|
|
shift += 32
|
|
class |= _INT
|
|
case reflect.Uint64, reflect.Uint, reflect.Uintptr:
|
|
addInt(uintptr(f.Uint()))
|
|
shift = 0
|
|
flushed = true
|
|
class = _NO_CLASS
|
|
case reflect.Int8:
|
|
val |= uint64(f.Int()&0xFF) << shift
|
|
shift += 8
|
|
class |= _INT
|
|
case reflect.Int16:
|
|
val |= uint64(f.Int()&0xFFFF) << shift
|
|
shift += 16
|
|
class |= _INT
|
|
case reflect.Int32:
|
|
val |= uint64(f.Int()&0xFFFF_FFFF) << shift
|
|
shift += 32
|
|
class |= _INT
|
|
case reflect.Int64, reflect.Int:
|
|
addInt(uintptr(f.Int()))
|
|
shift = 0
|
|
flushed = true
|
|
class = _NO_CLASS
|
|
case reflect.Float32:
|
|
if class == _FLOAT {
|
|
addFloat(uintptr(val))
|
|
val = 0
|
|
shift = 0
|
|
}
|
|
val |= uint64(math.Float32bits(float32(f.Float()))) << shift
|
|
shift += 32
|
|
class |= _FLOAT
|
|
case reflect.Float64:
|
|
addFloat(uintptr(math.Float64bits(float64(f.Float()))))
|
|
shift = 0
|
|
flushed = true
|
|
class = _NO_CLASS
|
|
case reflect.Ptr:
|
|
addInt(f.Pointer())
|
|
shift = 0
|
|
flushed = true
|
|
class = _NO_CLASS
|
|
case reflect.Array:
|
|
place(f)
|
|
default:
|
|
panic("purego: unsupported kind " + f.Kind().String())
|
|
}
|
|
}
|
|
}
|
|
place(v)
|
|
if !flushed {
|
|
if class == _FLOAT {
|
|
addFloat(uintptr(val))
|
|
} else {
|
|
addInt(uintptr(val))
|
|
}
|
|
}
|
|
}
|
|
|
|
func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
|
|
// Struct is too big to be placed in registers.
|
|
// Copy to heap and place the pointer in register
|
|
ptrStruct := reflect.New(v.Type())
|
|
ptrStruct.Elem().Set(v)
|
|
ptr := ptrStruct.Elem().Addr().UnsafePointer()
|
|
keepAlive = append(keepAlive, ptr)
|
|
addInt(uintptr(ptr))
|
|
return keepAlive
|
|
}
|