Commit d553c29d authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: directly construct Fields instead of ODCLFIELD nodes

Avoids some garbage allocations while loading import data. Seems to
especially benefit html/template for some reason, but significant
allocation improvements for other packages too.

name       old time/op     new time/op     delta
Template       345ms ± 6%      332ms ± 6%   -3.76%        (p=0.000 n=49+47)
Unicode        185ms ±10%      184ms ±12%     ~           (p=0.401 n=50+49)
GoTypes        1.04s ± 3%      1.04s ± 3%   -0.72%        (p=0.012 n=48+47)
Compiler       4.52s ± 7%      4.49s ± 9%     ~           (p=0.465 n=48+47)

name       old user-ns/op  new user-ns/op  delta
Template        532M ±17%       471M ±23%  -11.48%        (p=0.000 n=50+50)
Unicode         298M ±29%       311M ±28%     ~           (p=0.065 n=50+50)
GoTypes        1.52G ± 7%      1.54G ± 9%     ~           (p=0.062 n=49+50)
Compiler       6.37G ± 7%      6.42G ± 8%     ~           (p=0.157 n=49+48)

name       old alloc/op    new alloc/op    delta
Template      43.9MB ± 0%     42.3MB ± 0%   -3.51%        (p=0.000 n=48+48)
Unicode       34.3MB ± 0%     34.3MB ± 0%     ~           (p=0.945 n=50+50)
GoTypes        123MB ± 0%      122MB ± 0%   -0.82%        (p=0.000 n=50+50)
Compiler       522MB ± 0%      519MB ± 0%   -0.51%        (p=0.000 n=50+50)

name       old allocs/op   new allocs/op   delta
Template        414k ± 0%       397k ± 0%   -4.14%        (p=0.000 n=50+49)
Unicode         320k ± 0%       320k ± 0%     ~           (p=0.988 n=48+49)
GoTypes        1.18M ± 0%      1.17M ± 0%   -0.97%        (p=0.000 n=50+50)
Compiler       4.44M ± 0%      4.41M ± 0%   -0.66%        (p=0.000 n=50+50)

Passes toolstash.

