struct_arm.go raw

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