Skip to content

Commit

Permalink
Compute topological sort using post-order traversal
Browse files Browse the repository at this point in the history
* fixes #2080
  • Loading branch information
Michael Emmi committed May 16, 2024
1 parent e4365f6 commit 83773b8
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 12 deletions.
29 changes: 17 additions & 12 deletions src/main/java/soot/jimple/spark/solver/TopoSorter.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
* #L%
*/

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;

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

protected void dfsVisit(VarNode n) {
if (visited.contains(n)) {
if (!visited.add(n)) {
return;
}
List<VarNode> stack = new ArrayList<>();
List<VarNode> all = new ArrayList<>();

Stack<VarNode> stack = new Stack<>();
Set<VarNode> visitedSuccessors = new HashSet<>();
stack.add(n);

while (!stack.isEmpty()) {
VarNode s = stack.remove(stack.size() - 1);
if (visited.add(s)) {
all.add(s);
VarNode s = stack.peek();

if (visitedSuccessors.add(s)) {
Node[] succs = pag.simpleLookup(s);
for (Node element : succs) {
if (ignoreTypes || pag.getTypeManager().castNeverFails(n.getType(), element.getType())) {
stack.add((VarNode) element);
if (visited.add((VarNode) element)) {
stack.push((VarNode) element);
}
}
}

} else {
stack.pop();
s.setFinishingNumber(nextFinishNumber++);
}
}
for (int i = all.size() - 1; i >= 0; i--) {
all.get(i).setFinishingNumber(nextFinishNumber++);
}
}
}
62 changes: 62 additions & 0 deletions src/test/java/soot/jimple/spark/solver/SCCCollapserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package soot.jimple.spark.solver;

/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 1997 - 2018 Raja Vallée-Rai and others
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

import java.util.Collections;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

import soot.Scene;
import soot.Type;
import soot.jimple.spark.pag.PAG;
import soot.jimple.spark.pag.VarNode;
import soot.options.SparkOptions;

public class SCCCollapserTest {

@Test
public void testSeparateComponents() {
Scene.v().loadBasicClasses();
Type type = Scene.v().getObjectType();

SparkOptions sparkOptions = new SparkOptions(Collections.emptyMap());
PAG pag = new PAG(sparkOptions);

VarNode a = pag.makeGlobalVarNode("a", type);
VarNode b = pag.makeGlobalVarNode("b", type);
VarNode c = pag.makeGlobalVarNode("c", type);
pag.addEdge(a, b);
pag.addEdge(a, c);
pag.addEdge(b, c);

SCCCollapser sccCollapser = new SCCCollapser(pag, false);
sccCollapser.collapse();
pag.cleanUpMerges();

assertEquals(a, a.getReplacement());
assertEquals(b, b.getReplacement());
assertEquals(c, c.getReplacement());
}
}

0 comments on commit 83773b8

Please sign in to comment.