summaryrefslogtreecommitdiffstats
path: root/src/cmd/internal/obj/inl.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:25:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:25:22 +0000
commitf6ad4dcef54c5ce997a4bad5a6d86de229015700 (patch)
tree7cfa4e31ace5c2bd95c72b154d15af494b2bcbef /src/cmd/internal/obj/inl.go
parentInitial commit. (diff)
downloadgolang-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.go143
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)
+ }
+}