mirror of https://github.com/golang/go.git
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 c85b77c (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/28072
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
fcb45e7cef
commit
f7ac5da495
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue