go/src/cmd/compile/internal/ir/abi.go
Michael Pratt f2656f20ea cmd/compile,cmd/link,runtime: add start line numbers to func metadata
This adds the function "start line number" to runtime._func and
runtime.inlinedCall objects. The "start line number" is the line number
of the func keyword or TEXT directive for assembly.

Subtracting the start line number from PC line number provides the
relative line offset of a PC from the the start of the function. This
helps with source stability by allowing code above the function to move
without invalidating samples within the function.

Encoding start line rather than relative lines directly is convenient
because the pprof format already contains a start line field.

This CL uses a straightforward encoding of explictly including a start
line field in every _func and inlinedCall. It is possible that we could
compress this further in the future. e.g., functions with a prologue
usually have <line of PC 0> == <start line>. In runtime.test, 95% of
functions have <line of PC 0> == <start line>.

According to bent, this is geomean +0.83% binary size vs master and
-0.31% binary size vs 1.19.

Note that //line directives can change the file and line numbers
arbitrarily. The encoded start line is as adjusted by //line directives.
Since this can change in the middle of a function, `line - start line`
offset calculations may not be meaningful if //line directives are in
use.

For #55022.

Change-Id: Iaabbc6dd4f85ffdda294266ef982ae838cc692f6
Reviewed-on: https://go-review.googlesource.com/c/go/+/429638
Run-TryBot: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
2022-10-14 14:47:12 +00:00

78 lines
2.1 KiB
Go

// Copyright 2022 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 ir
import (
"cmd/compile/internal/base"
"cmd/internal/obj"
)
// InitLSym defines f's obj.LSym and initializes it based on the
// properties of f. This includes setting the symbol flags and ABI and
// creating and initializing related DWARF symbols.
//
// InitLSym must be called exactly once per function and must be
// called for both functions with bodies and functions without bodies.
// For body-less functions, we only create the LSym; for functions
// with bodies call a helper to setup up / populate the LSym.
func InitLSym(f *Func, hasBody bool) {
if f.LSym != nil {
base.FatalfAt(f.Pos(), "InitLSym called twice on %v", f)
}
if nam := f.Nname; !IsBlank(nam) {
f.LSym = nam.LinksymABI(f.ABI)
if f.Pragma&Systemstack != 0 {
f.LSym.Set(obj.AttrCFunc, true)
}
}
if hasBody {
setupTextLSym(f, 0)
}
}
// setupTextLSym initializes the LSym for a with-body text symbol.
func setupTextLSym(f *Func, flag int) {
if f.Dupok() {
flag |= obj.DUPOK
}
if f.Wrapper() {
flag |= obj.WRAPPER
}
if f.ABIWrapper() {
flag |= obj.ABIWRAPPER
}
if f.Needctxt() {
flag |= obj.NEEDCTXT
}
if f.Pragma&Nosplit != 0 {
flag |= obj.NOSPLIT
}
if f.ReflectMethod() {
flag |= obj.REFLECTMETHOD
}
// Clumsy but important.
// For functions that could be on the path of invoking a deferred
// function that can recover (runtime.reflectcall, reflect.callReflect,
// and reflect.callMethod), we want the panic+recover special handling.
// See test/recover.go for test cases and src/reflect/value.go
// for the actual functions being considered.
//
// runtime.reflectcall is an assembly function which tailcalls
// WRAPPER functions (runtime.callNN). Its ABI wrapper needs WRAPPER
// flag as well.
fnname := f.Sym().Name
if base.Ctxt.Pkgpath == "runtime" && fnname == "reflectcall" {
flag |= obj.WRAPPER
} else if base.Ctxt.Pkgpath == "reflect" {
switch fnname {
case "callReflect", "callMethod":
flag |= obj.WRAPPER
}
}
base.Ctxt.InitTextSym(f.LSym, flag, f.Pos())
}