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