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