diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go index 27d9c55fdb1..0f57f8ca829 100644 --- a/src/cmd/compile/internal/gc/compile.go +++ b/src/cmd/compile/internal/gc/compile.go @@ -113,10 +113,6 @@ func prepareFunc(fn *ir.Func) { // It fans out nBackendWorkers to do the work // and waits for them to complete. func compileFunctions() { - if len(compilequeue) == 0 { - return - } - if race.Enabled { // Randomize compilation order to try to shake out races. tmp := make([]*ir.Func, len(compilequeue)) diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 05f0340d39b..1314a207dea 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -19,6 +19,7 @@ import ( "cmd/compile/internal/noder" "cmd/compile/internal/pgo" "cmd/compile/internal/pkginit" + "cmd/compile/internal/reflectdata" "cmd/compile/internal/ssa" "cmd/compile/internal/ssagen" "cmd/compile/internal/staticinit" @@ -295,18 +296,62 @@ func Main(archInit func(*ssagen.ArchInfo)) { ir.CurFunc = nil - // Compile top level functions. - // Don't use range--walk can add functions to Target.Decls. - 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++ - } - base.Timer.AddEvent(fcount, "funcs") + reflectdata.WriteBasicTypes() - compileFunctions() + // 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") + 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 late as possible to maximize how much work we can batch and + // process concurrently. + if len(compilequeue) != 0 { + compileFunctions() + continue + } + + // Finalize DWARF inline routine DIEs, then explicitly turn off + // further DWARF inlining generation to avoid problems with + // generated method wrappers. + // + // Note: The DWARF fixup code for inlined calls currently doesn't + // allow multiple invocations, so we intentionally run it just + // once after everything else. Worst case, some generated + // functions have slightly larger DWARF DIEs. + if base.Ctxt.DwFixups != nil { + base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0) + base.Ctxt.DwFixups = nil + base.Flag.GenDwarfInl = 0 + continue // may have called reflectdata.TypeLinksym (#62156) + } + + break + } + + base.Timer.AddEvent(int64(len(typecheck.Target.Funcs)), "funcs") if base.Flag.CompilingRuntime { // Write barriers are now known. Check the call graph. @@ -318,15 +363,6 @@ func Main(archInit func(*ssagen.ArchInfo)) { staticinit.AddKeepRelocations() } - // Finalize DWARF inline routine DIEs, then explicitly turn off - // DWARF inlining gen so as to avoid problems with generated - // method wrappers. - if base.Ctxt.DwFixups != nil { - base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0) - base.Ctxt.DwFixups = nil - base.Flag.GenDwarfInl = 0 - } - // Write object data to disk. base.Timer.Start("be", "dumpobj") dumpdata() diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 4ff249ca2e0..249eeb221dd 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -110,39 +110,11 @@ func dumpCompilerObj(bout *bio.Writer) { } 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) @@ -217,18 +189,6 @@ func dumpGlobalConst(n *ir.Name) { 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 @@ -323,12 +283,3 @@ func dumpembeds() { 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()) - } - } -} diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 1bf7c8dc730..223ba1b7ba3 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1266,7 +1266,9 @@ func WriteRuntimeTypes() { } signatslice = signatslice[len(signats):] } +} +func WriteGCSymbols() { // Emit GC data symbols. gcsyms := make([]typeAndStr, 0, len(gcsymset)) for t := range gcsymset { diff --git a/src/cmd/go/testdata/script/build_issue62156.txt b/src/cmd/go/testdata/script/build_issue62156.txt new file mode 100644 index 00000000000..d241570cf61 --- /dev/null +++ b/src/cmd/go/testdata/script/build_issue62156.txt @@ -0,0 +1,27 @@ +# Regression test for https://go.dev/issue/62156: +# DWARF generation for inlined functions may require more runtime type +# descriptors to be written. + +go build + +-- go.mod -- +module m + +go 1.20 +-- main.go -- +package main + +import "m/sub" + +func main() { sub.F() } +-- sub/sub.go -- +package sub + +type iface interface{ m() } + +func F() { + f := func(rt []iface) []iface { + return append([]iface{}, rt...) + } + f(nil) +}