Commit 9e2a04d5 authored by Yury Smolsky's avatar Yury Smolsky Committed by Josh Bleecher Snyder

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: 's avatarKeith Randall <khr@golang.org>
parent c374984e
......@@ -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.
......
......@@ -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.
......
......@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment