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