mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
cmd/compile: ensure first instruction in a function is not inlined
People are using this to get the name of the function from a function type: runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() Unfortunately, this technique falls down when the first instruction of the function is from an inlined callee. Then the expression above gets you the name of the inlined function instead of the function itself. To fix this, ensure that the first instruction is never from an inlinee. Normally functions have prologs so those are already fine. In just the cases where a function is a leaf with no local variables, and an instruction from an inlinee appears first in the prog list, add a nop at the start of the function to hold a non-inlined position. Consider the nop a "mini-prolog" for leaf functions. Fixes #58300 Change-Id: Ie37092f4ac3167fe8e5ef4a2207b14abc1786897 Reviewed-on: https://go-review.googlesource.com/c/go/+/465076 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
55bd193575
commit
103f37497f
@ -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 {
|
||||
|
29
test/fixedbugs/issue58300.go
Normal file
29
test/fixedbugs/issue58300.go
Normal file
@ -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))
|
||||
}
|
2
test/fixedbugs/issue58300.out
Normal file
2
test/fixedbugs/issue58300.out
Normal file
@ -0,0 +1,2 @@
|
||||
main.f
|
||||
main.g
|
Loading…
x
Reference in New Issue
Block a user