n := nod(ORETJMP, nil, nil)
n.Left = newname(methodsym(method.Sym, methodrcvr, 0))
fn.Nbody.Append(n)
+ // When tail-calling, we can't use a frame pointer.
+ fn.Func.NoFramePointer = true
} else {
fn.Func.Wrapper = true // ignore frame for panic+recover matching
call := nod(OCALL, dot, nil)
autoffset = 0
}
+ hasCall := false
+ for q := p; q != nil; q = q.Link {
+ if q.As == obj.ACALL || q.As == obj.ADUFFCOPY || q.As == obj.ADUFFZERO {
+ hasCall = true
+ break
+ }
+ }
+
var bpsize int
- if p.Mode == 64 && ctxt.Framepointer_enabled && autoffset > 0 && p.From3.Offset&obj.NOFRAME == 0 {
- // Make room for to save a base pointer. If autoffset == 0,
- // this might do something special like a tail jump to
- // another function, so in that case we omit this.
+ if p.Mode == 64 && ctxt.Framepointer_enabled &&
+ p.From3.Offset&obj.NOFRAME == 0 && // (1) below
+ !(autoffset == 0 && p.From3.Offset&obj.NOSPLIT != 0) && // (2) below
+ !(autoffset == 0 && !hasCall) { // (3) below
+ // Make room to save a base pointer.
+ // There are 2 cases we must avoid:
+ // 1) If noframe is set (which we do for functions which tail call).
+ // 2) Scary runtime internals which would be all messed up by frame pointers.
+ // We detect these using a heuristic: frameless nosplit functions.
+ // TODO: Maybe someday we label them all with NOFRAME and get rid of this heuristic.
+ // For performance, we also want to avoid:
+ // 3) Frameless leaf functions
bpsize = ctxt.Arch.PtrSize
autoffset += int32(bpsize)
p.To.Offset += int64(bpsize)