chore(mod): upgrade purego version to v0.8.3

This commit is contained in:
naison
2025-05-12 07:41:39 +00:00
parent 46aebef01f
commit b28eaef6a7
47 changed files with 106 additions and 408 deletions

2
go.mod
View File

@@ -161,7 +161,7 @@ require (
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 // indirect
github.com/ebitengine/purego v0.9.0-alpha.3.0.20250507171635-5047c08daa38 // indirect github.com/ebitengine/purego v0.8.3 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 // indirect github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect

4
go.sum
View File

@@ -265,8 +265,8 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m
github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg= github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg=
github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds= github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds=
github.com/ebitengine/purego v0.9.0-alpha.3.0.20250507171635-5047c08daa38 h1:61WY14WhyU89bEJCjegpt6b8wDNsU+Z1416JGwfEKwI= github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
github.com/ebitengine/purego v0.9.0-alpha.3.0.20250507171635-5047c08daa38/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=

View File

@@ -36,7 +36,7 @@ except for float arguments and return values.
## Example ## Example
The example below only showcases purego use for macOS and Linux. The other platforms require special handling which can The example below only showcases purego use for macOS and Linux. The other platforms require special handling which can
be seen in the complete example at [examples/libc](https://github.com/ebitengine/purego/tree/main/examples/libc) which supports FreeBSD and Windows. be seen in the complete example at [examples/libc](https://github.com/ebitengine/purego/tree/main/examples/libc) which supports Windows and FreeBSD.
```go ```go
package main package main
@@ -92,7 +92,6 @@ This is a list of the copied files:
* `internal/fakecgo/iscgo.go` from package `runtime/cgo` * `internal/fakecgo/iscgo.go` from package `runtime/cgo`
* `internal/fakecgo/setenv.go` from package `runtime/cgo` * `internal/fakecgo/setenv.go` from package `runtime/cgo`
* `internal/fakecgo/freebsd.go` from package `runtime/cgo` * `internal/fakecgo/freebsd.go` from package `runtime/cgo`
* `internal/fakecgo/netbsd.go` from package `runtime/cgo`
The files `abi_*.h` and `internal/fakecgo/abi_*.h` are the same because Bazel does not support cross-package use of The files `abi_*.h` and `internal/fakecgo/abi_*.h` are the same because Bazel does not support cross-package use of
`#include` so we need each one once per package. (cf. [issue](https://github.com/bazelbuild/rules_go/issues/3636)) `#include` so we need each one once per package. (cf. [issue](https://github.com/bazelbuild/rules_go/issues/3636))

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build cgo && (darwin || freebsd || linux || netbsd) //go:build cgo && (darwin || freebsd || linux)
package purego package purego

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 The Ebitengine Authors // SPDX-FileCopyrightText: 2023 The Ebitengine Authors
//go:build darwin || freebsd || linux || netbsd //go:build darwin || freebsd || linux
package purego package purego

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build (darwin || freebsd || linux || netbsd) && !android && !faketime //go:build (darwin || freebsd || linux) && !android && !faketime
package purego package purego

View File

@@ -1,15 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package purego
// Source for constants: https://github.com/NetBSD/src/blob/trunk/include/dlfcn.h
const (
intSize = 32 << (^uint(0) >> 63) // 32 or 64
RTLD_DEFAULT = 1<<intSize - 2 // Pseudo-handle for dlsym so search for any loaded symbol
RTLD_LAZY = 0x00000001 // Relocations are performed at an implementation-dependent time.
RTLD_NOW = 0x00000002 // Relocations are performed when the object is loaded.
RTLD_LOCAL = 0x00000000 // All symbols are not made available for relocation processing by other modules.
RTLD_GLOBAL = 0x00000100 // All symbols are available for relocation processing of other modules.
)

View File

@@ -1,9 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package purego
//go:cgo_import_dynamic purego_dlopen dlopen "libc.so"
//go:cgo_import_dynamic purego_dlsym dlsym "libc.so"
//go:cgo_import_dynamic purego_dlerror dlerror "libc.so"
//go:cgo_import_dynamic purego_dlclose dlclose "libc.so"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || !cgo && (freebsd || linux || netbsd) && !faketime //go:build darwin || !cgo && (freebsd || linux) && !faketime
#include "textflag.h" #include "textflag.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || netbsd || windows //go:build darwin || freebsd || linux || windows
package purego package purego
@@ -10,20 +10,14 @@ import (
"math" "math"
"reflect" "reflect"
"runtime" "runtime"
"strconv"
"sync"
"unsafe" "unsafe"
"github.com/ebitengine/purego/internal/strings" "github.com/ebitengine/purego/internal/strings"
) )
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). // 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. // It panics if it can't find the name symbol.
func RegisterLibFunc(fptr any, handle uintptr, name string) { func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
sym, err := loadSymbol(handle, name) sym, err := loadSymbol(handle, name)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -66,7 +60,7 @@ func RegisterLibFunc(fptr any, handle uintptr, name string) {
// //
// There is a special case when the last argument of fptr is a variadic interface (or []interface} // 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. // 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 ...any is like a cast to the function with the arguments inside arg. // This means that using arg ...interface{} is like a cast to the function with the arguments inside arg.
// This is not the same as C variadic. // This is not the same as C variadic.
// //
// # Memory // # Memory
@@ -111,7 +105,7 @@ func RegisterLibFunc(fptr any, handle uintptr, name string) {
// defer free(mustFree) // defer free(mustFree)
// //
// [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C // [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C
func RegisterFunc(fptr any, cfn uintptr) { func RegisterFunc(fptr interface{}, cfn uintptr) {
fn := reflect.ValueOf(fptr).Elem() fn := reflect.ValueOf(fptr).Elem()
ty := fn.Type() ty := fn.Type()
if ty.Kind() != reflect.Func { if ty.Kind() != reflect.Func {
@@ -162,7 +156,7 @@ func RegisterFunc(fptr any, cfn uintptr) {
if is32bit { if is32bit {
panic("purego: floats only supported on 64bit platforms") panic("purego: floats only supported on 64bit platforms")
} }
if floats < numOfFloatRegisters { if floats < numOfFloats {
floats++ floats++
} else { } else {
stack++ stack++
@@ -206,8 +200,21 @@ func RegisterFunc(fptr any, cfn uintptr) {
} }
} }
v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) { 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
}
}
var sysargs [maxArgs]uintptr var sysargs [maxArgs]uintptr
var floats [numOfFloatRegisters]uintptr stack := sysargs[numOfIntegerRegisters():]
var floats [numOfFloats]uintptr
var numInts int var numInts int
var numFloats int var numFloats int
var numStack int var numStack int
@@ -215,7 +222,7 @@ func RegisterFunc(fptr any, cfn uintptr) {
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" { if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
// Windows arm64 uses the same calling convention as macOS and Linux // Windows arm64 uses the same calling convention as macOS and Linux
addStack = func(x uintptr) { addStack = func(x uintptr) {
sysargs[numOfIntegerRegisters()+numStack] = x stack[numStack] = x
numStack++ numStack++
} }
addInt = func(x uintptr) { addInt = func(x uintptr) {
@@ -248,13 +255,12 @@ func RegisterFunc(fptr any, cfn uintptr) {
addFloat = addStack addFloat = addStack
} }
var keepAlive []any var keepAlive []interface{}
defer func() { defer func() {
runtime.KeepAlive(keepAlive) runtime.KeepAlive(keepAlive)
runtime.KeepAlive(args) runtime.KeepAlive(args)
}() }()
var syscall syscall15Args
var arm64_r8 uintptr
if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct { if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
outType := ty.Out(0) outType := ty.Out(0)
if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize { if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize {
@@ -266,63 +272,53 @@ func RegisterFunc(fptr any, cfn uintptr) {
if !isAllFloats || numFields > 4 { if !isAllFloats || numFields > 4 {
val := reflect.New(outType) val := reflect.New(outType)
keepAlive = append(keepAlive, val) keepAlive = append(keepAlive, val)
arm64_r8 = val.Pointer() syscall.arm64_r8 = val.Pointer()
} }
} }
} }
for i, v := range args { for _, v := range args {
if variadic, ok := args[i].Interface().([]any); ok { switch v.Kind() {
if i != len(args)-1 { case reflect.String:
panic("purego: can only expand last parameter") 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 _, x := range variadic { case reflect.Float32:
keepAlive = addValue(reflect.ValueOf(x), keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack) addFloat(uintptr(math.Float32bits(float32(v.Float()))))
} case reflect.Float64:
continue 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())
} }
if runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" &&
(numInts >= numOfIntegerRegisters() || numFloats >= numOfFloatRegisters) && v.Kind() != reflect.Struct { // hit the stack
fields := make([]reflect.StructField, len(args[i:]))
for j, val := range args[i:] {
if val.Kind() == reflect.String {
ptr := strings.CString(v.String())
keepAlive = append(keepAlive, ptr)
val = reflect.ValueOf(ptr)
args[i+j] = val
}
fields[j] = reflect.StructField{
Name: "X" + strconv.Itoa(j),
Type: val.Type(),
}
}
structType := reflect.StructOf(fields)
structInstance := reflect.New(structType).Elem()
for j, val := range args[i:] {
structInstance.Field(j).Set(val)
}
placeRegisters(structInstance, addFloat, addInt)
break
}
keepAlive = addValue(v, keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
} }
syscall := thePool.Get().(*syscall15Args)
defer thePool.Put(syscall)
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" { if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
// Use the normal arm64 calling convention even on Windows // Use the normal arm64 calling convention even on Windows
*syscall = syscall15Args{ syscall = syscall15Args{
cfn, cfn,
sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5], 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[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
sysargs[12], sysargs[13], sysargs[14], sysargs[12], sysargs[13], sysargs[14],
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7], floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7],
arm64_r8, syscall.arm64_r8,
} }
runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall)) runtime_cgocall(syscall15XABI0, unsafe.Pointer(&syscall))
} else { } else {
*syscall = syscall15Args{}
// This is a fallback for Windows amd64, 386, and arm. Note this may not support floats // 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], 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], sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
@@ -361,54 +357,15 @@ func RegisterFunc(fptr any, cfn uintptr) {
// On 32bit platforms syscall.r2 is the upper part of a 64bit return. // On 32bit platforms syscall.r2 is the upper part of a 64bit return.
v.SetFloat(math.Float64frombits(uint64(syscall.f1))) v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
case reflect.Struct: case reflect.Struct:
v = getStruct(outType, *syscall) v = getStruct(outType, syscall)
default: default:
panic("purego: unsupported return kind: " + outType.Kind().String()) panic("purego: unsupported return kind: " + outType.Kind().String())
} }
if len(args) > 0 { return []reflect.Value{v}
// reuse args slice instead of allocating one when possible
args[0] = v
return args[:1]
} else {
return []reflect.Value{v}
}
}) })
fn.Set(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 {
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:
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())
}
return keepAlive
}
// maxRegAllocStructSize is the biggest a struct can be while still fitting in registers. // 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 // 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. // the function as the first parameter on amd64 or in R8 on arm64.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || netbsd || windows //go:build darwin || freebsd || linux || windows
package purego package purego

View File

@@ -1,12 +1,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2024 The Ebitengine Authors // SPDX-FileCopyrightText: 2024 The Ebitengine Authors
//go:build freebsd || linux || netbsd //go:build freebsd || linux
package cgo package cgo
/* /*
#cgo !netbsd LDFLAGS: -ldl #cgo LDFLAGS: -ldl
#include <dlfcn.h> #include <dlfcn.h>
#include <stdlib.h> #include <stdlib.h>

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build freebsd || (linux && !(arm64 || amd64)) || netbsd //go:build freebsd || (linux && !(arm64 || amd64))
package cgo package cgo
@@ -9,7 +9,7 @@ package cgo
// because Cgo and assembly files can't be in the same package. // because Cgo and assembly files can't be in the same package.
/* /*
#cgo !netbsd LDFLAGS: -ldl #cgo LDFLAGS: -ldl
#include <stdint.h> #include <stdint.h>
#include <dlfcn.h> #include <dlfcn.h>

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
package fakecgo package fakecgo

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
// Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go. // Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go.
// This allows code that calls into C to function properly when CGO_ENABLED=0. // This allows code that calls into C to function properly when CGO_ENABLED=0.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
package fakecgo package fakecgo

View File

@@ -1,106 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !cgo && (amd64 || arm64)
package fakecgo
import "unsafe"
//go:nosplit
func _cgo_sys_thread_start(ts *ThreadStart) {
var attr pthread_attr_t
var ign, oset sigset_t
var p pthread_t
var size size_t
var err int
// fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
sigfillset(&ign)
pthread_sigmask(SIG_SETMASK, &ign, &oset)
pthread_attr_init(&attr)
pthread_attr_getstacksize(&attr, &size)
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
ts.g.stackhi = uintptr(size)
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
pthread_sigmask(SIG_SETMASK, &oset, nil)
if err != 0 {
print("fakecgo: pthread_create failed: ")
println(err)
abort()
}
}
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
//
//go:linkname x_threadentry_trampoline threadentry_trampoline
var x_threadentry_trampoline byte
var threadentry_trampolineABI0 = &x_threadentry_trampoline
//go:nosplit
func threadentry(v unsafe.Pointer) unsafe.Pointer {
var ss stack_t
ts := *(*ThreadStart)(v)
free(v)
// On NetBSD, a new thread inherits the signal stack of the
// creating thread. That confuses minit, so we remove that
// signal stack here before calling the regular mstart. It's
// a bit baroque to remove a signal stack here only to add one
// in minit, but it's a simple change that keeps NetBSD
// working like other OS's. At this point all signals are
// blocked, so there is no race.
ss.ss_flags = SS_DISABLE
sigaltstack(&ss, nil)
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
// faking funcs in go is a bit a... involved - but the following works :)
fn := uintptr(unsafe.Pointer(&ts.fn))
(*(*func())(unsafe.Pointer(&fn)))()
return nil
}
// here we will store a pointer to the provided setg func
var setg_func uintptr
//go:nosplit
func x_cgo_init(g *G, setg uintptr) {
var size size_t
var attr *pthread_attr_t
/* The memory sanitizer distributed with versions of clang
before 3.8 has a bug: if you call mmap before malloc, mmap
may return an address that is later overwritten by the msan
library. Avoid this problem by forcing a call to malloc
here, before we ever call malloc.
This is only required for the memory sanitizer, so it's
unfortunate that we always run it. It should be possible
to remove this when we no longer care about versions of
clang before 3.8. The test for this is
misc/cgo/testsanitizers.
GCC works hard to eliminate a seemingly unnecessary call to
malloc, so we actually use the memory we allocate. */
setg_func = setg
attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
if attr == nil {
println("fakecgo: malloc failed")
abort()
}
pthread_attr_init(attr)
pthread_attr_getstacksize(attr, &size)
// runtime/cgo uses __builtin_frame_address(0) instead of `uintptr(unsafe.Pointer(&size))`
// but this should be OK since we are taking the address of the first variable in this function.
g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
pthread_attr_destroy(attr)
free(unsafe.Pointer(attr))
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
package fakecgo package fakecgo

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
package fakecgo package fakecgo

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
// The runtime package contains an uninitialized definition // The runtime package contains an uninitialized definition
// for runtime·iscgo. Override it to tell the runtime we're here. // for runtime·iscgo. Override it to tell the runtime we're here.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
package fakecgo package fakecgo

View File

@@ -20,7 +20,3 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t{sig: 0x3CB0B1BB} PTHREAD_COND_INITIALIZER = pthread_cond_t{sig: 0x3CB0B1BB}
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{sig: 0x32AAABA7} PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{sig: 0x32AAABA7}
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -14,7 +14,3 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t(0) PTHREAD_COND_INITIALIZER = pthread_cond_t(0)
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0) PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -14,7 +14,3 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t{} PTHREAD_COND_INITIALIZER = pthread_cond_t{}
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{} PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{}
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -1,26 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
//go:build !cgo
package fakecgo
type (
pthread_cond_t uintptr
pthread_mutex_t uintptr
)
var (
PTHREAD_COND_INITIALIZER = pthread_cond_t(0)
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
)
// Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/compat/linux/arch/m68k/linux_signal.h#L133
type stack_t struct {
ss_sp uintptr
ss_flags int32
ss_size uintptr
}
// Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L261
const SS_DISABLE = 0x004

View File

@@ -1,23 +0,0 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build netbsd
package fakecgo
import _ "unsafe" // for go:linkname
// Supply environ and __progname, because we don't
// link against the standard NetBSD crt0.o and the
// libc dynamic library needs them.
//go:linkname _environ environ
//go:linkname _progname __progname
//go:linkname ___ps_strings __ps_strings
var (
_environ uintptr
_progname uintptr
___ps_strings uintptr
)

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
package fakecgo package fakecgo

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
package fakecgo package fakecgo
@@ -55,11 +55,6 @@ func abort() {
call5(abortABI0, 0, 0, 0, 0, 0) call5(abortABI0, 0, 0, 0, 0, 0)
} }
//go:nosplit
func sigaltstack(ss *stack_t, old_ss *stack_t) int32 {
return int32(call5(sigaltstackABI0, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(old_ss)), 0, 0, 0))
}
//go:nosplit //go:nosplit
func pthread_attr_init(attr *pthread_attr_t) int32 { func pthread_attr_init(attr *pthread_attr_t) int32 {
return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0)) return int32(call5(pthread_attr_initABI0, uintptr(unsafe.Pointer(attr)), 0, 0, 0, 0))
@@ -153,10 +148,6 @@ var nanosleepABI0 = uintptr(unsafe.Pointer(&_nanosleep))
var _abort uint8 var _abort uint8
var abortABI0 = uintptr(unsafe.Pointer(&_abort)) var abortABI0 = uintptr(unsafe.Pointer(&_abort))
//go:linkname _sigaltstack _sigaltstack
var _sigaltstack uint8
var sigaltstackABI0 = uintptr(unsafe.Pointer(&_sigaltstack))
//go:linkname _pthread_attr_init _pthread_attr_init //go:linkname _pthread_attr_init _pthread_attr_init
var _pthread_attr_init uint8 var _pthread_attr_init uint8
var pthread_attr_initABI0 = uintptr(unsafe.Pointer(&_pthread_attr_init)) var pthread_attr_initABI0 = uintptr(unsafe.Pointer(&_pthread_attr_init))

