diff --git a/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java index 80c4393323e..a01278307fd 100644 --- a/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java @@ -128,12 +128,6 @@ public Iterator iterator() { return backingGraph.iterator(); } - @Nonnull - @Override - public List buildTraps() { - return backingGraph.buildTraps(); - } - @Override public void removeExceptionalFlowFromAllBlocks( @Nonnull ClassType exceptionType, @Nonnull Stmt exceptionHandlerStmt) { diff --git a/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java index 84e0b4fe91a..43fcd101521 100644 --- a/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java @@ -137,12 +137,6 @@ public boolean hasEdgeConnecting(@Nonnull Stmt source, @Nonnull Stmt target) { throw new UnsupportedOperationException("Not implemented yet!"); } - @Nonnull - @Override - public List buildTraps() { - throw new UnsupportedOperationException("Not implemented yet!"); - } - @Override public void removeExceptionalFlowFromAllBlocks(ClassType classType, Stmt exceptionHandlerStmt) { throw new UnsupportedOperationException("Not implemented yet!"); diff --git a/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java index d27f2170116..2798f6640fb 100644 --- a/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java @@ -1596,39 +1596,6 @@ public boolean hasEdgeConnecting(@Nonnull Stmt source, @Nonnull Stmt target) { } } - /** Comparator which sorts the trap output in getTraps() */ - public Comparator getTrapComparator(@Nonnull Map stmtsBlockIdx) { - return (a, b) -> - ComparisonChain.start() - .compare(stmtsBlockIdx.get(a.getBeginStmt()), stmtsBlockIdx.get(b.getBeginStmt())) - .compare(stmtsBlockIdx.get(a.getEndStmt()), stmtsBlockIdx.get(b.getEndStmt())) - // [ms] would be nice to have the traps ordered by exception hierarchy as well - .compare(a.getExceptionType().toString(), b.getExceptionType().toString()) - .result(); - } - - /** hint: little expensive getter - its more of a build/create - currently no overlaps */ - @Override - public List buildTraps() { - // [ms] try to incorporate it into the serialisation of jimple printing so the other half of - // iteration information is not wasted.. - BlockGraphIteratorAndTrapAggregator it = - new BlockGraphIteratorAndTrapAggregator(new MutableBasicBlockImpl()); - // it.getTraps() is valid/completely build when the iterator is done. - Map stmtsBlockIdx = new IdentityHashMap<>(); - int i = 0; - // collect BlockIdx positions to sort the traps according to the numbering - while (it.hasNext()) { - final BasicBlock nextBlock = it.next(); - stmtsBlockIdx.put(nextBlock.getHead(), i); - stmtsBlockIdx.put(nextBlock.getTail(), i); - i++; - } - final List traps = it.getTraps(); - traps.sort(getTrapComparator(stmtsBlockIdx)); - return traps; - } - @Override public void removeExceptionalFlowFromAllBlocks( @Nonnull ClassType exceptionType, @Nonnull Stmt exceptionHandlerStmt) { diff --git a/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java index 17482b62e41..15df3c01580 100644 --- a/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java @@ -65,6 +65,8 @@ */ public abstract class StmtGraph> implements Iterable { + public final JimplePrinter jimplePrinter = new JimplePrinter(); + public abstract Stmt getStartingStmt(); public abstract BasicBlock getStartingStmtBlock(); @@ -148,15 +150,6 @@ public int degree(@Nonnull Stmt node) { */ public abstract boolean hasEdgeConnecting(@Nonnull Stmt source, @Nonnull Stmt target); - /** - * returns a (reconstructed) list of traps like the traptable in the bytecode - * - *

Note: if you need exceptionional flow information in more augmented with the affected - * blocks/stmts and not just a (reconstructed, possibly more verbose) traptable - have a look at - * BasicBlock.getExceptionalSuccessor() - */ - public abstract List buildTraps(); - /** * Removes the specified exceptional flow from all blocks. * @@ -206,15 +199,25 @@ public Collection getEntrypoints() { /** validates whether the each Stmt has the correct amount of outgoing flows. */ public void validateStmtConnectionsInGraph() { try { + List handlerStmts = new ArrayList<>(); + for (Stmt stmt: getNodes()){ + if (stmt instanceof JIdentityStmt) { + //JThrowStmt? + IdentityRef rightOp = ((JIdentityStmt) stmt).getRightOp(); + if (rightOp instanceof JCaughtExceptionRef) { + handlerStmts.add(stmt); + } + } + } for (Stmt stmt : getNodes()) { final List successors = successors(stmt); final int successorCount = successors.size(); if (predecessors(stmt).isEmpty()) { + if (!(stmt == getStartingStmt() - || buildTraps().stream() - .map(Trap::getHandlerStmt) + || handlerStmts.stream() .anyMatch(handler -> handler == stmt))) { throw new IllegalStateException( "Stmt '" @@ -353,7 +356,7 @@ public boolean equals(Object o) { return false; } - if (!buildTraps().equals(otherGraph.buildTraps())) { + if (!jimplePrinter.buildTraps(this).equals(jimplePrinter.buildTraps(otherGraph))) { return false; } @@ -517,7 +520,7 @@ public List getTraps() { } /** Iterates over the blocks */ - protected class BlockGraphIterator implements Iterator> { + public class BlockGraphIterator implements Iterator> { @Nonnull private final ArrayDeque> trapHandlerBlocks = new ArrayDeque<>(); @@ -717,7 +720,7 @@ public Collection getLabeledStmts() { } } - for (Trap trap : buildTraps()) { + for (Trap trap : jimplePrinter.buildTraps(this)) { stmtList.add(trap.getBeginStmt()); stmtList.add(trap.getEndStmt()); stmtList.add(trap.getHandlerStmt()); @@ -730,7 +733,7 @@ public Collection getLabeledStmts() { public String toString() { StringWriter writer = new StringWriter(); try (PrintWriter writerOut = new PrintWriter(new EscapedWriter(writer))) { - new JimplePrinter().printTo(this, writerOut); + jimplePrinter.printTo(this, writerOut); } return writer.toString(); } diff --git a/sootup.core/src/main/java/sootup/core/model/Body.java b/sootup.core/src/main/java/sootup/core/model/Body.java index 7e8606a9088..1c161f05aa6 100644 --- a/sootup.core/src/main/java/sootup/core/model/Body.java +++ b/sootup.core/src/main/java/sootup/core/model/Body.java @@ -117,7 +117,7 @@ public Set getLocals() { @Nonnull @Deprecated() public List getTraps() { - return graph.buildTraps(); + return new JimplePrinter().buildTraps(graph); } /** Return unit containing the \@this-assignment * */ diff --git a/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java b/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java index daf83dc9794..a5cd90c5f5c 100644 --- a/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java +++ b/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java @@ -22,11 +22,8 @@ * #L% */ -import java.io.PrintWriter; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; -import sootup.core.graph.StmtGraph; +import com.google.common.collect.ComparisonChain; +import sootup.core.graph.*; import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Trap; @@ -38,6 +35,12 @@ import sootup.core.types.ClassType; import sootup.core.types.Type; +import javax.annotation.Nonnull; +import java.io.PrintWriter; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + /** * Prints out a class and all its methods. * @@ -297,6 +300,44 @@ public void printTo(StmtGraph graph, PrintWriter out, LabeledStmtPrinter prin out.print(printer); } + /** + * returns a (reconstructed) list of traps like the traptable in the bytecode + * + *

Note: if you need exceptionional flow information in more augmented with the affected + * blocks/stmts and not just a (reconstructed, possibly more verbose) traptable - have a look at + * BasicBlock.getExceptionalSuccessor() + */ + /** hint: little expensive getter - its more of a build/create - currently no overlaps */ + public List buildTraps(StmtGraph stmtGraph) { + // [ms] try to incorporate it into the serialisation of jimple printing so the other half of + // iteration information is not wasted.. + StmtGraph.BlockGraphIteratorAndTrapAggregator it = stmtGraph.new BlockGraphIteratorAndTrapAggregator(new MutableBasicBlockImpl()); + // it.getTraps() is valid/completely build when the iterator is done. + Map stmtsBlockIdx = new IdentityHashMap<>(); + int i = 0; + // collect BlockIdx positions to sort the traps according to the numbering + while (it.hasNext()) { + final BasicBlock nextBlock = it.next(); + stmtsBlockIdx.put(nextBlock.getHead(), i); + stmtsBlockIdx.put(nextBlock.getTail(), i); + i++; + } + final List traps = it.getTraps(); + traps.sort(getTrapComparator(stmtsBlockIdx)); + return traps; + } + + /** Comparator which sorts the trap output in getTraps() */ + public Comparator getTrapComparator(@Nonnull Map stmtsBlockIdx) { + return (a, b) -> + ComparisonChain.start() + .compare(stmtsBlockIdx.get(a.getBeginStmt()), stmtsBlockIdx.get(b.getBeginStmt())) + .compare(stmtsBlockIdx.get(a.getEndStmt()), stmtsBlockIdx.get(b.getEndStmt())) + // [ms] would be nice to have the traps ordered by exception hierarchy as well + .compare(a.getExceptionType().toString(), b.getExceptionType().toString()) + .result(); + } + /** * Prints out the method corresponding to b Body, (declaration and body), in the textual format * corresponding to the IR used to encode b body. @@ -380,7 +421,7 @@ private void printStmts(StmtGraph stmtGraph, LabeledStmtPrinter printer) { // Print out exceptions { - Iterator trapIt = stmtGraph.buildTraps().iterator(); + Iterator trapIt = buildTraps(stmtGraph).iterator(); if (trapIt.hasNext()) { printer.newline(); diff --git a/sootup.core/src/main/java/sootup/core/util/printer/LabeledStmtPrinter.java b/sootup.core/src/main/java/sootup/core/util/printer/LabeledStmtPrinter.java index 01f4eb5eb75..f49d463cb60 100644 --- a/sootup.core/src/main/java/sootup/core/util/printer/LabeledStmtPrinter.java +++ b/sootup.core/src/main/java/sootup/core/util/printer/LabeledStmtPrinter.java @@ -114,7 +114,7 @@ public Iterable initializeSootMethod(@Nonnull StmtGraph stmtGraph) { @Nonnull public List getStmts(@Nonnull StmtGraph stmtGraph) { final Collection targetStmtsOfBranches = stmtGraph.getLabeledStmts(); - final List traps = stmtGraph.buildTraps(); + final List traps = new JimplePrinter().buildTraps(stmtGraph); final int maxEstimatedSize = targetStmtsOfBranches.size() + traps.size() * 3; labels = new HashMap<>(maxEstimatedSize, 1); diff --git a/sootup.core/src/test/java/sootup/core/graph/MutableBlockStmtGraphTest.java b/sootup.core/src/test/java/sootup/core/graph/MutableBlockStmtGraphTest.java index e64299713f9..2b88a74afdd 100644 --- a/sootup.core/src/test/java/sootup/core/graph/MutableBlockStmtGraphTest.java +++ b/sootup.core/src/test/java/sootup/core/graph/MutableBlockStmtGraphTest.java @@ -19,10 +19,13 @@ import sootup.core.types.ClassType; import sootup.core.types.PrimitiveType; import sootup.core.types.UnknownType; +import sootup.core.util.printer.JimplePrinter; @Tag("Java8") public class MutableBlockStmtGraphTest { + public JimplePrinter jimplePrinter = new JimplePrinter(); + BranchingStmt firstGoto = new JGotoStmt(StmtPositionInfo.getNoStmtPositionInfo()); JNopStmt firstNop = new JNopStmt(StmtPositionInfo.getNoStmtPositionInfo()); JNopStmt secondNop = new JNopStmt(StmtPositionInfo.getNoStmtPositionInfo()); @@ -621,7 +624,7 @@ public PackageName getPackageName() { graph0.putEdge(stmt2, 0, returnStmt); { - final List traps = graph0.buildTraps(); + final List traps = jimplePrinter.buildTraps(graph0); assertEquals(2, traps.size()); // as @caughtexception gets currently in their way. assertEquals(stmt2, traps.get(1).getBeginStmt()); assertEquals(returnStmt, traps.get(1).getEndStmt()); @@ -659,7 +662,7 @@ public PackageName getPackageName() { graph2.putEdge(stmt2, JGotoStmt.BRANCH_IDX, returnStmt); { assertEquals(5, graph2.getBlocks().size()); - final List traps = graph2.buildTraps(); + final List traps = jimplePrinter.buildTraps(graph2); assertEquals(2, traps.size()); } @@ -675,7 +678,7 @@ public PackageName getPackageName() { graph3.putEdge(stmt3, JGotoStmt.BRANCH_IDX, returnStmt); { - final List traps = graph3.buildTraps(); + final List traps = jimplePrinter.buildTraps(graph3); assertEquals(5, graph2.getBlocks().size()); assertEquals(2, traps.size()); } @@ -698,7 +701,7 @@ public PackageName getPackageName() { graph4.putEdge(stmt2, JGotoStmt.BRANCH_IDX, stmt3); graph4.putEdge(stmt3, JGotoStmt.BRANCH_IDX, returnStmt); - assertEquals(3, graph4.buildTraps().size()); + assertEquals(3, jimplePrinter.buildTraps(graph4).size()); // mixed 2 MutableBlockStmtGraph graph5 = new MutableBlockStmtGraph(); @@ -733,7 +736,7 @@ public PackageName getPackageName() { graph5.putEdge(stmt3, JGotoStmt.BRANCH_IDX, returnStmt); { - final List traps = graph5.buildTraps(); + final List traps = jimplePrinter.buildTraps(graph5); assertEquals(6, traps.size()); assertEquals(6, graph5.getBlocks().size()); } @@ -769,7 +772,7 @@ public PackageName getPackageName() { graph6.putEdge(stmt2, JGotoStmt.BRANCH_IDX, stmt3); graph6.putEdge(stmt3, JGotoStmt.BRANCH_IDX, returnStmt); { - final List traps = graph6.buildTraps(); + final List traps = jimplePrinter.buildTraps(graph6); assertEquals(5, traps.size()); assertEquals(6, graph6.getBlocks().size()); assertEquals( @@ -1030,6 +1033,7 @@ public void simpleInsertion() { assertTrue(graph.successors(stmt1).contains(stmt2)); } + // It is an invalid graph, just for the test @Test public void testRemoveSingleTrap() { MutableBlockStmtGraph graph = new MutableBlockStmtGraph(); @@ -1052,7 +1056,7 @@ public void testRemoveSingleTrap() { graph.addExceptionalEdge(stmt1, throwableSig, handlerStmt); // Verify the trap is present - List traps = graph.buildTraps(); + List traps = jimplePrinter.buildTraps(graph); assertEquals(1, traps.size()); assertEquals(stmt1, traps.get(0).getBeginStmt()); assertEquals(handlerStmt, traps.get(0).getHandlerStmt()); @@ -1061,7 +1065,7 @@ public void testRemoveSingleTrap() { Trap trapToRemove = traps.get(0); graph.removeExceptionalFlowFromAllBlocks( trapToRemove.getExceptionType(), trapToRemove.getHandlerStmt()); - traps = graph.buildTraps(); + traps = jimplePrinter.buildTraps(graph); assertEquals(0, traps.size()); } @@ -1095,7 +1099,7 @@ public void testRemoveMultipleTrapsWithDifferentExceptionTypes() { graph.addExceptionalEdge(stmt2, ioExceptionSig, handlerStmt2); // Verify both traps are present - List traps = graph.buildTraps(); + List traps = jimplePrinter.buildTraps(graph); assertEquals(2, traps.size()); // Remove one trap and verify the remaining @@ -1104,7 +1108,7 @@ public void testRemoveMultipleTrapsWithDifferentExceptionTypes() { graph.removeExceptionalFlowFromAllBlocks( trapToRemove.getExceptionType(), trapToRemove.getHandlerStmt()); - traps = graph.buildTraps(); + traps = jimplePrinter.buildTraps(graph); assertEquals(1, traps.size()); assertEquals(stmt2, trapToKeep.getBeginStmt()); assertEquals(handlerStmt2, trapToKeep.getHandlerStmt()); diff --git a/sootup.java.bytecode.frontend/src/test/java/sootup/java/bytecode/frontend/interceptors/TrapTightenerTest.java b/sootup.java.bytecode.frontend/src/test/java/sootup/java/bytecode/frontend/interceptors/TrapTightenerTest.java index 9097545d073..f6d1bcb1f3d 100644 --- a/sootup.java.bytecode.frontend/src/test/java/sootup/java/bytecode/frontend/interceptors/TrapTightenerTest.java +++ b/sootup.java.bytecode.frontend/src/test/java/sootup/java/bytecode/frontend/interceptors/TrapTightenerTest.java @@ -23,6 +23,7 @@ import sootup.core.types.ClassType; import sootup.core.types.VoidType; import sootup.core.util.ImmutableUtils; +import sootup.core.util.printer.JimplePrinter; import sootup.interceptors.TrapTightener; import sootup.java.core.JavaIdentifierFactory; import sootup.java.core.language.JavaJimple; @@ -33,6 +34,8 @@ @Tag(TestCategories.JAVA_8_CATEGORY) @Disabled("FIXME: needs .setTraps() adapted to MutableBlockStmtGraph") public class TrapTightenerTest { + public JimplePrinter jimplePrinter = new JimplePrinter(); + JavaIdentifierFactory factory = JavaIdentifierFactory.getInstance(); StmtPositionInfo noStmtPositionInfo = StmtPositionInfo.getNoStmtPositionInfo(); @@ -131,7 +134,7 @@ public void testSimpleBody() { List excepted = new ArrayList<>(); excepted.add(trap3); - List actual = stmtGraph.buildTraps(); + List actual = jimplePrinter.buildTraps(stmtGraph); AssertUtils.assertTrapsEquiv(excepted, actual); } /** @@ -172,7 +175,7 @@ public void testMonitoredBody() { List excepted = new ArrayList<>(); excepted.add(trap1); - List actual = stmtGraph.buildTraps(); + List actual = jimplePrinter.buildTraps(stmtGraph); AssertUtils.assertTrapsEquiv(excepted, actual); } diff --git a/sootup.java.bytecode.frontend/src/test/java/sootup/java/bytecode/frontend/interceptors/UnreachableCodeEliminatorTest.java b/sootup.java.bytecode.frontend/src/test/java/sootup/java/bytecode/frontend/interceptors/UnreachableCodeEliminatorTest.java index cc114b2fb14..77845f7b464 100644 --- a/sootup.java.bytecode.frontend/src/test/java/sootup/java/bytecode/frontend/interceptors/UnreachableCodeEliminatorTest.java +++ b/sootup.java.bytecode.frontend/src/test/java/sootup/java/bytecode/frontend/interceptors/UnreachableCodeEliminatorTest.java @@ -23,6 +23,7 @@ import sootup.core.types.PrimitiveType; import sootup.core.types.VoidType; import sootup.core.util.ImmutableUtils; +import sootup.core.util.printer.JimplePrinter; import sootup.interceptors.UnreachableCodeEliminator; import sootup.java.core.JavaIdentifierFactory; import sootup.java.core.language.JavaJimple; @@ -33,6 +34,8 @@ @Tag(TestCategories.JAVA_8_CATEGORY) public class UnreachableCodeEliminatorTest { + public final JimplePrinter jimplePrinter = new JimplePrinter(); + JavaIdentifierFactory factory = JavaIdentifierFactory.getInstance(); JavaJimple javaJimple = JavaJimple.getInstance(); StmtPositionInfo noStmtPositionInfo = StmtPositionInfo.getNoStmtPositionInfo(); @@ -139,7 +142,7 @@ public void testTrappedBody1() { new UnreachableCodeEliminator().interceptBody(builder, new JavaView(Collections.emptyList())); - assertEquals(0, builder.getStmtGraph().buildTraps().size()); + assertEquals(0, jimplePrinter.buildTraps(builder.getStmtGraph()).size()); Set expectedStmtsSet = ImmutableUtils.immutableSet(startingStmt, stmt1, ret1); AssertUtils.assertSetsEquiv(expectedStmtsSet, builder.getStmtGraph().getNodes()); @@ -175,7 +178,7 @@ public void testTrappedBody2() { UnreachableCodeEliminator eliminator = new UnreachableCodeEliminator(); eliminator.interceptBody(builder, new JavaView(Collections.emptyList())); - assertEquals(0, builder.getStmtGraph().buildTraps().size()); + assertEquals(0, jimplePrinter.buildTraps(builder.getStmtGraph()).size()); Set expectedStmtsSet = ImmutableUtils.immutableSet(startingStmt, stmt1, ret1); assertEquals(expectedStmtsSet, builder.getStmtGraph().getNodes());