aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYury Smolsky <yury@smolsky.by>2018-07-26 12:51:06 +0300
committerJosh Bleecher Snyder <josharian@gmail.com>2018-08-23 05:11:33 +0000
commit9e2a04d5ebe450defe3435d827ef07ca3c0eae3f (patch)
tree7659fe966c8910aad75c3826e926f08ce43ebce6 /src
parentc374984e99888bb2e2dd6c331a1328275debe19d (diff)
downloadgo-9e2a04d5ebe450defe3435d827ef07ca3c0eae3f.tar.xz
cmd/compile: add sources for inlined functions to ssa.html
This CL adds the source code of all inlined functions into the function specified in $GOSSAFUNC. The code is appended to the sources column of ssa.html. ssaDumpInlined is populated with references to inlined functions. Then it is used for dumping the sources in buildssa. The source columns contains code in following order: target function, inlined functions sorted by filename, lineno. Fixes #25904 Change-Id: I4f6d4834376f1efdfda1f968a5335c0543ed36bc Reviewed-on: https://go-review.googlesource.com/126606 Run-TryBot: Yury Smolsky <yury@smolsky.by> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/gc/inl.go4
-rw-r--r--src/cmd/compile/internal/gc/ssa.go78
-rw-r--r--src/cmd/compile/internal/ssa/html.go61
3 files changed, 114 insertions, 29 deletions
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index feb3c8556a..fb5a413b84 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -893,6 +893,10 @@ func mkinlcall1(n, fn *Node, maxCost int32) *Node {
fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
}
+ if ssaDump != "" && ssaDump == Curfn.funcname() {
+ ssaDumpInlined = append(ssaDumpInlined, fn)
+ }
+
ninit := n.Ninit
// Make temp names to use instead of the originals.
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 2abd9448d4..bbd2a668a5 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -27,6 +27,9 @@ var ssaDump string // early copy of $GOSSAFUNC; the func name to dump output
var ssaDumpStdout bool // whether to dump to stdout
const ssaDumpFile = "ssa.html"
+// ssaDumpInlined holds all inlined functions when ssaDump contains a function name.
+var ssaDumpInlined []*Node
+
func initssaconfig() {
types_ := ssa.NewTypes()
@@ -147,27 +150,7 @@ func buildssa(fn *Node, worker int) *ssa.Func {
if printssa {
s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDumpFile, s.f.Frontend(), name)
// TODO: generate and print a mapping from nodes to values and blocks
-
- // Read sources for a function fn and format into a column.
- fname := Ctxt.PosTable.Pos(fn.Pos).Filename()
- f, err := os.Open(fname)
- if err != nil {
- s.f.HTMLWriter.Logger.Logf("skipping sources column: %v", err)
- } else {
- defer f.Close()
- firstLn := fn.Pos.Line() - 1
- lastLn := fn.Func.Endlineno.Line()
- var lines []string
- ln := uint(0)
- scanner := bufio.NewScanner(f)
- for scanner.Scan() && ln < lastLn {
- if ln >= firstLn {
- lines = append(lines, scanner.Text())
- }
- ln++
- }
- s.f.HTMLWriter.WriteSources("sources", fname, firstLn+1, lines)
- }
+ dumpSourcesColumn(s.f.HTMLWriter, fn)
}
// Allocate starting block
@@ -239,6 +222,59 @@ func buildssa(fn *Node, worker int) *ssa.Func {
return s.f
}
+func dumpSourcesColumn(writer *ssa.HTMLWriter, fn *Node) {
+ // Read sources of target function fn.
+ fname := Ctxt.PosTable.Pos(fn.Pos).Filename()
+ targetFn, err := readFuncLines(fname, fn.Pos.Line(), fn.Func.Endlineno.Line())
+ if err != nil {
+ writer.Logger.Logf("cannot read sources for function %v: %v", fn, err)
+ }
+
+ // Read sources of inlined functions.
+ var inlFns []*ssa.FuncLines
+ for _, fi := range ssaDumpInlined {
+ var elno src.XPos
+ if fi.Name.Defn == nil {
+ // Endlineno is filled from exported data.
+ elno = fi.Func.Endlineno
+ } else {
+ elno = fi.Name.Defn.Func.Endlineno
+ }
+ fname := Ctxt.PosTable.Pos(fi.Pos).Filename()
+ fnLines, err := readFuncLines(fname, fi.Pos.Line(), elno.Line())
+ if err != nil {
+ writer.Logger.Logf("cannot read sources for function %v: %v", fi, err)
+ continue
+ }
+ inlFns = append(inlFns, fnLines)
+ }
+
+ sort.Sort(ssa.ByTopo(inlFns))
+ if targetFn != nil {
+ inlFns = append([]*ssa.FuncLines{targetFn}, inlFns...)
+ }
+
+ writer.WriteSources("sources", inlFns)
+}
+
+func readFuncLines(file string, start, end uint) (*ssa.FuncLines, error) {
+ f, err := os.Open(os.ExpandEnv(file))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ var lines []string
+ ln := uint(1)
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() && ln <= end {
+ if ln >= start {
+ lines = append(lines, scanner.Text())
+ }
+ ln++
+ }
+ return &ssa.FuncLines{Filename: file, StartLineno: start, Lines: lines}, nil
+}
+
// updateUnsetPredPos propagates the earliest-value position information for b
// towards all of b's predecessors that need a position, and recurs on that
// predecessor if its position is updated. B should have a non-empty position.
diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go
index 2e48e8105b..6943e5ef40 100644
--- a/src/cmd/compile/internal/ssa/html.go
+++ b/src/cmd/compile/internal/ssa/html.go
@@ -458,25 +458,70 @@ func (w *HTMLWriter) WriteFunc(phase, title string, f *Func) {
// TODO: Add visual representation of f's CFG.
}
+// FuncLines contains source code for a function to be displayed
+// in sources column.
+type FuncLines struct {
+ Filename string
+ StartLineno uint
+ Lines []string
+}
+
+// ByTopo sorts topologically: target function is on top,
+// followed by inlined functions sorted by filename and line numbers.
+type ByTopo []*FuncLines
+
+func (x ByTopo) Len() int { return len(x) }
+func (x ByTopo) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x ByTopo) Less(i, j int) bool {
+ a := x[i]
+ b := x[j]
+ if a.Filename == a.Filename {
+ return a.StartLineno < b.StartLineno
+ }
+ return a.Filename < b.Filename
+}
+
// WriteSources writes lines as source code in a column headed by title.
// phase is used for collapsing columns and should be unique across the table.
-func (w *HTMLWriter) WriteSources(phase, title string, firstLineno uint, lines []string) {
+func (w *HTMLWriter) WriteSources(phase string, all []*FuncLines) {
if w == nil {
return // avoid generating HTML just to discard it
}
var buf bytes.Buffer
fmt.Fprint(&buf, "<div class=\"lines\" style=\"width: 8%\">")
- for i, _ := range lines {
- ln := int(firstLineno) + i
- fmt.Fprintf(&buf, "<div class=\"l%v line-number\">%v</div>", ln, ln)
+ filename := ""
+ for _, fl := range all {
+ fmt.Fprint(&buf, "<div>&nbsp;</div>")
+ if filename != fl.Filename {
+ fmt.Fprint(&buf, "<div>&nbsp;</div>")
+ filename = fl.Filename
+ }
+ for i := range fl.Lines {
+ ln := int(fl.StartLineno) + i
+ fmt.Fprintf(&buf, "<div class=\"l%v line-number\">%v</div>", ln, ln)
+ }
}
fmt.Fprint(&buf, "</div><div style=\"width: 92%\"><pre>")
- for i, l := range lines {
- ln := int(firstLineno) + i
- fmt.Fprintf(&buf, "<div class=\"l%v line-number\">%v</div>", ln, html.EscapeString(l))
+ filename = ""
+ for _, fl := range all {
+ fmt.Fprint(&buf, "<div>&nbsp;</div>")
+ if filename != fl.Filename {
+ fmt.Fprintf(&buf, "<div><strong>%v</strong></div>", fl.Filename)
+ filename = fl.Filename
+ }
+ for i, line := range fl.Lines {
+ ln := int(fl.StartLineno) + i
+ var escaped string
+ if strings.TrimSpace(line) == "" {
+ escaped = "&nbsp;"
+ } else {
+ escaped = html.EscapeString(line)
+ }
+ fmt.Fprintf(&buf, "<div class=\"l%v line-number\">%v</div>", ln, escaped)
+ }
}
fmt.Fprint(&buf, "</pre></div>")
- w.WriteColumn(phase, title, "", buf.String())
+ w.WriteColumn(phase, phase, "", buf.String())
}
// WriteColumn writes raw HTML in a column headed by title.