github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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/bio" 15 "cmd/internal/dwarf" 16 "cmd/internal/obj" 17 "cmd/internal/objabi" 18 "cmd/internal/src" 19 "cmd/internal/sys" 20 "flag" 21 "fmt" 22 "go/build" 23 "io" 24 "io/ioutil" 25 "log" 26 "os" 27 "path" 28 "regexp" 29 "runtime" 30 "strconv" 31 "strings" 32 ) 33 34 var imported_unsafe bool 35 36 var ( 37 buildid string 38 ) 39 40 var ( 41 Debug_append int 42 Debug_closure int 43 Debug_compilelater int 44 debug_dclstack int 45 Debug_panic int 46 Debug_slice int 47 Debug_vlog bool 48 Debug_wb int 49 Debug_pctab string 50 Debug_locationlist int 51 Debug_typecheckinl int 52 Debug_gendwarfinl int 53 Debug_softfloat int 54 ) 55 56 // Debug arguments. 57 // These can be specified with the -d flag, as in "-d nil" 58 // to set the debug_checknil variable. 59 // Multiple options can be comma-separated. 60 // Each option accepts an optional argument, as in "gcprog=2" 61 var debugtab = []struct { 62 name string 63 help string 64 val interface{} // must be *int or *string 65 }{ 66 {"append", "print information about append compilation", &Debug_append}, 67 {"closure", "print information about closure compilation", &Debug_closure}, 68 {"compilelater", "compile functions as late as possible", &Debug_compilelater}, 69 {"disablenil", "disable nil checks", &disable_checknil}, 70 {"dclstack", "run internal dclstack check", &debug_dclstack}, 71 {"gcprog", "print dump of GC programs", &Debug_gcprog}, 72 {"nil", "print information about nil checks", &Debug_checknil}, 73 {"panic", "do not hide any compiler panic", &Debug_panic}, 74 {"slice", "print information about slice compilation", &Debug_slice}, 75 {"typeassert", "print information about type assertion inlining", &Debug_typeassert}, 76 {"wb", "print information about write barriers", &Debug_wb}, 77 {"export", "print export data", &Debug_export}, 78 {"pctab", "print named pc-value table", &Debug_pctab}, 79 {"locationlists", "print information about DWARF location list creation", &Debug_locationlist}, 80 {"typecheckinl", "eager typechecking of inline function bodies", &Debug_typecheckinl}, 81 {"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl}, 82 {"softfloat", "force compiler to emit soft-float code", &Debug_softfloat}, 83 } 84 85 const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>] 86 87 <key> is one of: 88 89 ` 90 91 const debugHelpFooter = ` 92 <value> is key-specific. 93 94 Key "pctab" supports values: 95 "pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata" 96 ` 97 98 func usage() { 99 fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n") 100 objabi.Flagprint(os.Stderr) 101 Exit(2) 102 } 103 104 func hidePanic() { 105 if Debug_panic == 0 && nsavederrors+nerrors > 0 { 106 // If we've already complained about things 107 // in the program, don't bother complaining 108 // about a panic too; let the user clean up 109 // the code and try again. 110 if err := recover(); err != nil { 111 errorexit() 112 } 113 } 114 } 115 116 // supportsDynlink reports whether or not the code generator for the given 117 // architecture supports the -shared and -dynlink flags. 118 func supportsDynlink(arch *sys.Arch) bool { 119 return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X) 120 } 121 122 // timing data for compiler phases 123 var timings Timings 124 var benchfile string 125 126 var nowritebarrierrecCheck *nowritebarrierrecChecker 127 128 // Main parses flags and Go source files specified in the command-line 129 // arguments, type-checks the parsed Go package, compiles functions to machine 130 // code, and finally writes the compiled package definition to disk. 131 func Main(archInit func(*Arch)) { 132 timings.Start("fe", "init") 133 134 defer hidePanic() 135 136 archInit(&thearch) 137 138 Ctxt = obj.Linknew(thearch.LinkArch) 139 Ctxt.DiagFunc = yyerror 140 Ctxt.DiagFlush = flusherrors 141 Ctxt.Bso = bufio.NewWriter(os.Stdout) 142 143 localpkg = types.NewPkg("", "") 144 localpkg.Prefix = "\"\"" 145 146 // We won't know localpkg's height until after import 147 // processing. In the mean time, set to MaxPkgHeight to ensure 148 // height comparisons at least work until then. 149 localpkg.Height = types.MaxPkgHeight 150 151 // pseudo-package, for scoping 152 builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin? 153 builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin 154 155 // pseudo-package, accessed by import "unsafe" 156 unsafepkg = types.NewPkg("unsafe", "unsafe") 157 158 // Pseudo-package that contains the compiler's builtin 159 // declarations for package runtime. These are declared in a 160 // separate package to avoid conflicts with package runtime's 161 // actual declarations, which may differ intentionally but 162 // insignificantly. 163 Runtimepkg = types.NewPkg("go.runtime", "runtime") 164 Runtimepkg.Prefix = "runtime" 165 166 // pseudo-packages used in symbol tables 167 itabpkg = types.NewPkg("go.itab", "go.itab") 168 itabpkg.Prefix = "go.itab" // not go%2eitab 169 170 itablinkpkg = types.NewPkg("go.itablink", "go.itablink") 171 itablinkpkg.Prefix = "go.itablink" // not go%2eitablink 172 173 trackpkg = types.NewPkg("go.track", "go.track") 174 trackpkg.Prefix = "go.track" // not go%2etrack 175 176 // pseudo-package used for map zero values 177 mappkg = types.NewPkg("go.map", "go.map") 178 mappkg.Prefix = "go.map" 179 180 // pseudo-package used for methods with anonymous receivers 181 gopkg = types.NewPkg("go", "") 182 183 Nacl = objabi.GOOS == "nacl" 184 Wasm := objabi.GOARCH == "wasm" 185 186 flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime") 187 flag.BoolVar(&compiling_std, "std", false, "compiling standard library") 188 objabi.Flagcount("%", "debug non-static initializers", &Debug['%']) 189 objabi.Flagcount("B", "disable bounds checking", &Debug['B']) 190 objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C']) // TODO(gri) remove eventually 191 flag.StringVar(&localimport, "D", "", "set relative `path` for local imports") 192 objabi.Flagcount("E", "debug symbol export", &Debug['E']) 193 objabi.Flagfn1("I", "add `directory` to import search path", addidir) 194 objabi.Flagcount("K", "debug missing line numbers", &Debug['K']) 195 objabi.Flagcount("L", "show full file names in error messages", &Debug['L']) 196 objabi.Flagcount("N", "disable optimizations", &Debug['N']) 197 objabi.Flagcount("S", "print assembly listing", &Debug['S']) 198 objabi.AddVersionFlag() // -V 199 objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W']) 200 flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`") 201 flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata") 202 flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency") 203 flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)") 204 flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help") 205 flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols") 206 flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode") 207 flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records") 208 objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e']) 209 objabi.Flagcount("h", "halt on error", &Debug['h']) 210 objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap) 211 objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg) 212 flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`") 213 objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j']) 214 objabi.Flagcount("l", "disable inlining", &Debug['l']) 215 flag.StringVar(&flag_lang, "lang", "", "release to compile for") 216 flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`") 217 objabi.Flagcount("live", "debug liveness analysis", &debuglive) 218 objabi.Flagcount("m", "print optimization decisions", &Debug['m']) 219 if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) { 220 flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer") 221 } 222 flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports") 223 flag.StringVar(&outfile, "o", "", "write output to `file`") 224 flag.StringVar(&myimportpath, "p", "", "set expected package import `path`") 225 flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o") 226 objabi.Flagcount("r", "debug generated wrappers", &Debug['r']) 227 if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) { 228 flag.BoolVar(&flag_race, "race", false, "enable race detector") 229 } 230 objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s']) 231 if enableTrace { 232 flag.BoolVar(&trace, "t", false, "trace type-checking") 233 } 234 flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths") 235 flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity") 236 objabi.Flagcount("w", "debug type checking", &Debug['w']) 237 flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier") 238 var flag_shared bool 239 var flag_dynlink bool 240 if supportsDynlink(thearch.LinkArch.Arch) { 241 flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library") 242 flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries") 243 } 244 flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`") 245 flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`") 246 flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`") 247 var goversion string 248 flag.StringVar(&goversion, "goversion", "", "required version of the runtime") 249 var symabisPath string 250 flag.StringVar(&symabisPath, "symabis", "", "read symbol ABIs from `file`") 251 flag.BoolVar(&allABIs, "allabis", false, "generate ABI wrappers for all symbols (for bootstrap)") 252 flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`") 253 flag.StringVar(&blockprofile, "blockprofile", "", "write block profile to `file`") 254 flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`") 255 flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`") 256 objabi.Flagparse(usage) 257 258 // Record flags that affect the build result. (And don't 259 // record flags that don't, since that would cause spurious 260 // changes in the binary.) 261 recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists") 262 263 Ctxt.Flag_shared = flag_dynlink || flag_shared 264 Ctxt.Flag_dynlink = flag_dynlink 265 Ctxt.Flag_optimize = Debug['N'] == 0 266 267 Ctxt.Debugasm = Debug['S'] 268 Ctxt.Debugvlog = Debug_vlog 269 if flagDWARF { 270 Ctxt.DebugInfo = debuginfo 271 Ctxt.GenAbstractFunc = genAbstractFunc 272 Ctxt.DwFixups = obj.NewDwarfFixupTable(Ctxt) 273 } else { 274 // turn off inline generation if no dwarf at all 275 genDwarfInline = 0 276 Ctxt.Flag_locationlists = false 277 } 278 279 if flag.NArg() < 1 && debugstr != "help" && debugstr != "ssa/help" { 280 usage() 281 } 282 283 if goversion != "" && goversion != runtime.Version() { 284 fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), goversion) 285 Exit(2) 286 } 287 288 checkLang() 289 290 if symabisPath != "" { 291 readSymABIs(symabisPath, myimportpath) 292 } 293 294 thearch.LinkArch.Init(Ctxt) 295 296 if outfile == "" { 297 p := flag.Arg(0) 298 if i := strings.LastIndex(p, "/"); i >= 0 { 299 p = p[i+1:] 300 } 301 if runtime.GOOS == "windows" { 302 if i := strings.LastIndex(p, `\`); i >= 0 { 303 p = p[i+1:] 304 } 305 } 306 if i := strings.LastIndex(p, "."); i >= 0 { 307 p = p[:i] 308 } 309 suffix := ".o" 310 if writearchive { 311 suffix = ".a" 312 } 313 outfile = p + suffix 314 } 315 316 startProfile() 317 318 if flag_race && flag_msan { 319 log.Fatal("cannot use both -race and -msan") 320 } 321 if ispkgin(omit_pkgs) { 322 flag_race = false 323 flag_msan = false 324 } 325 if flag_race { 326 racepkg = types.NewPkg("runtime/race", "") 327 } 328 if flag_msan { 329 msanpkg = types.NewPkg("runtime/msan", "") 330 } 331 if flag_race || flag_msan { 332 instrumenting = true 333 } 334 335 if compiling_runtime && Debug['N'] != 0 { 336 log.Fatal("cannot disable optimizations while compiling runtime") 337 } 338 if nBackendWorkers < 1 { 339 log.Fatalf("-c must be at least 1, got %d", nBackendWorkers) 340 } 341 if nBackendWorkers > 1 && !concurrentBackendAllowed() { 342 log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args) 343 } 344 if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 { 345 log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name) 346 } 347 348 // parse -d argument 349 if debugstr != "" { 350 Split: 351 for _, name := range strings.Split(debugstr, ",") { 352 if name == "" { 353 continue 354 } 355 // display help about the -d option itself and quit 356 if name == "help" { 357 fmt.Print(debugHelpHeader) 358 maxLen := len("ssa/help") 359 for _, t := range debugtab { 360 if len(t.name) > maxLen { 361 maxLen = len(t.name) 362 } 363 } 364 for _, t := range debugtab { 365 fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help) 366 } 367 // ssa options have their own help 368 fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging") 369 fmt.Print(debugHelpFooter) 370 os.Exit(0) 371 } 372 val, valstring, haveInt := 1, "", true 373 if i := strings.IndexAny(name, "=:"); i >= 0 { 374 var err error 375 name, valstring = name[:i], name[i+1:] 376 val, err = strconv.Atoi(valstring) 377 if err != nil { 378 val, haveInt = 1, false 379 } 380 } 381 for _, t := range debugtab { 382 if t.name != name { 383 continue 384 } 385 switch vp := t.val.(type) { 386 case nil: 387 // Ignore 388 case *string: 389 *vp = valstring 390 case *int: 391 if !haveInt { 392 log.Fatalf("invalid debug value %v", name) 393 } 394 *vp = val 395 default: 396 panic("bad debugtab type") 397 } 398 continue Split 399 } 400 // special case for ssa for now 401 if strings.HasPrefix(name, "ssa/") { 402 // expect form ssa/phase/flag 403 // e.g. -d=ssa/generic_cse/time 404 // _ in phase name also matches space 405 phase := name[4:] 406 flag := "debug" // default flag is debug 407 if i := strings.Index(phase, "/"); i >= 0 { 408 flag = phase[i+1:] 409 phase = phase[:i] 410 } 411 err := ssa.PhaseOption(phase, flag, val, valstring) 412 if err != "" { 413 log.Fatalf(err) 414 } 415 continue Split 416 } 417 log.Fatalf("unknown debug key -d %s\n", name) 418 } 419 } 420 421 // set via a -d flag 422 Ctxt.Debugpcln = Debug_pctab 423 if flagDWARF { 424 dwarf.EnableLogging(Debug_gendwarfinl != 0) 425 } 426 427 if Debug_softfloat != 0 { 428 thearch.SoftFloat = true 429 } 430 431 // enable inlining. for now: 432 // default: inlining on. (debug['l'] == 1) 433 // -l: inlining off (debug['l'] == 0) 434 // -l=2, -l=3: inlining on again, with extra debugging (debug['l'] > 1) 435 if Debug['l'] <= 1 { 436 Debug['l'] = 1 - Debug['l'] 437 } 438 439 ssaDump = os.Getenv("GOSSAFUNC") 440 if ssaDump != "" { 441 if strings.HasSuffix(ssaDump, "+") { 442 ssaDump = ssaDump[:len(ssaDump)-1] 443 ssaDumpStdout = true 444 } 445 spl := strings.Split(ssaDump, ":") 446 if len(spl) > 1 { 447 ssaDump = spl[0] 448 ssaDumpCFG = spl[1] 449 } 450 } 451 452 trackScopes = flagDWARF 453 454 Widthptr = thearch.LinkArch.PtrSize 455 Widthreg = thearch.LinkArch.RegSize 456 457 // initialize types package 458 // (we need to do this to break dependencies that otherwise 459 // would lead to import cycles) 460 types.Widthptr = Widthptr 461 types.Dowidth = dowidth 462 types.Fatalf = Fatalf 463 types.Sconv = func(s *types.Sym, flag, mode int) string { 464 return sconv(s, FmtFlag(flag), fmtMode(mode)) 465 } 466 types.Tconv = func(t *types.Type, flag, mode, depth int) string { 467 return tconv(t, FmtFlag(flag), fmtMode(mode), depth) 468 } 469 types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) { 470 symFormat(sym, s, verb, fmtMode(mode)) 471 } 472 types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) { 473 typeFormat(t, s, verb, fmtMode(mode)) 474 } 475 types.TypeLinkSym = func(t *types.Type) *obj.LSym { 476 return typenamesym(t).Linksym() 477 } 478 types.FmtLeft = int(FmtLeft) 479 types.FmtUnsigned = int(FmtUnsigned) 480 types.FErr = FErr 481 types.Ctxt = Ctxt 482 483 initUniverse() 484 485 dclcontext = PEXTERN 486 nerrors = 0 487 488 autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0) 489 490 timings.Start("fe", "loadsys") 491 loadsys() 492 493 timings.Start("fe", "parse") 494 lines := parseFiles(flag.Args()) 495 timings.Stop() 496 timings.AddEvent(int64(lines), "lines") 497 498 finishUniverse() 499 500 typecheckok = true 501 502 // Process top-level declarations in phases. 503 504 // Phase 1: const, type, and names and types of funcs. 505 // This will gather all the information about types 506 // and methods but doesn't depend on any of it. 507 // 508 // We also defer type alias declarations until phase 2 509 // to avoid cycles like #18640. 510 // TODO(gri) Remove this again once we have a fix for #25838. 511 defercheckwidth() 512 513 // Don't use range--typecheck can add closures to xtop. 514 timings.Start("fe", "typecheck", "top1") 515 for i := 0; i < len(xtop); i++ { 516 n := xtop[i] 517 if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) { 518 xtop[i] = typecheck(n, ctxStmt) 519 } 520 } 521 522 // Phase 2: Variable assignments. 523 // To check interface assignments, depends on phase 1. 524 525 // Don't use range--typecheck can add closures to xtop. 526 timings.Start("fe", "typecheck", "top2") 527 for i := 0; i < len(xtop); i++ { 528 n := xtop[i] 529 if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias { 530 xtop[i] = typecheck(n, ctxStmt) 531 } 532 } 533 resumecheckwidth() 534 535 // Phase 3: Type check function bodies. 536 // Don't use range--typecheck can add closures to xtop. 537 timings.Start("fe", "typecheck", "func") 538 var fcount int64 539 for i := 0; i < len(xtop); i++ { 540 n := xtop[i] 541 if op := n.Op; op == ODCLFUNC || op == OCLOSURE { 542 Curfn = n 543 decldepth = 1 544 saveerrors() 545 typecheckslice(Curfn.Nbody.Slice(), ctxStmt) 546 checkreturn(Curfn) 547 if nerrors != 0 { 548 Curfn.Nbody.Set(nil) // type errors; do not compile 549 } 550 // Now that we've checked whether n terminates, 551 // we can eliminate some obviously dead code. 552 deadcode(Curfn) 553 fcount++ 554 } 555 } 556 // With all types ckecked, it's now safe to verify map keys. One single 557 // check past phase 9 isn't sufficient, as we may exit with other errors 558 // before then, thus skipping map key errors. 559 checkMapKeys() 560 timings.AddEvent(fcount, "funcs") 561 562 if nsavederrors+nerrors != 0 { 563 errorexit() 564 } 565 566 // Phase 4: Decide how to capture closed variables. 567 // This needs to run before escape analysis, 568 // because variables captured by value do not escape. 569 timings.Start("fe", "capturevars") 570 for _, n := range xtop { 571 if n.Op == ODCLFUNC && n.Func.Closure != nil { 572 Curfn = n 573 capturevars(n) 574 } 575 } 576 capturevarscomplete = true 577 578 Curfn = nil 579 580 if nsavederrors+nerrors != 0 { 581 errorexit() 582 } 583 584 // Phase 5: Inlining 585 timings.Start("fe", "inlining") 586 if Debug_typecheckinl != 0 { 587 // Typecheck imported function bodies if debug['l'] > 1, 588 // otherwise lazily when used or re-exported. 589 for _, n := range importlist { 590 if n.Func.Inl != nil { 591 saveerrors() 592 typecheckinl(n) 593 } 594 } 595 596 if nsavederrors+nerrors != 0 { 597 errorexit() 598 } 599 } 600 601 if Debug['l'] != 0 { 602 // Find functions that can be inlined and clone them before walk expands them. 603 visitBottomUp(xtop, func(list []*Node, recursive bool) { 604 for _, n := range list { 605 if !recursive { 606 caninl(n) 607 } else { 608 if Debug['m'] > 1 { 609 fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname) 610 } 611 } 612 inlcalls(n) 613 } 614 }) 615 } 616 617 // Phase 6: Escape analysis. 618 // Required for moving heap allocations onto stack, 619 // which in turn is required by the closure implementation, 620 // which stores the addresses of stack variables into the closure. 621 // If the closure does not escape, it needs to be on the stack 622 // or else the stack copier will not update it. 623 // Large values are also moved off stack in escape analysis; 624 // because large values may contain pointers, it must happen early. 625 timings.Start("fe", "escapes") 626 escapes(xtop) 627 628 // Collect information for go:nowritebarrierrec 629 // checking. This must happen before transformclosure. 630 // We'll do the final check after write barriers are 631 // inserted. 632 if compiling_runtime { 633 nowritebarrierrecCheck = newNowritebarrierrecChecker() 634 } 635 636 // Phase 7: Transform closure bodies to properly reference captured variables. 637 // This needs to happen before walk, because closures must be transformed 638 // before walk reaches a call of a closure. 639 timings.Start("fe", "xclosures") 640 for _, n := range xtop { 641 if n.Op == ODCLFUNC && n.Func.Closure != nil { 642 Curfn = n 643 transformclosure(n) 644 } 645 } 646 647 // Prepare for SSA compilation. 648 // This must be before peekitabs, because peekitabs 649 // can trigger function compilation. 650 initssaconfig() 651 652 // Just before compilation, compile itabs found on 653 // the right side of OCONVIFACE so that methods 654 // can be de-virtualized during compilation. 655 Curfn = nil 656 peekitabs() 657 658 // Phase 8: Compile top level functions. 659 // Don't use range--walk can add functions to xtop. 660 timings.Start("be", "compilefuncs") 661 fcount = 0 662 for i := 0; i < len(xtop); i++ { 663 n := xtop[i] 664 if n.Op == ODCLFUNC { 665 funccompile(n) 666 fcount++ 667 } 668 } 669 timings.AddEvent(fcount, "funcs") 670 671 if nsavederrors+nerrors == 0 { 672 fninit(xtop) 673 } 674 675 compileFunctions() 676 677 if nowritebarrierrecCheck != nil { 678 // Write barriers are now known. Check the 679 // call graph. 680 nowritebarrierrecCheck.check() 681 nowritebarrierrecCheck = nil 682 } 683 684 // Finalize DWARF inline routine DIEs, then explicitly turn off 685 // DWARF inlining gen so as to avoid problems with generated 686 // method wrappers. 687 if Ctxt.DwFixups != nil { 688 Ctxt.DwFixups.Finalize(myimportpath, Debug_gendwarfinl != 0) 689 Ctxt.DwFixups = nil 690 genDwarfInline = 0 691 } 692 693 // Phase 9: Check external declarations. 694 timings.Start("be", "externaldcls") 695 for i, n := range externdcl { 696 if n.Op == ONAME { 697 externdcl[i] = typecheck(externdcl[i], ctxExpr) 698 } 699 } 700 // Check the map keys again, since we typechecked the external 701 // declarations. 702 checkMapKeys() 703 704 if nerrors+nsavederrors != 0 { 705 errorexit() 706 } 707 708 // Write object data to disk. 709 timings.Start("be", "dumpobj") 710 dumpobj() 711 if asmhdr != "" { 712 dumpasmhdr() 713 } 714 715 // Check whether any of the functions we have compiled have gigantic stack frames. 716 obj.SortSlice(largeStackFrames, func(i, j int) bool { 717 return largeStackFrames[i].pos.Before(largeStackFrames[j].pos) 718 }) 719 for _, large := range largeStackFrames { 720 if large.callee != 0 { 721 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) 722 } else { 723 yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20) 724 } 725 } 726 727 if len(compilequeue) != 0 { 728 Fatalf("%d uncompiled functions", len(compilequeue)) 729 } 730 731 if nerrors+nsavederrors != 0 { 732 errorexit() 733 } 734 735 flusherrors() 736 timings.Stop() 737 738 if benchfile != "" { 739 if err := writebench(benchfile); err != nil { 740 log.Fatalf("cannot write benchmark data: %v", err) 741 } 742 } 743 } 744 745 func writebench(filename string) error { 746 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) 747 if err != nil { 748 return err 749 } 750 751 var buf bytes.Buffer 752 fmt.Fprintln(&buf, "commit:", objabi.Version) 753 fmt.Fprintln(&buf, "goos:", runtime.GOOS) 754 fmt.Fprintln(&buf, "goarch:", runtime.GOARCH) 755 timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":") 756 757 n, err := f.Write(buf.Bytes()) 758 if err != nil { 759 return err 760 } 761 if n != buf.Len() { 762 panic("bad writer") 763 } 764 765 return f.Close() 766 } 767 768 var ( 769 importMap = map[string]string{} 770 packageFile map[string]string // nil means not in use 771 ) 772 773 func addImportMap(s string) { 774 if strings.Count(s, "=") != 1 { 775 log.Fatal("-importmap argument must be of the form source=actual") 776 } 777 i := strings.Index(s, "=") 778 source, actual := s[:i], s[i+1:] 779 if source == "" || actual == "" { 780 log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty") 781 } 782 importMap[source] = actual 783 } 784 785 func readImportCfg(file string) { 786 packageFile = map[string]string{} 787 data, err := ioutil.ReadFile(file) 788 if err != nil { 789 log.Fatalf("-importcfg: %v", err) 790 } 791 792 for lineNum, line := range strings.Split(string(data), "\n") { 793 lineNum++ // 1-based 794 line = strings.TrimSpace(line) 795 if line == "" || strings.HasPrefix(line, "#") { 796 continue 797 } 798 799 var verb, args string 800 if i := strings.Index(line, " "); i < 0 { 801 verb = line 802 } else { 803 verb, args = line[:i], strings.TrimSpace(line[i+1:]) 804 } 805 var before, after string 806 if i := strings.Index(args, "="); i >= 0 { 807 before, after = args[:i], args[i+1:] 808 } 809 switch verb { 810 default: 811 log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb) 812 case "importmap": 813 if before == "" || after == "" { 814 log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum) 815 } 816 importMap[before] = after 817 case "packagefile": 818 if before == "" || after == "" { 819 log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum) 820 } 821 packageFile[before] = after 822 } 823 } 824 } 825 826 // symabiDefs and symabiRefs record the defined and referenced ABIs of 827 // symbols required by non-Go code. These are keyed by link symbol 828 // name, where the local package prefix is always `"".` 829 var symabiDefs, symabiRefs map[string]obj.ABI 830 831 // allABIs indicates that all symbol definitions should have ABI 832 // wrappers. This is used during toolchain bootstrapping to avoid 833 // having to find cross-package references. 834 var allABIs bool 835 836 // readSymABIs reads a symabis file that specifies definitions and 837 // references of text symbols by ABI. 838 // 839 // The symabis format is a set of lines, where each line is a sequence 840 // of whitespace-separated fields. The first field is a verb and is 841 // either "def" for defining a symbol ABI or "ref" for referencing a 842 // symbol using an ABI. For both "def" and "ref", the second field is 843 // the symbol name and the third field is the ABI name, as one of the 844 // named cmd/internal/obj.ABI constants. 845 func readSymABIs(file, myimportpath string) { 846 data, err := ioutil.ReadFile(file) 847 if err != nil { 848 log.Fatalf("-symabis: %v", err) 849 } 850 851 symabiDefs = make(map[string]obj.ABI) 852 symabiRefs = make(map[string]obj.ABI) 853 854 localPrefix := "" 855 if myimportpath != "" { 856 // Symbols in this package may be written either as 857 // "".X or with the package's import path already in 858 // the symbol. 859 localPrefix = objabi.PathToPrefix(myimportpath) + "." 860 } 861 862 for lineNum, line := range strings.Split(string(data), "\n") { 863 lineNum++ // 1-based 864 line = strings.TrimSpace(line) 865 if line == "" || strings.HasPrefix(line, "#") { 866 continue 867 } 868 869 parts := strings.Fields(line) 870 switch parts[0] { 871 case "def", "ref": 872 // Parse line. 873 if len(parts) != 3 { 874 log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0]) 875 } 876 sym, abi := parts[1], parts[2] 877 if abi != "ABI0" { // Only supported external ABI right now 878 log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi) 879 } 880 881 // If the symbol is already prefixed with 882 // myimportpath, rewrite it to start with "" 883 // so it matches the compiler's internal 884 // symbol names. 885 if localPrefix != "" && strings.HasPrefix(sym, localPrefix) { 886 sym = `"".` + sym[len(localPrefix):] 887 } 888 889 // Record for later. 890 if parts[0] == "def" { 891 symabiDefs[sym] = obj.ABI0 892 } else { 893 symabiRefs[sym] = obj.ABI0 894 } 895 default: 896 log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0]) 897 } 898 } 899 } 900 901 func saveerrors() { 902 nsavederrors += nerrors 903 nerrors = 0 904 } 905 906 func arsize(b *bufio.Reader, name string) int { 907 var buf [ArhdrSize]byte 908 if _, err := io.ReadFull(b, buf[:]); err != nil { 909 return -1 910 } 911 aname := strings.Trim(string(buf[0:16]), " ") 912 if !strings.HasPrefix(aname, name) { 913 return -1 914 } 915 asize := strings.Trim(string(buf[48:58]), " ") 916 i, _ := strconv.Atoi(asize) 917 return i 918 } 919 920 var idirs []string 921 922 func addidir(dir string) { 923 if dir != "" { 924 idirs = append(idirs, dir) 925 } 926 } 927 928 func isDriveLetter(b byte) bool { 929 return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' 930 } 931 932 // is this path a local name? begins with ./ or ../ or / 933 func islocalname(name string) bool { 934 return strings.HasPrefix(name, "/") || 935 runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' || 936 strings.HasPrefix(name, "./") || name == "." || 937 strings.HasPrefix(name, "../") || name == ".." 938 } 939 940 func findpkg(name string) (file string, ok bool) { 941 if islocalname(name) { 942 if nolocalimports { 943 return "", false 944 } 945 946 if packageFile != nil { 947 file, ok = packageFile[name] 948 return file, ok 949 } 950 951 // try .a before .6. important for building libraries: 952 // if there is an array.6 in the array.a library, 953 // want to find all of array.a, not just array.6. 954 file = fmt.Sprintf("%s.a", name) 955 if _, err := os.Stat(file); err == nil { 956 return file, true 957 } 958 file = fmt.Sprintf("%s.o", name) 959 if _, err := os.Stat(file); err == nil { 960 return file, true 961 } 962 return "", false 963 } 964 965 // local imports should be canonicalized already. 966 // don't want to see "encoding/../encoding/base64" 967 // as different from "encoding/base64". 968 if q := path.Clean(name); q != name { 969 yyerror("non-canonical import path %q (should be %q)", name, q) 970 return "", false 971 } 972 973 if packageFile != nil { 974 file, ok = packageFile[name] 975 return file, ok 976 } 977 978 for _, dir := range idirs { 979 file = fmt.Sprintf("%s/%s.a", dir, name) 980 if _, err := os.Stat(file); err == nil { 981 return file, true 982 } 983 file = fmt.Sprintf("%s/%s.o", dir, name) 984 if _, err := os.Stat(file); err == nil { 985 return file, true 986 } 987 } 988 989 if objabi.GOROOT != "" { 990 suffix := "" 991 suffixsep := "" 992 if flag_installsuffix != "" { 993 suffixsep = "_" 994 suffix = flag_installsuffix 995 } else if flag_race { 996 suffixsep = "_" 997 suffix = "race" 998 } else if flag_msan { 999 suffixsep = "_" 1000 suffix = "msan" 1001 } 1002 1003 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name) 1004 if _, err := os.Stat(file); err == nil { 1005 return file, true 1006 } 1007 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name) 1008 if _, err := os.Stat(file); err == nil { 1009 return file, true 1010 } 1011 } 1012 1013 return "", false 1014 } 1015 1016 // loadsys loads the definitions for the low-level runtime functions, 1017 // so that the compiler can generate calls to them, 1018 // but does not make them visible to user code. 1019 func loadsys() { 1020 types.Block = 1 1021 1022 inimport = true 1023 typecheckok = true 1024 defercheckwidth() 1025 1026 typs := runtimeTypes() 1027 for _, d := range runtimeDecls { 1028 sym := Runtimepkg.Lookup(d.name) 1029 typ := typs[d.typ] 1030 switch d.tag { 1031 case funcTag: 1032 importfunc(Runtimepkg, src.NoXPos, sym, typ) 1033 case varTag: 1034 importvar(Runtimepkg, src.NoXPos, sym, typ) 1035 default: 1036 Fatalf("unhandled declaration tag %v", d.tag) 1037 } 1038 } 1039 1040 typecheckok = false 1041 resumecheckwidth() 1042 inimport = false 1043 } 1044 1045 // myheight tracks the local package's height based on packages 1046 // imported so far. 1047 var myheight int 1048 1049 func importfile(f *Val) *types.Pkg { 1050 path_, ok := f.U.(string) 1051 if !ok { 1052 yyerror("import path must be a string") 1053 return nil 1054 } 1055 1056 if len(path_) == 0 { 1057 yyerror("import path is empty") 1058 return nil 1059 } 1060 1061 if isbadimport(path_, false) { 1062 return nil 1063 } 1064 1065 // The package name main is no longer reserved, 1066 // but we reserve the import path "main" to identify 1067 // the main package, just as we reserve the import 1068 // path "math" to identify the standard math package. 1069 if path_ == "main" { 1070 yyerror("cannot import \"main\"") 1071 errorexit() 1072 } 1073 1074 if myimportpath != "" && path_ == myimportpath { 1075 yyerror("import %q while compiling that package (import cycle)", path_) 1076 errorexit() 1077 } 1078 1079 if mapped, ok := importMap[path_]; ok { 1080 path_ = mapped 1081 } 1082 1083 if path_ == "unsafe" { 1084 imported_unsafe = true 1085 return unsafepkg 1086 } 1087 1088 if islocalname(path_) { 1089 if path_[0] == '/' { 1090 yyerror("import path cannot be absolute path") 1091 return nil 1092 } 1093 1094 prefix := Ctxt.Pathname 1095 if localimport != "" { 1096 prefix = localimport 1097 } 1098 path_ = path.Join(prefix, path_) 1099 1100 if isbadimport(path_, true) { 1101 return nil 1102 } 1103 } 1104 1105 file, found := findpkg(path_) 1106 if !found { 1107 yyerror("can't find import: %q", path_) 1108 errorexit() 1109 } 1110 1111 importpkg := types.NewPkg(path_, "") 1112 if importpkg.Imported { 1113 return importpkg 1114 } 1115 1116 importpkg.Imported = true 1117 1118 imp, err := bio.Open(file) 1119 if err != nil { 1120 yyerror("can't open import: %q: %v", path_, err) 1121 errorexit() 1122 } 1123 defer imp.Close() 1124 1125 // check object header 1126 p, err := imp.ReadString('\n') 1127 if err != nil { 1128 yyerror("import %s: reading input: %v", file, err) 1129 errorexit() 1130 } 1131 1132 if p == "!<arch>\n" { // package archive 1133 // package export block should be first 1134 sz := arsize(imp.Reader, "__.PKGDEF") 1135 if sz <= 0 { 1136 yyerror("import %s: not a package file", file) 1137 errorexit() 1138 } 1139 p, err = imp.ReadString('\n') 1140 if err != nil { 1141 yyerror("import %s: reading input: %v", file, err) 1142 errorexit() 1143 } 1144 } 1145 1146 if !strings.HasPrefix(p, "go object ") { 1147 yyerror("import %s: not a go object file: %s", file, p) 1148 errorexit() 1149 } 1150 q := fmt.Sprintf("%s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring()) 1151 if p[10:] != q { 1152 yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q) 1153 errorexit() 1154 } 1155 1156 // process header lines 1157 for { 1158 p, err = imp.ReadString('\n') 1159 if err != nil { 1160 yyerror("import %s: reading input: %v", file, err) 1161 errorexit() 1162 } 1163 if p == "\n" { 1164 break // header ends with blank line 1165 } 1166 } 1167 1168 // assume files move (get installed) so don't record the full path 1169 if packageFile != nil { 1170 // If using a packageFile map, assume path_ can be recorded directly. 1171 Ctxt.AddImport(path_) 1172 } else { 1173 // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a". 1174 Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):]) 1175 } 1176 1177 // In the importfile, if we find: 1178 // $$\n (textual format): not supported anymore 1179 // $$B\n (binary format) : import directly, then feed the lexer a dummy statement 1180 1181 // look for $$ 1182 var c byte 1183 for { 1184 c, err = imp.ReadByte() 1185 if err != nil { 1186 break 1187 } 1188 if c == '$' { 1189 c, err = imp.ReadByte() 1190 if c == '$' || err != nil { 1191 break 1192 } 1193 } 1194 } 1195 1196 // get character after $$ 1197 if err == nil { 1198 c, _ = imp.ReadByte() 1199 } 1200 1201 switch c { 1202 case '\n': 1203 yyerror("cannot import %s: old export format no longer supported (recompile library)", path_) 1204 return nil 1205 1206 case 'B': 1207 if Debug_export != 0 { 1208 fmt.Printf("importing %s (%s)\n", path_, file) 1209 } 1210 imp.ReadByte() // skip \n after $$B 1211 1212 c, err = imp.ReadByte() 1213 if err != nil { 1214 yyerror("import %s: reading input: %v", file, err) 1215 errorexit() 1216 } 1217 1218 // Indexed format is distinguished by an 'i' byte, 1219 // whereas previous export formats started with 'c', 'd', or 'v'. 1220 if c != 'i' { 1221 yyerror("import %s: unexpected package format byte: %v", file, c) 1222 errorexit() 1223 } 1224 iimport(importpkg, imp) 1225 1226 default: 1227 yyerror("no import in %q", path_) 1228 errorexit() 1229 } 1230 1231 if importpkg.Height >= myheight { 1232 myheight = importpkg.Height + 1 1233 } 1234 1235 return importpkg 1236 } 1237 1238 func pkgnotused(lineno src.XPos, path string, name string) { 1239 // If the package was imported with a name other than the final 1240 // import path element, show it explicitly in the error message. 1241 // Note that this handles both renamed imports and imports of 1242 // packages containing unconventional package declarations. 1243 // Note that this uses / always, even on Windows, because Go import 1244 // paths always use forward slashes. 1245 elem := path 1246 if i := strings.LastIndex(elem, "/"); i >= 0 { 1247 elem = elem[i+1:] 1248 } 1249 if name == "" || elem == name { 1250 yyerrorl(lineno, "imported and not used: %q", path) 1251 } else { 1252 yyerrorl(lineno, "imported and not used: %q as %s", path, name) 1253 } 1254 } 1255 1256 func mkpackage(pkgname string) { 1257 if localpkg.Name == "" { 1258 if pkgname == "_" { 1259 yyerror("invalid package name _") 1260 } 1261 localpkg.Name = pkgname 1262 } else { 1263 if pkgname != localpkg.Name { 1264 yyerror("package %s; expected %s", pkgname, localpkg.Name) 1265 } 1266 } 1267 } 1268 1269 func clearImports() { 1270 type importedPkg struct { 1271 pos src.XPos 1272 path string 1273 name string 1274 } 1275 var unused []importedPkg 1276 1277 for _, s := range localpkg.Syms { 1278 n := asNode(s.Def) 1279 if n == nil { 1280 continue 1281 } 1282 if n.Op == OPACK { 1283 // throw away top-level package name left over 1284 // from previous file. 1285 // leave s->block set to cause redeclaration 1286 // errors if a conflicting top-level name is 1287 // introduced by a different file. 1288 if !n.Name.Used() && nsyntaxerrors == 0 { 1289 unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name}) 1290 } 1291 s.Def = nil 1292 continue 1293 } 1294 if IsAlias(s) { 1295 // throw away top-level name left over 1296 // from previous import . "x" 1297 if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 { 1298 unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""}) 1299 n.Name.Pack.Name.SetUsed(true) 1300 } 1301 s.Def = nil 1302 continue 1303 } 1304 } 1305 1306 obj.SortSlice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) }) 1307 for _, pkg := range unused { 1308 pkgnotused(pkg.pos, pkg.path, pkg.name) 1309 } 1310 } 1311 1312 func IsAlias(sym *types.Sym) bool { 1313 return sym.Def != nil && asNode(sym.Def).Sym != sym 1314 } 1315 1316 // By default, assume any debug flags are incompatible with concurrent compilation. 1317 // A few are safe and potentially in common use for normal compiles, though; mark them as such here. 1318 var concurrentFlagOK = [256]bool{ 1319 'B': true, // disabled bounds checking 1320 'C': true, // disable printing of columns in error messages 1321 'e': true, // no limit on errors; errors all come from non-concurrent code 1322 'I': true, // add `directory` to import search path 1323 'N': true, // disable optimizations 1324 'l': true, // disable inlining 1325 'w': true, // all printing happens before compilation 1326 'W': true, // all printing happens before compilation 1327 'S': true, // printing disassembly happens at the end (but see concurrentBackendAllowed below) 1328 } 1329 1330 func concurrentBackendAllowed() bool { 1331 for i, x := range Debug { 1332 if x != 0 && !concurrentFlagOK[i] { 1333 return false 1334 } 1335 } 1336 // Debug['S'] by itself is ok, because all printing occurs 1337 // while writing the object file, and that is non-concurrent. 1338 // Adding Debug_vlog, however, causes Debug['S'] to also print 1339 // while flushing the plist, which happens concurrently. 1340 if Debug_vlog || debugstr != "" || debuglive > 0 { 1341 return false 1342 } 1343 // TODO: Test and delete this condition. 1344 if objabi.Fieldtrack_enabled != 0 { 1345 return false 1346 } 1347 // TODO: fix races and enable the following flags 1348 if Ctxt.Flag_shared || Ctxt.Flag_dynlink || flag_race { 1349 return false 1350 } 1351 return true 1352 } 1353 1354 // recordFlags records the specified command-line flags to be placed 1355 // in the DWARF info. 1356 func recordFlags(flags ...string) { 1357 if myimportpath == "" { 1358 // We can't record the flags if we don't know what the 1359 // package name is. 1360 return 1361 } 1362 1363 type BoolFlag interface { 1364 IsBoolFlag() bool 1365 } 1366 type CountFlag interface { 1367 IsCountFlag() bool 1368 } 1369 var cmd bytes.Buffer 1370 for _, name := range flags { 1371 f := flag.Lookup(name) 1372 if f == nil { 1373 continue 1374 } 1375 getter := f.Value.(flag.Getter) 1376 if getter.String() == f.DefValue { 1377 // Flag has default value, so omit it. 1378 continue 1379 } 1380 if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() { 1381 val, ok := getter.Get().(bool) 1382 if ok && val { 1383 fmt.Fprintf(&cmd, " -%s", f.Name) 1384 continue 1385 } 1386 } 1387 if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() { 1388 val, ok := getter.Get().(int) 1389 if ok && val == 1 { 1390 fmt.Fprintf(&cmd, " -%s", f.Name) 1391 continue 1392 } 1393 } 1394 fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get()) 1395 } 1396 1397 if cmd.Len() == 0 { 1398 return 1399 } 1400 s := Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + myimportpath) 1401 s.Type = objabi.SDWARFINFO 1402 // Sometimes (for example when building tests) we can link 1403 // together two package main archives. So allow dups. 1404 s.Set(obj.AttrDuplicateOK, true) 1405 Ctxt.Data = append(Ctxt.Data, s) 1406 s.P = cmd.Bytes()[1:] 1407 } 1408 1409 // flag_lang is the language version we are compiling for, set by the -lang flag. 1410 var flag_lang string 1411 1412 // currentLang returns the current language version. 1413 func currentLang() string { 1414 tags := build.Default.ReleaseTags 1415 return tags[len(tags)-1] 1416 } 1417 1418 // goVersionRE is a regular expression that matches the valid 1419 // arguments to the -lang flag. 1420 var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) 1421 1422 // A lang is a language version broken into major and minor numbers. 1423 type lang struct { 1424 major, minor int 1425 } 1426 1427 // langWant is the desired language version set by the -lang flag. 1428 // If the -lang flag is not set, this is the zero value, meaning that 1429 // any language version is supported. 1430 var langWant lang 1431 1432 // langSupported reports whether language version major.minor is supported. 1433 func langSupported(major, minor int) bool { 1434 if langWant.major == 0 && langWant.minor == 0 { 1435 return true 1436 } 1437 return langWant.major > major || (langWant.major == major && langWant.minor >= minor) 1438 } 1439 1440 // checkLang verifies that the -lang flag holds a valid value, and 1441 // exits if not. It initializes data used by langSupported. 1442 func checkLang() { 1443 if flag_lang == "" { 1444 return 1445 } 1446 1447 var err error 1448 langWant, err = parseLang(flag_lang) 1449 if err != nil { 1450 log.Fatalf("invalid value %q for -lang: %v", flag_lang, err) 1451 } 1452 1453 if def := currentLang(); flag_lang != def { 1454 defVers, err := parseLang(def) 1455 if err != nil { 1456 log.Fatalf("internal error parsing default lang %q: %v", def, err) 1457 } 1458 if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) { 1459 log.Fatalf("invalid value %q for -lang: max known version is %q", flag_lang, def) 1460 } 1461 } 1462 } 1463 1464 // parseLang parses a -lang option into a langVer. 1465 func parseLang(s string) (lang, error) { 1466 matches := goVersionRE.FindStringSubmatch(s) 1467 if matches == nil { 1468 return lang{}, fmt.Errorf(`should be something like "go1.12"`) 1469 } 1470 major, err := strconv.Atoi(matches[1]) 1471 if err != nil { 1472 return lang{}, err 1473 } 1474 minor, err := strconv.Atoi(matches[2]) 1475 if err != nil { 1476 return lang{}, err 1477 } 1478 return lang{major: major, minor: minor}, nil 1479 }