Skip to content

Commit

Permalink
purego: decrease number of allocs
Browse files Browse the repository at this point in the history
This rewrites part of the RegisterFunc to have less code escape to the heap. Running the benchmark inside ebitengine#121 shows a speed increase and alloc decrease.

goos: darwin
goarch: arm64
pkg: github.com/ebitengine/purego
BenchmarkCStringC
BenchmarkCStringC-10    	 2294838	       500.3 ns/op	     472 B/op	       8 allocs/op
PASS
  • Loading branch information
TotallyGamerJet committed Apr 10, 2023
1 parent c3a82d7 commit 4a862a7
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 4 deletions.
11 changes: 7 additions & 4 deletions func.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
}
}
var sysargs [maxArgs]uintptr
var stack = sysargs[numOfIntegerRegisters():]
stack := sysargs[numOfIntegerRegisters():]
var floats [numOfFloats]uintptr
var numInts int
var numFloats int
Expand All @@ -147,6 +147,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
var keepAlive []interface{}
defer func() {
runtime.KeepAlive(keepAlive)
runtime.KeepAlive(args)
}()
for _, v := range args {
switch v.Kind() {
Expand All @@ -159,7 +160,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
addInt(uintptr(v.Int()))
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
keepAlive = append(keepAlive, v.Pointer())
// 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()))
Expand Down Expand Up @@ -192,7 +193,8 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
cfn,
sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5], sysargs[6], sysargs[7], sysargs[8],
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7],
0, 0, 0}
0, 0, 0,
}
runtime_cgocall(syscall9XABI0, unsafe.Pointer(&syscall))
r1, r2 := syscall.r1, syscall.r2

Expand All @@ -212,7 +214,8 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
// We take the address and then dereference it to trick go vet from creating a possible miss-use of unsafe.Pointer
v.SetPointer(*(*unsafe.Pointer)(unsafe.Pointer(&r1)))
case reflect.Ptr:
v = reflect.NewAt(outType, unsafe.Pointer(&r1)).Elem()
// It is safe to have the address of r1 not escape because it is immediately dereferenced with .Elem()
v = reflect.NewAt(outType, runtime_noescape(unsafe.Pointer(&r1))).Elem()
case reflect.Func:
// wrap this C function in a nicely typed Go function
v = reflect.New(outType)
Expand Down
4 changes: 4 additions & 0 deletions go_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ import (

//go:linkname runtime_cgocall runtime.cgocall
func runtime_cgocall(fn uintptr, arg unsafe.Pointer) int32 // from runtime/sys_libc.go

//go:linkname runtime_noescape runtime.noescape
//go:noescape
func runtime_noescape(p unsafe.Pointer) unsafe.Pointer

0 comments on commit 4a862a7

Please sign in to comment.