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