Skip to content

Commit 83773b8

Browse files
author
Michael Emmi
committed
Compute topological sort using post-order traversal
* fixes #2080
1 parent e4365f6 commit 83773b8

File tree

2 files changed

+79
-12
lines changed

2 files changed

+79
-12
lines changed

src/main/java/soot/jimple/spark/solver/TopoSorter.java

+17-12
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
* #L%
2323
*/
2424

25-
import java.util.ArrayList;
2625
import java.util.HashSet;
27-
import java.util.List;
26+
import java.util.Set;
27+
import java.util.Stack;
2828

2929
import soot.jimple.spark.pag.Node;
3030
import soot.jimple.spark.pag.PAG;
@@ -61,26 +61,31 @@ public TopoSorter(PAG pag, boolean ignoreTypes) {
6161
protected HashSet<VarNode> visited;
6262

6363
protected void dfsVisit(VarNode n) {
64-
if (visited.contains(n)) {
64+
if (!visited.add(n)) {
6565
return;
6666
}
67-
List<VarNode> stack = new ArrayList<>();
68-
List<VarNode> all = new ArrayList<>();
67+
68+
Stack<VarNode> stack = new Stack<>();
69+
Set<VarNode> visitedSuccessors = new HashSet<>();
6970
stack.add(n);
71+
7072
while (!stack.isEmpty()) {
71-
VarNode s = stack.remove(stack.size() - 1);
72-
if (visited.add(s)) {
73-
all.add(s);
73+
VarNode s = stack.peek();
74+
75+
if (visitedSuccessors.add(s)) {
7476
Node[] succs = pag.simpleLookup(s);
7577
for (Node element : succs) {
7678
if (ignoreTypes || pag.getTypeManager().castNeverFails(n.getType(), element.getType())) {
77-
stack.add((VarNode) element);
79+
if (visited.add((VarNode) element)) {
80+
stack.push((VarNode) element);
81+
}
7882
}
7983
}
84+
85+
} else {
86+
stack.pop();
87+
s.setFinishingNumber(nextFinishNumber++);
8088
}
8189
}
82-
for (int i = all.size() - 1; i >= 0; i--) {
83-
all.get(i).setFinishingNumber(nextFinishNumber++);
84-
}
8590
}
8691
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package soot.jimple.spark.solver;
2+
3+
/*-
4+
* #%L
5+
* Soot - a J*va Optimization Framework
6+
* %%
7+
* Copyright (C) 1997 - 2018 Raja Vallée-Rai and others
8+
* %%
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License as
11+
* published by the Free Software Foundation, either version 2.1 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Lesser Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Lesser Public
20+
* License along with this program. If not, see
21+
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
22+
* #L%
23+
*/
24+
25+
import java.util.Collections;
26+
27+
import org.junit.Test;
28+
29+
import static org.junit.Assert.assertEquals;
30+
31+
import soot.Scene;
32+
import soot.Type;
33+
import soot.jimple.spark.pag.PAG;
34+
import soot.jimple.spark.pag.VarNode;
35+
import soot.options.SparkOptions;
36+
37+
public class SCCCollapserTest {
38+
39+
@Test
40+
public void testSeparateComponents() {
41+
Scene.v().loadBasicClasses();
42+
Type type = Scene.v().getObjectType();
43+
44+
SparkOptions sparkOptions = new SparkOptions(Collections.emptyMap());
45+
PAG pag = new PAG(sparkOptions);
46+
47+
VarNode a = pag.makeGlobalVarNode("a", type);
48+
VarNode b = pag.makeGlobalVarNode("b", type);
49+
VarNode c = pag.makeGlobalVarNode("c", type);
50+
pag.addEdge(a, b);
51+
pag.addEdge(a, c);
52+
pag.addEdge(b, c);
53+
54+
SCCCollapser sccCollapser = new SCCCollapser(pag, false);
55+
sccCollapser.collapse();
56+
pag.cleanUpMerges();
57+
58+
assertEquals(a, a.getReplacement());
59+
assertEquals(b, b.getReplacement());
60+
assertEquals(c, c.getReplacement());
61+
}
62+
}

0 commit comments

Comments
 (0)