mirror of
https://github.com/golang/go
synced 2024-11-18 08:14:41 -07:00
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: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
6ca662ca0e
commit
d553c29dc1
@ -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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user