Commit f7ac5da4 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: make internal objects directly print to printer

Internal objects that satisfy the Printable interface can print
directly to a printer w/o going through the conversion to a string
first.

Made printer.f understand and special-case %v so that Printable
objects use the printer directly.

This is work in progress and we may end up doing something else
eventually (perhaps using fmt.Formatter) - or even undo these
changes if this exploration doesn't get us to a significantly
better place.

Allocations numbers relative to commit c85b77c2 (still up, but
reduced from most recent change):

name       old time/op     new time/op     delta
Template       307ms ± 4%      315ms ± 4%   +2.55%        (p=0.000 n=29+29)
Unicode        164ms ± 4%      165ms ± 4%     ~           (p=0.057 n=30+30)
GoTypes        1.01s ± 3%      1.03s ± 3%   +1.72%        (p=0.000 n=30+30)
Compiler       5.49s ± 1%      5.62s ± 2%   +2.31%        (p=0.000 n=30+28)

name       old user-ns/op  new user-ns/op  delta
Template        397M ± 3%       406M ± 6%   +2.21%        (p=0.000 n=28+30)
Unicode         225M ± 4%       226M ± 3%     ~           (p=0.230 n=29+30)
GoTypes        1.31G ± 3%      1.34G ± 5%   +2.79%        (p=0.000 n=30+30)
Compiler       7.39G ± 2%      7.50G ± 2%   +1.43%        (p=0.000 n=30+29)

name       old alloc/op    new alloc/op    delta
Template      46.8MB ± 0%     47.5MB ± 0%   +1.48%        (p=0.000 n=29+28)
Unicode       37.8MB ± 0%     38.1MB ± 0%   +0.64%        (p=0.000 n=30+28)
GoTypes        143MB ± 0%      145MB ± 0%   +1.72%        (p=0.000 n=30+30)
Compiler       683MB ± 0%      706MB ± 0%   +3.31%        (p=0.000 n=30+29)

name       old allocs/op   new allocs/op   delta
Template        444k ± 0%       481k ± 0%   +8.38%        (p=0.000 n=30+30)
Unicode         369k ± 0%       379k ± 0%   +2.74%        (p=0.000 n=30+30)
GoTypes        1.35M ± 0%      1.50M ± 0%  +10.78%        (p=0.000 n=30+30)
Compiler       5.66M ± 0%      6.25M ± 0%  +10.31%        (p=0.000 n=29+29)

For #16897.

