Source file src/cmd/internal/obj/inl.go
1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package obj 6 7 import "cmd/internal/src" 8 9 // InlTree is a collection of inlined calls. The Parent field of an 10 // InlinedCall is the index of another InlinedCall in InlTree. 11 // 12 // The compiler maintains a global inlining tree and adds a node to it 13 // every time a function is inlined. For example, suppose f() calls g() 14 // and g has two calls to h(), and that f, g, and h are inlineable: 15 // 16 // 1 func main() { 17 // 2 f() 18 // 3 } 19 // 4 func f() { 20 // 5 g() 21 // 6 } 22 // 7 func g() { 23 // 8 h() 24 // 9 h() 25 // 10 } 26 // 11 func h() { 27 // 12 println("H") 28 // 13 } 29 // 30 // Assuming the global tree starts empty, inlining will produce the 31 // following tree: 32 // 33 // []InlinedCall{ 34 // {Parent: -1, Func: "f", Pos: <line 2>}, 35 // {Parent: 0, Func: "g", Pos: <line 5>}, 36 // {Parent: 1, Func: "h", Pos: <line 8>}, 37 // {Parent: 1, Func: "h", Pos: <line 9>}, 38 // } 39 // 40 // The nodes of h inlined into main will have inlining indexes 2 and 3. 41 // 42 // Eventually, the compiler extracts a per-function inlining tree from 43 // the global inlining tree (see pcln.go). 44 type InlTree struct { 45 nodes []InlinedCall 46 } 47 48 // InlinedCall is a node in an InlTree. 49 type InlinedCall struct { 50 Parent int // index of the parent in the InlTree or < 0 if outermost call 51 Pos src.XPos // position of the inlined call 52 Func *LSym // function that was inlined 53 ParentPC int32 // PC of instruction just before inlined body. Only valid in local trees. 54 } 55 56 // Add adds a new call to the tree, returning its index. 57 func (tree *InlTree) Add(parent int, pos src.XPos, func_ *LSym) int { 58 r := len(tree.nodes) 59 call := InlinedCall{ 60 Parent: parent, 61 Pos: pos, 62 Func: func_, 63 } 64 tree.nodes = append(tree.nodes, call) 65 return r 66 } 67 68 func (tree *InlTree) Parent(inlIndex int) int { 69 return tree.nodes[inlIndex].Parent 70 } 71 72 func (tree *InlTree) InlinedFunction(inlIndex int) *LSym { 73 return tree.nodes[inlIndex].Func 74 } 75 76 func (tree *InlTree) CallPos(inlIndex int) src.XPos { 77 return tree.nodes[inlIndex].Pos 78 } 79 80 func (tree *InlTree) setParentPC(inlIndex int, pc int32) { 81 tree.nodes[inlIndex].ParentPC = pc 82 } 83 84 // OutermostPos returns the outermost position corresponding to xpos, 85 // which is where xpos was ultimately inlined to. In the example for 86 // InlTree, main() contains inlined AST nodes from h(), but the 87 // outermost position for those nodes is line 2. 88 func (ctxt *Link) OutermostPos(xpos src.XPos) src.Pos { 89 pos := ctxt.InnermostPos(xpos) 90 91 outerxpos := xpos 92 for ix := pos.Base().InliningIndex(); ix >= 0; { 93 call := ctxt.InlTree.nodes[ix] 94 ix = call.Parent 95 outerxpos = call.Pos 96 } 97 return ctxt.PosTable.Pos(outerxpos) 98 } 99 100 // InnermostPos returns the innermost position corresponding to xpos, 101 // that is, the code that is inlined and that inlines nothing else. 102 // In the example for InlTree above, the code for println within h 103 // would have an innermost position with line number 12, whether 104 // h was not inlined, inlined into g, g-then-f, or g-then-f-then-main. 105 // This corresponds to what someone debugging main, f, g, or h might 106 // expect to see while single-stepping. 107 func (ctxt *Link) InnermostPos(xpos src.XPos) src.Pos { 108 return ctxt.PosTable.Pos(xpos) 109 } 110 111 // AllPos returns a slice of the positions inlined at xpos, from 112 // innermost (index zero) to outermost. To avoid gratuitous allocation 113 // the result is passed in and extended if necessary. 114 func (ctxt *Link) AllPos(xpos src.XPos, result []src.Pos) []src.Pos { 115 pos := ctxt.InnermostPos(xpos) 116 result = result[:0] 117 result = append(result, ctxt.PosTable.Pos(xpos)) 118 for ix := pos.Base().InliningIndex(); ix >= 0; { 119 call := ctxt.InlTree.nodes[ix] 120 ix = call.Parent 121 result = append(result, ctxt.PosTable.Pos(call.Pos)) 122 } 123 return result 124 } 125 126 func dumpInlTree(ctxt *Link, tree InlTree) { 127 for i, call := range tree.nodes { 128 pos := ctxt.PosTable.Pos(call.Pos) 129 ctxt.Logf("%0d | %0d | %s (%s) pc=%d\n", i, call.Parent, call.Func, pos, call.ParentPC) 130 } 131 } 132