1
2
3
4
5 package pointer
6
7
8
9
10 import (
11 "fmt"
12 "go/types"
13 )
14
15 type solverState struct {
16 complex []constraint
17 copyTo nodeset
18 pts nodeset
19 prevPTS nodeset
20 }
21
22 func (a *analysis) solve() {
23 start("Solving")
24 if a.log != nil {
25 fmt.Fprintf(a.log, "\n\n==== Solving constraints\n\n")
26 }
27
28
29 var delta nodeset
30 for {
31
32
33
34 a.processNewConstraints()
35
36 var x int
37 if !a.work.TakeMin(&x) {
38 break
39 }
40 id := nodeid(x)
41 if a.log != nil {
42 fmt.Fprintf(a.log, "\tnode n%d\n", id)
43 }
44
45 n := a.nodes[id]
46
47
48 delta.Difference(&n.solve.pts.Sparse, &n.solve.prevPTS.Sparse)
49 if delta.IsEmpty() {
50 continue
51 }
52 if a.log != nil {
53 fmt.Fprintf(a.log, "\t\tpts(n%d : %s) = %s + %s\n",
54 id, n.typ, &delta, &n.solve.prevPTS)
55 }
56 n.solve.prevPTS.Copy(&n.solve.pts.Sparse)
57
58
59 a.solveConstraints(n, &delta)
60
61 if a.log != nil {
62 fmt.Fprintf(a.log, "\t\tpts(n%d) = %s\n", id, &n.solve.pts)
63 }
64 }
65
66 if !a.nodes[0].solve.pts.IsEmpty() {
67 panic(fmt.Sprintf("pts(0) is nonempty: %s", &a.nodes[0].solve.pts))
68 }
69
70
71 for _, n := range a.nodes {
72 n.solve.complex = nil
73 n.solve.copyTo.Clear()
74 n.solve.prevPTS.Clear()
75 }
76
77 if a.log != nil {
78 fmt.Fprintf(a.log, "Solver done\n")
79
80
81 for i, n := range a.nodes {
82 if !n.solve.pts.IsEmpty() {
83 fmt.Fprintf(a.log, "pts(n%d) = %s : %s\n", i, &n.solve.pts, n.typ)
84 }
85 }
86 }
87 stop("Solving")
88 }
89
90
91
92
93
94 func (a *analysis) processNewConstraints() {
95
96
97 constraints := a.constraints
98 a.constraints = nil
99
100
101 for _, c := range constraints {
102 if c, ok := c.(*addrConstraint); ok {
103 dst := a.nodes[c.dst]
104 dst.solve.pts.add(c.src)
105
106
107
108
109
110 if !dst.solve.copyTo.IsEmpty() || len(dst.solve.complex) > 0 {
111 a.addWork(c.dst)
112 }
113 }
114 }
115
116
117 var stale nodeset
118 for _, c := range constraints {
119 var id nodeid
120 switch c := c.(type) {
121 case *addrConstraint:
122
123 continue
124 case *copyConstraint:
125
126 id = c.src
127 a.nodes[id].solve.copyTo.add(c.dst)
128 default:
129
130 id = c.ptr()
131 solve := a.nodes[id].solve
132 solve.complex = append(solve.complex, c)
133 }
134
135 if n := a.nodes[id]; !n.solve.pts.IsEmpty() {
136 if !n.solve.prevPTS.IsEmpty() {
137 stale.add(id)
138 }
139 a.addWork(id)
140 }
141 }
142
143 var space [50]int
144 for _, id := range stale.AppendTo(space[:0]) {
145 n := a.nodes[nodeid(id)]
146 a.solveConstraints(n, &n.solve.prevPTS)
147 }
148 }
149
150
151
152
153 func (a *analysis) solveConstraints(n *node, delta *nodeset) {
154 if delta.IsEmpty() {
155 return
156 }
157
158
159 for _, c := range n.solve.complex {
160 if a.log != nil {
161 fmt.Fprintf(a.log, "\t\tconstraint %s\n", c)
162 }
163 c.solve(a, delta)
164 }
165
166
167 var copySeen nodeset
168 for _, x := range n.solve.copyTo.AppendTo(a.deltaSpace) {
169 mid := nodeid(x)
170 if copySeen.add(mid) {
171 if a.nodes[mid].solve.pts.addAll(delta) {
172 a.addWork(mid)
173 }
174 }
175 }
176 }
177
178
179 func (a *analysis) addLabel(ptr, label nodeid) bool {
180 b := a.nodes[ptr].solve.pts.add(label)
181 if b && a.log != nil {
182 fmt.Fprintf(a.log, "\t\tpts(n%d) += n%d\n", ptr, label)
183 }
184 return b
185 }
186
187 func (a *analysis) addWork(id nodeid) {
188 a.work.Insert(int(id))
189 if a.log != nil {
190 fmt.Fprintf(a.log, "\t\twork: n%d\n", id)
191 }
192 }
193
194
195
196
197
198
199
200 func (a *analysis) onlineCopy(dst, src nodeid) bool {
201 if dst != src {
202 if nsrc := a.nodes[src]; nsrc.solve.copyTo.add(dst) {
203 if a.log != nil {
204 fmt.Fprintf(a.log, "\t\t\tdynamic copy n%d <- n%d\n", dst, src)
205 }
206
207
208
209
210 return a.nodes[dst].solve.pts.addAll(&nsrc.solve.pts)
211 }
212 }
213 return false
214 }
215
216
217
218
219
220
221 func (a *analysis) onlineCopyN(dst, src nodeid, sizeof uint32) uint32 {
222 for i := uint32(0); i < sizeof; i++ {
223 if a.onlineCopy(dst, src) {
224 a.addWork(dst)
225 }
226 src++
227 dst++
228 }
229 return sizeof
230 }
231
232 func (c *loadConstraint) solve(a *analysis, delta *nodeset) {
233 var changed bool
234 for _, x := range delta.AppendTo(a.deltaSpace) {
235 k := nodeid(x)
236 koff := k + nodeid(c.offset)
237 if a.onlineCopy(c.dst, koff) {
238 changed = true
239 }
240 }
241 if changed {
242 a.addWork(c.dst)
243 }
244 }
245
246 func (c *storeConstraint) solve(a *analysis, delta *nodeset) {
247 for _, x := range delta.AppendTo(a.deltaSpace) {
248 k := nodeid(x)
249 koff := k + nodeid(c.offset)
250 if a.onlineCopy(koff, c.src) {
251 a.addWork(koff)
252 }
253 }
254 }
255
256 func (c *offsetAddrConstraint) solve(a *analysis, delta *nodeset) {
257 dst := a.nodes[c.dst]
258 for _, x := range delta.AppendTo(a.deltaSpace) {
259 k := nodeid(x)
260 if dst.solve.pts.add(k + nodeid(c.offset)) {
261 a.addWork(c.dst)
262 }
263 }
264 }
265
266 func (c *typeFilterConstraint) solve(a *analysis, delta *nodeset) {
267 for _, x := range delta.AppendTo(a.deltaSpace) {
268 ifaceObj := nodeid(x)
269 tDyn, _, indirect := a.taggedValue(ifaceObj)
270 if indirect {
271
272
273 panic("indirect tagged object")
274 }
275
276 if types.AssignableTo(tDyn, c.typ) {
277 if a.addLabel(c.dst, ifaceObj) {
278 a.addWork(c.dst)
279 }
280 }
281 }
282 }
283
284 func (c *untagConstraint) solve(a *analysis, delta *nodeset) {
285 predicate := types.AssignableTo
286 if c.exact {
287 predicate = types.Identical
288 }
289 for _, x := range delta.AppendTo(a.deltaSpace) {
290 ifaceObj := nodeid(x)
291 tDyn, v, indirect := a.taggedValue(ifaceObj)
292 if indirect {
293
294
295 panic("indirect tagged object")
296 }
297
298 if predicate(tDyn, c.typ) {
299
300
301
302
303
304
305 a.onlineCopyN(c.dst, v, a.sizeof(tDyn))
306 }
307 }
308 }
309
310 func (c *invokeConstraint) solve(a *analysis, delta *nodeset) {
311 for _, x := range delta.AppendTo(a.deltaSpace) {
312 ifaceObj := nodeid(x)
313 tDyn, v, indirect := a.taggedValue(ifaceObj)
314 if indirect {
315
316
317
318 panic("indirect tagged object")
319 }
320
321
322 fn := a.prog.LookupMethod(tDyn, c.method.Pkg(), c.method.Name())
323 if fn == nil {
324 panic(fmt.Sprintf("n%d: no ssa.Function for %s", c.iface, c.method))
325 }
326 sig := fn.Signature
327
328 fnObj := a.globalobj[fn]
329 if fnObj == 0 {
330
331 panic(fmt.Sprintf("a.globalobj[%s]==nil", fn))
332 }
333
334
335
336
337 a.addLabel(c.params, fnObj)
338
339
340
341 arg0 := a.funcParams(fnObj)
342 recvSize := a.sizeof(sig.Recv().Type())
343 a.onlineCopyN(arg0, v, recvSize)
344
345 src := c.params + 1
346 dst := arg0 + nodeid(recvSize)
347
348
349 paramsSize := a.sizeof(sig.Params())
350 a.onlineCopyN(dst, src, paramsSize)
351 src += nodeid(paramsSize)
352 dst += nodeid(paramsSize)
353
354
355 resultsSize := a.sizeof(sig.Results())
356 a.onlineCopyN(src, dst, resultsSize)
357 }
358 }
359
360 func (c *addrConstraint) solve(a *analysis, delta *nodeset) {
361 panic("addr is not a complex constraint")
362 }
363
364 func (c *copyConstraint) solve(a *analysis, delta *nodeset) {
365 panic("copy is not a complex constraint")
366 }
367
View as plain text