Open gh-liu opened 5 months ago
// 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<ABIInternal>(SB), NOSPLIT, $0-8 // 不需要栈分割
MOVQ AX, DX // DX = fn // 将函数参数 fn 存储到寄存器 DX 中
// Save state in g->sched. The caller's SP and PC are restored by gogo to
// resume execution in the caller's frame (implicit return). The caller's BP
// is also restored to support frame pointer unwinding.
MOVQ SP, BX // hide (SP) reads from vet // 将当前栈指针保存到寄存器 BX 中
MOVQ 8(BX), BX // caller's PC // 将调用者的程序计数器 PC 存储到寄存器 BX 中
MOVQ BX, (g_sched+gobuf_pc)(R14) // 将调用者的 PC 存储到当前 g 的调度器结构体中的 gobuf.pc 字段
LEAQ fn+0(FP), BX // caller's SP // 计算函数 fn 的地址,并存储到寄存器 BX 中
MOVQ BX, (g_sched+gobuf_sp)(R14) // 将函数地址存储到当前 g 的调度器结构体中的 gobuf.sp 字段,将在调度器恢复时调用
// Get the caller's frame pointer by dereferencing BP. Storing BP as it is
// can cause a frame pointer cycle, see CL 476235.
MOVQ (BP), BX // caller's BP // 从当前帧指针(BP)指向的内存地址读取上一个帧指针的值,存储到寄存器 BX 中,支持帧指针的展开
MOVQ BX, (g_sched+gobuf_bp)(R14) // 将帧指针的值存储到当前 g 的调度器结构体中的 gobuf.bp 字段。
// switch to m->g0 & its stack, call fn
MOVQ g_m(R14), BX // 将当前 g 所属的调度器结构体中的 g 字段(即 M)的值读取到寄存器 BX 中
MOVQ m_g0(BX), SI // SI = g.m.g0 // 将 M 的 g0 字段(即全局 G0)的值读取到寄存器 SI 中
CMPQ SI, R14 // if g == m->g0 call badmcall // 比较当前 g 是否为全局 G0。如果不是,继续执行,否则跳转到 badmcall 标签
JNE goodm // 如果当前 g 不是全局 G0,则跳转到 goodm 标签
JMP runtime·badmcall(SB) // 如果当前 g 是全局 G0,则调用 badmcall 函数进行错误处理
goodm:
MOVQ R14, AX // AX (and arg 0) = g // 将当前 g 的地址存储到寄存器 AX 中,并作为参数传递给函数调用
MOVQ SI, R14 // g = g.m.g0 // 将全局 G0 的地址存储到寄存器 R14 中
get_tls(CX) // Set G in TLS // 将当前 g 的地址存储到 TLS 中
MOVQ R14, g(CX) // 将当前 g 的地址存储到 TLS 中
MOVQ (g_sched+gobuf_sp)(R14), SP // sp = g0.sched.sp // 将全局 G0 的调度器结构体中的栈指针(SP)加载到栈指针寄存器中
PUSHQ AX // open up space for fn's arg spill slot // 将当前 g 的地址压入栈中,为函数调用的参数腾出空间
MOVQ 0(DX), R12 // 将函数 fn 的地址读取到寄存器 R12 中
CALL R12 // fn(g) // 调用函数 fn
POPQ AX // 弹出栈顶元素,即当前 g 的地址
JMP runtime·badmcall2(SB) // 跳转到错误处理函数
RET