...
1
2
3
4
5 package vta
6
7 import (
8 "go/types"
9
10 "golang.org/x/tools/go/callgraph/vta/internal/trie"
11 "golang.org/x/tools/go/ssa"
12
13 "golang.org/x/tools/go/types/typeutil"
14 )
15
16
17
18
19
20
21 func scc(g vtaGraph) (map[node]int, int) {
22
23 var index uint64
24 var stack []node
25 indexMap := make(map[node]uint64)
26 lowLink := make(map[node]uint64)
27 onStack := make(map[node]bool)
28
29 nodeToSccID := make(map[node]int)
30 sccID := 0
31
32 var doSCC func(node)
33 doSCC = func(n node) {
34 indexMap[n] = index
35 lowLink[n] = index
36 index = index + 1
37 onStack[n] = true
38 stack = append(stack, n)
39
40 for s := range g[n] {
41 if _, ok := indexMap[s]; !ok {
42
43 doSCC(s)
44 lowLink[n] = min(lowLink[n], lowLink[s])
45 } else if onStack[s] {
46
47
48 lowLink[n] = min(lowLink[n], indexMap[s])
49 }
50 }
51
52
53 if lowLink[n] == indexMap[n] {
54 for {
55 w := stack[len(stack)-1]
56 stack = stack[:len(stack)-1]
57 onStack[w] = false
58 nodeToSccID[w] = sccID
59 if w == n {
60 break
61 }
62 }
63 sccID++
64 }
65 }
66
67 index = 0
68 for n := range g {
69 if _, ok := indexMap[n]; !ok {
70 doSCC(n)
71 }
72 }
73
74 return nodeToSccID, sccID
75 }
76
77 func min(x, y uint64) uint64 {
78 if x < y {
79 return x
80 }
81 return y
82 }
83
84
85
86
87
88
89 type propType struct {
90 typ types.Type
91 f *ssa.Function
92 }
93
94
95
96 type propTypeMap struct {
97 nodeToScc map[node]int
98 sccToTypes map[int]*trie.MutMap
99 }
100
101
102
103 func (ptm propTypeMap) propTypes(n node) []propType {
104 id, ok := ptm.nodeToScc[n]
105 if !ok {
106 return nil
107 }
108 var pts []propType
109 for _, elem := range trie.Elems(ptm.sccToTypes[id].M) {
110 pts = append(pts, elem.(propType))
111 }
112 return pts
113 }
114
115
116
117
118
119
120 func propagate(graph vtaGraph, canon *typeutil.Map) propTypeMap {
121 nodeToScc, sccID := scc(graph)
122
123
124 sccs := make(map[int][]node, sccID)
125 for n, id := range nodeToScc {
126 sccs[id] = append(sccs[id], n)
127 }
128
129
130
131 propTypeIds := make(map[propType]uint64)
132
133
134 propTypeId := func(p propType) uint64 {
135 if id, ok := propTypeIds[p]; ok {
136 return id
137 }
138 id := uint64(len(propTypeIds))
139 propTypeIds[p] = id
140 return id
141 }
142 builder := trie.NewBuilder()
143
144
145 sccToTypes := make(map[int]*trie.MutMap, sccID)
146 for i := 0; i <= sccID; i++ {
147 sccToTypes[i] = nodeTypes(sccs[i], builder, propTypeId, canon)
148 }
149
150 for i := len(sccs) - 1; i >= 0; i-- {
151 nextSccs := make(map[int]struct{})
152 for _, node := range sccs[i] {
153 for succ := range graph[node] {
154 nextSccs[nodeToScc[succ]] = struct{}{}
155 }
156 }
157
158 for nextScc := range nextSccs {
159 sccToTypes[nextScc].Merge(sccToTypes[i].M)
160 }
161 }
162 return propTypeMap{nodeToScc: nodeToScc, sccToTypes: sccToTypes}
163 }
164
165
166
167 func nodeTypes(nodes []node, builder *trie.Builder, propTypeId func(p propType) uint64, canon *typeutil.Map) *trie.MutMap {
168 typeSet := builder.MutEmpty()
169 for _, n := range nodes {
170 if hasInitialTypes(n) {
171 pt := getPropType(n, canon)
172 typeSet.Update(propTypeId(pt), pt)
173 }
174 }
175 return &typeSet
176 }
177
178
179
180
181 func hasInitialTypes(n node) bool {
182 switch n.(type) {
183 case panicArg, recoverReturn, nestedPtrFunction, nestedPtrInterface:
184 return false
185 default:
186 return !types.IsInterface(n.Type())
187 }
188 }
189
190
191
192
193 func getPropType(node node, canon *typeutil.Map) propType {
194 t := canonicalize(node.Type(), canon)
195 if fn, ok := node.(function); ok {
196 return propType{f: fn.f, typ: t}
197 }
198 return propType{f: nil, typ: t}
199 }
200
View as plain text