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