Commit f0112825 authored by Russ Cox's avatar Russ Cox

runtime: more cgocallback_gofunc work

Debugging the Windows breakage I noticed that SEH
only exists on 386, so we can balance the two stacks
a little more on amd64 and reclaim another word.

Now we're down to just one word consumed by
cgocallback_gofunc, having reclaimed 25% of the
overall budget (4 words out of 16).

Separately, fix windows/386 - the SEH must be on the
m0 stack, as must the saved SP, so we are forced to have
a three-word frame for 386. It matters much less for
386, because there 128 bytes gives 32 words to use.

R=dvyukov, alex.brainman
CC=golang-dev
https://golang.org/cl/11551044
parent a0935cc9
...@@ -524,7 +524,7 @@ TEXT runtime·cgocallback(SB),7,$12-12 ...@@ -524,7 +524,7 @@ TEXT runtime·cgocallback(SB),7,$12-12
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize) // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
// See cgocall.c for more details. // See cgocall.c for more details.
TEXT runtime·cgocallback_gofunc(SB),7,$8-12 TEXT runtime·cgocallback_gofunc(SB),7,$12-12
// If m is nil, Go did not create the current thread. // If m is nil, Go did not create the current thread.
// Call needm to obtain one for temporary use. // Call needm to obtain one for temporary use.
// In this case, we're running on the thread stack, so there's // In this case, we're running on the thread stack, so there's
...@@ -537,12 +537,14 @@ TEXT runtime·cgocallback_gofunc(SB),7,$8-12 ...@@ -537,12 +537,14 @@ TEXT runtime·cgocallback_gofunc(SB),7,$8-12
JEQ 2(PC) JEQ 2(PC)
#endif #endif
MOVL m(CX), BP MOVL m(CX), BP
MOVL BP, 4(SP) MOVL BP, DX // saved copy of oldm
CMPL BP, $0 CMPL BP, $0
JNE havem JNE havem
needm: needm:
MOVL DX, 0(SP)
MOVL $runtime·needm(SB), AX MOVL $runtime·needm(SB), AX
CALL AX CALL AX
MOVL 0(SP), DX
get_tls(CX) get_tls(CX)
MOVL m(CX), BP MOVL m(CX), BP
...@@ -552,6 +554,7 @@ havem: ...@@ -552,6 +554,7 @@ havem:
// Save current sp in m->g0->sched.sp in preparation for // Save current sp in m->g0->sched.sp in preparation for
// switch back to m->curg stack. // switch back to m->curg stack.
// NOTE: unwindm knows that the saved g->sched.sp is at 0(SP). // NOTE: unwindm knows that the saved g->sched.sp is at 0(SP).
// On Windows, the SEH is at 4(SP) and 8(SP).
MOVL m_g0(BP), SI MOVL m_g0(BP), SI
MOVL (g_sched+gobuf_sp)(SI), AX MOVL (g_sched+gobuf_sp)(SI), AX
MOVL AX, 0(SP) MOVL AX, 0(SP)
...@@ -571,22 +574,24 @@ havem: ...@@ -571,22 +574,24 @@ havem:
// so that the traceback will seamlessly trace back into // so that the traceback will seamlessly trace back into
// the earlier calls. // the earlier calls.
// //
// In the new goroutine, 0(SP) and 4(SP) are unused except // In the new goroutine, 0(SP) holds the saved oldm (DX) register.
// on Windows, where they are the SEH block. // 4(SP) and 8(SP) are unused.
MOVL m_curg(BP), SI MOVL m_curg(BP), SI
MOVL SI, g(CX) MOVL SI, g(CX)
MOVL (g_sched+gobuf_sp)(SI), DI // prepare stack as DI MOVL (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
MOVL (g_sched+gobuf_pc)(SI), BP MOVL (g_sched+gobuf_pc)(SI), BP
MOVL BP, -4(DI) MOVL BP, -4(DI)
LEAL -(4+8)(DI), SP LEAL -(4+12)(DI), SP
MOVL DX, 0(SP)
CALL runtime·cgocallbackg(SB) CALL runtime·cgocallbackg(SB)
MOVL 0(SP), DX
// Restore g->sched (== m->curg->sched) from saved values. // Restore g->sched (== m->curg->sched) from saved values.
get_tls(CX) get_tls(CX)
MOVL g(CX), SI MOVL g(CX), SI
MOVL 8(SP), BP MOVL 12(SP), BP
MOVL BP, (g_sched+gobuf_pc)(SI) MOVL BP, (g_sched+gobuf_pc)(SI)
LEAL (8+4)(SP), DI LEAL (12+4)(SP), DI
MOVL DI, (g_sched+gobuf_sp)(SI) MOVL DI, (g_sched+gobuf_sp)(SI)
// Switch back to m->g0's stack and restore m->g0->sched.sp. // Switch back to m->g0's stack and restore m->g0->sched.sp.
...@@ -601,8 +606,7 @@ havem: ...@@ -601,8 +606,7 @@ havem:
// If the m on entry was nil, we called needm above to borrow an m // If the m on entry was nil, we called needm above to borrow an m
// for the duration of the call. Since the call is over, return it with dropm. // for the duration of the call. Since the call is over, return it with dropm.
MOVL 8(SP), BP CMPL DX, $0
CMPL BP, $0
JNE 3(PC) JNE 3(PC)
MOVL $runtime·dropm(SB), AX MOVL $runtime·dropm(SB), AX
CALL AX CALL AX
......
...@@ -563,7 +563,7 @@ TEXT runtime·cgocallback(SB),7,$24-24 ...@@ -563,7 +563,7 @@ TEXT runtime·cgocallback(SB),7,$24-24
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize) // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
// See cgocall.c for more details. // See cgocall.c for more details.
TEXT runtime·cgocallback_gofunc(SB),7,$16-24 TEXT runtime·cgocallback_gofunc(SB),7,$8-24
// If m is nil, Go did not create the current thread. // If m is nil, Go did not create the current thread.
// Call needm to obtain one for temporary use. // Call needm to obtain one for temporary use.
// In this case, we're running on the thread stack, so there's // In this case, we're running on the thread stack, so there's
...@@ -576,12 +576,14 @@ TEXT runtime·cgocallback_gofunc(SB),7,$16-24 ...@@ -576,12 +576,14 @@ TEXT runtime·cgocallback_gofunc(SB),7,$16-24
JEQ 2(PC) JEQ 2(PC)
#endif #endif
MOVQ m(CX), BP MOVQ m(CX), BP
MOVQ BP, 8(SP) MOVQ BP, R8 // holds oldm until end of function
CMPQ BP, $0 CMPQ BP, $0
JNE havem JNE havem
needm: needm:
MOVQ R8, 0(SP)
MOVQ $runtime·needm(SB), AX MOVQ $runtime·needm(SB), AX
CALL AX CALL AX
MOVQ 0(SP), R8
get_tls(CX) get_tls(CX)
MOVQ m(CX), BP MOVQ m(CX), BP
...@@ -610,22 +612,23 @@ havem: ...@@ -610,22 +612,23 @@ havem:
// so that the traceback will seamlessly trace back into // so that the traceback will seamlessly trace back into
// the earlier calls. // the earlier calls.
// //
// In the new goroutine, 0(SP) and 8(SP) are unused except // In the new goroutine, 0(SP) holds the saved R8.
// on Windows, where they are the SEH block.
MOVQ m_curg(BP), SI MOVQ m_curg(BP), SI
MOVQ SI, g(CX) MOVQ SI, g(CX)
MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
MOVQ (g_sched+gobuf_pc)(SI), BP MOVQ (g_sched+gobuf_pc)(SI), BP
MOVQ BP, -8(DI) MOVQ BP, -8(DI)
LEAQ -(8+16)(DI), SP LEAQ -(8+8)(DI), SP
MOVQ R8, 0(SP)
CALL runtime·cgocallbackg(SB) CALL runtime·cgocallbackg(SB)
MOVQ 0(SP), R8
// Restore g->sched (== m->curg->sched) from saved values. // Restore g->sched (== m->curg->sched) from saved values.
get_tls(CX) get_tls(CX)
MOVQ g(CX), SI MOVQ g(CX), SI
MOVQ 16(SP), BP MOVQ 8(SP), BP
MOVQ BP, (g_sched+gobuf_pc)(SI) MOVQ BP, (g_sched+gobuf_pc)(SI)
LEAQ (16+8)(SP), DI LEAQ (8+8)(SP), DI
MOVQ DI, (g_sched+gobuf_sp)(SI) MOVQ DI, (g_sched+gobuf_sp)(SI)
// Switch back to m->g0's stack and restore m->g0->sched.sp. // Switch back to m->g0's stack and restore m->g0->sched.sp.
...@@ -640,8 +643,7 @@ havem: ...@@ -640,8 +643,7 @@ havem:
// If the m on entry was nil, we called needm above to borrow an m // If the m on entry was nil, we called needm above to borrow an m
// for the duration of the call. Since the call is over, return it with dropm. // for the duration of the call. Since the call is over, return it with dropm.
MOVQ 8(SP), BP CMPQ R8, $0
CMPQ BP, $0
JNE 3(PC) JNE 3(PC)
MOVQ $runtime·dropm(SB), AX MOVQ $runtime·dropm(SB), AX
CALL AX CALL AX
......
...@@ -236,7 +236,24 @@ struct CallbackArgs ...@@ -236,7 +236,24 @@ struct CallbackArgs
uintptr argsize; uintptr argsize;
}; };
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+(3+(thechar=='5'))*sizeof(void*)) // Location of callback arguments depends on stack frame layout
// and size of stack frame of cgocallback_gofunc.
// On arm, stack frame is two words and there's a saved LR between
// SP and the stack frame and between the stack frame and the arguments.
#ifdef GOARCH_arm
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+4*sizeof(void*))
#endif
// On amd64, stack frame is one word, plus caller PC.
#ifdef GOARCH_amd64
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))
#endif
// On 386, stack frame is three words, plus caller PC.
#ifdef GOARCH_386
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+4*sizeof(void*))
#endif
void void
runtime·cgocallbackg(void) runtime·cgocallbackg(void)
......
...@@ -499,7 +499,11 @@ runtime·mstart(void) ...@@ -499,7 +499,11 @@ runtime·mstart(void)
runtime·gosave(&m->g0->sched); runtime·gosave(&m->g0->sched);
m->g0->sched.pc = (uintptr)-1; // make sure it is never used m->g0->sched.pc = (uintptr)-1; // make sure it is never used
m->g0->stackguard = m->g0->stackguard0; // cgo sets only stackguard0, copy it to stackguard m->g0->stackguard = m->g0->stackguard0; // cgo sets only stackguard0, copy it to stackguard
#ifdef GOOS_windows
#ifdef GOARCH_386
m->seh = &seh; m->seh = &seh;
#endif
#endif
runtime·asminit(); runtime·asminit();
runtime·minit(); runtime·minit();
...@@ -650,11 +654,15 @@ runtime·needm(byte x) ...@@ -650,11 +654,15 @@ runtime·needm(byte x)
g->stackguard = (uintptr)(&x - 32*1024); g->stackguard = (uintptr)(&x - 32*1024);
g->stackguard0 = g->stackguard; g->stackguard0 = g->stackguard;
#ifdef GOOS_windows
#ifdef GOARCH_386
// On windows/386, we need to put an SEH frame (two words) // On windows/386, we need to put an SEH frame (two words)
// somewhere on the current stack. We are called from cgocallback_gofunc // somewhere on the current stack. We are called from cgocallback_gofunc
// and we know that it will leave two unused words below m->curg->sched.sp. // and we know that it will leave two unused words below m->curg->sched.sp.
// Use those. // Use those.
m->seh = (SEH*)((uintptr*)m->curg->sched.sp - 3); m->seh = (SEH*)((uintptr*)&x + 1);
#endif
#endif
// Initialize this thread to use the m. // Initialize this thread to use the m.
runtime·asminit(); runtime·asminit();
...@@ -734,7 +742,12 @@ runtime·dropm(void) ...@@ -734,7 +742,12 @@ runtime·dropm(void)
// Undo whatever initialization minit did during needm. // Undo whatever initialization minit did during needm.
runtime·unminit(); runtime·unminit();
#ifdef GOOS_windows
#ifdef GOARCH_386
m->seh = nil; // reset dangling typed pointer m->seh = nil; // reset dangling typed pointer
#endif
#endif
// Clear m and g, and return m to the extra list. // Clear m and g, and return m to the extra list.
// After the call to setmg we can only call nosplit functions. // After the call to setmg we can only call nosplit functions.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment