Skip to content

Commit f7ac5da

Browse files
committed
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 <[email protected]>
1 parent fcb45e7 commit f7ac5da

File tree

1 file changed

+92
-34
lines changed
  • src/cmd/compile/internal/gc

1 file changed

+92
-34
lines changed

src/cmd/compile/internal/gc/fmt.go

+92-34
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
537537
if t == bytetype || t == runetype {
538538
// in %-T mode collapse rune and byte with their originals.
539539
if fmtmode != FTypeId {
540-
return p.s(sconv(t.Sym, FmtShort))
540+
return p.sconv(t.Sym, FmtShort)
541541
}
542542
t = Types[t.Etype]
543543
}
@@ -554,19 +554,19 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
554554
if t.Vargen != 0 {
555555
return p.f("%v·%d", sconv(t.Sym, FmtShort), t.Vargen)
556556
}
557-
return p.s(sconv(t.Sym, FmtShort))
557+
return p.sconv(t.Sym, FmtShort)
558558
}
559559

560560
if flag&FmtUnsigned != 0 {
561-
return p.s(sconv(t.Sym, FmtUnsigned))
561+
return p.sconv(t.Sym, FmtUnsigned)
562562
}
563563

564564
if t.Sym.Pkg == localpkg && t.Vargen != 0 {
565565
return p.f("%v·%d", t.Sym, t.Vargen)
566566
}
567567
}
568568

569-
return p.s(sconv(t.Sym, 0))
569+
return p.sconv(t.Sym, 0)
570570
}
571571

572572
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
@@ -629,11 +629,11 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
629629
// Wrong interface definitions may have types lacking a symbol.
630630
break
631631
case exportname(f.Sym.Name):
632-
p.s(sconv(f.Sym, FmtShort))
632+
p.sconv(f.Sym, FmtShort)
633633
default:
634-
p.s(sconv(f.Sym, FmtUnsigned))
634+
p.sconv(f.Sym, FmtUnsigned)
635635
}
636-
p.s(Tconv(f.Type, FmtShort))
636+
p.Tconv(f.Type, FmtShort)
637637
}
638638
if t.NumFields() != 0 {
639639
p.s(" ")
@@ -646,24 +646,24 @@ func (p *printer) typefmt(t *Type, flag FmtFlag) *printer {
646646
} else {
647647
if t.Recv() != nil {
648648
p.s("method")
649-
p.s(Tconv(t.Recvs(), 0))
649+
p.Tconv(t.Recvs(), 0)
650650
p.s(" ")
651651
}
652652
p.s("func")
653653
}
654-
p.s(Tconv(t.Params(), 0))
654+
p.Tconv(t.Params(), 0)
655655

656656
switch t.Results().NumFields() {
657657
case 0:
658658
// nothing to do
659659

660660
case 1:
661661
p.s(" ")
662-
p.s(Tconv(t.Results().Field(0).Type, 0)) // struct->field->field's type
662+
p.Tconv(t.Results().Field(0).Type, 0) // struct->field->field's type
663663

664664
default:
665665
p.s(" ")
666-
p.s(Tconv(t.Results(), 0))
666+
p.Tconv(t.Results(), 0)
667667
}
668668
return p
669669

@@ -777,7 +777,7 @@ func (p *printer) stmtfmt(n *Node) *printer {
777777
if n.Left != nil {
778778
p.f("%v %v", n.Left, n.Right)
779779
} else {
780-
p.s(Nconv(n.Right, 0))
780+
p.Nconv(n.Right, 0)
781781
}
782782

783783
// Don't export "v = <N>" initializing statements, hope they're always
@@ -1075,7 +1075,7 @@ func (p *printer) exprfmt(n *Node, prec int) *printer {
10751075
return p.exprfmt(n.Orig, prec)
10761076
}
10771077
if n.Sym != nil {
1078-
return p.s(sconv(n.Sym, 0))
1078+
return p.sconv(n.Sym, 0)
10791079
}
10801080
}
10811081
if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
@@ -1102,13 +1102,13 @@ func (p *printer) exprfmt(n *Node, prec int) *printer {
11021102
fallthrough
11031103

11041104
case OPACK, ONONAME:
1105-
return p.s(sconv(n.Sym, 0))
1105+
return p.sconv(n.Sym, 0)
11061106

11071107
case OTYPE:
11081108
if n.Type == nil && n.Sym != nil {
1109-
return p.s(sconv(n.Sym, 0))
1109+
return p.sconv(n.Sym, 0)
11101110
}
1111-
return p.s(Tconv(n.Type, 0))
1111+
return p.Tconv(n.Type, 0)
11121112

11131113
case OTARRAY:
11141114
if n.Left != nil {
@@ -1450,10 +1450,10 @@ func (p *printer) nodedump(n *Node, flag FmtFlag) *printer {
14501450

14511451
if recur {
14521452
if n.Left != nil {
1453-
p.s(Nconv(n.Left, 0))
1453+
p.Nconv(n.Left, 0)
14541454
}
14551455
if n.Right != nil {
1456-
p.s(Nconv(n.Right, 0))
1456+
p.Nconv(n.Right, 0)
14571457
}
14581458
if n.List.Len() != 0 {
14591459
p.indent()
@@ -1474,25 +1474,33 @@ func (p *printer) nodedump(n *Node, flag FmtFlag) *printer {
14741474
return p
14751475
}
14761476

1477+
func (s *Sym) Print(p *printer) {
1478+
p.sconv(s, 0)
1479+
}
1480+
1481+
var _ Printable = new(Sym) // verify that Sym implements Printable
1482+
14771483
func (s *Sym) String() string {
14781484
return sconv(s, 0)
14791485
}
14801486

14811487
// Fmt "%S": syms
14821488
// Flags: "%hS" suppresses qualifying with package
14831489
func sconv(s *Sym, flag FmtFlag) string {
1484-
var p printer
1490+
return new(printer).sconv(s, flag).String()
1491+
}
14851492

1493+
func (p *printer) sconv(s *Sym, flag FmtFlag) *printer {
14861494
if flag&FmtLong != 0 {
14871495
panic("linksymfmt")
14881496
}
14891497

14901498
if s == nil {
1491-
return "<S>"
1499+
return p.s("<S>")
14921500
}
14931501

14941502
if s.Name == "_" {
1495-
return "_"
1503+
return p.s("_")
14961504
}
14971505

14981506
sf := flag
@@ -1502,9 +1510,15 @@ func sconv(s *Sym, flag FmtFlag) string {
15021510
fmtmode = sm
15031511
fmtbody = sb
15041512

1505-
return p.String()
1513+
return p
15061514
}
15071515

1516+
func (t *Type) Print(p *printer) {
1517+
p.Tconv(t, 0)
1518+
}
1519+
1520+
var _ Printable = new(Type) // verify Type implements Printable
1521+
15081522
func (t *Type) String() string {
15091523
return Tconv(t, 0)
15101524
}
@@ -1595,14 +1609,16 @@ func Fldconv(f *Field, flag FmtFlag) string {
15951609
// 'h' omit 'func' and receiver from function types, short type names
15961610
// 'u' package name, not prefix (FTypeId mode, sticky)
15971611
func Tconv(t *Type, flag FmtFlag) string {
1598-
var p printer
1612+
return new(printer).Tconv(t, flag).String()
1613+
}
15991614

1615+
func (p *printer) Tconv(t *Type, flag FmtFlag) *printer {
16001616
if t == nil {
1601-
return "<T>"
1617+
return p.s("<T>")
16021618
}
16031619

16041620
if t.Trecur > 4 {
1605-
return "<...>"
1621+
return p.s("<...>")
16061622
}
16071623

16081624
t.Trecur++
@@ -1627,9 +1643,15 @@ func Tconv(t *Type, flag FmtFlag) string {
16271643
fmtmode = sm
16281644
t.Trecur--
16291645

1630-
return p.String()
1646+
return p
1647+
}
1648+
1649+
func (n *Node) Print(p *printer) {
1650+
p.Nconv(n, 0)
16311651
}
16321652

1653+
var _ Printable = new(Node) // verify that Node implements Printable
1654+
16331655
func (n *Node) String() string {
16341656
return Nconv(n, 0)
16351657
}
@@ -1638,10 +1660,12 @@ func (n *Node) String() string {
16381660
// Flags: 'l' suffix with "(type %T)" where possible
16391661
// '+h' in debug mode, don't recurse, no multiline output
16401662
func Nconv(n *Node, flag FmtFlag) string {
1641-
var p printer
1663+
return new(printer).Nconv(n, flag).String()
1664+
}
16421665

1666+
func (p *printer) Nconv(n *Node, flag FmtFlag) *printer {
16431667
if n == nil {
1644-
return "<N>"
1668+
return p.s("<N>")
16451669
}
16461670
sf := flag
16471671
sm, sb := setfmode(&flag)
@@ -1663,20 +1687,28 @@ func Nconv(n *Node, flag FmtFlag) string {
16631687
fmtbody = sb
16641688
fmtmode = sm
16651689

1666-
return p.String()
1690+
return p
16671691
}
16681692

1693+
func (n Nodes) Print(p *printer) {
1694+
p.hconv(n, 0)
1695+
}
1696+
1697+
var _ Printable = Nodes{} // verify that Nodes implements Printable
1698+
16691699
func (n Nodes) String() string {
16701700
return hconv(n, 0)
16711701
}
16721702

16731703
// Fmt '%H': Nodes.
16741704
// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
16751705
func hconv(l Nodes, flag FmtFlag) string {
1676-
var p printer
1706+
return new(printer).hconv(l, flag).String()
1707+
}
16771708

1709+
func (p *printer) hconv(l Nodes, flag FmtFlag) *printer {
16781710
if l.Len() == 0 && fmtmode == FDbg {
1679-
return "<nil>"
1711+
return p.s("<nil>")
16801712
}
16811713

16821714
sf := flag
@@ -1689,7 +1721,7 @@ func hconv(l Nodes, flag FmtFlag) string {
16891721
}
16901722

16911723
for i, n := range l.Slice() {
1692-
p.s(Nconv(n, 0))
1724+
p.Nconv(n, 0)
16931725
if i+1 < l.Len() {
16941726
p.s(sep)
16951727
}
@@ -1699,7 +1731,7 @@ func hconv(l Nodes, flag FmtFlag) string {
16991731
fmtbody = sb
17001732
fmtmode = sm
17011733

1702-
return p.String()
1734+
return p
17031735
}
17041736

17051737
func dumplist(s string, l Nodes) {
@@ -1715,6 +1747,13 @@ type printer struct {
17151747
buf []byte
17161748
}
17171749

1750+
// Types that implement the Printable interface print
1751+
// to a printer directly without first converting to
1752+
// a string.
1753+
type Printable interface {
1754+
Print(*printer)
1755+
}
1756+
17181757
// printer implements io.Writer.
17191758
func (p *printer) Write(buf []byte) (n int, err error) {
17201759
p.buf = append(p.buf, buf...)
@@ -1733,8 +1772,27 @@ func (p *printer) s(s string) *printer {
17331772
}
17341773

17351774
// f prints the formatted arguments to p and returns p.
1775+
// %v arguments that implement the Printable interface
1776+
// are printed to p via that interface.
17361777
func (p *printer) f(format string, args ...interface{}) *printer {
1737-
fmt.Fprintf(p, format, args...)
1778+
for len(format) > 0 {
1779+
i := strings.IndexByte(format, '%')
1780+
if i < 0 || i+1 >= len(format) || format[i+1] != 'v' || len(args) == 0 {
1781+
break // don't be clever, let fmt.Fprintf handle this for now
1782+
}
1783+
// found "%v" and at least one argument (and no other %x before)
1784+
p.s(format[:i])
1785+
format = format[i+len("%v"):]
1786+
if a, ok := args[0].(Printable); ok {
1787+
a.Print(p)
1788+
} else {
1789+
fmt.Fprintf(p, "%v", args[0])
1790+
}
1791+
args = args[1:]
1792+
}
1793+
if len(format) > 0 || len(args) > 0 {
1794+
fmt.Fprintf(p, format, args...)
1795+
}
17381796
return p
17391797
}
17401798

0 commit comments

Comments
 (0)