// 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") 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) }