| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package gc |
| |
| import ( |
| "cmd/compile/internal/types" |
| "cmd/internal/obj" |
| ) |
| |
| // A function named init is a special case. |
| // It is called by the initialization before main is run. |
| // To make it unique within a package and also uncallable, |
| // the name, normally "pkg.init", is altered to "pkg.init.0". |
| var renameinitgen int |
| |
| // Dummy function for autotmps generated during typechecking. |
| var dummyInitFn = nod(ODCLFUNC, nil, nil) |
| |
| func renameinit() *types.Sym { |
| s := lookupN("init.", renameinitgen) |
| renameinitgen++ |
| return s |
| } |
| |
| // fninit makes an initialization record for the package. |
| // See runtime/proc.go:initTask for its layout. |
| // The 3 tasks for initialization are: |
| // 1) Initialize all of the packages the current package depends on. |
| // 2) Initialize all the variables that have initializers. |
| // 3) Run any init functions. |
| func fninit(n []*Node) { |
| nf := initOrder(n) |
| |
| var deps []*obj.LSym // initTask records for packages the current package depends on |
| var fns []*obj.LSym // functions to call for package initialization |
| |
| // Find imported packages with init tasks. |
| for _, s := range types.InitSyms { |
| deps = append(deps, s.Linksym()) |
| } |
| |
| // Make a function that contains all the initialization statements. |
| if len(nf) > 0 { |
| lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt |
| initializers := lookup("init") |
| disableExport(initializers) |
| fn := dclfunc(initializers, nod(OTFUNC, nil, nil)) |
| for _, dcl := range dummyInitFn.Func.Dcl { |
| dcl.Name.Curfn = fn |
| } |
| fn.Func.Dcl = append(fn.Func.Dcl, dummyInitFn.Func.Dcl...) |
| dummyInitFn.Func.Dcl = nil |
| |
| fn.Nbody.Set(nf) |
| funcbody() |
| |
| fn = typecheck(fn, ctxStmt) |
| Curfn = fn |
| typecheckslice(nf, ctxStmt) |
| Curfn = nil |
| funccompile(fn) |
| fns = append(fns, initializers.Linksym()) |
| } |
| if dummyInitFn.Func.Dcl != nil { |
| // We only generate temps using dummyInitFn if there |
| // are package-scope initialization statements, so |
| // something's weird if we get here. |
| Fatalf("dummyInitFn still has declarations") |
| } |
| |
| // Record user init functions. |
| for i := 0; i < renameinitgen; i++ { |
| s := lookupN("init.", i) |
| fn := asNode(s.Def).Name.Defn |
| // Skip init functions with empty bodies. |
| // noder.go doesn't allow external init functions, and |
| // order.go has already removed any OEMPTY nodes, so |
| // checking Len() == 0 is sufficient here. |
| if fn.Nbody.Len() == 0 { |
| continue |
| } |
| fns = append(fns, s.Linksym()) |
| } |
| |
| if len(deps) == 0 && len(fns) == 0 && localpkg.Name != "main" && localpkg.Name != "runtime" { |
| return // nothing to initialize |
| } |
| |
| // Make an .inittask structure. |
| sym := lookup(".inittask") |
| nn := newname(sym) |
| nn.Type = types.Types[TUINT8] // dummy type |
| nn.SetClass(PEXTERN) |
| sym.Def = asTypesNode(nn) |
| exportsym(nn) |
| lsym := sym.Linksym() |
| ot := 0 |
| ot = duintptr(lsym, ot, 0) // state: not initialized yet |
| ot = duintptr(lsym, ot, uint64(len(deps))) |
| ot = duintptr(lsym, ot, uint64(len(fns))) |
| for _, d := range deps { |
| ot = dsymptr(lsym, ot, d, 0) |
| } |
| for _, f := range fns { |
| ot = dsymptr(lsym, ot, f, 0) |
| } |
| // An initTask has pointers, but none into the Go heap. |
| // It's not quite read only, the state field must be modifiable. |
| ggloblsym(lsym, int32(ot), obj.NOPTR) |
| } |