detached 3aa994f

fix callbacks on go 1.15 (#34)

Go 1.16 significantly changed the way Go calls into C code in  golang/go#30c1887. Purego assumed versioned 1.16 method. This commit expands support back down to 1.15.

Closes #27
commit
3aa994fcbff60ba81dc1120e4fd38dd6d8546c24
author
TotallyGamerJet · · 2022-09-07 02:42 UTC
committer
GitHub · · 2022-09-07 02:42 UTC
parent
46cb710
signature
GPG Unverified4AEE18F83AFDEB23 The key is unknown
5 files · +53 -24
M .github/workflows/test.yml +0 -1
@@ -72,6 +72,5 @@ jobs:
7272 go build -v .
7373
7474 - name: go test
75- if: ${{ !startsWith(matrix.go, '1.15.') }} # TODO: Remove this condition after #27 is fixed.
7675 run: |
7776 go test -tags=example ${{ !startsWith(matrix.go, '1.15.') && !startsWith(matrix.go, '1.16.') && '-shuffle=on' || '' }} -v -count=10 ./...
@@ -72,6 +72,5 @@ jobs:
72 go build -v .72 go build -v .
73 73
74 - name: go test74 - name: go test
75- if: ${{ !startsWith(matrix.go, '1.15.') }} # TODO: Remove this condition after #27 is fixed.
76 run: |75 run: |
77 go test -tags=example ${{ !startsWith(matrix.go, '1.15.') && !startsWith(matrix.go, '1.16.') && '-shuffle=on' || '' }} -v -count=10 ./...76 go test -tags=example ${{ !startsWith(matrix.go, '1.15.') && !startsWith(matrix.go, '1.16.') && '-shuffle=on' || '' }} -v -count=10 ./...
A callback_go1_15_darwin_amd64.go +16 -0
@@ -0,0 +1,16 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build !go1.16
5+// +build !go1.16
6+
7+package purego
8+
9+// callbackWrapPicker is here because Go 1.16+ needs it
10+// to decide between stack and register arguments.
11+// This only has a single pointer because Go 1.15 runtime.cgocallback
12+// dereferences the argument once before passing it to this
13+// function.
14+func callbackWrapPicker(stack, _ *callbackArgs) {
15+ callbackWrap(stack)
16+}
@@ -0,0 +1,16 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build !go1.16
5+// +build !go1.16
6+
7+package purego
8+
9+// callbackWrapPicker is here because Go 1.16+ needs it
10+// to decide between stack and register arguments.
11+// This only has a single pointer because Go 1.15 runtime.cgocallback
12+// dereferences the argument once before passing it to this
13+// function.
14+func callbackWrapPicker(stack, _ *callbackArgs) {
15+ callbackWrap(stack)
16+}
A callback_go1_16_darwin_amd64.go +24 -0
@@ -0,0 +1,24 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build go1.16
5+// +build go1.16
6+
7+package purego
8+
9+// callbackWrapPicker gets called with whatever is on the stack and in the first register.
10+// Depending on which version of Go that uses stack or register-based
11+// calling it passes the respective argument to the real calbackWrap function.
12+// The other argument is therefore invalid and points to undefined memory so don't use it.
13+// This function is necessary since we can't use the ABIInternal selector which is only
14+// valid in the runtime.
15+//
16+// the double indirection is because Go 1.15 will do that in runtime.cgocallback
17+// but in 1.16+ it doesn't so we do it here.
18+func callbackWrapPicker(stack, register **callbackArgs) {
19+ if stackCallingConvention {
20+ callbackWrap(*stack)
21+ } else {
22+ callbackWrap(*register)
23+ }
24+}
@@ -0,0 +1,24 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build go1.16
5+// +build go1.16
6+
7+package purego
8+
9+// callbackWrapPicker gets called with whatever is on the stack and in the first register.
10+// Depending on which version of Go that uses stack or register-based
11+// calling it passes the respective argument to the real calbackWrap function.
12+// The other argument is therefore invalid and points to undefined memory so don't use it.
13+// This function is necessary since we can't use the ABIInternal selector which is only
14+// valid in the runtime.
15+//
16+// the double indirection is because Go 1.15 will do that in runtime.cgocallback
17+// but in 1.16+ it doesn't so we do it here.
18+func callbackWrapPicker(stack, register **callbackArgs) {
19+ if stackCallingConvention {
20+ callbackWrap(*stack)
21+ } else {
22+ callbackWrap(*register)
23+ }
24+}
M sys_darwin_amd64.s +13 -9
@@ -115,23 +115,27 @@ TEXT callbackasm1(SB), NOSPLIT, $0
115115
116116 // Create a struct callbackArgs on our stack to be passed as
117117 // the "frame" to cgocallback and on to callbackWrap.
118- // $24 to make enough room for the arguments to runtime.cgocallback
119- SUBQ $(24+callbackArgs__size), SP
120- MOVQ AX, (24+callbackArgs_index)(SP) // callback index
121- MOVQ R8, (24+callbackArgs_args)(SP) // address of args vector
122- MOVQ $0, (24+callbackArgs_result)(SP) // result
123- LEAQ 24(SP), AX // take the address of callbackArgs
118+ // $32 to make enough room for the arguments to runtime.cgocallback
119+ // and on Go 1.15 to take a pointer to the pointer to callbackArgs
120+ SUBQ $(32+callbackArgs__size), SP
121+ MOVQ AX, (32+callbackArgs_index)(SP) // callback index
122+ MOVQ R8, (32+callbackArgs_args)(SP) // address of args vector
123+ MOVQ $0, (32+callbackArgs_result)(SP) // result
124+ LEAQ 32(SP), AX // take the address of callbackArgs
125+
126+ MOVQ AX, 24(SP) // get a **callbackArgs for go 1.15
127+ LEAQ 24(SP), AX // ^^^^
124128
125129 // Call cgocallback, which will call callbackWrap(frame).
126- MOVQ $0, 16(SP) // context
130+ MOVQ $8, 16(SP) // context is 0 or argsize (including return value) for Go 1.15
127131 MOVQ AX, 8(SP) // frame (address of callbackArgs)
128132 MOVQ $callbackWrapInternal<>(SB), BX
129133 MOVQ BX, 0(SP) // PC of function value to call (callbackWrap)
130134 CALL runtime·cgocallback(SB) // runtime.cgocallback(fn, frame, ctxt uintptr)
131135
132136 // Get callback result.
133- MOVQ (24+callbackArgs_result)(SP), AX
134- ADDQ $(24+callbackArgs__size), SP // remove callbackArgs struct
137+ MOVQ (32+callbackArgs_result)(SP), AX
138+ ADDQ $(32+callbackArgs__size), SP // remove callbackArgs struct
135139
136140 POP_REGS_HOST_TO_ABI0()
137141
@@ -115,23 +115,27 @@ TEXT callbackasm1(SB), NOSPLIT, $0
115 115
116 // Create a struct callbackArgs on our stack to be passed as116 // Create a struct callbackArgs on our stack to be passed as
117 // the "frame" to cgocallback and on to callbackWrap.117 // the "frame" to cgocallback and on to callbackWrap.
118- // $24 to make enough room for the arguments to runtime.cgocallback118+ // $32 to make enough room for the arguments to runtime.cgocallback
119- SUBQ $(24+callbackArgs__size), SP119+ // and on Go 1.15 to take a pointer to the pointer to callbackArgs
120- MOVQ AX, (24+callbackArgs_index)(SP) // callback index120+ SUBQ $(32+callbackArgs__size), SP
121- MOVQ R8, (24+callbackArgs_args)(SP) // address of args vector121+ MOVQ AX, (32+callbackArgs_index)(SP) // callback index
122- MOVQ $0, (24+callbackArgs_result)(SP) // result122+ MOVQ R8, (32+callbackArgs_args)(SP) // address of args vector
123- LEAQ 24(SP), AX // take the address of callbackArgs123+ MOVQ $0, (32+callbackArgs_result)(SP) // result
124+ LEAQ 32(SP), AX // take the address of callbackArgs
125+
126+ MOVQ AX, 24(SP) // get a **callbackArgs for go 1.15
127+ LEAQ 24(SP), AX // ^^^^
124 128
125 // Call cgocallback, which will call callbackWrap(frame).129 // Call cgocallback, which will call callbackWrap(frame).
126- MOVQ $0, 16(SP) // context130+ MOVQ $8, 16(SP) // context is 0 or argsize (including return value) for Go 1.15
127 MOVQ AX, 8(SP) // frame (address of callbackArgs)131 MOVQ AX, 8(SP) // frame (address of callbackArgs)
128 MOVQ $callbackWrapInternal<>(SB), BX132 MOVQ $callbackWrapInternal<>(SB), BX
129 MOVQ BX, 0(SP) // PC of function value to call (callbackWrap)133 MOVQ BX, 0(SP) // PC of function value to call (callbackWrap)
130 CALL runtime·cgocallback(SB) // runtime.cgocallback(fn, frame, ctxt uintptr)134 CALL runtime·cgocallback(SB) // runtime.cgocallback(fn, frame, ctxt uintptr)
131 135
132 // Get callback result.136 // Get callback result.
133- MOVQ (24+callbackArgs_result)(SP), AX137+ MOVQ (32+callbackArgs_result)(SP), AX
134- ADDQ $(24+callbackArgs__size), SP // remove callbackArgs struct138+ ADDQ $(32+callbackArgs__size), SP // remove callbackArgs struct
135 139
136 POP_REGS_HOST_TO_ABI0()140 POP_REGS_HOST_TO_ABI0()
137 141
M syscall_darwin.go +0 -14
@@ -95,20 +95,6 @@ const callbackMaxFrame = 64 * ptrSize
9595 // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s
9696 var callbackasmABI0 uintptr
9797
98-// callbackWrapPicker gets whatever is on the stack and in the first register.
99-// Depending on which version of Go that uses stack or register-based
100-// calling it passes the respective argument to the real calbackWrap function.
101-// The other argument is therefore invalid and points to undefined memory so don't use it.
102-// This function is necessary since we can't use the ABIInternal selector which is only
103-// valid in the runtime.
104-func callbackWrapPicker(stack, register *callbackArgs) {
105- if stackCallingConvention {
106- callbackWrap(stack)
107- } else {
108- callbackWrap(register)
109- }
110-}
111-
11298 // callbackWrap is called by assembly code which determines which Go function to call.
11399 // This function takes the arguments and passes them to the Go function and returns the result.
114100 func callbackWrap(a *callbackArgs) {
@@ -95,20 +95,6 @@ const callbackMaxFrame = 64 * ptrSize
95 // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s95 // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s
96 var callbackasmABI0 uintptr96 var callbackasmABI0 uintptr
97 97
98-// callbackWrapPicker gets whatever is on the stack and in the first register.
99-// Depending on which version of Go that uses stack or register-based
100-// calling it passes the respective argument to the real calbackWrap function.
101-// The other argument is therefore invalid and points to undefined memory so don't use it.
102-// This function is necessary since we can't use the ABIInternal selector which is only
103-// valid in the runtime.
104-func callbackWrapPicker(stack, register *callbackArgs) {
105- if stackCallingConvention {
106- callbackWrap(stack)
107- } else {
108- callbackWrap(register)
109- }
110-}
111-
112 // callbackWrap is called by assembly code which determines which Go function to call.98 // callbackWrap is called by assembly code which determines which Go function to call.
113 // This function takes the arguments and passes them to the Go function and returns the result.99 // This function takes the arguments and passes them to the Go function and returns the result.
114 func callbackWrap(a *callbackArgs) {100 func callbackWrap(a *callbackArgs) {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close