diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index d2711db6d..6ee1e2497 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1576,47 +1576,6 @@ public class AVM2Code implements Cloneable { } } } - /*if ((ip + 8 < code.size())) { //return in finally clause - if (ins.definition instanceof SetLocalTypeIns) { - if (code.get(ip + 1).definition instanceof PushByteIns) { - AVM2Instruction jmp = code.get(ip + 2); - if (jmp.definition instanceof JumpIns) { - if (jmp.operands[0] == 0) { - if (code.get(ip + 3).definition instanceof LabelIns) { - if (code.get(ip + 4).definition instanceof PopIns) { - if (code.get(ip + 5).definition instanceof LabelIns) { - AVM2Instruction gl = code.get(ip + 6); - if (gl.definition instanceof GetLocalTypeIns) { - if (((GetLocalTypeIns) gl.definition).getRegisterId(gl) == ((SetLocalTypeIns) ins.definition).getRegisterId(ins)) { - AVM2Instruction ki = code.get(ip + 7); - if (ki.definition instanceof KillIns) { - if (ki.operands[0] == ((SetLocalTypeIns) ins.definition).getRegisterId(ins)) { - if (code.get(ip + 8).definition instanceof ReturnValueIns) { - ip = ip + 8; - continue; - } - } - } - } - } - } - } - } - } - } - } - } - }//*/ - - /*if ((ip + 2 < code.size()) && (ins.definition instanceof NewCatchIns)) { // Filling local register in catch clause - if (code.get(ip + 1).definition instanceof DupIns) { - if (code.get(ip + 2).definition instanceof SetLocalTypeIns) { - ins.definition.translate(isStatic, classIndex, localRegs, stack, scopeStack, constants, ins, method_info, output, body, abc, localRegNames, fullyQualifiedNames); - ip += 3; - continue; - } - } - }*/ if ((ins.definition instanceof SetLocalTypeIns) && (ip + 1 <= end)) { // set_local_x,get_local_x.. no other local_x get AVM2Instruction insAfter = code.get(ip + 1); 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 685b9e2db..40f225fad 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 @@ -440,135 +440,126 @@ public class AVM2Graph extends Graph { } } + private void walkLocalRegsUsage(AVM2LocalData localData, Set getLocalPos, GraphPart startPart, GraphPart part, Set visited, int ip, int searchRegId) { + if (visited.contains(part) && part != startPart) { + return; + } + + if (localData.finallyThrowParts.containsValue(part)) { + visited.add(part); + return; + } + + for (int i = ip; i <= part.end; i++) { + AVM2Instruction ins = avm2code.code.get(i); + if (ins.definition instanceof SetLocalTypeIns) { + int regId = ((SetLocalTypeIns) ins.definition).getRegisterId(ins); + if (searchRegId == regId) { + return; + } + } + if (ins.definition instanceof GetLocalTypeIns) { + int regId = ((GetLocalTypeIns) ins.definition).getRegisterId(ins); + if (regId == searchRegId) { + getLocalPos.add(i); + } + } + if ((ins.definition instanceof IncLocalIns) + || (ins.definition instanceof IncLocalIIns) + || (ins.definition instanceof IncLocalPIns) + || (ins.definition instanceof DecLocalIns) + || (ins.definition instanceof DecLocalIIns) + || (ins.definition instanceof DecLocalPIns)) { + int regId = ins.operands[0]; + if (regId == searchRegId) { + getLocalPos.add(i); + } + } + if ((ins.definition instanceof IncLocalPIns) + || (ins.definition instanceof DecLocalPIns)) { + int regId = ins.operands[1]; + if (regId == searchRegId) { + getLocalPos.add(i); + } + } + if (ins.definition instanceof HasNext2Ins) { + int regId1 = ins.operands[0]; + if (regId1 == searchRegId) { + getLocalPos.add(i); + } + int regId2 = ins.operands[1]; + if (regId2 == searchRegId) { + getLocalPos.add(i); + } + } + } + + if (visited.contains(part)) { + return; + } + visited.add(part); + + try { + //stop on switch + if (localData.ignoredSwitches.values().contains(part)) { + return; + } + if (localData.finallyJumps.containsKey(part)) { + GraphPart targetPart = localData.finallyJumps.get(part); + if (localData.defaultParts.containsValue(targetPart)) { + //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); + return; + } else { + return; + } + } + for (GraphPart p : part.nextParts) { + walkLocalRegsUsage(localData, getLocalPos, startPart, p, visited, p.start, searchRegId); + } + } finally { + for (GraphPart p : part.throwParts) { + walkLocalRegsUsage(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) { logger.log(Level.FINE, "--- {0} ---", path); Map> setLocalPosToGetLocalPos = new TreeMap<>(); - Map>> partUnresolvedRegisterToGetLocalPos = new HashMap<>(); - Map> partRegisterToLastSetLocalPos = new HashMap<>(); - Map reverseFinallyJumps = new HashMap<>(); for (GraphPart p : localData.finallyJumps.keySet()) { reverseFinallyJumps.put(localData.finallyJumps.get(p), p); } - for (GraphPart p : allParts) { - if (p.start < 0) { - continue; - } - Map registerToLastSetLocalPos = new HashMap<>(); - for (int ip = p.start; ip <= p.end; ip++) { - AVM2Instruction ins = avm2code.code.get(ip); - if (ins.definition instanceof SetLocalTypeIns) { - int regId = ((SetLocalTypeIns) ins.definition).getRegisterId(ins); - registerToLastSetLocalPos.put(regId, ip); - setLocalPosToGetLocalPos.put(ip, new TreeSet<>()); - } - List usedRegs = new ArrayList<>(); - if (ins.definition instanceof GetLocalTypeIns) { - int regId = ((GetLocalTypeIns) ins.definition).getRegisterId(ins); - usedRegs.add(regId); - } - if ((ins.definition instanceof IncLocalIns) - || (ins.definition instanceof IncLocalIIns) - || (ins.definition instanceof IncLocalPIns) - || (ins.definition instanceof DecLocalIns) - || (ins.definition instanceof DecLocalIIns) - || (ins.definition instanceof DecLocalPIns)) { - usedRegs.add(ins.operands[0]); - } - if ((ins.definition instanceof IncLocalPIns) - || (ins.definition instanceof DecLocalPIns)) { - usedRegs.add(ins.operands[1]); - } - if (ins.definition instanceof HasNext2Ins) { - usedRegs.add(ins.operands[0]); - usedRegs.add(ins.operands[1]); - } - for (int regId : usedRegs) { - if (registerToLastSetLocalPos.containsKey(regId)) { - int setLocalPos = registerToLastSetLocalPos.get(regId); - setLocalPosToGetLocalPos.get(setLocalPos).add(ip); - } else { - if (!partUnresolvedRegisterToGetLocalPos.containsKey(p)) { - partUnresolvedRegisterToGetLocalPos.put(p, new HashMap<>()); - } - if (!partUnresolvedRegisterToGetLocalPos.get(p).containsKey(regId)) { - partUnresolvedRegisterToGetLocalPos.get(p).put(regId, new ArrayList<>()); - } - partUnresolvedRegisterToGetLocalPos.get(p).get(regId).add(ip); - } - } - } - partRegisterToLastSetLocalPos.put(p, registerToLastSetLocalPos); - } + Map setLocalPosToRegisterId = new HashMap<>(); - Set pSet = new HashSet<>(partUnresolvedRegisterToGetLocalPos.keySet()); - for (GraphPart p : pSet) { - Map> unresolvedRegisterToGetLocalPos = partUnresolvedRegisterToGetLocalPos.get(p); - Set visited = new HashSet<>(); - visited.add(p); - if (reverseFinallyJumps.containsKey(p)) { - GraphPart q = reverseFinallyJumps.get(p); - calculateLocalRegsUsageWalk(reverseFinallyJumps, ignoredSwitches, q, unresolvedRegisterToGetLocalPos, visited, partRegisterToLastSetLocalPos, setLocalPosToGetLocalPos, p); - } else { - for (GraphPart q : p.refs) { - calculateLocalRegsUsageWalk(reverseFinallyJumps, ignoredSwitches, q, unresolvedRegisterToGetLocalPos, visited, partRegisterToLastSetLocalPos, setLocalPosToGetLocalPos, p); - } + for (int ip = 0; ip < avm2code.code.size(); ip++) { + AVM2Instruction ins = avm2code.code.get(ip); + if (ins.definition instanceof SetLocalTypeIns) { + int regId = ((SetLocalTypeIns) ins.definition).getRegisterId(ins); + setLocalPosToGetLocalPos.put(ip, new TreeSet<>()); + setLocalPosToRegisterId.put(ip, regId); } } - for (int setLocalPos : setLocalPosToGetLocalPos.keySet()) { - AVM2Instruction ins = avm2code.code.get(setLocalPos); - int regId = ((SetLocalTypeIns) ins.definition).getRegisterId(ins); - logger.log(Level.FINE, "set local reg {0} at pos {1}{2}", new Object[]{regId, setLocalPos, 1}); - - for (int getLocalPos : setLocalPosToGetLocalPos.get(setLocalPos)) { - logger.log(Level.FINE, "- usage at pos {0}{1}", new Object[]{getLocalPos, 1}); - } + for (int ip : setLocalPosToGetLocalPos.keySet()) { + GraphPart part = searchPart(ip + 1, allParts); + walkLocalRegsUsage(localData, setLocalPosToGetLocalPos.get(ip), part, part, new HashSet<>(), ip + 1, setLocalPosToRegisterId.get(ip)); } + + /*for (int ip : setLocalPosToGetLocalPos.keySet()) { + System.err.println("definition at ip " + (ip + 1) + ", regid=" + setLocalPosToRegisterId.get(ip)); + for (int usageIp : setLocalPosToGetLocalPos.get(ip)) { + System.err.println("- used at " + (usageIp + 1)); + } + }*/ return setLocalPosToGetLocalPos; } - public void calculateLocalRegsUsageWalk(Map reverseFinallyJumps, Set ignoredSwitches, GraphPart q, - Map> unresolvedRegisterToGetLocalPos, - Set visited, - Map> partRegisterToLastSetLocalPos, - Map> setLocalPosToGetLocalPos, GraphPart next) { - if (visited.contains(q)) { - return; - } - if (ignoredSwitches.contains(q.end)) { - if (q.nextParts.isEmpty() || !next.equals(q.nextParts.get(0))) { //first is after finally - return; - } - } - Set regIds = new HashSet<>(unresolvedRegisterToGetLocalPos.keySet()); - for (int regId : regIds) { - if (partRegisterToLastSetLocalPos.containsKey(q)) { - if (partRegisterToLastSetLocalPos.get(q).containsKey(regId)) { - int lastSetLocalPos = partRegisterToLastSetLocalPos.get(q).get(regId); - setLocalPosToGetLocalPos.get(lastSetLocalPos).addAll(unresolvedRegisterToGetLocalPos.get(regId)); - unresolvedRegisterToGetLocalPos = new HashMap<>(unresolvedRegisterToGetLocalPos); - unresolvedRegisterToGetLocalPos.remove(regId); - } - } - } - if (unresolvedRegisterToGetLocalPos.isEmpty()) { - return; - } - - visited.add(q); - - if (reverseFinallyJumps.containsKey(q)) { - GraphPart r = reverseFinallyJumps.get(q); - calculateLocalRegsUsageWalk(reverseFinallyJumps, ignoredSwitches, r, unresolvedRegisterToGetLocalPos, visited, partRegisterToLastSetLocalPos, setLocalPosToGetLocalPos, q); - } else { - for (GraphPart r : q.refs) { - calculateLocalRegsUsageWalk(reverseFinallyJumps, ignoredSwitches, r, unresolvedRegisterToGetLocalPos, visited, partRegisterToLastSetLocalPos, setLocalPosToGetLocalPos, q); - } - } - } - public static List translateViaGraph(String path, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, ScopeStack scopeStack, HashMap localRegNames, List fullyQualifiedNames, int staticOperation, HashMap localRegAssigmentIps, HashMap> refs, boolean thisHasDefaultToPrimitive) throws InterruptedException { AVM2Graph g = new AVM2Graph(code, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, fullyQualifiedNames, localRegAssigmentIps, refs); @@ -820,7 +811,6 @@ public class AVM2Graph extends Graph { stack.clear(); //If the original code (before check()) had "if" in it, there would be something on stack - if (finallyException == null) { List stopPart2 = new ArrayList<>(stopPart); stopPart2.add(afterPart); @@ -1110,12 +1100,12 @@ public class AVM2Graph extends Graph { defaultPart = defaultPart.nextParts.get(0); } - ret = new ArrayList<>(); - ret.addAll(output); 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); - checkSwitch(localData, sw, otherSide, ret); + ret = new ArrayList<>(); + ret.addAll(output); + checkSwitch(localData, sw, otherSide, ret.isEmpty() ? currentRet : ret /*hack :-(*/); ret.add(sw); if (nextRef.getVal() != null) { if (tiRef.getVal() != null) { diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ClassicDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ClassicDecompileTest.java index 49784d84a..5a9573027 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ClassicDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3ClassicDecompileTest.java @@ -36,7 +36,8 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes + "finally\r\n" + "{\r\n" + "trace(\"infinally\");\r\n" - + "}\r\n", + + "}\r\n" + + "trace(\"after\");\r\n", false); } diff --git a/libsrc/ffdec_lib/testdata/flashdevelop/bin/Main.air.swf b/libsrc/ffdec_lib/testdata/flashdevelop/bin/Main.air.swf index cac503186..f0a441616 100644 Binary files a/libsrc/ffdec_lib/testdata/flashdevelop/bin/Main.air.swf and b/libsrc/ffdec_lib/testdata/flashdevelop/bin/Main.air.swf differ diff --git a/libsrc/ffdec_lib/testdata/flashdevelop/bin/Main.flex.swf b/libsrc/ffdec_lib/testdata/flashdevelop/bin/Main.flex.swf index a47d2c87c..c4bdc2e41 100644 Binary files a/libsrc/ffdec_lib/testdata/flashdevelop/bin/Main.flex.swf and b/libsrc/ffdec_lib/testdata/flashdevelop/bin/Main.flex.swf differ diff --git a/libsrc/ffdec_lib/testdata/flashdevelop/src/tests/TestCatchFinally.as b/libsrc/ffdec_lib/testdata/flashdevelop/src/tests/TestCatchFinally.as index 33ea55064..15b8d24ab 100644 --- a/libsrc/ffdec_lib/testdata/flashdevelop/src/tests/TestCatchFinally.as +++ b/libsrc/ffdec_lib/testdata/flashdevelop/src/tests/TestCatchFinally.as @@ -19,6 +19,7 @@ package tests { trace("infinally"); } + trace("after"); } } }