mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/{asm,compile,internal/obj}: add "maymorestack" support
This adds a debugging hook for optionally calling a "maymorestack" function in the prologue of any function that might call morestack (whether it does at run time or not). The maymorestack function will let us improve lock checking and add debugging modes that stress function preemption and stack growth. Passes toolstash-check -all (except on js/wasm, where toolstash appears to be broken) Fixes #48297. Change-Id: I27197947482b329af75dafb9971fc0d3a52eaf31 Reviewed-on: https://go-review.googlesource.com/c/go/+/359795 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
1c4cfd8010
commit
3839b60014
14 changed files with 620 additions and 46 deletions
|
|
@ -644,19 +644,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
|||
}
|
||||
}
|
||||
|
||||
var regg int16
|
||||
if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() {
|
||||
if ctxt.Arch.Family == sys.AMD64 && cursym.ABI() == obj.ABIInternal {
|
||||
regg = REGG // use the g register directly in ABIInternal
|
||||
} else {
|
||||
p = obj.Appendp(p, newprog)
|
||||
regg = REG_CX
|
||||
if ctxt.Arch.Family == sys.AMD64 {
|
||||
regg = REGG // == REG_R14
|
||||
}
|
||||
p = load_g(ctxt, p, newprog, regg) // load g into regg
|
||||
}
|
||||
}
|
||||
var regEntryTmp0, regEntryTmp1 int16
|
||||
if ctxt.Arch.Family == sys.AMD64 {
|
||||
regEntryTmp0, regEntryTmp1 = REGENTRYTMP0, REGENTRYTMP1
|
||||
|
|
@ -664,8 +651,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
|||
regEntryTmp0, regEntryTmp1 = REG_BX, REG_DI
|
||||
}
|
||||
|
||||
if !cursym.Func().Text.From.Sym.NoSplit() {
|
||||
p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg), regg) // emit split check
|
||||
var regg int16
|
||||
if !p.From.Sym.NoSplit() {
|
||||
// Emit split check and load G register
|
||||
p, regg = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg))
|
||||
} else if p.From.Sym.Wrapper() {
|
||||
// Load G register for the wrapper code
|
||||
p, regg = loadG(ctxt, cursym, p, newprog)
|
||||
}
|
||||
|
||||
// Delve debugger would like the next instruction to be noted as the end of the function prologue.
|
||||
|
|
@ -973,12 +965,21 @@ func indir_cx(ctxt *obj.Link, a *obj.Addr) {
|
|||
a.Reg = REG_CX
|
||||
}
|
||||
|
||||
// Append code to p to load g into cx.
|
||||
// Overwrites p with the first instruction (no first appendp).
|
||||
// Overwriting p is unusual but it lets use this in both the
|
||||
// prologue (caller must call appendp first) and in the epilogue.
|
||||
// Returns last new instruction.
|
||||
func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.Prog {
|
||||
// loadG ensures the G is loaded into a register (either CX or REGG),
|
||||
// appending instructions to p if necessary. It returns the new last
|
||||
// instruction and the G register.
|
||||
func loadG(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc) (*obj.Prog, int16) {
|
||||
if ctxt.Arch.Family == sys.AMD64 && cursym.ABI() == obj.ABIInternal {
|
||||
// Use the G register directly in ABIInternal
|
||||
return p, REGG
|
||||
}
|
||||
|
||||
var regg int16 = REG_CX
|
||||
if ctxt.Arch.Family == sys.AMD64 {
|
||||
regg = REGG // == REG_R14
|
||||
}
|
||||
|
||||
p = obj.Appendp(p, newprog)
|
||||
p.As = AMOVQ
|
||||
if ctxt.Arch.PtrSize == 4 {
|
||||
p.As = AMOVL
|
||||
|
|
@ -987,8 +988,9 @@ func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.P
|
|||
p.From.Reg = REG_TLS
|
||||
p.From.Offset = 0
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = rg
|
||||
p.To.Reg = regg
|
||||
|
||||
// Rewrite TLS instruction if necessary.
|
||||
next := p.Link
|
||||
progedit(ctxt, p, newprog)
|
||||
for p.Link != next {
|
||||
|
|
@ -1000,24 +1002,26 @@ func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.P
|
|||
p.From.Scale = 2
|
||||
}
|
||||
|
||||
return p
|
||||
return p, regg
|
||||
}
|
||||
|
||||
// Append code to p to check for stack split.
|
||||
// Appends to (does not overwrite) p.
|
||||
// Assumes g is in rg.
|
||||
// Returns last new instruction.
|
||||
func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32, rg int16) *obj.Prog {
|
||||
// Returns last new instruction and G register.
|
||||
func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) (*obj.Prog, int16) {
|
||||
cmp := ACMPQ
|
||||
lea := ALEAQ
|
||||
mov := AMOVQ
|
||||
sub := ASUBQ
|
||||
push, pop := APUSHQ, APOPQ
|
||||
|
||||
if ctxt.Arch.Family == sys.I386 {
|
||||
cmp = ACMPL
|
||||
lea = ALEAL
|
||||
mov = AMOVL
|
||||
sub = ASUBL
|
||||
push, pop = APUSHL, APOPL
|
||||
}
|
||||
|
||||
tmp := int16(REG_AX) // use AX for 32-bit
|
||||
|
|
@ -1026,6 +1030,45 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
|||
tmp = int16(REGENTRYTMP0)
|
||||
}
|
||||
|
||||
if ctxt.Flag_maymorestack != "" {
|
||||
p = cursym.Func().SpillRegisterArgs(p, newprog)
|
||||
|
||||
if cursym.Func().Text.From.Sym.NeedCtxt() {
|
||||
p = obj.Appendp(p, newprog)
|
||||
p.As = push
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = REGCTXT
|
||||
}
|
||||
|
||||
// We call maymorestack with an ABI matching the
|
||||
// caller's ABI. Since this is the first thing that
|
||||
// happens in the function, we have to be consistent
|
||||
// with the caller about CPU state (notably,
|
||||
// fixed-meaning registers).
|
||||
|
||||
p = obj.Appendp(p, newprog)
|
||||
p.As = obj.ACALL
|
||||
p.To.Type = obj.TYPE_BRANCH
|
||||
p.To.Name = obj.NAME_EXTERN
|
||||
p.To.Sym = ctxt.LookupABI(ctxt.Flag_maymorestack, cursym.ABI())
|
||||
|
||||
if cursym.Func().Text.From.Sym.NeedCtxt() {
|
||||
p = obj.Appendp(p, newprog)
|
||||
p.As = pop
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = REGCTXT
|
||||
}
|
||||
|
||||
p = cursym.Func().UnspillRegisterArgs(p, newprog)
|
||||
}
|
||||
|
||||
// Jump back to here after morestack returns.
|
||||
startPred := p
|
||||
|
||||
// Load G register
|
||||
var rg int16
|
||||
p, rg = loadG(ctxt, cursym, p, newprog)
|
||||
|
||||
var q1 *obj.Prog
|
||||
if framesize <= objabi.StackSmall {
|
||||
// small stack: SP <= stackguard
|
||||
|
|
@ -1171,7 +1214,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
|||
jmp := obj.Appendp(pcdata, newprog)
|
||||
jmp.As = obj.AJMP
|
||||
jmp.To.Type = obj.TYPE_BRANCH
|
||||
jmp.To.SetTarget(cursym.Func().Text.Link)
|
||||
jmp.To.SetTarget(startPred.Link)
|
||||
jmp.Spadj = +framesize
|
||||
|
||||
jls.To.SetTarget(spill)
|
||||
|
|
@ -1179,7 +1222,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
|||
q1.To.SetTarget(spill)
|
||||
}
|
||||
|
||||
return end
|
||||
return end, rg
|
||||
}
|
||||
|
||||
func isR15(r int16) bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue