github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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  //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/obj"
    15  	"cmd/internal/objabi"
    16  	"cmd/internal/src"
    17  	"cmd/internal/sys"
    18  	"flag"
    19  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"log"
    23  	"os"
    24  	"path"
    25  	"runtime"
    26  	"strconv"
    27  	"strings"
    28  )
    29  
    30  var imported_unsafe bool
    31  
    32  var (
    33  	buildid string
    34  )
    35  
    36  var (
    37  	Debug_append       int
    38  	Debug_asm          bool
    39  	Debug_closure      int
    40  	Debug_compilelater int
    41  	debug_dclstack     int
    42  	Debug_panic        int
    43  	Debug_slice        int
    44  	Debug_vlog         bool
    45  	Debug_wb           int
    46  	Debug_pctab        string
    47  	Debug_locationlist int
    48  )
    49  
    50  // Debug arguments.
    51  // These can be specified with the -d flag, as in "-d nil"
    52  // to set the debug_checknil variable.
    53  // Multiple options can be comma-separated.
    54  // Each option accepts an optional argument, as in "gcprog=2"
    55  var debugtab = []struct {
    56  	name string
    57  	help string
    58  	val  interface{} // must be *int or *string
    59  }{
    60  	{"append", "print information about append compilation", &Debug_append},
    61  	{"closure", "print information about closure compilation", &Debug_closure},
    62  	{"compilelater", "compile functions as late as possible", &Debug_compilelater},
    63  	{"disablenil", "disable nil checks", &disable_checknil},
    64  	{"dclstack", "run internal dclstack check", &debug_dclstack},
    65  	{"gcprog", "print dump of GC programs", &Debug_gcprog},
    66  	{"nil", "print information about nil checks", &Debug_checknil},
    67  	{"panic", "do not hide any compiler panic", &Debug_panic},
    68  	{"slice", "print information about slice compilation", &Debug_slice},
    69  	{"typeassert", "print information about type assertion inlining", &Debug_typeassert},
    70  	{"wb", "print information about write barriers", &Debug_wb},
    71  	{"export", "print export data", &Debug_export},
    72  	{"pctab", "print named pc-value table", &Debug_pctab},
    73  	{"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
    74  }
    75  
    76  const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
    77  
    78  <key> is one of:
    79  
    80  `
    81  
    82  const debugHelpFooter = `
    83  <value> is key-specific.
    84  
    85  Key "pctab" supports values:
    86  	"pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
    87  `
    88  
    89  func usage() {
    90  	fmt.Printf("usage: compile [options] file.go...\n")
    91  	objabi.Flagprint(1)
    92  	Exit(2)
    93  }
    94  
    95  func hidePanic() {
    96  	if Debug_panic == 0 && nsavederrors+nerrors > 0 {
    97  		// If we've already complained about things
    98  		// in the program, don't bother complaining
    99  		// about a panic too; let the user clean up
   100  		// the code and try again.
   101  		if err := recover(); err != nil {
   102  			errorexit()
   103  		}
   104  	}
   105  }
   106  
   107  func doversion() {
   108  	p := objabi.Expstring()
   109  	if p == objabi.DefaultExpstring() {
   110  		p = ""
   111  	}
   112  	sep := ""
   113  	if p != "" {
   114  		sep = " "
   115  	}
   116  	fmt.Printf("compile version %s%s%s\n", objabi.Version, sep, p)
   117  	os.Exit(0)
   118  }
   119  
   120  // supportsDynlink reports whether or not the code generator for the given
   121  // architecture supports the -shared and -dynlink flags.
   122  func supportsDynlink(arch *sys.Arch) bool {
   123  	return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
   124  }
   125  
   126  // timing data for compiler phases
   127  var timings Timings
   128  var benchfile string
   129  
   130  // Main parses flags and Go source files specified in the command-line
   131  // arguments, type-checks the parsed Go package, compiles functions to machine
   132  // code, and finally writes the compiled package definition to disk.
   133  func Main(archInit func(*Arch)) {
   134  	timings.Start("fe", "init")
   135  
   136  	defer hidePanic()
   137  
   138  	archInit(&thearch)
   139  
   140  	Ctxt = obj.Linknew(thearch.LinkArch)
   141  	Ctxt.DiagFunc = yyerror
   142  	Ctxt.Bso = bufio.NewWriter(os.Stdout)
   143  
   144  	localpkg = types.NewPkg("", "")
   145  	localpkg.Prefix = "\"\""
   146  
   147  	// pseudo-package, for scoping
   148  	builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
   149  	builtinpkg.Prefix = "go.builtin"            // not go%2ebuiltin
   150  
   151  	// pseudo-package, accessed by import "unsafe"
   152  	unsafepkg = types.NewPkg("unsafe", "unsafe")
   153  
   154  	// Pseudo-package that contains the compiler's builtin
   155  	// declarations for package runtime. These are declared in a
   156  	// separate package to avoid conflicts with package runtime's
   157  	// actual declarations, which may differ intentionally but
   158  	// insignificantly.
   159  	Runtimepkg = types.NewPkg("go.runtime", "runtime")
   160  	Runtimepkg.Prefix = "runtime"
   161  
   162  	// pseudo-packages used in symbol tables
   163  	itabpkg = types.NewPkg("go.itab", "go.itab")
   164  	itabpkg.Prefix = "go.itab" // not go%2eitab
   165  
   166  	itablinkpkg = types.NewPkg("go.itablink", "go.itablink")
   167  	itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
   168  
   169  	trackpkg = types.NewPkg("go.track", "go.track")
   170  	trackpkg.Prefix = "go.track" // not go%2etrack
   171  
   172  	// pseudo-package used for map zero values
   173  	mappkg = types.NewPkg("go.map", "go.map")
   174  	mappkg.Prefix = "go.map"
   175  
   176  	Nacl = objabi.GOOS == "nacl"
   177  
   178  	flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
   179  	flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
   180  	objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
   181  	objabi.Flagcount("B", "disable bounds checking", &Debug['B'])
   182  	objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C']) // TODO(gri) remove eventually
   183  	flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
   184  	objabi.Flagcount("E", "debug symbol export", &Debug['E'])
   185  	objabi.Flagfn1("I", "add `directory` to import search path", addidir)
   186  	objabi.Flagcount("K", "debug missing line numbers", &Debug['K'])
   187  	objabi.Flagcount("N", "disable optimizations", &Debug['N'])
   188  	flag.BoolVar(&Debug_asm, "S", false, "print assembly listing")
   189  	objabi.AddVersionFlag() // -V
   190  	objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
   191  	flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
   192  	flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
   193  	flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
   194  	flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
   195  	flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
   196  	flag.BoolVar(&flagDWARF, "dwarf", true, "generate DWARF symbols")
   197  	flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", false, "add location lists to DWARF in optimized mode")
   198  	objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
   199  	objabi.Flagcount("f", "debug stack frames", &Debug['f'])
   200  	objabi.Flagcount("h", "halt on error", &Debug['h'])
   201  	objabi.Flagcount("i", "debug line number stack", &Debug['i'])
   202  	objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
   203  	objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
   204  	flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
   205  	objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
   206  	objabi.Flagcount("l", "disable inlining", &Debug['l'])
   207  	flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
   208  	objabi.Flagcount("live", "debug liveness analysis", &debuglive)
   209  	objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
   210  	flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
   211  	flag.BoolVar(&dolinkobj, "dolinkobj", true, "generate linker-specific objects; if false, some invalid code may compile")
   212  	flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
   213  	flag.StringVar(&outfile, "o", "", "write output to `file`")
   214  	flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
   215  	flag.BoolVar(&writearchive, "pack", false, "write package file instead of object file")
   216  	objabi.Flagcount("r", "debug generated wrappers", &Debug['r'])
   217  	flag.BoolVar(&flag_race, "race", false, "enable race detector")
   218  	objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
   219  	flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
   220  	flag.BoolVar(&safemode, "u", false, "reject unsafe code")
   221  	flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
   222  	objabi.Flagcount("w", "debug type checking", &Debug['w'])
   223  	flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
   224  	var flag_shared bool
   225  	var flag_dynlink bool
   226  	if supportsDynlink(thearch.LinkArch.Arch) {
   227  		flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
   228  		flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
   229  	}
   230  	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
   231  	flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
   232  	flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
   233  	var goversion string
   234  	flag.StringVar(&goversion, "goversion", "", "required version of the runtime")
   235  	flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
   236  	flag.StringVar(&blockprofile, "blockprofile", "", "write block profile to `file`")
   237  	flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`")
   238  	flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
   239  	objabi.Flagparse(usage)
   240  
   241  	Ctxt.Flag_shared = flag_dynlink || flag_shared
   242  	Ctxt.Flag_dynlink = flag_dynlink
   243  	Ctxt.Flag_optimize = Debug['N'] == 0
   244  
   245  	Ctxt.Debugasm = Debug_asm
   246  	Ctxt.Debugvlog = Debug_vlog
   247  	if flagDWARF {
   248  		Ctxt.DebugInfo = debuginfo
   249  	}
   250  
   251  	if flag.NArg() < 1 && debugstr != "help" && debugstr != "ssa/help" {
   252  		usage()
   253  	}
   254  
   255  	if goversion != "" && goversion != runtime.Version() {
   256  		fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), goversion)
   257  		Exit(2)
   258  	}
   259  
   260  	thearch.LinkArch.Init(Ctxt)
   261  
   262  	if outfile == "" {
   263  		p := flag.Arg(0)
   264  		if i := strings.LastIndex(p, "/"); i >= 0 {
   265  			p = p[i+1:]
   266  		}
   267  		if runtime.GOOS == "windows" {
   268  			if i := strings.LastIndex(p, `\`); i >= 0 {
   269  				p = p[i+1:]
   270  			}
   271  		}
   272  		if i := strings.LastIndex(p, "."); i >= 0 {
   273  			p = p[:i]
   274  		}
   275  		suffix := ".o"
   276  		if writearchive {
   277  			suffix = ".a"
   278  		}
   279  		outfile = p + suffix
   280  	}
   281  
   282  	startProfile()
   283  
   284  	if flag_race {
   285  		racepkg = types.NewPkg("runtime/race", "race")
   286  	}
   287  	if flag_msan {
   288  		msanpkg = types.NewPkg("runtime/msan", "msan")
   289  	}
   290  	if flag_race && flag_msan {
   291  		log.Fatal("cannot use both -race and -msan")
   292  	} else if flag_race || flag_msan {
   293  		instrumenting = true
   294  	}
   295  	if compiling_runtime && Debug['N'] != 0 {
   296  		log.Fatal("cannot disable optimizations while compiling runtime")
   297  	}
   298  	if nBackendWorkers < 1 {
   299  		log.Fatalf("-c must be at least 1, got %d", nBackendWorkers)
   300  	}
   301  	if nBackendWorkers > 1 && !concurrentBackendAllowed() {
   302  		log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
   303  	}
   304  	if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
   305  		log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
   306  	}
   307  
   308  	// parse -d argument
   309  	if debugstr != "" {
   310  	Split:
   311  		for _, name := range strings.Split(debugstr, ",") {
   312  			if name == "" {
   313  				continue
   314  			}
   315  			// display help about the -d option itself and quit
   316  			if name == "help" {
   317  				fmt.Printf(debugHelpHeader)
   318  				maxLen := len("ssa/help")
   319  				for _, t := range debugtab {
   320  					if len(t.name) > maxLen {
   321  						maxLen = len(t.name)
   322  					}
   323  				}
   324  				for _, t := range debugtab {
   325  					fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
   326  				}
   327  				// ssa options have their own help
   328  				fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
   329  				fmt.Printf(debugHelpFooter)
   330  				os.Exit(0)
   331  			}
   332  			val, valstring, haveInt := 1, "", true
   333  			if i := strings.IndexAny(name, "=:"); i >= 0 {
   334  				var err error
   335  				name, valstring = name[:i], name[i+1:]
   336  				val, err = strconv.Atoi(valstring)
   337  				if err != nil {
   338  					val, haveInt = 1, false
   339  				}
   340  			}
   341  			for _, t := range debugtab {
   342  				if t.name != name {
   343  					continue
   344  				}
   345  				switch vp := t.val.(type) {
   346  				case nil:
   347  					// Ignore
   348  				case *string:
   349  					*vp = valstring
   350  				case *int:
   351  					if !haveInt {
   352  						log.Fatalf("invalid debug value %v", name)
   353  					}
   354  					*vp = val
   355  				default:
   356  					panic("bad debugtab type")
   357  				}
   358  				continue Split
   359  			}
   360  			// special case for ssa for now
   361  			if strings.HasPrefix(name, "ssa/") {
   362  				// expect form ssa/phase/flag
   363  				// e.g. -d=ssa/generic_cse/time
   364  				// _ in phase name also matches space
   365  				phase := name[4:]
   366  				flag := "debug" // default flag is debug
   367  				if i := strings.Index(phase, "/"); i >= 0 {
   368  					flag = phase[i+1:]
   369  					phase = phase[:i]
   370  				}
   371  				err := ssa.PhaseOption(phase, flag, val, valstring)
   372  				if err != "" {
   373  					log.Fatalf(err)
   374  				}
   375  				continue Split
   376  			}
   377  			log.Fatalf("unknown debug key -d %s\n", name)
   378  		}
   379  	}
   380  
   381  	// set via a -d flag
   382  	Ctxt.Debugpcln = Debug_pctab
   383  
   384  	// enable inlining.  for now:
   385  	//	default: inlining on.  (debug['l'] == 1)
   386  	//	-l: inlining off  (debug['l'] == 0)
   387  	//	-ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
   388  	if Debug['l'] <= 1 {
   389  		Debug['l'] = 1 - Debug['l']
   390  	}
   391  
   392  	trackScopes = flagDWARF && ((Debug['l'] == 0 && Debug['N'] != 0) || Ctxt.Flag_locationlists)
   393  
   394  	Widthptr = thearch.LinkArch.PtrSize
   395  	Widthreg = thearch.LinkArch.RegSize
   396  
   397  	// initialize types package
   398  	// (we need to do this to break dependencies that otherwise
   399  	// would lead to import cycles)
   400  	types.Widthptr = Widthptr
   401  	types.Dowidth = dowidth
   402  	types.Fatalf = Fatalf
   403  	types.Sconv = func(s *types.Sym, flag, mode int) string {
   404  		return sconv(s, FmtFlag(flag), fmtMode(mode))
   405  	}
   406  	types.Tconv = func(t *types.Type, flag, mode, depth int) string {
   407  		return tconv(t, FmtFlag(flag), fmtMode(mode), depth)
   408  	}
   409  	types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
   410  		symFormat(sym, s, verb, fmtMode(mode))
   411  	}
   412  	types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
   413  		typeFormat(t, s, verb, fmtMode(mode))
   414  	}
   415  	types.TypeLinkSym = func(t *types.Type) *obj.LSym {
   416  		return typenamesym(t).Linksym()
   417  	}
   418  	types.FmtLeft = int(FmtLeft)
   419  	types.FmtUnsigned = int(FmtUnsigned)
   420  	types.FErr = FErr
   421  	types.Ctxt = Ctxt
   422  
   423  	initUniverse()
   424  
   425  	dclcontext = PEXTERN
   426  	nerrors = 0
   427  
   428  	autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
   429  
   430  	timings.Start("fe", "loadsys")
   431  	loadsys()
   432  
   433  	timings.Start("fe", "parse")
   434  	lines := parseFiles(flag.Args())
   435  	timings.Stop()
   436  	timings.AddEvent(int64(lines), "lines")
   437  
   438  	finishUniverse()
   439  
   440  	typecheckok = true
   441  	if Debug['f'] != 0 {
   442  		frame(1)
   443  	}
   444  
   445  	// Process top-level declarations in phases.
   446  
   447  	// Phase 1: const, type, and names and types of funcs.
   448  	//   This will gather all the information about types
   449  	//   and methods but doesn't depend on any of it.
   450  	//   We also defer type alias declarations until phase 2
   451  	//   to avoid cycles like #18640.
   452  	defercheckwidth()
   453  
   454  	// Don't use range--typecheck can add closures to xtop.
   455  	timings.Start("fe", "typecheck", "top1")
   456  	for i := 0; i < len(xtop); i++ {
   457  		n := xtop[i]
   458  		if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
   459  			xtop[i] = typecheck(n, Etop)
   460  		}
   461  	}
   462  
   463  	// Phase 2: Variable assignments.
   464  	//   To check interface assignments, depends on phase 1.
   465  
   466  	// Don't use range--typecheck can add closures to xtop.
   467  	timings.Start("fe", "typecheck", "top2")
   468  	for i := 0; i < len(xtop); i++ {
   469  		n := xtop[i]
   470  		if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
   471  			xtop[i] = typecheck(n, Etop)
   472  		}
   473  	}
   474  	resumecheckwidth()
   475  
   476  	// Phase 3: Type check function bodies.
   477  	// Don't use range--typecheck can add closures to xtop.
   478  	timings.Start("fe", "typecheck", "func")
   479  	var fcount int64
   480  	for i := 0; i < len(xtop); i++ {
   481  		n := xtop[i]
   482  		if op := n.Op; op == ODCLFUNC || op == OCLOSURE {
   483  			Curfn = n
   484  			decldepth = 1
   485  			saveerrors()
   486  			typecheckslice(Curfn.Nbody.Slice(), Etop)
   487  			checkreturn(Curfn)
   488  			if nerrors != 0 {
   489  				Curfn.Nbody.Set(nil) // type errors; do not compile
   490  			}
   491  			// Now that we've checked whether n terminates,
   492  			// we can eliminate some obviously dead code.
   493  			deadcode(Curfn)
   494  			fcount++
   495  		}
   496  	}
   497  	timings.AddEvent(fcount, "funcs")
   498  
   499  	// Phase 4: Decide how to capture closed variables.
   500  	// This needs to run before escape analysis,
   501  	// because variables captured by value do not escape.
   502  	timings.Start("fe", "capturevars")
   503  	for _, n := range xtop {
   504  		if n.Op == ODCLFUNC && n.Func.Closure != nil {
   505  			Curfn = n
   506  			capturevars(n)
   507  		}
   508  	}
   509  	capturevarscomplete = true
   510  
   511  	Curfn = nil
   512  
   513  	if nsavederrors+nerrors != 0 {
   514  		errorexit()
   515  	}
   516  
   517  	// Phase 5: Inlining
   518  	timings.Start("fe", "inlining")
   519  	if Debug['l'] > 1 {
   520  		// Typecheck imported function bodies if debug['l'] > 1,
   521  		// otherwise lazily when used or re-exported.
   522  		for _, n := range importlist {
   523  			if n.Func.Inl.Len() != 0 {
   524  				saveerrors()
   525  				typecheckinl(n)
   526  			}
   527  		}
   528  
   529  		if nsavederrors+nerrors != 0 {
   530  			errorexit()
   531  		}
   532  	}
   533  
   534  	if Debug['l'] != 0 {
   535  		// Find functions that can be inlined and clone them before walk expands them.
   536  		visitBottomUp(xtop, func(list []*Node, recursive bool) {
   537  			for _, n := range list {
   538  				if !recursive {
   539  					caninl(n)
   540  				} else {
   541  					if Debug['m'] > 1 {
   542  						fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
   543  					}
   544  				}
   545  				inlcalls(n)
   546  			}
   547  		})
   548  	}
   549  
   550  	// Phase 6: Escape analysis.
   551  	// Required for moving heap allocations onto stack,
   552  	// which in turn is required by the closure implementation,
   553  	// which stores the addresses of stack variables into the closure.
   554  	// If the closure does not escape, it needs to be on the stack
   555  	// or else the stack copier will not update it.
   556  	// Large values are also moved off stack in escape analysis;
   557  	// because large values may contain pointers, it must happen early.
   558  	timings.Start("fe", "escapes")
   559  	escapes(xtop)
   560  
   561  	if dolinkobj {
   562  		// Phase 7: Transform closure bodies to properly reference captured variables.
   563  		// This needs to happen before walk, because closures must be transformed
   564  		// before walk reaches a call of a closure.
   565  		timings.Start("fe", "xclosures")
   566  		for _, n := range xtop {
   567  			if n.Op == ODCLFUNC && n.Func.Closure != nil {
   568  				Curfn = n
   569  				transformclosure(n)
   570  			}
   571  		}
   572  
   573  		// Prepare for SSA compilation.
   574  		// This must be before peekitabs, because peekitabs
   575  		// can trigger function compilation.
   576  		initssaconfig()
   577  
   578  		// Just before compilation, compile itabs found on
   579  		// the right side of OCONVIFACE so that methods
   580  		// can be de-virtualized during compilation.
   581  		Curfn = nil
   582  		peekitabs()
   583  
   584  		// Phase 8: Compile top level functions.
   585  		// Don't use range--walk can add functions to xtop.
   586  		timings.Start("be", "compilefuncs")
   587  		fcount = 0
   588  		for i := 0; i < len(xtop); i++ {
   589  			n := xtop[i]
   590  			if n.Op == ODCLFUNC {
   591  				funccompile(n)
   592  				fcount++
   593  			}
   594  		}
   595  		timings.AddEvent(fcount, "funcs")
   596  
   597  		if nsavederrors+nerrors == 0 {
   598  			fninit(xtop)
   599  		}
   600  
   601  		compileFunctions()
   602  
   603  		// We autogenerate and compile some small functions
   604  		// such as method wrappers and equality/hash routines
   605  		// while exporting code.
   606  		// Disable concurrent compilation from here on,
   607  		// at least until this convoluted structure has been unwound.
   608  		nBackendWorkers = 1
   609  
   610  		if compiling_runtime {
   611  			checknowritebarrierrec()
   612  		}
   613  
   614  		// Check whether any of the functions we have compiled have gigantic stack frames.
   615  		obj.SortSlice(largeStackFrames, func(i, j int) bool {
   616  			return largeStackFrames[i].Before(largeStackFrames[j])
   617  		})
   618  		for _, largePos := range largeStackFrames {
   619  			yyerrorl(largePos, "stack frame too large (>2GB)")
   620  		}
   621  	}
   622  
   623  	// Phase 9: Check external declarations.
   624  	timings.Start("be", "externaldcls")
   625  	for i, n := range externdcl {
   626  		if n.Op == ONAME {
   627  			externdcl[i] = typecheck(externdcl[i], Erv)
   628  		}
   629  	}
   630  
   631  	if nerrors+nsavederrors != 0 {
   632  		errorexit()
   633  	}
   634  
   635  	// Write object data to disk.
   636  	timings.Start("be", "dumpobj")
   637  	dumpobj()
   638  	if asmhdr != "" {
   639  		dumpasmhdr()
   640  	}
   641  
   642  	if len(compilequeue) != 0 {
   643  		Fatalf("%d uncompiled functions", len(compilequeue))
   644  	}
   645  
   646  	if nerrors+nsavederrors != 0 {
   647  		errorexit()
   648  	}
   649  
   650  	flusherrors()
   651  	timings.Stop()
   652  
   653  	if benchfile != "" {
   654  		if err := writebench(benchfile); err != nil {
   655  			log.Fatalf("cannot write benchmark data: %v", err)
   656  		}
   657  	}
   658  }
   659  
   660  func writebench(filename string) error {
   661  	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
   662  	if err != nil {
   663  		return err
   664  	}
   665  
   666  	var buf bytes.Buffer
   667  	fmt.Fprintln(&buf, "commit:", objabi.Version)
   668  	fmt.Fprintln(&buf, "goos:", runtime.GOOS)
   669  	fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
   670  	timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":")
   671  
   672  	n, err := f.Write(buf.Bytes())
   673  	if err != nil {
   674  		return err
   675  	}
   676  	if n != buf.Len() {
   677  		panic("bad writer")
   678  	}
   679  
   680  	return f.Close()
   681  }
   682  
   683  var (
   684  	importMap   = map[string]string{}
   685  	packageFile map[string]string // nil means not in use
   686  )
   687  
   688  func addImportMap(s string) {
   689  	if strings.Count(s, "=") != 1 {
   690  		log.Fatal("-importmap argument must be of the form source=actual")
   691  	}
   692  	i := strings.Index(s, "=")
   693  	source, actual := s[:i], s[i+1:]
   694  	if source == "" || actual == "" {
   695  		log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
   696  	}
   697  	importMap[source] = actual
   698  }
   699  
   700  func readImportCfg(file string) {
   701  	packageFile = map[string]string{}
   702  	data, err := ioutil.ReadFile(file)
   703  	if err != nil {
   704  		log.Fatalf("-importcfg: %v", err)
   705  	}
   706  
   707  	for lineNum, line := range strings.Split(string(data), "\n") {
   708  		lineNum++ // 1-based
   709  		line = strings.TrimSpace(line)
   710  		if line == "" || strings.HasPrefix(line, "#") {
   711  			continue
   712  		}
   713  
   714  		var verb, args string
   715  		if i := strings.Index(line, " "); i < 0 {
   716  			verb = line
   717  		} else {
   718  			verb, args = line[:i], strings.TrimSpace(line[i+1:])
   719  		}
   720  		var before, after string
   721  		if i := strings.Index(args, "="); i >= 0 {
   722  			before, after = args[:i], args[i+1:]
   723  		}
   724  		switch verb {
   725  		default:
   726  			log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
   727  		case "importmap":
   728  			if before == "" || after == "" {
   729  				log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
   730  			}
   731  			importMap[before] = after
   732  		case "packagefile":
   733  			if before == "" || after == "" {
   734  				log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
   735  			}
   736  			packageFile[before] = after
   737  		}
   738  	}
   739  }
   740  
   741  func saveerrors() {
   742  	nsavederrors += nerrors
   743  	nerrors = 0
   744  }
   745  
   746  func arsize(b *bufio.Reader, name string) int {
   747  	var buf [ArhdrSize]byte
   748  	if _, err := io.ReadFull(b, buf[:]); err != nil {
   749  		return -1
   750  	}
   751  	aname := strings.Trim(string(buf[0:16]), " ")
   752  	if !strings.HasPrefix(aname, name) {
   753  		return -1
   754  	}
   755  	asize := strings.Trim(string(buf[48:58]), " ")
   756  	i, _ := strconv.Atoi(asize)
   757  	return i
   758  }
   759  
   760  var idirs []string
   761  
   762  func addidir(dir string) {
   763  	if dir != "" {
   764  		idirs = append(idirs, dir)
   765  	}
   766  }
   767  
   768  func isDriveLetter(b byte) bool {
   769  	return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
   770  }
   771  
   772  // is this path a local name? begins with ./ or ../ or /
   773  func islocalname(name string) bool {
   774  	return strings.HasPrefix(name, "/") ||
   775  		runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
   776  		strings.HasPrefix(name, "./") || name == "." ||
   777  		strings.HasPrefix(name, "../") || name == ".."
   778  }
   779  
   780  func findpkg(name string) (file string, ok bool) {
   781  	if islocalname(name) {
   782  		if safemode || nolocalimports {
   783  			return "", false
   784  		}
   785  
   786  		if packageFile != nil {
   787  			file, ok = packageFile[name]
   788  			return file, ok
   789  		}
   790  
   791  		// try .a before .6.  important for building libraries:
   792  		// if there is an array.6 in the array.a library,
   793  		// want to find all of array.a, not just array.6.
   794  		file = fmt.Sprintf("%s.a", name)
   795  		if _, err := os.Stat(file); err == nil {
   796  			return file, true
   797  		}
   798  		file = fmt.Sprintf("%s.o", name)
   799  		if _, err := os.Stat(file); err == nil {
   800  			return file, true
   801  		}
   802  		return "", false
   803  	}
   804  
   805  	// local imports should be canonicalized already.
   806  	// don't want to see "encoding/../encoding/base64"
   807  	// as different from "encoding/base64".
   808  	if q := path.Clean(name); q != name {
   809  		yyerror("non-canonical import path %q (should be %q)", name, q)
   810  		return "", false
   811  	}
   812  
   813  	if packageFile != nil {
   814  		file, ok = packageFile[name]
   815  		return file, ok
   816  	}
   817  
   818  	for _, dir := range idirs {
   819  		file = fmt.Sprintf("%s/%s.a", dir, name)
   820  		if _, err := os.Stat(file); err == nil {
   821  			return file, true
   822  		}
   823  		file = fmt.Sprintf("%s/%s.o", dir, name)
   824  		if _, err := os.Stat(file); err == nil {
   825  			return file, true
   826  		}
   827  	}
   828  
   829  	if objabi.GOROOT != "" {
   830  		suffix := ""
   831  		suffixsep := ""
   832  		if flag_installsuffix != "" {
   833  			suffixsep = "_"
   834  			suffix = flag_installsuffix
   835  		} else if flag_race {
   836  			suffixsep = "_"
   837  			suffix = "race"
   838  		} else if flag_msan {
   839  			suffixsep = "_"
   840  			suffix = "msan"
   841  		}
   842  
   843  		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
   844  		if _, err := os.Stat(file); err == nil {
   845  			return file, true
   846  		}
   847  		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
   848  		if _, err := os.Stat(file); err == nil {
   849  			return file, true
   850  		}
   851  	}
   852  
   853  	return "", false
   854  }
   855  
   856  // loadsys loads the definitions for the low-level runtime functions,
   857  // so that the compiler can generate calls to them,
   858  // but does not make them visible to user code.
   859  func loadsys() {
   860  	types.Block = 1
   861  
   862  	inimport = true
   863  	typecheckok = true
   864  	defercheckwidth()
   865  
   866  	typs := runtimeTypes()
   867  	for _, d := range runtimeDecls {
   868  		sym := Runtimepkg.Lookup(d.name)
   869  		typ := typs[d.typ]
   870  		switch d.tag {
   871  		case funcTag:
   872  			importsym(Runtimepkg, sym, ONAME)
   873  			n := newfuncname(sym)
   874  			n.Type = typ
   875  			declare(n, PFUNC)
   876  		case varTag:
   877  			importvar(lineno, Runtimepkg, sym, typ)
   878  		default:
   879  			Fatalf("unhandled declaration tag %v", d.tag)
   880  		}
   881  	}
   882  
   883  	typecheckok = false
   884  	resumecheckwidth()
   885  	inimport = false
   886  }
   887  
   888  func importfile(f *Val) *types.Pkg {
   889  	path_, ok := f.U.(string)
   890  	if !ok {
   891  		yyerror("import path must be a string")
   892  		return nil
   893  	}
   894  
   895  	if len(path_) == 0 {
   896  		yyerror("import path is empty")
   897  		return nil
   898  	}
   899  
   900  	if isbadimport(path_, false) {
   901  		return nil
   902  	}
   903  
   904  	// The package name main is no longer reserved,
   905  	// but we reserve the import path "main" to identify
   906  	// the main package, just as we reserve the import
   907  	// path "math" to identify the standard math package.
   908  	if path_ == "main" {
   909  		yyerror("cannot import \"main\"")
   910  		errorexit()
   911  	}
   912  
   913  	if myimportpath != "" && path_ == myimportpath {
   914  		yyerror("import %q while compiling that package (import cycle)", path_)
   915  		errorexit()
   916  	}
   917  
   918  	if mapped, ok := importMap[path_]; ok {
   919  		path_ = mapped
   920  	}
   921  
   922  	if path_ == "unsafe" {
   923  		if safemode {
   924  			yyerror("cannot import package unsafe")
   925  			errorexit()
   926  		}
   927  
   928  		imported_unsafe = true
   929  		return unsafepkg
   930  	}
   931  
   932  	if islocalname(path_) {
   933  		if path_[0] == '/' {
   934  			yyerror("import path cannot be absolute path")
   935  			return nil
   936  		}
   937  
   938  		prefix := Ctxt.Pathname
   939  		if localimport != "" {
   940  			prefix = localimport
   941  		}
   942  		path_ = path.Join(prefix, path_)
   943  
   944  		if isbadimport(path_, true) {
   945  			return nil
   946  		}
   947  	}
   948  
   949  	file, found := findpkg(path_)
   950  	if !found {
   951  		yyerror("can't find import: %q", path_)
   952  		errorexit()
   953  	}
   954  
   955  	importpkg := types.NewPkg(path_, "")
   956  	if importpkg.Imported {
   957  		return importpkg
   958  	}
   959  
   960  	importpkg.Imported = true
   961  
   962  	impf, err := os.Open(file)
   963  	if err != nil {
   964  		yyerror("can't open import: %q: %v", path_, err)
   965  		errorexit()
   966  	}
   967  	defer impf.Close()
   968  	imp := bufio.NewReader(impf)
   969  
   970  	// check object header
   971  	p, err := imp.ReadString('\n')
   972  	if err != nil {
   973  		yyerror("import %s: reading input: %v", file, err)
   974  		errorexit()
   975  	}
   976  	if len(p) > 0 {
   977  		p = p[:len(p)-1]
   978  	}
   979  
   980  	if p == "!<arch>" { // package archive
   981  		// package export block should be first
   982  		sz := arsize(imp, "__.PKGDEF")
   983  		if sz <= 0 {
   984  			yyerror("import %s: not a package file", file)
   985  			errorexit()
   986  		}
   987  		p, err = imp.ReadString('\n')
   988  		if err != nil {
   989  			yyerror("import %s: reading input: %v", file, err)
   990  			errorexit()
   991  		}
   992  		if len(p) > 0 {
   993  			p = p[:len(p)-1]
   994  		}
   995  	}
   996  
   997  	if p != "empty archive" {
   998  		if !strings.HasPrefix(p, "go object ") {
   999  			yyerror("import %s: not a go object file: %s", file, p)
  1000  			errorexit()
  1001  		}
  1002  
  1003  		q := fmt.Sprintf("%s %s %s %s", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
  1004  		if p[10:] != q {
  1005  			yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
  1006  			errorexit()
  1007  		}
  1008  	}
  1009  
  1010  	// process header lines
  1011  	safe := false
  1012  	for {
  1013  		p, err = imp.ReadString('\n')
  1014  		if err != nil {
  1015  			yyerror("import %s: reading input: %v", file, err)
  1016  			errorexit()
  1017  		}
  1018  		if p == "\n" {
  1019  			break // header ends with blank line
  1020  		}
  1021  		if strings.HasPrefix(p, "safe") {
  1022  			safe = true
  1023  			break // ok to ignore rest
  1024  		}
  1025  	}
  1026  	if safemode && !safe {
  1027  		yyerror("cannot import unsafe package %q", importpkg.Path)
  1028  	}
  1029  
  1030  	// assume files move (get installed) so don't record the full path
  1031  	if packageFile != nil {
  1032  		// If using a packageFile map, assume path_ can be recorded directly.
  1033  		Ctxt.AddImport(path_)
  1034  	} else {
  1035  		// For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
  1036  		Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):])
  1037  	}
  1038  
  1039  	// In the importfile, if we find:
  1040  	// $$\n  (textual format): not supported anymore
  1041  	// $$B\n (binary format) : import directly, then feed the lexer a dummy statement
  1042  
  1043  	// look for $$
  1044  	var c byte
  1045  	for {
  1046  		c, err = imp.ReadByte()
  1047  		if err != nil {
  1048  			break
  1049  		}
  1050  		if c == '$' {
  1051  			c, err = imp.ReadByte()
  1052  			if c == '$' || err != nil {
  1053  				break
  1054  			}
  1055  		}
  1056  	}
  1057  
  1058  	// get character after $$
  1059  	if err == nil {
  1060  		c, _ = imp.ReadByte()
  1061  	}
  1062  
  1063  	switch c {
  1064  	case '\n':
  1065  		yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
  1066  		return nil
  1067  
  1068  	case 'B':
  1069  		if Debug_export != 0 {
  1070  			fmt.Printf("importing %s (%s)\n", path_, file)
  1071  		}
  1072  		imp.ReadByte() // skip \n after $$B
  1073  		Import(importpkg, imp)
  1074  
  1075  	default:
  1076  		yyerror("no import in %q", path_)
  1077  		errorexit()
  1078  	}
  1079  
  1080  	return importpkg
  1081  }
  1082  
  1083  func pkgnotused(lineno src.XPos, path string, name string) {
  1084  	// If the package was imported with a name other than the final
  1085  	// import path element, show it explicitly in the error message.
  1086  	// Note that this handles both renamed imports and imports of
  1087  	// packages containing unconventional package declarations.
  1088  	// Note that this uses / always, even on Windows, because Go import
  1089  	// paths always use forward slashes.
  1090  	elem := path
  1091  	if i := strings.LastIndex(elem, "/"); i >= 0 {
  1092  		elem = elem[i+1:]
  1093  	}
  1094  	if name == "" || elem == name {
  1095  		yyerrorl(lineno, "imported and not used: %q", path)
  1096  	} else {
  1097  		yyerrorl(lineno, "imported and not used: %q as %s", path, name)
  1098  	}
  1099  }
  1100  
  1101  func mkpackage(pkgname string) {
  1102  	if localpkg.Name == "" {
  1103  		if pkgname == "_" {
  1104  			yyerror("invalid package name _")
  1105  		}
  1106  		localpkg.Name = pkgname
  1107  	} else {
  1108  		if pkgname != localpkg.Name {
  1109  			yyerror("package %s; expected %s", pkgname, localpkg.Name)
  1110  		}
  1111  	}
  1112  }
  1113  
  1114  func clearImports() {
  1115  	type importedPkg struct {
  1116  		pos  src.XPos
  1117  		path string
  1118  		name string
  1119  	}
  1120  	var unused []importedPkg
  1121  
  1122  	for _, s := range localpkg.Syms {
  1123  		n := asNode(s.Def)
  1124  		if n == nil {
  1125  			continue
  1126  		}
  1127  		if n.Op == OPACK {
  1128  			// throw away top-level package name left over
  1129  			// from previous file.
  1130  			// leave s->block set to cause redeclaration
  1131  			// errors if a conflicting top-level name is
  1132  			// introduced by a different file.
  1133  			if !n.Name.Used() && nsyntaxerrors == 0 {
  1134  				unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name})
  1135  			}
  1136  			s.Def = nil
  1137  			continue
  1138  		}
  1139  		if IsAlias(s) {
  1140  			// throw away top-level name left over
  1141  			// from previous import . "x"
  1142  			if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 {
  1143  				unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""})
  1144  				n.Name.Pack.Name.SetUsed(true)
  1145  			}
  1146  			s.Def = nil
  1147  			continue
  1148  		}
  1149  	}
  1150  
  1151  	obj.SortSlice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
  1152  	for _, pkg := range unused {
  1153  		pkgnotused(pkg.pos, pkg.path, pkg.name)
  1154  	}
  1155  }
  1156  
  1157  func IsAlias(sym *types.Sym) bool {
  1158  	return sym.Def != nil && asNode(sym.Def).Sym != sym
  1159  }
  1160  
  1161  // By default, assume any debug flags are incompatible with concurrent compilation.
  1162  // A few are safe and potentially in common use for normal compiles, though; mark them as such here.
  1163  var concurrentFlagOK = [256]bool{
  1164  	'B': true, // disabled bounds checking
  1165  	'C': true, // disable printing of columns in error messages
  1166  	'e': true, // no limit on errors; errors all come from non-concurrent code
  1167  	'I': true, // add `directory` to import search path
  1168  	'N': true, // disable optimizations
  1169  	'l': true, // disable inlining
  1170  	'w': true, // all printing happens before compilation
  1171  	'W': true, // all printing happens before compilation
  1172  }
  1173  
  1174  func concurrentBackendAllowed() bool {
  1175  	for i, x := range Debug {
  1176  		if x != 0 && !concurrentFlagOK[i] {
  1177  			return false
  1178  		}
  1179  	}
  1180  	// Debug_asm by itself is ok, because all printing occurs
  1181  	// while writing the object file, and that is non-concurrent.
  1182  	// Adding Debug_vlog, however, causes Debug_asm to also print
  1183  	// while flushing the plist, which happens concurrently.
  1184  	if Debug_vlog || debugstr != "" || debuglive > 0 {
  1185  		return false
  1186  	}
  1187  	// TODO: test and add builders for GOEXPERIMENT values, and enable
  1188  	if os.Getenv("GOEXPERIMENT") != "" {
  1189  		return false
  1190  	}
  1191  	// TODO: fix races and enable the following flags
  1192  	if Ctxt.Flag_shared || Ctxt.Flag_dynlink || flag_race {
  1193  		return false
  1194  	}
  1195  	return true
  1196  }