github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/gc/main.go (about)

     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  	"github.com/bir3/gocompiler/src/cmd/compile/internal/base"
    11  	"github.com/bir3/gocompiler/src/cmd/compile/internal/coverage"
    12  	"github.com/bir3/gocompiler/src/cmd/compile/internal/deadcode"
    13  	"github.com/bir3/gocompiler/src/cmd/compile/internal/devirtualize"
    14  	"github.com/bir3/gocompiler/src/cmd/compile/internal/dwarfgen"
    15  	"github.com/bir3/gocompiler/src/cmd/compile/internal/escape"
    16  	"github.com/bir3/gocompiler/src/cmd/compile/internal/inline"
    17  	"github.com/bir3/gocompiler/src/cmd/compile/internal/ir"
    18  	"github.com/bir3/gocompiler/src/cmd/compile/internal/logopt"
    19  	"github.com/bir3/gocompiler/src/cmd/compile/internal/noder"
    20  	"github.com/bir3/gocompiler/src/cmd/compile/internal/pgo"
    21  	"github.com/bir3/gocompiler/src/cmd/compile/internal/pkginit"
    22  	"github.com/bir3/gocompiler/src/cmd/compile/internal/reflectdata"
    23  	"github.com/bir3/gocompiler/src/cmd/compile/internal/ssa"
    24  	"github.com/bir3/gocompiler/src/cmd/compile/internal/ssagen"
    25  	"github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck"
    26  	"github.com/bir3/gocompiler/src/cmd/compile/internal/types"
    27  	"github.com/bir3/gocompiler/src/cmd/internal/dwarf"
    28  	"github.com/bir3/gocompiler/src/cmd/internal/obj"
    29  	"github.com/bir3/gocompiler/src/cmd/internal/objabi"
    30  	"github.com/bir3/gocompiler/src/cmd/internal/src"
    31  	"github.com/bir3/gocompiler/src/cmd/compile/flag"
    32  	"fmt"
    33  	"github.com/bir3/gocompiler/src/internal/buildcfg"
    34  	"log"
    35  	"os"
    36  	"runtime"
    37  )
    38  
    39  // handlePanic ensures that we print out an "internal compiler error" for any panic
    40  // or runtime exception during front-end compiler processing (unless there have
    41  // already been some compiler errors). It may also be invoked from the explicit panic in
    42  // hcrash(), in which case, we pass the panic on through.
    43  func handlePanic() {
    44  	if err := recover(); err != nil {
    45  		if err == "-h" {
    46  			// Force real panic now with -h option (hcrash) - the error
    47  			// information will have already been printed.
    48  			panic(err)
    49  		}
    50  		base.Fatalf("panic: %v", err)
    51  	}
    52  }
    53  
    54  // Main parses flags and Go source files specified in the command-line
    55  // arguments, type-checks the parsed Go package, compiles functions to machine
    56  // code, and finally writes the compiled package definition to disk.
    57  func Main(archInit func(*ssagen.ArchInfo)) {
    58  	base.Timer.Start("fe", "init")
    59  
    60  	defer handlePanic()
    61  
    62  	archInit(&ssagen.Arch)
    63  
    64  	base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
    65  	base.Ctxt.DiagFunc = base.Errorf
    66  	base.Ctxt.DiagFlush = base.FlushErrors
    67  	base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
    68  
    69  	// UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
    70  	// on Darwin don't support it properly, especially since macOS 10.14 (Mojave).  This is exposed as a flag
    71  	// to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
    72  	// See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
    73  	base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin
    74  
    75  	base.DebugSSA = ssa.PhaseOption
    76  	base.ParseFlags()
    77  
    78  	if os.Getenv("GOGC") == "" { // GOGC set disables starting heap adjustment
    79  		// More processors will use more heap, but assume that more memory is available.
    80  		// So 1 processor -> 40MB, 4 -> 64MB, 12 -> 128MB
    81  		base.AdjustStartingHeap(uint64(32+8*base.Flag.LowerC) << 20)
    82  	}
    83  
    84  	types.LocalPkg = types.NewPkg(base.Ctxt.Pkgpath, "")
    85  
    86  	// pseudo-package, for scoping
    87  	types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
    88  	types.BuiltinPkg.Prefix = "go:builtin"
    89  
    90  	// pseudo-package, accessed by import "unsafe"
    91  	types.UnsafePkg = types.NewPkg("unsafe", "unsafe")
    92  
    93  	// Pseudo-package that contains the compiler's builtin
    94  	// declarations for package runtime. These are declared in a
    95  	// separate package to avoid conflicts with package runtime's
    96  	// actual declarations, which may differ intentionally but
    97  	// insignificantly.
    98  	ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
    99  	ir.Pkgs.Runtime.Prefix = "runtime"
   100  
   101  	// pseudo-packages used in symbol tables
   102  	ir.Pkgs.Itab = types.NewPkg("go.itab", "go.itab")
   103  	ir.Pkgs.Itab.Prefix = "go:itab"
   104  
   105  	// pseudo-package used for methods with anonymous receivers
   106  	ir.Pkgs.Go = types.NewPkg("go", "")
   107  
   108  	// pseudo-package for use with code coverage instrumentation.
   109  	ir.Pkgs.Coverage = types.NewPkg("go.coverage", "runtime/coverage")
   110  	ir.Pkgs.Coverage.Prefix = "runtime/coverage"
   111  
   112  	// Record flags that affect the build result. (And don't
   113  	// record flags that don't, since that would cause spurious
   114  	// changes in the binary.)
   115  	dwarfgen.RecordFlags("B", "N", "l", "msan", "race", "asan", "shared", "dynlink", "dwarf", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
   116  
   117  	if !base.EnableTrace && base.Flag.LowerT {
   118  		log.Fatalf("compiler not built with support for -t")
   119  	}
   120  
   121  	// Enable inlining (after RecordFlags, to avoid recording the rewritten -l).  For now:
   122  	//	default: inlining on.  (Flag.LowerL == 1)
   123  	//	-l: inlining off  (Flag.LowerL == 0)
   124  	//	-l=2, -l=3: inlining on again, with extra debugging (Flag.LowerL > 1)
   125  	if base.Flag.LowerL <= 1 {
   126  		base.Flag.LowerL = 1 - base.Flag.LowerL
   127  	}
   128  
   129  	if base.Flag.SmallFrames {
   130  		ir.MaxStackVarSize = 128 * 1024
   131  		ir.MaxImplicitStackVarSize = 16 * 1024
   132  	}
   133  
   134  	if base.Flag.Dwarf {
   135  		base.Ctxt.DebugInfo = dwarfgen.Info
   136  		base.Ctxt.GenAbstractFunc = dwarfgen.AbstractFunc
   137  		base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt)
   138  	} else {
   139  		// turn off inline generation if no dwarf at all
   140  		base.Flag.GenDwarfInl = 0
   141  		base.Ctxt.Flag_locationlists = false
   142  	}
   143  	if base.Ctxt.Flag_locationlists && len(base.Ctxt.Arch.DWARFRegisters) == 0 {
   144  		log.Fatalf("location lists requested but register mapping not available on %v", base.Ctxt.Arch.Name)
   145  	}
   146  
   147  	types.ParseLangFlag()
   148  
   149  	symABIs := ssagen.NewSymABIs()
   150  	if base.Flag.SymABIs != "" {
   151  		symABIs.ReadSymABIs(base.Flag.SymABIs)
   152  	}
   153  
   154  	if base.Compiling(base.NoInstrumentPkgs) {
   155  		base.Flag.Race = false
   156  		base.Flag.MSan = false
   157  		base.Flag.ASan = false
   158  	}
   159  
   160  	ssagen.Arch.LinkArch.Init(base.Ctxt)
   161  	startProfile()
   162  	if base.Flag.Race || base.Flag.MSan || base.Flag.ASan {
   163  		base.Flag.Cfg.Instrumenting = true
   164  	}
   165  	if base.Flag.Dwarf {
   166  		dwarf.EnableLogging(base.Debug.DwarfInl != 0)
   167  	}
   168  	if base.Debug.SoftFloat != 0 {
   169  		ssagen.Arch.SoftFloat = true
   170  	}
   171  
   172  	if base.Flag.JSON != "" { // parse version,destination from json logging optimization.
   173  		logopt.LogJsonOption(base.Flag.JSON)
   174  	}
   175  
   176  	ir.EscFmt = escape.Fmt
   177  	ir.IsIntrinsicCall = ssagen.IsIntrinsicCall
   178  	inline.SSADumpInline = ssagen.DumpInline
   179  	ssagen.InitEnv()
   180  	ssagen.InitTables()
   181  
   182  	types.PtrSize = ssagen.Arch.LinkArch.PtrSize
   183  	types.RegSize = ssagen.Arch.LinkArch.RegSize
   184  	types.MaxWidth = ssagen.Arch.MAXWIDTH
   185  
   186  	typecheck.Target = new(ir.Package)
   187  
   188  	typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): TypeSym for lock?
   189  
   190  	base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
   191  
   192  	typecheck.InitUniverse()
   193  	typecheck.InitRuntime()
   194  
   195  	// Parse and typecheck input.
   196  	noder.LoadPackage(flag.Args())
   197  
   198  	// As a convenience to users (toolchain maintainers, in particular),
   199  	// when compiling a package named "main", we default the package
   200  	// path to "main" if the -p flag was not specified.
   201  	if base.Ctxt.Pkgpath == obj.UnlinkablePkg && types.LocalPkg.Name == "main" {
   202  		base.Ctxt.Pkgpath = "main"
   203  		types.LocalPkg.Path = "main"
   204  		types.LocalPkg.Prefix = "main"
   205  	}
   206  
   207  	dwarfgen.RecordPackageName()
   208  
   209  	// Prepare for backend processing. This must happen before pkginit,
   210  	// because it generates itabs for initializing global variables.
   211  	ssagen.InitConfig()
   212  
   213  	// First part of coverage fixup (if applicable).
   214  	var cnames coverage.Names
   215  	if base.Flag.Cfg.CoverageInfo != nil {
   216  		cnames = coverage.FixupVars()
   217  	}
   218  
   219  	// Create "init" function for package-scope variable initialization
   220  	// statements, if any.
   221  	//
   222  	// Note: This needs to happen early, before any optimizations. The
   223  	// Go spec defines a precise order than initialization should be
   224  	// carried out in, and even mundane optimizations like dead code
   225  	// removal can skew the results (e.g., #43444).
   226  	pkginit.MakeInit()
   227  
   228  	// Second part of code coverage fixup (init func modification),
   229  	// if applicable.
   230  	if base.Flag.Cfg.CoverageInfo != nil {
   231  		coverage.FixupInit(cnames)
   232  	}
   233  
   234  	// Eliminate some obviously dead code.
   235  	// Must happen after typechecking.
   236  	for _, n := range typecheck.Target.Decls {
   237  		if n.Op() == ir.ODCLFUNC {
   238  			deadcode.Func(n.(*ir.Func))
   239  		}
   240  	}
   241  
   242  	// Compute Addrtaken for names.
   243  	// We need to wait until typechecking is done so that when we see &x[i]
   244  	// we know that x has its address taken if x is an array, but not if x is a slice.
   245  	// We compute Addrtaken in bulk here.
   246  	// After this phase, we maintain Addrtaken incrementally.
   247  	if typecheck.DirtyAddrtaken {
   248  		typecheck.ComputeAddrtaken(typecheck.Target.Decls)
   249  		typecheck.DirtyAddrtaken = false
   250  	}
   251  	typecheck.IncrementalAddrtaken = true
   252  
   253  	if base.Debug.TypecheckInl != 0 {
   254  		// Typecheck imported function bodies if Debug.l > 1,
   255  		// otherwise lazily when used or re-exported.
   256  		typecheck.AllImportedBodies()
   257  	}
   258  
   259  	// Read profile file and build profile-graph and weighted-call-graph.
   260  	base.Timer.Start("fe", "pgoprofile")
   261  	var profile *pgo.Profile
   262  	if base.Flag.PgoProfile != "" {
   263  		profile = pgo.New(base.Flag.PgoProfile)
   264  	}
   265  
   266  	// Inlining
   267  	base.Timer.Start("fe", "inlining")
   268  	if base.Flag.LowerL != 0 {
   269  		inline.InlinePackage(profile)
   270  	}
   271  	noder.MakeWrappers(typecheck.Target) // must happen after inlining
   272  
   273  	// Devirtualize.
   274  	for _, n := range typecheck.Target.Decls {
   275  		if n.Op() == ir.ODCLFUNC {
   276  			devirtualize.Func(n.(*ir.Func))
   277  		}
   278  	}
   279  	ir.CurFunc = nil
   280  
   281  	// Build init task, if needed.
   282  	if initTask := pkginit.Task(); initTask != nil {
   283  		typecheck.Export(initTask)
   284  	}
   285  
   286  	// Generate ABI wrappers. Must happen before escape analysis
   287  	// and doesn't benefit from dead-coding or inlining.
   288  	symABIs.GenABIWrappers()
   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.Decls)
   300  
   301  	// TODO(mdempsky): This is a hack. We need a proper, global work
   302  	// queue for scheduling function compilation so components don't
   303  	// need to adjust their behavior depending on when they're called.
   304  	reflectdata.AfterGlobalEscapeAnalysis = true
   305  
   306  	// Collect information for go:nowritebarrierrec
   307  	// checking. This must happen before transforming closures during Walk
   308  	// We'll do the final check after write barriers are
   309  	// inserted.
   310  	if base.Flag.CompilingRuntime {
   311  		ssagen.EnableNoWriteBarrierRecCheck()
   312  	}
   313  
   314  	ir.CurFunc = nil
   315  
   316  	// Compile top level functions.
   317  	// Don't use range--walk can add functions to Target.Decls.
   318  	base.Timer.Start("be", "compilefuncs")
   319  	fcount := int64(0)
   320  	for i := 0; i < len(typecheck.Target.Decls); i++ {
   321  		if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
   322  			// Don't try compiling dead hidden closure.
   323  			if fn.IsDeadcodeClosure() {
   324  				continue
   325  			}
   326  			enqueueFunc(fn)
   327  			fcount++
   328  		}
   329  	}
   330  	base.Timer.AddEvent(fcount, "funcs")
   331  
   332  	compileFunctions()
   333  
   334  	if base.Flag.CompilingRuntime {
   335  		// Write barriers are now known. Check the call graph.
   336  		ssagen.NoWriteBarrierRecCheck()
   337  	}
   338  
   339  	// Finalize DWARF inline routine DIEs, then explicitly turn off
   340  	// DWARF inlining gen so as to avoid problems with generated
   341  	// method wrappers.
   342  	if base.Ctxt.DwFixups != nil {
   343  		base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0)
   344  		base.Ctxt.DwFixups = nil
   345  		base.Flag.GenDwarfInl = 0
   346  	}
   347  
   348  	// Write object data to disk.
   349  	base.Timer.Start("be", "dumpobj")
   350  	dumpdata()
   351  	base.Ctxt.NumberSyms()
   352  	dumpobj()
   353  	if base.Flag.AsmHdr != "" {
   354  		dumpasmhdr()
   355  	}
   356  
   357  	ssagen.CheckLargeStacks()
   358  	typecheck.CheckFuncStack()
   359  
   360  	if len(compilequeue) != 0 {
   361  		base.Fatalf("%d uncompiled functions", len(compilequeue))
   362  	}
   363  
   364  	logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath)
   365  	base.ExitIfErrors()
   366  
   367  	base.FlushErrors()
   368  	base.Timer.Stop()
   369  
   370  	if base.Flag.Bench != "" {
   371  		if err := writebench(base.Flag.Bench); err != nil {
   372  			log.Fatalf("cannot write benchmark data: %v", err)
   373  		}
   374  	}
   375  }
   376  
   377  func writebench(filename string) error {
   378  	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   379  	if err != nil {
   380  		return err
   381  	}
   382  
   383  	var buf bytes.Buffer
   384  	fmt.Fprintln(&buf, "commit:", buildcfg.Version)
   385  	fmt.Fprintln(&buf, "goos:", runtime.GOOS)
   386  	fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
   387  	base.Timer.Write(&buf, "BenchmarkCompile:"+base.Ctxt.Pkgpath+":")
   388  
   389  	n, err := f.Write(buf.Bytes())
   390  	if err != nil {
   391  		return err
   392  	}
   393  	if n != buf.Len() {
   394  		panic("bad writer")
   395  	}
   396  
   397  	return f.Close()
   398  }
   399  
   400  func makePos(b *src.PosBase, line, col uint) src.XPos {
   401  	return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col))
   402  }