blob: 03e475e85a0c1b652ac4562f34d62e0f7dea35c7 [file] [log] [blame]
// 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)
}