summaryrefslogtreecommitdiffstats
path: root/src/cmd/compile/internal/gc/init.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/gc/init.go')
-rw-r--r--src/cmd/compile/internal/gc/init.go109
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)
+}