2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
cmd/compile: avoid giant init functions due to many user inits
We generate code that calls each user init function one at a time.
When there are lots of user init functions,
usually due to generated code, like test/rotate* or
github.com/juju/govmomi/vim25/types,
we can end up with a giant function,
which can be slow to compile.
This CL puts in an escape valve.
When there are more than 500 functions, instead of doing:
init.0()
init.1()
// ...
we construct a static array of functions:
var fns = [...]func(){init.0, init.1, ... }
and call them in a loop.
This generates marginally bigger, marginally worse code,
so we restrict it to cases in which it might start to matter.
500 was selected as a mostly arbitrary threshold for "lots".
Each call uses two Progs, one for PCDATA and one for the call,
so at 500 calls we use ~1000 Progs.
At concurrency==8, we get a Prog cache of about
1000 Progs per worker.
So a threshold of 500 should more or less avoid
exhausting the Prog cache in most cases.
Change-Id: I276b887173ddbf65b2164ec9f9b5eb04d8c753c2
Reviewed-on: https://go-review.googlesource.com/41500
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-23 17:31:15 -07:00
|
|
|
import (
|
|
|
|
"cmd/compile/internal/types"
|
|
|
|
)
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
|
2017-04-23 16:34:35 -07:00
|
|
|
// A function named init is a special case.
|
|
|
|
// It is called by the initialization before main is run.
|
|
|
|
// To make it unique within a package and also uncallable,
|
|
|
|
// the name, normally "pkg.init", is altered to "pkg.init.0".
|
|
|
|
var renameinitgen int
|
2015-02-13 14:40:36 -05:00
|
|
|
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
func renameinit() *types.Sym {
|
2017-04-23 16:34:35 -07:00
|
|
|
s := lookupN("init.", renameinitgen)
|
|
|
|
renameinitgen++
|
|
|
|
return s
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2017-03-30 07:38:46 -07:00
|
|
|
// anyinit reports whether there any interesting init statements.
|
2016-02-27 14:31:33 -08:00
|
|
|
func anyinit(n []*Node) bool {
|
|
|
|
for _, ln := range n {
|
|
|
|
switch ln.Op {
|
2015-04-01 09:38:44 -07:00
|
|
|
case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
|
2016-12-19 10:30:44 -08:00
|
|
|
case OAS:
|
2018-04-08 13:39:10 +01:00
|
|
|
if !ln.Left.isBlank() || !candiscard(ln.Right) {
|
2017-03-30 07:38:46 -07:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
default:
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// is this main
|
|
|
|
if localpkg.Name == "main" {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// is there an explicit init function
|
2017-04-23 16:34:35 -07:00
|
|
|
if renameinitgen > 0 {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// are there any imported init functions
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
for _, s := range types.InitSyms {
|
2015-03-02 16:21:15 -05:00
|
|
|
if s.Def != nil {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// then none
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2017-03-30 07:38:46 -07:00
|
|
|
// fninit hand-crafts package initialization code.
|
|
|
|
//
|
2019-01-25 10:21:40 -08:00
|
|
|
// func init.ializers() { (0)
|
|
|
|
// <init stmts>
|
|
|
|
// }
|
2017-03-30 07:38:46 -07:00
|
|
|
// var initdone· uint8 (1)
|
|
|
|
// func init() { (2)
|
|
|
|
// if initdone· > 1 { (3)
|
|
|
|
// return (3a)
|
|
|
|
// }
|
|
|
|
// if initdone· == 1 { (4)
|
|
|
|
// throw() (4a)
|
|
|
|
// }
|
|
|
|
// initdone· = 1 (5)
|
|
|
|
// // over all matching imported symbols
|
|
|
|
// <pkg>.init() (6)
|
2019-01-25 10:21:40 -08:00
|
|
|
// init.ializers() (7)
|
2017-03-30 07:38:46 -07:00
|
|
|
// init.<n>() // if any (8)
|
|
|
|
// initdone· = 2 (9)
|
|
|
|
// return (10)
|
|
|
|
// }
|
2016-03-09 20:29:21 -08:00
|
|
|
func fninit(n []*Node) {
|
2017-03-28 13:52:14 -07:00
|
|
|
lineno = autogeneratedPos
|
2016-03-09 20:29:21 -08:00
|
|
|
nf := initfix(n)
|
2016-02-27 14:31:33 -08:00
|
|
|
if !anyinit(nf) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-25 10:21:40 -08:00
|
|
|
// (0)
|
|
|
|
// Make a function that contains all the initialization statements.
|
|
|
|
// This is a separate function because we want it to appear in
|
|
|
|
// stack traces, where the init function itself does not.
|
|
|
|
var initializers *types.Sym
|
|
|
|
if len(nf) > 0 {
|
|
|
|
lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt
|
|
|
|
initializers = lookup("init.ializers")
|
|
|
|
disableExport(initializers)
|
|
|
|
fn := dclfunc(initializers, nod(OTFUNC, nil, nil))
|
|
|
|
fn.Nbody.Set(nf)
|
|
|
|
funcbody()
|
|
|
|
|
|
|
|
fn = typecheck(fn, ctxStmt)
|
|
|
|
Curfn = fn
|
|
|
|
typecheckslice(nf, ctxStmt)
|
|
|
|
Curfn = nil
|
|
|
|
funccompile(fn)
|
|
|
|
lineno = autogeneratedPos
|
|
|
|
}
|
|
|
|
|
2016-02-27 14:31:33 -08:00
|
|
|
var r []*Node
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// (1)
|
2016-09-15 15:45:10 +10:00
|
|
|
gatevar := newname(lookup("initdone·"))
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
addvar(gatevar, types.Types[TUINT8], PEXTERN)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// (2)
|
2016-09-15 15:45:10 +10:00
|
|
|
initsym := lookup("init")
|
2017-04-10 13:03:14 -07:00
|
|
|
fn := dclfunc(initsym, nod(OTFUNC, nil, nil))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// (3)
|
2016-09-16 11:00:54 +10:00
|
|
|
a := nod(OIF, nil, nil)
|
|
|
|
a.Left = nod(OGT, gatevar, nodintconst(1))
|
2017-04-25 08:46:00 -07:00
|
|
|
a.SetLikely(true)
|
2016-02-27 14:31:33 -08:00
|
|
|
r = append(r, a)
|
2016-01-26 15:55:05 -08:00
|
|
|
// (3a)
|
2016-09-16 11:00:54 +10:00
|
|
|
a.Nbody.Set1(nod(ORETURN, nil, nil))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
// (4)
|
2016-09-16 11:00:54 +10:00
|
|
|
b := nod(OIF, nil, nil)
|
|
|
|
b.Left = nod(OEQ, gatevar, nodintconst(1))
|
2016-01-26 15:55:05 -08:00
|
|
|
// this actually isn't likely, but code layout is better
|
|
|
|
// like this: no JMP needed after the call.
|
2017-04-25 08:46:00 -07:00
|
|
|
b.SetLikely(true)
|
2016-03-01 12:50:17 -08:00
|
|
|
r = append(r, b)
|
2016-01-26 15:55:05 -08:00
|
|
|
// (4a)
|
2016-09-16 11:00:54 +10:00
|
|
|
b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-05-12 12:09:18 -04:00
|
|
|
// (5)
|
2016-09-16 11:00:54 +10:00
|
|
|
a = nod(OAS, gatevar, nodintconst(1))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-27 14:31:33 -08:00
|
|
|
r = append(r, a)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-05-12 12:09:18 -04:00
|
|
|
// (6)
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
for _, s := range types.InitSyms {
|
2018-04-26 15:25:36 -07:00
|
|
|
if s == initsym {
|
|
|
|
continue
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2018-04-26 15:25:36 -07:00
|
|
|
n := resolve(oldname(s))
|
|
|
|
if n.Op == ONONAME {
|
|
|
|
// No package-scope init function; just a
|
|
|
|
// local variable, field name, or something.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
n.checkInitFuncSignature()
|
|
|
|
a = nod(OCALL, n, nil)
|
|
|
|
r = append(r, a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2016-05-12 12:09:18 -04:00
|
|
|
// (7)
|
2019-01-25 10:21:40 -08:00
|
|
|
if initializers != nil {
|
|
|
|
n := newname(initializers)
|
|
|
|
addvar(n, functype(nil, nil, nil), PFUNC)
|
|
|
|
r = append(r, nod(OCALL, n, nil))
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-05-12 12:09:18 -04:00
|
|
|
// (8)
|
cmd/compile: avoid giant init functions due to many user inits
We generate code that calls each user init function one at a time.
When there are lots of user init functions,
usually due to generated code, like test/rotate* or
github.com/juju/govmomi/vim25/types,
we can end up with a giant function,
which can be slow to compile.
This CL puts in an escape valve.
When there are more than 500 functions, instead of doing:
init.0()
init.1()
// ...
we construct a static array of functions:
var fns = [...]func(){init.0, init.1, ... }
and call them in a loop.
This generates marginally bigger, marginally worse code,
so we restrict it to cases in which it might start to matter.
500 was selected as a mostly arbitrary threshold for "lots".
Each call uses two Progs, one for PCDATA and one for the call,
so at 500 calls we use ~1000 Progs.
At concurrency==8, we get a Prog cache of about
1000 Progs per worker.
So a threshold of 500 should more or less avoid
exhausting the Prog cache in most cases.
Change-Id: I276b887173ddbf65b2164ec9f9b5eb04d8c753c2
Reviewed-on: https://go-review.googlesource.com/41500
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-23 17:31:15 -07:00
|
|
|
|
|
|
|
// maxInlineInitCalls is the threshold at which we switch
|
|
|
|
// from generating calls inline to generating a static array
|
|
|
|
// of functions and calling them in a loop.
|
|
|
|
// See CL 41500 for more discussion.
|
|
|
|
const maxInlineInitCalls = 500
|
|
|
|
|
|
|
|
if renameinitgen < maxInlineInitCalls {
|
|
|
|
// Not many init functions. Just call them all directly.
|
|
|
|
for i := 0; i < renameinitgen; i++ {
|
|
|
|
s := lookupN("init.", i)
|
|
|
|
n := asNode(s.Def)
|
|
|
|
n.checkInitFuncSignature()
|
|
|
|
a = nod(OCALL, n, nil)
|
|
|
|
r = append(r, a)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Lots of init functions.
|
|
|
|
// Set up an array of functions and loop to call them.
|
|
|
|
// This is faster to compile and similar at runtime.
|
|
|
|
|
|
|
|
// Build type [renameinitgen]func().
|
|
|
|
typ := types.NewArray(functype(nil, nil, nil), int64(renameinitgen))
|
|
|
|
|
|
|
|
// Make and fill array.
|
|
|
|
fnarr := staticname(typ)
|
|
|
|
fnarr.Name.SetReadonly(true)
|
|
|
|
for i := 0; i < renameinitgen; i++ {
|
|
|
|
s := lookupN("init.", i)
|
|
|
|
lhs := nod(OINDEX, fnarr, nodintconst(int64(i)))
|
|
|
|
rhs := asNode(s.Def)
|
|
|
|
rhs.checkInitFuncSignature()
|
|
|
|
as := nod(OAS, lhs, rhs)
|
2018-11-18 08:34:38 -08:00
|
|
|
as = typecheck(as, ctxStmt)
|
cmd/compile: avoid giant init functions due to many user inits
We generate code that calls each user init function one at a time.
When there are lots of user init functions,
usually due to generated code, like test/rotate* or
github.com/juju/govmomi/vim25/types,
we can end up with a giant function,
which can be slow to compile.
This CL puts in an escape valve.
When there are more than 500 functions, instead of doing:
init.0()
init.1()
// ...
we construct a static array of functions:
var fns = [...]func(){init.0, init.1, ... }
and call them in a loop.
This generates marginally bigger, marginally worse code,
so we restrict it to cases in which it might start to matter.
500 was selected as a mostly arbitrary threshold for "lots".
Each call uses two Progs, one for PCDATA and one for the call,
so at 500 calls we use ~1000 Progs.
At concurrency==8, we get a Prog cache of about
1000 Progs per worker.
So a threshold of 500 should more or less avoid
exhausting the Prog cache in most cases.
Change-Id: I276b887173ddbf65b2164ec9f9b5eb04d8c753c2
Reviewed-on: https://go-review.googlesource.com/41500
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-23 17:31:15 -07:00
|
|
|
genAsStatic(as)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a loop that calls each function in turn.
|
|
|
|
// for i := 0; i < renameinitgen; i++ {
|
|
|
|
// fnarr[i]()
|
|
|
|
// }
|
|
|
|
i := temp(types.Types[TINT])
|
|
|
|
fnidx := nod(OINDEX, fnarr, i)
|
|
|
|
fnidx.SetBounded(true)
|
|
|
|
|
|
|
|
zero := nod(OAS, i, nodintconst(0))
|
|
|
|
cond := nod(OLT, i, nodintconst(int64(renameinitgen)))
|
|
|
|
incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
|
|
|
|
body := nod(OCALL, fnidx, nil)
|
|
|
|
|
|
|
|
loop := nod(OFOR, cond, incr)
|
|
|
|
loop.Nbody.Set1(body)
|
|
|
|
loop.Ninit.Set1(zero)
|
|
|
|
|
2018-11-18 08:34:38 -08:00
|
|
|
loop = typecheck(loop, ctxStmt)
|
cmd/compile: avoid giant init functions due to many user inits
We generate code that calls each user init function one at a time.
When there are lots of user init functions,
usually due to generated code, like test/rotate* or
github.com/juju/govmomi/vim25/types,
we can end up with a giant function,
which can be slow to compile.
This CL puts in an escape valve.
When there are more than 500 functions, instead of doing:
init.0()
init.1()
// ...
we construct a static array of functions:
var fns = [...]func(){init.0, init.1, ... }
and call them in a loop.
This generates marginally bigger, marginally worse code,
so we restrict it to cases in which it might start to matter.
500 was selected as a mostly arbitrary threshold for "lots".
Each call uses two Progs, one for PCDATA and one for the call,
so at 500 calls we use ~1000 Progs.
At concurrency==8, we get a Prog cache of about
1000 Progs per worker.
So a threshold of 500 should more or less avoid
exhausting the Prog cache in most cases.
Change-Id: I276b887173ddbf65b2164ec9f9b5eb04d8c753c2
Reviewed-on: https://go-review.googlesource.com/41500
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-23 17:31:15 -07:00
|
|
|
r = append(r, loop)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2016-05-12 12:09:18 -04:00
|
|
|
// (9)
|
2016-09-16 11:00:54 +10:00
|
|
|
a = nod(OAS, gatevar, nodintconst(2))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-27 14:31:33 -08:00
|
|
|
r = append(r, a)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-05-12 12:09:18 -04:00
|
|
|
// (10)
|
2016-09-16 11:00:54 +10:00
|
|
|
a = nod(ORETURN, nil, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-27 14:31:33 -08:00
|
|
|
r = append(r, a)
|
2015-05-27 10:42:55 -04:00
|
|
|
exportsym(fn.Func.Nname)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-27 14:31:33 -08:00
|
|
|
fn.Nbody.Set(r)
|
2017-08-09 16:13:09 +09:00
|
|
|
funcbody()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
Curfn = fn
|
2018-11-18 08:34:38 -08:00
|
|
|
fn = typecheck(fn, ctxStmt)
|
|
|
|
typecheckslice(r, ctxStmt)
|
2015-02-13 14:40:36 -05:00
|
|
|
Curfn = nil
|
|
|
|
funccompile(fn)
|
|
|
|
}
|
cmd/compile: avoid giant init functions due to many user inits
We generate code that calls each user init function one at a time.
When there are lots of user init functions,
usually due to generated code, like test/rotate* or
github.com/juju/govmomi/vim25/types,
we can end up with a giant function,
which can be slow to compile.
This CL puts in an escape valve.
When there are more than 500 functions, instead of doing:
init.0()
init.1()
// ...
we construct a static array of functions:
var fns = [...]func(){init.0, init.1, ... }
and call them in a loop.
This generates marginally bigger, marginally worse code,
so we restrict it to cases in which it might start to matter.
500 was selected as a mostly arbitrary threshold for "lots".
Each call uses two Progs, one for PCDATA and one for the call,
so at 500 calls we use ~1000 Progs.
At concurrency==8, we get a Prog cache of about
1000 Progs per worker.
So a threshold of 500 should more or less avoid
exhausting the Prog cache in most cases.
Change-Id: I276b887173ddbf65b2164ec9f9b5eb04d8c753c2
Reviewed-on: https://go-review.googlesource.com/41500
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-23 17:31:15 -07:00
|
|
|
|
|
|
|
func (n *Node) checkInitFuncSignature() {
|
2017-05-02 09:16:22 -07:00
|
|
|
if n.Type.NumRecvs()+n.Type.NumParams()+n.Type.NumResults() > 0 {
|
cmd/compile: avoid giant init functions due to many user inits
We generate code that calls each user init function one at a time.
When there are lots of user init functions,
usually due to generated code, like test/rotate* or
github.com/juju/govmomi/vim25/types,
we can end up with a giant function,
which can be slow to compile.
This CL puts in an escape valve.
When there are more than 500 functions, instead of doing:
init.0()
init.1()
// ...
we construct a static array of functions:
var fns = [...]func(){init.0, init.1, ... }
and call them in a loop.
This generates marginally bigger, marginally worse code,
so we restrict it to cases in which it might start to matter.
500 was selected as a mostly arbitrary threshold for "lots".
Each call uses two Progs, one for PCDATA and one for the call,
so at 500 calls we use ~1000 Progs.
At concurrency==8, we get a Prog cache of about
1000 Progs per worker.
So a threshold of 500 should more or less avoid
exhausting the Prog cache in most cases.
Change-Id: I276b887173ddbf65b2164ec9f9b5eb04d8c753c2
Reviewed-on: https://go-review.googlesource.com/41500
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-23 17:31:15 -07:00
|
|
|
Fatalf("init function cannot have receiver, params, or results: %v (%v)", n, n.Type)
|
|
|
|
}
|
|
|
|
}
|