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