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
5 #include "go.h"
6
7 /*
8 * a function named init is a special case.
9 * it is called by the initialization before
10 * main is run. to make it unique within a
11 * package and also uncallable, the name,
12 * normally "pkg.init", is altered to "pkg.init·1".
13 */
14 Node*
15 renameinit(Node *n)
16 {
17 Sym *s;
18 static int initgen;
19
20 s = n->sym;
21 if(s == S)
22 return n;
23 if(strcmp(s->name, "init") != 0)
24 return n;
25
26 snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
27 s = lookup(namebuf);
28 return newname(s);
29 }
30
31 /*
32 * hand-craft the following initialization code
33 * var initdone· uint8 (1)
34 * func init() (2)
35 * if initdone· != 0 { (3)
36 * if initdone· == 2 (4)
37 * return
38 * throw(); (5)
39 * }
40 * initdone· = 1; (6)
41 * // over all matching imported symbols
42 * <pkg>.init() (7)
43 * { <init stmts> } (8)
44 * init·<n>() // if any (9)
45 * initdone· = 2; (10)
46 * return (11)
47 * }
48 */
49 static int
50 anyinit(NodeList *n)
51 {
52 uint32 h;
53 Sym *s;
54 NodeList *l;
55
56 // are there any interesting init statements
57 for(l=n; l; l=l->next) {
58 switch(l->n->op) {
59 case ODCLFUNC:
60 case ODCLCONST:
61 case ODCLTYPE:
62 case OEMPTY:
63 break;
64 default:
65 return 1;
66 }
67 }
68
69 // is this main
70 if(strcmp(localpkg->name, "main") == 0)
71 return 1;
72
73 // is there an explicit init function
74 snprint(namebuf, sizeof(namebuf), "init·1");
75 s = lookup(namebuf);
76 if(s->def != N)
77 return 1;
78
79 // are there any imported init functions
80 for(h=0; h<NHASH; h++)
81 for(s = hash[h]; s != S; s = s->link) {
82 if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
83 continue;
84 if(s->def == N)
85 continue;
86 return 1;
87 }
88
89 // then none
90 return 0;
91 }
92
93 void
94 fninit(NodeList *n)
95 {
96 int i;
97 Node *gatevar;
98 Node *a, *b, *fn;
99 NodeList *r;
100 uint32 h;
101 Sym *s, *initsym;
102
103 if(debug['A']) {
104 // sys.go or unsafe.go during compiler build
105 return;
106 }
107
108 n = initfix(n);
109 if(!anyinit(n))
110 return;
111
112 r = nil;
113
114 // (1)
115 snprint(namebuf, sizeof(namebuf), "initdone·");
116 gatevar = newname(lookup(namebuf));
117 addvar(gatevar, types[TUINT8], PEXTERN);
118
119 // (2)
120 maxarg = 0;
121 snprint(namebuf, sizeof(namebuf), "init");
122
123 fn = nod(ODCLFUNC, N, N);
124 initsym = lookup(namebuf);
125 fn->nname = newname(initsym);
126 fn->nname->ntype = nod(OTFUNC, N, N);
127 funchdr(fn);
128
129 // (3)
130 a = nod(OIF, N, N);
131 a->ntest = nod(ONE, gatevar, nodintconst(0));
132 r = list(r, a);
133
134 // (4)
135 b = nod(OIF, N, N);
136 b->ntest = nod(OEQ, gatevar, nodintconst(2));
137 b->nbody = list1(nod(ORETURN, N, N));
138 a->nbody = list1(b);
139
140 // (5)
141 b = syslook("throwinit", 0);
142 b = nod(OCALL, b, N);
143 a->nbody = list(a->nbody, b);
144
145 // (6)
146 a = nod(OAS, gatevar, nodintconst(1));
147 r = list(r, a);
148
149 // (7)
150 for(h=0; h<NHASH; h++)
151 for(s = hash[h]; s != S; s = s->link) {
152 if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
153 continue;
154 if(s->def == N)
155 continue;
156 if(s == initsym)
157 continue;
158
159 // could check that it is fn of no args/returns
160 a = nod(OCALL, s->def, N);
161 r = list(r, a);
162 }
163
164 // (8)
165 r = concat(r, n);
166
167 // (9)
168 // could check that it is fn of no args/returns
169 for(i=1;; i++) {
170 snprint(namebuf, sizeof(namebuf), "init·%d", i);
171 s = lookup(namebuf);
172 if(s->def == N)
173 break;
174 a = nod(OCALL, s->def, N);
175 r = list(r, a);
176 }
177
178 // (10)
179 a = nod(OAS, gatevar, nodintconst(2));
180 r = list(r, a);
181
182 // (11)
183 a = nod(ORETURN, N, N);
184 r = list(r, a);
185 exportsym(fn->nname);
186
187 fn->nbody = r;
188 funcbody(fn);
189
190 curfn = fn;
191 typecheck(&fn, Etop);
192 typechecklist(r, Etop);
193 curfn = nil;
194 funccompile(fn, 0);
195 }