...

Source file src/pkg/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	func dumpInlTree(ctxt *Link, tree InlTree) {
   112		for i, call := range tree.nodes {
   113			pos := ctxt.PosTable.Pos(call.Pos)
   114			ctxt.Logf("%0d | %0d | %s (%s) pc=%d\n", i, call.Parent, call.Func, pos, call.ParentPC)
   115		}
   116	}
   117	

View as plain text