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