...

Source file src/pkg/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	//go:generate go run mkbuiltin.go
     6	
     7	package gc
     8	
     9	import (
    10		"bufio"
    11		"bytes"
    12		"cmd/compile/internal/ssa"
    13		"cmd/compile/internal/types"
    14		"cmd/internal/bio"
    15		"cmd/internal/dwarf"
    16		"cmd/internal/obj"
    17		"cmd/internal/objabi"
    18		"cmd/internal/src"
    19		"cmd/internal/sys"
    20		"flag"
    21		"fmt"
    22		"internal/goversion"
    23		"io"
    24		"io/ioutil"
    25		"log"
    26		"os"
    27		"path"
    28		"regexp"
    29		"runtime"
    30		"sort"
    31		"strconv"
    32		"strings"
    33	)
    34	
    35	var imported_unsafe bool
    36	
    37	var (
    38		buildid string
    39	)
    40	
    41	var (
    42		Debug_append       int
    43		Debug_closure      int
    44		Debug_compilelater int
    45		debug_dclstack     int
    46		Debug_panic        int
    47		Debug_slice        int
    48		Debug_vlog         bool
    49		Debug_wb           int
    50		Debug_pctab        string
    51		Debug_locationlist int
    52		Debug_typecheckinl int
    53		Debug_gendwarfinl  int
    54		Debug_softfloat    int
    55	)
    56	
    57	// Debug arguments.
    58	// These can be specified with the -d flag, as in "-d nil"
    59	// to set the debug_checknil variable.
    60	// Multiple options can be comma-separated.
    61	// Each option accepts an optional argument, as in "gcprog=2"
    62	var debugtab = []struct {
    63		name string
    64		help string
    65		val  interface{} // must be *int or *string
    66	}{
    67		{"append", "print information about append compilation", &Debug_append},
    68		{"closure", "print information about closure compilation", &Debug_closure},
    69		{"compilelater", "compile functions as late as possible", &Debug_compilelater},
    70		{"disablenil", "disable nil checks", &disable_checknil},
    71		{"dclstack", "run internal dclstack check", &debug_dclstack},
    72		{"gcprog", "print dump of GC programs", &Debug_gcprog},
    73		{"nil", "print information about nil checks", &Debug_checknil},
    74		{"panic", "do not hide any compiler panic", &Debug_panic},
    75		{"slice", "print information about slice compilation", &Debug_slice},
    76		{"typeassert", "print information about type assertion inlining", &Debug_typeassert},
    77		{"wb", "print information about write barriers", &Debug_wb},
    78		{"export", "print export data", &Debug_export},
    79		{"pctab", "print named pc-value table", &Debug_pctab},
    80		{"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
    81		{"typecheckinl", "eager typechecking of inline function bodies", &Debug_typecheckinl},
    82		{"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl},
    83		{"softfloat", "force compiler to emit soft-float code", &Debug_softfloat},
    84	}
    85	
    86	const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
    87	
    88	<key> is one of:
    89	
    90	`
    91	
    92	const debugHelpFooter = `
    93	<value> is key-specific.
    94	
    95	Key "pctab" supports values:
    96		"pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
    97	`
    98	
    99	func usage() {
   100		fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n")
   101		objabi.Flagprint(os.Stderr)
   102		Exit(2)
   103	}
   104	
   105	func hidePanic() {
   106		if Debug_panic == 0 && nsavederrors+nerrors > 0 {
   107			// If we've already complained about things
   108			// in the program, don't bother complaining
   109			// about a panic too; let the user clean up
   110			// the code and try again.
   111			if err := recover(); err != nil {
   112				errorexit()
   113			}
   114		}
   115	}
   116	
   117	// supportsDynlink reports whether or not the code generator for the given
   118	// architecture supports the -shared and -dynlink flags.
   119	func supportsDynlink(arch *sys.Arch) bool {
   120		return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
   121	}
   122	
   123	// timing data for compiler phases
   124	var timings Timings
   125	var benchfile string
   126	
   127	var nowritebarrierrecCheck *nowritebarrierrecChecker
   128	
   129	// Main parses flags and Go source files specified in the command-line
   130	// arguments, type-checks the parsed Go package, compiles functions to machine
   131	// code, and finally writes the compiled package definition to disk.
   132	func Main(archInit func(*Arch)) {
   133		timings.Start("fe", "init")
   134	
   135		defer hidePanic()
   136	
   137		archInit(&thearch)
   138	
   139		Ctxt = obj.Linknew(thearch.LinkArch)
   140		Ctxt.DiagFunc = yyerror
   141		Ctxt.DiagFlush = flusherrors
   142		Ctxt.Bso = bufio.NewWriter(os.Stdout)
   143	
   144		// UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
   145		// on Darwin don't support it properly, especially since macOS 10.14 (Mojave).  This is exposed as a flag
   146		// to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
   147		// See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
   148		Ctxt.UseBASEntries = Ctxt.Headtype != objabi.Hdarwin
   149	
   150		localpkg = types.NewPkg("", "")
   151		localpkg.Prefix = "\"\""
   152	
   153		// We won't know localpkg's height until after import
   154		// processing. In the mean time, set to MaxPkgHeight to ensure
   155		// height comparisons at least work until then.
   156		localpkg.Height = types.MaxPkgHeight
   157	
   158		// pseudo-package, for scoping
   159		builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
   160		builtinpkg.Prefix = "go.builtin"            // not go%2ebuiltin
   161	
   162		// pseudo-package, accessed by import "unsafe"
   163		unsafepkg = types.NewPkg("unsafe", "unsafe")
   164	
   165		// Pseudo-package that contains the compiler's builtin
   166		// declarations for package runtime. These are declared in a
   167		// separate package to avoid conflicts with package runtime's
   168		// actual declarations, which may differ intentionally but
   169		// insignificantly.
   170		Runtimepkg = types.NewPkg("go.runtime", "runtime")
   171		Runtimepkg.Prefix = "runtime"
   172	
   173		// pseudo-packages used in symbol tables
   174		itabpkg = types.NewPkg("go.itab", "go.itab")
   175		itabpkg.Prefix = "go.itab" // not go%2eitab
   176	
   177		itablinkpkg = types.NewPkg("go.itablink", "go.itablink")
   178		itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
   179	
   180		trackpkg = types.NewPkg("go.track", "go.track")
   181		trackpkg.Prefix = "go.track" // not go%2etrack
   182	
   183		// pseudo-package used for map zero values
   184		mappkg = types.NewPkg("go.map", "go.map")
   185		mappkg.Prefix = "go.map"
   186	
   187		// pseudo-package used for methods with anonymous receivers
   188		gopkg = types.NewPkg("go", "")
   189	
   190		Nacl = objabi.GOOS == "nacl"
   191		Wasm := objabi.GOARCH == "wasm"
   192	
   193		// Whether the limit for stack-allocated objects is much smaller than normal.
   194		// This can be helpful for diagnosing certain causes of GC latency. See #27732.
   195		smallFrames := false
   196	
   197		flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
   198		flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
   199		objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
   200		objabi.Flagcount("B", "disable bounds checking", &Debug['B'])
   201		objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C']) // TODO(gri) remove eventually
   202		flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
   203		objabi.Flagcount("E", "debug symbol export", &Debug['E'])
   204		objabi.Flagfn1("I", "add `directory` to import search path", addidir)
   205		objabi.Flagcount("K", "debug missing line numbers", &Debug['K'])
   206		objabi.Flagcount("L", "show full file names in error messages", &Debug['L'])
   207		objabi.Flagcount("N", "disable optimizations", &Debug['N'])
   208		objabi.Flagcount("S", "print assembly listing", &Debug['S'])
   209		objabi.AddVersionFlag() // -V
   210		objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
   211		flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
   212		flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
   213		flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
   214		flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
   215		flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
   216		flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
   217		flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
   218		flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
   219		objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
   220		objabi.Flagcount("h", "halt on error", &Debug['h'])
   221		objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
   222		objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
   223		flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
   224		objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
   225		objabi.Flagcount("l", "disable inlining", &Debug['l'])
   226		flag.StringVar(&flag_lang, "lang", "", "release to compile for")
   227		flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
   228		objabi.Flagcount("live", "debug liveness analysis", &debuglive)
   229		objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
   230		if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
   231			flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
   232		}
   233		flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
   234		flag.StringVar(&outfile, "o", "", "write output to `file`")
   235		flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
   236		flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o")
   237		objabi.Flagcount("r", "debug generated wrappers", &Debug['r'])
   238		if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
   239			flag.BoolVar(&flag_race, "race", false, "enable race detector")
   240		}
   241		objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
   242		if enableTrace {
   243			flag.BoolVar(&trace, "t", false, "trace type-checking")
   244		}
   245		flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
   246		flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
   247		objabi.Flagcount("w", "debug type checking", &Debug['w'])
   248		flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
   249		var flag_shared bool
   250		var flag_dynlink bool
   251		if supportsDynlink(thearch.LinkArch.Arch) {
   252			flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
   253			flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
   254		}
   255		flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
   256		flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
   257		flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
   258		var goversion string
   259		flag.StringVar(&goversion, "goversion", "", "required version of the runtime")
   260		var symabisPath string
   261		flag.StringVar(&symabisPath, "symabis", "", "read symbol ABIs from `file`")
   262		flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
   263		flag.StringVar(&blockprofile, "blockprofile", "", "write block profile to `file`")
   264		flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`")
   265		flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
   266		flag.BoolVar(&newescape, "newescape", true, "enable new escape analysis")
   267		flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
   268		flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
   269		objabi.Flagparse(usage)
   270	
   271		// Record flags that affect the build result. (And don't
   272		// record flags that don't, since that would cause spurious
   273		// changes in the binary.)
   274		recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "newescape", "dwarfbasentries", "smallframes")
   275	
   276		if smallFrames {
   277			maxStackVarSize = 128 * 1024
   278			maxImplicitStackVarSize = 16 * 1024
   279		}
   280	
   281		Ctxt.Flag_shared = flag_dynlink || flag_shared
   282		Ctxt.Flag_dynlink = flag_dynlink
   283		Ctxt.Flag_optimize = Debug['N'] == 0
   284	
   285		Ctxt.Debugasm = Debug['S']
   286		Ctxt.Debugvlog = Debug_vlog
   287		if flagDWARF {
   288			Ctxt.DebugInfo = debuginfo
   289			Ctxt.GenAbstractFunc = genAbstractFunc
   290			Ctxt.DwFixups = obj.NewDwarfFixupTable(Ctxt)
   291		} else {
   292			// turn off inline generation if no dwarf at all
   293			genDwarfInline = 0
   294			Ctxt.Flag_locationlists = false
   295		}
   296	
   297		if flag.NArg() < 1 && debugstr != "help" && debugstr != "ssa/help" {
   298			usage()
   299		}
   300	
   301		if goversion != "" && goversion != runtime.Version() {
   302			fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), goversion)
   303			Exit(2)
   304		}
   305	
   306		checkLang()
   307	
   308		if symabisPath != "" {
   309			readSymABIs(symabisPath, myimportpath)
   310		}
   311	
   312		thearch.LinkArch.Init(Ctxt)
   313	
   314		if outfile == "" {
   315			p := flag.Arg(0)
   316			if i := strings.LastIndex(p, "/"); i >= 0 {
   317				p = p[i+1:]
   318			}
   319			if runtime.GOOS == "windows" {
   320				if i := strings.LastIndex(p, `\`); i >= 0 {
   321					p = p[i+1:]
   322				}
   323			}
   324			if i := strings.LastIndex(p, "."); i >= 0 {
   325				p = p[:i]
   326			}
   327			suffix := ".o"
   328			if writearchive {
   329				suffix = ".a"
   330			}
   331			outfile = p + suffix
   332		}
   333	
   334		startProfile()
   335	
   336		if flag_race && flag_msan {
   337			log.Fatal("cannot use both -race and -msan")
   338		}
   339		if ispkgin(omit_pkgs) {
   340			flag_race = false
   341			flag_msan = false
   342		}
   343		if flag_race {
   344			racepkg = types.NewPkg("runtime/race", "")
   345		}
   346		if flag_msan {
   347			msanpkg = types.NewPkg("runtime/msan", "")
   348		}
   349		if flag_race || flag_msan {
   350			instrumenting = true
   351		}
   352	
   353		if compiling_runtime && Debug['N'] != 0 {
   354			log.Fatal("cannot disable optimizations while compiling runtime")
   355		}
   356		if nBackendWorkers < 1 {
   357			log.Fatalf("-c must be at least 1, got %d", nBackendWorkers)
   358		}
   359		if nBackendWorkers > 1 && !concurrentBackendAllowed() {
   360			log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
   361		}
   362		if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
   363			log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
   364		}
   365	
   366		// parse -d argument
   367		if debugstr != "" {
   368		Split:
   369			for _, name := range strings.Split(debugstr, ",") {
   370				if name == "" {
   371					continue
   372				}
   373				// display help about the -d option itself and quit
   374				if name == "help" {
   375					fmt.Print(debugHelpHeader)
   376					maxLen := len("ssa/help")
   377					for _, t := range debugtab {
   378						if len(t.name) > maxLen {
   379							maxLen = len(t.name)
   380						}
   381					}
   382					for _, t := range debugtab {
   383						fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
   384					}
   385					// ssa options have their own help
   386					fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
   387					fmt.Print(debugHelpFooter)
   388					os.Exit(0)
   389				}
   390				val, valstring, haveInt := 1, "", true
   391				if i := strings.IndexAny(name, "=:"); i >= 0 {
   392					var err error
   393					name, valstring = name[:i], name[i+1:]
   394					val, err = strconv.Atoi(valstring)
   395					if err != nil {
   396						val, haveInt = 1, false
   397					}
   398				}
   399				for _, t := range debugtab {
   400					if t.name != name {
   401						continue
   402					}
   403					switch vp := t.val.(type) {
   404					case nil:
   405						// Ignore
   406					case *string:
   407						*vp = valstring
   408					case *int:
   409						if !haveInt {
   410							log.Fatalf("invalid debug value %v", name)
   411						}
   412						*vp = val
   413					default:
   414						panic("bad debugtab type")
   415					}
   416					continue Split
   417				}
   418				// special case for ssa for now
   419				if strings.HasPrefix(name, "ssa/") {
   420					// expect form ssa/phase/flag
   421					// e.g. -d=ssa/generic_cse/time
   422					// _ in phase name also matches space
   423					phase := name[4:]
   424					flag := "debug" // default flag is debug
   425					if i := strings.Index(phase, "/"); i >= 0 {
   426						flag = phase[i+1:]
   427						phase = phase[:i]
   428					}
   429					err := ssa.PhaseOption(phase, flag, val, valstring)
   430					if err != "" {
   431						log.Fatalf(err)
   432					}
   433					continue Split
   434				}
   435				log.Fatalf("unknown debug key -d %s\n", name)
   436			}
   437		}
   438	
   439		// set via a -d flag
   440		Ctxt.Debugpcln = Debug_pctab
   441		if flagDWARF {
   442			dwarf.EnableLogging(Debug_gendwarfinl != 0)
   443		}
   444	
   445		if Debug_softfloat != 0 {
   446			thearch.SoftFloat = true
   447		}
   448	
   449		// enable inlining.  for now:
   450		//	default: inlining on.  (debug['l'] == 1)
   451		//	-l: inlining off  (debug['l'] == 0)
   452		//	-l=2, -l=3: inlining on again, with extra debugging (debug['l'] > 1)
   453		if Debug['l'] <= 1 {
   454			Debug['l'] = 1 - Debug['l']
   455		}
   456	
   457		ssaDump = os.Getenv("GOSSAFUNC")
   458		if ssaDump != "" {
   459			if strings.HasSuffix(ssaDump, "+") {
   460				ssaDump = ssaDump[:len(ssaDump)-1]
   461				ssaDumpStdout = true
   462			}
   463			spl := strings.Split(ssaDump, ":")
   464			if len(spl) > 1 {
   465				ssaDump = spl[0]
   466				ssaDumpCFG = spl[1]
   467			}
   468		}
   469	
   470		trackScopes = flagDWARF
   471	
   472		Widthptr = thearch.LinkArch.PtrSize
   473		Widthreg = thearch.LinkArch.RegSize
   474	
   475		// initialize types package
   476		// (we need to do this to break dependencies that otherwise
   477		// would lead to import cycles)
   478		types.Widthptr = Widthptr
   479		types.Dowidth = dowidth
   480		types.Fatalf = Fatalf
   481		types.Sconv = func(s *types.Sym, flag, mode int) string {
   482			return sconv(s, FmtFlag(flag), fmtMode(mode))
   483		}
   484		types.Tconv = func(t *types.Type, flag, mode, depth int) string {
   485			return tconv(t, FmtFlag(flag), fmtMode(mode), depth)
   486		}
   487		types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
   488			symFormat(sym, s, verb, fmtMode(mode))
   489		}
   490		types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
   491			typeFormat(t, s, verb, fmtMode(mode))
   492		}
   493		types.TypeLinkSym = func(t *types.Type) *obj.LSym {
   494			return typenamesym(t).Linksym()
   495		}
   496		types.FmtLeft = int(FmtLeft)
   497		types.FmtUnsigned = int(FmtUnsigned)
   498		types.FErr = FErr
   499		types.Ctxt = Ctxt
   500	
   501		initUniverse()
   502	
   503		dclcontext = PEXTERN
   504		nerrors = 0
   505	
   506		autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
   507	
   508		timings.Start("fe", "loadsys")
   509		loadsys()
   510	
   511		timings.Start("fe", "parse")
   512		lines := parseFiles(flag.Args())
   513		timings.Stop()
   514		timings.AddEvent(int64(lines), "lines")
   515	
   516		finishUniverse()
   517	
   518		recordPackageName()
   519	
   520		typecheckok = true
   521	
   522		// Process top-level declarations in phases.
   523	
   524		// Phase 1: const, type, and names and types of funcs.
   525		//   This will gather all the information about types
   526		//   and methods but doesn't depend on any of it.
   527		//
   528		//   We also defer type alias declarations until phase 2
   529		//   to avoid cycles like #18640.
   530		//   TODO(gri) Remove this again once we have a fix for #25838.
   531		defercheckwidth()
   532	
   533		// Don't use range--typecheck can add closures to xtop.
   534		timings.Start("fe", "typecheck", "top1")
   535		for i := 0; i < len(xtop); i++ {
   536			n := xtop[i]
   537			if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
   538				xtop[i] = typecheck(n, ctxStmt)
   539			}
   540		}
   541	
   542		// Phase 2: Variable assignments.
   543		//   To check interface assignments, depends on phase 1.
   544	
   545		// Don't use range--typecheck can add closures to xtop.
   546		timings.Start("fe", "typecheck", "top2")
   547		for i := 0; i < len(xtop); i++ {
   548			n := xtop[i]
   549			if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
   550				xtop[i] = typecheck(n, ctxStmt)
   551			}
   552		}
   553		resumecheckwidth()
   554	
   555		// Phase 3: Type check function bodies.
   556		// Don't use range--typecheck can add closures to xtop.
   557		timings.Start("fe", "typecheck", "func")
   558		var fcount int64
   559		for i := 0; i < len(xtop); i++ {
   560			n := xtop[i]
   561			if op := n.Op; op == ODCLFUNC || op == OCLOSURE {
   562				Curfn = n
   563				decldepth = 1
   564				saveerrors()
   565				typecheckslice(Curfn.Nbody.Slice(), ctxStmt)
   566				checkreturn(Curfn)
   567				if nerrors != 0 {
   568					Curfn.Nbody.Set(nil) // type errors; do not compile
   569				}
   570				// Now that we've checked whether n terminates,
   571				// we can eliminate some obviously dead code.
   572				deadcode(Curfn)
   573				fcount++
   574			}
   575		}
   576		// With all types ckecked, it's now safe to verify map keys. One single
   577		// check past phase 9 isn't sufficient, as we may exit with other errors
   578		// before then, thus skipping map key errors.
   579		checkMapKeys()
   580		timings.AddEvent(fcount, "funcs")
   581	
   582		if nsavederrors+nerrors != 0 {
   583			errorexit()
   584		}
   585	
   586		// Phase 4: Decide how to capture closed variables.
   587		// This needs to run before escape analysis,
   588		// because variables captured by value do not escape.
   589		timings.Start("fe", "capturevars")
   590		for _, n := range xtop {
   591			if n.Op == ODCLFUNC && n.Func.Closure != nil {
   592				Curfn = n
   593				capturevars(n)
   594			}
   595		}
   596		capturevarscomplete = true
   597	
   598		Curfn = nil
   599	
   600		if nsavederrors+nerrors != 0 {
   601			errorexit()
   602		}
   603	
   604		// Phase 5: Inlining
   605		timings.Start("fe", "inlining")
   606		if Debug_typecheckinl != 0 {
   607			// Typecheck imported function bodies if debug['l'] > 1,
   608			// otherwise lazily when used or re-exported.
   609			for _, n := range importlist {
   610				if n.Func.Inl != nil {
   611					saveerrors()
   612					typecheckinl(n)
   613				}
   614			}
   615	
   616			if nsavederrors+nerrors != 0 {
   617				errorexit()
   618			}
   619		}
   620	
   621		if Debug['l'] != 0 {
   622			// Find functions that can be inlined and clone them before walk expands them.
   623			visitBottomUp(xtop, func(list []*Node, recursive bool) {
   624				for _, n := range list {
   625					if !recursive {
   626						caninl(n)
   627					} else {
   628						if Debug['m'] > 1 {
   629							fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
   630						}
   631					}
   632					inlcalls(n)
   633				}
   634			})
   635		}
   636	
   637		// Phase 6: Escape analysis.
   638		// Required for moving heap allocations onto stack,
   639		// which in turn is required by the closure implementation,
   640		// which stores the addresses of stack variables into the closure.
   641		// If the closure does not escape, it needs to be on the stack
   642		// or else the stack copier will not update it.
   643		// Large values are also moved off stack in escape analysis;
   644		// because large values may contain pointers, it must happen early.
   645		timings.Start("fe", "escapes")
   646		escapes(xtop)
   647	
   648		// Collect information for go:nowritebarrierrec
   649		// checking. This must happen before transformclosure.
   650		// We'll do the final check after write barriers are
   651		// inserted.
   652		if compiling_runtime {
   653			nowritebarrierrecCheck = newNowritebarrierrecChecker()
   654		}
   655	
   656		// Phase 7: Transform closure bodies to properly reference captured variables.
   657		// This needs to happen before walk, because closures must be transformed
   658		// before walk reaches a call of a closure.
   659		timings.Start("fe", "xclosures")
   660		for _, n := range xtop {
   661			if n.Op == ODCLFUNC && n.Func.Closure != nil {
   662				Curfn = n
   663				transformclosure(n)
   664			}
   665		}
   666	
   667		// Prepare for SSA compilation.
   668		// This must be before peekitabs, because peekitabs
   669		// can trigger function compilation.
   670		initssaconfig()
   671	
   672		// Just before compilation, compile itabs found on
   673		// the right side of OCONVIFACE so that methods
   674		// can be de-virtualized during compilation.
   675		Curfn = nil
   676		peekitabs()
   677	
   678		// Phase 8: Compile top level functions.
   679		// Don't use range--walk can add functions to xtop.
   680		timings.Start("be", "compilefuncs")
   681		fcount = 0
   682		for i := 0; i < len(xtop); i++ {
   683			n := xtop[i]
   684			if n.Op == ODCLFUNC {
   685				funccompile(n)
   686				fcount++
   687			}
   688		}
   689		timings.AddEvent(fcount, "funcs")
   690	
   691		if nsavederrors+nerrors == 0 {
   692			fninit(xtop)
   693		}
   694	
   695		compileFunctions()
   696	
   697		if nowritebarrierrecCheck != nil {
   698			// Write barriers are now known. Check the
   699			// call graph.
   700			nowritebarrierrecCheck.check()
   701			nowritebarrierrecCheck = nil
   702		}
   703	
   704		// Finalize DWARF inline routine DIEs, then explicitly turn off
   705		// DWARF inlining gen so as to avoid problems with generated
   706		// method wrappers.
   707		if Ctxt.DwFixups != nil {
   708			Ctxt.DwFixups.Finalize(myimportpath, Debug_gendwarfinl != 0)
   709			Ctxt.DwFixups = nil
   710			genDwarfInline = 0
   711		}
   712	
   713		// Phase 9: Check external declarations.
   714		timings.Start("be", "externaldcls")
   715		for i, n := range externdcl {
   716			if n.Op == ONAME {
   717				externdcl[i] = typecheck(externdcl[i], ctxExpr)
   718			}
   719		}
   720		// Check the map keys again, since we typechecked the external
   721		// declarations.
   722		checkMapKeys()
   723	
   724		if nerrors+nsavederrors != 0 {
   725			errorexit()
   726		}
   727	
   728		// Write object data to disk.
   729		timings.Start("be", "dumpobj")
   730		dumpobj()
   731		if asmhdr != "" {
   732			dumpasmhdr()
   733		}
   734	
   735		// Check whether any of the functions we have compiled have gigantic stack frames.
   736		sort.Slice(largeStackFrames, func(i, j int) bool {
   737			return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
   738		})
   739		for _, large := range largeStackFrames {
   740			if large.callee != 0 {
   741				yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
   742			} else {
   743				yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
   744			}
   745		}
   746	
   747		if len(compilequeue) != 0 {
   748			Fatalf("%d uncompiled functions", len(compilequeue))
   749		}
   750	
   751		if nerrors+nsavederrors != 0 {
   752			errorexit()
   753		}
   754	
   755		flusherrors()
   756		timings.Stop()
   757	
   758		if benchfile != "" {
   759			if err := writebench(benchfile); err != nil {
   760				log.Fatalf("cannot write benchmark data: %v", err)
   761			}
   762		}
   763	}
   764	
   765	func writebench(filename string) error {
   766		f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   767		if err != nil {
   768			return err
   769		}
   770	
   771		var buf bytes.Buffer
   772		fmt.Fprintln(&buf, "commit:", objabi.Version)
   773		fmt.Fprintln(&buf, "goos:", runtime.GOOS)
   774		fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
   775		timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":")
   776	
   777		n, err := f.Write(buf.Bytes())
   778		if err != nil {
   779			return err
   780		}
   781		if n != buf.Len() {
   782			panic("bad writer")
   783		}
   784	
   785		return f.Close()
   786	}
   787	
   788	var (
   789		importMap   = map[string]string{}
   790		packageFile map[string]string // nil means not in use
   791	)
   792	
   793	func addImportMap(s string) {
   794		if strings.Count(s, "=") != 1 {
   795			log.Fatal("-importmap argument must be of the form source=actual")
   796		}
   797		i := strings.Index(s, "=")
   798		source, actual := s[:i], s[i+1:]
   799		if source == "" || actual == "" {
   800			log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
   801		}
   802		importMap[source] = actual
   803	}
   804	
   805	func readImportCfg(file string) {
   806		packageFile = map[string]string{}
   807		data, err := ioutil.ReadFile(file)
   808		if err != nil {
   809			log.Fatalf("-importcfg: %v", err)
   810		}
   811	
   812		for lineNum, line := range strings.Split(string(data), "\n") {
   813			lineNum++ // 1-based
   814			line = strings.TrimSpace(line)
   815			if line == "" || strings.HasPrefix(line, "#") {
   816				continue
   817			}
   818	
   819			var verb, args string
   820			if i := strings.Index(line, " "); i < 0 {
   821				verb = line
   822			} else {
   823				verb, args = line[:i], strings.TrimSpace(line[i+1:])
   824			}
   825			var before, after string
   826			if i := strings.Index(args, "="); i >= 0 {
   827				before, after = args[:i], args[i+1:]
   828			}
   829			switch verb {
   830			default:
   831				log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
   832			case "importmap":
   833				if before == "" || after == "" {
   834					log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
   835				}
   836				importMap[before] = after
   837			case "packagefile":
   838				if before == "" || after == "" {
   839					log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
   840				}
   841				packageFile[before] = after
   842			}
   843		}
   844	}
   845	
   846	// symabiDefs and symabiRefs record the defined and referenced ABIs of
   847	// symbols required by non-Go code. These are keyed by link symbol
   848	// name, where the local package prefix is always `"".`
   849	var symabiDefs, symabiRefs map[string]obj.ABI
   850	
   851	// readSymABIs reads a symabis file that specifies definitions and
   852	// references of text symbols by ABI.
   853	//
   854	// The symabis format is a set of lines, where each line is a sequence
   855	// of whitespace-separated fields. The first field is a verb and is
   856	// either "def" for defining a symbol ABI or "ref" for referencing a
   857	// symbol using an ABI. For both "def" and "ref", the second field is
   858	// the symbol name and the third field is the ABI name, as one of the
   859	// named cmd/internal/obj.ABI constants.
   860	func readSymABIs(file, myimportpath string) {
   861		data, err := ioutil.ReadFile(file)
   862		if err != nil {
   863			log.Fatalf("-symabis: %v", err)
   864		}
   865	
   866		symabiDefs = make(map[string]obj.ABI)
   867		symabiRefs = make(map[string]obj.ABI)
   868	
   869		localPrefix := ""
   870		if myimportpath != "" {
   871			// Symbols in this package may be written either as
   872			// "".X or with the package's import path already in
   873			// the symbol.
   874			localPrefix = objabi.PathToPrefix(myimportpath) + "."
   875		}
   876	
   877		for lineNum, line := range strings.Split(string(data), "\n") {
   878			lineNum++ // 1-based
   879			line = strings.TrimSpace(line)
   880			if line == "" || strings.HasPrefix(line, "#") {
   881				continue
   882			}
   883	
   884			parts := strings.Fields(line)
   885			switch parts[0] {
   886			case "def", "ref":
   887				// Parse line.
   888				if len(parts) != 3 {
   889					log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
   890				}
   891				sym, abi := parts[1], parts[2]
   892				if abi != "ABI0" { // Only supported external ABI right now
   893					log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi)
   894				}
   895	
   896				// If the symbol is already prefixed with
   897				// myimportpath, rewrite it to start with ""
   898				// so it matches the compiler's internal
   899				// symbol names.
   900				if localPrefix != "" && strings.HasPrefix(sym, localPrefix) {
   901					sym = `"".` + sym[len(localPrefix):]
   902				}
   903	
   904				// Record for later.
   905				if parts[0] == "def" {
   906					symabiDefs[sym] = obj.ABI0
   907				} else {
   908					symabiRefs[sym] = obj.ABI0
   909				}
   910			default:
   911				log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
   912			}
   913		}
   914	}
   915	
   916	func saveerrors() {
   917		nsavederrors += nerrors
   918		nerrors = 0
   919	}
   920	
   921	func arsize(b *bufio.Reader, name string) int {
   922		var buf [ArhdrSize]byte
   923		if _, err := io.ReadFull(b, buf[:]); err != nil {
   924			return -1
   925		}
   926		aname := strings.Trim(string(buf[0:16]), " ")
   927		if !strings.HasPrefix(aname, name) {
   928			return -1
   929		}
   930		asize := strings.Trim(string(buf[48:58]), " ")
   931		i, _ := strconv.Atoi(asize)
   932		return i
   933	}
   934	
   935	var idirs []string
   936	
   937	func addidir(dir string) {
   938		if dir != "" {
   939			idirs = append(idirs, dir)
   940		}
   941	}
   942	
   943	func isDriveLetter(b byte) bool {
   944		return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
   945	}
   946	
   947	// is this path a local name? begins with ./ or ../ or /
   948	func islocalname(name string) bool {
   949		return strings.HasPrefix(name, "/") ||
   950			runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
   951			strings.HasPrefix(name, "./") || name == "." ||
   952			strings.HasPrefix(name, "../") || name == ".."
   953	}
   954	
   955	func findpkg(name string) (file string, ok bool) {
   956		if islocalname(name) {
   957			if nolocalimports {
   958				return "", false
   959			}
   960	
   961			if packageFile != nil {
   962				file, ok = packageFile[name]
   963				return file, ok
   964			}
   965	
   966			// try .a before .6.  important for building libraries:
   967			// if there is an array.6 in the array.a library,
   968			// want to find all of array.a, not just array.6.
   969			file = fmt.Sprintf("%s.a", name)
   970			if _, err := os.Stat(file); err == nil {
   971				return file, true
   972			}
   973			file = fmt.Sprintf("%s.o", name)
   974			if _, err := os.Stat(file); err == nil {
   975				return file, true
   976			}
   977			return "", false
   978		}
   979	
   980		// local imports should be canonicalized already.
   981		// don't want to see "encoding/../encoding/base64"
   982		// as different from "encoding/base64".
   983		if q := path.Clean(name); q != name {
   984			yyerror("non-canonical import path %q (should be %q)", name, q)
   985			return "", false
   986		}
   987	
   988		if packageFile != nil {
   989			file, ok = packageFile[name]
   990			return file, ok
   991		}
   992	
   993		for _, dir := range idirs {
   994			file = fmt.Sprintf("%s/%s.a", dir, name)
   995			if _, err := os.Stat(file); err == nil {
   996				return file, true
   997			}
   998			file = fmt.Sprintf("%s/%s.o", dir, name)
   999			if _, err := os.Stat(file); err == nil {
  1000				return file, true
  1001			}
  1002		}
  1003	
  1004		if objabi.GOROOT != "" {
  1005			suffix := ""
  1006			suffixsep := ""
  1007			if flag_installsuffix != "" {
  1008				suffixsep = "_"
  1009				suffix = flag_installsuffix
  1010			} else if flag_race {
  1011				suffixsep = "_"
  1012				suffix = "race"
  1013			} else if flag_msan {
  1014				suffixsep = "_"
  1015				suffix = "msan"
  1016			}
  1017	
  1018			file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
  1019			if _, err := os.Stat(file); err == nil {
  1020				return file, true
  1021			}
  1022			file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
  1023			if _, err := os.Stat(file); err == nil {
  1024				return file, true
  1025			}
  1026		}
  1027	
  1028		return "", false
  1029	}
  1030	
  1031	// loadsys loads the definitions for the low-level runtime functions,
  1032	// so that the compiler can generate calls to them,
  1033	// but does not make them visible to user code.
  1034	func loadsys() {
  1035		types.Block = 1
  1036	
  1037		inimport = true
  1038		typecheckok = true
  1039		defercheckwidth()
  1040	
  1041		typs := runtimeTypes()
  1042		for _, d := range runtimeDecls {
  1043			sym := Runtimepkg.Lookup(d.name)
  1044			typ := typs[d.typ]
  1045			switch d.tag {
  1046			case funcTag:
  1047				importfunc(Runtimepkg, src.NoXPos, sym, typ)
  1048			case varTag:
  1049				importvar(Runtimepkg, src.NoXPos, sym, typ)
  1050			default:
  1051				Fatalf("unhandled declaration tag %v", d.tag)
  1052			}
  1053		}
  1054	
  1055		typecheckok = false
  1056		resumecheckwidth()
  1057		inimport = false
  1058	}
  1059	
  1060	// myheight tracks the local package's height based on packages
  1061	// imported so far.
  1062	var myheight int
  1063	
  1064	func importfile(f *Val) *types.Pkg {
  1065		path_, ok := f.U.(string)
  1066		if !ok {
  1067			yyerror("import path must be a string")
  1068			return nil
  1069		}
  1070	
  1071		if len(path_) == 0 {
  1072			yyerror("import path is empty")
  1073			return nil
  1074		}
  1075	
  1076		if isbadimport(path_, false) {
  1077			return nil
  1078		}
  1079	
  1080		// The package name main is no longer reserved,
  1081		// but we reserve the import path "main" to identify
  1082		// the main package, just as we reserve the import
  1083		// path "math" to identify the standard math package.
  1084		if path_ == "main" {
  1085			yyerror("cannot import \"main\"")
  1086			errorexit()
  1087		}
  1088	
  1089		if myimportpath != "" && path_ == myimportpath {
  1090			yyerror("import %q while compiling that package (import cycle)", path_)
  1091			errorexit()
  1092		}
  1093	
  1094		if mapped, ok := importMap[path_]; ok {
  1095			path_ = mapped
  1096		}
  1097	
  1098		if path_ == "unsafe" {
  1099			imported_unsafe = true
  1100			return unsafepkg
  1101		}
  1102	
  1103		if islocalname(path_) {
  1104			if path_[0] == '/' {
  1105				yyerror("import path cannot be absolute path")
  1106				return nil
  1107			}
  1108	
  1109			prefix := Ctxt.Pathname
  1110			if localimport != "" {
  1111				prefix = localimport
  1112			}
  1113			path_ = path.Join(prefix, path_)
  1114	
  1115			if isbadimport(path_, true) {
  1116				return nil
  1117			}
  1118		}
  1119	
  1120		file, found := findpkg(path_)
  1121		if !found {
  1122			yyerror("can't find import: %q", path_)
  1123			errorexit()
  1124		}
  1125	
  1126		importpkg := types.NewPkg(path_, "")
  1127		if importpkg.Imported {
  1128			return importpkg
  1129		}
  1130	
  1131		importpkg.Imported = true
  1132	
  1133		imp, err := bio.Open(file)
  1134		if err != nil {
  1135			yyerror("can't open import: %q: %v", path_, err)
  1136			errorexit()
  1137		}
  1138		defer imp.Close()
  1139	
  1140		// check object header
  1141		p, err := imp.ReadString('\n')
  1142		if err != nil {
  1143			yyerror("import %s: reading input: %v", file, err)
  1144			errorexit()
  1145		}
  1146	
  1147		if p == "!<arch>\n" { // package archive
  1148			// package export block should be first
  1149			sz := arsize(imp.Reader, "__.PKGDEF")
  1150			if sz <= 0 {
  1151				yyerror("import %s: not a package file", file)
  1152				errorexit()
  1153			}
  1154			p, err = imp.ReadString('\n')
  1155			if err != nil {
  1156				yyerror("import %s: reading input: %v", file, err)
  1157				errorexit()
  1158			}
  1159		}
  1160	
  1161		if !strings.HasPrefix(p, "go object ") {
  1162			yyerror("import %s: not a go object file: %s", file, p)
  1163			errorexit()
  1164		}
  1165		q := fmt.Sprintf("%s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
  1166		if p[10:] != q {
  1167			yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
  1168			errorexit()
  1169		}
  1170	
  1171		// process header lines
  1172		for {
  1173			p, err = imp.ReadString('\n')
  1174			if err != nil {
  1175				yyerror("import %s: reading input: %v", file, err)
  1176				errorexit()
  1177			}
  1178			if p == "\n" {
  1179				break // header ends with blank line
  1180			}
  1181		}
  1182	
  1183		// assume files move (get installed) so don't record the full path
  1184		if packageFile != nil {
  1185			// If using a packageFile map, assume path_ can be recorded directly.
  1186			Ctxt.AddImport(path_)
  1187		} else {
  1188			// For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
  1189			Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):])
  1190		}
  1191	
  1192		// In the importfile, if we find:
  1193		// $$\n  (textual format): not supported anymore
  1194		// $$B\n (binary format) : import directly, then feed the lexer a dummy statement
  1195	
  1196		// look for $$
  1197		var c byte
  1198		for {
  1199			c, err = imp.ReadByte()
  1200			if err != nil {
  1201				break
  1202			}
  1203			if c == '$' {
  1204				c, err = imp.ReadByte()
  1205				if c == '$' || err != nil {
  1206					break
  1207				}
  1208			}
  1209		}
  1210	
  1211		// get character after $$
  1212		if err == nil {
  1213			c, _ = imp.ReadByte()
  1214		}
  1215	
  1216		switch c {
  1217		case '\n':
  1218			yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
  1219			return nil
  1220	
  1221		case 'B':
  1222			if Debug_export != 0 {
  1223				fmt.Printf("importing %s (%s)\n", path_, file)
  1224			}
  1225			imp.ReadByte() // skip \n after $$B
  1226	
  1227			c, err = imp.ReadByte()
  1228			if err != nil {
  1229				yyerror("import %s: reading input: %v", file, err)
  1230				errorexit()
  1231			}
  1232	
  1233			// Indexed format is distinguished by an 'i' byte,
  1234			// whereas previous export formats started with 'c', 'd', or 'v'.
  1235			if c != 'i' {
  1236				yyerror("import %s: unexpected package format byte: %v", file, c)
  1237				errorexit()
  1238			}
  1239			iimport(importpkg, imp)
  1240	
  1241		default:
  1242			yyerror("no import in %q", path_)
  1243			errorexit()
  1244		}
  1245	
  1246		if importpkg.Height >= myheight {
  1247			myheight = importpkg.Height + 1
  1248		}
  1249	
  1250		return importpkg
  1251	}
  1252	
  1253	func pkgnotused(lineno src.XPos, path string, name string) {
  1254		// If the package was imported with a name other than the final
  1255		// import path element, show it explicitly in the error message.
  1256		// Note that this handles both renamed imports and imports of
  1257		// packages containing unconventional package declarations.
  1258		// Note that this uses / always, even on Windows, because Go import
  1259		// paths always use forward slashes.
  1260		elem := path
  1261		if i := strings.LastIndex(elem, "/"); i >= 0 {
  1262			elem = elem[i+1:]
  1263		}
  1264		if name == "" || elem == name {
  1265			yyerrorl(lineno, "imported and not used: %q", path)
  1266		} else {
  1267			yyerrorl(lineno, "imported and not used: %q as %s", path, name)
  1268		}
  1269	}
  1270	
  1271	func mkpackage(pkgname string) {
  1272		if localpkg.Name == "" {
  1273			if pkgname == "_" {
  1274				yyerror("invalid package name _")
  1275			}
  1276			localpkg.Name = pkgname
  1277		} else {
  1278			if pkgname != localpkg.Name {
  1279				yyerror("package %s; expected %s", pkgname, localpkg.Name)
  1280			}
  1281		}
  1282	}
  1283	
  1284	func clearImports() {
  1285		type importedPkg struct {
  1286			pos  src.XPos
  1287			path string
  1288			name string
  1289		}
  1290		var unused []importedPkg
  1291	
  1292		for _, s := range localpkg.Syms {
  1293			n := asNode(s.Def)
  1294			if n == nil {
  1295				continue
  1296			}
  1297			if n.Op == OPACK {
  1298				// throw away top-level package name left over
  1299				// from previous file.
  1300				// leave s->block set to cause redeclaration
  1301				// errors if a conflicting top-level name is
  1302				// introduced by a different file.
  1303				if !n.Name.Used() && nsyntaxerrors == 0 {
  1304					unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name})
  1305				}
  1306				s.Def = nil
  1307				continue
  1308			}
  1309			if IsAlias(s) {
  1310				// throw away top-level name left over
  1311				// from previous import . "x"
  1312				if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 {
  1313					unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""})
  1314					n.Name.Pack.Name.SetUsed(true)
  1315				}
  1316				s.Def = nil
  1317				continue
  1318			}
  1319		}
  1320	
  1321		sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
  1322		for _, pkg := range unused {
  1323			pkgnotused(pkg.pos, pkg.path, pkg.name)
  1324		}
  1325	}
  1326	
  1327	func IsAlias(sym *types.Sym) bool {
  1328		return sym.Def != nil && asNode(sym.Def).Sym != sym
  1329	}
  1330	
  1331	// By default, assume any debug flags are incompatible with concurrent compilation.
  1332	// A few are safe and potentially in common use for normal compiles, though; mark them as such here.
  1333	var concurrentFlagOK = [256]bool{
  1334		'B': true, // disabled bounds checking
  1335		'C': true, // disable printing of columns in error messages
  1336		'e': true, // no limit on errors; errors all come from non-concurrent code
  1337		'I': true, // add `directory` to import search path
  1338		'N': true, // disable optimizations
  1339		'l': true, // disable inlining
  1340		'w': true, // all printing happens before compilation
  1341		'W': true, // all printing happens before compilation
  1342		'S': true, // printing disassembly happens at the end (but see concurrentBackendAllowed below)
  1343	}
  1344	
  1345	func concurrentBackendAllowed() bool {
  1346		for i, x := range Debug {
  1347			if x != 0 && !concurrentFlagOK[i] {
  1348				return false
  1349			}
  1350		}
  1351		// Debug['S'] by itself is ok, because all printing occurs
  1352		// while writing the object file, and that is non-concurrent.
  1353		// Adding Debug_vlog, however, causes Debug['S'] to also print
  1354		// while flushing the plist, which happens concurrently.
  1355		if Debug_vlog || debugstr != "" || debuglive > 0 {
  1356			return false
  1357		}
  1358		// TODO: Test and delete this condition.
  1359		if objabi.Fieldtrack_enabled != 0 {
  1360			return false
  1361		}
  1362		// TODO: fix races and enable the following flags
  1363		if Ctxt.Flag_shared || Ctxt.Flag_dynlink || flag_race {
  1364			return false
  1365		}
  1366		return true
  1367	}
  1368	
  1369	// recordFlags records the specified command-line flags to be placed
  1370	// in the DWARF info.
  1371	func recordFlags(flags ...string) {
  1372		if myimportpath == "" {
  1373			// We can't record the flags if we don't know what the
  1374			// package name is.
  1375			return
  1376		}
  1377	
  1378		type BoolFlag interface {
  1379			IsBoolFlag() bool
  1380		}
  1381		type CountFlag interface {
  1382			IsCountFlag() bool
  1383		}
  1384		var cmd bytes.Buffer
  1385		for _, name := range flags {
  1386			f := flag.Lookup(name)
  1387			if f == nil {
  1388				continue
  1389			}
  1390			getter := f.Value.(flag.Getter)
  1391			if getter.String() == f.DefValue {
  1392				// Flag has default value, so omit it.
  1393				continue
  1394			}
  1395			if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
  1396				val, ok := getter.Get().(bool)
  1397				if ok && val {
  1398					fmt.Fprintf(&cmd, " -%s", f.Name)
  1399					continue
  1400				}
  1401			}
  1402			if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
  1403				val, ok := getter.Get().(int)
  1404				if ok && val == 1 {
  1405					fmt.Fprintf(&cmd, " -%s", f.Name)
  1406					continue
  1407				}
  1408			}
  1409			fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
  1410		}
  1411	
  1412		if cmd.Len() == 0 {
  1413			return
  1414		}
  1415		s := Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + myimportpath)
  1416		s.Type = objabi.SDWARFINFO
  1417		// Sometimes (for example when building tests) we can link
  1418		// together two package main archives. So allow dups.
  1419		s.Set(obj.AttrDuplicateOK, true)
  1420		Ctxt.Data = append(Ctxt.Data, s)
  1421		s.P = cmd.Bytes()[1:]
  1422	}
  1423	
  1424	// recordPackageName records the name of the package being
  1425	// compiled, so that the linker can save it in the compile unit's DIE.
  1426	func recordPackageName() {
  1427		s := Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + myimportpath)
  1428		s.Type = objabi.SDWARFINFO
  1429		// Sometimes (for example when building tests) we can link
  1430		// together two package main archives. So allow dups.
  1431		s.Set(obj.AttrDuplicateOK, true)
  1432		Ctxt.Data = append(Ctxt.Data, s)
  1433		s.P = []byte(localpkg.Name)
  1434	}
  1435	
  1436	// flag_lang is the language version we are compiling for, set by the -lang flag.
  1437	var flag_lang string
  1438	
  1439	// currentLang returns the current language version.
  1440	func currentLang() string {
  1441		return fmt.Sprintf("go1.%d", goversion.Version)
  1442	}
  1443	
  1444	// goVersionRE is a regular expression that matches the valid
  1445	// arguments to the -lang flag.
  1446	var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
  1447	
  1448	// A lang is a language version broken into major and minor numbers.
  1449	type lang struct {
  1450		major, minor int
  1451	}
  1452	
  1453	// langWant is the desired language version set by the -lang flag.
  1454	// If the -lang flag is not set, this is the zero value, meaning that
  1455	// any language version is supported.
  1456	var langWant lang
  1457	
  1458	// langSupported reports whether language version major.minor is supported.
  1459	func langSupported(major, minor int) bool {
  1460		if langWant.major == 0 && langWant.minor == 0 {
  1461			return true
  1462		}
  1463		return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
  1464	}
  1465	
  1466	// checkLang verifies that the -lang flag holds a valid value, and
  1467	// exits if not. It initializes data used by langSupported.
  1468	func checkLang() {
  1469		if flag_lang == "" {
  1470			return
  1471		}
  1472	
  1473		var err error
  1474		langWant, err = parseLang(flag_lang)
  1475		if err != nil {
  1476			log.Fatalf("invalid value %q for -lang: %v", flag_lang, err)
  1477		}
  1478	
  1479		if def := currentLang(); flag_lang != def {
  1480			defVers, err := parseLang(def)
  1481			if err != nil {
  1482				log.Fatalf("internal error parsing default lang %q: %v", def, err)
  1483			}
  1484			if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) {
  1485				log.Fatalf("invalid value %q for -lang: max known version is %q", flag_lang, def)
  1486			}
  1487		}
  1488	}
  1489	
  1490	// parseLang parses a -lang option into a langVer.
  1491	func parseLang(s string) (lang, error) {
  1492		matches := goVersionRE.FindStringSubmatch(s)
  1493		if matches == nil {
  1494			return lang{}, fmt.Errorf(`should be something like "go1.12"`)
  1495		}
  1496		major, err := strconv.Atoi(matches[1])
  1497		if err != nil {
  1498			return lang{}, err
  1499		}
  1500		minor, err := strconv.Atoi(matches[2])
  1501		if err != nil {
  1502			return lang{}, err
  1503		}
  1504		return lang{major: major, minor: minor}, nil
  1505	}
  1506	

View as plain text