1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
3
4package purego
5
6import (
7 "reflect"
8 "runtime"
9 "unsafe"
10)
11
12func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
13 size := v.Type().Size()
14 if size == 0 {
15 return keepAlive
16 }
17
18 // TODO: ARM EABI: small structs are passed in registers or on stack
19 // For simplicity, pass by pointer for now
20 ptr, live := stableValuePointer(v)
21 if live != nil {
22 keepAlive = append(keepAlive, live)
23 }
24 if *numInts < 4 {
25 addInt(uintptr(ptr))
26 *numInts++
27 } else {
28 addStack(uintptr(ptr))
29 *numStack++
30 }
31 runtime.KeepAlive(live)
32 return keepAlive
33}
34
35func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
36 outSize := outType.Size()
37 if outSize == 0 {
38 return reflect.New(outType).Elem()
39 }
40 if outSize <= 4 {
41 // Fits in one register
42 return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{syscall.a1})).Elem()
43 }
44 if outSize <= 8 {
45 // Fits in two registers
46 return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b uintptr }{syscall.a1, syscall.a2})).Elem()
47 }
48 // Larger structs returned via pointer in a1
49 return reflect.NewAt(outType, *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))).Elem()
50}
51
52func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
53 // TODO: For ARM32, just pass the struct data directly
54 // This is a simplified implementation
55 size := v.Type().Size()
56 if size == 0 {
57 return
58 }
59 ptr, live := stableValuePointer(v)
60 if size <= 4 {
61 addInt(*(*uintptr)(ptr))
62 } else if size <= 8 {
63 addInt(*(*uintptr)(ptr))
64 addInt(*(*uintptr)(unsafe.Add(ptr, 4)))
65 }
66 runtime.KeepAlive(live)
67}
68
69// shouldBundleStackArgs always returns false on arm
70// since C-style stack argument bundling is only needed on Darwin ARM64.
71func shouldBundleStackArgs(v reflect.Value, numInts, numFloats int) bool {
72 return false
73}
74
75// structFitsInRegisters is not used on arm.
76func structFitsInRegisters(val reflect.Value, tempNumInts, tempNumFloats int) (bool, int, int) {
77 panic("purego: structFitsInRegisters should not be called on arm")
78}
79
80// collectStackArgs is not used on arm.
81func collectStackArgs(args []reflect.Value, startIdx int, numInts, numFloats int,
82 keepAlive []any, addInt, addFloat, addStack func(uintptr),
83 pNumInts, pNumFloats, pNumStack *int) ([]reflect.Value, []any) {
84 panic("purego: collectStackArgs should not be called on arm")
85}
86
87// bundleStackArgs is not used on arm.
88func bundleStackArgs(stackArgs []reflect.Value, addStack func(uintptr)) {
89 panic("purego: bundleStackArgs should not be called on arm")
90}
91
92func getCallbackStruct(inType reflect.Type, frame unsafe.Pointer, floatsN *int, intsN *int, stackSlot *int, stackByteOffset *uintptr) reflect.Value {
93 panic("purego: struct callback arguments are not supported on arm")
94}
95
96func setStruct(a *callbackArgs, ret reflect.Value) {
97 panic("purego: struct returns are not supported on arm")
98}