blob: 2805f3930b4fa5e422ce732c17bcc64c38dfb35f [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// 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 "fmt"
8
9// case OADD:
10// if(n->right->op == OLITERAL) {
11// v = n->right->vconst;
12// naddr(n->left, a, canemitcode);
13// } else
14// if(n->left->op == OLITERAL) {
15// v = n->left->vconst;
16// naddr(n->right, a, canemitcode);
17// } else
18// goto bad;
19// a->offset += v;
20// break;
21
22/*
23 * a function named init is a special case.
24 * it is called by the initialization before
25 * main is run. to make it unique within a
26 * package and also uncallable, the name,
27 * normally "pkg.init", is altered to "pkg.init·1".
28 */
29
30var renameinit_initgen int
31
32func renameinit() *Sym {
33 renameinit_initgen++
34 namebuf = fmt.Sprintf("init·%d", renameinit_initgen)
35 return Lookup(namebuf)
36}
37
38/*
39 * hand-craft the following initialization code
40 * var initdone· uint8 (1)
41 * func init() (2)
42 * if initdone· != 0 { (3)
43 * if initdone· == 2 (4)
44 * return
45 * throw(); (5)
46 * }
47 * initdone· = 1; (6)
48 * // over all matching imported symbols
49 * <pkg>.init() (7)
50 * { <init stmts> } (8)
51 * init·<n>() // if any (9)
52 * initdone· = 2; (10)
53 * return (11)
54 * }
55 */
Russ Coxdc7b54b2015-02-17 22:13:49 -050056func anyinit(n *NodeList) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -050057 var h uint32
58 var s *Sym
59 var l *NodeList
60
61 // are there any interesting init statements
62 for l = n; l != nil; l = l.Next {
63 switch l.N.Op {
64 case ODCLFUNC,
65 ODCLCONST,
66 ODCLTYPE,
67 OEMPTY:
68 break
69
70 case OAS:
Russ Coxdc7b54b2015-02-17 22:13:49 -050071 if isblank(l.N.Left) && candiscard(l.N.Right) {
Russ Cox8c195bd2015-02-13 14:40:36 -050072 break
73 }
74 fallthrough
75
76 // fall through
77 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -050078 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050079 }
80 }
81
82 // is this main
83 if localpkg.Name == "main" {
Russ Coxdc7b54b2015-02-17 22:13:49 -050084 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050085 }
86
87 // is there an explicit init function
88 namebuf = fmt.Sprintf("init·1")
89
90 s = Lookup(namebuf)
91 if s.Def != nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -050092 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050093 }
94
95 // are there any imported init functions
96 for h = 0; h < NHASH; h++ {
97 for s = hash[h]; s != nil; s = s.Link {
98 if s.Name[0] != 'i' || s.Name != "init" {
99 continue
100 }
101 if s.Def == nil {
102 continue
103 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500104 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500105 }
106 }
107
108 // then none
Russ Coxdc7b54b2015-02-17 22:13:49 -0500109 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500110}
111
112func fninit(n *NodeList) {
113 var i int
114 var gatevar *Node
115 var a *Node
116 var b *Node
117 var fn *Node
118 var r *NodeList
119 var h uint32
120 var s *Sym
121 var initsym *Sym
122
123 if Debug['A'] != 0 {
124 // sys.go or unsafe.go during compiler build
125 return
126 }
127
128 n = initfix(n)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500129 if !anyinit(n) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500130 return
131 }
132
133 r = nil
134
135 // (1)
136 namebuf = fmt.Sprintf("initdone·")
137
138 gatevar = newname(Lookup(namebuf))
139 addvar(gatevar, Types[TUINT8], PEXTERN)
140
141 // (2)
142 Maxarg = 0
143
144 namebuf = fmt.Sprintf("init")
145
146 fn = Nod(ODCLFUNC, nil, nil)
147 initsym = Lookup(namebuf)
148 fn.Nname = newname(initsym)
149 fn.Nname.Defn = fn
150 fn.Nname.Ntype = Nod(OTFUNC, nil, nil)
151 declare(fn.Nname, PFUNC)
152 funchdr(fn)
153
154 // (3)
155 a = Nod(OIF, nil, nil)
156
157 a.Ntest = Nod(ONE, gatevar, Nodintconst(0))
158 r = list(r, a)
159
160 // (4)
161 b = Nod(OIF, nil, nil)
162
163 b.Ntest = Nod(OEQ, gatevar, Nodintconst(2))
164 b.Nbody = list1(Nod(ORETURN, nil, nil))
165 a.Nbody = list1(b)
166
167 // (5)
168 b = syslook("throwinit", 0)
169
170 b = Nod(OCALL, b, nil)
171 a.Nbody = list(a.Nbody, b)
172
173 // (6)
174 a = Nod(OAS, gatevar, Nodintconst(1))
175
176 r = list(r, a)
177
178 // (7)
179 for h = 0; h < NHASH; h++ {
180 for s = hash[h]; s != nil; s = s.Link {
181 if s.Name[0] != 'i' || s.Name != "init" {
182 continue
183 }
184 if s.Def == nil {
185 continue
186 }
187 if s == initsym {
188 continue
189 }
190
191 // could check that it is fn of no args/returns
192 a = Nod(OCALL, s.Def, nil)
193
194 r = list(r, a)
195 }
196 }
197
198 // (8)
199 r = concat(r, n)
200
201 // (9)
202 // could check that it is fn of no args/returns
203 for i = 1; ; i++ {
204 namebuf = fmt.Sprintf("init·%d", i)
205 s = Lookup(namebuf)
206 if s.Def == nil {
207 break
208 }
209 a = Nod(OCALL, s.Def, nil)
210 r = list(r, a)
211 }
212
213 // (10)
214 a = Nod(OAS, gatevar, Nodintconst(2))
215
216 r = list(r, a)
217
218 // (11)
219 a = Nod(ORETURN, nil, nil)
220
221 r = list(r, a)
222 exportsym(fn.Nname)
223
224 fn.Nbody = r
225 funcbody(fn)
226
227 Curfn = fn
228 typecheck(&fn, Etop)
229 typechecklist(r, Etop)
230 Curfn = nil
231 funccompile(fn)
232}