aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/asm_mipsx.s
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2020-10-01 17:22:38 -0400
committerAustin Clements <austin@google.com>2020-10-26 14:50:32 +0000
commit30c18878730434027dbefd343aad74963a1fdc48 (patch)
treefa134fee222fee13eca873820988d42cafd33b25 /src/runtime/asm_mipsx.s
parent404899f6b56800c1d8e0521fc9ce0c856e459d94 (diff)
downloadgo-30c18878730434027dbefd343aad74963a1fdc48.tar.gz
go-30c18878730434027dbefd343aad74963a1fdc48.zip
runtime,cmd/cgo: simplify C -> Go call path
This redesigns the way calls work from C to exported Go functions. It removes several steps from the call path, makes cmd/cgo no longer sensitive to the Go calling convention, and eliminates the use of reflectcall from cgo. In order to avoid generating a large amount of FFI glue between the C and Go ABIs, the cgo tool has long depended on generating a C function that marshals the arguments into a struct, and then the actual ABI switch happens in functions with fixed signatures that simply take a pointer to this struct. In a way, this CL simply pushes this idea further. Currently, the cgo tool generates this argument struct in the exact layout of the Go stack frame and depends on reflectcall to unpack it into the appropriate Go call (even though it's actually reflectcall'ing a function generated by cgo). In this CL, we decouple this struct from the Go stack layout. Instead, cgo generates a Go function that takes the struct, unpacks it, and calls the exported function. Since this generated function has a generic signature (like the rest of the call path), we don't need reflectcall and can instead depend on the Go compiler itself to implement the call to the exported Go function. One complication is that syscall.NewCallback on Windows, which converts a Go function into a C function pointer, depends on cgocallback's current dynamic calling approach since the signatures of the callbacks aren't known statically. For this specific case, we continue to depend on reflectcall. Really, the current approach makes some overly simplistic assumptions about translating the C ABI to the Go ABI. Now we're at least in a much better position to do a proper ABI translation. For comparison, the current cgo call path looks like: GoF (generated C function) -> crosscall2 (in cgo/asm_*.s) -> _cgoexp_GoF (generated Go function) -> cgocallback (in asm_*.s) -> cgocallback_gofunc (in asm_*.s) -> cgocallbackg (in cgocall.go) -> cgocallbackg1 (in cgocall.go) -> reflectcall (in asm_*.s) -> _cgoexpwrap_GoF (generated Go function) -> p.GoF Now the call path looks like: GoF (generated C function) -> crosscall2 (in cgo/asm_*.s) -> cgocallback (in asm_*.s) -> cgocallbackg (in cgocall.go) -> cgocallbackg1 (in cgocall.go) -> _cgoexp_GoF (generated Go function) -> p.GoF Notably: 1. We combine _cgoexp_GoF and _cgoexpwrap_GoF and move the combined operation to the end of the sequence. This combined function also handles reflectcall's previous role. 2. We combined cgocallback and cgocallback_gofunc since the only purpose of having both was to convert a raw PC into a Go function value. We instead construct the Go function value in cgocallbackg1. 3. cgocallbackg1 no longer reaches backwards through the stack to get the arguments to cgocallback_gofunc. Instead, we just pass the arguments down. 4. Currently, we need an explicit msanwrite to mark the results struct as written because reflectcall doesn't do this. Now, the results are written by regular Go assignments, so the Go compiler generates the necessary MSAN annotations. This also means we no longer need to track the size of the arguments frame. Updates #40724, since now we don't need to teach cgo about the register ABI or change how it uses reflectcall. Change-Id: I7840489a2597962aeb670e0c1798a16a7359c94f Reviewed-on: https://go-review.googlesource.com/c/go/+/258938 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/asm_mipsx.s')
-rw-r--r--src/runtime/asm_mipsx.s54
1 files changed, 19 insertions, 35 deletions
diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s
index aca0510b69..ee87d81436 100644
--- a/src/runtime/asm_mipsx.s
+++ b/src/runtime/asm_mipsx.s
@@ -472,25 +472,9 @@ g0:
MOVW R2, ret+8(FP)
RET
-// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
-// Turn the fn into a Go func (by taking its address) and call
-// cgocallback_gofunc.
-TEXT runtime·cgocallback(SB),NOSPLIT,$16-16
- MOVW $fn+0(FP), R1
- MOVW R1, 4(R29)
- MOVW frame+4(FP), R1
- MOVW R1, 8(R29)
- MOVW framesize+8(FP), R1
- MOVW R1, 12(R29)
- MOVW ctxt+12(FP), R1
- MOVW R1, 16(R29)
- MOVW $runtime·cgocallback_gofunc(SB), R1
- JAL (R1)
- RET
-
-// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
+// cgocallback(fn, frame unsafe.Pointer, ctxt uintptr)
// See cgocall.go for more details.
-TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-16
+TEXT ·cgocallback(SB),NOSPLIT,$12-12
NO_LOCAL_POINTERS
// Load m and g from thread-local storage.
@@ -538,7 +522,7 @@ havem:
// NOTE: unwindm knows that the saved g->sched.sp is at 4(R29) aka savedsp-8(SP).
MOVW m_g0(R3), R1
MOVW (g_sched+gobuf_sp)(R1), R2
- MOVW R2, savedsp-8(SP)
+ MOVW R2, savedsp-12(SP) // must match frame size
MOVW R29, (g_sched+gobuf_sp)(R1)
// Switch to m->curg stack and call runtime.cgocallbackg.
@@ -547,30 +531,30 @@ havem:
// save that information (m->curg->sched) so we can restore it.
// We can restore m->curg->sched.sp easily, because calling
// runtime.cgocallbackg leaves SP unchanged upon return.
- // To save m->curg->sched.pc, we push it onto the stack.
- // This has the added benefit that it looks to the traceback
- // routine like cgocallbackg is going to return to that
- // PC (because the frame we allocate below has the same
- // size as cgocallback_gofunc's frame declared above)
- // so that the traceback will seamlessly trace back into
- // the earlier calls.
- //
- // In the new goroutine, -4(SP) is unused (where SP refers to
- // m->curg's SP while we're setting it up, before we've adjusted it).
+ // To save m->curg->sched.pc, we push it onto the curg stack and
+ // open a frame the same size as cgocallback's g0 frame.
+ // Once we switch to the curg stack, the pushed PC will appear
+ // to be the return PC of cgocallback, so that the traceback
+ // will seamlessly trace back into the earlier calls.
MOVW m_curg(R3), g
JAL runtime·save_g(SB)
MOVW (g_sched+gobuf_sp)(g), R2 // prepare stack as R2
MOVW (g_sched+gobuf_pc)(g), R4
- MOVW R4, -12(R2)
- MOVW ctxt+12(FP), R1
- MOVW R1, -8(R2)
- MOVW $-12(R2), R29
+ MOVW R4, -(12+4)(R2) // "saved LR"; must match frame size
+ // Gather our arguments into registers.
+ MOVW fn+0(FP), R5
+ MOVW frame+4(FP), R6
+ MOVW ctxt+8(FP), R7
+ MOVW $-(12+4)(R2), R29 // switch stack; must match frame size
+ MOVW R5, 4(R29)
+ MOVW R6, 8(R29)
+ MOVW R7, 12(R29)
JAL runtime·cgocallbackg(SB)
// Restore g->sched (== m->curg->sched) from saved values.
MOVW 0(R29), R4
MOVW R4, (g_sched+gobuf_pc)(g)
- MOVW $12(R29), R2
+ MOVW $(12+4)(R29), R2 // must match frame size
MOVW R2, (g_sched+gobuf_sp)(g)
// Switch back to m->g0's stack and restore m->g0->sched.sp.
@@ -580,7 +564,7 @@ havem:
MOVW m_g0(R3), g
JAL runtime·save_g(SB)
MOVW (g_sched+gobuf_sp)(g), R29
- MOVW savedsp-8(SP), R2
+ MOVW savedsp-12(SP), R2 // must match frame size
MOVW R2, (g_sched+gobuf_sp)(g)
// If the m on entry was nil, we called needm above to borrow an m