diff options
Diffstat (limited to 'go/callgraph/vta/propagation.go')
-rw-r--r-- | go/callgraph/vta/propagation.go | 57 |
1 files changed, 34 insertions, 23 deletions
diff --git a/go/callgraph/vta/propagation.go b/go/callgraph/vta/propagation.go index 5934ebc21..5817e8938 100644 --- a/go/callgraph/vta/propagation.go +++ b/go/callgraph/vta/propagation.go @@ -20,53 +20,52 @@ import ( // with ids X and Y s.t. X < Y, Y comes before X in the topological order. func scc(g vtaGraph) (map[node]int, int) { // standard data structures used by Tarjan's algorithm. - var index uint64 + type state struct { + index int + lowLink int + onStack bool + } + states := make(map[node]*state, len(g)) var stack []node - indexMap := make(map[node]uint64) - lowLink := make(map[node]uint64) - onStack := make(map[node]bool) - nodeToSccID := make(map[node]int) + nodeToSccID := make(map[node]int, len(g)) sccID := 0 var doSCC func(node) doSCC = func(n node) { - indexMap[n] = index - lowLink[n] = index - index = index + 1 - onStack[n] = true + index := len(states) + ns := &state{index: index, lowLink: index, onStack: true} + states[n] = ns stack = append(stack, n) for s := range g[n] { - if _, ok := indexMap[s]; !ok { + if ss, visited := states[s]; !visited { // Analyze successor s that has not been visited yet. doSCC(s) - lowLink[n] = min(lowLink[n], lowLink[s]) - } else if onStack[s] { + ss = states[s] + ns.lowLink = min(ns.lowLink, ss.lowLink) + } else if ss.onStack { // The successor is on the stack, meaning it has to be // in the current SCC. - lowLink[n] = min(lowLink[n], indexMap[s]) + ns.lowLink = min(ns.lowLink, ss.index) } } // if n is a root node, pop the stack and generate a new SCC. - if lowLink[n] == indexMap[n] { - for { - w := stack[len(stack)-1] + if ns.lowLink == index { + var w node + for w != n { + w = stack[len(stack)-1] stack = stack[:len(stack)-1] - onStack[w] = false + states[w].onStack = false nodeToSccID[w] = sccID - if w == n { - break - } } sccID++ } } - index = 0 for n := range g { - if _, ok := indexMap[n]; !ok { + if _, visited := states[n]; !visited { doSCC(n) } } @@ -74,7 +73,7 @@ func scc(g vtaGraph) (map[node]int, int) { return nodeToSccID, sccID } -func min(x, y uint64) uint64 { +func min(x, y int) int { if x < y { return x } @@ -175,6 +174,18 @@ func nodeTypes(nodes []node, builder *trie.Builder, propTypeId func(p propType) return &typeSet } +// hasInitialTypes check if a node can have initial types. +// Returns true iff `n` is not a panic, recover, nestedPtr* +// node, nor a node whose type is an interface. +func hasInitialTypes(n node) bool { + switch n.(type) { + case panicArg, recoverReturn, nestedPtrFunction, nestedPtrInterface: + return false + default: + return !types.IsInterface(n.Type()) + } +} + // getPropType creates a propType for `node` based on its type. // propType.typ is always node.Type(). If node is function, then // propType.val is the underlying function; nil otherwise. |