]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add sources for inlined functions to ssa.html
authorYury Smolsky <yury@smolsky.by>
Thu, 26 Jul 2018 09:51:06 +0000 (12:51 +0300)
committerJosh Bleecher Snyder <josharian@gmail.com>
Thu, 23 Aug 2018 05:11:33 +0000 (05:11 +0000)
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>
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/html.go

index feb3c8556acc16da754076b1673cc49ba530f476..fb5a413b846149f6f0dd51f8c873562e55110033 100644 (file)
@@ -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.
index 2abd9448d4ee20997303144bc791ab09bd4b0937..bbd2a668a597925c581ee3e26d62d6c342978a0c 100644 (file)
@@ -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.
index 2e48e8105b14627f394bf8bd007d707dfe927a07..6943e5ef4031f85e4c9a2432b5e2271651cb2de6 100644 (file)
@@ -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.