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