diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:25:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:25:22 +0000 |
commit | f6ad4dcef54c5ce997a4bad5a6d86de229015700 (patch) | |
tree | 7cfa4e31ace5c2bd95c72b154d15af494b2bcbef /src/cmd/internal/obj/inl.go | |
parent | Initial commit. (diff) | |
download | golang-1.22-f6ad4dcef54c5ce997a4bad5a6d86de229015700.tar.xz golang-1.22-f6ad4dcef54c5ce997a4bad5a6d86de229015700.zip |
Adding upstream version 1.22.1.upstream/1.22.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cmd/internal/obj/inl.go')
-rw-r--r-- | src/cmd/internal/obj/inl.go | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/cmd/internal/obj/inl.go b/src/cmd/internal/obj/inl.go new file mode 100644 index 0000000..6874471 --- /dev/null +++ b/src/cmd/internal/obj/inl.go @@ -0,0 +1,143 @@ +// Copyright 2017 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 obj + +import "cmd/internal/src" + +// InlTree is a collection of inlined calls. The Parent field of an +// InlinedCall is the index of another InlinedCall in InlTree. +// +// The compiler maintains a global inlining tree and adds a node to it +// every time a function is inlined. For example, suppose f() calls g() +// and g has two calls to h(), and that f, g, and h are inlineable: +// +// 1 func main() { +// 2 f() +// 3 } +// 4 func f() { +// 5 g() +// 6 } +// 7 func g() { +// 8 h() +// 9 h() +// 10 } +// 11 func h() { +// 12 println("H") +// 13 } +// +// Assuming the global tree starts empty, inlining will produce the +// following tree: +// +// []InlinedCall{ +// {Parent: -1, Func: "f", Pos: <line 2>}, +// {Parent: 0, Func: "g", Pos: <line 5>}, +// {Parent: 1, Func: "h", Pos: <line 8>}, +// {Parent: 1, Func: "h", Pos: <line 9>}, +// } +// +// The nodes of h inlined into main will have inlining indexes 2 and 3. +// +// Eventually, the compiler extracts a per-function inlining tree from +// the global inlining tree (see pcln.go). +type InlTree struct { + nodes []InlinedCall +} + +// InlinedCall is a node in an InlTree. +type InlinedCall struct { + Parent int // index of the parent in the InlTree or < 0 if outermost call + Pos src.XPos // position of the inlined call + Func *LSym // function that was inlined + Name string // bare name of the function (w/o package prefix) + ParentPC int32 // PC of instruction just before inlined body. Only valid in local trees. +} + +// Add adds a new call to the tree, returning its index. +func (tree *InlTree) Add(parent int, pos src.XPos, func_ *LSym, name string) int { + r := len(tree.nodes) + call := InlinedCall{ + Parent: parent, + Pos: pos, + Func: func_, + Name: name, + } + tree.nodes = append(tree.nodes, call) + return r +} + +// AllParents invokes do on each InlinedCall in the inlining call +// stack, from outermost to innermost. +// +// That is, if inlIndex corresponds to f inlining g inlining h, +// AllParents invokes do with the call for inlining g into f, and then +// inlining h into g. +func (tree *InlTree) AllParents(inlIndex int, do func(InlinedCall)) { + if inlIndex >= 0 { + call := tree.nodes[inlIndex] + tree.AllParents(call.Parent, do) + do(call) + } +} + +func (tree *InlTree) Parent(inlIndex int) int { + return tree.nodes[inlIndex].Parent +} + +func (tree *InlTree) InlinedFunction(inlIndex int) *LSym { + return tree.nodes[inlIndex].Func +} + +func (tree *InlTree) CallPos(inlIndex int) src.XPos { + return tree.nodes[inlIndex].Pos +} + +func (tree *InlTree) setParentPC(inlIndex int, pc int32) { + tree.nodes[inlIndex].ParentPC = pc +} + +// OutermostPos returns the outermost position corresponding to xpos, +// which is where xpos was ultimately inlined to. In the example for +// InlTree, main() contains inlined AST nodes from h(), but the +// outermost position for those nodes is line 2. +func (ctxt *Link) OutermostPos(xpos src.XPos) src.Pos { + pos := ctxt.InnermostPos(xpos) + + outerxpos := xpos + for ix := pos.Base().InliningIndex(); ix >= 0; { + call := ctxt.InlTree.nodes[ix] + ix = call.Parent + outerxpos = call.Pos + } + return ctxt.PosTable.Pos(outerxpos) +} + +// InnermostPos returns the innermost position corresponding to xpos, +// that is, the code that is inlined and that inlines nothing else. +// In the example for InlTree above, the code for println within h +// would have an innermost position with line number 12, whether +// h was not inlined, inlined into g, g-then-f, or g-then-f-then-main. +// This corresponds to what someone debugging main, f, g, or h might +// expect to see while single-stepping. +func (ctxt *Link) InnermostPos(xpos src.XPos) src.Pos { + return ctxt.PosTable.Pos(xpos) +} + +// AllPos invokes do with every position in the inlining call stack for xpos, +// from outermost to innermost. That is, xpos corresponds to f inlining g inlining h, +// AllPos invokes do with the position in f, then the position in g, then the position in h. +func (ctxt *Link) AllPos(xpos src.XPos, do func(src.Pos)) { + pos := ctxt.InnermostPos(xpos) + ctxt.InlTree.AllParents(pos.Base().InliningIndex(), func(call InlinedCall) { + do(ctxt.InnermostPos(call.Pos)) + }) + do(pos) +} + +func dumpInlTree(ctxt *Link, tree InlTree) { + for i, call := range tree.nodes { + pos := ctxt.PosTable.Pos(call.Pos) + ctxt.Logf("%0d | %0d | %s (%s) pc=%d\n", i, call.Parent, call.Func, pos, call.ParentPC) + } +} |