// hostArchive reads an archive file holding host objects and links in // required objects. The general format is the same as a Go archive // file, but it has an armap listing symbols and the objects that // define them. This is used for the compiler support library // libgcc.a. func hostArchive(name string) { f, err := obj.Bopenr(name) if err != nil { if os.IsNotExist(err) { // It's OK if we don't have a libgcc file at all. return } Exitf("cannot open file %s: %v", name, err) } defer obj.Bterm(f) magbuf := make([]byte, len(ARMAG)) if obj.Bread(f, magbuf) != len(magbuf) { Exitf("file %s too short", name) } var arhdr ArHdr l := nextar(f, obj.Boffset(f), &arhdr) if l <= 0 { Exitf("%s missing armap", name) } var armap archiveMap if arhdr.name == "/" || arhdr.name == "/SYM64/" { armap = readArmap(name, f, arhdr) } else { Exitf("%s missing armap", name) } loaded := make(map[uint64]bool) any := true for any { var load []uint64 for s := Ctxt.Allsym; s != nil; s = s.Allsym { for _, r := range s.R { if r.Sym != nil && r.Sym.Type&obj.SMASK == obj.SXREF { if off := armap[r.Sym.Name]; off != 0 && !loaded[off] { load = append(load, off) loaded[off] = true } } } } for _, off := range load { l := nextar(f, int64(off), &arhdr) if l <= 0 { Exitf("%s missing archive entry at offset %d", name, off) } pname := fmt.Sprintf("%s(%s)", name, arhdr.name) l = atolwhex(arhdr.size) h := ldobj(f, "libgcc", l, pname, name, ArchiveObj) obj.Bseek(f, h.off, 0) h.ld(f, h.pkg, h.length, h.pn) } any = len(load) > 0 } }
func hostobjs() { var f *obj.Biobuf var h *Hostobj for i := 0; i < len(hostobj); i++ { h = &hostobj[i] var err error f, err = obj.Bopenr(h.file) if f == nil { Exitf("cannot reopen %s: %v", h.pn, err) } obj.Bseek(f, h.off, 0) h.ld(f, h.pkg, h.length, h.pn) obj.Bterm(f) } }
func objfile(lib *Library) { pkg := pathtoprefix(lib.Pkg) if Debug['v'] > 1 { fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg) } Bso.Flush() var err error var f *obj.Biobuf f, err = obj.Bopenr(lib.File) if err != nil { Exitf("cannot open file %s: %v", lib.File, err) } magbuf := make([]byte, len(ARMAG)) if obj.Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) { /* load it as a regular file */ l := obj.Bseek(f, 0, 2) obj.Bseek(f, 0, 0) ldobj(f, pkg, l, lib.File, lib.File, FileObj) obj.Bterm(f) return } /* skip over optional __.GOSYMDEF and process __.PKGDEF */ off := obj.Boffset(f) var arhdr ArHdr l := nextar(f, off, &arhdr) var pname string if l <= 0 { Diag("%s: short read on archive file symbol header", lib.File) goto out } if strings.HasPrefix(arhdr.name, symname) { off += l l = nextar(f, off, &arhdr) if l <= 0 { Diag("%s: short read on archive file symbol header", lib.File) goto out } } if !strings.HasPrefix(arhdr.name, pkgname) { Diag("%s: cannot find package header", lib.File) goto out } if Buildmode == BuildmodeShared { before := obj.Boffset(f) pkgdefBytes := make([]byte, atolwhex(arhdr.size)) obj.Bread(f, pkgdefBytes) hash := sha1.Sum(pkgdefBytes) lib.hash = hash[:] obj.Bseek(f, before, 0) } off += l if Debug['u'] != 0 { ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef) } /* * load all the object files from the archive now. * this gives us sequential file access and keeps us * from needing to come back later to pick up more * objects. it breaks the usual C archive model, but * this is Go, not C. the common case in Go is that * we need to load all the objects, and then we throw away * the individual symbols that are unused. * * loading every object will also make it possible to * load foreign objects not referenced by __.GOSYMDEF. */ for { l = nextar(f, off, &arhdr) if l == 0 { break } if l < 0 { Exitf("%s: malformed archive", lib.File) } off += l pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name) l = atolwhex(arhdr.size) ldobj(f, pkg, l, pname, lib.File, ArchiveObj) } out: obj.Bterm(f) }
func importfile(f *Val, line int) { if f.Ctype != CTSTR { Yyerror("import statement not a string") fakeimport() return } if len(f.U.Sval) == 0 { Yyerror("import path is empty") fakeimport() return } if isbadimport(f.U.Sval) { fakeimport() return } // The package name main is no longer reserved, // but we reserve the import path "main" to identify // the main package, just as we reserve the import // path "math" to identify the standard math package. if f.U.Sval == "main" { Yyerror("cannot import \"main\"") errorexit() } if myimportpath != "" && f.U.Sval == myimportpath { Yyerror("import %q while compiling that package (import cycle)", f.U.Sval) errorexit() } if f.U.Sval == "unsafe" { if safemode != 0 { Yyerror("cannot import package unsafe") errorexit() } importpkg = mkpkg(f.U.Sval) cannedimports("unsafe.6", unsafeimport) imported_unsafe = 1 return } path_ := f.U.Sval if islocalname(path_) { if path_[0] == '/' { Yyerror("import path cannot be absolute path") fakeimport() return } prefix := Ctxt.Pathname if localimport != "" { prefix = localimport } cleanbuf := prefix cleanbuf += "/" cleanbuf += path_ cleanbuf = path.Clean(cleanbuf) path_ = cleanbuf if isbadimport(path_) { fakeimport() return } } file, found := findpkg(path_) if !found { Yyerror("can't find import: %q", f.U.Sval) errorexit() } importpkg = mkpkg(path_) // If we already saw that package, feed a dummy statement // to the lexer to avoid parsing export data twice. if importpkg.Imported != 0 { tag := "" if importpkg.Safe { tag = "safe" } p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag) cannedimports(file, p) return } importpkg.Imported = 1 var err error var imp *obj.Biobuf imp, err = obj.Bopenr(file) if err != nil { Yyerror("can't open import: %q: %v", f.U.Sval, err) errorexit() } if strings.HasSuffix(file, ".a") { if !skiptopkgdef(imp) { Yyerror("import %s: not a package file", file) errorexit() } } // check object header p := obj.Brdstr(imp, '\n', 1) if p != "empty archive" { if !strings.HasPrefix(p, "go object ") { Yyerror("import %s: not a go object file", file) errorexit() } q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) if p[10:] != q { Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q) errorexit() } } // assume files move (get installed) // so don't record the full path. linehist(file[len(file)-len(path_)-2:], -1, 1) // acts as #pragma lib /* * position the input right * after $$ and return */ pushedio = curio curio.bin = imp curio.peekc = 0 curio.peekc1 = 0 curio.infile = file curio.nlsemi = 0 typecheckok = 1 var c int32 for { c = int32(getc()) if c == EOF { break } if c != '$' { continue } c = int32(getc()) if c == EOF { break } if c != '$' { continue } return } Yyerror("no import in %q", f.U.Sval) unimportfile() }
func Main() { defer hidePanic() // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix, // but not other values. p := obj.Getgoarch() if !strings.HasPrefix(p, Thearch.Thestring) { log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p) } goarch = p Thearch.Linkarchinit() Ctxt = obj.Linknew(Thearch.Thelinkarch) Ctxt.Diag = Yyerror Ctxt.Bso = &bstdout bstdout = *obj.Binitw(os.Stdout) localpkg = mkpkg("") localpkg.Prefix = "\"\"" // pseudo-package, for scoping builtinpkg = mkpkg("go.builtin") builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin // pseudo-package, accessed by import "unsafe" unsafepkg = mkpkg("unsafe") unsafepkg.Name = "unsafe" // real package, referred to by generated runtime calls Runtimepkg = mkpkg("runtime") Runtimepkg.Name = "runtime" // pseudo-packages used in symbol tables gostringpkg = mkpkg("go.string") gostringpkg.Name = "go.string" gostringpkg.Prefix = "go.string" // not go%2estring itabpkg = mkpkg("go.itab") itabpkg.Name = "go.itab" itabpkg.Prefix = "go.itab" // not go%2eitab weaktypepkg = mkpkg("go.weak.type") weaktypepkg.Name = "go.weak.type" weaktypepkg.Prefix = "go.weak.type" // not go%2eweak%2etype typelinkpkg = mkpkg("go.typelink") typelinkpkg.Name = "go.typelink" typelinkpkg.Prefix = "go.typelink" // not go%2etypelink trackpkg = mkpkg("go.track") trackpkg.Name = "go.track" trackpkg.Prefix = "go.track" // not go%2etrack typepkg = mkpkg("type") typepkg.Name = "type" goroot = obj.Getgoroot() goos = obj.Getgoos() Nacl = goos == "nacl" if Nacl { flag_largemodel = 1 } outfile = "" obj.Flagcount("+", "compiling runtime", &compiling_runtime) obj.Flagcount("%", "debug non-static initializers", &Debug['%']) obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A']) obj.Flagcount("B", "disable bounds checking", &Debug['B']) obj.Flagstr("D", "path: set relative path for local imports", &localimport) obj.Flagcount("E", "debug symbol export", &Debug['E']) obj.Flagfn1("I", "dir: add dir to import search path", addidir) obj.Flagcount("K", "debug missing line numbers", &Debug['K']) obj.Flagcount("L", "use full (long) path in error messages", &Debug['L']) obj.Flagcount("M", "debug move generation", &Debug['M']) obj.Flagcount("N", "disable optimizations", &Debug['N']) obj.Flagcount("P", "debug peephole optimizer", &Debug['P']) obj.Flagcount("R", "debug register optimizer", &Debug['R']) obj.Flagcount("S", "print assembly listing", &Debug['S']) obj.Flagfn0("V", "print compiler version", doversion) obj.Flagcount("W", "debug parse tree after type checking", &Debug['W']) obj.Flagstr("asmhdr", "file: write assembly header to named file", &asmhdr) obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go) obj.Flagstr("d", "list: print debug information about items in list", &debugstr) obj.Flagcount("e", "no limit on number of errors reported", &Debug['e']) obj.Flagcount("f", "debug stack frames", &Debug['f']) obj.Flagcount("g", "debug code generation", &Debug['g']) obj.Flagcount("h", "halt on error", &Debug['h']) obj.Flagcount("i", "debug line number stack", &Debug['i']) obj.Flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix) obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j']) obj.Flagcount("l", "disable inlining", &Debug['l']) obj.Flagcount("live", "debug liveness analysis", &debuglive) obj.Flagcount("m", "print optimization decisions", &Debug['m']) obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports) obj.Flagstr("o", "obj: set output file", &outfile) obj.Flagstr("p", "path: set expected package import path", &myimportpath) obj.Flagcount("pack", "write package file instead of object file", &writearchive) obj.Flagcount("r", "debug generated wrappers", &Debug['r']) obj.Flagcount("race", "enable race detector", &flag_race) obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s']) obj.Flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &Ctxt.Trimpath) obj.Flagcount("u", "reject unsafe code", &safemode) obj.Flagcount("v", "increase debug verbosity", &Debug['v']) obj.Flagcount("w", "debug type checking", &Debug['w']) use_writebarrier = 1 obj.Flagcount("wb", "enable write barrier", &use_writebarrier) obj.Flagcount("x", "debug lexer", &Debug['x']) obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y']) var flag_shared int if Thearch.Thechar == '6' { obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel) obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared) } obj.Flagstr("cpuprofile", "file: write cpu profile to file", &cpuprofile) obj.Flagstr("memprofile", "file: write memory profile to file", &memprofile) obj.Flagparse(usage) Ctxt.Flag_shared = int32(flag_shared) Ctxt.Debugasm = int32(Debug['S']) Ctxt.Debugvlog = int32(Debug['v']) if flag.NArg() < 1 { usage() } startProfile() if flag_race != 0 { racepkg = mkpkg("runtime/race") racepkg.Name = "race" } // parse -d argument if debugstr != "" { var j int f := strings.Split(debugstr, ",") for i := range f { if f[i] == "" { continue } for j = 0; j < len(debugtab); j++ { if debugtab[j].name == f[i] { if debugtab[j].val != nil { *debugtab[j].val = 1 } break } } if j >= len(debugtab) { log.Fatalf("unknown debug information -d '%s'\n", f[i]) } } } // enable inlining. for now: // default: inlining on. (debug['l'] == 1) // -l: inlining off (debug['l'] == 0) // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1) if Debug['l'] <= 1 { Debug['l'] = 1 - Debug['l'] } Thearch.Betypeinit() if Widthptr == 0 { Fatal("betypeinit failed") } lexinit() typeinit() lexinit1() // TODO(rsc): Restore yytinit? blockgen = 1 dclcontext = PEXTERN nerrors = 0 lexlineno = 1 for _, infile = range flag.Args() { linehist(infile, 0, 0) curio.infile = infile var err error curio.bin, err = obj.Bopenr(infile) if err != nil { fmt.Printf("open %s: %v\n", infile, err) errorexit() } curio.peekc = 0 curio.peekc1 = 0 curio.nlsemi = 0 curio.eofnl = 0 curio.last = 0 // Skip initial BOM if present. if obj.Bgetrune(curio.bin) != obj.BOM { obj.Bungetrune(curio.bin) } block = 1 iota_ = -1000000 imported_unsafe = 0 yyparse() if nsyntaxerrors != 0 { errorexit() } linehist("<pop>", 0, 0) if curio.bin != nil { obj.Bterm(curio.bin) } } testdclstack() mkpackage(localpkg.Name) // final import not used checks lexfini() typecheckok = 1 if Debug['f'] != 0 { frame(1) } // Process top-level declarations in phases. // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. defercheckwidth() for l := xtop; l != nil; l = l.Next { if l.N.Op != ODCL && l.N.Op != OAS { typecheck(&l.N, Etop) } } // Phase 2: Variable assignments. // To check interface assignments, depends on phase 1. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCL || l.N.Op == OAS { typecheck(&l.N, Etop) } } resumecheckwidth() // Phase 3: Type check function bodies. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCLFUNC || l.N.Op == OCLOSURE { Curfn = l.N decldepth = 1 saveerrors() typechecklist(l.N.Nbody, Etop) checkreturn(l.N) if nerrors != 0 { l.N.Nbody = nil // type errors; do not compile } } } // Phase 4: Decide how to capture closed variables. // This needs to run before escape analysis, // because variables captured by value do not escape. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCLFUNC && l.N.Closure != nil { Curfn = l.N capturevars(l.N) } } Curfn = nil if nsavederrors+nerrors != 0 { errorexit() } // Phase 5: Inlining if Debug['l'] > 1 { // Typecheck imported function bodies if debug['l'] > 1, // otherwise lazily when used or re-exported. for l := importlist; l != nil; l = l.Next { if l.N.Func.Inl != nil { saveerrors() typecheckinl(l.N) } } if nsavederrors+nerrors != 0 { errorexit() } } if Debug['l'] != 0 { // Find functions that can be inlined and clone them before walk expands them. visitBottomUp(xtop, func(list *NodeList, recursive bool) { for l := list; l != nil; l = l.Next { if l.N.Op == ODCLFUNC { caninl(l.N) inlcalls(l.N) } } }) } // Phase 6: Escape analysis. // Required for moving heap allocations onto stack, // which in turn is required by the closure implementation, // which stores the addresses of stack variables into the closure. // If the closure does not escape, it needs to be on the stack // or else the stack copier will not update it. escapes(xtop) // Escape analysis moved escaped values off stack. // Move large values off stack too. movelarge(xtop) // Phase 7: Transform closure bodies to properly reference captured variables. // This needs to happen before walk, because closures must be transformed // before walk reaches a call of a closure. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCLFUNC && l.N.Closure != nil { Curfn = l.N transformclosure(l.N) } } Curfn = nil // Phase 8: Compile top level functions. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCLFUNC { funccompile(l.N) } } if nsavederrors+nerrors == 0 { fninit(xtop) } // Phase 9: Check external declarations. for l := externdcl; l != nil; l = l.Next { if l.N.Op == ONAME { typecheck(&l.N, Erv) } } if nerrors+nsavederrors != 0 { errorexit() } dumpobj() if asmhdr != "" { dumpasmhdr() } if nerrors+nsavederrors != 0 { errorexit() } Flusherrors() }
func Main() { defer hidePanic() // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix, // but not other values. p := obj.Getgoarch() if !strings.HasPrefix(p, Thearch.Thestring) { log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p) } goarch = p Thearch.Linkarchinit() Ctxt = obj.Linknew(Thearch.Thelinkarch) Ctxt.DiagFunc = Yyerror Ctxt.Bso = &bstdout bstdout = *obj.Binitw(os.Stdout) localpkg = mkpkg("") localpkg.Prefix = "\"\"" // pseudo-package, for scoping builtinpkg = mkpkg("go.builtin") builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin // pseudo-package, accessed by import "unsafe" unsafepkg = mkpkg("unsafe") unsafepkg.Name = "unsafe" // real package, referred to by generated runtime calls Runtimepkg = mkpkg("runtime") Runtimepkg.Name = "runtime" // pseudo-packages used in symbol tables gostringpkg = mkpkg("go.string") gostringpkg.Name = "go.string" gostringpkg.Prefix = "go.string" // not go%2estring itabpkg = mkpkg("go.itab") itabpkg.Name = "go.itab" itabpkg.Prefix = "go.itab" // not go%2eitab weaktypepkg = mkpkg("go.weak.type") weaktypepkg.Name = "go.weak.type" weaktypepkg.Prefix = "go.weak.type" // not go%2eweak%2etype typelinkpkg = mkpkg("go.typelink") typelinkpkg.Name = "go.typelink" typelinkpkg.Prefix = "go.typelink" // not go%2etypelink trackpkg = mkpkg("go.track") trackpkg.Name = "go.track" trackpkg.Prefix = "go.track" // not go%2etrack typepkg = mkpkg("type") typepkg.Name = "type" goroot = obj.Getgoroot() goos = obj.Getgoos() Nacl = goos == "nacl" if Nacl { flag_largemodel = 1 } outfile = "" obj.Flagcount("+", "compiling runtime", &compiling_runtime) obj.Flagcount("%", "debug non-static initializers", &Debug['%']) obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A']) obj.Flagcount("B", "disable bounds checking", &Debug['B']) obj.Flagstr("D", "set relative `path` for local imports", &localimport) obj.Flagcount("E", "debug symbol export", &Debug['E']) obj.Flagfn1("I", "add `directory` to import search path", addidir) obj.Flagcount("K", "debug missing line numbers", &Debug['K']) obj.Flagcount("L", "use full (long) path in error messages", &Debug['L']) obj.Flagcount("M", "debug move generation", &Debug['M']) obj.Flagcount("N", "disable optimizations", &Debug['N']) obj.Flagcount("P", "debug peephole optimizer", &Debug['P']) obj.Flagcount("R", "debug register optimizer", &Debug['R']) obj.Flagcount("S", "print assembly listing", &Debug['S']) obj.Flagfn0("V", "print compiler version", doversion) obj.Flagcount("W", "debug parse tree after type checking", &Debug['W']) obj.Flagstr("asmhdr", "write assembly header to `file`", &asmhdr) obj.Flagstr("buildid", "record `id` as the build id in the export metadata", &buildid) obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go) obj.Flagstr("d", "print debug information about items in `list`", &debugstr) obj.Flagcount("e", "no limit on number of errors reported", &Debug['e']) obj.Flagcount("f", "debug stack frames", &Debug['f']) obj.Flagcount("g", "debug code generation", &Debug['g']) obj.Flagcount("h", "halt on error", &Debug['h']) obj.Flagcount("i", "debug line number stack", &Debug['i']) obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap) obj.Flagstr("installsuffix", "set pkg directory `suffix`", &flag_installsuffix) obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j']) obj.Flagcount("l", "disable inlining", &Debug['l']) obj.Flagcount("live", "debug liveness analysis", &debuglive) obj.Flagcount("m", "print optimization decisions", &Debug['m']) obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan) obj.Flagcount("newexport", "use new export format", &newexport) // TODO(gri) remove eventually (issue 13241) obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports) obj.Flagstr("o", "write output to `file`", &outfile) obj.Flagstr("p", "set expected package import `path`", &myimportpath) obj.Flagcount("pack", "write package file instead of object file", &writearchive) obj.Flagcount("r", "debug generated wrappers", &Debug['r']) obj.Flagcount("race", "enable race detector", &flag_race) obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s']) obj.Flagstr("trimpath", "remove `prefix` from recorded source file paths", &Ctxt.LineHist.TrimPathPrefix) obj.Flagcount("u", "reject unsafe code", &safemode) obj.Flagcount("v", "increase debug verbosity", &Debug['v']) obj.Flagcount("w", "debug type checking", &Debug['w']) use_writebarrier = 1 obj.Flagcount("wb", "enable write barrier", &use_writebarrier) obj.Flagcount("x", "debug lexer", &Debug['x']) obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y']) var flag_shared int var flag_dynlink bool switch Thearch.Thechar { case '5', '6', '7', '8', '9': obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared) } if Thearch.Thechar == '6' { obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel) } switch Thearch.Thechar { case '5', '6', '7', '8', '9': flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries") } obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile) obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile) obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate) obj.Flagparse(usage) if flag_dynlink { flag_shared = 1 } Ctxt.Flag_shared = int32(flag_shared) Ctxt.Flag_dynlink = flag_dynlink Ctxt.Debugasm = int32(Debug['S']) Ctxt.Debugvlog = int32(Debug['v']) if flag.NArg() < 1 { usage() } startProfile() if flag_race != 0 { racepkg = mkpkg("runtime/race") racepkg.Name = "race" } if flag_msan != 0 { msanpkg = mkpkg("runtime/msan") msanpkg.Name = "msan" } if flag_race != 0 && flag_msan != 0 { log.Fatal("can not use both -race and -msan") } else if flag_race != 0 || flag_msan != 0 { instrumenting = true } // parse -d argument if debugstr != "" { Split: for _, name := range strings.Split(debugstr, ",") { if name == "" { continue } val := 1 if i := strings.Index(name, "="); i >= 0 { var err error val, err = strconv.Atoi(name[i+1:]) if err != nil { log.Fatalf("invalid debug value %v", name) } name = name[:i] } for _, t := range debugtab { if t.name == name { if t.val != nil { *t.val = val continue Split } } } log.Fatalf("unknown debug key -d %s\n", name) } } // enable inlining. for now: // default: inlining on. (debug['l'] == 1) // -l: inlining off (debug['l'] == 0) // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1) if Debug['l'] <= 1 { Debug['l'] = 1 - Debug['l'] } Thearch.Betypeinit() if Widthptr == 0 { Fatalf("betypeinit failed") } lexinit() typeinit() lexinit1() blockgen = 1 dclcontext = PEXTERN nerrors = 0 lexlineno = 1 const BOM = 0xFEFF for _, infile = range flag.Args() { if trace && Debug['x'] != 0 { fmt.Printf("--- %s ---\n", infile) } linehistpush(infile) curio.infile = infile var err error curio.bin, err = obj.Bopenr(infile) if err != nil { fmt.Printf("open %s: %v\n", infile, err) errorexit() } curio.peekc = 0 curio.peekc1 = 0 curio.nlsemi = false curio.eofnl = false curio.last = 0 // Skip initial BOM if present. if obj.Bgetrune(curio.bin) != BOM { obj.Bungetrune(curio.bin) } block = 1 iota_ = -1000000 imported_unsafe = false parse_file() if nsyntaxerrors != 0 { errorexit() } linehistpop() if curio.bin != nil { obj.Bterm(curio.bin) } } testdclstack() mkpackage(localpkg.Name) // final import not used checks lexfini() typecheckok = true if Debug['f'] != 0 { frame(1) } // Process top-level declarations in phases. // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. defercheckwidth() for l := xtop; l != nil; l = l.Next { if l.N.Op != ODCL && l.N.Op != OAS && l.N.Op != OAS2 { typecheck(&l.N, Etop) } } // Phase 2: Variable assignments. // To check interface assignments, depends on phase 1. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCL || l.N.Op == OAS || l.N.Op == OAS2 { typecheck(&l.N, Etop) } } resumecheckwidth() // Phase 3: Type check function bodies. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCLFUNC || l.N.Op == OCLOSURE { Curfn = l.N decldepth = 1 saveerrors() typechecklist(l.N.Nbody, Etop) checkreturn(l.N) if nerrors != 0 { l.N.Nbody = nil // type errors; do not compile } } } // Phase 4: Decide how to capture closed variables. // This needs to run before escape analysis, // because variables captured by value do not escape. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCLFUNC && l.N.Func.Closure != nil { Curfn = l.N capturevars(l.N) } } Curfn = nil if nsavederrors+nerrors != 0 { errorexit() } // Phase 5: Inlining if Debug['l'] > 1 { // Typecheck imported function bodies if debug['l'] > 1, // otherwise lazily when used or re-exported. for _, n := range importlist { if n.Func.Inl != nil { saveerrors() typecheckinl(n) } } if nsavederrors+nerrors != 0 { errorexit() } } if Debug['l'] != 0 { // Find functions that can be inlined and clone them before walk expands them. visitBottomUp(xtop, func(list []*Node, recursive bool) { // TODO: use a range statement here if the order does not matter for i := len(list) - 1; i >= 0; i-- { n := list[i] if n.Op == ODCLFUNC { caninl(n) inlcalls(n) } } }) } // Phase 6: Escape analysis. // Required for moving heap allocations onto stack, // which in turn is required by the closure implementation, // which stores the addresses of stack variables into the closure. // If the closure does not escape, it needs to be on the stack // or else the stack copier will not update it. // Large values are also moved off stack in escape analysis; // because large values may contain pointers, it must happen early. escapes(xtop) // Phase 7: Transform closure bodies to properly reference captured variables. // This needs to happen before walk, because closures must be transformed // before walk reaches a call of a closure. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCLFUNC && l.N.Func.Closure != nil { Curfn = l.N transformclosure(l.N) } } Curfn = nil // Phase 8: Compile top level functions. for l := xtop; l != nil; l = l.Next { if l.N.Op == ODCLFUNC { funccompile(l.N) } } if nsavederrors+nerrors == 0 { fninit(xtop) } if compiling_runtime != 0 { checknowritebarrierrec() } // Phase 9: Check external declarations. for i, n := range externdcl { if n.Op == ONAME { typecheck(&externdcl[i], Erv) } } if nerrors+nsavederrors != 0 { errorexit() } dumpobj() if asmhdr != "" { dumpasmhdr() } if nerrors+nsavederrors != 0 { errorexit() } Flusherrors() }
// TODO(gri) line argument doesn't appear to be used func importfile(f *Val, line int) { if _, ok := f.U.(string); !ok { Yyerror("import statement not a string") fakeimport() return } if len(f.U.(string)) == 0 { Yyerror("import path is empty") fakeimport() return } if isbadimport(f.U.(string)) { fakeimport() return } // The package name main is no longer reserved, // but we reserve the import path "main" to identify // the main package, just as we reserve the import // path "math" to identify the standard math package. if f.U.(string) == "main" { Yyerror("cannot import \"main\"") errorexit() } if myimportpath != "" && f.U.(string) == myimportpath { Yyerror("import %q while compiling that package (import cycle)", f.U.(string)) errorexit() } path_ := f.U.(string) if mapped, ok := importMap[path_]; ok { path_ = mapped } if path_ == "unsafe" { if safemode != 0 { Yyerror("cannot import package unsafe") errorexit() } importpkg = mkpkg(f.U.(string)) cannedimports("unsafe.o", unsafeimport) imported_unsafe = true return } if islocalname(path_) { if path_[0] == '/' { Yyerror("import path cannot be absolute path") fakeimport() return } prefix := Ctxt.Pathname if localimport != "" { prefix = localimport } cleanbuf := prefix cleanbuf += "/" cleanbuf += path_ cleanbuf = path.Clean(cleanbuf) path_ = cleanbuf if isbadimport(path_) { fakeimport() return } } file, found := findpkg(path_) if !found { Yyerror("can't find import: %q", f.U.(string)) errorexit() } importpkg = mkpkg(path_) // If we already saw that package, feed a dummy statement // to the lexer to avoid parsing export data twice. if importpkg.Imported { tag := "" if importpkg.Safe { tag = "safe" } p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag) cannedimports(file, p) return } importpkg.Imported = true var err error var imp *obj.Biobuf imp, err = obj.Bopenr(file) if err != nil { Yyerror("can't open import: %q: %v", f.U.(string), err) errorexit() } if strings.HasSuffix(file, ".a") { if !skiptopkgdef(imp) { Yyerror("import %s: not a package file", file) errorexit() } } // check object header p := obj.Brdstr(imp, '\n', 1) if p != "empty archive" { if !strings.HasPrefix(p, "go object ") { Yyerror("import %s: not a go object file", file) errorexit() } q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) if p[10:] != q { Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q) errorexit() } } // assume files move (get installed) // so don't record the full path. linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib // In the importfile, if we find: // $$\n (old format): position the input right after $$\n and return // $$B\n (new format): import directly, then feed the lexer a dummy statement // look for $$ var c int for { c = obj.Bgetc(imp) if c < 0 { break } if c == '$' { c = obj.Bgetc(imp) if c == '$' || c < 0 { break } } } // get character after $$ if c >= 0 { c = obj.Bgetc(imp) } switch c { case '\n': // old export format pushedio = curio curio.bin = imp curio.peekc = 0 curio.peekc1 = 0 curio.infile = file curio.nlsemi = false typecheckok = true push_parser() case 'B': // new export format obj.Bgetc(imp) // skip \n after $$B Import(imp) // continue as if the package was imported before (see above) tag := "" if importpkg.Safe { tag = "safe" } p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag) cannedimports(file, p) // Reset incannedimport flag (we are not truly in a // canned import) - this will cause importpkg.Direct to // be set via parser.import_package (was issue #13977). // // TODO(gri) Remove this global variable and convoluted // code in the process of streamlining the import code. incannedimport = 0 default: Yyerror("no import in %q", f.U.(string)) } }
func importfile(f *Val, indent []byte) { if importpkg != nil { Fatalf("importpkg not nil") } path_, ok := f.U.(string) if !ok { Yyerror("import statement not a string") return } if len(path_) == 0 { Yyerror("import path is empty") return } if isbadimport(path_) { return } // The package name main is no longer reserved, // but we reserve the import path "main" to identify // the main package, just as we reserve the import // path "math" to identify the standard math package. if path_ == "main" { Yyerror("cannot import \"main\"") errorexit() } if myimportpath != "" && path_ == myimportpath { Yyerror("import %q while compiling that package (import cycle)", path_) errorexit() } if mapped, ok := importMap[path_]; ok { path_ = mapped } if path_ == "unsafe" { if safemode != 0 { Yyerror("cannot import package unsafe") errorexit() } importpkg = unsafepkg imported_unsafe = true return } if islocalname(path_) { if path_[0] == '/' { Yyerror("import path cannot be absolute path") return } prefix := Ctxt.Pathname if localimport != "" { prefix = localimport } path_ = path.Join(prefix, path_) if isbadimport(path_) { return } } file, found := findpkg(path_) if !found { Yyerror("can't find import: %q", path_) errorexit() } importpkg = mkpkg(path_) if importpkg.Imported { return } importpkg.Imported = true imp, err := obj.Bopenr(file) if err != nil { Yyerror("can't open import: %q: %v", path_, err) errorexit() } defer obj.Bterm(imp) if strings.HasSuffix(file, ".a") { if !skiptopkgdef(imp) { Yyerror("import %s: not a package file", file) errorexit() } } // check object header p := obj.Brdstr(imp, '\n', 1) if p != "empty archive" { if !strings.HasPrefix(p, "go object ") { Yyerror("import %s: not a go object file", file) errorexit() } q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) if p[10:] != q { Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q) errorexit() } } // assume files move (get installed) // so don't record the full path. linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib // In the importfile, if we find: // $$\n (old format): position the input right after $$\n and return // $$B\n (new format): import directly, then feed the lexer a dummy statement // look for $$ var c int for { c = obj.Bgetc(imp) if c < 0 { break } if c == '$' { c = obj.Bgetc(imp) if c == '$' || c < 0 { break } } } // get character after $$ if c >= 0 { c = obj.Bgetc(imp) } switch c { case '\n': // old export format parse_import(imp, indent) case 'B': // new export format obj.Bgetc(imp) // skip \n after $$B Import(imp) default: Yyerror("no import in %q", path_) errorexit() } if safemode != 0 && !importpkg.Safe { Yyerror("cannot import unsafe package %q", importpkg.Path) } }