2016-03-01 22:57:46 +00:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
2015-01-19 14:34:58 -05:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package obj
|
|
|
|
|
|
2018-02-13 17:39:38 -05:00
|
|
|
import (
|
|
|
|
|
"cmd/internal/src"
|
|
|
|
|
"log"
|
|
|
|
|
)
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2016-12-07 22:09:15 -08:00
|
|
|
func addvarint(d *Pcdata, v uint32) {
|
|
|
|
|
for ; v >= 0x80; v >>= 7 {
|
2015-01-19 14:34:58 -05:00
|
|
|
d.P = append(d.P, uint8(v|0x80))
|
|
|
|
|
}
|
|
|
|
|
d.P = append(d.P, uint8(v))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// funcpctab writes to dst a pc-value table mapping the code in func to the values
|
|
|
|
|
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
|
|
|
|
|
// current value is, for each p,
|
|
|
|
|
//
|
|
|
|
|
// val = valfunc(func, val, p, 0, arg);
|
|
|
|
|
// record val as value at p->pc;
|
|
|
|
|
// val = valfunc(func, val, p, 1, arg);
|
|
|
|
|
//
|
|
|
|
|
// where func is the function, val is the current value, p is the instruction being
|
|
|
|
|
// considered, and arg can be used to further parameterize valfunc.
|
|
|
|
|
func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
|
2017-02-17 16:55:40 -05:00
|
|
|
dbg := desc == ctxt.Debugpcln
|
2015-01-19 14:34:58 -05:00
|
|
|
|
|
|
|
|
dst.P = dst.P[:0]
|
|
|
|
|
|
2017-02-17 16:55:40 -05:00
|
|
|
if dbg {
|
2016-08-25 12:32:42 +10:00
|
|
|
ctxt.Logf("funcpctab %s [valfunc=%s]\n", func_.Name, desc)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
val := int32(-1)
|
|
|
|
|
oldval := val
|
2017-04-18 10:18:34 -07:00
|
|
|
if func_.Func.Text == nil {
|
2015-01-19 14:34:58 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-18 10:18:34 -07:00
|
|
|
pc := func_.Func.Text.Pc
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2017-02-17 16:55:40 -05:00
|
|
|
if dbg {
|
2017-04-18 10:18:34 -07:00
|
|
|
ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Func.Text)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-07 10:44:12 -08:00
|
|
|
started := false
|
2015-02-23 16:07:24 -05:00
|
|
|
var delta uint32
|
2017-04-18 10:18:34 -07:00
|
|
|
for p := func_.Func.Text; p != nil; p = p.Link {
|
2015-01-19 14:34:58 -05:00
|
|
|
// Update val. If it's not changing, keep going.
|
|
|
|
|
val = valfunc(ctxt, func_, val, p, 0, arg)
|
|
|
|
|
|
2017-03-07 10:44:12 -08:00
|
|
|
if val == oldval && started {
|
2015-01-19 14:34:58 -05:00
|
|
|
val = valfunc(ctxt, func_, val, p, 1, arg)
|
2017-02-17 16:55:40 -05:00
|
|
|
if dbg {
|
2016-08-25 12:32:42 +10:00
|
|
|
ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the pc of the next instruction is the same as the
|
|
|
|
|
// pc of this instruction, this instruction is not a real
|
|
|
|
|
// instruction. Keep going, so that we only emit a delta
|
|
|
|
|
// for a true instruction boundary in the program.
|
|
|
|
|
if p.Link != nil && p.Link.Pc == p.Pc {
|
|
|
|
|
val = valfunc(ctxt, func_, val, p, 1, arg)
|
2017-02-17 16:55:40 -05:00
|
|
|
if dbg {
|
2016-08-25 12:32:42 +10:00
|
|
|
ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The table is a sequence of (value, pc) pairs, where each
|
|
|
|
|
// pair states that the given value is in effect from the current position
|
|
|
|
|
// up to the given pc, which becomes the new current position.
|
|
|
|
|
// To generate the table as we scan over the program instructions,
|
|
|
|
|
// we emit a "(value" when pc == func->value, and then
|
|
|
|
|
// each time we observe a change in value we emit ", pc) (value".
|
|
|
|
|
// When the scan is over, we emit the closing ", pc)".
|
|
|
|
|
//
|
|
|
|
|
// The table is delta-encoded. The value deltas are signed and
|
|
|
|
|
// transmitted in zig-zag form, where a complement bit is placed in bit 0,
|
|
|
|
|
// and the pc deltas are unsigned. Both kinds of deltas are sent
|
|
|
|
|
// as variable-length little-endian base-128 integers,
|
|
|
|
|
// where the 0x80 bit indicates that the integer continues.
|
|
|
|
|
|
2017-02-17 16:55:40 -05:00
|
|
|
if dbg {
|
2016-08-25 12:32:42 +10:00
|
|
|
ctxt.Logf("%6x %6d %v\n", uint64(p.Pc), val, p)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-07 10:44:12 -08:00
|
|
|
if started {
|
2016-12-07 22:09:15 -08:00
|
|
|
addvarint(dst, uint32((p.Pc-pc)/int64(ctxt.Arch.MinLC)))
|
2015-01-19 14:34:58 -05:00
|
|
|
pc = p.Pc
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delta = uint32(val) - uint32(oldval)
|
|
|
|
|
if delta>>31 != 0 {
|
|
|
|
|
delta = 1 | ^(delta << 1)
|
|
|
|
|
} else {
|
|
|
|
|
delta <<= 1
|
|
|
|
|
}
|
2016-12-07 22:09:15 -08:00
|
|
|
addvarint(dst, delta)
|
2015-01-19 14:34:58 -05:00
|
|
|
oldval = val
|
2017-03-07 10:44:12 -08:00
|
|
|
started = true
|
2015-01-19 14:34:58 -05:00
|
|
|
val = valfunc(ctxt, func_, val, p, 1, arg)
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-07 10:44:12 -08:00
|
|
|
if started {
|
2017-02-17 16:55:40 -05:00
|
|
|
if dbg {
|
2017-04-18 10:18:34 -07:00
|
|
|
ctxt.Logf("%6x done\n", uint64(func_.Func.Text.Pc+func_.Size))
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-12-07 22:09:15 -08:00
|
|
|
addvarint(dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
|
|
|
|
|
addvarint(dst, 0) // terminator
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2017-02-17 16:55:40 -05:00
|
|
|
if dbg {
|
2016-08-25 12:32:42 +10:00
|
|
|
ctxt.Logf("wrote %d bytes to %p\n", len(dst.P), dst)
|
2015-02-23 16:07:24 -05:00
|
|
|
for i := 0; i < len(dst.P); i++ {
|
2016-08-25 12:32:42 +10:00
|
|
|
ctxt.Logf(" %02x", dst.P[i])
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-08-25 12:32:42 +10:00
|
|
|
ctxt.Logf("\n")
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pctofileline computes either the file number (arg == 0)
|
|
|
|
|
// or the line number (arg == 1) to use at p.
|
2016-12-09 14:30:40 -05:00
|
|
|
// Because p.Pos applies to p, phase == 0 (before p)
|
2015-01-19 14:34:58 -05:00
|
|
|
// takes care of the update.
|
|
|
|
|
func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
|
2017-03-03 14:27:24 -08:00
|
|
|
if p.As == ATEXT || p.As == ANOP || p.Pos.Line() == 0 || phase == 1 {
|
2015-01-19 14:34:58 -05:00
|
|
|
return oldval
|
|
|
|
|
}
|
2016-12-09 17:15:05 -08:00
|
|
|
f, l := linkgetlineFromPos(ctxt, p.Pos)
|
2015-01-19 14:34:58 -05:00
|
|
|
if arg == nil {
|
|
|
|
|
return l
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
pcln := arg.(*Pcln)
|
2015-01-19 14:34:58 -05:00
|
|
|
|
|
|
|
|
if f == pcln.Lastfile {
|
|
|
|
|
return int32(pcln.Lastindex)
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-14 19:44:55 -07:00
|
|
|
for i, file := range pcln.File {
|
2015-01-19 14:34:58 -05:00
|
|
|
if file == f {
|
|
|
|
|
pcln.Lastfile = f
|
2016-04-14 19:44:55 -07:00
|
|
|
pcln.Lastindex = i
|
|
|
|
|
return int32(i)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
2016-04-14 19:44:55 -07:00
|
|
|
i := len(pcln.File)
|
2015-01-19 14:34:58 -05:00
|
|
|
pcln.File = append(pcln.File, f)
|
|
|
|
|
pcln.Lastfile = f
|
2016-04-14 19:44:55 -07:00
|
|
|
pcln.Lastindex = i
|
|
|
|
|
return int32(i)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
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 <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
// pcinlineState holds the state used to create a function's inlining
|
|
|
|
|
// tree and the PC-value table that maps PCs to nodes in that tree.
|
|
|
|
|
type pcinlineState struct {
|
|
|
|
|
globalToLocal map[int]int
|
|
|
|
|
localTree InlTree
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// addBranch adds a branch from the global inlining tree in ctxt to
|
|
|
|
|
// the function's local inlining tree, returning the index in the local tree.
|
|
|
|
|
func (s *pcinlineState) addBranch(ctxt *Link, globalIndex int) int {
|
|
|
|
|
if globalIndex < 0 {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
localIndex, ok := s.globalToLocal[globalIndex]
|
|
|
|
|
if ok {
|
|
|
|
|
return localIndex
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Since tracebacks don't include column information, we could
|
|
|
|
|
// use one node for multiple calls of the same function on the
|
|
|
|
|
// same line (e.g., f(x) + f(y)). For now, we use one node for
|
|
|
|
|
// each inlined call.
|
|
|
|
|
call := ctxt.InlTree.nodes[globalIndex]
|
|
|
|
|
call.Parent = s.addBranch(ctxt, call.Parent)
|
|
|
|
|
localIndex = len(s.localTree.nodes)
|
|
|
|
|
s.localTree.nodes = append(s.localTree.nodes, call)
|
|
|
|
|
s.globalToLocal[globalIndex] = localIndex
|
|
|
|
|
return localIndex
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pctoinline computes the index into the local inlining tree to use at p.
|
|
|
|
|
// If p is not the result of inlining, pctoinline returns -1. Because p.Pos
|
|
|
|
|
// applies to p, phase == 0 (before p) takes care of the update.
|
|
|
|
|
func (s *pcinlineState) pctoinline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
|
|
|
|
|
if phase == 1 {
|
|
|
|
|
return oldval
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
posBase := ctxt.PosTable.Pos(p.Pos).Base()
|
|
|
|
|
if posBase == nil {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
globalIndex := posBase.InliningIndex()
|
|
|
|
|
if globalIndex < 0 {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if s.globalToLocal == nil {
|
|
|
|
|
s.globalToLocal = make(map[int]int)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return int32(s.addBranch(ctxt, globalIndex))
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-19 14:34:58 -05:00
|
|
|
// pctospadj computes the sp adjustment in effect.
|
|
|
|
|
// It is oldval plus any adjustment made by p itself.
|
|
|
|
|
// The adjustment by p takes effect only after p, so we
|
|
|
|
|
// apply the change during phase == 1.
|
|
|
|
|
func pctospadj(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
|
|
|
|
|
if oldval == -1 { // starting
|
|
|
|
|
oldval = 0
|
|
|
|
|
}
|
|
|
|
|
if phase == 0 {
|
|
|
|
|
return oldval
|
|
|
|
|
}
|
|
|
|
|
if oldval+p.Spadj < -10000 || oldval+p.Spadj > 1100000000 {
|
|
|
|
|
ctxt.Diag("overflow in spadj: %d + %d = %d", oldval, p.Spadj, oldval+p.Spadj)
|
2017-10-10 17:43:41 -07:00
|
|
|
ctxt.DiagFlush()
|
2015-01-19 14:34:58 -05:00
|
|
|
log.Fatalf("bad code")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return oldval + p.Spadj
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 17:39:38 -05:00
|
|
|
// pctostmt returns either,
|
|
|
|
|
// if phase==0, then whether the current instruction is a step-target (Dwarf is_stmt)
|
|
|
|
|
// else (phase == 1), zero.
|
|
|
|
|
//
|
|
|
|
|
func pctostmt(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
|
|
|
|
|
if phase == 1 {
|
|
|
|
|
return 0 // Ignored; also different from initial value of -1, if that ever matters.
|
|
|
|
|
}
|
|
|
|
|
s := p.Pos.IsStmt()
|
|
|
|
|
if s == src.PosIsStmt {
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
if s == src.PosNotStmt { // includes NoSrcPos case
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
// Line numbers in .s files will have no special setting, therefore default to is_stmt=1.
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-19 14:34:58 -05:00
|
|
|
// pctopcdata computes the pcdata value in effect at p.
|
|
|
|
|
// A PCDATA instruction sets the value in effect at future
|
|
|
|
|
// non-PCDATA instructions.
|
|
|
|
|
// Since PCDATA instructions have no width in the final code,
|
|
|
|
|
// it does not matter which phase we use for the update.
|
|
|
|
|
func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
|
[dev.cc] cmd/internal/obj: reconvert from liblink
cmd/internal/obj reconverted using rsc.io/c2go rev 2a95256.
- Brings in new, more regular Prog, Addr definitions
- Add Prog* argument to oclass in liblink/asm[68].c, for c2go conversion.
- Update objwriter for change in TEXT size encoding.
- Merge 5a, 6a, 8a, 9a changes into new5a, new6a, new8a, new9a (by hand).
- Add +build ignore to cmd/asm/internal/{addr,arch,asm}, cmd/asm.
They need to be updated for the changes.
- Reenable verifyAsm in cmd/go.
- Reenable GOOBJ=2 mode by default in liblink.
All architectures build successfully again.
Change-Id: I2c845c5d365aa484b570476898171bee657b626d
Reviewed-on: https://go-review.googlesource.com/3963
Reviewed-by: Rob Pike <r@golang.org>
2015-02-05 03:57:44 -05:00
|
|
|
if phase == 0 || p.As != APCDATA || p.From.Offset != int64(arg.(uint32)) {
|
2015-01-19 14:34:58 -05:00
|
|
|
return oldval
|
|
|
|
|
}
|
|
|
|
|
if int64(int32(p.To.Offset)) != p.To.Offset {
|
|
|
|
|
ctxt.Diag("overflow in PCDATA instruction: %v", p)
|
2017-10-10 17:43:41 -07:00
|
|
|
ctxt.DiagFlush()
|
2015-01-19 14:34:58 -05:00
|
|
|
log.Fatalf("bad code")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return int32(p.To.Offset)
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 17:39:38 -05:00
|
|
|
// stmtData writes out pc-linked is_stmt data for eventual use in the DWARF line numbering table.
|
|
|
|
|
func stmtData(ctxt *Link, cursym *LSym) {
|
|
|
|
|
var pctostmtData Pcdata
|
|
|
|
|
funcpctab(ctxt, &pctostmtData, cursym, "pctostmt", pctostmt, nil)
|
|
|
|
|
cursym.Func.dwarfIsStmtSym.P = pctostmtData.P
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-19 14:34:58 -05:00
|
|
|
func linkpcln(ctxt *Link, cursym *LSym) {
|
2017-04-18 10:18:34 -07:00
|
|
|
pcln := &cursym.Func.Pcln
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
npcdata := 0
|
|
|
|
|
nfuncdata := 0
|
2017-04-18 10:18:34 -07:00
|
|
|
for p := cursym.Func.Text; p != nil; p = p.Link {
|
2016-10-02 17:10:13 -04:00
|
|
|
// Find the highest ID of any used PCDATA table. This ignores PCDATA table
|
|
|
|
|
// that consist entirely of "-1", since that's the assumed default value.
|
|
|
|
|
// From.Offset is table ID
|
|
|
|
|
// To.Offset is data
|
|
|
|
|
if p.As == APCDATA && p.From.Offset >= int64(npcdata) && p.To.Offset != -1 { // ignore -1 as we start at -1, if we only see -1, nothing changed
|
2015-01-19 14:34:58 -05:00
|
|
|
npcdata = int(p.From.Offset + 1)
|
|
|
|
|
}
|
2016-10-02 17:10:13 -04:00
|
|
|
// Find the highest ID of any FUNCDATA table.
|
|
|
|
|
// From.Offset is table ID
|
[dev.cc] cmd/internal/obj: reconvert from liblink
cmd/internal/obj reconverted using rsc.io/c2go rev 2a95256.
- Brings in new, more regular Prog, Addr definitions
- Add Prog* argument to oclass in liblink/asm[68].c, for c2go conversion.
- Update objwriter for change in TEXT size encoding.
- Merge 5a, 6a, 8a, 9a changes into new5a, new6a, new8a, new9a (by hand).
- Add +build ignore to cmd/asm/internal/{addr,arch,asm}, cmd/asm.
They need to be updated for the changes.
- Reenable verifyAsm in cmd/go.
- Reenable GOOBJ=2 mode by default in liblink.
All architectures build successfully again.
Change-Id: I2c845c5d365aa484b570476898171bee657b626d
Reviewed-on: https://go-review.googlesource.com/3963
Reviewed-by: Rob Pike <r@golang.org>
2015-02-05 03:57:44 -05:00
|
|
|
if p.As == AFUNCDATA && p.From.Offset >= int64(nfuncdata) {
|
2015-01-19 14:34:58 -05:00
|
|
|
nfuncdata = int(p.From.Offset + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pcln.Pcdata = make([]Pcdata, npcdata)
|
|
|
|
|
pcln.Pcdata = pcln.Pcdata[:npcdata]
|
|
|
|
|
pcln.Funcdata = make([]*LSym, nfuncdata)
|
|
|
|
|
pcln.Funcdataoff = make([]int64, nfuncdata)
|
|
|
|
|
pcln.Funcdataoff = pcln.Funcdataoff[:nfuncdata]
|
|
|
|
|
|
|
|
|
|
funcpctab(ctxt, &pcln.Pcsp, cursym, "pctospadj", pctospadj, nil)
|
|
|
|
|
funcpctab(ctxt, &pcln.Pcfile, cursym, "pctofile", pctofileline, pcln)
|
|
|
|
|
funcpctab(ctxt, &pcln.Pcline, cursym, "pctoline", pctofileline, nil)
|
|
|
|
|
|
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 <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
pcinlineState := new(pcinlineState)
|
|
|
|
|
funcpctab(ctxt, &pcln.Pcinline, cursym, "pctoinline", pcinlineState.pctoinline, nil)
|
|
|
|
|
pcln.InlTree = pcinlineState.localTree
|
2017-02-17 16:55:40 -05:00
|
|
|
if ctxt.Debugpcln == "pctoinline" && len(pcln.InlTree.nodes) > 0 {
|
|
|
|
|
ctxt.Logf("-- inlining tree for %s:\n", cursym)
|
|
|
|
|
dumpInlTree(ctxt, pcln.InlTree)
|
|
|
|
|
ctxt.Logf("--\n")
|
|
|
|
|
}
|
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 <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
|
2015-01-19 14:34:58 -05:00
|
|
|
// tabulate which pc and func data we have.
|
|
|
|
|
havepc := make([]uint32, (npcdata+31)/32)
|
|
|
|
|
havefunc := make([]uint32, (nfuncdata+31)/32)
|
2017-04-18 10:18:34 -07:00
|
|
|
for p := cursym.Func.Text; p != nil; p = p.Link {
|
[dev.cc] cmd/internal/obj: reconvert from liblink
cmd/internal/obj reconverted using rsc.io/c2go rev 2a95256.
- Brings in new, more regular Prog, Addr definitions
- Add Prog* argument to oclass in liblink/asm[68].c, for c2go conversion.
- Update objwriter for change in TEXT size encoding.
- Merge 5a, 6a, 8a, 9a changes into new5a, new6a, new8a, new9a (by hand).
- Add +build ignore to cmd/asm/internal/{addr,arch,asm}, cmd/asm.
They need to be updated for the changes.
- Reenable verifyAsm in cmd/go.
- Reenable GOOBJ=2 mode by default in liblink.
All architectures build successfully again.
Change-Id: I2c845c5d365aa484b570476898171bee657b626d
Reviewed-on: https://go-review.googlesource.com/3963
Reviewed-by: Rob Pike <r@golang.org>
2015-02-05 03:57:44 -05:00
|
|
|
if p.As == AFUNCDATA {
|
2015-01-19 14:34:58 -05:00
|
|
|
if (havefunc[p.From.Offset/32]>>uint64(p.From.Offset%32))&1 != 0 {
|
|
|
|
|
ctxt.Diag("multiple definitions for FUNCDATA $%d", p.From.Offset)
|
|
|
|
|
}
|
|
|
|
|
havefunc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 17:10:13 -04:00
|
|
|
if p.As == APCDATA && p.To.Offset != -1 {
|
2015-01-19 14:34:58 -05:00
|
|
|
havepc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pcdata.
|
2015-02-23 16:07:24 -05:00
|
|
|
for i := 0; i < npcdata; i++ {
|
2015-01-19 14:34:58 -05:00
|
|
|
if (havepc[i/32]>>uint(i%32))&1 == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
funcpctab(ctxt, &pcln.Pcdata[i], cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// funcdata
|
|
|
|
|
if nfuncdata > 0 {
|
2015-02-23 16:07:24 -05:00
|
|
|
var i int
|
2017-04-18 10:18:34 -07:00
|
|
|
for p := cursym.Func.Text; p != nil; p = p.Link {
|
[dev.cc] cmd/internal/obj: reconvert from liblink
cmd/internal/obj reconverted using rsc.io/c2go rev 2a95256.
- Brings in new, more regular Prog, Addr definitions
- Add Prog* argument to oclass in liblink/asm[68].c, for c2go conversion.
- Update objwriter for change in TEXT size encoding.
- Merge 5a, 6a, 8a, 9a changes into new5a, new6a, new8a, new9a (by hand).
- Add +build ignore to cmd/asm/internal/{addr,arch,asm}, cmd/asm.
They need to be updated for the changes.
- Reenable verifyAsm in cmd/go.
- Reenable GOOBJ=2 mode by default in liblink.
All architectures build successfully again.
Change-Id: I2c845c5d365aa484b570476898171bee657b626d
Reviewed-on: https://go-review.googlesource.com/3963
Reviewed-by: Rob Pike <r@golang.org>
2015-02-05 03:57:44 -05:00
|
|
|
if p.As == AFUNCDATA {
|
2015-01-19 14:34:58 -05:00
|
|
|
i = int(p.From.Offset)
|
|
|
|
|
pcln.Funcdataoff[i] = p.To.Offset
|
[dev.cc] cmd/internal/obj: reconvert from liblink
cmd/internal/obj reconverted using rsc.io/c2go rev 2a95256.
- Brings in new, more regular Prog, Addr definitions
- Add Prog* argument to oclass in liblink/asm[68].c, for c2go conversion.
- Update objwriter for change in TEXT size encoding.
- Merge 5a, 6a, 8a, 9a changes into new5a, new6a, new8a, new9a (by hand).
- Add +build ignore to cmd/asm/internal/{addr,arch,asm}, cmd/asm.
They need to be updated for the changes.
- Reenable verifyAsm in cmd/go.
- Reenable GOOBJ=2 mode by default in liblink.
All architectures build successfully again.
Change-Id: I2c845c5d365aa484b570476898171bee657b626d
Reviewed-on: https://go-review.googlesource.com/3963
Reviewed-by: Rob Pike <r@golang.org>
2015-02-05 03:57:44 -05:00
|
|
|
if p.To.Type != TYPE_CONST {
|
2015-01-19 14:34:58 -05:00
|
|
|
// TODO: Dedup.
|
|
|
|
|
//funcdata_bytes += p->to.sym->size;
|
|
|
|
|
pcln.Funcdata[i] = p.To.Sym
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|