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