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.
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()
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
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.
// 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> </div>")
+ if filename != fl.Filename {
+ fmt.Fprint(&buf, "<div> </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> </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 = " "
+ } 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.