mirror of https://github.com/golang/go.git
cmd/internal/obj: mark split-stack prologue nonpreemptible
When there are both a synchronous preemption request (by clobbering the stack guard) and an asynchronous one (by signal), the running goroutine may observe the synchronous request first in stack bounds check, and go to the path of calling morestack. If the preemption signal arrives at this point before the call to morestack, the goroutine will be asynchronously preempted, entering the scheduler. When it is resumed, the scheduler clears the preemption request, unclobbers the stack guard. But the resumed goroutine will still call morestack, as it is already on its way. morestack will, as there is no preemption request, double the stack unnecessarily. If this happens multiple times, the stack may grow too big, although only a small amount is actually used. To fix this, we mark the stack bounds check and the call to morestack async-nonpreemptible, starting after the memory instruction (mostly a load, on x86 CMP with memory). Not done for Wasm as it does not support async preemption. Fixes #35470. Change-Id: Ibd7f3d935a3649b80f47539116ec9b9556680cf2 Reviewed-on: https://go-review.googlesource.com/c/go/+/207350 Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
c3f149250e
commit
b2482e4817
|
|
@ -674,6 +674,12 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = REG_R1
|
p.To.Reg = REG_R1
|
||||||
|
|
||||||
|
// Mark the stack bound check and morestack call async nonpreemptible.
|
||||||
|
// If we get preempted here, when resumed the preemption request is
|
||||||
|
// cleared, but we'll still call morestack, which will double the stack
|
||||||
|
// unnecessarily. See issue #35470.
|
||||||
|
p = c.ctxt.StartUnsafePoint(p, c.newprog)
|
||||||
|
|
||||||
if framesize <= objabi.StackSmall {
|
if framesize <= objabi.StackSmall {
|
||||||
// small stack: SP < stackguard
|
// small stack: SP < stackguard
|
||||||
// CMP stackguard, SP
|
// CMP stackguard, SP
|
||||||
|
|
@ -757,6 +763,8 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
bls.As = ABLS
|
bls.As = ABLS
|
||||||
bls.To.Type = obj.TYPE_BRANCH
|
bls.To.Type = obj.TYPE_BRANCH
|
||||||
|
|
||||||
|
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
|
||||||
|
|
||||||
var last *obj.Prog
|
var last *obj.Prog
|
||||||
for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
|
for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
|
||||||
}
|
}
|
||||||
|
|
@ -768,7 +776,8 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
spfix.As = obj.ANOP
|
spfix.As = obj.ANOP
|
||||||
spfix.Spadj = -framesize
|
spfix.Spadj = -framesize
|
||||||
|
|
||||||
pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
|
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
|
||||||
|
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
|
||||||
|
|
||||||
// MOVW LR, R3
|
// MOVW LR, R3
|
||||||
movw := obj.Appendp(pcdata, c.newprog)
|
movw := obj.Appendp(pcdata, c.newprog)
|
||||||
|
|
@ -793,14 +802,16 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
}
|
}
|
||||||
call.To.Sym = c.ctxt.Lookup(morestack)
|
call.To.Sym = c.ctxt.Lookup(morestack)
|
||||||
|
|
||||||
|
pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
|
||||||
|
|
||||||
// B start
|
// B start
|
||||||
b := obj.Appendp(call, c.newprog)
|
b := obj.Appendp(pcdata, c.newprog)
|
||||||
b.As = obj.AJMP
|
b.As = obj.AJMP
|
||||||
b.To.Type = obj.TYPE_BRANCH
|
b.To.Type = obj.TYPE_BRANCH
|
||||||
b.Pcond = c.cursym.Func.Text.Link
|
b.Pcond = c.cursym.Func.Text.Link
|
||||||
b.Spadj = +framesize
|
b.Spadj = +framesize
|
||||||
|
|
||||||
return bls
|
return end
|
||||||
}
|
}
|
||||||
|
|
||||||
var unaryDst = map[obj.As]bool{
|
var unaryDst = map[obj.As]bool{
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,12 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = REG_R1
|
p.To.Reg = REG_R1
|
||||||
|
|
||||||
|
// Mark the stack bound check and morestack call async nonpreemptible.
|
||||||
|
// If we get preempted here, when resumed the preemption request is
|
||||||
|
// cleared, but we'll still call morestack, which will double the stack
|
||||||
|
// unnecessarily. See issue #35470.
|
||||||
|
p = c.ctxt.StartUnsafePoint(p, c.newprog)
|
||||||
|
|
||||||
q := (*obj.Prog)(nil)
|
q := (*obj.Prog)(nil)
|
||||||
if framesize <= objabi.StackSmall {
|
if framesize <= objabi.StackSmall {
|
||||||
// small stack: SP < stackguard
|
// small stack: SP < stackguard
|
||||||
|
|
@ -156,6 +162,8 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
bls.As = ABLS
|
bls.As = ABLS
|
||||||
bls.To.Type = obj.TYPE_BRANCH
|
bls.To.Type = obj.TYPE_BRANCH
|
||||||
|
|
||||||
|
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
|
||||||
|
|
||||||
var last *obj.Prog
|
var last *obj.Prog
|
||||||
for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
|
for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +175,8 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
spfix.As = obj.ANOP
|
spfix.As = obj.ANOP
|
||||||
spfix.Spadj = -framesize
|
spfix.Spadj = -framesize
|
||||||
|
|
||||||
pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
|
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
|
||||||
|
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
|
||||||
|
|
||||||
// MOV LR, R3
|
// MOV LR, R3
|
||||||
movlr := obj.Appendp(pcdata, c.newprog)
|
movlr := obj.Appendp(pcdata, c.newprog)
|
||||||
|
|
@ -204,18 +213,16 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
}
|
}
|
||||||
call.To.Sym = c.ctxt.Lookup(morestack)
|
call.To.Sym = c.ctxt.Lookup(morestack)
|
||||||
|
|
||||||
|
pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
|
||||||
|
|
||||||
// B start
|
// B start
|
||||||
jmp := obj.Appendp(call, c.newprog)
|
jmp := obj.Appendp(pcdata, c.newprog)
|
||||||
jmp.As = AB
|
jmp.As = AB
|
||||||
jmp.To.Type = obj.TYPE_BRANCH
|
jmp.To.Type = obj.TYPE_BRANCH
|
||||||
jmp.Pcond = c.cursym.Func.Text.Link
|
jmp.Pcond = c.cursym.Func.Text.Link
|
||||||
jmp.Spadj = +framesize
|
jmp.Spadj = +framesize
|
||||||
|
|
||||||
// placeholder for bls's jump target
|
return end
|
||||||
// p = obj.Appendp(ctxt, p)
|
|
||||||
// p.As = obj.ANOP
|
|
||||||
|
|
||||||
return bls
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
|
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
|
||||||
|
|
|
||||||
|
|
@ -677,6 +677,12 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = REG_R1
|
p.To.Reg = REG_R1
|
||||||
|
|
||||||
|
// Mark the stack bound check and morestack call async nonpreemptible.
|
||||||
|
// If we get preempted here, when resumed the preemption request is
|
||||||
|
// cleared, but we'll still call morestack, which will double the stack
|
||||||
|
// unnecessarily. See issue #35470.
|
||||||
|
p = c.ctxt.StartUnsafePoint(p, c.newprog)
|
||||||
|
|
||||||
var q *obj.Prog
|
var q *obj.Prog
|
||||||
if framesize <= objabi.StackSmall {
|
if framesize <= objabi.StackSmall {
|
||||||
// small stack: SP < stackguard
|
// small stack: SP < stackguard
|
||||||
|
|
@ -796,7 +802,7 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
p.Mark |= LABEL
|
p.Mark |= LABEL
|
||||||
}
|
}
|
||||||
|
|
||||||
p = c.ctxt.EmitEntryLiveness(c.cursym, p, c.newprog)
|
p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
|
||||||
|
|
||||||
// JAL runtime.morestack(SB)
|
// JAL runtime.morestack(SB)
|
||||||
p = obj.Appendp(p, c.newprog)
|
p = obj.Appendp(p, c.newprog)
|
||||||
|
|
@ -812,6 +818,8 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
}
|
}
|
||||||
p.Mark |= BRANCH
|
p.Mark |= BRANCH
|
||||||
|
|
||||||
|
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
|
||||||
|
|
||||||
// JMP start
|
// JMP start
|
||||||
p = obj.Appendp(p, c.newprog)
|
p = obj.Appendp(p, c.newprog)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,13 @@ func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
|
||||||
// liveness map active at the entry of function s. It returns the last
|
// liveness map active at the entry of function s. It returns the last
|
||||||
// Prog generated.
|
// Prog generated.
|
||||||
func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
|
func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
|
||||||
|
pcdata := ctxt.EmitEntryStackMap(s, p, newprog)
|
||||||
|
pcdata = ctxt.EmitEntryRegMap(s, pcdata, newprog)
|
||||||
|
return pcdata
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar to EmitEntryLiveness, but just emit stack map.
|
||||||
|
func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
|
||||||
pcdata := Appendp(p, newprog)
|
pcdata := Appendp(p, newprog)
|
||||||
pcdata.Pos = s.Func.Text.Pos
|
pcdata.Pos = s.Func.Text.Pos
|
||||||
pcdata.As = APCDATA
|
pcdata.As = APCDATA
|
||||||
|
|
@ -195,8 +202,12 @@ func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
|
||||||
pcdata.To.Type = TYPE_CONST
|
pcdata.To.Type = TYPE_CONST
|
||||||
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
|
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
|
||||||
|
|
||||||
// Same, with register map.
|
return pcdata
|
||||||
pcdata = Appendp(pcdata, newprog)
|
}
|
||||||
|
|
||||||
|
// Similar to EmitEntryLiveness, but just emit register map.
|
||||||
|
func (ctxt *Link) EmitEntryRegMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
|
||||||
|
pcdata := Appendp(p, newprog)
|
||||||
pcdata.Pos = s.Func.Text.Pos
|
pcdata.Pos = s.Func.Text.Pos
|
||||||
pcdata.As = APCDATA
|
pcdata.As = APCDATA
|
||||||
pcdata.From.Type = TYPE_CONST
|
pcdata.From.Type = TYPE_CONST
|
||||||
|
|
|
||||||
|
|
@ -1045,6 +1045,12 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = REG_R3
|
p.To.Reg = REG_R3
|
||||||
|
|
||||||
|
// Mark the stack bound check and morestack call async nonpreemptible.
|
||||||
|
// If we get preempted here, when resumed the preemption request is
|
||||||
|
// cleared, but we'll still call morestack, which will double the stack
|
||||||
|
// unnecessarily. See issue #35470.
|
||||||
|
p = c.ctxt.StartUnsafePoint(p, c.newprog)
|
||||||
|
|
||||||
var q *obj.Prog
|
var q *obj.Prog
|
||||||
if framesize <= objabi.StackSmall {
|
if framesize <= objabi.StackSmall {
|
||||||
// small stack: SP < stackguard
|
// small stack: SP < stackguard
|
||||||
|
|
@ -1153,7 +1159,7 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
q.Pcond = p
|
q.Pcond = p
|
||||||
}
|
}
|
||||||
|
|
||||||
p = c.ctxt.EmitEntryLiveness(c.cursym, p, c.newprog)
|
p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
|
||||||
|
|
||||||
var morestacksym *obj.LSym
|
var morestacksym *obj.LSym
|
||||||
if c.cursym.CFunc() {
|
if c.cursym.CFunc() {
|
||||||
|
|
@ -1239,6 +1245,8 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
||||||
p.To.Reg = REG_R2
|
p.To.Reg = REG_R2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
|
||||||
|
|
||||||
// BR start
|
// BR start
|
||||||
p = obj.Appendp(p, c.newprog)
|
p = obj.Appendp(p, c.newprog)
|
||||||
p.As = ABR
|
p.As = ABR
|
||||||
|
|
|
||||||
|
|
@ -335,6 +335,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
||||||
if !p.From.Sym.NoSplit() {
|
if !p.From.Sym.NoSplit() {
|
||||||
p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check
|
p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check
|
||||||
pPre = p
|
pPre = p
|
||||||
|
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
|
||||||
wasSplit = true //need post part of split
|
wasSplit = true //need post part of split
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -575,15 +576,16 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = REG_R3
|
p.To.Reg = REG_R3
|
||||||
|
|
||||||
|
// Mark the stack bound check and morestack call async nonpreemptible.
|
||||||
|
// If we get preempted here, when resumed the preemption request is
|
||||||
|
// cleared, but we'll still call morestack, which will double the stack
|
||||||
|
// unnecessarily. See issue #35470.
|
||||||
|
p = c.ctxt.StartUnsafePoint(p, c.newprog)
|
||||||
|
|
||||||
q = nil
|
q = nil
|
||||||
if framesize <= objabi.StackSmall {
|
if framesize <= objabi.StackSmall {
|
||||||
// small stack: SP < stackguard
|
// small stack: SP < stackguard
|
||||||
// CMP stackguard, SP
|
// CMPUBGE stackguard, SP, label-of-call-to-morestack
|
||||||
|
|
||||||
//p.To.Type = obj.TYPE_REG
|
|
||||||
//p.To.Reg = REGSP
|
|
||||||
|
|
||||||
// q1: BLT done
|
|
||||||
|
|
||||||
p = obj.Appendp(p, c.newprog)
|
p = obj.Appendp(p, c.newprog)
|
||||||
//q1 = p
|
//q1 = p
|
||||||
|
|
@ -592,22 +594,11 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
|
||||||
p.Reg = REGSP
|
p.Reg = REGSP
|
||||||
p.As = ACMPUBGE
|
p.As = ACMPUBGE
|
||||||
p.To.Type = obj.TYPE_BRANCH
|
p.To.Type = obj.TYPE_BRANCH
|
||||||
//p = obj.Appendp(ctxt, p)
|
|
||||||
|
|
||||||
//p.As = ACMPU
|
|
||||||
//p.From.Type = obj.TYPE_REG
|
|
||||||
//p.From.Reg = REG_R3
|
|
||||||
//p.To.Type = obj.TYPE_REG
|
|
||||||
//p.To.Reg = REGSP
|
|
||||||
|
|
||||||
//p = obj.Appendp(ctxt, p)
|
|
||||||
//p.As = ABGE
|
|
||||||
//p.To.Type = obj.TYPE_BRANCH
|
|
||||||
|
|
||||||
} else if framesize <= objabi.StackBig {
|
} else if framesize <= objabi.StackBig {
|
||||||
// large stack: SP-framesize < stackguard-StackSmall
|
// large stack: SP-framesize < stackguard-StackSmall
|
||||||
// ADD $-(framesize-StackSmall), SP, R4
|
// ADD $-(framesize-StackSmall), SP, R4
|
||||||
// CMP stackguard, R4
|
// CMPUBGE stackguard, R4, label-of-call-to-morestack
|
||||||
p = obj.Appendp(p, c.newprog)
|
p = obj.Appendp(p, c.newprog)
|
||||||
|
|
||||||
p.As = AADD
|
p.As = AADD
|
||||||
|
|
@ -639,7 +630,7 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Pro
|
||||||
// ADD $StackGuard, SP, R4
|
// ADD $StackGuard, SP, R4
|
||||||
// SUB R3, R4
|
// SUB R3, R4
|
||||||
// MOVD $(framesize+(StackGuard-StackSmall)), TEMP
|
// MOVD $(framesize+(StackGuard-StackSmall)), TEMP
|
||||||
// CMPUBGE TEMP, R4
|
// CMPUBGE TEMP, R4, label-of-call-to-morestack
|
||||||
p = obj.Appendp(p, c.newprog)
|
p = obj.Appendp(p, c.newprog)
|
||||||
|
|
||||||
p.As = ACMP
|
p.As = ACMP
|
||||||
|
|
@ -694,7 +685,8 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
|
||||||
spfix.As = obj.ANOP
|
spfix.As = obj.ANOP
|
||||||
spfix.Spadj = -framesize
|
spfix.Spadj = -framesize
|
||||||
|
|
||||||
pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
|
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
|
||||||
|
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
|
||||||
|
|
||||||
// MOVD LR, R5
|
// MOVD LR, R5
|
||||||
p = obj.Appendp(pcdata, c.newprog)
|
p = obj.Appendp(pcdata, c.newprog)
|
||||||
|
|
@ -721,6 +713,8 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
|
||||||
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
|
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
|
||||||
|
|
||||||
// BR start
|
// BR start
|
||||||
p = obj.Appendp(p, c.newprog)
|
p = obj.Appendp(p, c.newprog)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -998,6 +998,12 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
||||||
if cursym.CFunc() {
|
if cursym.CFunc() {
|
||||||
p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
|
p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark the stack bound check and morestack call async nonpreemptible.
|
||||||
|
// If we get preempted here, when resumed the preemption request is
|
||||||
|
// cleared, but we'll still call morestack, which will double the stack
|
||||||
|
// unnecessarily. See issue #35470.
|
||||||
|
p = ctxt.StartUnsafePoint(p, newprog)
|
||||||
} else if framesize <= objabi.StackBig {
|
} else if framesize <= objabi.StackBig {
|
||||||
// large stack: SP-framesize <= stackguard-StackSmall
|
// large stack: SP-framesize <= stackguard-StackSmall
|
||||||
// LEAQ -xxx(SP), AX
|
// LEAQ -xxx(SP), AX
|
||||||
|
|
@ -1020,6 +1026,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
||||||
if cursym.CFunc() {
|
if cursym.CFunc() {
|
||||||
p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
|
p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
|
||||||
} else {
|
} else {
|
||||||
// Such a large stack we need to protect against wraparound.
|
// Such a large stack we need to protect against wraparound.
|
||||||
// If SP is close to zero:
|
// If SP is close to zero:
|
||||||
|
|
@ -1029,11 +1037,11 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
||||||
//
|
//
|
||||||
// Preemption sets stackguard to StackPreempt, a very large value.
|
// Preemption sets stackguard to StackPreempt, a very large value.
|
||||||
// That breaks the math above, so we have to check for that explicitly.
|
// That breaks the math above, so we have to check for that explicitly.
|
||||||
// MOVQ stackguard, CX
|
// MOVQ stackguard, SI
|
||||||
// CMPQ CX, $StackPreempt
|
// CMPQ SI, $StackPreempt
|
||||||
// JEQ label-of-call-to-morestack
|
// JEQ label-of-call-to-morestack
|
||||||
// LEAQ StackGuard(SP), AX
|
// LEAQ StackGuard(SP), AX
|
||||||
// SUBQ CX, AX
|
// SUBQ SI, AX
|
||||||
// CMPQ AX, $(framesize+(StackGuard-StackSmall))
|
// CMPQ AX, $(framesize+(StackGuard-StackSmall))
|
||||||
|
|
||||||
p = obj.Appendp(p, newprog)
|
p = obj.Appendp(p, newprog)
|
||||||
|
|
@ -1047,6 +1055,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = REG_SI
|
p.To.Reg = REG_SI
|
||||||
|
|
||||||
|
p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
|
||||||
|
|
||||||
p = obj.Appendp(p, newprog)
|
p = obj.Appendp(p, newprog)
|
||||||
p.As = cmp
|
p.As = cmp
|
||||||
p.From.Type = obj.TYPE_REG
|
p.From.Type = obj.TYPE_REG
|
||||||
|
|
@ -1090,6 +1100,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
||||||
jls.As = AJLS
|
jls.As = AJLS
|
||||||
jls.To.Type = obj.TYPE_BRANCH
|
jls.To.Type = obj.TYPE_BRANCH
|
||||||
|
|
||||||
|
end := ctxt.EndUnsafePoint(jls, newprog, -1)
|
||||||
|
|
||||||
var last *obj.Prog
|
var last *obj.Prog
|
||||||
for last = cursym.Func.Text; last.Link != nil; last = last.Link {
|
for last = cursym.Func.Text; last.Link != nil; last = last.Link {
|
||||||
}
|
}
|
||||||
|
|
@ -1101,7 +1113,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
||||||
spfix.As = obj.ANOP
|
spfix.As = obj.ANOP
|
||||||
spfix.Spadj = -framesize
|
spfix.Spadj = -framesize
|
||||||
|
|
||||||
pcdata := ctxt.EmitEntryLiveness(cursym, spfix, newprog)
|
pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
|
||||||
|
pcdata = ctxt.StartUnsafePoint(pcdata, newprog)
|
||||||
|
|
||||||
call := obj.Appendp(pcdata, newprog)
|
call := obj.Appendp(pcdata, newprog)
|
||||||
call.Pos = cursym.Func.Text.Pos
|
call.Pos = cursym.Func.Text.Pos
|
||||||
|
|
@ -1126,7 +1139,9 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
||||||
progedit(ctxt, callend.Link, newprog)
|
progedit(ctxt, callend.Link, newprog)
|
||||||
}
|
}
|
||||||
|
|
||||||
jmp := obj.Appendp(callend, newprog)
|
pcdata = ctxt.EndUnsafePoint(callend, newprog, -1)
|
||||||
|
|
||||||
|
jmp := obj.Appendp(pcdata, newprog)
|
||||||
jmp.As = obj.AJMP
|
jmp.As = obj.AJMP
|
||||||
jmp.To.Type = obj.TYPE_BRANCH
|
jmp.To.Type = obj.TYPE_BRANCH
|
||||||
jmp.Pcond = cursym.Func.Text.Link
|
jmp.Pcond = cursym.Func.Text.Link
|
||||||
|
|
@ -1137,7 +1152,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
|
||||||
q1.Pcond = call
|
q1.Pcond = call
|
||||||
}
|
}
|
||||||
|
|
||||||
return jls
|
return end
|
||||||
}
|
}
|
||||||
|
|
||||||
var unaryDst = map[obj.As]bool{
|
var unaryDst = map[obj.As]bool{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue