@@ -6,6 +6,7 @@ package gc
6
6
7
7
import (
8
8
"cmd/compile/internal/types"
9
+ "cmd/internal/obj"
9
10
)
10
11
11
12
// A function named init is a special case.
@@ -23,77 +24,29 @@ func renameinit() *types.Sym {
23
24
return s
24
25
}
25
26
26
- // anyinit reports whether there any interesting init statements.
27
- func anyinit (n []* Node ) bool {
28
- for _ , ln := range n {
29
- switch ln .Op {
30
- case ODCLFUNC , ODCLCONST , ODCLTYPE , OEMPTY :
31
- case OAS :
32
- if ! ln .Left .isBlank () || ! candiscard (ln .Right ) {
33
- return true
34
- }
35
- default :
36
- return true
37
- }
38
- }
39
-
40
- // is this main
41
- if localpkg .Name == "main" {
42
- return true
43
- }
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.
33
+ func fninit (n []* Node ) {
34
+ nf := initfix (n )
44
35
45
- // is there an explicit init function
46
- if renameinitgen > 0 {
47
- return true
48
- }
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
49
38
50
- // are there any imported init functions
51
- for _ , s := range types .InitSyms {
52
- if s . Def != nil {
53
- return true
39
+ // Find imported packages with init tasks.
40
+ for _ , p := range types .ImportedPkgList () {
41
+ if s , ok := p . LookupOK ( ".inittask" ); ok {
42
+ deps = append ( deps , s . Linksym ())
54
43
}
55
44
}
56
45
57
- // then none
58
- return false
59
- }
60
-
61
- // fninit hand-crafts package initialization code.
62
- //
63
- // func init.ializers() { (0)
64
- // <init stmts>
65
- // }
66
- // var initdone· uint8 (1)
67
- // func init() { (2)
68
- // if initdone· > 1 { (3)
69
- // return (3a)
70
- // }
71
- // if initdone· == 1 { (4)
72
- // throw() (4a)
73
- // }
74
- // initdone· = 1 (5)
75
- // // over all matching imported symbols
76
- // <pkg>.init() (6)
77
- // init.ializers() (7)
78
- // init.<n>() // if any (8)
79
- // initdone· = 2 (9)
80
- // return (10)
81
- // }
82
- func fninit (n []* Node ) {
83
- lineno = autogeneratedPos
84
- nf := initfix (n )
85
- if ! anyinit (nf ) {
86
- return
87
- }
88
-
89
- // (0)
90
46
// Make a function that contains all the initialization statements.
91
- // This is a separate function because we want it to appear in
92
- // stack traces, where the init function itself does not.
93
- var initializers * types.Sym
94
47
if len (nf ) > 0 {
95
48
lineno = nf [0 ].Pos // prolog/epilog gets line number of first init stmt
96
- initializers = lookup ("init.ializers" )
49
+ initializers : = lookup ("init.ializers" )
97
50
disableExport (initializers )
98
51
fn := dclfunc (initializers , nod (OTFUNC , nil , nil ))
99
52
for _ , dcl := range dummyInitFn .Func .Dcl {
@@ -110,7 +63,7 @@ func fninit(n []*Node) {
110
63
typecheckslice (nf , ctxStmt )
111
64
Curfn = nil
112
65
funccompile (fn )
113
- lineno = autogeneratedPos
66
+ fns = append ( fns , initializers . Linksym ())
114
67
}
115
68
if dummyInitFn .Func .Dcl != nil {
116
69
// We only generate temps using dummyInitFn if there
@@ -119,140 +72,37 @@ func fninit(n []*Node) {
119
72
Fatalf ("dummyInitFn still has declarations" )
120
73
}
121
74
122
- var r []* Node
123
-
124
- // (1)
125
- gatevar := newname (lookup ("initdone·" ))
126
- addvar (gatevar , types .Types [TUINT8 ], PEXTERN )
127
-
128
- // (2)
129
- initsym := lookup ("init" )
130
- fn := dclfunc (initsym , nod (OTFUNC , nil , nil ))
131
-
132
- // (3)
133
- a := nod (OIF , nil , nil )
134
- a .Left = nod (OGT , gatevar , nodintconst (1 ))
135
- a .SetLikely (true )
136
- r = append (r , a )
137
- // (3a)
138
- a .Nbody .Set1 (nod (ORETURN , nil , nil ))
139
-
140
- // (4)
141
- b := nod (OIF , nil , nil )
142
- b .Left = nod (OEQ , gatevar , nodintconst (1 ))
143
- // this actually isn't likely, but code layout is better
144
- // like this: no JMP needed after the call.
145
- b .SetLikely (true )
146
- r = append (r , b )
147
- // (4a)
148
- b .Nbody .Set1 (nod (OCALL , syslook ("throwinit" ), nil ))
149
-
150
- // (5)
151
- a = nod (OAS , gatevar , nodintconst (1 ))
152
-
153
- r = append (r , a )
154
-
155
- // (6)
156
- for _ , s := range types .InitSyms {
157
- if s == initsym {
158
- continue
159
- }
160
- n := resolve (oldname (s ))
161
- if n .Op == ONONAME {
162
- // No package-scope init function; just a
163
- // local variable, field name, or something.
164
- continue
165
- }
166
- n .checkInitFuncSignature ()
167
- a = nod (OCALL , n , nil )
168
- r = append (r , a )
75
+ // Record user init functions.
76
+ for i := 0 ; i < renameinitgen ; i ++ {
77
+ s := lookupN ("init." , i )
78
+ fns = append (fns , s .Linksym ())
169
79
}
170
80
171
- // (7)
172
- if initializers != nil {
173
- n := newname (initializers )
174
- addvar (n , functype (nil , nil , nil ), PFUNC )
175
- r = append (r , nod (OCALL , n , nil ))
81
+ if len (deps ) == 0 && len (fns ) == 0 && localpkg .Name != "main" && localpkg .Name != "runtime" {
82
+ return // nothing to initialize
176
83
}
177
84
178
- // (8)
179
-
180
- // maxInlineInitCalls is the threshold at which we switch
181
- // from generating calls inline to generating a static array
182
- // of functions and calling them in a loop.
183
- // See CL 41500 for more discussion.
184
- const maxInlineInitCalls = 500
185
-
186
- if renameinitgen < maxInlineInitCalls {
187
- // Not many init functions. Just call them all directly.
188
- for i := 0 ; i < renameinitgen ; i ++ {
189
- s := lookupN ("init." , i )
190
- n := asNode (s .Def )
191
- n .checkInitFuncSignature ()
192
- a = nod (OCALL , n , nil )
193
- r = append (r , a )
194
- }
195
- } else {
196
- // Lots of init functions.
197
- // Set up an array of functions and loop to call them.
198
- // This is faster to compile and similar at runtime.
199
-
200
- // Build type [renameinitgen]func().
201
- typ := types .NewArray (functype (nil , nil , nil ), int64 (renameinitgen ))
202
-
203
- // Make and fill array.
204
- fnarr := staticname (typ )
205
- fnarr .Name .SetReadonly (true )
206
- for i := 0 ; i < renameinitgen ; i ++ {
207
- s := lookupN ("init." , i )
208
- lhs := nod (OINDEX , fnarr , nodintconst (int64 (i )))
209
- rhs := asNode (s .Def )
210
- rhs .checkInitFuncSignature ()
211
- as := nod (OAS , lhs , rhs )
212
- as = typecheck (as , ctxStmt )
213
- genAsStatic (as )
214
- }
215
-
216
- // Generate a loop that calls each function in turn.
217
- // for i := 0; i < renameinitgen; i++ {
218
- // fnarr[i]()
219
- // }
220
- i := temp (types .Types [TINT ])
221
- fnidx := nod (OINDEX , fnarr , i )
222
- fnidx .SetBounded (true )
223
-
224
- zero := nod (OAS , i , nodintconst (0 ))
225
- cond := nod (OLT , i , nodintconst (int64 (renameinitgen )))
226
- incr := nod (OAS , i , nod (OADD , i , nodintconst (1 )))
227
- body := nod (OCALL , fnidx , nil )
228
-
229
- loop := nod (OFOR , cond , incr )
230
- loop .Nbody .Set1 (body )
231
- loop .Ninit .Set1 (zero )
232
-
233
- loop = typecheck (loop , ctxStmt )
234
- r = append (r , loop )
85
+ // Make an .inittask structure.
86
+ sym := lookup (".inittask" )
87
+ nn := newname (sym )
88
+ nn .Type = types .Types [TUINT8 ] // dummy type
89
+ nn .SetClass (PEXTERN )
90
+ sym .Def = asTypesNode (nn )
91
+ exportsym (nn )
92
+ lsym := sym .Linksym ()
93
+ ot := 0
94
+ ot = duintptr (lsym , ot , 0 ) // state: not initialized yet
95
+ ot = duintptr (lsym , ot , uint64 (len (deps )))
96
+ ot = duintptr (lsym , ot , uint64 (len (fns )))
97
+ for _ , d := range deps {
98
+ ot = dsymptr (lsym , ot , d , 0 )
235
99
}
236
-
237
- // (9)
238
- a = nod (OAS , gatevar , nodintconst (2 ))
239
-
240
- r = append (r , a )
241
-
242
- // (10)
243
- a = nod (ORETURN , nil , nil )
244
-
245
- r = append (r , a )
246
- exportsym (fn .Func .Nname )
247
-
248
- fn .Nbody .Set (r )
249
- funcbody ()
250
-
251
- Curfn = fn
252
- fn = typecheck (fn , ctxStmt )
253
- typecheckslice (r , ctxStmt )
254
- Curfn = nil
255
- funccompile (fn )
100
+ for _ , f := range fns {
101
+ ot = dsymptr (lsym , ot , f , 0 )
102
+ }
103
+ // An initTask has pointers, but none into the Go heap.
104
+ // It's not quite read only, the state field must be modifiable.
105
+ ggloblsym (lsym , int32 (ot ), obj .NOPTR )
256
106
}
257
107
258
108
func (n * Node ) checkInitFuncSignature () {
0 commit comments