ir.CurFunc = nil
- // Compile top level functions.
- // Don't use range--walk can add functions to Target.Decls.
+ reflectdata.WriteBasicTypes()
+
+ // Compile top-level declarations.
+ //
+ // There are cyclic dependencies between all of these phases, so we
+ // need to iterate all of them until we reach a fixed point.
base.Timer.Start("be", "compilefuncs")
- fcount := int64(0)
- for i := 0; i < len(typecheck.Target.Funcs); i++ {
- fn := typecheck.Target.Funcs[i]
- enqueueFunc(fn)
- fcount++
+ for nextFunc, nextExtern := 0, 0; ; {
+ reflectdata.WriteRuntimeTypes()
+
+ if nextExtern < len(typecheck.Target.Externs) {
+ switch n := typecheck.Target.Externs[nextExtern]; n.Op() {
+ case ir.ONAME:
+ dumpGlobal(n)
+ case ir.OLITERAL:
+ dumpGlobalConst(n)
+ case ir.OTYPE:
+ reflectdata.NeedRuntimeType(n.Type())
+ }
+ nextExtern++
+ continue
+ }
+
+ if nextFunc < len(typecheck.Target.Funcs) {
+ enqueueFunc(typecheck.Target.Funcs[nextFunc])
+ nextFunc++
+ continue
+ }
+
+ // The SSA backend supports using multiple goroutines, so keep it
+ // as the last step to maximize how much work we can batch and
+ // process concurrently.
+ if len(compilequeue) != 0 {
+ compileFunctions()
+ continue
+ }
+
+ break
}
- base.Timer.AddEvent(fcount, "funcs")
- compileFunctions()
+ base.Timer.AddEvent(int64(len(typecheck.Target.Funcs)), "funcs")
if base.Flag.CompilingRuntime {
// Write barriers are now known. Check the call graph.
}
func dumpdata() {
- numExterns := len(typecheck.Target.Externs)
- numDecls := len(typecheck.Target.Funcs)
- dumpglobls(typecheck.Target.Externs)
- addsignats(typecheck.Target.Externs)
- reflectdata.WriteRuntimeTypes()
+ reflectdata.WriteGCSymbols()
reflectdata.WritePluginTable()
reflectdata.WriteImportStrings()
- reflectdata.WriteBasicTypes()
dumpembeds()
- // Calls to WriteRuntimeTypes can generate functions,
- // like method wrappers and hash and equality routines.
- // Compile any generated functions, process any new resulting types, repeat.
- // This can't loop forever, because there is no way to generate an infinite
- // number of types in a finite amount of code.
- // In the typical case, we loop 0 or 1 times.
- // It was not until issue 24761 that we found any code that required a loop at all.
- for {
- for i := numDecls; i < len(typecheck.Target.Funcs); i++ {
- fn := typecheck.Target.Funcs[i]
- enqueueFunc(fn)
- }
- numDecls = len(typecheck.Target.Funcs)
- compileFunctions()
- reflectdata.WriteRuntimeTypes()
- if numDecls == len(typecheck.Target.Funcs) {
- break
- }
- }
-
- // Dump extra globals.
- dumpglobls(typecheck.Target.Externs[numExterns:])
-
if reflectdata.ZeroSize > 0 {
zero := base.PkgLinksym("go:map", "zero", obj.ABI0)
objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
}
-func dumpglobls(externs []*ir.Name) {
- // add globals
- for _, n := range externs {
- switch n.Op() {
- case ir.ONAME:
- dumpGlobal(n)
- case ir.OLITERAL:
- dumpGlobalConst(n)
- }
- }
-}
-
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
//
// This is done during the sequential phase after compilation, since
staticdata.WriteEmbed(v)
}
}
-
-func addsignats(dcls []*ir.Name) {
- // copy types from dcl list to signatset
- for _, n := range dcls {
- if n.Op() == ir.OTYPE {
- reflectdata.NeedRuntimeType(n.Type())
- }
- }
-}