build(deps): bump github.com/testcontainers/testcontainers-go
Bumps [github.com/testcontainers/testcontainers-go](https://github.com/testcontainers/testcontainers-go) from 0.40.0 to 0.41.0. - [Release notes](https://github.com/testcontainers/testcontainers-go/releases) - [Commits](https://github.com/testcontainers/testcontainers-go/compare/v0.40.0...v0.41.0) --- updated-dependencies: - dependency-name: github.com/testcontainers/testcontainers-go dependency-version: 0.41.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
fef601f104
commit
de59bb63ad
+220
-85
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build darwin || freebsd || linux || windows
|
||||
//go:build darwin || freebsd || linux || netbsd || windows
|
||||
|
||||
package purego
|
||||
|
||||
@@ -10,14 +10,25 @@ import (
|
||||
"math"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego/internal/strings"
|
||||
"github.com/ebitengine/purego/internal/xreflect"
|
||||
)
|
||||
|
||||
const (
|
||||
align8ByteMask = 7 // Mask for 8-byte alignment: (val + 7) &^ 7
|
||||
align8ByteSize = 8 // 8-byte alignment boundary
|
||||
)
|
||||
|
||||
var thePool = sync.Pool{New: func() any {
|
||||
return new(syscall15Args)
|
||||
}}
|
||||
|
||||
// RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name).
|
||||
// It panics if it can't find the name symbol.
|
||||
func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
|
||||
func RegisterLibFunc(fptr any, handle uintptr, name string) {
|
||||
sym, err := loadSymbol(handle, name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -53,14 +64,14 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
|
||||
// int64 <=> int64_t
|
||||
// float32 <=> float
|
||||
// float64 <=> double
|
||||
// struct <=> struct (WIP - darwin only)
|
||||
// struct <=> struct (darwin amd64/arm64, linux amd64/arm64)
|
||||
// func <=> C function
|
||||
// unsafe.Pointer, *T <=> void*
|
||||
// []T => void*
|
||||
//
|
||||
// There is a special case when the last argument of fptr is a variadic interface (or []interface}
|
||||
// it will be expanded into a call to the C function as if it had the arguments in that slice.
|
||||
// This means that using arg ...interface{} is like a cast to the function with the arguments inside arg.
|
||||
// This means that using arg ...any is like a cast to the function with the arguments inside arg.
|
||||
// This is not the same as C variadic.
|
||||
//
|
||||
// # Memory
|
||||
@@ -88,6 +99,9 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
|
||||
// it does not support aligning fields properly. It is therefore the responsibility of the caller to ensure
|
||||
// that all padding is added to the Go struct to match the C one. See `BoolStructFn` in struct_test.go for an example.
|
||||
//
|
||||
// On Darwin ARM64, purego handles proper alignment of struct arguments when passing them on the stack,
|
||||
// following the C ABI's byte-level packing rules.
|
||||
//
|
||||
// # Example
|
||||
//
|
||||
// All functions below call this C function:
|
||||
@@ -105,7 +119,8 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
|
||||
// defer free(mustFree)
|
||||
//
|
||||
// [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C
|
||||
func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
func RegisterFunc(fptr any, cfn uintptr) {
|
||||
const is32bit = unsafe.Sizeof(uintptr(0)) == 4
|
||||
fn := reflect.ValueOf(fptr).Elem()
|
||||
ty := fn.Type()
|
||||
if ty.Kind() != reflect.Func {
|
||||
@@ -118,7 +133,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
panic("purego: cfn is nil")
|
||||
}
|
||||
if ty.NumOut() == 1 && (ty.Out(0).Kind() == reflect.Float32 || ty.Out(0).Kind() == reflect.Float64) &&
|
||||
runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" {
|
||||
runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" && runtime.GOARCH != "386" && runtime.GOARCH != "amd64" && runtime.GOARCH != "loong64" && runtime.GOARCH != "ppc64le" && runtime.GOARCH != "riscv64" && runtime.GOARCH != "s390x" {
|
||||
panic("purego: float returns are not supported")
|
||||
}
|
||||
{
|
||||
@@ -152,19 +167,13 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
stack++
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
const is32bit = unsafe.Sizeof(uintptr(0)) == 4
|
||||
if is32bit {
|
||||
panic("purego: floats only supported on 64bit platforms")
|
||||
}
|
||||
if floats < numOfFloats {
|
||||
if floats < numOfFloatRegisters() {
|
||||
floats++
|
||||
} else {
|
||||
stack++
|
||||
}
|
||||
case reflect.Struct:
|
||||
if runtime.GOOS != "darwin" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64") {
|
||||
panic("purego: struct arguments are only supported on darwin amd64 & arm64")
|
||||
}
|
||||
ensureStructSupportedForRegisterFunc()
|
||||
if arg.Size() == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -183,9 +192,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
}
|
||||
}
|
||||
if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
|
||||
if runtime.GOOS != "darwin" {
|
||||
panic("purego: struct return values only supported on darwin arm64 & amd64")
|
||||
}
|
||||
ensureStructSupportedForRegisterFunc()
|
||||
outType := ty.Out(0)
|
||||
checkStructFieldsSupported(outType)
|
||||
if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize {
|
||||
@@ -194,27 +201,29 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
ints++
|
||||
}
|
||||
}
|
||||
|
||||
sizeOfStack := maxArgs - numOfIntegerRegisters()
|
||||
if stack > sizeOfStack {
|
||||
panic("purego: too many arguments")
|
||||
}
|
||||
}
|
||||
v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) {
|
||||
if len(args) > 0 {
|
||||
if variadic, ok := args[len(args)-1].Interface().([]interface{}); ok {
|
||||
// subtract one from args bc the last argument in args is []interface{}
|
||||
// which we are currently expanding
|
||||
tmp := make([]reflect.Value, len(args)-1+len(variadic))
|
||||
n := copy(tmp, args[:len(args)-1])
|
||||
for i, v := range variadic {
|
||||
tmp[n+i] = reflect.ValueOf(v)
|
||||
}
|
||||
args = tmp
|
||||
// On Darwin ARM64, use byte-based validation since arguments pack efficiently.
|
||||
// See https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms
|
||||
if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
|
||||
stackBytes := estimateStackBytes(ty)
|
||||
maxStackBytes := sizeOfStack * 8
|
||||
if stackBytes > maxStackBytes {
|
||||
panic("purego: too many stack arguments")
|
||||
}
|
||||
} else {
|
||||
if stack > sizeOfStack {
|
||||
panic("purego: too many stack arguments")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) {
|
||||
var sysargs [maxArgs]uintptr
|
||||
stack := sysargs[numOfIntegerRegisters():]
|
||||
var floats [numOfFloats]uintptr
|
||||
// Use maxArgs instead of numOfFloatRegisters() to keep this code path allocation-free,
|
||||
// since numOfFloatRegisters() is a function call, not a constant.
|
||||
// maxArgs is always greater than or equal to numOfFloatRegisters() so this is safe.
|
||||
var floats [maxArgs]uintptr
|
||||
var numInts int
|
||||
var numFloats int
|
||||
var numStack int
|
||||
@@ -222,7 +231,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
|
||||
// Windows arm64 uses the same calling convention as macOS and Linux
|
||||
addStack = func(x uintptr) {
|
||||
stack[numStack] = x
|
||||
sysargs[numOfIntegerRegisters()+numStack] = x
|
||||
numStack++
|
||||
}
|
||||
addInt = func(x uintptr) {
|
||||
@@ -234,7 +243,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
}
|
||||
}
|
||||
addFloat = func(x uintptr) {
|
||||
if numFloats < len(floats) {
|
||||
if numFloats < numOfFloatRegisters() {
|
||||
floats[numFloats] = x
|
||||
numFloats++
|
||||
} else {
|
||||
@@ -255,15 +264,16 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
addFloat = addStack
|
||||
}
|
||||
|
||||
var keepAlive []interface{}
|
||||
var keepAlive []any
|
||||
defer func() {
|
||||
runtime.KeepAlive(keepAlive)
|
||||
runtime.KeepAlive(args)
|
||||
}()
|
||||
var syscall syscall15Args
|
||||
|
||||
var arm64_r8 uintptr
|
||||
if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
|
||||
outType := ty.Out(0)
|
||||
if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize {
|
||||
if (runtime.GOARCH == "amd64" || runtime.GOARCH == "loong64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "s390x") && outType.Size() > maxRegAllocStructSize {
|
||||
val := reflect.New(outType)
|
||||
keepAlive = append(keepAlive, val)
|
||||
addInt(val.Pointer())
|
||||
@@ -272,53 +282,46 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
if !isAllFloats || numFields > 4 {
|
||||
val := reflect.New(outType)
|
||||
keepAlive = append(keepAlive, val)
|
||||
syscall.arm64_r8 = val.Pointer()
|
||||
arm64_r8 = val.Pointer()
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, v := range args {
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
ptr := strings.CString(v.String())
|
||||
keepAlive = append(keepAlive, ptr)
|
||||
addInt(uintptr(unsafe.Pointer(ptr)))
|
||||
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
addInt(uintptr(v.Uint()))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
addInt(uintptr(v.Int()))
|
||||
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
|
||||
// There is no need to keepAlive this pointer separately because it is kept alive in the args variable
|
||||
addInt(v.Pointer())
|
||||
case reflect.Func:
|
||||
addInt(NewCallback(v.Interface()))
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
addInt(1)
|
||||
} else {
|
||||
addInt(0)
|
||||
for i, v := range args {
|
||||
if variadic, ok := xreflect.TypeAssert[[]any](args[i]); ok {
|
||||
if i != len(args)-1 {
|
||||
panic("purego: can only expand last parameter")
|
||||
}
|
||||
case reflect.Float32:
|
||||
addFloat(uintptr(math.Float32bits(float32(v.Float()))))
|
||||
case reflect.Float64:
|
||||
addFloat(uintptr(math.Float64bits(v.Float())))
|
||||
case reflect.Struct:
|
||||
keepAlive = addStruct(v, &numInts, &numFloats, &numStack, addInt, addFloat, addStack, keepAlive)
|
||||
default:
|
||||
panic("purego: unsupported kind: " + v.Kind().String())
|
||||
for _, x := range variadic {
|
||||
keepAlive = addValue(reflect.ValueOf(x), keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Check if we need to start Darwin ARM64 C-style stack packing
|
||||
if runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" && shouldBundleStackArgs(v, numInts, numFloats) {
|
||||
// Collect and separate remaining args into register vs stack
|
||||
stackArgs, newKeepAlive := collectStackArgs(args, i, numInts, numFloats,
|
||||
keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
|
||||
keepAlive = newKeepAlive
|
||||
|
||||
// Bundle stack arguments with C-style packing
|
||||
bundleStackArgs(stackArgs, addStack)
|
||||
break
|
||||
}
|
||||
keepAlive = addValue(v, keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
|
||||
}
|
||||
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
|
||||
|
||||
syscall := thePool.Get().(*syscall15Args)
|
||||
defer thePool.Put(syscall)
|
||||
|
||||
if runtime.GOARCH == "loong64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "s390x" {
|
||||
syscall.Set(cfn, sysargs[:], floats[:], 0)
|
||||
runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall))
|
||||
} else if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
|
||||
// Use the normal arm64 calling convention even on Windows
|
||||
syscall = syscall15Args{
|
||||
cfn,
|
||||
sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5],
|
||||
sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
|
||||
sysargs[12], sysargs[13], sysargs[14],
|
||||
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7],
|
||||
syscall.arm64_r8,
|
||||
}
|
||||
runtime_cgocall(syscall15XABI0, unsafe.Pointer(&syscall))
|
||||
syscall.Set(cfn, sysargs[:], floats[:], arm64_r8)
|
||||
runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall))
|
||||
} else {
|
||||
*syscall = syscall15Args{}
|
||||
// This is a fallback for Windows amd64, 386, and arm. Note this may not support floats
|
||||
syscall.a1, syscall.a2, _ = syscall_syscall15X(cfn, sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4],
|
||||
sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
|
||||
@@ -351,21 +354,89 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
case reflect.Float32:
|
||||
// NOTE: syscall.r2 is only the floating return value on 64bit platforms.
|
||||
// On 32bit platforms syscall.r2 is the upper part of a 64bit return.
|
||||
v.SetFloat(float64(math.Float32frombits(uint32(syscall.f1))))
|
||||
// On 386, x87 FPU returns floats as float64 in ST(0), so we read as float64 and convert.
|
||||
// On PPC64LE, C ABI converts float32 to double in FPR, so we read as float64.
|
||||
// On S390X (big-endian), float32 is in upper 32 bits of the 64-bit FP register.
|
||||
switch runtime.GOARCH {
|
||||
case "386":
|
||||
v.SetFloat(math.Float64frombits(uint64(syscall.f1) | (uint64(syscall.f2) << 32)))
|
||||
case "ppc64le":
|
||||
v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
|
||||
case "s390x":
|
||||
// S390X is big-endian: float32 in upper 32 bits of 64-bit register
|
||||
v.SetFloat(float64(math.Float32frombits(uint32(syscall.f1 >> 32))))
|
||||
default:
|
||||
v.SetFloat(float64(math.Float32frombits(uint32(syscall.f1))))
|
||||
}
|
||||
case reflect.Float64:
|
||||
// NOTE: syscall.r2 is only the floating return value on 64bit platforms.
|
||||
// On 32bit platforms syscall.r2 is the upper part of a 64bit return.
|
||||
v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
|
||||
if is32bit {
|
||||
v.SetFloat(math.Float64frombits(uint64(syscall.f1) | (uint64(syscall.f2) << 32)))
|
||||
} else {
|
||||
v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
|
||||
}
|
||||
case reflect.Struct:
|
||||
v = getStruct(outType, syscall)
|
||||
v = getStruct(outType, *syscall)
|
||||
default:
|
||||
panic("purego: unsupported return kind: " + outType.Kind().String())
|
||||
}
|
||||
return []reflect.Value{v}
|
||||
if len(args) > 0 {
|
||||
// reuse args slice instead of allocating one when possible
|
||||
args[0] = v
|
||||
return args[:1]
|
||||
} else {
|
||||
return []reflect.Value{v}
|
||||
}
|
||||
})
|
||||
fn.Set(v)
|
||||
}
|
||||
|
||||
func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat func(x uintptr), addStack func(x uintptr), numInts *int, numFloats *int, numStack *int) []any {
|
||||
const is32bit = unsafe.Sizeof(uintptr(0)) == 4
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
ptr := strings.CString(v.String())
|
||||
keepAlive = append(keepAlive, ptr)
|
||||
addInt(uintptr(unsafe.Pointer(ptr)))
|
||||
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
addInt(uintptr(v.Uint()))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
addInt(uintptr(v.Int()))
|
||||
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
|
||||
// There is no need to keepAlive this pointer separately because it is kept alive in the args variable
|
||||
addInt(v.Pointer())
|
||||
case reflect.Func:
|
||||
addInt(NewCallback(v.Interface()))
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
addInt(1)
|
||||
} else {
|
||||
addInt(0)
|
||||
}
|
||||
case reflect.Float32:
|
||||
// On S390X big-endian, float32 goes in upper 32 bits of 64-bit FP register
|
||||
if runtime.GOARCH == "s390x" {
|
||||
addFloat(uintptr(math.Float32bits(float32(v.Float()))) << 32)
|
||||
} else {
|
||||
addFloat(uintptr(math.Float32bits(float32(v.Float()))))
|
||||
}
|
||||
case reflect.Float64:
|
||||
if is32bit {
|
||||
bits := math.Float64bits(v.Float())
|
||||
addFloat(uintptr(bits))
|
||||
addFloat(uintptr(bits >> 32))
|
||||
} else {
|
||||
addFloat(uintptr(math.Float64bits(v.Float())))
|
||||
}
|
||||
case reflect.Struct:
|
||||
keepAlive = addStruct(v, numInts, numFloats, numStack, addInt, addFloat, addStack, keepAlive)
|
||||
default:
|
||||
panic("purego: unsupported kind: " + v.Kind().String())
|
||||
}
|
||||
return keepAlive
|
||||
}
|
||||
|
||||
// maxRegAllocStructSize is the biggest a struct can be while still fitting in registers.
|
||||
// if it is bigger than this than enough space must be allocated on the heap and then passed into
|
||||
// the function as the first parameter on amd64 or in R8 on arm64.
|
||||
@@ -411,26 +482,90 @@ func checkStructFieldsSupported(ty reflect.Type) {
|
||||
switch f.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Uintptr, reflect.Ptr, reflect.UnsafePointer, reflect.Float64, reflect.Float32:
|
||||
reflect.Uintptr, reflect.Ptr, reflect.UnsafePointer, reflect.Float64, reflect.Float32,
|
||||
reflect.Bool:
|
||||
default:
|
||||
panic(fmt.Sprintf("purego: struct field type %s is not supported", f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ensureStructSupportedForRegisterFunc() {
|
||||
if runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" {
|
||||
panic("purego: struct arguments are only supported on amd64 and arm64")
|
||||
}
|
||||
if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
|
||||
panic("purego: struct arguments are only supported on darwin and linux")
|
||||
}
|
||||
}
|
||||
|
||||
func roundUpTo8(val uintptr) uintptr {
|
||||
return (val + 7) &^ 7
|
||||
return (val + align8ByteMask) &^ align8ByteMask
|
||||
}
|
||||
|
||||
func numOfFloatRegisters() int {
|
||||
switch runtime.GOARCH {
|
||||
case "amd64", "arm64", "loong64", "ppc64le", "riscv64":
|
||||
return 8
|
||||
case "s390x":
|
||||
return 4
|
||||
case "arm":
|
||||
return 16
|
||||
case "386":
|
||||
// i386 SysV ABI passes all arguments on the stack, including floats
|
||||
return 0
|
||||
default:
|
||||
// since this platform isn't supported and can therefore only access
|
||||
// integer registers it is safest to return 8
|
||||
return 8
|
||||
}
|
||||
}
|
||||
|
||||
func numOfIntegerRegisters() int {
|
||||
switch runtime.GOARCH {
|
||||
case "arm64":
|
||||
case "arm64", "loong64", "ppc64le", "riscv64":
|
||||
return 8
|
||||
case "amd64":
|
||||
return 6
|
||||
case "s390x":
|
||||
// S390X uses R2-R6 for integer arguments
|
||||
return 5
|
||||
case "arm":
|
||||
return 4
|
||||
case "386":
|
||||
// i386 SysV ABI passes all arguments on the stack
|
||||
return 0
|
||||
default:
|
||||
// since this platform isn't supported and can therefore only access
|
||||
// integer registers it is fine to return the maxArgs
|
||||
return maxArgs
|
||||
}
|
||||
}
|
||||
|
||||
// estimateStackBytes estimates stack bytes needed for Darwin ARM64 validation.
|
||||
// This is a conservative estimate used only for early error detection.
|
||||
func estimateStackBytes(ty reflect.Type) int {
|
||||
var numInts, numFloats int
|
||||
var stackBytes int
|
||||
|
||||
for i := 0; i < ty.NumIn(); i++ {
|
||||
arg := ty.In(i)
|
||||
size := int(arg.Size())
|
||||
|
||||
// Check if this goes to register or stack
|
||||
usesInt := arg.Kind() != reflect.Float32 && arg.Kind() != reflect.Float64
|
||||
if usesInt && numInts < numOfIntegerRegisters() {
|
||||
numInts++
|
||||
} else if !usesInt && numFloats < numOfFloatRegisters() {
|
||||
numFloats++
|
||||
} else {
|
||||
// Goes to stack - accumulate total bytes
|
||||
stackBytes += size
|
||||
}
|
||||
}
|
||||
// Round total to 8-byte boundary
|
||||
if stackBytes > 0 && stackBytes%align8ByteSize != 0 {
|
||||
stackBytes = int(roundUpTo8(uintptr(stackBytes)))
|
||||
}
|
||||
return stackBytes
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user