compiler,linker: support for DWARF inlined instances Compiler and linker changes to support DWARF inlined instances, see https://go.googlesource.com/proposal/+/HEAD/design/22080-dwarf-inlining.md for design details. This functionality is gated via the cmd/compile option -gendwarfinl=N, where N={0,1,2}, where a value of 0 disables dwarf inline generation, a value of 1 turns on dwarf generation without tracking of formal/local vars from inlined routines, and a value of 2 enables inlines with variable tracking. Updates #22080 Change-Id: I69309b3b815d9fed04aebddc0b8d33d0dbbfad6e Reviewed-on: https://go-review.googlesource.com/75550 Run-TryBot: Than McIntosh <thanm@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index e54bb97..0e8ef19 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go
@@ -31,8 +31,11 @@ import ( "cmd/compile/internal/types" + "cmd/internal/obj" "cmd/internal/src" "fmt" + "sort" + "strings" ) // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods @@ -809,6 +812,9 @@ // Make temp names to use instead of the originals. inlvars := make(map[*Node]*Node) + // record formals/locals for later post-processing + var inlfvars []*Node + // Find declarations corresponding to inlineable body. var dcl []*Node if fn.Name.Defn != nil { @@ -867,13 +873,25 @@ if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM { ninit.Append(nod(ODCL, inlvars[ln], nil)) } + if genDwarfInline > 0 { + inlf := inlvars[ln] + if ln.Class() == PPARAM { + inlf.SetInlFormal(true) + } else { + inlf.SetInlLocal(true) + } + inlf.Pos = ln.Pos + inlfvars = append(inlfvars, inlf) + } } // temporaries for return values. var retvars []*Node for i, t := range fn.Type.Results().Fields().Slice() { var m *Node + var mpos src.XPos if t != nil && asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) { + mpos = asNode(t.Nname).Pos m = inlvar(asNode(t.Nname)) m = typecheck(m, Erv) inlvars[asNode(t.Nname)] = m @@ -882,6 +900,17 @@ m = retvar(t, i) } + if genDwarfInline > 0 { + // Don't update the src.Pos on a return variable if it + // was manufactured by the inliner (e.g. "~r2"); such vars + // were not part of the original callee. + if !strings.HasPrefix(m.Sym.Name, "~r") { + m.SetInlFormal(true) + m.Pos = mpos + inlfvars = append(inlfvars, m) + } + } + ninit.Append(nod(ODCL, m, nil)) retvars = append(retvars, m) } @@ -976,8 +1005,16 @@ if b := Ctxt.PosTable.Pos(n.Pos).Base(); b != nil { parent = b.InliningIndex() } + sort.Sort(byNodeName(dcl)) newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym()) + if genDwarfInline > 0 { + if !fn.Sym.Linksym().WasInlined() { + Ctxt.DwFixups.SetPrecursorFunc(fn.Sym.Linksym(), fn) + fn.Sym.Linksym().Set(obj.AttrWasInlined, true) + } + } + subst := inlsubst{ retlabel: retlabel, retvars: retvars, @@ -993,6 +1030,12 @@ typecheckslice(body, Etop) + if genDwarfInline > 0 { + for _, v := range inlfvars { + v.Pos = subst.updatedPos(v.Pos) + } + } + //dumplist("ninit post", ninit); call := nod(OINLCALL, nil, nil) @@ -1192,3 +1235,28 @@ pos.SetBase(newbase) return Ctxt.PosTable.XPos(pos) } + +func cmpNodeName(a, b *Node) bool { + // named before artificial + aart := 0 + if strings.HasPrefix(a.Sym.Name, "~r") { + aart = 1 + } + bart := 0 + if strings.HasPrefix(b.Sym.Name, "~r") { + bart = 1 + } + if aart != bart { + return aart < bart + } + + // otherwise sort by name + return a.Sym.Name < b.Sym.Name +} + +// byNodeName implements sort.Interface for []*Node using cmpNodeName. +type byNodeName []*Node + +func (s byNodeName) Len() int { return len(s) } +func (s byNodeName) Less(i, j int) bool { return cmpNodeName(s[i], s[j]) } +func (s byNodeName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }