struct_arm.go 2.5 KB

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