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