Source file src/cmd/compile/internal/gc/main.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gc
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"cmd/compile/internal/base"
    11  	"cmd/compile/internal/bloop"
    12  	"cmd/compile/internal/coverage"
    13  	"cmd/compile/internal/deadlocals"
    14  	"cmd/compile/internal/dwarfgen"
    15  	"cmd/compile/internal/escape"
    16  	"cmd/compile/internal/inline"
    17  	"cmd/compile/internal/inline/interleaved"
    18  	"cmd/compile/internal/ir"
    19  	"cmd/compile/internal/logopt"
    20  	"cmd/compile/internal/loopvar"
    21  	"cmd/compile/internal/noder"
    22  	"cmd/compile/internal/pgoir"
    23  	"cmd/compile/internal/pkginit"
    24  	"cmd/compile/internal/reflectdata"
    25  	"cmd/compile/internal/rewriteresults"
    26  	"cmd/compile/internal/rttype"
    27  	"cmd/compile/internal/slice"
    28  	"cmd/compile/internal/ssacompile"
    29  	"cmd/compile/internal/ssagen"
    30  	"cmd/compile/internal/staticinit"
    31  	"cmd/compile/internal/stats"
    32  	"cmd/compile/internal/typecheck"
    33  	"cmd/compile/internal/types"
    34  	"cmd/internal/dwarf"
    35  	"cmd/internal/obj"
    36  	"cmd/internal/objabi"
    37  	"cmd/internal/src"
    38  	"cmd/internal/telemetry/counter"
    39  	"flag"
    40  	"fmt"
    41  	"internal/buildcfg"
    42  	"log"
    43  	"os"
    44  	"runtime"
    45  )
    46  
    47  // handlePanic ensures that we print out an "internal compiler error" for any panic
    48  // or runtime exception during front-end compiler processing (unless there have
    49  // already been some compiler errors). It may also be invoked from the explicit panic in
    50  // hcrash(), in which case, we pass the panic on through.
    51  func handlePanic() {
    52  	ir.CloseHTMLWriters()
    53  	noder.CloseHTMLWriters()
    54  	if err := recover(); err != nil {
    55  		if err == "-h" {
    56  			// Force real panic now with -h option (hcrash) - the error
    57  			// information will have already been printed.
    58  			panic(err)
    59  		}
    60  		base.Fatalf("panic: %v", err)
    61  	}
    62  }
    63  
    64  // Main parses flags and Go source files specified in the command-line
    65  // arguments, type-checks the parsed Go package, compiles functions to machine
    66  // code, and finally writes the compiled package definition to disk.
    67  func Main(archInit func(*ssagen.ArchInfo)) {
    68  	base.Timer.Start("fe", "init")
    69  	counter.Open()
    70  	counter.Inc("compile/invocations")
    71  
    72  	defer handlePanic()
    73  
    74  	archInit(&ssagen.Arch)
    75  
    76  	base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
    77  	base.Ctxt.DiagFunc = base.Diagf
    78  	base.Ctxt.DiagFlush = base.FlushErrors
    79  	base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
    80  
    81  	// UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
    82  	// on Darwin don't support it properly, especially since macOS 10.14 (Mojave).  This is exposed as a flag
    83  	// to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
    84  	// See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
    85  	base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin
    86  
    87  	base.DebugSSA = ssacompile.PhaseOption
    88  	base.ParseFlags()
    89  
    90  	if flagGCStart := base.Debug.GCStart; flagGCStart > 0 || // explicit flags overrides environment variable disable of GC boost
    91  		os.Getenv("GOGC") == "" && os.Getenv("GOMEMLIMIT") == "" && base.Flag.LowerC != 1 { // explicit GC knobs or no concurrency implies default heap
    92  		startHeapMB := int64(128)
    93  		if flagGCStart > 0 {
    94  			startHeapMB = int64(flagGCStart)
    95  		}
    96  		base.AdjustStartingHeap(uint64(startHeapMB)<<20, 0, 0, 0, base.Debug.GCAdjust == 1)
    97  	}
    98  
    99  	types.LocalPkg = types.NewPkg(base.Ctxt.Pkgpath, "")
   100  
   101  	// pseudo-package, for scoping
   102  	types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
   103  	types.BuiltinPkg.Prefix = "go:builtin"
   104  
   105  	// pseudo-package, accessed by import "unsafe"
   106  	types.UnsafePkg = types.NewPkg("unsafe", "unsafe")
   107  
   108  	// Pseudo-package that contains the compiler's builtin
   109  	// declarations for package runtime. These are declared in a
   110  	// separate package to avoid conflicts with package runtime's
   111  	// actual declarations, which may differ intentionally but
   112  	// insignificantly.
   113  	ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
   114  	ir.Pkgs.Runtime.Prefix = "runtime"
   115  
   116  	// Pseudo-package that contains the compiler's builtin
   117  	// declarations for maps.
   118  	ir.Pkgs.InternalMaps = types.NewPkg("go.internal/runtime/maps", "internal/runtime/maps")
   119  	ir.Pkgs.InternalMaps.Prefix = "internal/runtime/maps"
   120  
   121  	// pseudo-packages used in symbol tables
   122  	ir.Pkgs.Itab = types.NewPkg("go.itab", "go.itab")
   123  	ir.Pkgs.Itab.Prefix = "go:itab"
   124  
   125  	// pseudo-package used for methods with anonymous receivers
   126  	ir.Pkgs.Go = types.NewPkg("go", "")
   127  
   128  	// pseudo-package for use with code coverage instrumentation.
   129  	ir.Pkgs.Coverage = types.NewPkg("go.coverage", "runtime/coverage")
   130  	ir.Pkgs.Coverage.Prefix = "runtime/coverage"
   131  
   132  	// Record flags that affect the build result. (And don't
   133  	// record flags that don't, since that would cause spurious
   134  	// changes in the binary.)
   135  	dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "asan", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
   136  
   137  	if !base.EnableTrace && base.Flag.LowerT {
   138  		log.Fatalf("compiler not built with support for -t")
   139  	}
   140  
   141  	// Enable inlining (after RecordFlags, to avoid recording the rewritten -l).  For now:
   142  	//	default: inlining on.  (Flag.LowerL == 1)
   143  	//	-l: inlining off  (Flag.LowerL == 0)
   144  	//	-l=2, -l=3: inlining on again, with extra debugging (Flag.LowerL > 1)
   145  	if base.Flag.LowerL <= 1 {
   146  		base.Flag.LowerL = 1 - base.Flag.LowerL
   147  	}
   148  
   149  	if base.Flag.SmallFrames {
   150  		ir.MaxStackVarSize = 64 * 1024
   151  		ir.MaxImplicitStackVarSize = 16 * 1024
   152  	}
   153  
   154  	if base.Flag.Dwarf {
   155  		base.Ctxt.DebugInfo = dwarfgen.Info
   156  		base.Ctxt.GenAbstractFunc = dwarfgen.AbstractFunc
   157  		base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt)
   158  	} else {
   159  		// turn off inline generation if no dwarf at all
   160  		base.Flag.GenDwarfInl = 0
   161  		base.Ctxt.Flag_locationlists = false
   162  	}
   163  	if base.Ctxt.Flag_locationlists && len(base.Ctxt.Arch.DWARFRegisters) == 0 {
   164  		log.Fatalf("location lists requested but register mapping not available on %v", base.Ctxt.Arch.Name)
   165  	}
   166  
   167  	types.ParseLangFlag()
   168  
   169  	symABIs := ssagen.NewSymABIs()
   170  	if base.Flag.SymABIs != "" {
   171  		symABIs.ReadSymABIs(base.Flag.SymABIs)
   172  	}
   173  
   174  	if objabi.LookupPkgSpecial(base.Ctxt.Pkgpath).NoInstrument {
   175  		base.Flag.Race = false
   176  		base.Flag.MSan = false
   177  		base.Flag.ASan = false
   178  	}
   179  
   180  	ssagen.Arch.LinkArch.Init(base.Ctxt)
   181  	startProfile()
   182  	if base.Flag.Race || base.Flag.MSan || base.Flag.ASan {
   183  		base.Flag.Cfg.Instrumenting = true
   184  	}
   185  	if base.Flag.Dwarf {
   186  		dwarf.EnableLogging(base.Debug.DwarfInl != 0)
   187  	}
   188  	if base.Debug.SoftFloat != 0 {
   189  		ssagen.Arch.SoftFloat = true
   190  	}
   191  
   192  	if base.Flag.JSON != "" { // parse version,destination from json logging optimization.
   193  		logopt.LogJsonOption(base.Flag.JSON)
   194  	}
   195  
   196  	ir.EscFmt = escape.Fmt
   197  	ir.IsIntrinsicCall = ssagen.IsIntrinsicCall
   198  	ir.IsIntrinsicSym = ssagen.IsIntrinsicSym
   199  	inline.SSADumpInline = ssagen.DumpInline
   200  	ssagen.InitEnv()
   201  
   202  	types.PtrSize = ssagen.Arch.LinkArch.PtrSize
   203  	types.RegSize = ssagen.Arch.LinkArch.RegSize
   204  	types.MaxWidth = ssagen.Arch.MAXWIDTH
   205  
   206  	typecheck.Target = new(ir.Package)
   207  
   208  	base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
   209  
   210  	typecheck.InitUniverse()
   211  	typecheck.InitRuntime()
   212  	rttype.Init()
   213  
   214  	// Some intrinsics (notably, the simd intrinsics) mention
   215  	// types "eagerly", thus ssagen must be initialized AFTER
   216  	// the type system is ready.
   217  	ssagen.InitTables()
   218  
   219  	// Parse and typecheck input.
   220  	noder.LoadPackage(flag.Args())
   221  
   222  	// As a convenience to users (toolchain maintainers, in particular),
   223  	// when compiling a package named "main", we default the package
   224  	// path to "main" if the -p flag was not specified.
   225  	if base.Ctxt.Pkgpath == obj.UnlinkablePkg && types.LocalPkg.Name == "main" {
   226  		base.Ctxt.Pkgpath = "main"
   227  		types.LocalPkg.Path = "main"
   228  		types.LocalPkg.Prefix = "main"
   229  	}
   230  
   231  	dwarfgen.RecordPackageName()
   232  
   233  	// Prepare for backend processing.
   234  	ssagen.InitConfig(ssacompile.NewConfig(ssagen.Arch.SoftFloat))
   235  
   236  	// Apply coverage fixups, if applicable.
   237  	coverage.Fixup()
   238  
   239  	// Read profile file and build profile-graph and weighted-call-graph.
   240  	base.Timer.Start("fe", "pgo-load-profile")
   241  	var profile *pgoir.Profile
   242  	if base.Flag.PgoProfile != "" {
   243  		var err error
   244  		profile, err = pgoir.New(base.Flag.PgoProfile)
   245  		if err != nil {
   246  			log.Fatalf("%s: PGO error: %v", base.Flag.PgoProfile, err)
   247  		}
   248  	}
   249  
   250  	for _, fn := range typecheck.Target.Funcs {
   251  		if ir.MatchAstDump(fn, "start") {
   252  			ir.AstDump(fn, "start, "+ir.FuncName(fn))
   253  		}
   254  	}
   255  
   256  	// Apply bloop markings.
   257  	bloop.Walk(typecheck.Target)
   258  
   259  	// Interleaved devirtualization and inlining.
   260  	base.Timer.Start("fe", "devirtualize-and-inline")
   261  	interleaved.DevirtualizeAndInlinePackage(typecheck.Target, profile)
   262  
   263  	for _, fn := range typecheck.Target.Funcs {
   264  		if ir.MatchAstDump(fn, "devirtualize-and-inline") {
   265  			ir.AstDump(fn, "devirtualize-and-inline, "+ir.FuncName(fn))
   266  		}
   267  	}
   268  
   269  	noder.MakeWrappers(typecheck.Target) // must happen after inlining
   270  
   271  	// Get variable capture right in for loops.
   272  	var transformed []loopvar.VarAndLoop
   273  	for _, fn := range typecheck.Target.Funcs {
   274  		transformed = append(transformed, loopvar.ForCapture(fn)...)
   275  	}
   276  
   277  	// Build init task, if needed.
   278  	pkginit.MakeTask()
   279  
   280  	// Generate ABI wrappers. Must happen before escape analysis
   281  	// and doesn't benefit from dead-coding or inlining.
   282  	symABIs.GenABIWrappers()
   283  
   284  	// Preassign symbol indexes so that they're set when we emit export data,
   285  	// if it's emitted early. This depends on the results of GenABIWrappers.
   286  	preassignSymIdxs(symABIs)
   287  
   288  	deadlocals.Funcs(typecheck.Target.Funcs)
   289  
   290  	// Escape analysis.
   291  	// Required for moving heap allocations onto stack,
   292  	// which in turn is required by the closure implementation,
   293  	// which stores the addresses of stack variables into the closure.
   294  	// If the closure does not escape, it needs to be on the stack
   295  	// or else the stack copier will not update it.
   296  	// Large values are also moved off stack in escape analysis;
   297  	// because large values may contain pointers, it must happen early.
   298  	base.Timer.Start("fe", "escapes")
   299  	escape.Funcs(typecheck.Target.Funcs)
   300  
   301  	rewriteresults.Funcs(typecheck.Target.Funcs)
   302  
   303  	slice.Funcs(typecheck.Target.Funcs)
   304  
   305  	loopvar.LogTransformations(transformed)
   306  
   307  	// Collect information for go:nowritebarrierrec
   308  	// checking. This must happen before transforming closures during Walk
   309  	// We'll do the final check after write barriers are
   310  	// inserted.
   311  	if base.Flag.CompilingRuntime {
   312  		ssagen.EnableNoWriteBarrierRecCheck()
   313  	}
   314  
   315  	base.Timer.Start("fe", "dumpexport")
   316  	dumpexport()
   317  
   318  	reflectdata.WriteBasicTypes()
   319  
   320  	// Compile top-level declarations.
   321  	//
   322  	// There are cyclic dependencies between all of these phases, so we
   323  	// need to iterate all of them until we reach a fixed point.
   324  	base.Timer.Start("be", "compilefuncs")
   325  	for nextFunc, nextExtern := 0, 0; ; {
   326  		reflectdata.WriteRuntimeTypes()
   327  
   328  		if nextExtern < len(typecheck.Target.Externs) {
   329  			switch n := typecheck.Target.Externs[nextExtern]; n.Op() {
   330  			case ir.ONAME:
   331  				dumpGlobal(n)
   332  			case ir.OLITERAL:
   333  				dumpGlobalConst(n)
   334  			case ir.OTYPE:
   335  				reflectdata.NeedRuntimeType(n.Type())
   336  			}
   337  			nextExtern++
   338  			continue
   339  		}
   340  
   341  		if nextFunc < len(typecheck.Target.Funcs) {
   342  			enqueueFunc(typecheck.Target.Funcs[nextFunc], symABIs)
   343  			nextFunc++
   344  			continue
   345  		}
   346  
   347  		// The SSA backend supports using multiple goroutines, so keep it
   348  		// as late as possible to maximize how much work we can batch and
   349  		// process concurrently.
   350  		if len(compilequeue) != 0 {
   351  			compileFunctions(profile)
   352  			continue
   353  		}
   354  
   355  		// Finalize DWARF inline routine DIEs, then explicitly turn off
   356  		// further DWARF inlining generation to avoid problems with
   357  		// generated method wrappers.
   358  		//
   359  		// Note: The DWARF fixup code for inlined calls currently doesn't
   360  		// allow multiple invocations, so we intentionally run it just
   361  		// once after everything else. Worst case, some generated
   362  		// functions have slightly larger DWARF DIEs.
   363  		if base.Ctxt.DwFixups != nil {
   364  			base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0)
   365  			base.Ctxt.DwFixups = nil
   366  			base.Flag.GenDwarfInl = 0
   367  			continue // may have called reflectdata.TypeLinksym (#62156)
   368  		}
   369  
   370  		break
   371  	}
   372  
   373  	if base.Flag.Stats {
   374  		s := new(stats.Stats)
   375  		for _, fn := range typecheck.Target.Funcs {
   376  			s.Merge(fn.Stats)
   377  		}
   378  		s.Print()
   379  	}
   380  
   381  	base.Timer.AddEvent(int64(len(typecheck.Target.Funcs)), "funcs")
   382  
   383  	if base.Flag.CompilingRuntime {
   384  		// Write barriers are now known. Check the call graph.
   385  		ssagen.NoWriteBarrierRecCheck()
   386  	}
   387  
   388  	// Add keep relocations for global maps.
   389  	if base.Debug.WrapGlobalMapCtl != 1 {
   390  		staticinit.AddKeepRelocations()
   391  	}
   392  
   393  	// Write object data to disk.
   394  	base.Timer.Start("be", "dumpobj")
   395  	dumpdata()
   396  	base.Ctxt.NumberSyms()
   397  	dumpobj()
   398  	if base.Flag.AsmHdr != "" {
   399  		dumpasmhdr()
   400  	}
   401  
   402  	ssagen.CheckLargeStacks()
   403  
   404  	if len(compilequeue) != 0 {
   405  		base.Fatalf("%d uncompiled functions", len(compilequeue))
   406  	}
   407  
   408  	logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath)
   409  	base.ExitIfErrors()
   410  
   411  	base.FlushErrors()
   412  	base.Timer.Stop()
   413  
   414  	if base.Flag.Bench != "" {
   415  		if err := writebench(base.Flag.Bench); err != nil {
   416  			log.Fatalf("cannot write benchmark data: %v", err)
   417  		}
   418  	}
   419  }
   420  
   421  func writebench(filename string) error {
   422  	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   423  	if err != nil {
   424  		return err
   425  	}
   426  
   427  	var buf bytes.Buffer
   428  	fmt.Fprintln(&buf, "commit:", buildcfg.Version)
   429  	fmt.Fprintln(&buf, "goos:", runtime.GOOS)
   430  	fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
   431  	base.Timer.Write(&buf, "BenchmarkCompile:"+base.Ctxt.Pkgpath+":")
   432  
   433  	n, err := f.Write(buf.Bytes())
   434  	if err != nil {
   435  		return err
   436  	}
   437  	if n != buf.Len() {
   438  		panic("bad writer")
   439  	}
   440  
   441  	return f.Close()
   442  }
   443  
   444  func makePos(b *src.PosBase, line, col uint) src.XPos {
   445  	return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col))
   446  }
   447  

View as plain text