diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 4e5e8f75127b19..7f14f61e2a8171 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -550,6 +550,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20 // come in on the m->g0 stack already. get_tls(CX) MOVQ g(CX), R8 + CMPQ R8, $0 + JEQ nosave MOVQ g_m(R8), R8 MOVQ m_g0(R8), SI MOVQ g(CX), DI @@ -559,11 +561,11 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20 CMPQ SI, DI JEQ nosave + // Switch to system stack. MOVQ m_g0(R8), SI CALL gosave<>(SB) MOVQ SI, g(CX) MOVQ (g_sched+gobuf_sp)(SI), SP -nosave: // Now on a scheduling stack (a pthread-created stack). // Make sure we have enough room for 4 stack-backed fast-call @@ -589,6 +591,29 @@ nosave: MOVL AX, ret+16(FP) RET +nosave: + // Running on a system stack, perhaps even without a g. + // Having no g can happen during thread creation or thread teardown + // (see needm/dropm on Solaris, for example). + // This code is like the above sequence but without saving/restoring g + // and without worrying about the stack moving out from under us + // (because we're on a system stack, not a goroutine stack). + // The above code could be used directly if already on a system stack, + // but then the only path through this code would be a rare case on Solaris. + // Using this code for all "already on system stack" calls exercises it more, + // which should help keep it correct. + SUBQ $64, SP + ANDQ $~15, SP + MOVQ $0, 48(SP) // where above code stores g, in case someone looks during debugging + MOVQ DX, 40(SP) // save original stack pointer + MOVQ BX, DI // DI = first argument in AMD64 ABI + MOVQ BX, CX // CX = first argument in Win64 + CALL AX + MOVQ 40(SP), SI // restore original stack pointer + MOVQ SI, SP + MOVL AX, ret+16(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.