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.
5 //go:generate go run mkbuiltin.go
12 "cmd/compile/internal/logopt"
13 "cmd/compile/internal/ssa"
14 "cmd/compile/internal/types"
36 var imported_unsafe bool
46 Debug_compilelater int
54 Debug_locationlist int
55 Debug_typecheckinl int
62 // These can be specified with the -d flag, as in "-d nil"
63 // to set the debug_checknil variable.
64 // Multiple options can be comma-separated.
65 // Each option accepts an optional argument, as in "gcprog=2"
66 var debugtab = []struct {
69 val interface{} // must be *int or *string
71 {"append", "print information about append compilation", &Debug_append},
72 {"checkptr", "instrument unsafe pointer conversions", &Debug_checkptr},
73 {"closure", "print information about closure compilation", &Debug_closure},
74 {"compilelater", "compile functions as late as possible", &Debug_compilelater},
75 {"disablenil", "disable nil checks", &disable_checknil},
76 {"dclstack", "run internal dclstack check", &debug_dclstack},
77 {"gcprog", "print dump of GC programs", &Debug_gcprog},
78 {"libfuzzer", "coverage instrumentation for libfuzzer", &Debug_libfuzzer},
79 {"nil", "print information about nil checks", &Debug_checknil},
80 {"panic", "do not hide any compiler panic", &Debug_panic},
81 {"slice", "print information about slice compilation", &Debug_slice},
82 {"typeassert", "print information about type assertion inlining", &Debug_typeassert},
83 {"wb", "print information about write barriers", &Debug_wb},
84 {"export", "print export data", &Debug_export},
85 {"pctab", "print named pc-value table", &Debug_pctab},
86 {"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
87 {"typecheckinl", "eager typechecking of inline function bodies", &Debug_typecheckinl},
88 {"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl},
89 {"softfloat", "force compiler to emit soft-float code", &Debug_softfloat},
90 {"defer", "print information about defer compilation", &Debug_defer},
93 const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
99 const debugHelpFooter = `
100 <value> is key-specific.
102 Key "checkptr" supports values:
103 "0": instrumentation disabled
104 "1": conversions involving unsafe.Pointer are instrumented
105 "2": conversions to unsafe.Pointer force heap allocation
107 Key "pctab" supports values:
108 "pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
112 fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n")
113 objabi.Flagprint(os.Stderr)
118 if Debug_panic == 0 && nsavederrors+nerrors > 0 {
119 // If we've already complained about things
120 // in the program, don't bother complaining
121 // about a panic too; let the user clean up
122 // the code and try again.
123 if err := recover(); err != nil {
129 // supportsDynlink reports whether or not the code generator for the given
130 // architecture supports the -shared and -dynlink flags.
131 func supportsDynlink(arch *sys.Arch) bool {
132 return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
135 // timing data for compiler phases
139 var nowritebarrierrecCheck *nowritebarrierrecChecker
141 // Main parses flags and Go source files specified in the command-line
142 // arguments, type-checks the parsed Go package, compiles functions to machine
143 // code, and finally writes the compiled package definition to disk.
144 func Main(archInit func(*Arch)) {
145 timings.Start("fe", "init")
151 Ctxt = obj.Linknew(thearch.LinkArch)
152 Ctxt.DiagFunc = yyerror
153 Ctxt.DiagFlush = flusherrors
154 Ctxt.Bso = bufio.NewWriter(os.Stdout)
156 // UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
157 // on Darwin don't support it properly, especially since macOS 10.14 (Mojave). This is exposed as a flag
158 // to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
159 // See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
160 Ctxt.UseBASEntries = Ctxt.Headtype != objabi.Hdarwin
162 localpkg = types.NewPkg("", "")
163 localpkg.Prefix = "\"\""
165 // We won't know localpkg's height until after import
166 // processing. In the mean time, set to MaxPkgHeight to ensure
167 // height comparisons at least work until then.
168 localpkg.Height = types.MaxPkgHeight
170 // pseudo-package, for scoping
171 builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
172 builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
174 // pseudo-package, accessed by import "unsafe"
175 unsafepkg = types.NewPkg("unsafe", "unsafe")
177 // Pseudo-package that contains the compiler's builtin
178 // declarations for package runtime. These are declared in a
179 // separate package to avoid conflicts with package runtime's
180 // actual declarations, which may differ intentionally but
182 Runtimepkg = types.NewPkg("go.runtime", "runtime")
183 Runtimepkg.Prefix = "runtime"
185 // pseudo-packages used in symbol tables
186 itabpkg = types.NewPkg("go.itab", "go.itab")
187 itabpkg.Prefix = "go.itab" // not go%2eitab
189 itablinkpkg = types.NewPkg("go.itablink", "go.itablink")
190 itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
192 trackpkg = types.NewPkg("go.track", "go.track")
193 trackpkg.Prefix = "go.track" // not go%2etrack
195 // pseudo-package used for map zero values
196 mappkg = types.NewPkg("go.map", "go.map")
197 mappkg.Prefix = "go.map"
199 // pseudo-package used for methods with anonymous receivers
200 gopkg = types.NewPkg("go", "")
202 Wasm := objabi.GOARCH == "wasm"
204 // Whether the limit for stack-allocated objects is much smaller than normal.
205 // This can be helpful for diagnosing certain causes of GC latency. See #27732.
209 flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
210 flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
211 objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
212 objabi.Flagcount("B", "disable bounds checking", &Debug['B'])
213 objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C']) // TODO(gri) remove eventually
214 flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
215 objabi.Flagcount("E", "debug symbol export", &Debug['E'])
216 objabi.Flagfn1("I", "add `directory` to import search path", addidir)
217 objabi.Flagcount("K", "debug missing line numbers", &Debug['K'])
218 objabi.Flagcount("L", "show full file names in error messages", &Debug['L'])
219 objabi.Flagcount("N", "disable optimizations", &Debug['N'])
220 objabi.Flagcount("S", "print assembly listing", &Debug['S'])
221 objabi.AddVersionFlag() // -V
222 objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
223 flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
224 flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
225 flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
226 flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
227 flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
228 flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
229 flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
230 flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
231 objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
232 objabi.Flagcount("h", "halt on error", &Debug['h'])
233 objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
234 objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
235 flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
236 objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
237 objabi.Flagcount("l", "disable inlining", &Debug['l'])
238 flag.StringVar(&flag_lang, "lang", "", "release to compile for")
239 flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
240 objabi.Flagcount("live", "debug liveness analysis", &debuglive)
241 objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
242 if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
243 flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
245 flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
246 flag.StringVar(&outfile, "o", "", "write output to `file`")
247 flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
248 flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o")
249 objabi.Flagcount("r", "debug generated wrappers", &Debug['r'])
250 if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
251 flag.BoolVar(&flag_race, "race", false, "enable race detector")
254 flag.BoolVar(&trace, "t", false, "trace type-checking")
256 flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
257 flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
258 objabi.Flagcount("w", "debug type checking", &Debug['w'])
259 flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
261 var flag_dynlink bool
262 if supportsDynlink(thearch.LinkArch.Arch) {
263 flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
264 flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
265 flag.BoolVar(&Ctxt.Flag_linkshared, "linkshared", false, "generate code that will be linked against Go shared libraries")
267 flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
268 flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
269 flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
271 flag.StringVar(&goversion, "goversion", "", "required version of the runtime")
272 var symabisPath string
273 flag.StringVar(&symabisPath, "symabis", "", "read symbol ABIs from `file`")
274 flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
275 flag.StringVar(&blockprofile, "blockprofile", "", "write block profile to `file`")
276 flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`")
277 flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
278 flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
279 flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
280 flag.StringVar(&jsonLogOpt, "json", "", "version,destination for JSON compiler/optimizer logging")
282 objabi.Flagparse(usage)
284 // Record flags that affect the build result. (And don't
285 // record flags that don't, since that would cause spurious
286 // changes in the binary.)
287 recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes")
290 maxStackVarSize = 128 * 1024
291 maxImplicitStackVarSize = 16 * 1024
294 Ctxt.Flag_shared = flag_dynlink || flag_shared
295 Ctxt.Flag_dynlink = flag_dynlink
296 Ctxt.Flag_optimize = Debug['N'] == 0
298 Ctxt.Debugasm = Debug['S']
299 Ctxt.Debugvlog = Debug_vlog
301 Ctxt.DebugInfo = debuginfo
302 Ctxt.GenAbstractFunc = genAbstractFunc
303 Ctxt.DwFixups = obj.NewDwarfFixupTable(Ctxt)
305 // turn off inline generation if no dwarf at all
307 Ctxt.Flag_locationlists = false
310 if flag.NArg() < 1 && debugstr != "help" && debugstr != "ssa/help" {
314 if goversion != "" && goversion != runtime.Version() {
315 fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), goversion)
321 if symabisPath != "" {
322 readSymABIs(symabisPath, myimportpath)
325 thearch.LinkArch.Init(Ctxt)
329 if i := strings.LastIndex(p, "/"); i >= 0 {
332 if runtime.GOOS == "windows" {
333 if i := strings.LastIndex(p, `\`); i >= 0 {
337 if i := strings.LastIndex(p, "."); i >= 0 {
349 if flag_race && flag_msan {
350 log.Fatal("cannot use both -race and -msan")
352 if (flag_race || flag_msan) && objabi.GOOS != "windows" {
353 // -race and -msan imply -d=checkptr for now (except on windows).
354 // TODO(mdempsky): Re-evaluate before Go 1.14. See #34964.
357 if ispkgin(omit_pkgs) {
362 racepkg = types.NewPkg("runtime/race", "")
365 msanpkg = types.NewPkg("runtime/msan", "")
367 if flag_race || flag_msan {
371 if compiling_runtime && Debug['N'] != 0 {
372 log.Fatal("cannot disable optimizations while compiling runtime")
374 if nBackendWorkers < 1 {
375 log.Fatalf("-c must be at least 1, got %d", nBackendWorkers)
377 if nBackendWorkers > 1 && !concurrentBackendAllowed() {
378 log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
380 if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
381 log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
387 for _, name := range strings.Split(debugstr, ",") {
391 // display help about the -d option itself and quit
393 fmt.Print(debugHelpHeader)
394 maxLen := len("ssa/help")
395 for _, t := range debugtab {
396 if len(t.name) > maxLen {
400 for _, t := range debugtab {
401 fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
403 // ssa options have their own help
404 fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
405 fmt.Print(debugHelpFooter)
408 val, valstring, haveInt := 1, "", true
409 if i := strings.IndexAny(name, "=:"); i >= 0 {
411 name, valstring = name[:i], name[i+1:]
412 val, err = strconv.Atoi(valstring)
414 val, haveInt = 1, false
417 for _, t := range debugtab {
421 switch vp := t.val.(type) {
428 log.Fatalf("invalid debug value %v", name)
432 panic("bad debugtab type")
436 // special case for ssa for now
437 if strings.HasPrefix(name, "ssa/") {
438 // expect form ssa/phase/flag
439 // e.g. -d=ssa/generic_cse/time
440 // _ in phase name also matches space
442 flag := "debug" // default flag is debug
443 if i := strings.Index(phase, "/"); i >= 0 {
447 err := ssa.PhaseOption(phase, flag, val, valstring)
453 log.Fatalf("unknown debug key -d %s\n", name)
457 if compiling_runtime {
458 // Runtime can't use -d=checkptr, at least not yet.
461 // Fuzzing the runtime isn't interesting either.
466 Ctxt.Debugpcln = Debug_pctab
468 dwarf.EnableLogging(Debug_gendwarfinl != 0)
471 if Debug_softfloat != 0 {
472 thearch.SoftFloat = true
475 // enable inlining. for now:
476 // default: inlining on. (debug['l'] == 1)
477 // -l: inlining off (debug['l'] == 0)
478 // -l=2, -l=3: inlining on again, with extra debugging (debug['l'] > 1)
480 Debug['l'] = 1 - Debug['l']
483 if jsonLogOpt != "" { // parse version,destination from json logging optimization.
484 logopt.LogJsonOption(jsonLogOpt)
487 ssaDump = os.Getenv("GOSSAFUNC")
489 if strings.HasSuffix(ssaDump, "+") {
490 ssaDump = ssaDump[:len(ssaDump)-1]
493 spl := strings.Split(ssaDump, ":")
500 trackScopes = flagDWARF
502 Widthptr = thearch.LinkArch.PtrSize
503 Widthreg = thearch.LinkArch.RegSize
505 // initialize types package
506 // (we need to do this to break dependencies that otherwise
507 // would lead to import cycles)
508 types.Widthptr = Widthptr
509 types.Dowidth = dowidth
510 types.Fatalf = Fatalf
511 types.Sconv = func(s *types.Sym, flag, mode int) string {
512 return sconv(s, FmtFlag(flag), fmtMode(mode))
514 types.Tconv = func(t *types.Type, flag, mode, depth int) string {
515 return tconv(t, FmtFlag(flag), fmtMode(mode), depth)
517 types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
518 symFormat(sym, s, verb, fmtMode(mode))
520 types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
521 typeFormat(t, s, verb, fmtMode(mode))
523 types.TypeLinkSym = func(t *types.Type) *obj.LSym {
524 return typenamesym(t).Linksym()
526 types.FmtLeft = int(FmtLeft)
527 types.FmtUnsigned = int(FmtUnsigned)
528 types.FErr = int(FErr)
536 autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
538 timings.Start("fe", "loadsys")
541 timings.Start("fe", "parse")
542 lines := parseFiles(flag.Args())
544 timings.AddEvent(int64(lines), "lines")
552 // Process top-level declarations in phases.
554 // Phase 1: const, type, and names and types of funcs.
555 // This will gather all the information about types
556 // and methods but doesn't depend on any of it.
558 // We also defer type alias declarations until phase 2
559 // to avoid cycles like #18640.
560 // TODO(gri) Remove this again once we have a fix for #25838.
562 // Don't use range--typecheck can add closures to xtop.
563 timings.Start("fe", "typecheck", "top1")
564 for i := 0; i < len(xtop); i++ {
566 if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
567 xtop[i] = typecheck(n, ctxStmt)
571 // Phase 2: Variable assignments.
572 // To check interface assignments, depends on phase 1.
574 // Don't use range--typecheck can add closures to xtop.
575 timings.Start("fe", "typecheck", "top2")
576 for i := 0; i < len(xtop); i++ {
578 if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
579 xtop[i] = typecheck(n, ctxStmt)
583 // Phase 3: Type check function bodies.
584 // Don't use range--typecheck can add closures to xtop.
585 timings.Start("fe", "typecheck", "func")
587 for i := 0; i < len(xtop); i++ {
589 if op := n.Op; op == ODCLFUNC || op == OCLOSURE {
593 typecheckslice(Curfn.Nbody.Slice(), ctxStmt)
596 Curfn.Nbody.Set(nil) // type errors; do not compile
598 // Now that we've checked whether n terminates,
599 // we can eliminate some obviously dead code.
604 // With all types checked, it's now safe to verify map keys. One single
605 // check past phase 9 isn't sufficient, as we may exit with other errors
606 // before then, thus skipping map key errors.
608 timings.AddEvent(fcount, "funcs")
610 if nsavederrors+nerrors != 0 {
614 // Phase 4: Decide how to capture closed variables.
615 // This needs to run before escape analysis,
616 // because variables captured by value do not escape.
617 timings.Start("fe", "capturevars")
618 for _, n := range xtop {
619 if n.Op == ODCLFUNC && n.Func.Closure != nil {
624 capturevarscomplete = true
628 if nsavederrors+nerrors != 0 {
633 timings.Start("fe", "inlining")
634 if Debug_typecheckinl != 0 {
635 // Typecheck imported function bodies if debug['l'] > 1,
636 // otherwise lazily when used or re-exported.
637 for _, n := range importlist {
638 if n.Func.Inl != nil {
644 if nsavederrors+nerrors != 0 {
650 // Find functions that can be inlined and clone them before walk expands them.
651 visitBottomUp(xtop, func(list []*Node, recursive bool) {
652 for _, n := range list {
657 fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
665 // Phase 6: Escape analysis.
666 // Required for moving heap allocations onto stack,
667 // which in turn is required by the closure implementation,
668 // which stores the addresses of stack variables into the closure.
669 // If the closure does not escape, it needs to be on the stack
670 // or else the stack copier will not update it.
671 // Large values are also moved off stack in escape analysis;
672 // because large values may contain pointers, it must happen early.
673 timings.Start("fe", "escapes")
676 // Collect information for go:nowritebarrierrec
677 // checking. This must happen before transformclosure.
678 // We'll do the final check after write barriers are
680 if compiling_runtime {
681 nowritebarrierrecCheck = newNowritebarrierrecChecker()
684 // Phase 7: Transform closure bodies to properly reference captured variables.
685 // This needs to happen before walk, because closures must be transformed
686 // before walk reaches a call of a closure.
687 timings.Start("fe", "xclosures")
688 for _, n := range xtop {
689 if n.Op == ODCLFUNC && n.Func.Closure != nil {
695 // Prepare for SSA compilation.
696 // This must be before peekitabs, because peekitabs
697 // can trigger function compilation.
700 // Just before compilation, compile itabs found on
701 // the right side of OCONVIFACE so that methods
702 // can be de-virtualized during compilation.
706 // Phase 8: Compile top level functions.
707 // Don't use range--walk can add functions to xtop.
708 timings.Start("be", "compilefuncs")
710 for i := 0; i < len(xtop); i++ {
712 if n.Op == ODCLFUNC {
717 timings.AddEvent(fcount, "funcs")
719 if nsavederrors+nerrors == 0 {
725 if nowritebarrierrecCheck != nil {
726 // Write barriers are now known. Check the
728 nowritebarrierrecCheck.check()
729 nowritebarrierrecCheck = nil
732 // Finalize DWARF inline routine DIEs, then explicitly turn off
733 // DWARF inlining gen so as to avoid problems with generated
735 if Ctxt.DwFixups != nil {
736 Ctxt.DwFixups.Finalize(myimportpath, Debug_gendwarfinl != 0)
741 // Phase 9: Check external declarations.
742 timings.Start("be", "externaldcls")
743 for i, n := range externdcl {
745 externdcl[i] = typecheck(externdcl[i], ctxExpr)
748 // Check the map keys again, since we typechecked the external
752 if nerrors+nsavederrors != 0 {
756 // Write object data to disk.
757 timings.Start("be", "dumpobj")
759 Ctxt.NumberSyms(false)
765 // Check whether any of the functions we have compiled have gigantic stack frames.
766 sort.Slice(largeStackFrames, func(i, j int) bool {
767 return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
769 for _, large := range largeStackFrames {
770 if large.callee != 0 {
771 yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
773 yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
777 if len(compilequeue) != 0 {
778 Fatalf("%d uncompiled functions", len(compilequeue))
781 logopt.FlushLoggedOpts(Ctxt, myimportpath)
783 if nerrors+nsavederrors != 0 {
791 if err := writebench(benchfile); err != nil {
792 log.Fatalf("cannot write benchmark data: %v", err)
797 func writebench(filename string) error {
798 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
804 fmt.Fprintln(&buf, "commit:", objabi.Version)
805 fmt.Fprintln(&buf, "goos:", runtime.GOOS)
806 fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
807 timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":")
809 n, err := f.Write(buf.Bytes())
821 importMap = map[string]string{}
822 packageFile map[string]string // nil means not in use
825 func addImportMap(s string) {
826 if strings.Count(s, "=") != 1 {
827 log.Fatal("-importmap argument must be of the form source=actual")
829 i := strings.Index(s, "=")
830 source, actual := s[:i], s[i+1:]
831 if source == "" || actual == "" {
832 log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
834 importMap[source] = actual
837 func readImportCfg(file string) {
838 packageFile = map[string]string{}
839 data, err := ioutil.ReadFile(file)
841 log.Fatalf("-importcfg: %v", err)
844 for lineNum, line := range strings.Split(string(data), "\n") {
846 line = strings.TrimSpace(line)
847 if line == "" || strings.HasPrefix(line, "#") {
851 var verb, args string
852 if i := strings.Index(line, " "); i < 0 {
855 verb, args = line[:i], strings.TrimSpace(line[i+1:])
857 var before, after string
858 if i := strings.Index(args, "="); i >= 0 {
859 before, after = args[:i], args[i+1:]
863 log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
865 if before == "" || after == "" {
866 log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
868 importMap[before] = after
870 if before == "" || after == "" {
871 log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
873 packageFile[before] = after
878 // symabiDefs and symabiRefs record the defined and referenced ABIs of
879 // symbols required by non-Go code. These are keyed by link symbol
880 // name, where the local package prefix is always `"".`
881 var symabiDefs, symabiRefs map[string]obj.ABI
883 // readSymABIs reads a symabis file that specifies definitions and
884 // references of text symbols by ABI.
886 // The symabis format is a set of lines, where each line is a sequence
887 // of whitespace-separated fields. The first field is a verb and is
888 // either "def" for defining a symbol ABI or "ref" for referencing a
889 // symbol using an ABI. For both "def" and "ref", the second field is
890 // the symbol name and the third field is the ABI name, as one of the
891 // named cmd/internal/obj.ABI constants.
892 func readSymABIs(file, myimportpath string) {
893 data, err := ioutil.ReadFile(file)
895 log.Fatalf("-symabis: %v", err)
898 symabiDefs = make(map[string]obj.ABI)
899 symabiRefs = make(map[string]obj.ABI)
902 if myimportpath != "" {
903 // Symbols in this package may be written either as
904 // "".X or with the package's import path already in
906 localPrefix = objabi.PathToPrefix(myimportpath) + "."
909 for lineNum, line := range strings.Split(string(data), "\n") {
911 line = strings.TrimSpace(line)
912 if line == "" || strings.HasPrefix(line, "#") {
916 parts := strings.Fields(line)
921 log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
923 sym, abi := parts[1], parts[2]
924 if abi != "ABI0" { // Only supported external ABI right now
925 log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi)
928 // If the symbol is already prefixed with
929 // myimportpath, rewrite it to start with ""
930 // so it matches the compiler's internal
932 if localPrefix != "" && strings.HasPrefix(sym, localPrefix) {
933 sym = `"".` + sym[len(localPrefix):]
937 if parts[0] == "def" {
938 symabiDefs[sym] = obj.ABI0
940 symabiRefs[sym] = obj.ABI0
943 log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
949 nsavederrors += nerrors
953 func arsize(b *bufio.Reader, name string) int {
954 var buf [ArhdrSize]byte
955 if _, err := io.ReadFull(b, buf[:]); err != nil {
958 aname := strings.Trim(string(buf[0:16]), " ")
959 if !strings.HasPrefix(aname, name) {
962 asize := strings.Trim(string(buf[48:58]), " ")
963 i, _ := strconv.Atoi(asize)
969 func addidir(dir string) {
971 idirs = append(idirs, dir)
975 func isDriveLetter(b byte) bool {
976 return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
979 // is this path a local name? begins with ./ or ../ or /
980 func islocalname(name string) bool {
981 return strings.HasPrefix(name, "/") ||
982 runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
983 strings.HasPrefix(name, "./") || name == "." ||
984 strings.HasPrefix(name, "../") || name == ".."
987 func findpkg(name string) (file string, ok bool) {
988 if islocalname(name) {
993 if packageFile != nil {
994 file, ok = packageFile[name]
998 // try .a before .6. important for building libraries:
999 // if there is an array.6 in the array.a library,
1000 // want to find all of array.a, not just array.6.
1001 file = fmt.Sprintf("%s.a", name)
1002 if _, err := os.Stat(file); err == nil {
1005 file = fmt.Sprintf("%s.o", name)
1006 if _, err := os.Stat(file); err == nil {
1012 // local imports should be canonicalized already.
1013 // don't want to see "encoding/../encoding/base64"
1014 // as different from "encoding/base64".
1015 if q := path.Clean(name); q != name {
1016 yyerror("non-canonical import path %q (should be %q)", name, q)
1020 if packageFile != nil {
1021 file, ok = packageFile[name]
1025 for _, dir := range idirs {
1026 file = fmt.Sprintf("%s/%s.a", dir, name)
1027 if _, err := os.Stat(file); err == nil {
1030 file = fmt.Sprintf("%s/%s.o", dir, name)
1031 if _, err := os.Stat(file); err == nil {
1036 if objabi.GOROOT != "" {
1039 if flag_installsuffix != "" {
1041 suffix = flag_installsuffix
1042 } else if flag_race {
1045 } else if flag_msan {
1050 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
1051 if _, err := os.Stat(file); err == nil {
1054 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
1055 if _, err := os.Stat(file); err == nil {
1063 // loadsys loads the definitions for the low-level runtime functions,
1064 // so that the compiler can generate calls to them,
1065 // but does not make them visible to user code.
1072 typs := runtimeTypes()
1073 for _, d := range runtimeDecls {
1074 sym := Runtimepkg.Lookup(d.name)
1078 importfunc(Runtimepkg, src.NoXPos, sym, typ)
1080 importvar(Runtimepkg, src.NoXPos, sym, typ)
1082 Fatalf("unhandled declaration tag %v", d.tag)
1090 // myheight tracks the local package's height based on packages
1094 func importfile(f *Val) *types.Pkg {
1095 path_, ok := f.U.(string)
1097 yyerror("import path must be a string")
1101 if len(path_) == 0 {
1102 yyerror("import path is empty")
1106 if isbadimport(path_, false) {
1110 // The package name main is no longer reserved,
1111 // but we reserve the import path "main" to identify
1112 // the main package, just as we reserve the import
1113 // path "math" to identify the standard math package.
1114 if path_ == "main" {
1115 yyerror("cannot import \"main\"")
1119 if myimportpath != "" && path_ == myimportpath {
1120 yyerror("import %q while compiling that package (import cycle)", path_)
1124 if mapped, ok := importMap[path_]; ok {
1128 if path_ == "unsafe" {
1129 imported_unsafe = true
1133 if islocalname(path_) {
1134 if path_[0] == '/' {
1135 yyerror("import path cannot be absolute path")
1139 prefix := Ctxt.Pathname
1140 if localimport != "" {
1141 prefix = localimport
1143 path_ = path.Join(prefix, path_)
1145 if isbadimport(path_, true) {
1150 file, found := findpkg(path_)
1152 yyerror("can't find import: %q", path_)
1156 importpkg := types.NewPkg(path_, "")
1157 if importpkg.Imported {
1161 importpkg.Imported = true
1163 imp, err := bio.Open(file)
1165 yyerror("can't open import: %q: %v", path_, err)
1170 // check object header
1171 p, err := imp.ReadString('\n')
1173 yyerror("import %s: reading input: %v", file, err)
1177 if p == "!<arch>\n" { // package archive
1178 // package export block should be first
1179 sz := arsize(imp.Reader, "__.PKGDEF")
1181 yyerror("import %s: not a package file", file)
1184 p, err = imp.ReadString('\n')
1186 yyerror("import %s: reading input: %v", file, err)
1191 if !strings.HasPrefix(p, "go object ") {
1192 yyerror("import %s: not a go object file: %s", file, p)
1195 q := fmt.Sprintf("%s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
1197 yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
1201 // process header lines
1203 p, err = imp.ReadString('\n')
1205 yyerror("import %s: reading input: %v", file, err)
1209 break // header ends with blank line
1213 // assume files move (get installed) so don't record the full path
1214 if packageFile != nil {
1215 // If using a packageFile map, assume path_ can be recorded directly.
1216 Ctxt.AddImport(path_)
1218 // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
1219 Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):])
1222 // In the importfile, if we find:
1223 // $$\n (textual format): not supported anymore
1224 // $$B\n (binary format) : import directly, then feed the lexer a dummy statement
1229 c, err = imp.ReadByte()
1234 c, err = imp.ReadByte()
1235 if c == '$' || err != nil {
1241 // get character after $$
1243 c, _ = imp.ReadByte()
1248 yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
1252 if Debug_export != 0 {
1253 fmt.Printf("importing %s (%s)\n", path_, file)
1255 imp.ReadByte() // skip \n after $$B
1257 c, err = imp.ReadByte()
1259 yyerror("import %s: reading input: %v", file, err)
1263 // Indexed format is distinguished by an 'i' byte,
1264 // whereas previous export formats started with 'c', 'd', or 'v'.
1266 yyerror("import %s: unexpected package format byte: %v", file, c)
1269 iimport(importpkg, imp)
1272 yyerror("no import in %q", path_)
1276 if importpkg.Height >= myheight {
1277 myheight = importpkg.Height + 1
1283 func pkgnotused(lineno src.XPos, path string, name string) {
1284 // If the package was imported with a name other than the final
1285 // import path element, show it explicitly in the error message.
1286 // Note that this handles both renamed imports and imports of
1287 // packages containing unconventional package declarations.
1288 // Note that this uses / always, even on Windows, because Go import
1289 // paths always use forward slashes.
1291 if i := strings.LastIndex(elem, "/"); i >= 0 {
1294 if name == "" || elem == name {
1295 yyerrorl(lineno, "imported and not used: %q", path)
1297 yyerrorl(lineno, "imported and not used: %q as %s", path, name)
1301 func mkpackage(pkgname string) {
1302 if localpkg.Name == "" {
1304 yyerror("invalid package name _")
1306 localpkg.Name = pkgname
1308 if pkgname != localpkg.Name {
1309 yyerror("package %s; expected %s", pkgname, localpkg.Name)
1314 func clearImports() {
1315 type importedPkg struct {
1320 var unused []importedPkg
1322 for _, s := range localpkg.Syms {
1328 // throw away top-level package name left over
1329 // from previous file.
1330 // leave s->block set to cause redeclaration
1331 // errors if a conflicting top-level name is
1332 // introduced by a different file.
1333 if !n.Name.Used() && nsyntaxerrors == 0 {
1334 unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name})
1340 // throw away top-level name left over
1341 // from previous import . "x"
1342 if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 {
1343 unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""})
1344 n.Name.Pack.Name.SetUsed(true)
1351 sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
1352 for _, pkg := range unused {
1353 pkgnotused(pkg.pos, pkg.path, pkg.name)
1357 func IsAlias(sym *types.Sym) bool {
1358 return sym.Def != nil && asNode(sym.Def).Sym != sym
1361 // By default, assume any debug flags are incompatible with concurrent compilation.
1362 // A few are safe and potentially in common use for normal compiles, though; mark them as such here.
1363 var concurrentFlagOK = [256]bool{
1364 'B': true, // disabled bounds checking
1365 'C': true, // disable printing of columns in error messages
1366 'e': true, // no limit on errors; errors all come from non-concurrent code
1367 'I': true, // add `directory` to import search path
1368 'N': true, // disable optimizations
1369 'l': true, // disable inlining
1370 'w': true, // all printing happens before compilation
1371 'W': true, // all printing happens before compilation
1372 'S': true, // printing disassembly happens at the end (but see concurrentBackendAllowed below)
1375 func concurrentBackendAllowed() bool {
1376 for i, x := range Debug {
1377 if x != 0 && !concurrentFlagOK[i] {
1381 // Debug['S'] by itself is ok, because all printing occurs
1382 // while writing the object file, and that is non-concurrent.
1383 // Adding Debug_vlog, however, causes Debug['S'] to also print
1384 // while flushing the plist, which happens concurrently.
1385 if Debug_vlog || debugstr != "" || debuglive > 0 {
1388 // TODO: Test and delete this condition.
1389 if objabi.Fieldtrack_enabled != 0 {
1392 // TODO: fix races and enable the following flags
1393 if Ctxt.Flag_shared || Ctxt.Flag_dynlink || flag_race {
1399 // recordFlags records the specified command-line flags to be placed
1400 // in the DWARF info.
1401 func recordFlags(flags ...string) {
1402 if myimportpath == "" {
1403 // We can't record the flags if we don't know what the
1408 type BoolFlag interface {
1411 type CountFlag interface {
1414 var cmd bytes.Buffer
1415 for _, name := range flags {
1416 f := flag.Lookup(name)
1420 getter := f.Value.(flag.Getter)
1421 if getter.String() == f.DefValue {
1422 // Flag has default value, so omit it.
1425 if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
1426 val, ok := getter.Get().(bool)
1428 fmt.Fprintf(&cmd, " -%s", f.Name)
1432 if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
1433 val, ok := getter.Get().(int)
1435 fmt.Fprintf(&cmd, " -%s", f.Name)
1439 fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
1445 s := Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + myimportpath)
1446 s.Type = objabi.SDWARFINFO
1447 // Sometimes (for example when building tests) we can link
1448 // together two package main archives. So allow dups.
1449 s.Set(obj.AttrDuplicateOK, true)
1450 Ctxt.Data = append(Ctxt.Data, s)
1451 s.P = cmd.Bytes()[1:]
1454 // recordPackageName records the name of the package being
1455 // compiled, so that the linker can save it in the compile unit's DIE.
1456 func recordPackageName() {
1457 s := Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + myimportpath)
1458 s.Type = objabi.SDWARFINFO
1459 // Sometimes (for example when building tests) we can link
1460 // together two package main archives. So allow dups.
1461 s.Set(obj.AttrDuplicateOK, true)
1462 Ctxt.Data = append(Ctxt.Data, s)
1463 s.P = []byte(localpkg.Name)
1466 // flag_lang is the language version we are compiling for, set by the -lang flag.
1467 var flag_lang string
1469 // currentLang returns the current language version.
1470 func currentLang() string {
1471 return fmt.Sprintf("go1.%d", goversion.Version)
1474 // goVersionRE is a regular expression that matches the valid
1475 // arguments to the -lang flag.
1476 var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
1478 // A lang is a language version broken into major and minor numbers.
1483 // langWant is the desired language version set by the -lang flag.
1484 // If the -lang flag is not set, this is the zero value, meaning that
1485 // any language version is supported.
1488 // langSupported reports whether language version major.minor is
1489 // supported in a particular package.
1490 func langSupported(major, minor int, pkg *types.Pkg) bool {
1492 // TODO(mdempsky): Set Pkg for local types earlier.
1495 if pkg != localpkg {
1496 // Assume imported packages passed type-checking.
1500 if langWant.major == 0 && langWant.minor == 0 {
1503 return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
1506 // checkLang verifies that the -lang flag holds a valid value, and
1507 // exits if not. It initializes data used by langSupported.
1509 if flag_lang == "" {
1514 langWant, err = parseLang(flag_lang)
1516 log.Fatalf("invalid value %q for -lang: %v", flag_lang, err)
1519 if def := currentLang(); flag_lang != def {
1520 defVers, err := parseLang(def)
1522 log.Fatalf("internal error parsing default lang %q: %v", def, err)
1524 if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) {
1525 log.Fatalf("invalid value %q for -lang: max known version is %q", flag_lang, def)
1530 // parseLang parses a -lang option into a langVer.
1531 func parseLang(s string) (lang, error) {
1532 matches := goVersionRE.FindStringSubmatch(s)
1534 return lang{}, fmt.Errorf(`should be something like "go1.12"`)
1536 major, err := strconv.Atoi(matches[1])
1540 minor, err := strconv.Atoi(matches[2])
1544 return lang{major: major, minor: minor}, nil