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