diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 48f813a48f..f31cf29925 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -7120,6 +7120,8 @@ func genssa(f *ssa.Func, pp *objw.Progs) { } if inlMarks != nil { + hasCall := false + // We have some inline marks. Try to find other instructions we're // going to emit anyway, and use those instructions instead of the // inline marks. @@ -7137,6 +7139,9 @@ func genssa(f *ssa.Func, pp *objw.Progs) { // whether they will be zero-sized or not yet. continue } + if p.As == obj.ACALL || p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { + hasCall = true + } pos := p.Pos.AtColumn1() s := inlMarksByPos[pos] if len(s) == 0 { @@ -7162,6 +7167,45 @@ func genssa(f *ssa.Func, pp *objw.Progs) { pp.CurFunc.LSym.Func().AddInlMark(p, inlMarks[p]) } } + + if e.stksize == 0 && !hasCall { + // Frameless leaf function. It doesn't need any preamble, + // so make sure its first instruction isn't from an inlined callee. + // If it is, add a nop at the start of the function with a position + // equal to the start of the function. + // This ensures that runtime.FuncForPC(uintptr(reflect.ValueOf(fn).Pointer())).Name() + // returns the right answer. See issue 58300. + for p := pp.Text; p != nil; p = p.Link { + if p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT { + continue + } + if base.Ctxt.PosTable.Pos(p.Pos).Base().InliningIndex() >= 0 { + // Make a real (not 0-sized) nop. + nop := Arch.Ginsnop(pp) + nop.Pos = e.curfn.Pos().WithIsStmt() + + // Unfortunately, Ginsnop puts the instruction at the + // end of the list. Move it up to just before p. + + // Unlink from the current list. + for x := pp.Text; x != nil; x = x.Link { + if x.Link == nop { + x.Link = nop.Link + break + } + } + // Splice in right before p. + for x := pp.Text; x != nil; x = x.Link { + if x.Link == p { + nop.Link = p + x.Link = nop + break + } + } + } + break + } + } } if base.Ctxt.Flag_locationlists { diff --git a/test/fixedbugs/issue58300.go b/test/fixedbugs/issue58300.go new file mode 100644 index 0000000000..fff3d211f3 --- /dev/null +++ b/test/fixedbugs/issue58300.go @@ -0,0 +1,29 @@ +// run + +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "reflect" + "runtime" +) + +func f(n int) int { + return n % 2 +} + +func g(n int) int { + return f(n) +} + +func name(fn any) (res string) { + return runtime.FuncForPC(uintptr(reflect.ValueOf(fn).Pointer())).Name() +} + +func main() { + println(name(f)) + println(name(g)) +} diff --git a/test/fixedbugs/issue58300.out b/test/fixedbugs/issue58300.out new file mode 100644 index 0000000000..f347287480 --- /dev/null +++ b/test/fixedbugs/issue58300.out @@ -0,0 +1,2 @@ +main.f +main.g