Source file src/pkg/cmd/compile/internal/gc/main.go
1
2
3
4
5
6
7 package gc
8
9 import (
10 "bufio"
11 "bytes"
12 "cmd/compile/internal/ssa"
13 "cmd/compile/internal/types"
14 "cmd/internal/bio"
15 "cmd/internal/dwarf"
16 "cmd/internal/obj"
17 "cmd/internal/objabi"
18 "cmd/internal/src"
19 "cmd/internal/sys"
20 "flag"
21 "fmt"
22 "internal/goversion"
23 "io"
24 "io/ioutil"
25 "log"
26 "os"
27 "path"
28 "regexp"
29 "runtime"
30 "sort"
31 "strconv"
32 "strings"
33 )
34
35 var imported_unsafe bool
36
37 var (
38 buildid string
39 )
40
41 var (
42 Debug_append int
43 Debug_closure int
44 Debug_compilelater int
45 debug_dclstack int
46 Debug_panic int
47 Debug_slice int
48 Debug_vlog bool
49 Debug_wb int
50 Debug_pctab string
51 Debug_locationlist int
52 Debug_typecheckinl int
53 Debug_gendwarfinl int
54 Debug_softfloat int
55 )
56
57
58
59
60
61
62 var debugtab = []struct {
63 name string
64 help string
65 val interface{}
66 }{
67 {"append", "print information about append compilation", &Debug_append},
68 {"closure", "print information about closure compilation", &Debug_closure},
69 {"compilelater", "compile functions as late as possible", &Debug_compilelater},
70 {"disablenil", "disable nil checks", &disable_checknil},
71 {"dclstack", "run internal dclstack check", &debug_dclstack},
72 {"gcprog", "print dump of GC programs", &Debug_gcprog},
73 {"nil", "print information about nil checks", &Debug_checknil},
74 {"panic", "do not hide any compiler panic", &Debug_panic},
75 {"slice", "print information about slice compilation", &Debug_slice},
76 {"typeassert", "print information about type assertion inlining", &Debug_typeassert},
77 {"wb", "print information about write barriers", &Debug_wb},
78 {"export", "print export data", &Debug_export},
79 {"pctab", "print named pc-value table", &Debug_pctab},
80 {"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
81 {"typecheckinl", "eager typechecking of inline function bodies", &Debug_typecheckinl},
82 {"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl},
83 {"softfloat", "force compiler to emit soft-float code", &Debug_softfloat},
84 }
85
86 const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
87
88 <key> is one of:
89
90 `
91
92 const debugHelpFooter = `
93 <value> is key-specific.
94
95 Key "pctab" supports values:
96 "pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
97 `
98
99 func usage() {
100 fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n")
101 objabi.Flagprint(os.Stderr)
102 Exit(2)
103 }
104
105 func hidePanic() {
106 if Debug_panic == 0 && nsavederrors+nerrors > 0 {
107
108
109
110
111 if err := recover(); err != nil {
112 errorexit()
113 }
114 }
115 }
116
117
118
119 func supportsDynlink(arch *sys.Arch) bool {
120 return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
121 }
122
123
124 var timings Timings
125 var benchfile string
126
127 var nowritebarrierrecCheck *nowritebarrierrecChecker
128
129
130
131
132 func Main(archInit func(*Arch)) {
133 timings.Start("fe", "init")
134
135 defer hidePanic()
136
137 archInit(&thearch)
138
139 Ctxt = obj.Linknew(thearch.LinkArch)
140 Ctxt.DiagFunc = yyerror
141 Ctxt.DiagFlush = flusherrors
142 Ctxt.Bso = bufio.NewWriter(os.Stdout)
143
144
145
146
147
148 Ctxt.UseBASEntries = Ctxt.Headtype != objabi.Hdarwin
149
150 localpkg = types.NewPkg("", "")
151 localpkg.Prefix = "\"\""
152
153
154
155
156 localpkg.Height = types.MaxPkgHeight
157
158
159 builtinpkg = types.NewPkg("go.builtin", "")
160 builtinpkg.Prefix = "go.builtin"
161
162
163 unsafepkg = types.NewPkg("unsafe", "unsafe")
164
165
166
167
168
169
170 Runtimepkg = types.NewPkg("go.runtime", "runtime")
171 Runtimepkg.Prefix = "runtime"
172
173
174 itabpkg = types.NewPkg("go.itab", "go.itab")
175 itabpkg.Prefix = "go.itab"
176
177 itablinkpkg = types.NewPkg("go.itablink", "go.itablink")
178 itablinkpkg.Prefix = "go.itablink"
179
180 trackpkg = types.NewPkg("go.track", "go.track")
181 trackpkg.Prefix = "go.track"
182
183
184 mappkg = types.NewPkg("go.map", "go.map")
185 mappkg.Prefix = "go.map"
186
187
188 gopkg = types.NewPkg("go", "")
189
190 Nacl = objabi.GOOS == "nacl"
191 Wasm := objabi.GOARCH == "wasm"
192
193
194
195 smallFrames := false
196
197 flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
198 flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
199 objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
200 objabi.Flagcount("B", "disable bounds checking", &Debug['B'])
201 objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C'])
202 flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
203 objabi.Flagcount("E", "debug symbol export", &Debug['E'])
204 objabi.Flagfn1("I", "add `directory` to import search path", addidir)
205 objabi.Flagcount("K", "debug missing line numbers", &Debug['K'])
206 objabi.Flagcount("L", "show full file names in error messages", &Debug['L'])
207 objabi.Flagcount("N", "disable optimizations", &Debug['N'])
208 objabi.Flagcount("S", "print assembly listing", &Debug['S'])
209 objabi.AddVersionFlag()
210 objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
211 flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
212 flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
213 flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
214 flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
215 flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
216 flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
217 flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
218 flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
219 objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
220 objabi.Flagcount("h", "halt on error", &Debug['h'])
221 objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
222 objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
223 flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
224 objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
225 objabi.Flagcount("l", "disable inlining", &Debug['l'])
226 flag.StringVar(&flag_lang, "lang", "", "release to compile for")
227 flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
228 objabi.Flagcount("live", "debug liveness analysis", &debuglive)
229 objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
230 if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
231 flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
232 }
233 flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
234 flag.StringVar(&outfile, "o", "", "write output to `file`")
235 flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
236 flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o")
237 objabi.Flagcount("r", "debug generated wrappers", &Debug['r'])
238 if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
239 flag.BoolVar(&flag_race, "race", false, "enable race detector")
240 }
241 objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
242 if enableTrace {
243 flag.BoolVar(&trace, "t", false, "trace type-checking")
244 }
245 flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
246 flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
247 objabi.Flagcount("w", "debug type checking", &Debug['w'])
248 flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
249 var flag_shared bool
250 var flag_dynlink bool
251 if supportsDynlink(thearch.LinkArch.Arch) {
252 flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
253 flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
254 }
255 flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
256 flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
257 flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
258 var goversion string
259 flag.StringVar(&goversion, "goversion", "", "required version of the runtime")
260 var symabisPath string
261 flag.StringVar(&symabisPath, "symabis", "", "read symbol ABIs from `file`")
262 flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
263 flag.StringVar(&blockprofile, "blockprofile", "", "write block profile to `file`")
264 flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`")
265 flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
266 flag.BoolVar(&newescape, "newescape", true, "enable new escape analysis")
267 flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
268 flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
269 objabi.Flagparse(usage)
270
271
272
273
274 recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "newescape", "dwarfbasentries", "smallframes")
275
276 if smallFrames {
277 maxStackVarSize = 128 * 1024
278 maxImplicitStackVarSize = 16 * 1024
279 }
280
281 Ctxt.Flag_shared = flag_dynlink || flag_shared
282 Ctxt.Flag_dynlink = flag_dynlink
283 Ctxt.Flag_optimize = Debug['N'] == 0
284
285 Ctxt.Debugasm = Debug['S']
286 Ctxt.Debugvlog = Debug_vlog
287 if flagDWARF {
288 Ctxt.DebugInfo = debuginfo
289 Ctxt.GenAbstractFunc = genAbstractFunc
290 Ctxt.DwFixups = obj.NewDwarfFixupTable(Ctxt)
291 } else {
292
293 genDwarfInline = 0
294 Ctxt.Flag_locationlists = false
295 }
296
297 if flag.NArg() < 1 && debugstr != "help" && debugstr != "ssa/help" {
298 usage()
299 }
300
301 if goversion != "" && goversion != runtime.Version() {
302 fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), goversion)
303 Exit(2)
304 }
305
306 checkLang()
307
308 if symabisPath != "" {
309 readSymABIs(symabisPath, myimportpath)
310 }
311
312 thearch.LinkArch.Init(Ctxt)
313
314 if outfile == "" {
315 p := flag.Arg(0)
316 if i := strings.LastIndex(p, "/"); i >= 0 {
317 p = p[i+1:]
318 }
319 if runtime.GOOS == "windows" {
320 if i := strings.LastIndex(p, `\`); i >= 0 {
321 p = p[i+1:]
322 }
323 }
324 if i := strings.LastIndex(p, "."); i >= 0 {
325 p = p[:i]
326 }
327 suffix := ".o"
328 if writearchive {
329 suffix = ".a"
330 }
331 outfile = p + suffix
332 }
333
334 startProfile()
335
336 if flag_race && flag_msan {
337 log.Fatal("cannot use both -race and -msan")
338 }
339 if ispkgin(omit_pkgs) {
340 flag_race = false
341 flag_msan = false
342 }
343 if flag_race {
344 racepkg = types.NewPkg("runtime/race", "")
345 }
346 if flag_msan {
347 msanpkg = types.NewPkg("runtime/msan", "")
348 }
349 if flag_race || flag_msan {
350 instrumenting = true
351 }
352
353 if compiling_runtime && Debug['N'] != 0 {
354 log.Fatal("cannot disable optimizations while compiling runtime")
355 }
356 if nBackendWorkers < 1 {
357 log.Fatalf("-c must be at least 1, got %d", nBackendWorkers)
358 }
359 if nBackendWorkers > 1 && !concurrentBackendAllowed() {
360 log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
361 }
362 if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
363 log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
364 }
365
366
367 if debugstr != "" {
368 Split:
369 for _, name := range strings.Split(debugstr, ",") {
370 if name == "" {
371 continue
372 }
373
374 if name == "help" {
375 fmt.Print(debugHelpHeader)
376 maxLen := len("ssa/help")
377 for _, t := range debugtab {
378 if len(t.name) > maxLen {
379 maxLen = len(t.name)
380 }
381 }
382 for _, t := range debugtab {
383 fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
384 }
385
386 fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
387 fmt.Print(debugHelpFooter)
388 os.Exit(0)
389 }
390 val, valstring, haveInt := 1, "", true
391 if i := strings.IndexAny(name, "=:"); i >= 0 {
392 var err error
393 name, valstring = name[:i], name[i+1:]
394 val, err = strconv.Atoi(valstring)
395 if err != nil {
396 val, haveInt = 1, false
397 }
398 }
399 for _, t := range debugtab {
400 if t.name != name {
401 continue
402 }
403 switch vp := t.val.(type) {
404 case nil:
405
406 case *string:
407 *vp = valstring
408 case *int:
409 if !haveInt {
410 log.Fatalf("invalid debug value %v", name)
411 }
412 *vp = val
413 default:
414 panic("bad debugtab type")
415 }
416 continue Split
417 }
418
419 if strings.HasPrefix(name, "ssa/") {
420
421
422
423 phase := name[4:]
424 flag := "debug"
425 if i := strings.Index(phase, "/"); i >= 0 {
426 flag = phase[i+1:]
427 phase = phase[:i]
428 }
429 err := ssa.PhaseOption(phase, flag, val, valstring)
430 if err != "" {
431 log.Fatalf(err)
432 }
433 continue Split
434 }
435 log.Fatalf("unknown debug key -d %s\n", name)
436 }
437 }
438
439
440 Ctxt.Debugpcln = Debug_pctab
441 if flagDWARF {
442 dwarf.EnableLogging(Debug_gendwarfinl != 0)
443 }
444
445 if Debug_softfloat != 0 {
446 thearch.SoftFloat = true
447 }
448
449
450
451
452
453 if Debug['l'] <= 1 {
454 Debug['l'] = 1 - Debug['l']
455 }
456
457 ssaDump = os.Getenv("GOSSAFUNC")
458 if ssaDump != "" {
459 if strings.HasSuffix(ssaDump, "+") {
460 ssaDump = ssaDump[:len(ssaDump)-1]
461 ssaDumpStdout = true
462 }
463 spl := strings.Split(ssaDump, ":")
464 if len(spl) > 1 {
465 ssaDump = spl[0]
466 ssaDumpCFG = spl[1]
467 }
468 }
469
470 trackScopes = flagDWARF
471
472 Widthptr = thearch.LinkArch.PtrSize
473 Widthreg = thearch.LinkArch.RegSize
474
475
476
477
478 types.Widthptr = Widthptr
479 types.Dowidth = dowidth
480 types.Fatalf = Fatalf
481 types.Sconv = func(s *types.Sym, flag, mode int) string {
482 return sconv(s, FmtFlag(flag), fmtMode(mode))
483 }
484 types.Tconv = func(t *types.Type, flag, mode, depth int) string {
485 return tconv(t, FmtFlag(flag), fmtMode(mode), depth)
486 }
487 types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
488 symFormat(sym, s, verb, fmtMode(mode))
489 }
490 types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
491 typeFormat(t, s, verb, fmtMode(mode))
492 }
493 types.TypeLinkSym = func(t *types.Type) *obj.LSym {
494 return typenamesym(t).Linksym()
495 }
496 types.FmtLeft = int(FmtLeft)
497 types.FmtUnsigned = int(FmtUnsigned)
498 types.FErr = FErr
499 types.Ctxt = Ctxt
500
501 initUniverse()
502
503 dclcontext = PEXTERN
504 nerrors = 0
505
506 autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
507
508 timings.Start("fe", "loadsys")
509 loadsys()
510
511 timings.Start("fe", "parse")
512 lines := parseFiles(flag.Args())
513 timings.Stop()
514 timings.AddEvent(int64(lines), "lines")
515
516 finishUniverse()
517
518 recordPackageName()
519
520 typecheckok = true
521
522
523
524
525
526
527
528
529
530
531 defercheckwidth()
532
533
534 timings.Start("fe", "typecheck", "top1")
535 for i := 0; i < len(xtop); i++ {
536 n := xtop[i]
537 if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
538 xtop[i] = typecheck(n, ctxStmt)
539 }
540 }
541
542
543
544
545
546 timings.Start("fe", "typecheck", "top2")
547 for i := 0; i < len(xtop); i++ {
548 n := xtop[i]
549 if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
550 xtop[i] = typecheck(n, ctxStmt)
551 }
552 }
553 resumecheckwidth()
554
555
556
557 timings.Start("fe", "typecheck", "func")
558 var fcount int64
559 for i := 0; i < len(xtop); i++ {
560 n := xtop[i]
561 if op := n.Op; op == ODCLFUNC || op == OCLOSURE {
562 Curfn = n
563 decldepth = 1
564 saveerrors()
565 typecheckslice(Curfn.Nbody.Slice(), ctxStmt)
566 checkreturn(Curfn)
567 if nerrors != 0 {
568 Curfn.Nbody.Set(nil)
569 }
570
571
572 deadcode(Curfn)
573 fcount++
574 }
575 }
576
577
578
579 checkMapKeys()
580 timings.AddEvent(fcount, "funcs")
581
582 if nsavederrors+nerrors != 0 {
583 errorexit()
584 }
585
586
587
588
589 timings.Start("fe", "capturevars")
590 for _, n := range xtop {
591 if n.Op == ODCLFUNC && n.Func.Closure != nil {
592 Curfn = n
593 capturevars(n)
594 }
595 }
596 capturevarscomplete = true
597
598 Curfn = nil
599
600 if nsavederrors+nerrors != 0 {
601 errorexit()
602 }
603
604
605 timings.Start("fe", "inlining")
606 if Debug_typecheckinl != 0 {
607
608
609 for _, n := range importlist {
610 if n.Func.Inl != nil {
611 saveerrors()
612 typecheckinl(n)
613 }
614 }
615
616 if nsavederrors+nerrors != 0 {
617 errorexit()
618 }
619 }
620
621 if Debug['l'] != 0 {
622
623 visitBottomUp(xtop, func(list []*Node, recursive bool) {
624 for _, n := range list {
625 if !recursive {
626 caninl(n)
627 } else {
628 if Debug['m'] > 1 {
629 fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
630 }
631 }
632 inlcalls(n)
633 }
634 })
635 }
636
637
638
639
640
641
642
643
644
645 timings.Start("fe", "escapes")
646 escapes(xtop)
647
648
649
650
651
652 if compiling_runtime {
653 nowritebarrierrecCheck = newNowritebarrierrecChecker()
654 }
655
656
657
658
659 timings.Start("fe", "xclosures")
660 for _, n := range xtop {
661 if n.Op == ODCLFUNC && n.Func.Closure != nil {
662 Curfn = n
663 transformclosure(n)
664 }
665 }
666
667
668
669
670 initssaconfig()
671
672
673
674
675 Curfn = nil
676 peekitabs()
677
678
679
680 timings.Start("be", "compilefuncs")
681 fcount = 0
682 for i := 0; i < len(xtop); i++ {
683 n := xtop[i]
684 if n.Op == ODCLFUNC {
685 funccompile(n)
686 fcount++
687 }
688 }
689 timings.AddEvent(fcount, "funcs")
690
691 if nsavederrors+nerrors == 0 {
692 fninit(xtop)
693 }
694
695 compileFunctions()
696
697 if nowritebarrierrecCheck != nil {
698
699
700 nowritebarrierrecCheck.check()
701 nowritebarrierrecCheck = nil
702 }
703
704
705
706
707 if Ctxt.DwFixups != nil {
708 Ctxt.DwFixups.Finalize(myimportpath, Debug_gendwarfinl != 0)
709 Ctxt.DwFixups = nil
710 genDwarfInline = 0
711 }
712
713
714 timings.Start("be", "externaldcls")
715 for i, n := range externdcl {
716 if n.Op == ONAME {
717 externdcl[i] = typecheck(externdcl[i], ctxExpr)
718 }
719 }
720
721
722 checkMapKeys()
723
724 if nerrors+nsavederrors != 0 {
725 errorexit()
726 }
727
728
729 timings.Start("be", "dumpobj")
730 dumpobj()
731 if asmhdr != "" {
732 dumpasmhdr()
733 }
734
735
736 sort.Slice(largeStackFrames, func(i, j int) bool {
737 return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
738 })
739 for _, large := range largeStackFrames {
740 if large.callee != 0 {
741 yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
742 } else {
743 yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
744 }
745 }
746
747 if len(compilequeue) != 0 {
748 Fatalf("%d uncompiled functions", len(compilequeue))
749 }
750
751 if nerrors+nsavederrors != 0 {
752 errorexit()
753 }
754
755 flusherrors()
756 timings.Stop()
757
758 if benchfile != "" {
759 if err := writebench(benchfile); err != nil {
760 log.Fatalf("cannot write benchmark data: %v", err)
761 }
762 }
763 }
764
765 func writebench(filename string) error {
766 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
767 if err != nil {
768 return err
769 }
770
771 var buf bytes.Buffer
772 fmt.Fprintln(&buf, "commit:", objabi.Version)
773 fmt.Fprintln(&buf, "goos:", runtime.GOOS)
774 fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
775 timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":")
776
777 n, err := f.Write(buf.Bytes())
778 if err != nil {
779 return err
780 }
781 if n != buf.Len() {
782 panic("bad writer")
783 }
784
785 return f.Close()
786 }
787
788 var (
789 importMap = map[string]string{}
790 packageFile map[string]string
791 )
792
793 func addImportMap(s string) {
794 if strings.Count(s, "=") != 1 {
795 log.Fatal("-importmap argument must be of the form source=actual")
796 }
797 i := strings.Index(s, "=")
798 source, actual := s[:i], s[i+1:]
799 if source == "" || actual == "" {
800 log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
801 }
802 importMap[source] = actual
803 }
804
805 func readImportCfg(file string) {
806 packageFile = map[string]string{}
807 data, err := ioutil.ReadFile(file)
808 if err != nil {
809 log.Fatalf("-importcfg: %v", err)
810 }
811
812 for lineNum, line := range strings.Split(string(data), "\n") {
813 lineNum++
814 line = strings.TrimSpace(line)
815 if line == "" || strings.HasPrefix(line, "#") {
816 continue
817 }
818
819 var verb, args string
820 if i := strings.Index(line, " "); i < 0 {
821 verb = line
822 } else {
823 verb, args = line[:i], strings.TrimSpace(line[i+1:])
824 }
825 var before, after string
826 if i := strings.Index(args, "="); i >= 0 {
827 before, after = args[:i], args[i+1:]
828 }
829 switch verb {
830 default:
831 log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
832 case "importmap":
833 if before == "" || after == "" {
834 log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
835 }
836 importMap[before] = after
837 case "packagefile":
838 if before == "" || after == "" {
839 log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
840 }
841 packageFile[before] = after
842 }
843 }
844 }
845
846
847
848
849 var symabiDefs, symabiRefs map[string]obj.ABI
850
851
852
853
854
855
856
857
858
859
860 func readSymABIs(file, myimportpath string) {
861 data, err := ioutil.ReadFile(file)
862 if err != nil {
863 log.Fatalf("-symabis: %v", err)
864 }
865
866 symabiDefs = make(map[string]obj.ABI)
867 symabiRefs = make(map[string]obj.ABI)
868
869 localPrefix := ""
870 if myimportpath != "" {
871
872
873
874 localPrefix = objabi.PathToPrefix(myimportpath) + "."
875 }
876
877 for lineNum, line := range strings.Split(string(data), "\n") {
878 lineNum++
879 line = strings.TrimSpace(line)
880 if line == "" || strings.HasPrefix(line, "#") {
881 continue
882 }
883
884 parts := strings.Fields(line)
885 switch parts[0] {
886 case "def", "ref":
887
888 if len(parts) != 3 {
889 log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
890 }
891 sym, abi := parts[1], parts[2]
892 if abi != "ABI0" {
893 log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi)
894 }
895
896
897
898
899
900 if localPrefix != "" && strings.HasPrefix(sym, localPrefix) {
901 sym = `"".` + sym[len(localPrefix):]
902 }
903
904
905 if parts[0] == "def" {
906 symabiDefs[sym] = obj.ABI0
907 } else {
908 symabiRefs[sym] = obj.ABI0
909 }
910 default:
911 log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
912 }
913 }
914 }
915
916 func saveerrors() {
917 nsavederrors += nerrors
918 nerrors = 0
919 }
920
921 func arsize(b *bufio.Reader, name string) int {
922 var buf [ArhdrSize]byte
923 if _, err := io.ReadFull(b, buf[:]); err != nil {
924 return -1
925 }
926 aname := strings.Trim(string(buf[0:16]), " ")
927 if !strings.HasPrefix(aname, name) {
928 return -1
929 }
930 asize := strings.Trim(string(buf[48:58]), " ")
931 i, _ := strconv.Atoi(asize)
932 return i
933 }
934
935 var idirs []string
936
937 func addidir(dir string) {
938 if dir != "" {
939 idirs = append(idirs, dir)
940 }
941 }
942
943 func isDriveLetter(b byte) bool {
944 return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
945 }
946
947
948 func islocalname(name string) bool {
949 return strings.HasPrefix(name, "/") ||
950 runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
951 strings.HasPrefix(name, "./") || name == "." ||
952 strings.HasPrefix(name, "../") || name == ".."
953 }
954
955 func findpkg(name string) (file string, ok bool) {
956 if islocalname(name) {
957 if nolocalimports {
958 return "", false
959 }
960
961 if packageFile != nil {
962 file, ok = packageFile[name]
963 return file, ok
964 }
965
966
967
968
969 file = fmt.Sprintf("%s.a", name)
970 if _, err := os.Stat(file); err == nil {
971 return file, true
972 }
973 file = fmt.Sprintf("%s.o", name)
974 if _, err := os.Stat(file); err == nil {
975 return file, true
976 }
977 return "", false
978 }
979
980
981
982
983 if q := path.Clean(name); q != name {
984 yyerror("non-canonical import path %q (should be %q)", name, q)
985 return "", false
986 }
987
988 if packageFile != nil {
989 file, ok = packageFile[name]
990 return file, ok
991 }
992
993 for _, dir := range idirs {
994 file = fmt.Sprintf("%s/%s.a", dir, name)
995 if _, err := os.Stat(file); err == nil {
996 return file, true
997 }
998 file = fmt.Sprintf("%s/%s.o", dir, name)
999 if _, err := os.Stat(file); err == nil {
1000 return file, true
1001 }
1002 }
1003
1004 if objabi.GOROOT != "" {
1005 suffix := ""
1006 suffixsep := ""
1007 if flag_installsuffix != "" {
1008 suffixsep = "_"
1009 suffix = flag_installsuffix
1010 } else if flag_race {
1011 suffixsep = "_"
1012 suffix = "race"
1013 } else if flag_msan {
1014 suffixsep = "_"
1015 suffix = "msan"
1016 }
1017
1018 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
1019 if _, err := os.Stat(file); err == nil {
1020 return file, true
1021 }
1022 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
1023 if _, err := os.Stat(file); err == nil {
1024 return file, true
1025 }
1026 }
1027
1028 return "", false
1029 }
1030
1031
1032
1033
1034 func loadsys() {
1035 types.Block = 1
1036
1037 inimport = true
1038 typecheckok = true
1039 defercheckwidth()
1040
1041 typs := runtimeTypes()
1042 for _, d := range runtimeDecls {
1043 sym := Runtimepkg.Lookup(d.name)
1044 typ := typs[d.typ]
1045 switch d.tag {
1046 case funcTag:
1047 importfunc(Runtimepkg, src.NoXPos, sym, typ)
1048 case varTag:
1049 importvar(Runtimepkg, src.NoXPos, sym, typ)
1050 default:
1051 Fatalf("unhandled declaration tag %v", d.tag)
1052 }
1053 }
1054
1055 typecheckok = false
1056 resumecheckwidth()
1057 inimport = false
1058 }
1059
1060
1061
1062 var myheight int
1063
1064 func importfile(f *Val) *types.Pkg {
1065 path_, ok := f.U.(string)
1066 if !ok {
1067 yyerror("import path must be a string")
1068 return nil
1069 }
1070
1071 if len(path_) == 0 {
1072 yyerror("import path is empty")
1073 return nil
1074 }
1075
1076 if isbadimport(path_, false) {
1077 return nil
1078 }
1079
1080
1081
1082
1083
1084 if path_ == "main" {
1085 yyerror("cannot import \"main\"")
1086 errorexit()
1087 }
1088
1089 if myimportpath != "" && path_ == myimportpath {
1090 yyerror("import %q while compiling that package (import cycle)", path_)
1091 errorexit()
1092 }
1093
1094 if mapped, ok := importMap[path_]; ok {
1095 path_ = mapped
1096 }
1097
1098 if path_ == "unsafe" {
1099 imported_unsafe = true
1100 return unsafepkg
1101 }
1102
1103 if islocalname(path_) {
1104 if path_[0] == '/' {
1105 yyerror("import path cannot be absolute path")
1106 return nil
1107 }
1108
1109 prefix := Ctxt.Pathname
1110 if localimport != "" {
1111 prefix = localimport
1112 }
1113 path_ = path.Join(prefix, path_)
1114
1115 if isbadimport(path_, true) {
1116 return nil
1117 }
1118 }
1119
1120 file, found := findpkg(path_)
1121 if !found {
1122 yyerror("can't find import: %q", path_)
1123 errorexit()
1124 }
1125
1126 importpkg := types.NewPkg(path_, "")
1127 if importpkg.Imported {
1128 return importpkg
1129 }
1130
1131 importpkg.Imported = true
1132
1133 imp, err := bio.Open(file)
1134 if err != nil {
1135 yyerror("can't open import: %q: %v", path_, err)
1136 errorexit()
1137 }
1138 defer imp.Close()
1139
1140
1141 p, err := imp.ReadString('\n')
1142 if err != nil {
1143 yyerror("import %s: reading input: %v", file, err)
1144 errorexit()
1145 }
1146
1147 if p == "!<arch>\n" {
1148
1149 sz := arsize(imp.Reader, "__.PKGDEF")
1150 if sz <= 0 {
1151 yyerror("import %s: not a package file", file)
1152 errorexit()
1153 }
1154 p, err = imp.ReadString('\n')
1155 if err != nil {
1156 yyerror("import %s: reading input: %v", file, err)
1157 errorexit()
1158 }
1159 }
1160
1161 if !strings.HasPrefix(p, "go object ") {
1162 yyerror("import %s: not a go object file: %s", file, p)
1163 errorexit()
1164 }
1165 q := fmt.Sprintf("%s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
1166 if p[10:] != q {
1167 yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
1168 errorexit()
1169 }
1170
1171
1172 for {
1173 p, err = imp.ReadString('\n')
1174 if err != nil {
1175 yyerror("import %s: reading input: %v", file, err)
1176 errorexit()
1177 }
1178 if p == "\n" {
1179 break
1180 }
1181 }
1182
1183
1184 if packageFile != nil {
1185
1186 Ctxt.AddImport(path_)
1187 } else {
1188
1189 Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):])
1190 }
1191
1192
1193
1194
1195
1196
1197 var c byte
1198 for {
1199 c, err = imp.ReadByte()
1200 if err != nil {
1201 break
1202 }
1203 if c == '$' {
1204 c, err = imp.ReadByte()
1205 if c == '$' || err != nil {
1206 break
1207 }
1208 }
1209 }
1210
1211
1212 if err == nil {
1213 c, _ = imp.ReadByte()
1214 }
1215
1216 switch c {
1217 case '\n':
1218 yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
1219 return nil
1220
1221 case 'B':
1222 if Debug_export != 0 {
1223 fmt.Printf("importing %s (%s)\n", path_, file)
1224 }
1225 imp.ReadByte()
1226
1227 c, err = imp.ReadByte()
1228 if err != nil {
1229 yyerror("import %s: reading input: %v", file, err)
1230 errorexit()
1231 }
1232
1233
1234
1235 if c != 'i' {
1236 yyerror("import %s: unexpected package format byte: %v", file, c)
1237 errorexit()
1238 }
1239 iimport(importpkg, imp)
1240
1241 default:
1242 yyerror("no import in %q", path_)
1243 errorexit()
1244 }
1245
1246 if importpkg.Height >= myheight {
1247 myheight = importpkg.Height + 1
1248 }
1249
1250 return importpkg
1251 }
1252
1253 func pkgnotused(lineno src.XPos, path string, name string) {
1254
1255
1256
1257
1258
1259
1260 elem := path
1261 if i := strings.LastIndex(elem, "/"); i >= 0 {
1262 elem = elem[i+1:]
1263 }
1264 if name == "" || elem == name {
1265 yyerrorl(lineno, "imported and not used: %q", path)
1266 } else {
1267 yyerrorl(lineno, "imported and not used: %q as %s", path, name)
1268 }
1269 }
1270
1271 func mkpackage(pkgname string) {
1272 if localpkg.Name == "" {
1273 if pkgname == "_" {
1274 yyerror("invalid package name _")
1275 }
1276 localpkg.Name = pkgname
1277 } else {
1278 if pkgname != localpkg.Name {
1279 yyerror("package %s; expected %s", pkgname, localpkg.Name)
1280 }
1281 }
1282 }
1283
1284 func clearImports() {
1285 type importedPkg struct {
1286 pos src.XPos
1287 path string
1288 name string
1289 }
1290 var unused []importedPkg
1291
1292 for _, s := range localpkg.Syms {
1293 n := asNode(s.Def)
1294 if n == nil {
1295 continue
1296 }
1297 if n.Op == OPACK {
1298
1299
1300
1301
1302
1303 if !n.Name.Used() && nsyntaxerrors == 0 {
1304 unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name})
1305 }
1306 s.Def = nil
1307 continue
1308 }
1309 if IsAlias(s) {
1310
1311
1312 if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 {
1313 unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""})
1314 n.Name.Pack.Name.SetUsed(true)
1315 }
1316 s.Def = nil
1317 continue
1318 }
1319 }
1320
1321 sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
1322 for _, pkg := range unused {
1323 pkgnotused(pkg.pos, pkg.path, pkg.name)
1324 }
1325 }
1326
1327 func IsAlias(sym *types.Sym) bool {
1328 return sym.Def != nil && asNode(sym.Def).Sym != sym
1329 }
1330
1331
1332
1333 var concurrentFlagOK = [256]bool{
1334 'B': true,
1335 'C': true,
1336 'e': true,
1337 'I': true,
1338 'N': true,
1339 'l': true,
1340 'w': true,
1341 'W': true,
1342 'S': true,
1343 }
1344
1345 func concurrentBackendAllowed() bool {
1346 for i, x := range Debug {
1347 if x != 0 && !concurrentFlagOK[i] {
1348 return false
1349 }
1350 }
1351
1352
1353
1354
1355 if Debug_vlog || debugstr != "" || debuglive > 0 {
1356 return false
1357 }
1358
1359 if objabi.Fieldtrack_enabled != 0 {
1360 return false
1361 }
1362
1363 if Ctxt.Flag_shared || Ctxt.Flag_dynlink || flag_race {
1364 return false
1365 }
1366 return true
1367 }
1368
1369
1370
1371 func recordFlags(flags ...string) {
1372 if myimportpath == "" {
1373
1374
1375 return
1376 }
1377
1378 type BoolFlag interface {
1379 IsBoolFlag() bool
1380 }
1381 type CountFlag interface {
1382 IsCountFlag() bool
1383 }
1384 var cmd bytes.Buffer
1385 for _, name := range flags {
1386 f := flag.Lookup(name)
1387 if f == nil {
1388 continue
1389 }
1390 getter := f.Value.(flag.Getter)
1391 if getter.String() == f.DefValue {
1392
1393 continue
1394 }
1395 if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
1396 val, ok := getter.Get().(bool)
1397 if ok && val {
1398 fmt.Fprintf(&cmd, " -%s", f.Name)
1399 continue
1400 }
1401 }
1402 if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
1403 val, ok := getter.Get().(int)
1404 if ok && val == 1 {
1405 fmt.Fprintf(&cmd, " -%s", f.Name)
1406 continue
1407 }
1408 }
1409 fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
1410 }
1411
1412 if cmd.Len() == 0 {
1413 return
1414 }
1415 s := Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + myimportpath)
1416 s.Type = objabi.SDWARFINFO
1417
1418
1419 s.Set(obj.AttrDuplicateOK, true)
1420 Ctxt.Data = append(Ctxt.Data, s)
1421 s.P = cmd.Bytes()[1:]
1422 }
1423
1424
1425
1426 func recordPackageName() {
1427 s := Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + myimportpath)
1428 s.Type = objabi.SDWARFINFO
1429
1430
1431 s.Set(obj.AttrDuplicateOK, true)
1432 Ctxt.Data = append(Ctxt.Data, s)
1433 s.P = []byte(localpkg.Name)
1434 }
1435
1436
1437 var flag_lang string
1438
1439
1440 func currentLang() string {
1441 return fmt.Sprintf("go1.%d", goversion.Version)
1442 }
1443
1444
1445
1446 var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
1447
1448
1449 type lang struct {
1450 major, minor int
1451 }
1452
1453
1454
1455
1456 var langWant lang
1457
1458
1459 func langSupported(major, minor int) bool {
1460 if langWant.major == 0 && langWant.minor == 0 {
1461 return true
1462 }
1463 return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
1464 }
1465
1466
1467
1468 func checkLang() {
1469 if flag_lang == "" {
1470 return
1471 }
1472
1473 var err error
1474 langWant, err = parseLang(flag_lang)
1475 if err != nil {
1476 log.Fatalf("invalid value %q for -lang: %v", flag_lang, err)
1477 }
1478
1479 if def := currentLang(); flag_lang != def {
1480 defVers, err := parseLang(def)
1481 if err != nil {
1482 log.Fatalf("internal error parsing default lang %q: %v", def, err)
1483 }
1484 if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) {
1485 log.Fatalf("invalid value %q for -lang: max known version is %q", flag_lang, def)
1486 }
1487 }
1488 }
1489
1490
1491 func parseLang(s string) (lang, error) {
1492 matches := goVersionRE.FindStringSubmatch(s)
1493 if matches == nil {
1494 return lang{}, fmt.Errorf(`should be something like "go1.12"`)
1495 }
1496 major, err := strconv.Atoi(matches[1])
1497 if err != nil {
1498 return lang{}, err
1499 }
1500 minor, err := strconv.Atoi(matches[2])
1501 if err != nil {
1502 return lang{}, err
1503 }
1504 return lang{major: major, minor: minor}, nil
1505 }
1506
View as plain text