mirror of
https://github.com/golang/go
synced 2024-11-23 18:10:04 -07:00
cmd/compile/internal/gc: steps towards work-queue
[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>
This commit is contained in:
parent
96b6e78ea9
commit
cf68384674
@ -113,10 +113,6 @@ func prepareFunc(fn *ir.Func) {
|
|||||||
// It fans out nBackendWorkers to do the work
|
// It fans out nBackendWorkers to do the work
|
||||||
// and waits for them to complete.
|
// and waits for them to complete.
|
||||||
func compileFunctions() {
|
func compileFunctions() {
|
||||||
if len(compilequeue) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if race.Enabled {
|
if race.Enabled {
|
||||||
// Randomize compilation order to try to shake out races.
|
// Randomize compilation order to try to shake out races.
|
||||||
tmp := make([]*ir.Func, len(compilequeue))
|
tmp := make([]*ir.Func, len(compilequeue))
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"cmd/compile/internal/noder"
|
"cmd/compile/internal/noder"
|
||||||
"cmd/compile/internal/pgo"
|
"cmd/compile/internal/pgo"
|
||||||
"cmd/compile/internal/pkginit"
|
"cmd/compile/internal/pkginit"
|
||||||
|
"cmd/compile/internal/reflectdata"
|
||||||
"cmd/compile/internal/ssa"
|
"cmd/compile/internal/ssa"
|
||||||
"cmd/compile/internal/ssagen"
|
"cmd/compile/internal/ssagen"
|
||||||
"cmd/compile/internal/staticinit"
|
"cmd/compile/internal/staticinit"
|
||||||
@ -295,18 +296,62 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
|||||||
|
|
||||||
ir.CurFunc = nil
|
ir.CurFunc = nil
|
||||||
|
|
||||||
// Compile top level functions.
|
reflectdata.WriteBasicTypes()
|
||||||
// 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")
|
|
||||||
|
|
||||||
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 {
|
if base.Flag.CompilingRuntime {
|
||||||
// Write barriers are now known. Check the call graph.
|
// Write barriers are now known. Check the call graph.
|
||||||
@ -318,15 +363,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
|||||||
staticinit.AddKeepRelocations()
|
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.
|
// Write object data to disk.
|
||||||
base.Timer.Start("be", "dumpobj")
|
base.Timer.Start("be", "dumpobj")
|
||||||
dumpdata()
|
dumpdata()
|
||||||
|
@ -110,39 +110,11 @@ func dumpCompilerObj(bout *bio.Writer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dumpdata() {
|
func dumpdata() {
|
||||||
numExterns := len(typecheck.Target.Externs)
|
reflectdata.WriteGCSymbols()
|
||||||
numDecls := len(typecheck.Target.Funcs)
|
|
||||||
dumpglobls(typecheck.Target.Externs)
|
|
||||||
addsignats(typecheck.Target.Externs)
|
|
||||||
reflectdata.WriteRuntimeTypes()
|
|
||||||
reflectdata.WritePluginTable()
|
reflectdata.WritePluginTable()
|
||||||
reflectdata.WriteImportStrings()
|
reflectdata.WriteImportStrings()
|
||||||
reflectdata.WriteBasicTypes()
|
|
||||||
dumpembeds()
|
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 {
|
if reflectdata.ZeroSize > 0 {
|
||||||
zero := base.PkgLinksym("go:map", "zero", obj.ABI0)
|
zero := base.PkgLinksym("go:map", "zero", obj.ABI0)
|
||||||
objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
|
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))
|
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.
|
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
|
||||||
//
|
//
|
||||||
// This is done during the sequential phase after compilation, since
|
// This is done during the sequential phase after compilation, since
|
||||||
@ -323,12 +283,3 @@ func dumpembeds() {
|
|||||||
staticdata.WriteEmbed(v)
|
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1266,7 +1266,9 @@ func WriteRuntimeTypes() {
|
|||||||
}
|
}
|
||||||
signatslice = signatslice[len(signats):]
|
signatslice = signatslice[len(signats):]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteGCSymbols() {
|
||||||
// Emit GC data symbols.
|
// Emit GC data symbols.
|
||||||
gcsyms := make([]typeAndStr, 0, len(gcsymset))
|
gcsyms := make([]typeAndStr, 0, len(gcsymset))
|
||||||
for t := range gcsymset {
|
for t := range gcsymset {
|
||||||
|
27
src/cmd/go/testdata/script/build_issue62156.txt
vendored
Normal file
27
src/cmd/go/testdata/script/build_issue62156.txt
vendored
Normal file
@ -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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user