View File

@@ -14,7 +14,6 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_sigfillset sigfillset "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_nanosleep nanosleep "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_nanosleep nanosleep "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_abort abort "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_abort abort "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_create pthread_create "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_create pthread_create "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "/usr/lib/libSystem.B.dylib"

View File

@@ -14,7 +14,6 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.7" //go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.7"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.7" //go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.7"
//go:cgo_import_dynamic purego_abort abort "libc.so.7" //go:cgo_import_dynamic purego_abort abort "libc.so.7"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so.7"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so" //go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"

View File

@@ -14,7 +14,6 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.6" //go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.6"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.6" //go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.6"
//go:cgo_import_dynamic purego_abort abort "libc.so.6" //go:cgo_import_dynamic purego_abort abort "libc.so.6"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so.6"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so.0"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so.0"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so.0"

View File

@@ -1,30 +0,0 @@
// Code generated by 'go generate' with gen.go. DO NOT EDIT.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo
package fakecgo
//go:cgo_import_dynamic purego_malloc malloc "libc.so"
//go:cgo_import_dynamic purego_free free "libc.so"
//go:cgo_import_dynamic purego_setenv setenv "libc.so"
//go:cgo_import_dynamic purego_unsetenv unsetenv "libc.so"
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so"
//go:cgo_import_dynamic purego_abort abort "libc.so"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"
//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "libpthread.so"
//go:cgo_import_dynamic purego_pthread_self pthread_self "libpthread.so"
//go:cgo_import_dynamic purego_pthread_get_stacksize_np pthread_get_stacksize_np "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_setstacksize pthread_attr_setstacksize "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "libpthread.so"
//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "libpthread.so"
//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "libpthread.so"
//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "libpthread.so"
//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "libpthread.so"

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
#include "textflag.h" #include "textflag.h"
@@ -37,10 +37,6 @@ TEXT _abort(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_abort(SB) JMP purego_abort(SB)
RET RET
TEXT _sigaltstack(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_sigaltstack(SB)
RET
TEXT _pthread_attr_init(SB), NOSPLIT|NOFRAME, $0-0 TEXT _pthread_attr_init(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_pthread_attr_init(SB) JMP purego_pthread_attr_init(SB)
RET RET

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux || netbsd) //go:build !cgo && (darwin || freebsd || linux)
package purego package purego

View File

@@ -85,7 +85,7 @@ const (
_MEMORY = 0b1111 _MEMORY = 0b1111
) )
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} {
if v.Type().Size() == 0 { if v.Type().Size() == 0 {
return keepAlive return keepAlive
} }
@@ -120,7 +120,7 @@ func postMerger(t reflect.Type) (passInMemory bool) {
if t.Size() <= 2*8 { if t.Size() <= 2*8 {
return false return false
} }
return true // Go does not have an SSE/SSEUP type so this is always true return true // Go does not have an SSE/SEEUP type so this is always true
} }
func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) { func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) {
@@ -258,7 +258,3 @@ func placeStack(v reflect.Value, addStack func(uintptr)) {
} }
} }
} }
func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
panic("purego: not needed on amd64")
}

