1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package gc
6
7import (
8	"cmd/compile/internal/types"
9	"cmd/internal/obj"
10)
11
12// A function named init is a special case.
13// It is called by the initialization before main is run.
14// To make it unique within a package and also uncallable,
15// the name, normally "pkg.init", is altered to "pkg.init.0".
16var renameinitgen int
17
18// Dummy function for autotmps generated during typechecking.
19var dummyInitFn = nod(ODCLFUNC, nil, nil)
20
21func renameinit() *types.Sym {
22	s := lookupN("init.", renameinitgen)
23	renameinitgen++
24	return s
25}
26
27// fninit makes an initialization record for the package.
28// See runtime/proc.go:initTask for its layout.
29// The 3 tasks for initialization are:
30//   1) Initialize all of the packages the current package depends on.
31//   2) Initialize all the variables that have initializers.
32//   3) Run any init functions.
33func fninit(n []*Node) {
34	nf := initOrder(n)
35
36	var deps []*obj.LSym // initTask records for packages the current package depends on
37	var fns []*obj.LSym  // functions to call for package initialization
38
39	// Find imported packages with init tasks.
40	for _, s := range types.InitSyms {
41		deps = append(deps, s.Linksym())
42	}
43
44	// Make a function that contains all the initialization statements.
45	if len(nf) > 0 {
46		lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt
47		initializers := lookup("init")
48		disableExport(initializers)
49		fn := dclfunc(initializers, nod(OTFUNC, nil, nil))
50		for _, dcl := range dummyInitFn.Func.Dcl {
51			dcl.Name.Curfn = fn
52		}
53		fn.Func.Dcl = append(fn.Func.Dcl, dummyInitFn.Func.Dcl...)
54		dummyInitFn.Func.Dcl = nil
55
56		fn.Nbody.Set(nf)
57		funcbody()
58
59		fn = typecheck(fn, ctxStmt)
60		Curfn = fn
61		typecheckslice(nf, ctxStmt)
62		Curfn = nil
63		funccompile(fn)
64		fns = append(fns, initializers.Linksym())
65	}
66	if dummyInitFn.Func.Dcl != nil {
67		// We only generate temps using dummyInitFn if there
68		// are package-scope initialization statements, so
69		// something's weird if we get here.
70		Fatalf("dummyInitFn still has declarations")
71	}
72
73	// Record user init functions.
74	for i := 0; i < renameinitgen; i++ {
75		s := lookupN("init.", i)
76		fn := asNode(s.Def).Name.Defn
77		// Skip init functions with empty bodies.
78		// noder.go doesn't allow external init functions, and
79		// order.go has already removed any OEMPTY nodes, so
80		// checking Len() == 0 is sufficient here.
81		if fn.Nbody.Len() == 0 {
82			continue
83		}
84		fns = append(fns, s.Linksym())
85	}
86
87	if len(deps) == 0 && len(fns) == 0 && localpkg.Name != "main" && localpkg.Name != "runtime" {
88		return // nothing to initialize
89	}
90
91	// Make an .inittask structure.
92	sym := lookup(".inittask")
93	nn := newname(sym)
94	nn.Type = types.Types[TUINT8] // dummy type
95	nn.SetClass(PEXTERN)
96	sym.Def = asTypesNode(nn)
97	exportsym(nn)
98	lsym := sym.Linksym()
99	ot := 0
100	ot = duintptr(lsym, ot, 0) // state: not initialized yet
101	ot = duintptr(lsym, ot, uint64(len(deps)))
102	ot = duintptr(lsym, ot, uint64(len(fns)))
103	for _, d := range deps {
104		ot = dsymptr(lsym, ot, d, 0)
105	}
106	for _, f := range fns {
107		ot = dsymptr(lsym, ot, f, 0)
108	}
109	// An initTask has pointers, but none into the Go heap.
110	// It's not quite read only, the state field must be modifiable.
111	ggloblsym(lsym, int32(ot), obj.NOPTR)
112}
113