aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/init.go
blob: 03e475e85a0c1b652ac4562f34d62e0f7dea35c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// 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)
}