// func mcall(fn func(*g))
// Switch to m->g0's stack, call fn(g).
// Fn must never return. It should gogo(&g->sched)
// to keep running g.
TEXT runtime·mcall(SB), NOSPLIT, $0-8
// 把待执行的函数放进DI寄存器
MOVQ fn+0(FP), DI
// 这里应该是拿到g
get_tls(CX)
MOVQ g(CX), AX // save state in g->sched
MOVQ 0(SP), BX // caller's PC
// 把g的现场寄存器信息存到g.sched里
MOVQ BX, (g_sched+gobuf_pc)(AX)
LEAQ fn+0(FP), BX // caller's SP
MOVQ BX, (g_sched+gobuf_sp)(AX)
MOVQ AX, (g_sched+gobuf_g)(AX)
MOVQ BP, (g_sched+gobuf_bp)(AX)
// switch to m->g0 & its stack, call fn
// 找出g0
MOVQ g(CX), BX
MOVQ g_m(BX), BX
MOVQ m_g0(BX), SI
// 此时 SI = g0, AX = g
CMPQ SI, AX // if g == m->g0 call badmcall
JNE 3(PC)
// 如果当前的g就是g0,就执行badmcall,否则跳过下面的三条指令
MOVQ $runtime·badmcall(SB), AX
JMP AX
MOVQ SI, g(CX) // g = m->g0
// 切到g0的栈上
MOVQ (g_sched+gobuf_sp)(SI), SP // sp = m->g0->sched.sp
// 推g进栈
PUSHQ AX
MOVQ DI, DX
MOVQ 0(DI), DI
// 调用fn,并且永远都不应该返回,否则执行badmcall2
CALL DI
POPQ AX
MOVQ $runtime·badmcall2(SB), AX
JMP AX
RET
有疑问加站长微信联系(非本文作者)