diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/init.go')
-rw-r--r-- | src/cmd/compile/internal/gc/init.go | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go new file mode 100644 index 0000000..ec9cc4b --- /dev/null +++ b/src/cmd/compile/internal/gc/init.go @@ -0,0 +1,109 @@ +// 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 + xtop = append(xtop, 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") + } + dummyInitFn = nil + + // 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. + if fn.Nbody.Len() == 1 && fn.Nbody.First().Op == OEMPTY { + 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) +} |