try..catch vs loops

This commit is contained in:
Jindra Petřík
2021-02-07 11:10:19 +01:00
parent 7644eddfd3
commit bca83c3bb4
20 changed files with 342 additions and 109 deletions

View File

@@ -89,6 +89,8 @@ public class AVM2LocalData extends BaseLocalData {
*/
public Map<Integer, GraphPart> finallyThrowParts = new HashMap<>();
public Map<Integer, GraphPart> finallyTargetParts = new HashMap<>();
//switchedPart -> index of nextpart
public Map<GraphPart, Integer> defaultWays = new HashMap<>();
@@ -156,6 +158,7 @@ public class AVM2LocalData extends BaseLocalData {
finallyThrowParts = localData.finallyThrowParts;
inGetLoops = localData.inGetLoops;
parsedExceptionIds = localData.parsedExceptionIds;
finallyTargetParts = localData.finallyTargetParts;
}
public AVM2ConstantPool getConstants() {

View File

@@ -160,9 +160,27 @@ public class AVM2Graph extends Graph {
}
@Override
protected boolean canBeBreakCandidate(BaseLocalData localData, GraphPart part) {
AVM2LocalData aLocalData = (AVM2LocalData) localData;
if (aLocalData.finallyTargetParts.containsValue(part)) {
return false;
}
return true;
}
@Override
protected void beforeGetLoops(BaseLocalData localData, String path, Set<GraphPart> allParts, List<ThrowState> throwStates) throws InterruptedException {
AVM2LocalData avm2LocalData = ((AVM2LocalData) localData);
for (int e = 0; e < body.exceptions.length; e++) {
ABCException ex = body.exceptions[e];
if (ex.isFinally()) {
avm2LocalData.finallyTargetParts.put(e, searchPart(code.adr2pos(ex.target), allParts));
}
}
avm2LocalData.codeStats = avm2LocalData.code.getStats(avm2LocalData.abc, avm2LocalData.methodBody, avm2LocalData.methodBody.init_scope_depth, false);
getIgnoredSwitches((AVM2LocalData) localData, allParts);
Set<Integer> integerSwitchesIps = new HashSet<>();

View File

@@ -143,7 +143,7 @@ public class ActionGraph extends Graph {
}
@Override
protected boolean canBeBreakCandidate(GraphPart part) {
protected boolean canBeBreakCandidate(BaseLocalData localData, GraphPart part) {
if (part.refs.size() <= 1) {
return true;
}

View File

@@ -517,7 +517,6 @@ public class Graph {
beforeGetLoops(localData, path, allParts, throwStates);
List<Loop> loops = new ArrayList<>();
getLoops(localData, heads.get(0), loops, throwStates, null);
afterGetLoops(localData, path, allParts);
@@ -532,7 +531,7 @@ public class Graph {
//TODO: Make getPrecontinues faster
getBackEdges(localData, loops, throwStates);
new GraphPrecontinueDetector().detectPrecontinues(heads, allParts, loops);
new GraphPrecontinueDetector().detectPrecontinues(heads, allParts, loops, throwStates);
/*System.err.println("<loopspre>");
for (Loop el : loops) {
@@ -1155,13 +1154,21 @@ public class Graph {
}
}
private void getLoops(BaseLocalData localData, GraphPart part, List<Loop> loops, List<ThrowState> throwStates, List<GraphPart> stopPart) throws InterruptedException {
clearLoops(loops);
getLoops(localData, part, loops, throwStates, stopPart, true, 1, new ArrayList<>());
clearLoops(loops);
private void clearThrowStates(List<ThrowState> throwStates) {
for (ThrowState ts : throwStates) {
ts.state = 0;
}
}
protected boolean canBeBreakCandidate(GraphPart part) {
private void getLoops(BaseLocalData localData, GraphPart part, List<Loop> loops, List<ThrowState> throwStates, List<GraphPart> stopPart) throws InterruptedException {
clearLoops(loops);
clearThrowStates(throwStates);
getLoopsWalk(localData, part, loops, throwStates, stopPart, true, new ArrayList<>(), 0);
clearLoops(loops);
clearThrowStates(throwStates);
}
protected boolean canBeBreakCandidate(BaseLocalData localData, GraphPart part) {
return true;
}
@@ -1169,7 +1176,21 @@ public class Graph {
}
private void getLoops(BaseLocalData localData, GraphPart part, List<Loop> loops, List<ThrowState> throwStates, List<GraphPart> stopPart, boolean first, int level, List<GraphPart> visited) throws InterruptedException {
private void findPartsOutsideTry(ThrowState ts, GraphPart part, List<GraphPart> ret, Set<GraphPart> visited) {
if (visited.contains(part)) {
return;
}
visited.add(part);
if (!ts.throwingParts.contains(part)) {
ret.add(part);
return;
}
for (GraphPart n : part.nextParts) {
findPartsOutsideTry(ts, n, ret, visited);
}
}
private void getLoopsWalk(BaseLocalData localData, GraphPart part, List<Loop> loops, List<ThrowState> throwStates, List<GraphPart> stopPart, boolean first, List<GraphPart> visited, int level) throws InterruptedException {
if (part == null) {
return;
@@ -1184,6 +1205,15 @@ public class Graph {
}
checkGetLoopsPart(part);
List<ThrowState> currentThrowStates = new ArrayList<>();
for (ThrowState ts : throwStates) {
if (ts.throwingParts.contains(part) && ts.state != 1) {
currentThrowStates.add(ts);
ts.state = 1;
}
}
if (debugGetLoops) {
System.err.println("getloops: " + part);
}
@@ -1200,8 +1230,11 @@ public class Graph {
}
}
if (lastP1 != null && canBeBreakCandidate(part)) {
if (lastP1 != null && canBeBreakCandidate(localData, part)) {
if (lastP1.breakCandidates.contains(part)) {
if (part.start == 54) {
System.err.println("xxx");
}
lastP1.breakCandidates.add(part);
lastP1.breakCandidatesLevels.add(level);
return;
@@ -1259,16 +1292,16 @@ public class Graph {
stopPart2.add(next);
}
if (next != nps.get(0)) {
getLoops(localData, nps.get(0), loops, throwStates, stopPart2, false, level + 1, visited);
getLoopsWalk(localData, nps.get(0), loops, throwStates, stopPart2, false, visited, level + 1);
}
if (next != nps.get(1)) {
getLoops(localData, nps.get(1), loops, throwStates, stopPart2, false, level + 1, visited);
getLoopsWalk(localData, nps.get(1), loops, throwStates, stopPart2, false, visited, level + 1);
}
if (next != null) {
getLoops(localData, next, loops, throwStates, stopPart, false, level, visited);
getLoopsWalk(localData, next, loops, throwStates, stopPart, false, visited, level);
}
} else if (part.nextParts.size() > 2 || partIsSwitch(part)) {
GraphPart next = getNextCommonPart(localData, part, loops, throwStates);
GraphPart next = getMostCommonPart(localData, part.nextParts, loops, throwStates);
for (GraphPart p : part.nextParts) {
List<GraphPart> stopPart2 = stopPart == null ? new ArrayList<>() : new ArrayList<>(stopPart);
@@ -1284,45 +1317,107 @@ public class Graph {
}
}
if (next != p) {
getLoops(localData, p, loops, throwStates, stopPart2, false, level + 1, visited);
getLoopsWalk(localData, p, loops, throwStates, stopPart2, false, visited, level + 1);
}
}
if (next != null) {
getLoops(localData, next, loops, throwStates, stopPart, false, level, visited);
getLoopsWalk(localData, next, loops, throwStates, stopPart, false, visited, level);
}
} else if (part.nextParts.size() == 1) {
getLoops(localData, part.nextParts.get(0), loops, throwStates, stopPart, false, level, visited);
getLoopsWalk(localData, part.nextParts.get(0), loops, throwStates, stopPart, false, visited, level);
}
List<Loop> loops2 = new ArrayList<>(loops);
for (Loop l : loops2) {
/*for (Loop l : loops2) {
l.breakCandidatesLocked++;
}
}*/
for (ThrowState ts : throwStates) {
//check state?
if (ts.throwingParts.contains(part)) {
if (ts.throwingParts.contains(part) && (currentThrowStates.contains(ts) || ts.state != 1)) {
GraphPart t = ts.targetPart;
if (!visited.contains(t)) {
getLoops(localData, t, loops, throwStates, stopPart, false, level, visited);
getLoopsWalk(localData, t, loops, throwStates, stopPart, false, visited, level + 1 /*???*/);
}
}
}
for (Loop l : loops2) {
/*for (Loop l : loops2) {
l.breakCandidatesLocked--;
}
}*/
if (isLoop && currentLoop != null) {
GraphPart found;
for (int i = 0; i < currentLoop.breakCandidates.size(); i++) {
GraphPart ch = checkPart(null, localData, null, currentLoop.breakCandidates.get(i), null);
if (ch == null) {
currentLoop.breakCandidates.remove(i);
currentLoop.breakCandidatesLevels.remove(i);
i--;
}
}
if (debugGetLoops) {
System.err.println("loop " + currentLoop + " break candidates:");
for (GraphPart cand : currentLoop.breakCandidates) {
System.err.println("- " + cand);
}
}
List<Integer> contThrowStates = new ArrayList<>();
for (ThrowState ts : throwStates) {
if (ts.throwingParts.contains(currentLoop.loopContinue)) {
contThrowStates.add(ts.exceptionId);
}
}
Map<GraphPart, Integer> removed = new HashMap<>();
do {
found = null;
for (int i = 0; i < currentLoop.breakCandidates.size(); i++) {
GraphPart ch = checkPart(null, localData, null, currentLoop.breakCandidates.get(i), null);
if (ch == null) {
currentLoop.breakCandidates.remove(i);
i--;
loopcand:
for (int c = 0; c < currentLoop.breakCandidates.size(); c++) {
GraphPart cand = currentLoop.breakCandidates.get(c);
List<Integer> candThrowStates = new ArrayList<>();
for (ThrowState ts : throwStates) {
if (ts.throwingParts.contains(cand)) {
if (contThrowStates.equals(candThrowStates)) {
//adding new ts
//this means breakcandidate is in nested try
if (debugGetLoops) {
System.err.println("candidate " + cand + " is in inner try, getting outside parts");
}
List<GraphPart> outsideTry = new ArrayList<>();
findPartsOutsideTry(ts, cand, outsideTry, new HashSet<>());
for (int j = outsideTry.size() - 1; j >= 0; j--) {
if (!canBeBreakCandidate(localData, outsideTry.get(j))) {
outsideTry.remove(j);
}
}
if (debugGetLoops) {
for (GraphPart op : outsideTry) {
System.err.println("- outsidepart " + op);
}
}
int bcLevel = currentLoop.breakCandidatesLevels.get(c);
currentLoop.breakCandidates.remove(c);
currentLoop.breakCandidates.addAll(c, outsideTry);
currentLoop.breakCandidatesLevels.remove(c);
removed.put(cand, bcLevel);
for (int j = 0; j < outsideTry.size(); j++) {
currentLoop.breakCandidatesLevels.add(c, bcLevel);
}
c--;
continue loopcand;
}
candThrowStates.add(ts.exceptionId);
}
}
}
do {
found = null;
loopcand:
for (GraphPart cand : currentLoop.breakCandidates) {
for (GraphPart cand2 : currentLoop.breakCandidates) {
@@ -1372,7 +1467,7 @@ public class Graph {
removed.put(found, maxlevel);
}
} while ((found != null) && (currentLoop.breakCandidates.size() > 1));
Map<GraphPart, Integer> count = new HashMap<>();
GraphPart winner = null;
int winnerCount = 0;
@@ -1431,7 +1526,7 @@ public class Graph {
if (removedVisited.contains(r)) {
continue;
}
getLoops(localData, r, loops, throwStates, stopPart, false, removed.get(r), visited);
getLoopsWalk(localData, r, loops, throwStates, stopPart, false, visited, removed.get(r));
removedVisited.add(r);
}
start = false;
@@ -1444,7 +1539,7 @@ public class Graph {
el.phase = 2;
}
}
getLoops(localData, currentLoop.loopBreak, loops, throwStates, stopPart, false, level, visited);
getLoopsWalk(localData, currentLoop.loopBreak, loops, throwStates, stopPart, false, visited, level);
}
}
@@ -1638,9 +1733,7 @@ public class Graph {
boolean vCanHandleVisited = canHandleVisited(localData, part);
/*if (part.start == 31) {
FIXME
/*if (part.start == 25) {
new RuntimeException().printStackTrace();
}*/
if (vCanHandleVisited) {

View File

@@ -175,7 +175,6 @@ public class GraphPart implements Serializable {
return true;
}
}
if (useThrow)
for (ThrowState ts : throwStates) {
if (ts.state != 1) {
if (ts.throwingParts.contains(this)) {
@@ -188,15 +187,6 @@ public class GraphPart implements Serializable {
}
}
}
/*if (useThrow) {
for (GraphPart p : throwParts) {
if (p == part) {
return true;
} else if (p.leadsTo(localData, gr, code, this, part, visited, loops, throwStates, useThrow)) {
return true;
}
}
}*/
return false;
}

View File

@@ -12,7 +12,8 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* License along with this library.
*/
package com.jpexs.decompiler.graph;
import java.io.Serializable;

View File

@@ -13,4 +13,29 @@ public class ThrowState {
public Set<GraphPart> throwingParts = new HashSet<>();
public GraphPart targetPart;
@Override
public int hashCode() {
int hash = 3;
hash = 97 * hash + this.exceptionId;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ThrowState other = (ThrowState) obj;
if (this.exceptionId != other.exceptionId) {
return false;
}
return true;
}
}

View File

@@ -18,6 +18,7 @@ package com.jpexs.decompiler.graph.precontinues;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.Loop;
import com.jpexs.decompiler.graph.ThrowState;
import com.jpexs.helpers.Reference;
import java.util.ArrayList;
import java.util.HashMap;
@@ -40,7 +41,7 @@ import java.util.Set;
*/
public class GraphPrecontinueDetector {
public void detectPrecontinues(List<GraphPart> heads, Set<GraphPart> allParts, List<Loop> loops) {
public void detectPrecontinues(List<GraphPart> heads, Set<GraphPart> allParts, List<Loop> loops, List<ThrowState> throwStates) {
boolean isSomethingTodo = false;
for (Loop el : loops) {
if (el.backEdges.size() == 1) {
@@ -60,6 +61,12 @@ public class GraphPrecontinueDetector {
for (GraphPart part : allParts) {
Node node = partToNode.get(part);
for (GraphPart prev : part.refs) {
/*if (prev.start < 0 && !partToNode.containsKey(prev)) {
Node minusNode = new Node();
minusNode.graphPart = prev;
partToNode.put(prev, node);
continue;
}*/
if (prev.start < 0) {
continue;
}
@@ -90,6 +97,12 @@ public class GraphPrecontinueDetector {
}
}
List<GraphPart> targetParts = new ArrayList<>();
for (ThrowState ts : throwStates) {
targetParts.add(ts.targetPart);
}
for (Loop el : loops) {
if (el.backEdges.size() == 1) {
//System.err.println("loop " + el.loopContinue);
@@ -97,15 +110,26 @@ public class GraphPrecontinueDetector {
Node node = partToNode.get(backEdgePart);
//System.err.println("backedge:" + backEdgePart);
boolean wholeLoop = false;
while (node.parentNode != null) {
node = node.parentNode;
//System.err.println("- parent " + node.graphPart);
if (node.graphPart.equals(el.loopContinue)) {
wholeLoop = true;
break;
boolean inTryTarget = false;
if (targetParts.contains(node.graphPart)) {
inTryTarget = true;
}
if (!inTryTarget) {
while (node.parentNode != null) {
node = node.parentNode;
//System.err.println("- parent " + node.graphPart);
if (node.graphPart.equals(el.loopContinue)) {
wholeLoop = true;
break;
}
if (targetParts.contains(node.graphPart)) {
inTryTarget = true;
break;
}
}
}
if (!wholeLoop) {
if (!wholeLoop && !inTryTarget) {
el.loopPreContinue = node.graphPart;
//System.err.println("found precontinue:" + node.graphPart);
}