Change-Id: I37f95ab60508018ee6d29a98d238482b60e3e4b5
Reviewed-on: https://go-review.googlesource.com/28072Reviewed-by: 's avatarMatthew Dempsky <mdempsky@google.com>
parent fcb45e7c
......@@ -537,7 +537,7 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
if t == bytetype || t == runetype {
// in %-T mode collapse rune and byte with their originals.
if fmtmode != FTypeId {
return p.s(sconv(t.Sym, FmtShort))
return p.sconv(t.Sym, FmtShort)
}
t = Types[t.Etype]
}
......@@ -554,11 +554,11 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
if t.Vargen != 0 {
return p.f("%v·%d", sconv(t.Sym, FmtShort), t.Vargen)
}
return p.s(sconv(t.Sym, FmtShort))
return p.sconv(t.Sym, FmtShort)
}
if flag&FmtUnsigned != 0 {
return p.s(sconv(t.Sym, FmtUnsigned))
return p.sconv(t.Sym, FmtUnsigned)
}
if t.Sym.Pkg == localpkg && t.Vargen != 0 {
......@@ -566,7 +566,7 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
}
}
return p.s(sconv(t.Sym, 0))
return p.sconv(t.Sym, 0)
}
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
......@@ -629,11 +629,11 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
// Wrong interface definitions may have types lacking a symbol.
break
case exportname(f.Sym.Name):
p.s(sconv(f.Sym, FmtShort))
p.sconv(f.Sym, FmtShort)
default:
p.s(sconv(f.Sym, FmtUnsigned))
p.sconv(f.Sym, FmtUnsigned)
}
p.s(Tconv(f.Type, FmtShort))
p.Tconv(f.Type, FmtShort)
}
if t.NumFields() != 0 {
p.s(" ")
......@@ -646,12 +646,12 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
} else {
if t.Recv() != nil {
p.s("method")
p.s(Tconv(t.Recvs(), 0))
p.Tconv(t.Recvs(), 0)
p.s(" ")
}
p.s("func")
}
p.s(Tconv(t.Params(), 0))
p.Tconv(t.Params(), 0)
switch t.Results().NumFields() {
case 0:
......@@ -659,11 +659,11 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
case 1:
p.s(" ")
p.s(Tconv(t.Results().Field(0).Type, 0)) // struct->field->field's type
p.Tconv(t.Results().Field(0).Type, 0) // struct->field->field's type
default:
p.s(" ")
p.s(Tconv(t.Results(), 0))
p.Tconv(t.Results(), 0)
}
return p
......@@ -777,7 +777,7 @@ func (p *printer) stmtfmt(n *Node) *printer {
if n.Left != nil {
p.f("%v %v", n.Left, n.Right)
} else {
p.s(Nconv(n.Right, 0))
p.Nconv(n.Right, 0)
}
// Don't export "v = <N>" initializing statements, hope they're always
......@@ -1075,7 +1075,7 @@ func (p *printer) exprfmt(n *Node, prec int) *printer {
return p.exprfmt(n.Orig, prec)
}
if n.Sym != nil {
return p.s(sconv(n.Sym, 0))
return p.sconv(n.Sym, 0)
}
}
if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
......@@ -1102,13 +1102,13 @@ func (p *printer) exprfmt(n *Node, prec int) *printer {
fallthrough
case OPACK, ONONAME:
return p.s(sconv(n.Sym, 0))
return p.sconv(n.Sym, 0)
case OTYPE:
if n.Type == nil && n.Sym != nil {
return p.s(sconv(n.Sym, 0))
return p.sconv(n.Sym, 0)
}
return p.s(Tconv(n.Type, 0))
return p.Tconv(n.Type, 0)
case OTARRAY:
if n.Left != nil {
......@@ -1450,10 +1450,10 @@ func (p *printer) nodedump(n *Node, flag FmtFlag) *printer {
if recur {
if n.Left != nil {
p.s(Nconv(n.Left, 0))
p.Nconv(n.Left, 0)
}
if n.Right != nil {
p.s(Nconv(n.Right, 0))
p.Nconv(n.Right, 0)
}
if n.List.Len() != 0 {
p.indent()
......@@ -1474,6 +1474,12 @@ func (p *printer) nodedump(n *Node, flag FmtFlag) *printer {
return p
}
func (s *Sym) Print(p *printer) {
p.sconv(s, 0)
}
var _ Printable = new(Sym) // verify that Sym implements Printable
func (s *Sym) String() string {
return sconv(s, 0)
}
......@@ -1481,18 +1487,20 @@ func (s *Sym) String() string {
// Fmt "%S": syms
// Flags: "%hS" suppresses qualifying with package
func sconv(s *Sym, flag FmtFlag) string {
var p printer
return new(printer).sconv(s, flag).String()
}
func (p *printer) sconv(s *Sym, flag FmtFlag) *printer {
if flag&FmtLong != 0 {
panic("linksymfmt")
}
if s == nil {
return "<S>"
return p.s("<S>")
}
if s.Name == "_" {
return "_"
return p.s("_")
}
sf := flag
......@@ -1502,9 +1510,15 @@ func sconv(s *Sym, flag FmtFlag) string {
fmtmode = sm
fmtbody = sb
return p.String()
return p
}
func (t *Type) Print(p *printer) {
p.Tconv(t, 0)
}
var _ Printable = new(Type) // verify Type implements Printable
func (t *Type) String() string {
return Tconv(t, 0)
}
......@@ -1595,14 +1609,16 @@ func Fldconv(f *Field, flag FmtFlag) string {
// 'h' omit 'func' and receiver from function types, short type names
// 'u' package name, not prefix (FTypeId mode, sticky)
func Tconv(t *Type, flag FmtFlag) string {
var p printer
return new(printer).Tconv(t, flag).String()
}
func (p *printer) Tconv(t *Type, flag FmtFlag) *printer {
if t == nil {
return "<T>"
return p.s("<T>")
}
if t.Trecur > 4 {
return "<...>"
return p.s("<...>")
}
t.Trecur++
......@@ -1627,9 +1643,15 @@ func Tconv(t *Type, flag FmtFlag) string {
fmtmode = sm
t.Trecur--
return p.String()
return p
}
func (n *Node) Print(p *printer) {
p.Nconv(n, 0)
}
var _ Printable = new(Node) // verify that Node implements Printable
func (n *Node) String() string {
return Nconv(n, 0)
}
......@@ -1638,10 +1660,12 @@ func (n *Node) String() string {
// Flags: 'l' suffix with "(type %T)" where possible
// '+h' in debug mode, don't recurse, no multiline output
func Nconv(n *Node, flag FmtFlag) string {
var p printer
return new(printer).Nconv(n, flag).String()
}
func (p *printer) Nconv(n *Node, flag FmtFlag) *printer {
if n == nil {
return "<N>"
return p.s("<N>")
}
sf := flag
sm, sb := setfmode(&flag)
......@@ -1663,9 +1687,15 @@ func Nconv(n *Node, flag FmtFlag) string {
fmtbody = sb
fmtmode = sm
return p.String()
return p
}
func (n Nodes) Print(p *printer) {
p.hconv(n, 0)
}
var _ Printable = Nodes{} // verify that Nodes implements Printable
func (n Nodes) String() string {
return hconv(n, 0)
}
......@@ -1673,10 +1703,12 @@ func (n Nodes) String() string {
// Fmt '%H': Nodes.
// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
func hconv(l Nodes, flag FmtFlag) string {
var p printer
return new(printer).hconv(l, flag).String()
}
func (p *printer) hconv(l Nodes, flag FmtFlag) *printer {
if l.Len() == 0 && fmtmode == FDbg {
return "<nil>"
return p.s("<nil>")
}
sf := flag
......@@ -1689,7 +1721,7 @@ func hconv(l Nodes, flag FmtFlag) string {
}
for i, n := range l.Slice() {
p.s(Nconv(n, 0))
p.Nconv(n, 0)
if i+1 < l.Len() {
p.s(sep)
}
......@@ -1699,7 +1731,7 @@ func hconv(l Nodes, flag FmtFlag) string {
fmtbody = sb
fmtmode = sm
return p.String()
return p
}
func dumplist(s string, l Nodes) {
......@@ -1715,6 +1747,13 @@ type printer struct {
buf []byte
}
// Types that implement the Printable interface print
// to a printer directly without first converting to
// a string.
type Printable interface {
Print(*printer)
}
// printer implements io.Writer.
func (p *printer) Write(buf []byte) (n int, err error) {
p.buf = append(p.buf, buf...)
......@@ -1733,8 +1772,27 @@ func (p *printer) s(s string) *printer {
}
// f prints the formatted arguments to p and returns p.
// %v arguments that implement the Printable interface
// are printed to p via that interface.
func (p *printer) f(format string, args ...interface{}) *printer {
fmt.Fprintf(p, format, args...)
for len(format) > 0 {
i := strings.IndexByte(format, '%')
if i < 0 || i+1 >= len(format) || format[i+1] != 'v' || len(args) == 0 {
break // don't be clever, let fmt.Fprintf handle this for now
}
// found "%v" and at least one argument (and no other %x before)
p.s(format[:i])
format = format[i+len("%v"):]
if a, ok := args[0].(Printable); ok {
a.Print(p)
} else {
fmt.Fprintf(p, "%v", args[0])
}
args = args[1:]
}
if len(format) > 0 || len(args) > 0 {
fmt.Fprintf(p, format, args...)
}
return p
}
......
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