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