Introduce garbage-free LookupN to replace most users of Lookupf.
Also, remove the string interning from LookupBytes which was hurting
more than helping.
name old alloc/op new alloc/op delta
Template 63.0MB ± 0% 62.7MB ± 0% -0.48% (p=0.000 n=10+9)
Unicode 43.0MB ± 0% 43.0MB ± 0% -0.17% (p=0.000 n=10+7)
GoTypes 219MB ± 0% 218MB ± 0% -0.14% (p=0.000 n=10+10)
Compiler 992MB ± 0% 991MB ± 0% -0.12% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
Template 683k ± 0% 681k ± 0% -0.38% (p=0.000 n=10+8)
Unicode 541k ± 0% 541k ± 0% -0.11% (p=0.000 n=10+10)
GoTypes 2.09M ± 0% 2.08M ± 0% -0.40% (p=0.000 n=10+10)
Compiler 9.28M ± 0% 9.24M ± 0% -0.36% (p=0.000 n=10+10)
Size of $GOROOT/pkg/darwin_amd64 drops from 40124 KB to 40100 KB too,
removing the zero padding as suggested by josharian.
Updates #6853
Change-Id: I3c557266e9325fe29c459cef8e5b8954913e7abb
Reviewed-on: https://go-review.googlesource.com/20931
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
var fld *Node
var n *Node
for _, t := range t0.Params().Fields().Slice() {
- n = newname(Lookupf("a%d", i))
+ n = newname(LookupN("a%d", i))
i++
n.Class = PPARAM
xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
l = nil
var retargs []*Node
for _, t := range t0.Results().Fields().Slice() {
- n = newname(Lookupf("r%d", i))
+ n = newname(LookupN("r", i))
i++
n.Class = PPARAMOUT
xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
if n.Left == nil {
// Name so that escape analysis can track it. ~r stands for 'result'.
- n.Left = newname(Lookupf("~r%d", gen))
+ n.Left = newname(LookupN("~r", gen))
gen++
}
*nn = *n.Left
nn.Orig = nn
- nn.Sym = Lookupf("~b%d", gen)
+ nn.Sym = LookupN("~b", gen)
gen++
n.Left = nn
}
// give each tmp a different name so that there
// a chance to registerizer them
- s := Lookupf("autotmp_%.4d", statuniqgen)
+ s := LookupN("autotmp_", statuniqgen)
statuniqgen++
n := Nod(ONAME, nil, nil)
n.Sym = s
func renameinit() *Sym {
renameinit_initgen++
- return Lookupf("init.%d", renameinit_initgen)
+ return LookupN("init.", renameinit_initgen)
}
// hand-craft the following initialization code
// (9)
// could check that it is fn of no args/returns
for i := 1; ; i++ {
- s := Lookupf("init.%d", i)
+ s := LookupN("init.", i)
if s.Def == nil {
break
}
// Synthesize a variable to store the inlined function's results in.
func retvar(t *Field, i int) *Node {
- n := newname(Lookupf("~r%d", i))
+ n := newname(LookupN("~r", i))
n.Type = t.Type
n.Class = PAUTO
n.Used = true
// Synthesize a variable to store the inlined function's arguments
// when they come from a multiple return call.
func argvar(t *Type, i int) *Node {
- n := newname(Lookupf("~arg%d", i))
+ n := newname(LookupN("~arg", i))
n.Type = t.Type
n.Class = PAUTO
n.Used = true
func newlabel_inl() *Node {
newlabel_inl_label++
- n := newname(Lookupf(".inlret%.6d", newlabel_inl_label))
+ n := newname(LookupN(".inlret", newlabel_inl_label))
n.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
return n
}
// "Portable" code generation.
-var makefuncdatasym_nsym int32
+var makefuncdatasym_nsym int
-func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
+func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym {
var nod Node
- sym := Lookupf(namefmt, makefuncdatasym_nsym)
+ sym := LookupN(nameprefix, makefuncdatasym_nsym)
makefuncdatasym_nsym++
pnod := newname(sym)
pnod.Class = PEXTERN
ginit()
- gcargs := makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
- gclocals := makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
+ gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
+ gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
if obj.Fieldtrack_enabled != 0 && len(Curfn.Func.FieldTrack) > 0 {
trackSyms := make([]*Sym, 0, len(Curfn.Func.FieldTrack))
// data statements for the constant
// part of the composite literal.
func staticname(t *Type, ctxt int) *Node {
- n := newname(Lookupf("statictmp_%.4d", statuniqgen))
+ n := newname(LookupN("statictmp_", statuniqgen))
statuniqgen++
if ctxt == 0 {
n.Name.Readonly = true
"fmt"
"os"
"sort"
+ "strconv"
"strings"
"unicode"
"unicode/utf8"
return localpkg.LookupBytes(name)
}
+// LookupN looks up the symbol starting with prefix and ending with
+// the decimal n. If prefix is too long, LookupN panics.
+func LookupN(prefix string, n int) *Sym {
+ var buf [20]byte // plenty long enough for all current users
+ copy(buf[:], prefix)
+ b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
+ return LookupBytes(b)
+}
+
var initSyms []*Sym
var nopkg = &Pkg{