Change-Id: I0f54c0fa420d4f4ed3584c47cec0dde100c70c03
Reviewed-on: https://go-review.googlesource.com/31670
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRobert Griesemer <gri@golang.org>
parent 6ca662ca
...@@ -330,7 +330,7 @@ func (p *importer) obj(tag int) { ...@@ -330,7 +330,7 @@ func (p *importer) obj(tag int) {
params := p.paramList() params := p.paramList()
result := p.paramList() result := p.paramList()
sig := functype(nil, params, result) sig := functypefield(nil, params, result)
importsym(sym, ONAME) importsym(sym, ONAME)
if sym.Def != nil && sym.Def.Op == ONAME { if sym.Def != nil && sym.Def.Op == ONAME {
// function was imported before (via another import) // function was imported before (via another import)
...@@ -465,8 +465,15 @@ func (p *importer) typ() *Type { ...@@ -465,8 +465,15 @@ func (p *importer) typ() *Type {
result := p.paramList() result := p.paramList()
nointerface := p.bool() nointerface := p.bool()
n := methodname(newname(sym), recv[0].Right) base := recv[0].Type
n.Type = functype(recv[0], params, result) star := false
if base.IsPtr() {
base = base.Elem()
star = true
}
n := methodname0(sym, star, base.Sym)
n.Type = functypefield(recv[0], params, result)
checkwidth(n.Type) checkwidth(n.Type)
addmethod(sym, n.Type, false, nointerface) addmethod(sym, n.Type, false, nointerface)
p.funcList = append(p.funcList, n) p.funcList = append(p.funcList, n)
...@@ -506,7 +513,8 @@ func (p *importer) typ() *Type { ...@@ -506,7 +513,8 @@ func (p *importer) typ() *Type {
case structTag: case structTag:
t = p.newtyp(TSTRUCT) t = p.newtyp(TSTRUCT)
tostruct0(t, p.fieldList()) t.SetFields(p.fieldList())
checkwidth(t)
case pointerTag: case pointerTag:
t = p.newtyp(Tptr) t = p.newtyp(Tptr)
...@@ -516,14 +524,15 @@ func (p *importer) typ() *Type { ...@@ -516,14 +524,15 @@ func (p *importer) typ() *Type {
t = p.newtyp(TFUNC) t = p.newtyp(TFUNC)
params := p.paramList() params := p.paramList()
result := p.paramList() result := p.paramList()
functype0(t, nil, params, result) functypefield0(t, nil, params, result)
case interfaceTag: case interfaceTag:
t = p.newtyp(TINTER) t = p.newtyp(TINTER)
if p.int() != 0 { if p.int() != 0 {
formatErrorf("unexpected embedded interface") formatErrorf("unexpected embedded interface")
} }
tointerface0(t, p.methodList()) t.SetFields(p.methodList())
checkwidth(t)
case mapTag: case mapTag:
t = p.newtyp(TMAP) t = p.newtyp(TMAP)
...@@ -555,9 +564,9 @@ func (p *importer) qualifiedName() *Sym { ...@@ -555,9 +564,9 @@ func (p *importer) qualifiedName() *Sym {
} }
// parser.go:hidden_structdcl_list // parser.go:hidden_structdcl_list
func (p *importer) fieldList() (fields []*Node) { func (p *importer) fieldList() (fields []*Field) {
if n := p.int(); n > 0 { if n := p.int(); n > 0 {
fields = make([]*Node, n) fields = make([]*Field, n)
for i := range fields { for i := range fields {
fields[i] = p.field() fields[i] = p.field()
} }
...@@ -566,37 +575,35 @@ func (p *importer) fieldList() (fields []*Node) { ...@@ -566,37 +575,35 @@ func (p *importer) fieldList() (fields []*Node) {
} }
// parser.go:hidden_structdcl // parser.go:hidden_structdcl
func (p *importer) field() *Node { func (p *importer) field() *Field {
p.pos() p.pos()
sym := p.fieldName() sym := p.fieldName()
typ := p.typ() typ := p.typ()
note := p.string() note := p.string()
var n *Node f := newField()
if sym.Name != "" { if sym.Name == "" {
n = nod(ODCLFIELD, newname(sym), typenod(typ))
} else {
// anonymous field - typ must be T or *T and T must be a type name // anonymous field - typ must be T or *T and T must be a type name
s := typ.Sym s := typ.Sym
if s == nil && typ.IsPtr() { if s == nil && typ.IsPtr() {
s = typ.Elem().Sym // deref s = typ.Elem().Sym // deref
} }
pkg := importpkg sym = sym.Pkg.Lookup(s.Name)
if sym != nil { f.Embedded = 1
pkg = sym.Pkg
} }
n = embedded(s, pkg)
n.Right = typenod(typ)
}
n.SetVal(Val{U: note})
return n f.Sym = sym
f.Nname = newname(sym)
f.Type = typ
f.Note = note
return f
} }
// parser.go:hidden_interfacedcl_list // parser.go:hidden_interfacedcl_list
func (p *importer) methodList() (methods []*Node) { func (p *importer) methodList() (methods []*Field) {
if n := p.int(); n > 0 { if n := p.int(); n > 0 {
methods = make([]*Node, n) methods = make([]*Field, n)
for i := range methods { for i := range methods {
methods[i] = p.method() methods[i] = p.method()
} }
...@@ -605,12 +612,17 @@ func (p *importer) methodList() (methods []*Node) { ...@@ -605,12 +612,17 @@ func (p *importer) methodList() (methods []*Node) {
} }
// parser.go:hidden_interfacedcl // parser.go:hidden_interfacedcl
func (p *importer) method() *Node { func (p *importer) method() *Field {
p.pos() p.pos()
sym := p.fieldName() sym := p.fieldName()
params := p.paramList() params := p.paramList()
result := p.paramList() result := p.paramList()
return nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result)))
f := newField()
f.Sym = sym
f.Nname = newname(sym)
f.Type = functypefield(fakethisfield(), params, result)
return f
} }
// parser.go:sym,hidden_importsym // parser.go:sym,hidden_importsym
...@@ -632,7 +644,7 @@ func (p *importer) fieldName() *Sym { ...@@ -632,7 +644,7 @@ func (p *importer) fieldName() *Sym {
} }
// parser.go:ohidden_funarg_list // parser.go:ohidden_funarg_list
func (p *importer) paramList() []*Node { func (p *importer) paramList() []*Field {
i := p.int() i := p.int()
if i == 0 { if i == 0 {
return nil return nil
...@@ -644,27 +656,23 @@ func (p *importer) paramList() []*Node { ...@@ -644,27 +656,23 @@ func (p *importer) paramList() []*Node {
named = false named = false
} }
// i > 0 // i > 0
n := make([]*Node, i) fs := make([]*Field, i)
for i := range n { for i := range fs {
n[i] = p.param(named) fs[i] = p.param(named)
} }
return n return fs
} }
// parser.go:hidden_funarg // parser.go:hidden_funarg
func (p *importer) param(named bool) *Node { func (p *importer) param(named bool) *Field {
typ := p.typ() f := newField()
f.Type = p.typ()
isddd := false if f.Type.Etype == TDDDFIELD {
if typ.Etype == TDDDFIELD {
// TDDDFIELD indicates wrapped ... slice type // TDDDFIELD indicates wrapped ... slice type
typ = typSlice(typ.DDDField()) f.Type = typSlice(f.Type.DDDField())
isddd = true f.Isddd = true
} }
n := nod(ODCLFIELD, nil, typenod(typ))
n.Isddd = isddd
if named { if named {
name := p.string() name := p.string()
if name == "" { if name == "" {
...@@ -676,14 +684,15 @@ func (p *importer) param(named bool) *Node { ...@@ -676,14 +684,15 @@ func (p *importer) param(named bool) *Node {
if name != "_" { if name != "_" {
pkg = p.pkg() pkg = p.pkg()
} }
n.Left = newname(pkg.Lookup(name)) f.Sym = pkg.Lookup(name)
f.Nname = newname(f.Sym)
} }
// TODO(gri) This is compiler-specific (escape info). // TODO(gri) This is compiler-specific (escape info).
// Move into compiler-specific section eventually? // Move into compiler-specific section eventually?
n.SetVal(Val{U: p.string()}) f.Note = p.string()
return n return f
} }
func (p *importer) value(typ *Type) (x Val) { func (p *importer) value(typ *Type) (x Val) {
......
...@@ -853,6 +853,22 @@ func tofunargs(l []*Node, funarg Funarg) *Type { ...@@ -853,6 +853,22 @@ func tofunargs(l []*Node, funarg Funarg) *Type {
return t return t
} }
func tofunargsfield(fields []*Field, funarg Funarg) *Type {
t := typ(TSTRUCT)
t.StructType().Funarg = funarg
for _, f := range fields {
f.Funarg = funarg
// esc.go needs to find f given a PPARAM to add the tag.
if f.Nname != nil && f.Nname.Class == PPARAM {
f.Nname.Name.Param.Field = f
}
}
t.SetFields(fields)
return t
}
func interfacefield(n *Node) *Field { func interfacefield(n *Node) *Field {
lno := lineno lno := lineno
lineno = n.Lineno lineno = n.Lineno
...@@ -994,6 +1010,12 @@ func fakethis() *Node { ...@@ -994,6 +1010,12 @@ func fakethis() *Node {
return n return n
} }
func fakethisfield() *Field {
f := newField()
f.Type = ptrto(typ(TSTRUCT))
return f
}
// Is this field a method on an interface? // Is this field a method on an interface?
// Those methods have an anonymous *struct{} as the receiver. // Those methods have an anonymous *struct{} as the receiver.
// (See fakethis above.) // (See fakethis above.)
...@@ -1048,6 +1070,30 @@ func functype0(t *Type, this *Node, in, out []*Node) { ...@@ -1048,6 +1070,30 @@ func functype0(t *Type, this *Node, in, out []*Node) {
} }
} }
func functypefield(this *Field, in, out []*Field) *Type {
t := typ(TFUNC)
functypefield0(t, this, in, out)
return t
}
func functypefield0(t *Type, this *Field, in, out []*Field) {
var rcvr []*Field
if this != nil {
rcvr = []*Field{this}
}
t.FuncType().Receiver = tofunargsfield(rcvr, FunargRcvr)
t.FuncType().Results = tofunargsfield(out, FunargRcvr)
t.FuncType().Params = tofunargsfield(in, FunargRcvr)
t.FuncType().Outnamed = false
if len(out) > 0 && out[0].Nname != nil && out[0].Nname.Orig != nil {
s := out[0].Nname.Orig.Sym
if s != nil && (s.Name[0] != '~' || s.Name[1] != 'r') { // ~r%d is the name invented for an unnamed result
t.FuncType().Outnamed = true
}
}
}
var methodsym_toppkg *Pkg var methodsym_toppkg *Pkg
func methodsym(nsym *Sym, t0 *Type, iface int) *Sym { func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
...@@ -1119,30 +1165,34 @@ bad: ...@@ -1119,30 +1165,34 @@ bad:
} }
func methodname(n *Node, t *Node) *Node { func methodname(n *Node, t *Node) *Node {
star := "" star := false
if t.Op == OIND { if t.Op == OIND {
star = "*" star = true
t = t.Left t = t.Left
} }
if t.Sym == nil || isblank(n) { return methodname0(n.Sym, star, t.Sym)
return newfuncname(n.Sym) }
func methodname0(s *Sym, star bool, tsym *Sym) *Node {
if tsym == nil || isblanksym(s) {
return newfuncname(s)
} }
var p string var p string
if star != "" { if star {
p = fmt.Sprintf("(%s%v).%v", star, t.Sym, n.Sym) p = fmt.Sprintf("(*%v).%v", tsym, s)
} else { } else {
p = fmt.Sprintf("%v.%v", t.Sym, n.Sym) p = fmt.Sprintf("%v.%v", tsym, s)
} }
if exportname(t.Sym.Name) { if exportname(tsym.Name) {
n = newfuncname(lookup(p)) s = lookup(p)
} else { } else {
n = newfuncname(Pkglookup(p, t.Sym.Pkg)) s = Pkglookup(p, tsym.Pkg)
} }
return n return newfuncname(s)
} }
// Add a method, declared as a function. // Add a method, declared as a function.
...@@ -1208,9 +1258,6 @@ func addmethod(msym *Sym, t *Type, local, nointerface bool) { ...@@ -1208,9 +1258,6 @@ func addmethod(msym *Sym, t *Type, local, nointerface bool) {
} }
} }
n := nod(ODCLFIELD, newname(msym), nil)
n.Type = t
for _, f := range mt.Methods().Slice() { for _, f := range mt.Methods().Slice() {
if msym.Name != f.Sym.Name { if msym.Name != f.Sym.Name {
continue continue
...@@ -1223,7 +1270,10 @@ func addmethod(msym *Sym, t *Type, local, nointerface bool) { ...@@ -1223,7 +1270,10 @@ func addmethod(msym *Sym, t *Type, local, nointerface bool) {
return return
} }
f := structfield(n) f := newField()
f.Sym = msym
f.Nname = newname(msym)
f.Type = t
f.Nointerface = nointerface f.Nointerface = nointerface
mt.Methods().Append(f) mt.Methods().Append(f)
......
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