inl.go 4.0 KB

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