1
2
3
4
5 package pkginit
6
7 import (
8 "bytes"
9 "container/heap"
10 "fmt"
11
12 "cmd/compile/internal/base"
13 "cmd/compile/internal/ir"
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 const (
58 InitNotStarted = iota
59 InitDone
60 InitPending
61 )
62
63 type InitOrder struct {
64
65
66 blocking map[ir.Node][]ir.Node
67
68
69
70 ready declOrder
71
72 order map[ir.Node]int
73 }
74
75
76
77
78
79 func initOrder(l []ir.Node) []ir.Node {
80 var res ir.Nodes
81 o := InitOrder{
82 blocking: make(map[ir.Node][]ir.Node),
83 order: make(map[ir.Node]int),
84 }
85
86
87 for _, n := range l {
88 switch n.Op() {
89 case ir.OAS, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
90 o.processAssign(n)
91 o.flushReady(func(n ir.Node) { res.Append(n) })
92 case ir.ODCLCONST, ir.ODCLFUNC, ir.ODCLTYPE:
93
94 default:
95 base.Fatalf("unexpected package-level statement: %v", n)
96 }
97 }
98
99
100
101 for _, n := range l {
102 switch n.Op() {
103 case ir.OAS, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
104 if o.order[n] != orderDone {
105
106
107
108
109
110 base.ExitIfErrors()
111
112 o.findInitLoopAndExit(firstLHS(n), new([]*ir.Name), new(ir.NameSet))
113 base.Fatalf("initialization unfinished, but failed to identify loop")
114 }
115 }
116 }
117
118
119
120 if len(o.blocking) != 0 {
121 base.Fatalf("expected empty map: %v", o.blocking)
122 }
123
124 return res
125 }
126
127 func (o *InitOrder) processAssign(n ir.Node) {
128 if _, ok := o.order[n]; ok {
129 base.Fatalf("unexpected state: %v, %v", n, o.order[n])
130 }
131 o.order[n] = 0
132
133
134
135 for dep := range collectDeps(n, true) {
136 defn := dep.Defn
137
138
139 if dep.Class != ir.PEXTERN || o.order[defn] == orderDone {
140 continue
141 }
142 o.order[n]++
143 o.blocking[defn] = append(o.blocking[defn], n)
144 }
145
146 if o.order[n] == 0 {
147 heap.Push(&o.ready, n)
148 }
149 }
150
151 const orderDone = -1000
152
153
154
155
156 func (o *InitOrder) flushReady(initialize func(ir.Node)) {
157 for o.ready.Len() != 0 {
158 n := heap.Pop(&o.ready).(ir.Node)
159 if order, ok := o.order[n]; !ok || order != 0 {
160 base.Fatalf("unexpected state: %v, %v, %v", n, ok, order)
161 }
162
163 initialize(n)
164 o.order[n] = orderDone
165
166 blocked := o.blocking[n]
167 delete(o.blocking, n)
168
169 for _, m := range blocked {
170 if o.order[m]--; o.order[m] == 0 {
171 heap.Push(&o.ready, m)
172 }
173 }
174 }
175 }
176
177
178
179
180
181
182
183 func (o *InitOrder) findInitLoopAndExit(n *ir.Name, path *[]*ir.Name, ok *ir.NameSet) {
184 for i, x := range *path {
185 if x == n {
186 reportInitLoopAndExit((*path)[i:])
187 return
188 }
189 }
190
191
192
193 refers := collectDeps(n.Defn, false).Sorted(func(ni, nj *ir.Name) bool {
194 return ni.Pos().Before(nj.Pos())
195 })
196
197 *path = append(*path, n)
198 for _, ref := range refers {
199
200 if ref.Class == ir.PEXTERN && o.order[ref.Defn] == orderDone || ok.Has(ref) {
201 continue
202 }
203
204 o.findInitLoopAndExit(ref, path, ok)
205 }
206
207
208
209
210
211 ok.Add(n)
212
213 *path = (*path)[:len(*path)-1]
214 }
215
216
217
218
219 func reportInitLoopAndExit(l []*ir.Name) {
220
221
222 i := -1
223 for j, n := range l {
224 if n.Class == ir.PEXTERN && (i == -1 || n.Pos().Before(l[i].Pos())) {
225 i = j
226 }
227 }
228 if i == -1 {
229
230
231
232 return
233 }
234 l = append(l[i:], l[:i]...)
235
236
237
238
239 var msg bytes.Buffer
240 fmt.Fprintf(&msg, "initialization loop:\n")
241 for _, n := range l {
242 fmt.Fprintf(&msg, "\t%v: %v refers to\n", ir.Line(n), n)
243 }
244 fmt.Fprintf(&msg, "\t%v: %v", ir.Line(l[0]), l[0])
245
246 base.ErrorfAt(l[0].Pos(), msg.String())
247 base.ErrorExit()
248 }
249
250
251
252
253
254 func collectDeps(n ir.Node, transitive bool) ir.NameSet {
255 d := initDeps{transitive: transitive}
256 switch n.Op() {
257 case ir.OAS:
258 n := n.(*ir.AssignStmt)
259 d.inspect(n.Y)
260 case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV:
261 n := n.(*ir.AssignListStmt)
262 d.inspect(n.Rhs[0])
263 case ir.ODCLFUNC:
264 n := n.(*ir.Func)
265 d.inspectList(n.Body)
266 default:
267 base.Fatalf("unexpected Op: %v", n.Op())
268 }
269 return d.seen
270 }
271
272 type initDeps struct {
273 transitive bool
274 seen ir.NameSet
275 cvisit func(ir.Node)
276 }
277
278 func (d *initDeps) cachedVisit() func(ir.Node) {
279 if d.cvisit == nil {
280 d.cvisit = d.visit
281 }
282 return d.cvisit
283 }
284
285 func (d *initDeps) inspect(n ir.Node) { ir.Visit(n, d.cachedVisit()) }
286 func (d *initDeps) inspectList(l ir.Nodes) { ir.VisitList(l, d.cachedVisit()) }
287
288
289
290 func (d *initDeps) visit(n ir.Node) {
291 switch n.Op() {
292 case ir.ONAME:
293 n := n.(*ir.Name)
294 switch n.Class {
295 case ir.PEXTERN, ir.PFUNC:
296 d.foundDep(n)
297 }
298
299 case ir.OCLOSURE:
300 n := n.(*ir.ClosureExpr)
301 d.inspectList(n.Func.Body)
302
303 case ir.ODOTMETH, ir.OMETHVALUE, ir.OMETHEXPR:
304 d.foundDep(ir.MethodExprName(n))
305 }
306 }
307
308
309
310 func (d *initDeps) foundDep(n *ir.Name) {
311
312
313 if n == nil {
314 return
315 }
316
317
318
319 if n.Defn == nil {
320 return
321 }
322
323 if d.seen.Has(n) {
324 return
325 }
326 d.seen.Add(n)
327 if d.transitive && n.Class == ir.PFUNC {
328 d.inspectList(n.Defn.(*ir.Func).Body)
329 }
330 }
331
332
333
334
335
336
337
338
339 type declOrder []ir.Node
340
341 func (s declOrder) Len() int { return len(s) }
342 func (s declOrder) Less(i, j int) bool {
343 return firstLHS(s[i]).Pos().Before(firstLHS(s[j]).Pos())
344 }
345 func (s declOrder) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
346
347 func (s *declOrder) Push(x interface{}) { *s = append(*s, x.(ir.Node)) }
348 func (s *declOrder) Pop() interface{} {
349 n := (*s)[len(*s)-1]
350 *s = (*s)[:len(*s)-1]
351 return n
352 }
353
354
355
356 func firstLHS(n ir.Node) *ir.Name {
357 switch n.Op() {
358 case ir.OAS:
359 n := n.(*ir.AssignStmt)
360 return n.X.Name()
361 case ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2RECV, ir.OAS2MAPR:
362 n := n.(*ir.AssignListStmt)
363 return n.Lhs[0].Name()
364 }
365
366 base.Fatalf("unexpected Op: %v", n.Op())
367 return nil
368 }
369
View as plain text