diff --git a/callback_test.go b/callback_test.go index e4967c31..28bcf1da 100644 --- a/callback_test.go +++ b/callback_test.go @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 The Ebitengine Authors -//go:build darwin +//go:build darwin || linux package purego_test @@ -48,82 +48,3 @@ func TestCallGoFromSharedLib(t *testing.T) { } } } - -func TestNewCallbackFloat64(t *testing.T) { - // This tests the maximum number of arguments a function to NewCallback can take - const ( - expectCbTotal = -3 - expectedCbTotalF = float64(36) - ) - var cbTotal int - var cbTotalF float64 - imp := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9 int, - f1, f2, f3, f4, f5, f6, f7, f8 float64) { - cbTotal = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 - cbTotalF = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 - }) - var fn func(a1, a2, a3, a4, a5, a6, a7, a8, a9 int, - f1, f2, f3, f4, f5, f6, f7, f8 float64) - purego.RegisterFunc(&fn, imp) - fn(1, 2, -3, 4, -5, 6, -7, 8, -9, - 1, 2, 3, 4, 5, 6, 7, 8) - - if cbTotal != expectCbTotal { - t.Errorf("cbTotal not correct got %d but wanted %d", cbTotal, expectCbTotal) - } - if cbTotalF != expectedCbTotalF { - t.Errorf("cbTotalF not correct got %f but wanted %f", cbTotalF, expectedCbTotalF) - } -} - -func TestNewCallbackFloat32(t *testing.T) { - // This tests the maximum number of float32 arguments a function to NewCallback can take - const ( - expectCbTotal = 6 - expectedCbTotalF = float32(45) - ) - var cbTotal int - var cbTotalF float32 - imp := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8 int, - f1, f2, f3, f4, f5, f6, f7, f8, f9 float32) { - cbTotal = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 - cbTotalF = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 - }) - var fn func(a1, a2, a3, a4, a5, a6, a7, a8 int, - f1, f2, f3, f4, f5, f6, f7, f8, f9 float32) - purego.RegisterFunc(&fn, imp) - fn(1, 2, -3, 4, -5, 6, -7, 8, - 1, 2, 3, 4, 5, 6, 7, 8, 9) - - if cbTotal != expectCbTotal { - t.Errorf("cbTotal not correct got %d but wanted %d", cbTotal, expectCbTotal) - } - if cbTotalF != expectedCbTotalF { - t.Errorf("cbTotalF not correct got %f but wanted %f", cbTotalF, expectedCbTotalF) - } -} - -func TestNewCallbackFloat32AndFloat64(t *testing.T) { - // This tests that calling a function with a mix of float32 and float64 arguments works - const ( - expectedCbTotalF32 = float32(30) - expectedCbTotalF64 = float64(15) - ) - var cbTotalF32 float32 - var cbTotalF64 float64 - imp := purego.NewCallback(func(f1, f2, f3 float32, f4, f5, f6 float64, f7, f8, f9 float32) { - cbTotalF32 = f1 + f2 + f3 + f7 + f8 + f9 - cbTotalF64 = f4 + f5 + f6 - - }) - var fn func(f1, f2, f3 float32, f4, f5, f6 float64, f7, f8, f9 float32) - purego.RegisterFunc(&fn, imp) - fn(1, 2, 3, 4, 5, 6, 7, 8, 9) - - if cbTotalF32 != expectedCbTotalF32 { - t.Errorf("cbTotalF32 not correct got %f but wanted %f", cbTotalF32, expectedCbTotalF32) - } - if cbTotalF64 != expectedCbTotalF64 { - t.Errorf("cbTotalF64 not correct got %f but wanted %f", cbTotalF64, expectedCbTotalF64) - } -} diff --git a/func_test.go b/func_test.go index b9245651..11dd07f8 100644 --- a/func_test.go +++ b/func_test.go @@ -47,12 +47,6 @@ func TestRegisterFunc(t *testing.T) { } func ExampleNewCallback() { - if runtime.GOOS == "linux" { - // TODO: enable once callbacks are working properly on Linux - fmt.Println("1 2 3 4 5 6 7 8 9\n45") - return - } - cb := purego.NewCallback(func(a1, a2, a3, a4, a5, a6, a7, a8, a9 int) int { fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9) return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 @@ -69,11 +63,6 @@ func ExampleNewCallback() { } func Test_qsort(t *testing.T) { - if runtime.GOOS == "linux" { - // TODO: enable once callbacks are working properly on Linux - t.Skip("callbacks are not supported on Linux") - } - library, err := getSystemLibrary() if err != nil { t.Errorf("couldn't get system library: %s", err) diff --git a/sys_amd64.s b/sys_amd64.s index 6daa298d..0afa3865 100644 --- a/sys_amd64.s +++ b/sys_amd64.s @@ -72,72 +72,3 @@ TEXT syscall9X(SB), NOSPLIT|NOFRAME, $0 MOVQ BP, SP POPQ BP RET - -TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0 - // remove return address from stack, we are not returning to callbackasm, but to its caller. - MOVQ 0(SP), AX - ADDQ $8, SP - - MOVQ 0(SP), R10 // get the return SP so that we can align register args with stack args - - // make space for first six int and 8 float arguments below the frame - ADJSP $14*8, SP - MOVSD X0, (1*8)(SP) - MOVSD X1, (2*8)(SP) - MOVSD X2, (3*8)(SP) - MOVSD X3, (4*8)(SP) - MOVSD X4, (5*8)(SP) - MOVSD X5, (6*8)(SP) - MOVSD X6, (7*8)(SP) - MOVSD X7, (8*8)(SP) - MOVQ DI, (9*8)(SP) - MOVQ SI, (10*8)(SP) - MOVQ DX, (11*8)(SP) - MOVQ CX, (12*8)(SP) - MOVQ R8, (13*8)(SP) - MOVQ R9, (14*8)(SP) - LEAQ 8(SP), R8 // R8 = address of args vector - - MOVQ R10, 0(SP) // push the stack pointer below registers - - // determine index into runtime·cbs table - MOVQ $callbackasm(SB), DX - SUBQ DX, AX - MOVQ $0, DX - MOVQ $5, CX // divide by 5 because each call instruction in ·callbacks is 5 bytes long - DIVL CX - SUBQ $1, AX // subtract 1 because return PC is to the next slot - - // Switch from the host ABI to the Go ABI. - PUSH_REGS_HOST_TO_ABI0() - - // Create a struct callbackArgs on our stack to be passed as - // the "frame" to cgocallback and on to callbackWrap. - // $24 to make enough room for the arguments to runtime.cgocallback - SUBQ $(24+callbackArgs__size), SP - MOVQ AX, (24+callbackArgs_index)(SP) // callback index - MOVQ R8, (24+callbackArgs_args)(SP) // address of args vector - MOVQ $0, (24+callbackArgs_result)(SP) // result - LEAQ 24(SP), AX // take the address of callbackArgs - - // Call cgocallback, which will call callbackWrap(frame). - MOVQ ·callbackWrap_call(SB), DI // Get the ABIInternal function pointer - MOVQ (DI), DI // without by using a closure. - MOVQ AX, SI // frame (address of callbackArgs) - MOVQ $0, CX // context - - CALL crosscall2(SB) // runtime.cgocallback(fn, frame, ctxt uintptr) - - // Get callback result. - MOVQ (24+callbackArgs_result)(SP), AX - ADDQ $(24+callbackArgs__size), SP // remove callbackArgs struct - - POP_REGS_HOST_TO_ABI0() - - MOVQ 0(SP), R10 // get the SP back - - ADJSP $-14*8, SP // remove arguments - - MOVQ R10, 0(SP) - - RET diff --git a/sys_unix_arm64.s b/sys_unix_arm64.s index f460482e..43471e84 100644 --- a/sys_unix_arm64.s +++ b/sys_unix_arm64.s @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 The Ebitengine Authors -//go:build darwin || freebsd || (!cgo && linux) +//go:build darwin || freebsd || linux #include "textflag.h" #include "go_asm.h" diff --git a/syscall_cgo_linux.go b/syscall_cgo_linux.go index 59c9a00b..525866fe 100644 --- a/syscall_cgo_linux.go +++ b/syscall_cgo_linux.go @@ -24,7 +24,3 @@ type syscall9Args struct { func syscall_syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { return cgo.Syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9) } - -func NewCallback(_ interface{}) uintptr { - panic("purego: NewCallback not supported") -} diff --git a/syscall_other.go b/syscall_other.go new file mode 100644 index 00000000..269e6719 --- /dev/null +++ b/syscall_other.go @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 The Ebitengine Authors + +//go:build darwin || freebsd || (!cgo && linux && (amd64 || arm64)) + +package purego + +import "unsafe" + +var syscall9XABI0 uintptr + +type syscall9Args struct { + fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr + f1, f2, f3, f4, f5, f6, f7, f8 uintptr + r1, r2, err uintptr +} + +//go:nosplit +func syscall_syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { + args := syscall9Args{ + fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a1, a2, a3, a4, a5, a6, a7, a8, + r1, r2, err, + } + runtime_cgocall(syscall9XABI0, unsafe.Pointer(&args)) + return args.r1, args.r2, args.err +} + diff --git a/syscall_sysv.go b/syscall_sysv.go index 2d295cb0..483eaa14 100644 --- a/syscall_sysv.go +++ b/syscall_sysv.go @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2022 The Ebitengine Authors -//go:build darwin || freebsd || (!cgo && linux && (amd64 || arm64)) +//go:build darwin || freebsd || (linux && (amd64 || arm64)) package purego @@ -12,25 +12,6 @@ import ( "unsafe" ) -var syscall9XABI0 uintptr - -type syscall9Args struct { - fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr - f1, f2, f3, f4, f5, f6, f7, f8 uintptr - r1, r2, err uintptr -} - -//go:nosplit -func syscall_syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { - args := syscall9Args{ - fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, - a1, a2, a3, a4, a5, a6, a7, a8, - r1, r2, err, - } - runtime_cgocall(syscall9XABI0, unsafe.Pointer(&args)) - return args.r1, args.r2, args.err -} - // NewCallback converts a Go function to a function pointer conforming to the C calling convention. // This is useful when interoperating with C code requiring callbacks. The argument is expected to be a // function with zero or one uintptr-sized result. The function must not have arguments with size larger than the size @@ -40,9 +21,6 @@ func syscall_syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, // // NOTE: Linux is currently not supported and will panic if called. func NewCallback(fn interface{}) uintptr { - if runtime.GOOS == "linux" { - panic("purego: NewCallback not supported") - } return compileCallback(fn) } diff --git a/zcallback_amd64.s b/zcallback_amd64.s index d2c75082..6a778bfc 100644 --- a/zcallback_amd64.s +++ b/zcallback_amd64.s @@ -1,6 +1,6 @@ // Code generated by wincallback.go using 'go generate'. DO NOT EDIT. -//go:build darwin || freebsd || (!cgo && linux) +//go:build darwin || freebsd || linux // runtime·callbackasm is called by external code to // execute Go implemented callback function. It is not diff --git a/zcallback_arm64.s b/zcallback_arm64.s index fc3683d5..c079b803 100644 --- a/zcallback_arm64.s +++ b/zcallback_arm64.s @@ -1,6 +1,6 @@ // Code generated by wincallback.go using 'go generate'. DO NOT EDIT. -//go:build darwin || freebsd || (!cgo && linux) +//go:build darwin || freebsd || linux // External code calls into callbackasm at an offset corresponding // to the callback index. Callbackasm is a table of MOV and B instructions.