-
Notifications
You must be signed in to change notification settings - Fork 17.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the inlined call stack for a given PC. This creates two tables per function for this purpose. The first table is the inlining tree (stored in the function's funcdata), which has a node containing the file, line, and function name for every inlined call. The second table is a PC-value table that maps each PC to a node in the inlining tree (or -1 if the PC is not the result of inlining). To give the appearance that inlining hasn't happened, the runtime also needs the original source position information of inlined AST nodes. Previously the compiler plastered over the line numbers of inlined AST nodes with the line number of the call. This meant that the PC-line table mapped each PC to line number of the outermost call in its inlined call stack, with no way to access the innermost line number. Now the compiler retains line numbers of inlined AST nodes and writes the innermost source position information to the PC-line and PC-file tables. Some tools and tests expect to see outermost line numbers, so we provide the OutermostLine function for displaying line info. To keep track of the inlined call stack for an AST node, we extend the src.PosBase type with an index into a global inlining tree. Every time the compiler inlines a call, it creates a node in the global inlining tree for the call, and writes its index to the PosBase of every inlined AST node. The parent of this node is the inlining tree index of the call. -1 signifies no parent. For each function, the compiler creates a local inlining tree and a PC-value table mapping each PC to an index in the local tree. These are written to an object file, which is read by the linker. The linker re-encodes these tables compactly by deduplicating function names and file names. This change increases the size of binaries by 4-5%. For example, this is how the go1 benchmark binary is impacted by this change: section old bytes new bytes delta .text 3.49M ± 0% 3.49M ± 0% +0.06% .rodata 1.12M ± 0% 1.21M ± 0% +8.21% .gopclntab 1.50M ± 0% 1.68M ± 0% +11.89% .debug_line 338k ± 0% 435k ± 0% +28.78% Total 9.21M ± 0% 9.58M ± 0% +4.01% Updates #19348. Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3 Reviewed-on: https://go-review.googlesource.com/37231 Run-TryBot: David Lazar <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Austin Clements <[email protected]>
- Loading branch information
1 parent
ed70f37
commit 699175a
Showing
17 changed files
with
354 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// 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 s 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 } | ||
// | ||
// 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 | ||
} | ||
|
||
// Add adds a new call to the tree, returning its index. | ||
func (tree *InlTree) Add(parent int, pos src.XPos, func_ *LSym) int { | ||
r := len(tree.nodes) | ||
call := InlinedCall{ | ||
Parent: parent, | ||
Pos: pos, | ||
Func: func_, | ||
} | ||
tree.nodes = append(tree.nodes, call) | ||
return r | ||
} | ||
|
||
// 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.PosTable.Pos(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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.