]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/gc: steps towards work-queue
authorMatthew Dempsky <mdempsky@google.com>
Fri, 18 Aug 2023 07:32:11 +0000 (00:32 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 24 Aug 2023 23:18:16 +0000 (23:18 +0000)
[This is a reattempt of go.dev/cl/520611.]

This CL reorganizes the top-level functions for handling package-level
declarations, runtime type descriptors, and SSA compilation to work in
a loop. This generalizes the loop that previously existed in dumpdata.

Change-Id: I7502798a8662b3cec92d3001169f3af4f804df2a
Reviewed-on: https://go-review.googlesource.com/c/go/+/522339
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/gc/compile.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/obj.go
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/go/testdata/script/build_issue62156.txt [new file with mode: 0644]

index 27d9c55fdb1d51afdd6d0dd35c47a9c7fd5a7911..0f57f8ca8293d18b3c3dcce662050625ee761d7c 100644 (file)
@@ -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))
index 05f0340d39b334f9e364520ded7dbd37aeccd6ed..1314a207deaa97dfd48f7f5c05a992713d1013f0 100644 (file)
@@ -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.
+       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 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(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.
@@ -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()
index 4ff249ca2e0d967fd62ffa65d479ee6dee5a2416..249eeb221dd6ccb386879b0fc6023ec296aa2440 100644 (file)
@@ -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())
-               }
-       }
-}
index 1bf7c8dc7300255f17029974741fdcb481c7154a..223ba1b7ba36fc90de1cc3dd3afe9a802e2155d8 100644 (file)
@@ -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 (file)
index 0000000..d241570
--- /dev/null
@@ -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)
+}