| // 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) | 
 | 	} | 
 | } |