View File

@@ -65,7 +65,7 @@ const (
_INT = 0b11 _INT = 0b11
) )
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} {
if v.Type().Size() == 0 { if v.Type().Size() == 0 {
return keepAlive return keepAlive
} }
@@ -73,8 +73,8 @@ func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFl
if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 { if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 {
// if this doesn't fit entirely in registers then // if this doesn't fit entirely in registers then
// each element goes onto the stack // each element goes onto the stack
if hfa && *numFloats+v.NumField() > numOfFloatRegisters { if hfa && *numFloats+v.NumField() > numOfFloats {
*numFloats = numOfFloatRegisters *numFloats = numOfFloats
} else if hva && *numInts+v.NumField() > numOfIntegerRegisters() { } else if hva && *numInts+v.NumField() > numOfIntegerRegisters() {
*numInts = numOfIntegerRegisters() *numInts = numOfIntegerRegisters()
} }
@@ -107,8 +107,6 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
} else { } else {
f = v.Index(k) f = v.Index(k)
} }
align := byte(f.Type().Align()*8 - 1)
shift = (shift + align) &^ align
if shift >= 64 { if shift >= 64 {
shift = 0 shift = 0
flushed = true flushed = true
@@ -139,11 +137,10 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
val |= f.Uint() << shift val |= f.Uint() << shift
shift += 32 shift += 32
class |= _INT class |= _INT
case reflect.Uint64, reflect.Uint, reflect.Uintptr: case reflect.Uint64:
addInt(uintptr(f.Uint())) addInt(uintptr(f.Uint()))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Int8: case reflect.Int8:
val |= uint64(f.Int()&0xFF) << shift val |= uint64(f.Int()&0xFF) << shift
shift += 8 shift += 8
@@ -156,11 +153,10 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
val |= uint64(f.Int()&0xFFFF_FFFF) << shift val |= uint64(f.Int()&0xFFFF_FFFF) << shift
shift += 32 shift += 32
class |= _INT class |= _INT
case reflect.Int64, reflect.Int: case reflect.Int64:
addInt(uintptr(f.Int())) addInt(uintptr(f.Int()))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Float32: case reflect.Float32:
if class == _FLOAT { if class == _FLOAT {
addFloat(uintptr(val)) addFloat(uintptr(val))
@@ -174,12 +170,6 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
addFloat(uintptr(math.Float64bits(float64(f.Float())))) addFloat(uintptr(math.Float64bits(float64(f.Float()))))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Ptr:
addInt(f.Pointer())
shift = 0
flushed = true
class = _NO_CLASS
case reflect.Array: case reflect.Array:
place(f) place(f)
default: default:
@@ -197,7 +187,7 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
} }
} }
func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any { func placeStack(v reflect.Value, keepAlive []interface{}, addInt func(uintptr)) []interface{} {
// Struct is too big to be placed in registers. // Struct is too big to be placed in registers.
// Copy to heap and place the pointer in register // Copy to heap and place the pointer in register
ptrStruct := reflect.New(v.Type()) ptrStruct := reflect.New(v.Type())

View File

@@ -7,14 +7,10 @@ package purego
import "reflect" import "reflect"
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} {
panic("purego: struct arguments are not supported") panic("purego: struct arguments are not supported")
} }
func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) { func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
panic("purego: struct returns are not supported") panic("purego: struct returns are not supported")
} }
func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
panic("purego: not needed on other platforms")
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || netbsd //go:build darwin || freebsd || linux
#include "textflag.h" #include "textflag.h"
#include "abi_amd64.h" #include "abi_amd64.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || netbsd || windows //go:build darwin || freebsd || linux || windows
#include "textflag.h" #include "textflag.h"
#include "go_asm.h" #include "go_asm.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 The Ebitengine Authors // SPDX-FileCopyrightText: 2023 The Ebitengine Authors
//go:build darwin || freebsd || linux || netbsd //go:build darwin || freebsd || linux
#include "textflag.h" #include "textflag.h"
#include "go_asm.h" #include "go_asm.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || netbsd || windows //go:build darwin || freebsd || linux || windows
package purego package purego
@@ -13,8 +13,8 @@ package purego
type CDecl struct{} type CDecl struct{}
const ( const (
maxArgs = 15 maxArgs = 15
numOfFloatRegisters = 8 // arm64 and amd64 both have 8 float registers numOfFloats = 8 // arm64 and amd64 both have 8 float registers
) )
type syscall15Args struct { type syscall15Args struct {
@@ -27,9 +27,6 @@ type syscall15Args struct {
// There is an internal maximum number of arguments that SyscallN can take. It panics // There is an internal maximum number of arguments that SyscallN can take. It panics
// when the maximum is exceeded. It returns the result and the libc error code if there is one. // when the maximum is exceeded. It returns the result and the libc error code if there is one.
// //
// In order to call this function properly make sure to follow all the rules specified in [unsafe.Pointer]
// especially point 4.
//
// NOTE: SyscallN does not properly call functions that have both integer and float parameters. // NOTE: SyscallN does not properly call functions that have both integer and float parameters.
// See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607 // See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607
// for an explanation of why that is. // for an explanation of why that is.

View File

@@ -16,6 +16,6 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
return cgo.Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) return cgo.Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
} }
func NewCallback(_ any) uintptr { func NewCallback(_ interface{}) uintptr {
panic("purego: NewCallback on Linux is only supported on amd64/arm64") panic("purego: NewCallback on Linux is only supported on amd64/arm64")
} }

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || (linux && (amd64 || arm64)) || netbsd //go:build darwin || freebsd || (linux && (amd64 || arm64))
package purego package purego
@@ -31,7 +31,7 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
// of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory allocated // of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory allocated
// for these callbacks is never released. At least 2000 callbacks can always be created. Although this function // for these callbacks is never released. At least 2000 callbacks can always be created. Although this function
// provides similar functionality to windows.NewCallback it is distinct. // provides similar functionality to windows.NewCallback it is distinct.
func NewCallback(fn any) uintptr { func NewCallback(fn interface{}) uintptr {
ty := reflect.TypeOf(fn) ty := reflect.TypeOf(fn)
for i := 0; i < ty.NumIn(); i++ { for i := 0; i < ty.NumIn(); i++ {
in := ty.In(i) in := ty.In(i)
@@ -71,7 +71,7 @@ type callbackArgs struct {
result uintptr result uintptr
} }
func compileCallback(fn any) uintptr { func compileCallback(fn interface{}) uintptr {
val := reflect.ValueOf(fn) val := reflect.ValueOf(fn)
if val.Kind() != reflect.Func { if val.Kind() != reflect.Func {
panic("purego: the type must be a function but was not") panic("purego: the type must be a function but was not")
@@ -146,12 +146,12 @@ func callbackWrap(a *callbackArgs) {
var intsN int // intsN represents the number of integer arguments processed var intsN int // intsN represents the number of integer arguments processed
// stack points to the index into frame of the current stack element. // stack points to the index into frame of the current stack element.
// The stack begins after the float and integer registers. // The stack begins after the float and integer registers.
stack := numOfIntegerRegisters() + numOfFloatRegisters stack := numOfIntegerRegisters() + numOfFloats
for i := range args { for i := range args {
var pos int var pos int
switch fnType.In(i).Kind() { switch fnType.In(i).Kind() {
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
if floatsN >= numOfFloatRegisters { if floatsN >= numOfFloats {
pos = stack pos = stack
stack++ stack++
} else { } else {
@@ -169,7 +169,7 @@ func callbackWrap(a *callbackArgs) {
stack++ stack++
} else { } else {
// the integers begin after the floats in frame // the integers begin after the floats in frame
pos = intsN + numOfFloatRegisters pos = intsN + numOfFloats
} }
intsN++ intsN++
} }

View File

@@ -22,7 +22,7 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
// allocated for these callbacks is never released. Between NewCallback and NewCallbackCDecl, at least 1024 // allocated for these callbacks is never released. Between NewCallback and NewCallbackCDecl, at least 1024
// callbacks can always be created. Although this function is similiar to the darwin version it may act // callbacks can always be created. Although this function is similiar to the darwin version it may act
// differently. // differently.
func NewCallback(fn any) uintptr { func NewCallback(fn interface{}) uintptr {
isCDecl := false isCDecl := false
ty := reflect.TypeOf(fn) ty := reflect.TypeOf(fn)
for i := 0; i < ty.NumIn(); i++ { for i := 0; i < ty.NumIn(); i++ {

View File

@@ -1,6 +1,6 @@
// Code generated by wincallback.go using 'go generate'. DO NOT EDIT. // Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
//go:build darwin || freebsd || linux || netbsd //go:build darwin || freebsd || linux
// runtime·callbackasm is called by external code to // runtime·callbackasm is called by external code to
// execute Go implemented callback function. It is not // execute Go implemented callback function. It is not

View File

@@ -1,6 +1,6 @@
// Code generated by wincallback.go using 'go generate'. DO NOT EDIT. // Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
//go:build darwin || freebsd || linux || netbsd //go:build darwin || freebsd || linux
// External code calls into callbackasm at an offset corresponding // External code calls into callbackasm at an offset corresponding
// to the callback index. Callbackasm is a table of MOV and B instructions. // to the callback index. Callbackasm is a table of MOV and B instructions.

2
vendor/modules.txt vendored
View File

@@ -673,7 +673,7 @@ github.com/dustin/go-humanize
# github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 # github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4
## explicit; go 1.20 ## explicit; go 1.20
github.com/eapache/queue/v2 github.com/eapache/queue/v2
# github.com/ebitengine/purego v0.9.0-alpha.3.0.20250507171635-5047c08daa38 # github.com/ebitengine/purego v0.8.3
## explicit; go 1.18 ## explicit; go 1.18
github.com/ebitengine/purego github.com/ebitengine/purego
github.com/ebitengine/purego/internal/cgo github.com/ebitengine/purego/internal/cgo