// Record user init functions.
for _, fn := range typecheck.Target.Inits {
- if fn.Sym().Name == "init" {
- // Synthetic init function for initialization of package-scope
- // variables. We can use staticinit to optimize away static
- // assignments.
+ if staticinit.CanOptimize(fn) {
s := staticinit.Schedule{
Plans: make(map[ir.Node]*staticinit.Plan),
Temps: make(map[ir.Node]*ir.Name),
"go/constant"
"go/token"
"os"
+ "slices"
"strings"
"cmd/compile/internal/base"
fmt.Fprintf(os.Stderr, "=-= outlined %v map initializations\n", outlined)
}
}
+
+const maxInitStatements = 1000
+
+// SplitLargeInit breaks up a large "init" function into smaller chunks to avoid slow compilation.
+func SplitLargeInit(fn *ir.Func) {
+ if !fn.IsPackageInit() || len(fn.Body) <= maxInitStatements {
+ return
+ }
+ var calls []ir.Node
+ for chunk := range slices.Chunk(fn.Body, maxInitStatements) {
+ varInitFn := generateVarInitFunc(chunk)
+ ir.WithFunc(fn, func() {
+ calls = append(calls, typecheck.Call(varInitFn.Pos(), varInitFn.Nname, nil, false))
+ })
+ }
+ fn.Body = calls
+}
+
+// CanOptimize reports whether the given fn can be optimized for static assignments.
+func CanOptimize(fn *ir.Func) bool {
+ name := fn.Sym().Name
+ return name == "init" || strings.HasPrefix(name, varInitFuncPrefix)
+}
+
+// varInitGen is a counter used to uniquify compiler-generated functions for initializing variables.
+var varInitGen int
+
+const varInitFuncPrefix = "init.var."
+
+// Create a new function that will (eventually) have this form:
+//
+// func init.var.%d() {
+// ...
+// }
+func generateVarInitFunc(body []ir.Node) *ir.Func {
+ pos := base.AutogeneratedPos
+ base.Pos = pos
+
+ sym := typecheck.LookupNum(varInitFuncPrefix, varInitGen)
+ varInitGen++
+
+ fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil, nil, nil))
+ fn.SetInlinabilityChecked(true) // suppress inlining; otherwise, we end up with giant init eventually.
+ fn.SetWrapper(true) // less disruptive on backtraces.
+ typecheck.DeclFunc(fn)
+
+ fn.Body = body
+ typecheck.FinishFuncBody()
+
+ return fn
+}