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