diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java index fff4ccb38..cebcb41b9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/AVM2LocalData.java @@ -59,6 +59,7 @@ public class AVM2LocalData extends BaseLocalData { public List fullyQualifiedNames; public List parsedExceptions = new ArrayList<>(); + public List parsedExceptionIds = new ArrayList<>(); //public Map> finallyJumps; /** @@ -154,6 +155,7 @@ public class AVM2LocalData extends BaseLocalData { defaultParts = localData.defaultParts; finallyThrowParts = localData.finallyThrowParts; inGetLoops = localData.inGetLoops; + parsedExceptionIds = localData.parsedExceptionIds; } public AVM2ConstantPool getConstants() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index e477dfa11..1a704594c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -84,6 +84,7 @@ import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.Loop; import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.decompiler.graph.ThrowState; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.AnyItem; import com.jpexs.decompiler.graph.model.BreakItem; @@ -160,7 +161,7 @@ public class AVM2Graph extends Graph { } @Override - protected void beforeGetLoops(BaseLocalData localData, String path, Set allParts) throws InterruptedException { + protected void beforeGetLoops(BaseLocalData localData, String path, Set allParts, List throwStates) throws InterruptedException { AVM2LocalData avm2LocalData = ((AVM2LocalData) localData); avm2LocalData.codeStats = avm2LocalData.code.getStats(avm2LocalData.abc, avm2LocalData.methodBody, avm2LocalData.methodBody.init_scope_depth, false); getIgnoredSwitches((AVM2LocalData) localData, allParts); @@ -171,10 +172,13 @@ public class AVM2Graph extends Graph { for (GraphPart finallySwitchTarget : avm2LocalData.finallyJumps.values()) { if (!avm2LocalData.defaultParts.values().contains(finallySwitchTarget)) { - finallySwitchTarget.throwParts.clear(); // having throwparts in these causes problems + for (ThrowState ts : throwStates) { + ts.throwingParts.remove(finallySwitchTarget); + } + //finallySwitchTarget.throwParts.clear(); // having throwparts in these causes problems } } - Map> setLocalPosToGetLocalPos = calculateLocalRegsUsage(avm2LocalData, integerSwitchesIps, path, allParts); + Map> setLocalPosToGetLocalPos = calculateLocalRegsUsage(throwStates, avm2LocalData, integerSwitchesIps, path, allParts); avm2LocalData.setLocalPosToGetLocalPos = setLocalPosToGetLocalPos; avm2LocalData.inGetLoops = true; } @@ -440,7 +444,7 @@ public class AVM2Graph extends Graph { } } - private void walkLocalRegsUsage(AVM2LocalData localData, Set getLocalPos, GraphPart startPart, GraphPart part, Set visited, int ip, int searchRegId) { + private void walkLocalRegsUsage(List throwStates, AVM2LocalData localData, Set getLocalPos, GraphPart startPart, GraphPart part, Set visited, int ip, int searchRegId) { if (visited.contains(part) && part != startPart) { return; } @@ -510,24 +514,28 @@ public class AVM2Graph extends Graph { //okay, proceed to finally block } else if (targetPart.nextParts.size() == 1) { //continue or break, definitely not a return, there won't be a register usage - walkLocalRegsUsage(localData, getLocalPos, startPart, targetPart.nextParts.get(0), visited, ip, searchRegId); + walkLocalRegsUsage(throwStates, localData, getLocalPos, startPart, targetPart.nextParts.get(0), visited, ip, searchRegId); return; } else { return; } } for (GraphPart p : part.nextParts) { - walkLocalRegsUsage(localData, getLocalPos, startPart, p, visited, p.start, searchRegId); + walkLocalRegsUsage(throwStates, localData, getLocalPos, startPart, p, visited, p.start, searchRegId); } } finally { - for (GraphPart p : part.throwParts) { - walkLocalRegsUsage(localData, getLocalPos, startPart, p, visited, p.start, searchRegId); + for (ThrowState ts : throwStates) { + if (ts.throwingParts.contains(part)) { + GraphPart p = ts.targetPart; + walkLocalRegsUsage(throwStates, localData, getLocalPos, startPart, p, visited, p.start, searchRegId); + } + } } } //TODO: optimize this to make it faster!!! - public Map> calculateLocalRegsUsage(AVM2LocalData localData, Set ignoredSwitches, String path, Set allParts) { + public Map> calculateLocalRegsUsage(List throwStates, AVM2LocalData localData, Set ignoredSwitches, String path, Set allParts) { logger.log(Level.FINE, "--- {0} ---", path); Map> setLocalPosToGetLocalPos = new TreeMap<>(); Map reverseFinallyJumps = new HashMap<>(); @@ -557,7 +565,7 @@ public class AVM2Graph extends Graph { if (part == null) { //might be last part of script (?) continue; } - walkLocalRegsUsage(localData, setLocalPosToGetLocalPos.get(ip), part, part, new HashSet<>(), ip + 1, setLocalPosToRegisterId.get(ip)); + walkLocalRegsUsage(throwStates, localData, setLocalPosToGetLocalPos.get(ip), part, part, new HashSet<>(), ip + 1, setLocalPosToRegisterId.get(ip)); } /*for (int ip : setLocalPosToGetLocalPos.keySet()) { @@ -601,7 +609,7 @@ public class AVM2Graph extends Graph { for (GraphPart p : allBlocks) { if (avm2code.pos2adr(p.start) >= ex.start && avm2code.pos2adr(p.end) <= ex.end && targetPart != null) { //Logger.getLogger(Graph.class.getName()).fine("ADDING throwpart " + target + " to " + p); - p.throwParts.add(targetPart); + //p.throwParts.add(targetPart); //target.refs.add(p); } } @@ -705,6 +713,31 @@ public class AVM2Graph extends Graph { return ret; } + private GraphPart firstPartOutsideWalk(GraphPart part, int startIp, int endIp, Set visited) { + if (visited.contains(part)) { + return null; + } + visited.add(part); + if (part.start < startIp || part.start >= endIp) { + return part; + } + for (GraphPart n : part.nextParts) { + GraphPart r = firstPartOutsideWalk(n, startIp, endIp, visited); + if (r != null) { + return r; + } + } + return null; + } + + private GraphPart searchFirstPartOutSideTryCatchSimple(ABCException ex, Collection allParts) { + int startIp = code.adr2pos(ex.start, true); + int endIp = code.adr2pos(ex.end, true); + + GraphPart startPart = searchPart(startIp, allParts); + return firstPartOutsideWalk(startPart, startIp, endIp, new HashSet<>()); + } + private GraphPart searchFirstPartOutSideTryCatch(AVM2LocalData localData, ABCException ex, List loops, Collection allParts) { LinkedHashSet reachable = new LinkedHashSet<>(); int startIp = localData.code.adr2pos(ex.start, true); @@ -722,7 +755,7 @@ public class AVM2Graph extends Graph { subLocalData.finallyJumpsToFinallyIndex = new HashMap<>(); subLocalData.finallyThrowParts = new HashMap<>(); subLocalData.ignoredSwitches = new HashMap<>(); - getReachableParts(subLocalData, startPart, reachable, loops); + getReachableParts(subLocalData, startPart, reachable, loops, new ArrayList<>() /*??*/); for (GraphPart r : reachable) { if (r.start < startIp || r.start >= endIp) { @@ -739,43 +772,36 @@ public class AVM2Graph extends Graph { return part; } - private boolean checkTry(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, AVM2LocalData localData, GraphPart part, List stopPart, List loops, Set allParts, TranslateStack stack, int staticOperation, String path) throws InterruptedException { - if (localData.parsedExceptions == null) { - localData.parsedExceptions = new ArrayList<>(); - } - List parsedExceptions = localData.parsedExceptions; - if (localData.finallyJumps == null) { - localData.finallyJumps = new HashMap<>(); - } - if (localData.ignoredSwitches == null) { - localData.ignoredSwitches = new HashMap<>(); - } - long addr = avm2code.pos2adr(part.start); //avm2code.getAddrThroughJumpAndDebugLine(avm2code.pos2adr(part.start)); - long maxEndAddr = -1; - List catchedExceptions = new ArrayList<>(); + private void getCatchedExceptionIds(GraphPart part, List previouslyCatchedExceptionIds, List catchedExceptionIds, Reference finallyIndex, Collection allParts, + List loops, AVM2LocalData localData) { + + long addr = avm2code.pos2adr(part.start); + long maxEndAddr = -1; + finallyIndex.setVal(-1); - int endIp = -1; List finnalysIndicesToBe = new ArrayList<>(); - int realEndIp = -1; + maxEndAddr = -1; for (int e = 0; e < body.exceptions.length; e++) { long fixedExStart = avm2code.pos2adr(avm2code.adr2pos(body.exceptions[e].start, true)); long fixedExEnd = avm2code.pos2adr(avm2code.adr2pos(body.exceptions[e].end, true)); + if (!previouslyCatchedExceptionIds.contains(e)) { + if (addr == fixedExStart) { //avm2code.getAddrThroughJumpAndDebugLine(fixedExStart)) { + ABCException ex = body.exceptions[e]; - if (addr == fixedExStart) { //avm2code.getAddrThroughJumpAndDebugLine(fixedExStart)) { - ABCException ex = body.exceptions[e]; - if (!parsedExceptions.contains(ex)) { if (ex.isFinally()) { finnalysIndicesToBe.add(e); } else { long endAddr = avm2code.getAddrThroughJumpAndDebugLine(fixedExEnd); if (endAddr > maxEndAddr) { - catchedExceptions.clear(); + catchedExceptionIds.clear(); maxEndAddr = avm2code.getAddrThroughJumpAndDebugLine(fixedExEnd); - endIp = avm2code.adr2pos(maxEndAddr); - realEndIp = avm2code.adr2pos(fixedExEnd); - catchedExceptions.add(body.exceptions[e]); + /*endIp = avm2code.adr2pos(maxEndAddr); + realEndIp = avm2code.adr2pos(fixedExEnd);*/ + + catchedExceptionIds.add(e); + } else if (endAddr == maxEndAddr) { - catchedExceptions.add(body.exceptions[e]); + catchedExceptionIds.add(e); } } } @@ -783,8 +809,7 @@ public class AVM2Graph extends Graph { } //GraphPart endPart = searchPart(endIp, allParts); - int finallyIndex = -1; - ABCException finallyException = null; + //finallyIndex.setVal(-1); Collections.sort(finnalysIndicesToBe, new Comparator() { @Override @@ -793,48 +818,63 @@ public class AVM2Graph extends Graph { } }); - /*if (catchedExceptions.isEmpty() && !finnalysIndicesToBe.isEmpty()) { - for (int i = 0; i < finnalysIndicesToBe.size(); i++) { - int e = finnalysIndicesToBe.get(i); - if (!localData.ignoredSwitches.containsKey(e)) { - catchedExceptions.add(body.exceptions[e]); - finnalysIndicesToBe.remove(i); - break; - } - } - }*/ - GraphPart outSideExceptionPart = null; - if (!catchedExceptions.isEmpty()) { - outSideExceptionPart = searchFirstPartOutSideTryCatch(localData, catchedExceptions.get(0), loops, allParts); + if (!catchedExceptionIds.isEmpty()) { + outSideExceptionPart = searchFirstPartOutSideTryCatch(localData, body.exceptions[catchedExceptionIds.get(0)], loops, allParts); } for (int e : finnalysIndicesToBe) { ABCException finallyExceptionToBe = body.exceptions[e]; - if (catchedExceptions.isEmpty() || outSideExceptionPart == null) { + if (catchedExceptionIds.isEmpty() || outSideExceptionPart == null) { //there's no exception, finally only - finallyIndex = e; - finallyException = finallyExceptionToBe; + finallyIndex.setVal(e); break; } GraphPart outSideExceptionNonEmptyPart = nearestNonEmptyPart(outSideExceptionPart); GraphPart outSideFinallyPart = searchFirstPartOutSideTryCatch(localData, finallyExceptionToBe, loops, allParts); if (outSideExceptionNonEmptyPart == outSideFinallyPart) { - finallyIndex = e; - finallyException = finallyExceptionToBe; + finallyIndex.setVal(e); break; } if (outSideExceptionNonEmptyPart.nextParts.size() == 1 && outSideExceptionNonEmptyPart.nextParts.get(0) == outSideFinallyPart) { if (outSideExceptionNonEmptyPart.getHeight() == 1) { if (avm2code.code.get(outSideExceptionNonEmptyPart.start).definition instanceof PushByteIns) { - finallyIndex = e; - finallyException = finallyExceptionToBe; + finallyIndex.setVal(e); break; } } } } + } + + private boolean checkTry(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, AVM2LocalData localData, GraphPart part, List stopPart, List loops, List throwStates, Set allParts, TranslateStack stack, int staticOperation, String path) throws InterruptedException { + if (localData.parsedExceptions == null) { + localData.parsedExceptions = new ArrayList<>(); + } + if (localData.finallyJumps == null) { + localData.finallyJumps = new HashMap<>(); + } + if (localData.ignoredSwitches == null) { + localData.ignoredSwitches = new HashMap<>(); + } + + List parsedExceptions = localData.parsedExceptions; + List parsedExceptionIds = localData.parsedExceptionIds; + + List catchedExceptionIds = new ArrayList<>(); + Reference finallyIndexRef = new Reference<>(-1); + + getCatchedExceptionIds(part, parsedExceptionIds, catchedExceptionIds, finallyIndexRef, allParts, loops, localData); + List catchedExceptions = new ArrayList<>(); + for (int e : catchedExceptionIds) { + catchedExceptions.add(body.exceptions[e]); + } + ABCException finallyException = null; + int finallyIndex = finallyIndexRef.getVal(); + if (finallyIndex > -1) { + finallyException = body.exceptions[finallyIndex]; + } if (finallyException != null) { catchedExceptions.add(finallyException); @@ -846,10 +886,24 @@ public class AVM2Graph extends Graph { } if (catchedExceptions.size() > 0) { + + for (ThrowState ts : throwStates) { + if (catchedExceptionIds.contains(ts.exceptionId)) { + ts.state = 1; + } + if (ts.exceptionId == finallyIndex) { + ts.state = 1; + } + } + parsedExceptions.addAll(catchedExceptions); + parsedExceptionIds.addAll(catchedExceptionIds); if (finallyException != null) { catchedExceptions.remove(finallyException); } + if (finallyIndex > -1) { + parsedExceptionIds.add(finallyIndex); + } List tryCommands = new ArrayList<>(); List> catchCommands = new ArrayList<>(); List finallyCommands = new ArrayList<>(); @@ -863,13 +917,20 @@ public class AVM2Graph extends Graph { } if (partsToCalCommon.size() > 1) { - afterPart = getMostCommonPart(localData, partsToCalCommon, loops); + /*System.err.println("getting common part of"); + for (GraphPart p : partsToCalCommon) { + System.err.println("- " + p); + }*/ + + afterPart = getMostCommonPart(localData, partsToCalCommon, loops, throwStates); + //System.err.println("result: " + afterPart); } if (catchedExceptions.size() > 0 && afterPart == null) { //in all catches is probably continue/return/break or something //we need to search a part which is first outside the try..block afterPart = searchFirstPartOutSideTryCatch(localData, catchedExceptions.get(0), loops, allParts); + //System.err.println("oursidetrycatch: " + afterPart); } GraphPart exAfterPart = afterPart; @@ -877,7 +938,7 @@ public class AVM2Graph extends Graph { if (finallyException == null) { List stopPart2 = new ArrayList<>(stopPart); stopPart2.add(afterPart); - tryCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, part, stopPart2, loops, staticOperation, path); + tryCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, part, stopPart2, loops, throwStates, staticOperation, path); } boolean inlinedFinally = false; @@ -899,12 +960,15 @@ public class AVM2Graph extends Graph { int targetPos = avm2code.adr2pos(finallyException.target); finallyTryTargetPart = searchPart(targetPos, allParts); + //Is it wrong to assume try target is only single part before finally? finallyPart = finallyTryTargetPart.nextParts.isEmpty() ? null : finallyTryTargetPart.nextParts.get(0); - List finallyTargetStopPart = new ArrayList<>(stopPart); - + //List finallyTargetStopPart = new ArrayList<>(stopPart); + if (finallyPart != null) { + //finallyTargetStopPart + } if (afterPart != null) { - finallyTargetStopPart.add(afterPart); + //finallyTargetStopPart.add(afterPart); } TranslateStack st2 = (TranslateStack) stack.clone(); @@ -912,8 +976,10 @@ public class AVM2Graph extends Graph { st2.add(new ExceptionAVM2Item(finallyException)); AVM2LocalData localData2 = new AVM2LocalData(localData); localData2.scopeStack = new ScopeStack(); - finallyTargetItems = printGraph(foundGotos, partCodes, partCodePos, localData2, st2, allParts, null, finallyTryTargetPart, finallyTargetStopPart, loops, 0, path); - boolean targetHasThrow = false; + + //We are assuming Finally target has only 1 part + finallyTargetItems = translatePart(localData, finallyTryTargetPart, st2, staticOperation, path);//printGraph(foundGotos, partCodes, partCodePos, visited, localData2, st2, allParts, null, finallyTryTargetPart, finallyTargetStopPart, loops, throwStates, 0, path); + //boolean targetHasThrow = false; if (!finallyTargetItems.isEmpty() && (finallyTargetItems.get(finallyTargetItems.size() - 1) instanceof ThrowAVM2Item)) { //ignore some usual commands at the beginning - these are ignored in ffdec later, but we need to check it's empty @@ -940,7 +1006,7 @@ public class AVM2Graph extends Graph { if (!isEmpty) { //there must be at least single command before Throw inlinedFinally = true; } - targetHasThrow = true; + //targetHasThrow = true; } List tryStopPart = new ArrayList<>(stopPart); @@ -948,23 +1014,27 @@ public class AVM2Graph extends Graph { tryStopPart.add(finallyPart); } - if (finallyPart == null && afterPart != null) { - tryStopPart.add(afterPart); - } - if (defaultPart != null) { tryStopPart.add(defaultPart); } - - if (switchPart == null && inlinedFinally && afterPart == null) { + //switchPart == null && inlinedFinally && + if (afterPart == null) { afterPart = searchFirstPartOutSideTryCatch(localData, finallyException, loops, allParts); - if (afterPart != null) { - tryStopPart.add(afterPart); + } + + if (afterPart != null) { + tryStopPart.add(afterPart); + } + + if (switchPart != null) { + afterPart = defaultPart; + } else { + if (!inlinedFinally) { + afterPart = null; } } - - tryCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, part, tryStopPart, loops, staticOperation, path); + tryCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, part, tryStopPart, loops, throwStates, staticOperation, path); makeAllCommands(tryCommands, stack); processIfs(tryCommands); @@ -980,17 +1050,11 @@ public class AVM2Graph extends Graph { finallyStopPart.add(switchPart); } if (finallyPart != null) { - finallyCommands = printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, finallyPart, finallyStopPart, loops, staticOperation, path); + finallyCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, finallyPart, finallyStopPart, loops, throwStates, staticOperation, path); } if (switchPart != null) { finallyCommands.addAll(translatePart(localData, switchPart, stack, staticOperation, path)); - stack.pop(); //value switched by lookupswitch - afterPart = defaultPart; - exAfterPart = afterPart; - } else { - if (!inlinedFinally) { - afterPart = null; - } + stack.pop(); //value switched by lookupswitch } } @@ -1016,7 +1080,7 @@ public class AVM2Graph extends Graph { stopPart2.add(defaultPart); } - List currentCatchCommands = printGraph(foundGotos, partCodes, partCodePos, localData2, st2, allParts, null, catchPart, stopPart2, loops, staticOperation, path); + List currentCatchCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData2, st2, allParts, null, catchPart, stopPart2, loops, throwStates, staticOperation, path); /*if (!currentCatchCommands.isEmpty() && (currentCatchCommands.get(0) instanceof SetLocalAVM2Item)) { if (currentCatchCommands.get(0).value.getNotCoerced() instanceof ExceptionAVM2Item) { currentCatchCommands.remove(0); @@ -1031,6 +1095,15 @@ public class AVM2Graph extends Graph { catchCommands.add(currentCatchCommands); } + for (ThrowState ts : throwStates) { + if (catchedExceptionIds.contains(ts.exceptionId)) { + ts.state = 2; + } + if (ts.exceptionId == finallyIndex) { + ts.state = 2; + } + } + if (!inlinedFinally && catchCommands.isEmpty() && finallyCommands.isEmpty() && tryCommands.isEmpty()) { return false; } @@ -1047,7 +1120,6 @@ public class AVM2Graph extends Graph { return true; } - TryAVM2Item tryItem = new TryAVM2Item(tryCommands, catchedExceptions, catchCommands, finallyCommands, ""); if (inlinedFinally) { List> parentCatchCommands = new ArrayList<>(); @@ -1079,7 +1151,7 @@ public class AVM2Graph extends Graph { if (finallyIndex > -1 && localData.finallyIndicesWithDoublePush.contains(finallyIndex)) { stack.push(new AnyItem()); } - currentRet.addAll(printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, afterPart, stopPart, loops, staticOperation, path)); + currentRet.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, afterPart, stopPart, loops, throwStates, staticOperation, path)); } return true; } @@ -1087,7 +1159,22 @@ public class AVM2Graph extends Graph { } @Override - protected boolean canHandleLoop(BaseLocalData localData, GraphPart part, List loops) { + protected boolean canHandleVisited(BaseLocalData localData, GraphPart part) { + AVM2LocalData aLocalData = (AVM2LocalData) localData; + for (ABCException ex : body.exceptions) { + if (aLocalData.parsedExceptions.contains(ex)) { + continue; + } + int fixStart = avm2code.adr2pos(ex.start, true); + if (part.start == fixStart) { + return false; + } + } + return true; + } + + @Override + protected boolean canHandleLoop(BaseLocalData localData, GraphPart part, List loops, List throwStates) { Loop toBeLoop = null; for (Loop el : loops) { if ((el.loopContinue == part) && (el.phase == 0)) { @@ -1124,15 +1211,14 @@ public class AVM2Graph extends Graph { return true; } - @Override - protected boolean checkPartOutput(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, Loop currentLoop, int staticOperation, String path) throws InterruptedException { + protected boolean checkPartOutput(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List throwStates, Loop currentLoop, int staticOperation, String path) throws InterruptedException { AVM2LocalData aLocalData = (AVM2LocalData) localData; - return checkTry(currentRet, foundGotos, partCodes, partCodePos, aLocalData, part, stopPart, loops, allParts, stack, staticOperation, path); + return checkTry(currentRet, foundGotos, partCodes, partCodePos, visited, aLocalData, part, stopPart, loops, throwStates, allParts, stack, staticOperation, path); } @Override - protected List check(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { + protected List check(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List throwStates, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { List ret = null; /*if (ret != null) { @@ -1218,13 +1304,15 @@ public class AVM2Graph extends Graph { } else { part = part.nextParts.get(1); GraphPart defaultPart = part; - if (code.size() > defaultPart.start && ((AVM2Instruction) code.get(defaultPart.start)).definition instanceof JumpIns) { + if (code.size() > defaultPart.start && ((AVM2Instruction) code.get(defaultPart.start)).definition instanceof JumpIns + && defaultPart.refs.size() == 1 + && !partIsLoopContBrePre(defaultPart, loops, throwStates)) { defaultPart = defaultPart.nextParts.get(0); } Reference nextRef = new Reference<>(null); Reference tiRef = new Reference<>(null); - SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, allParts, stack, stopPart, loops, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef); + SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, loops, throwStates, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef); ret = new ArrayList<>(); ret.addAll(output); checkSwitch(localData, sw, otherSide, ret.isEmpty() ? currentRet : ret /*hack :-(*/); @@ -1233,7 +1321,7 @@ public class AVM2Graph extends Graph { if (tiRef.getVal() != null) { ret.add(tiRef.getVal()); } else { - ret.addAll(printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, nextRef.getVal(), stopPart, loops, staticOperation, path)); + ret.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, nextRef.getVal(), stopPart, loops, throwStates, staticOperation, path)); } } } @@ -1348,7 +1436,7 @@ public class AVM2Graph extends Graph { } @Override - protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops) { + protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops, List throwStates) { AVM2LocalData aLocalData = (AVM2LocalData) localData; if (loopItem instanceof WhileItem) { WhileItem w = (WhileItem) loopItem; @@ -1812,8 +1900,8 @@ public class AVM2Graph extends Graph { } @Override - protected FinalProcessLocalData getFinalData(BaseLocalData localData, List loops) { - FinalProcessLocalData finalProcess = super.getFinalData(localData, loops); + protected FinalProcessLocalData getFinalData(BaseLocalData localData, List loops, List throwStates) { + FinalProcessLocalData finalProcess = super.getFinalData(localData, loops, throwStates); finalProcess.registerUsage = ((AVM2LocalData) localData).setLocalPosToGetLocalPos; return finalProcess; } @@ -1868,4 +1956,25 @@ public class AVM2Graph extends Graph { } return avm2code.code.get(part.end).definition instanceof LookupSwitchIns; } + + @Override + protected List getThrowStates(Set allParts) { + List ret = new ArrayList<>(); + for (int e = 0; e < body.exceptions.length; e++) { + ThrowState ts = new ThrowState(); + ts.exceptionId = e; + ts.state = 0; + ts.targetPart = searchPart(code.adr2pos(body.exceptions[e].target), allParts); + int startIp = code.adr2pos(body.exceptions[e].start, true); + int endIp = code.adr2pos(body.exceptions[e].end, true); + for (GraphPart p : allParts) { + if (p.start >= startIp && p.start < endIp) { + ts.throwingParts.add(p); + } + } + ret.add(ts); + } + return ret; + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java index 20c8fc405..a1f3124db 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -48,6 +48,7 @@ import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphSourceItemContainer; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.Loop; +import com.jpexs.decompiler.graph.ThrowState; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.ContinueItem; @@ -58,6 +59,7 @@ import com.jpexs.decompiler.graph.model.ScriptEndItem; import com.jpexs.decompiler.graph.model.SwitchItem; import com.jpexs.decompiler.graph.model.WhileItem; import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Reference; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; @@ -288,7 +290,7 @@ public class ActionGraph extends Graph { } @Override - protected List check(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { + protected List check(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List throwStates, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { if (!output.isEmpty()) { if (output.get(output.size() - 1) instanceof StoreRegisterActionItem) { StoreRegisterActionItem str = (StoreRegisterActionItem) output.get(output.size() - 1); @@ -312,13 +314,11 @@ public class ActionGraph extends Graph { } List caseValuesMap = new ArrayList<>(); - //int pos = 0; StrictEqActionItem set = (StrictEqActionItem) stack.pop(); caseValuesMap.add(set.rightSide); if (set.leftSide instanceof StoreRegisterActionItem) { switchedObject = ((StoreRegisterActionItem) set.leftSide).value; } - //GraphPart switchLoc = part.nextParts.get(1).nextParts.get(0); List caseBodyParts = new ArrayList<>(); caseBodyParts.add(part.nextParts.get(0)); GraphTargetItem top = null; @@ -339,185 +339,23 @@ public class ActionGraph extends Graph { } else { part = part.nextParts.get(1); GraphPart defaultPart = part; - if (code.size() > defaultPart.start && code.get(defaultPart.start) instanceof ActionJump) { + if (code.size() > defaultPart.start && code.get(defaultPart.start) instanceof ActionJump + && defaultPart.refs.size() == 1 + && !partIsLoopContBrePre(defaultPart, loops, throwStates)) { defaultPart = defaultPart.nextParts.get(0); } - boolean hasDefault = false; - /* - case 4: - case 5: - default: - trace("5 & def"); - ... - case 6: - - */ - //must go backwards to hit case 5, not case 4 - for (int i = caseBodyParts.size() - 1; i >= 0; i--) { - if (caseBodyParts.get(i) == defaultPart) { - DefaultItem di = new DefaultItem(); - caseValuesMap.add(i + 1, di); - caseBodyParts.add(i + 1, defaultPart); - hasDefault = true; - break; - } - } - - if (!hasDefault) { - /* - case 1: - trace("1"); - case 2: - trace("2"); //no break - default: - trace("def"); - ... - case 3: - */ - //must go backwards to hit case 2, not case 1 - for (int i = caseBodyParts.size() - 1; i >= 0; i--) { - if (caseBodyParts.get(i).leadsTo(localData, this, code, defaultPart, loops, false)) { - DefaultItem di = new DefaultItem(); - caseValuesMap.add(i + 1, di); - caseBodyParts.add(i + 1, defaultPart); - hasDefault = true; - break; - } - } - } - - if (!hasDefault) { - /* - case 1: - trace("1"); - break; - default: - trace("def"); //no break - case 2: - trace("2"); - */ - for (int i = 0; i < caseBodyParts.size(); i++) { - if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops, false)) { - DefaultItem di = new DefaultItem(); - caseValuesMap.add(i, di); - caseBodyParts.add(i, defaultPart); - hasDefault = true; - break; - } - } - } - - if (!hasDefault) { - /* - case 1: - ... - case 2: - ... - default: - trace("def"); - */ - caseValuesMap.add(new DefaultItem()); - caseBodyParts.add(defaultPart); - } - - GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops); - //removeEdgeToFromList(gotoTargets, breakPart); - List> caseCommands = new ArrayList<>(); - GraphPart next = breakPart; - - GraphTargetItem ti = checkLoop(new ArrayList(), next, stopPart, loops); - - //create switch as new loop break command detection to work - currentLoop = new Loop(loops.size(), null, next); - currentLoop.phase = 1; - loops.add(currentLoop); - List valuesMapping = new ArrayList<>(); - List caseBodies = new ArrayList<>(); - for (int i = 0; i < caseValuesMap.size(); i++) { - GraphPart cur = caseBodyParts.get(i); - if (!caseBodies.contains(cur)) { - //removeEdgeToFromList(gotoTargets, cur); - caseBodies.add(cur); - } - valuesMapping.add(caseBodies.indexOf(cur)); - } - - for (int i = 0; i < caseBodies.size(); i++) { - List currentCaseCommands = new ArrayList<>(); - GraphPart nextCase = next; - if (next != null) { - if (i < caseBodies.size() - 1) { - if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops, false)) { - currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id)); - } else { - nextCase = caseBodies.get(i + 1); - } - } - } - List stopPart2x = new ArrayList<>(stopPart); - for (GraphPart b : caseBodies) { - if (b != caseBodies.get(i)) { - stopPart2x.add(b); - } - } - if (breakPart != null) { - stopPart2x.add(breakPart); - } - currentCaseCommands.addAll(0, printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, staticOperation, path)); - if (currentCaseCommands.size() >= 2) { - if (currentCaseCommands.get(currentCaseCommands.size() - 1) instanceof BreakItem) { - if ((currentCaseCommands.get(currentCaseCommands.size() - 2) instanceof ContinueItem) || (currentCaseCommands.get(currentCaseCommands.size() - 2) instanceof BreakItem)) { - currentCaseCommands.remove(currentCaseCommands.size() - 1); - } - } - } - caseCommands.add(currentCaseCommands); - } - - //If the lastone is default empty and alone, remove it - if (!caseCommands.isEmpty()) { - List lastc = caseCommands.get(caseCommands.size() - 1); - if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) { - BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1); - lastc.remove(lastc.size() - 1); - } - if (lastc.isEmpty()) { - int cnt2 = 0; - if (caseValuesMap.get(caseValuesMap.size() - 1) instanceof DefaultItem) { - for (int i = valuesMapping.size() - 1; i >= 0; i--) { - if (valuesMapping.get(i) == caseCommands.size() - 1) { - cnt2++; - } - } - - caseValuesMap.remove(caseValuesMap.size() - 1); - valuesMapping.remove(valuesMapping.size() - 1); - if (cnt2 == 1) { - caseCommands.remove(lastc); - } - } - } - } - //remove last break from last section - if (!caseCommands.isEmpty()) { - List lastc = caseCommands.get(caseCommands.size() - 1); - if (!lastc.isEmpty() && (lastc.get(lastc.size() - 1) instanceof BreakItem)) { - BreakItem bi = (BreakItem) lastc.get(lastc.size() - 1); - lastc.remove(lastc.size() - 1); - } - } - + Reference nextRef = new Reference<>(null); + Reference tiRef = new Reference<>(null); + SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, loops, throwStates, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef); ret = new ArrayList<>(); ret.addAll(output); - SwitchItem sti = new SwitchItem(null, switchStartItem, currentLoop, switchedObject, caseValuesMap, caseCommands, valuesMapping); - ret.add(sti); - currentLoop.phase = 2; - if (next != null) { - if (ti != null) { - ret.add(ti); + ret.add(sw); + if (nextRef.getVal() != null) { + if (tiRef.getVal() != null) { + ret.add(tiRef.getVal()); } else { - ret.addAll(printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, next, stopPart, loops, staticOperation, path)); + ret.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, nextRef.getVal(), stopPart, loops, throwStates, staticOperation, path)); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 60aee5a2c..54112ccf2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -179,12 +179,12 @@ public class Graph { } } - protected void getReachableParts(BaseLocalData localData, GraphPart part, LinkedHashSet ret, List loops) { + protected void getReachableParts(BaseLocalData localData, GraphPart part, LinkedHashSet ret, List loops, List throwStates) { // use LinkedHashSet to preserve order - getReachableParts(localData, part, ret, loops, true); + getReachableParts(localData, part, ret, loops, throwStates, true); } - private void getReachableParts(BaseLocalData localData, GraphPart part, LinkedHashSet ret, List loops, boolean first) { + private void getReachableParts(BaseLocalData localData, GraphPart part, LinkedHashSet ret, List loops, List throwStates, boolean first) { // todo: honfika: why call with first = true parameter always? Stack stack = new Stack<>(); GraphPartQueue queue = new GraphPartQueue(); @@ -237,8 +237,18 @@ public class Graph { } GraphPartQueue newParts = new GraphPartQueue(); + List nextParts = new ArrayList<>(getNextParts(localData, part)); + /* + !!THROW + for (ThrowState ts : throwStates) { + if (ts.state != 1) { + if (ts.throwingParts.contains(part)) { + newParts.add(ts.targetPart); + } + } + }*/ loopnext: - for (GraphPart nextRaw : getNextParts(localData, part)) { + for (GraphPart nextRaw : nextParts) { GraphPart next = checkPart(null, localData, part, nextRaw, null); if (next == null) { @@ -275,12 +285,12 @@ public class Graph { } } - public GraphPart getNextCommonPart(BaseLocalData localData, GraphPart part, List loops) throws InterruptedException { - return getCommonPart(localData, part, getNextParts(localData, part), loops); + public GraphPart getNextCommonPart(BaseLocalData localData, GraphPart part, List loops, List throwStates) throws InterruptedException { + return getCommonPart(localData, part, getNextParts(localData, part), loops, throwStates); } //TODO: Make this faster! - public GraphPart getCommonPart(BaseLocalData localData, GraphPart prev, List parts, List loops) throws InterruptedException { + public GraphPart getCommonPart(BaseLocalData localData, GraphPart prev, List parts, List loops, List throwStates) throws InterruptedException { if (parts.isEmpty()) { return null; } @@ -304,7 +314,7 @@ public class Graph { if (q == p) { continue; } - if (!q.leadsTo(localData, this, code, p, loops, false)) { + if (!q.leadsTo(localData, this, code, p, loops, throwStates, false /*!!THROW*/)) { common = false; break; } @@ -316,7 +326,7 @@ public class Graph { List> reachable = new ArrayList<>(); for (GraphPart p : parts) { LinkedHashSet r1 = new LinkedHashSet<>(); - getReachableParts(localData, p, r1, loops); + getReachableParts(localData, p, r1, loops, throwStates); r1.add(p); reachable.add(r1); } @@ -339,7 +349,7 @@ public class Graph { return null; } - public GraphPart getMostCommonPart(BaseLocalData localData, List parts, List loops) throws InterruptedException { + public GraphPart getMostCommonPart(BaseLocalData localData, List parts, List loops, List throwStates) throws InterruptedException { if (parts.isEmpty()) { return null; } @@ -364,7 +374,7 @@ public class Graph { if (q == p) { continue; } - if (!q.leadsTo(localData, this, code, p, loops, false)) { + if (!q.leadsTo(localData, this, code, p, loops, throwStates, false /*!!THROW*/)) { common = false; break; } @@ -391,7 +401,7 @@ public class Graph { Set allReachable = new LinkedHashSet<>(); for (GraphPart p : parts) { LinkedHashSet r1 = new LinkedHashSet<>(); - getReachableParts(localData, p, r1, loops); + getReachableParts(localData, p, r1, loops, throwStates); Set r2 = new LinkedHashSet<>(); r2.add(p); r2.addAll(r1); @@ -472,6 +482,10 @@ public class Graph { } + protected List getThrowStates(Set allParts) { + return new ArrayList<>(); + } + public List translate(BaseLocalData localData, int staticOperation, String path) throws InterruptedException { Set allParts = new HashSet<>(); @@ -499,10 +513,12 @@ public class Graph { System.err.println("/parts"); } TranslateStack stack = new TranslateStack(path); - beforeGetLoops(localData, path, allParts); + List throwStates = getThrowStates(allParts); + beforeGetLoops(localData, path, allParts, throwStates); List loops = new ArrayList<>(); - getLoops(localData, heads.get(0), loops, null); + + getLoops(localData, heads.get(0), loops, throwStates, null); afterGetLoops(localData, path, allParts); if (debugPrintLoopList) { @@ -514,7 +530,7 @@ public class Graph { } //TODO: Make getPrecontinues faster - getBackEdges(localData, loops); + getBackEdges(localData, loops, throwStates); new GraphPrecontinueDetector().detectPrecontinues(heads, allParts, loops); @@ -525,7 +541,7 @@ public class Graph { System.err.println("");//*/ List gotos = new ArrayList<>(); - List ret = printGraph(gotos, new HashMap<>(), new HashMap<>(), localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path); + List ret = printGraph(gotos, new HashMap<>(), new HashMap<>(), new HashSet<>(), localData, stack, allParts, null, heads.get(0), null, loops, throwStates, staticOperation, path); processIfGotos(gotos, ret); @@ -548,15 +564,15 @@ public class Graph { processIfs(ret); finalProcessStack(stack, ret, path); makeAllCommands(ret, stack); - finalProcessAll(ret, 0, getFinalData(localData, loops), path); + finalProcessAll(ret, 0, getFinalData(localData, loops, throwStates), path); return ret; } - protected FinalProcessLocalData getFinalData(BaseLocalData localData, List loops) { + protected FinalProcessLocalData getFinalData(BaseLocalData localData, List loops, List throwStates) { return new FinalProcessLocalData(loops); } - protected void beforeGetLoops(BaseLocalData localData, String path, Set allParts) throws InterruptedException { + protected void beforeGetLoops(BaseLocalData localData, String path, Set allParts, List throwStates) throws InterruptedException { } @@ -598,7 +614,7 @@ public class Graph { return getUnicatePartList(result); } - private List getUsableRefs(GraphPart g, List loops) { + private List getUsableRefs(GraphPart g, List loops, List throwStates) { List ret = getUnicatePartList(g.refs); for (Loop el : loops) { for (GraphPart be : el.backEdges) { @@ -613,13 +629,13 @@ public class Graph { /**/ //if (getNextParts(localData, ref)) - private void getBackEdges(BaseLocalData localData, List loops) throws InterruptedException { + private void getBackEdges(BaseLocalData localData, List loops, List throwStates) throws InterruptedException { clearLoops(loops); for (Loop el : loops) { el.backEdges.clear(); Set uniqueRefs = new HashSet<>(el.loopContinue.refs); for (GraphPart r : uniqueRefs) { - if (el.loopContinue.leadsTo(localData, this, code, r, loops, true)) { + if (el.loopContinue.leadsTo(localData, this, code, r, loops, throwStates, true)) { el.backEdges.add(r); } } @@ -985,7 +1001,7 @@ public class Graph { return ret; } - protected GraphTargetItem checkLoop(List output, GraphPart part, List stopPart, List loops) { + protected GraphTargetItem checkLoop(List output, GraphPart part, List stopPart, List loops, List throwStates) { if (stopPart.contains(part)) { return null; } @@ -1045,7 +1061,7 @@ public class Graph { return false; } - protected List check(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { + protected List check(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List throwStates, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { return null; } @@ -1125,11 +1141,11 @@ public class Graph { list.remove(list.size() - 1); } - protected List printGraph(List foundGotos, Map> partCodes, Map partCodePos, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List loops, int staticOperation, String path) throws InterruptedException { - return printGraph(foundGotos, partCodes, partCodePos, new HashSet<>(), localData, stack, allParts, parent, part, stopPart, loops, null, staticOperation, path, 0); + protected List printGraph(List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List loops, List throwStates, int staticOperation, String path) throws InterruptedException { + return printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, parent, part, stopPart, loops, throwStates, null, staticOperation, path, 0); } - protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops) { + protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops, List throwStates) { return loopItem; } @@ -1139,9 +1155,9 @@ public class Graph { } } - private void getLoops(BaseLocalData localData, GraphPart part, List loops, List stopPart) throws InterruptedException { + private void getLoops(BaseLocalData localData, GraphPart part, List loops, List throwStates, List stopPart) throws InterruptedException { clearLoops(loops); - getLoops(localData, part, loops, stopPart, true, 1, new ArrayList<>()); + getLoops(localData, part, loops, throwStates, stopPart, true, 1, new ArrayList<>()); clearLoops(loops); } @@ -1149,7 +1165,11 @@ public class Graph { return true; } - private void getLoops(BaseLocalData localData, GraphPart part, List loops, List stopPart, boolean first, int level, List visited) throws InterruptedException { + protected void checkGetLoopsPart(GraphPart part) { + + } + + private void getLoops(BaseLocalData localData, GraphPart part, List loops, List throwStates, List stopPart, boolean first, int level, List visited) throws InterruptedException { if (part == null) { return; @@ -1162,6 +1182,7 @@ public class Graph { if (!visited.contains(part)) { visited.add(part); } + checkGetLoopsPart(part); if (debugGetLoops) { System.err.println("getloops: " + part); @@ -1187,7 +1208,7 @@ public class Graph { } else { List loops2 = new ArrayList<>(loops); loops2.remove(lastP1); - if (!part.leadsTo(localData, this, code, lastP1.loopContinue, loops2, true)) { + if (!part.leadsTo(localData, this, code, lastP1.loopContinue, loops2, throwStates, true)) { if (lastP1.breakCandidatesLocked == 0) { if (debugGetLoops) { System.err.println("added breakCandidate " + part + " to " + lastP1); @@ -1212,7 +1233,7 @@ public class Graph { } part.level = level; - boolean isLoop = part.leadsTo(localData, this, code, part, loops, true); + boolean isLoop = part.leadsTo(localData, this, code, part, loops, throwStates, true); Loop currentLoop = null; if (isLoop) { currentLoop = new Loop(loops.size(), part, null); @@ -1232,22 +1253,22 @@ public class Graph { }*/ nps = part.nextParts; - GraphPart next = getCommonPart(localData, part, nps, loops); + GraphPart next = getCommonPart(localData, part, nps, loops, throwStates); List stopPart2 = stopPart == null ? new ArrayList<>() : new ArrayList<>(stopPart); if (next != null) { stopPart2.add(next); } if (next != nps.get(0)) { - getLoops(localData, nps.get(0), loops, stopPart2, false, level + 1, visited); + getLoops(localData, nps.get(0), loops, throwStates, stopPart2, false, level + 1, visited); } if (next != nps.get(1)) { - getLoops(localData, nps.get(1), loops, stopPart2, false, level + 1, visited); + getLoops(localData, nps.get(1), loops, throwStates, stopPart2, false, level + 1, visited); } if (next != null) { - getLoops(localData, next, loops, stopPart, false, level, visited); + getLoops(localData, next, loops, throwStates, stopPart, false, level, visited); } } else if (part.nextParts.size() > 2 || partIsSwitch(part)) { - GraphPart next = getNextCommonPart(localData, part, loops); + GraphPart next = getNextCommonPart(localData, part, loops, throwStates); for (GraphPart p : part.nextParts) { List stopPart2 = stopPart == null ? new ArrayList<>() : new ArrayList<>(stopPart); @@ -1263,23 +1284,27 @@ public class Graph { } } if (next != p) { - getLoops(localData, p, loops, stopPart2, false, level + 1, visited); + getLoops(localData, p, loops, throwStates, stopPart2, false, level + 1, visited); } } if (next != null) { - getLoops(localData, next, loops, stopPart, false, level, visited); + getLoops(localData, next, loops, throwStates, stopPart, false, level, visited); } } else if (part.nextParts.size() == 1) { - getLoops(localData, part.nextParts.get(0), loops, stopPart, false, level, visited); + getLoops(localData, part.nextParts.get(0), loops, throwStates, stopPart, false, level, visited); } List loops2 = new ArrayList<>(loops); for (Loop l : loops2) { l.breakCandidatesLocked++; } - for (GraphPart t : part.throwParts) { - if (!visited.contains(t)) { - getLoops(localData, t, loops, stopPart, false, level, visited); + for (ThrowState ts : throwStates) { + //check state? + if (ts.throwingParts.contains(part)) { + GraphPart t = ts.targetPart; + if (!visited.contains(t)) { + getLoops(localData, t, loops, throwStates, stopPart, false, level, visited); + } } } for (Loop l : loops2) { @@ -1304,7 +1329,7 @@ public class Graph { if (cand == cand2) { continue; } - if (cand.leadsTo(localData, this, code, cand2, loops, true)) { + if (cand.leadsTo(localData, this, code, cand2, loops, throwStates, true)) { int lev1 = Integer.MAX_VALUE; int lev2 = Integer.MAX_VALUE; for (int i = 0; i < currentLoop.breakCandidates.size(); i++) { @@ -1406,7 +1431,7 @@ public class Graph { if (removedVisited.contains(r)) { continue; } - getLoops(localData, r, loops, stopPart, false, removed.get(r), visited); + getLoops(localData, r, loops, throwStates, stopPart, false, removed.get(r), visited); removedVisited.add(r); } start = false; @@ -1419,7 +1444,7 @@ public class Graph { el.phase = 2; } } - getLoops(localData, currentLoop.loopBreak, loops, stopPart, false, level, visited); + getLoops(localData, currentLoop.loopBreak, loops, throwStates, stopPart, false, level, visited); } } @@ -1444,14 +1469,36 @@ public class Graph { return part.nextParts; } - protected boolean checkPartOutput(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, Loop currentLoop, int staticOperation, String path) throws InterruptedException { + protected boolean checkPartOutput(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List throwStates, Loop currentLoop, int staticOperation, String path) throws InterruptedException { return false; } - protected boolean canHandleLoop(BaseLocalData localData, GraphPart part, List loops) { + protected boolean partIsLoopContBrePre(GraphPart part, List loops, List throwStates) { + for (Loop el : loops) { + if (el.phase == 1) { + if (el.loopBreak == part) { + return true; + } + if (el.loopContinue == part) { + return true; + } + if (el.loopPreContinue == part) { + return true; + } + } + } + return false; + } + + protected boolean canHandleLoop(BaseLocalData localData, GraphPart part, List loops, List throwStates) { return true; } - protected List printGraph(List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List loops, List ret, int staticOperation, String path, int recursionLevel) throws InterruptedException { + + protected boolean canHandleVisited(BaseLocalData localData, GraphPart part) { + return true; + } + + protected List printGraph(List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List loops, List throwStates, List ret, int staticOperation, String path, int recursionLevel) throws InterruptedException { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } @@ -1465,8 +1512,8 @@ public class Graph { if (ret == null) { ret = new ArrayList<>(); } - //try { + //try { if (debugPrintGraph) { System.err.println("PART " + part + " nextsize:" + getNextParts(localData, part).size()); } @@ -1499,7 +1546,7 @@ public class Graph { boolean isLoop = false; Loop currentLoop = null; - boolean vCanHandleLoop = canHandleLoop(localData, part, loops); + boolean vCanHandleLoop = canHandleLoop(localData, part, loops, throwStates); Loop ignoredLoop = null; for (Loop el : loops) { if ((el.loopContinue == part) && (el.phase == 0)) { @@ -1589,24 +1636,33 @@ public class Graph { return ret; } - if (visited.contains(part)) { - String labelName = "addr" + part.start; - List firstCode = partCodes.get(part); - int firstCodePos = partCodePos.get(part); - if (firstCodePos > firstCode.size()) { - firstCodePos = firstCode.size(); - } - if (firstCode.size() > firstCodePos && (firstCode.get(firstCodePos) instanceof LabelItem)) { - labelName = ((LabelItem) firstCode.get(firstCodePos)).labelName; + boolean vCanHandleVisited = canHandleVisited(localData, part); + + /*if (part.start == 31) { + + FIXME + new RuntimeException().printStackTrace(); + }*/ + if (vCanHandleVisited) { + if (visited.contains(part)) { + String labelName = "addr" + part.start; + List firstCode = partCodes.get(part); + int firstCodePos = partCodePos.get(part); + if (firstCodePos > firstCode.size()) { + firstCodePos = firstCode.size(); + } + if (firstCode.size() > firstCodePos && (firstCode.get(firstCodePos) instanceof LabelItem)) { + labelName = ((LabelItem) firstCode.get(firstCodePos)).labelName; + } else { + firstCode.add(firstCodePos, new LabelItem(null, localData.lineStartInstruction, labelName)); + } + ret.add(new GotoItem(null, localData.lineStartInstruction, labelName)); + return ret; } else { - firstCode.add(firstCodePos, new LabelItem(null, localData.lineStartInstruction, labelName)); + visited.add(part); + partCodes.put(part, ret); + partCodePos.put(part, ret.size()); } - ret.add(new GotoItem(null, localData.lineStartInstruction, labelName)); - return ret; - } else { - visited.add(part); - partCodes.put(part, ret); - partCodePos.put(part, ret.size()); } List currentRet = ret; UniversalLoopItem loopItem = null; @@ -1633,7 +1689,7 @@ public class Graph { //****************************DECOMPILING PART************* List output = new ArrayList<>(); - if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, code, localData, allParts, stack, parent, part, stopPart, loops, currentLoop, staticOperation, path)) { + if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, loops, throwStates, currentLoop, staticOperation, path)) { parseNext = false; } else { output.addAll(code.translatePart(part, localData, stack, part.start, part.end, staticOperation, path)); @@ -1643,7 +1699,7 @@ public class Graph { } if (parseNext) { - List retCheck = check(currentRet, foundGotos, partCodes, partCodePos, code, localData, allParts, stack, parent, part, stopPart, loops, output, currentLoop, staticOperation, path); + List retCheck = check(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, loops, throwStates, output, currentLoop, staticOperation, path); if (retCheck != null) { if (!retCheck.isEmpty()) { currentRet.addAll(retCheck); @@ -1811,7 +1867,7 @@ public class Graph { } Reference nextRef = new Reference<>(null); Reference tiRef = new Reference<>(null); - SwitchItem sw = handleSwitch(switchedItem, originalSwitchedItem.getSrc(), foundGotos, partCodes, partCodePos, allParts, stack, stopPart, loops, localData, staticOperation, path, + SwitchItem sw = handleSwitch(switchedItem, originalSwitchedItem.getSrc(), foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, loops, throwStates, localData, staticOperation, path, caseValues, defaultPart, caseBodyParts, nextRef, tiRef); GraphPart next = nextRef.getVal(); checkSwitch(localData, sw, caseExpressionOtherSides.values(), currentRet); @@ -1820,7 +1876,7 @@ public class Graph { if (tiRef.getVal() != null) { ret.add(tiRef.getVal()); } else { - currentRet.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, null, staticOperation, path, recursionLevel + 1)); + currentRet.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, throwStates, null, staticOperation, path, recursionLevel + 1)); } } pos++; @@ -1839,7 +1895,7 @@ public class Graph { nps = getNextParts(localData, part); boolean isEmpty = nps.get(0) == nps.get(1); - GraphPart next = getCommonPart(localData, part, nps, loops); + GraphPart next = getCommonPart(localData, part, nps, loops, throwStates); //System.err.println("on part " + part + ", next: " + next); TranslateStack trueStack = (TranslateStack) stack.clone(); TranslateStack falseStack = (TranslateStack) stack.clone(); @@ -1866,12 +1922,12 @@ public class Graph { List onTrue = new ArrayList<>(); if (!isEmpty && hasOntrue) { - onTrue = printGraph(foundGotos, partCodes, partCodePos, visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + onTrue = printGraph(foundGotos, partCodes, partCodePos, visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); } List onFalse = new ArrayList<>(); if (!isEmpty && hasOnFalse) { - onFalse = printGraph(foundGotos, partCodes, partCodePos, visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + onFalse = printGraph(foundGotos, partCodes, partCodePos, visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); } //List out2 = new ArrayList<>(); //makeAllCommands(out2, stack); @@ -1974,7 +2030,7 @@ public class Graph { } //currentRet.addAll(out2); if (next != null) { - printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1); + printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, throwStates, currentRet, staticOperation, path, recursionLevel + 1); //currentRet.addAll(); } } @@ -1988,7 +2044,7 @@ public class Graph { } if (nextOnePart != null) { - printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, getNextParts(localData, part).get(0), stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1); + printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, getNextParts(localData, part).get(0), stopPart, loops, throwStates, currentRet, staticOperation, path, recursionLevel + 1); } } @@ -2013,7 +2069,7 @@ public class Graph { stopContPart.add(currentLoop.loopContinue); GraphPart precoBackup = currentLoop.loopPreContinue; currentLoop.loopPreContinue = null; - loopItem.commands.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, precoBackup, stopContPart, loops, null, staticOperation, path, recursionLevel + 1)); + loopItem.commands.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, precoBackup, stopContPart, loops, throwStates, null, staticOperation, path, recursionLevel + 1)); checkContinueAtTheEnd(loopItem.commands, currentLoop); } } @@ -2078,7 +2134,7 @@ public class Graph { currentLoop.loopPreContinue = null; List stopPart2 = new ArrayList<>(stopPart); stopPart2.add(currentLoop.loopContinue); - List precoCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + List precoCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); currentLoop.loopPreContinue = backup; checkContinueAtTheEnd(precoCommands, currentLoop); @@ -2171,7 +2227,7 @@ public class Graph { currentLoop.loopPreContinue = null; List stopPart2 = new ArrayList<>(stopPart); stopPart2.add(currentLoop.loopContinue); - List finalComm = printGraph(foundGotos, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + List finalComm = printGraph(foundGotos, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); currentLoop.loopPreContinue = backup; checkContinueAtTheEnd(finalComm, currentLoop); @@ -2211,7 +2267,7 @@ public class Graph { } currentLoop.phase = 2; - GraphTargetItem replaced = checkLoop(ret, li, localData, loops); + GraphTargetItem replaced = checkLoop(ret, li, localData, loops, throwStates); if (replaced != li) { int index = ret.indexOf(li); ret.remove(index); @@ -2221,7 +2277,7 @@ public class Graph { } if (currentLoop.loopBreak != null) { - ret.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, loops, null, staticOperation, path, recursionLevel + 1)); + ret.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, loops, throwStates, null, staticOperation, path, recursionLevel + 1)); } } @@ -2505,7 +2561,7 @@ public class Graph { } protected SwitchItem handleSwitch(GraphTargetItem switchedObject, - GraphSourceItem switchStartItem, List foundGotos, Map> partCodes, Map partCodePos, Set allParts, TranslateStack stack, List stopPart, List loops, BaseLocalData localData, int staticOperation, String path, + GraphSourceItem switchStartItem, List foundGotos, Map> partCodes, Map partCodePos, Set visited, Set allParts, TranslateStack stack, List stopPart, List loops, List throwStates, BaseLocalData localData, int staticOperation, String path, List caseValuesMap, GraphPart defaultPart, List caseBodyParts, Reference nextRef, Reference tiRef) throws InterruptedException { boolean hasDefault = false; /* @@ -2541,7 +2597,7 @@ public class Graph { */ //must go backwards to hit case 2, not case 1 for (int i = caseBodyParts.size() - 1; i >= 0; i--) { - if (caseBodyParts.get(i).leadsTo(localData, this, code, defaultPart, loops, false)) { + if (caseBodyParts.get(i).leadsTo(localData, this, code, defaultPart, loops, throwStates, false)) { DefaultItem di = new DefaultItem(); caseValuesMap.add(i + 1, di); caseBodyParts.add(i + 1, defaultPart); @@ -2562,7 +2618,7 @@ public class Graph { trace("2"); */ for (int i = 0; i < caseBodyParts.size(); i++) { - if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops, false)) { + if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops, throwStates, false)) { DefaultItem di = new DefaultItem(); caseValuesMap.add(i, di); caseBodyParts.add(i, defaultPart); @@ -2586,13 +2642,13 @@ public class Graph { } //gotoTargets - GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops); + GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops, throwStates); //removeEdgeToFromList(gotoTargets, breakPart); List> caseCommands = new ArrayList<>(); GraphPart next = breakPart; - GraphTargetItem ti = checkLoop(new ArrayList<>() /*??*/, next, stopPart, loops); + GraphTargetItem ti = checkLoop(new ArrayList<>() /*??*/, next, stopPart, loops, throwStates); //create switch as new loop break command detection to work Loop currentLoop = new Loop(loops.size(), null, next); @@ -2614,13 +2670,13 @@ public class Graph { GraphPart b = caseBodies.get(i); for (int j = i + 1; j < caseBodies.size(); j++) { GraphPart b2 = caseBodies.get(j); - if (b2.leadsTo(localData, this, code, b, loops, false)) { + if (b2.leadsTo(localData, this, code, b, loops, throwStates, false)) { caseBodies.remove(j); caseBodies.add(i, b2); i--; continue loopi; } else if (j > i + 1) { - if (b.leadsTo(localData, this, code, b2, loops, false)) { + if (b.leadsTo(localData, this, code, b2, loops, throwStates, false)) { caseBodies.remove(j); caseBodies.add(i + 1, b2); continue loopi; @@ -2636,9 +2692,10 @@ public class Graph { for (int i = 0; i < caseBodies.size(); i++) { List currentCaseCommands = new ArrayList<>(); + boolean willHaveBreak = false; if (i < caseBodies.size() - 1) { - if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops, false)) { - currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id)); + if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops, throwStates, false)) { + willHaveBreak = true; } } @@ -2651,11 +2708,12 @@ public class Graph { if (breakPart != null) { stopPart2x.add(breakPart); } - currentCaseCommands.addAll(0, printGraph(foundGotos, partCodes, partCodePos, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, staticOperation, path)); - if (currentCaseCommands.size() >= 2) { - if (currentCaseCommands.get(currentCaseCommands.size() - 1) instanceof BreakItem) { - if ((currentCaseCommands.get(currentCaseCommands.size() - 2) instanceof ContinueItem) || (currentCaseCommands.get(currentCaseCommands.size() - 2) instanceof BreakItem)) { - currentCaseCommands.remove(currentCaseCommands.size() - 1); + currentCaseCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, throwStates, staticOperation, path); + if (willHaveBreak) { + if (!currentCaseCommands.isEmpty()) { + GraphTargetItem last = currentCaseCommands.get(currentCaseCommands.size() - 1); + if (!(last instanceof ContinueItem) && !(last instanceof BreakItem) && !(last instanceof GotoItem) && !(last instanceof ExitItem) && !(last instanceof ScriptEndItem)) { + currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id)); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPart.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPart.java index 61f4a4f04..80b4ccec1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPart.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPart.java @@ -74,7 +74,7 @@ public class GraphPart implements Serializable { public int order; - public List throwParts = new ArrayList<>(); + //public List throwParts = new ArrayList<>(); public enum StopPartType { @@ -124,7 +124,7 @@ public class GraphPart implements Serializable { return time; } - private boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart prev, GraphPart part, HashSet visited, List loops, boolean useThrow) throws InterruptedException { + private boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart prev, GraphPart part, HashSet visited, List loops, List throwStates, boolean useThrow) throws InterruptedException { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } @@ -134,7 +134,7 @@ public class GraphPart implements Serializable { return false; } if (tpart != this) { - return tpart.leadsTo(localData, gr, code, null, part, visited, loops, useThrow); + return tpart.leadsTo(localData, gr, code, null, part, visited, loops, throwStates, useThrow); } Loop currentLoop = null; for (Loop l : loops) { @@ -171,27 +171,40 @@ public class GraphPart implements Serializable { for (GraphPart p : nextParts) { if (p == part) { return true; - } else if (p.leadsTo(localData, gr, code, this, part, visited, loops, useThrow)) { + } else if (p.leadsTo(localData, gr, code, this, part, visited, loops, throwStates, useThrow)) { return true; } } - if (useThrow) { - for (GraphPart p : throwParts) { - if (p == part) { - return true; - } else if (p.leadsTo(localData, gr, code, this, part, visited, loops, useThrow)) { - return true; + if (useThrow) + for (ThrowState ts : throwStates) { + if (ts.state != 1) { + if (ts.throwingParts.contains(this)) { + GraphPart p = ts.targetPart; + if (p == part) { + return true; + } else if (p.leadsTo(localData, gr, code, this, part, visited, loops, throwStates, useThrow)) { + return true; + } } } } + /*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; } - public boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart part, List loops, boolean useThrow) throws InterruptedException { + public boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart part, List loops, List throwStates, boolean useThrow) throws InterruptedException { for (Loop l : loops) { l.leadsToMark = 0; } - return leadsTo(localData, gr, code, null /*???*/, part, new HashSet<>(), loops, useThrow); + return leadsTo(localData, gr, code, null /*???*/, part, new HashSet<>(), loops, throwStates, useThrow); } public GraphPart(int start, int end) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/ThrowState.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/ThrowState.java new file mode 100644 index 000000000..d3786c385 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/ThrowState.java @@ -0,0 +1,16 @@ +package com.jpexs.decompiler.graph; + +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public class ThrowState { + public int exceptionId; + public int state; + + public Set throwingParts = new HashSet<>(); + public GraphPart targetPart; +} diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java index 73d81e560..70869bd41 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java @@ -122,7 +122,7 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT + "case 0:\r\n" + "var _loc2_:String = \"X\";\r\n" + "return;\r\n" - + "break;\r\n" + //+ "break;\r\n" + "case 1:\r\n" + "_loc2_ = \"A\";\r\n" + "break;\r\n" diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.air.swf b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.air.swf index d747bcebc..429b394ed 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.air.swf and b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.air.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex.swf b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex.swf index 138635265..d4db64948 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex.swf and b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex_apache.swf b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex_apache.swf index b4b5c3b56..193a266e4 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex_apache.swf and b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.flex_apache.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.swftools.swf b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.swftools.swf index 0039b62d7..87853972b 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.swftools.swf and b/libsrc/ffdec_lib/testdata/as3_cross_compile/bin/as3_cross_compile.swftools.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/obj/as3_cross_compileConfig.old b/libsrc/ffdec_lib/testdata/as3_cross_compile/obj/as3_cross_compileConfig.old index 68f0bc5f0..e4c2ad11e 100644 --- a/libsrc/ffdec_lib/testdata/as3_cross_compile/obj/as3_cross_compileConfig.old +++ b/libsrc/ffdec_lib/testdata/as3_cross_compile/obj/as3_cross_compileConfig.old @@ -16,7 +16,7 @@ CONFIG::timeStamp - '05.02.2021' + '06.02.2021' CONFIG::air diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/obj/as3_cross_compileConfig.xml b/libsrc/ffdec_lib/testdata/as3_cross_compile/obj/as3_cross_compileConfig.xml index 68f0bc5f0..e4c2ad11e 100644 --- a/libsrc/ffdec_lib/testdata/as3_cross_compile/obj/as3_cross_compileConfig.xml +++ b/libsrc/ffdec_lib/testdata/as3_cross_compile/obj/as3_cross_compileConfig.xml @@ -16,7 +16,7 @@ CONFIG::timeStamp - '05.02.2021' + '06.02.2021' CONFIG::air diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/src/Main.as b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/Main.as index 1d307bf4a..d979aa5f6 100644 --- a/libsrc/ffdec_lib/testdata/as3_cross_compile/src/Main.as +++ b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/Main.as @@ -12,9 +12,12 @@ package { TestTryCatch; TestTryCatchIfInTry; + TestTryCatchInIf; TestTryCatchInWhile; TestTryCatchInWhile2; + TestTryCatchInWhile3; TestTryCatchLoop; + TestTryCatchLoopBreak; TestTryCatchExceptionUsage TestTryFinally; TestTryFinallyDirectReturnInFinally; diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchInIf.as b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchInIf.as new file mode 100644 index 000000000..17b224968 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchInIf.as @@ -0,0 +1,29 @@ +package tests +{ + /** + * ... + * @author JPEXS + */ + public class TestTryCatchInIf + { + + public function run() : int + { + var a:int = Math.random(); + if (a > 10) + { + try + { + return 1; + } + catch(e:Error) + { + // ignore + } + } + return 2; + } + + } + +} \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchInWhile3.as b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchInWhile3.as new file mode 100644 index 000000000..e2ee5c3bd --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchInWhile3.as @@ -0,0 +1,33 @@ +package tests +{ + import flash.errors.EOFError; + /** + * ... + * @author JPEXS + */ + public class TestTryCatchInWhile3 + { + + public function run() : String + { + var a:int; + a = 0; + trace("before loop"); + while (a > 5) + { + try + { + return "intry return"; + } + catch(e:Error) + { + trace("in catch"); + } + a++; + } + return "OK"; + } + + } + +} \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchLoopBreak.as b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchLoopBreak.as new file mode 100644 index 000000000..51c64b75a --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_cross_compile/src/tests/TestTryCatchLoopBreak.as @@ -0,0 +1,74 @@ +package tests +{ + import flash.errors.EOFError; + /** + * ... + * @author JPEXS + */ + public class TestTryCatchLoopBreak + { + + + public function run() : void + { + var a:int; + a = 0; + trace("before loop");//1-15 + try + { + trace("try1a");//16-22 + while (a < 10){ //34-37 loop0 + trace("a=" + a); //23-33 + a++; + } + trace("try1b"); //38-44 + //45-45 + } + catch(e:Error) + { + trace("in catch"); //46-61 + } + + trace("middle");//62-68 + + + while (a < 20) { //104-107 loop1 + //69-69 + try + { + trace("try2"); //70-77 + return; + } + catch(e:Error) + { + trace("in catch2"); //80-103 + } + trace("a=" + a); //pokračuje 80-103 + } + trace("middle2"); //108-114 + + while (true) { //161-161 loop2 + //115-115 + try + { + trace("try3"); //116-122 + } + catch(e:Error) + { + trace("in catch3"); //124-141 + break; + } + catch(e:EOFError) + { + trace("in catch4"); //141-159 + break; + } + //123-123 + } + trace("exit"); //162-167 + + } + + } + +} \ No newline at end of file