Source file
src/go/types/initorder.go
1
2
3
4
5
6
7
8 package types
9
10 import (
11 "container/heap"
12 "fmt"
13 . "internal/types/errors"
14 "sort"
15 )
16
17
18 func (check *Checker) initOrder() {
19
20
21 check.Info.InitOrder = check.Info.InitOrder[:0]
22
23
24
25 pq := nodeQueue(dependencyGraph(check.objMap))
26 heap.Init(&pq)
27
28 const debug = false
29 if debug {
30 fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
31 fmt.Println("Object dependency graph:")
32 for obj, d := range check.objMap {
33
34 if obj, _ := obj.(dependency); obj != nil {
35 if len(d.deps) > 0 {
36 fmt.Printf("\t%s depends on\n", obj.Name())
37 for dep := range d.deps {
38 fmt.Printf("\t\t%s\n", dep.Name())
39 }
40 } else {
41 fmt.Printf("\t%s has no dependencies\n", obj.Name())
42 }
43 }
44 }
45 fmt.Println()
46
47 fmt.Println("Transposed object dependency graph (functions eliminated):")
48 for _, n := range pq {
49 fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.ndeps)
50 for p := range n.pred {
51 fmt.Printf("\t\t%s is dependent\n", p.obj.Name())
52 }
53 }
54 fmt.Println()
55
56 fmt.Println("Processing nodes:")
57 }
58
59
60
61
62
63
64
65 emitted := make(map[*declInfo]bool)
66 for len(pq) > 0 {
67
68 n := heap.Pop(&pq).(*graphNode)
69
70 if debug {
71 fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
72 n.obj.Name(), n.obj.order(), n.ndeps)
73 }
74
75
76 if n.ndeps > 0 {
77 cycle := findPath(check.objMap, n.obj, n.obj, make(map[Object]bool))
78
79
80
81
82
83
84
85
86 if cycle != nil {
87 check.reportCycle(cycle)
88 }
89
90
91
92 }
93
94
95
96 for p := range n.pred {
97 p.ndeps--
98 heap.Fix(&pq, p.index)
99 }
100
101
102 v, _ := n.obj.(*Var)
103 info := check.objMap[v]
104 if v == nil || !info.hasInitializer() {
105 continue
106 }
107
108
109
110
111
112 if emitted[info] {
113 continue
114 }
115 emitted[info] = true
116
117 infoLhs := info.lhs
118 if infoLhs == nil {
119 infoLhs = []*Var{v}
120 }
121 init := &Initializer{infoLhs, info.init}
122 check.Info.InitOrder = append(check.Info.InitOrder, init)
123 }
124
125 if debug {
126 fmt.Println()
127 fmt.Println("Initialization order:")
128 for _, init := range check.Info.InitOrder {
129 fmt.Printf("\t%s\n", init)
130 }
131 fmt.Println()
132 }
133 }
134
135
136
137
138 func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool) []Object {
139 if seen[from] {
140 return nil
141 }
142 seen[from] = true
143
144 for d := range objMap[from].deps {
145 if d == to {
146 return []Object{d}
147 }
148 if P := findPath(objMap, d, to, seen); P != nil {
149 return append(P, d)
150 }
151 }
152
153 return nil
154 }
155
156
157 func (check *Checker) reportCycle(cycle []Object) {
158 obj := cycle[0]
159
160
161 if len(cycle) == 1 {
162 check.errorf(obj, InvalidInitCycle, "initialization cycle: %s refers to itself", obj.Name())
163 return
164 }
165
166 err := check.newError(InvalidInitCycle)
167 err.addf(obj, "initialization cycle for %s", obj.Name())
168
169 for i := len(cycle) - 1; i >= 0; i-- {
170 err.addf(obj, "%s refers to", obj.Name())
171 obj = cycle[i]
172 }
173
174 err.addf(obj, "%s", obj.Name())
175 err.report()
176 }
177
178
179
180
181
182
183
184
185 type dependency interface {
186 Object
187 isDependency()
188 }
189
190
191
192
193
194 type graphNode struct {
195 obj dependency
196 pred, succ nodeSet
197 index int
198 ndeps int
199 }
200
201
202
203 func (n *graphNode) cost() int {
204 return len(n.pred) * len(n.succ)
205 }
206
207 type nodeSet map[*graphNode]bool
208
209 func (s *nodeSet) add(p *graphNode) {
210 if *s == nil {
211 *s = make(nodeSet)
212 }
213 (*s)[p] = true
214 }
215
216
217
218
219 func dependencyGraph(objMap map[Object]*declInfo) []*graphNode {
220
221 M := make(map[dependency]*graphNode)
222 for obj := range objMap {
223
224 if obj, _ := obj.(dependency); obj != nil {
225 M[obj] = &graphNode{obj: obj}
226 }
227 }
228
229
230
231
232 for obj, n := range M {
233
234 for d := range objMap[obj].deps {
235
236 if d, _ := d.(dependency); d != nil {
237 d := M[d]
238 n.succ.add(d)
239 d.pred.add(n)
240 }
241 }
242 }
243
244 var G, funcG []*graphNode
245 for _, n := range M {
246 if _, ok := n.obj.(*Func); ok {
247 funcG = append(funcG, n)
248 } else {
249 G = append(G, n)
250 }
251 }
252
253
254
255
256
257
258
259
260
261
262
263 sort.Slice(funcG, func(i, j int) bool {
264 return funcG[i].cost() < funcG[j].cost()
265 })
266 for _, n := range funcG {
267
268
269 for p := range n.pred {
270
271 if p != n {
272
273
274 for s := range n.succ {
275
276 if s != n {
277 p.succ.add(s)
278 s.pred.add(p)
279 }
280 }
281 delete(p.succ, n)
282 }
283 }
284 for s := range n.succ {
285 delete(s.pred, n)
286 }
287 }
288
289
290 for i, n := range G {
291 n.index = i
292 n.ndeps = len(n.succ)
293 }
294
295 return G
296 }
297
298
299
300
301
302
303 type nodeQueue []*graphNode
304
305 func (a nodeQueue) Len() int { return len(a) }
306
307 func (a nodeQueue) Swap(i, j int) {
308 x, y := a[i], a[j]
309 a[i], a[j] = y, x
310 x.index, y.index = j, i
311 }
312
313 func (a nodeQueue) Less(i, j int) bool {
314 x, y := a[i], a[j]
315
316
317 _, xConst := x.obj.(*Const)
318 _, yConst := y.obj.(*Const)
319 if xConst != yConst {
320 return xConst
321 }
322
323
324
325 return x.ndeps < y.ndeps || x.ndeps == y.ndeps && x.obj.order() < y.obj.order()
326 }
327
328 func (a *nodeQueue) Push(x any) {
329 panic("unreachable")
330 }
331
332 func (a *nodeQueue) Pop() any {
333 n := len(*a)
334 x := (*a)[n-1]
335 x.index = -1
336 *a = (*a)[:n-1]
337 return x
338 }
339
View as plain text