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 15e7ad0d1..e58c8f24f 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 @@ -1101,6 +1101,7 @@ public class AVM2Graph extends Graph { /** * Checks try. * + * @param hasEmptyStackPops Has empty stack pops * @param currentRet Current return * @param foundGotos Found gotos * @param partCodes Part codes @@ -1120,7 +1121,7 @@ public class AVM2Graph extends Graph { * @return True if try is found * @throws InterruptedException On interrupt */ - private boolean checkTry(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, AVM2LocalData localData, GraphPart part, List stopPart, List stopPartKind, List loops, List throwStates, Set allParts, TranslateStack stack, int staticOperation, String path, int recursionLevel) throws InterruptedException { + private boolean checkTry(Reference hasEmptyStackPops, List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, AVM2LocalData localData, GraphPart part, List stopPart, List stopPartKind, List loops, List throwStates, Set allParts, TranslateStack stack, int staticOperation, String path, int recursionLevel) throws InterruptedException { if (localData.parsedExceptions == null) { localData.parsedExceptions = new ArrayList<>(); } @@ -1255,7 +1256,7 @@ public class AVM2Graph extends Graph { } } stack = (TranslateStack) stack.clone(); - tryCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, part, stopPart2, stopPartKind2, loops, throwStates, staticOperation, path); + tryCommands = printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, part, stopPart2, stopPartKind2, loops, throwStates, staticOperation, path); } boolean inlinedFinally = false; @@ -1376,7 +1377,7 @@ public class AVM2Graph extends Graph { tryStopPartKind.add(StopPartKind.OTHER); } - tryCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, part, tryStopPart, tryStopPartKind, loops, throwStates, staticOperation, path); + tryCommands = printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, part, tryStopPart, tryStopPartKind, loops, throwStates, staticOperation, path); makeAllCommands(tryCommands, stack); processIfs(tryCommands); @@ -1394,7 +1395,7 @@ public class AVM2Graph extends Graph { finallyStopPartKind.add(StopPartKind.OTHER); } if (finallyPart != null) { - finallyCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, finallyPart, finallyStopPart, finallyStopPartKind, loops, throwStates, staticOperation, path); + finallyCommands = printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, finallyPart, finallyStopPart, finallyStopPartKind, loops, throwStates, staticOperation, path); } if (switchPart != null) { try { @@ -1446,7 +1447,7 @@ public class AVM2Graph extends Graph { stopPartKind2.add(StopPartKind.OTHER); } - List currentCatchCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData2, st2, allParts, null, catchPart, stopPart2, stopPartKind2, loops, throwStates, staticOperation, path); + List currentCatchCommands = printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData2, st2, allParts, null, catchPart, stopPart2, stopPartKind2, loops, throwStates, staticOperation, path); st2.finishBlock(currentCatchCommands, true); int tempExceptionPos = 0; if (!currentCatchCommands.isEmpty() && currentCatchCommands.get(0) instanceof WithAVM2Item) { @@ -1616,7 +1617,7 @@ public class AVM2Graph extends Graph { if (finallyIndex > -1 && localData.finallyIndicesWithDoublePush.contains(finallyIndex)) { stack.push(new AnyItem()); } - printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, afterPart, stopPart, stopPartKind, loops, throwStates, currentRet, staticOperation, path, recursionLevel); + printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, afterPart, stopPart, stopPartKind, loops, throwStates, currentRet, staticOperation, path, recursionLevel); } return true; } @@ -1691,34 +1692,9 @@ public class AVM2Graph extends Graph { } return true; } - - /** - * Check part output. - * - * @param currentRet Current return - * @param foundGotos Found gotos - * @param partCodes Part codes - * @param partCodePos Part code position - * @param visited Visited - * @param code Code - * @param localData Local data - * @param allParts All parts - * @param stack Stack - * @param parent Parent part - * @param part Part - * @param stopPart Stop part - * @param stopPartKind Stop part kind - * @param loops Loops - * @param throwStates Throw states - * @param currentLoop Current loop - * @param staticOperation Unused - * @param path Path - * @param recursionLevel Recursion level - * @return True to stop processing. False to continue. - * @throws InterruptedException On interrupt - */ + @Override - protected boolean checkPartOutput(List currentRet, List foundGotos, + protected boolean checkPartOutput(Reference hasEmptyStackPops, List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, GraphSource code, BaseLocalData localData, Set allParts, @@ -1729,38 +1705,11 @@ public class AVM2Graph extends Graph { int staticOperation, String path, int recursionLevel) throws InterruptedException { AVM2LocalData aLocalData = (AVM2LocalData) localData; - return checkTry(currentRet, foundGotos, partCodes, partCodePos, visited, aLocalData, part, stopPart, stopPartKind, loops, throwStates, allParts, stack, staticOperation, path, recursionLevel); + return checkTry(hasEmptyStackPops, currentRet, foundGotos, partCodes, partCodePos, visited, aLocalData, part, stopPart, stopPartKind, loops, throwStates, allParts, stack, staticOperation, path, recursionLevel); } - - /** - * Check before decompiling next section. Override this method to provide - * custom behavior. - * - * @param currentRet Current return - * @param foundGotos Found gotos - * @param partCodes Part codes - * @param partCodePos Part code position - * @param visited Visited - * @param code Code - * @param localData Local data - * @param allParts All parts - * @param stack Stack - * @param parent Parent part - * @param part Part - * @param stopPart Stop part - * @param stopPartKind Stop part kind - * @param loops Loops - * @param throwStates Throw states - * @param output Output - * @param currentLoop Current loop - * @param staticOperation Unused - * @param path Path - * @return List of GraphTargetItems to replace current output and stop - * further processing. Null to continue. - * @throws InterruptedException On interrupt - */ + @Override - protected List check(List currentRet, List foundGotos, + protected List check(Reference hasEmptyStackPops, List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, GraphSource code, BaseLocalData localData, Set allParts, @@ -1963,7 +1912,7 @@ public class AVM2Graph extends Graph { Reference nextRef = new Reference<>(null); Reference tiRef = new Reference<>(null); makeAllCommands(output, stack); - SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, stopPartKind, loops, throwStates, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef); + SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, stopPartKind, loops, throwStates, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef, hasEmptyStackPops); ret = new ArrayList<>(); ret.addAll(output); checkSwitch(localData, sw, otherSide, ret.isEmpty() ? currentRet : ret /*hack :-(*/); @@ -1972,7 +1921,7 @@ public class AVM2Graph extends Graph { if (tiRef.getVal() != null) { ret.add(tiRef.getVal()); } else { - ret.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, nextRef.getVal(), stopPart, stopPartKind, loops, throwStates, staticOperation, path)); + ret.addAll(printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, nextRef.getVal(), stopPart, stopPartKind, loops, throwStates, staticOperation, path)); } } } 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 e5ec620b7..5b663c4a8 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 @@ -815,6 +815,7 @@ public class ActionGraph extends Graph { /** * Check before decompiling next section. * + * @param hasEmptyStackPops Has empty stack pops * @param currentRet Current return * @param foundGotos Found gotos * @param partCodes Part codes @@ -839,7 +840,7 @@ public class ActionGraph extends Graph { * @throws InterruptedException On interrupt */ @Override - 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 stopPartKind, List loops, List throwStates, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { + protected List check(Reference hasEmptyStackPops, 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 stopPartKind, 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); @@ -928,7 +929,7 @@ public class ActionGraph extends Graph { Reference nextRef = new Reference<>(null); Reference tiRef = new Reference<>(null); makeAllCommands(output, stack); - SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, stopPartKind, loops, throwStates, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef); + SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, stopPartKind, loops, throwStates, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef, hasEmptyStackPops); fixSwitchEnd(sw); ret = new ArrayList<>(); ret.addAll(output); @@ -937,7 +938,7 @@ public class ActionGraph extends Graph { if (tiRef.getVal() != null) { ret.add(tiRef.getVal()); } else { - ret.addAll(printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, nextRef.getVal(), stopPart, stopPartKind, loops, throwStates, staticOperation, path)); + ret.addAll(printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, null, nextRef.getVal(), stopPart, stopPartKind, loops, throwStates, staticOperation, path)); } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java index e84e05759..cc1af9ef9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java @@ -305,7 +305,7 @@ public class FunctionActionItem extends ActionItem { } writer.append(")").startBlock(); - Graph.graphToString(actions, writer, localData); + Graph.graphToString(actions, writer, localData); writer.endBlock(); writer.endMethod(); 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 4740635dd..6fc74799d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.model.AndItem; import com.jpexs.decompiler.graph.model.BinaryOpItem; +import com.jpexs.decompiler.graph.model.BlockItem; import com.jpexs.decompiler.graph.model.BranchStackResistant; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.CommaExpressionItem; @@ -992,7 +993,8 @@ public class Graph { System.err.println("");//*/ List gotos = new ArrayList<>(); - List ret = printGraph(gotos, new HashMap<>(), new HashMap<>(), new HashSet<>(), localData, stack, allParts, null, heads.get(0), null, null, loops, throwStates, staticOperation, path); + Reference hasEmptyStackPops = new Reference<>(false); + List ret = printGraph(hasEmptyStackPops, gotos, new HashMap<>(), new HashMap<>(), new HashSet<>(), localData, stack, allParts, null, heads.get(0), null, null, loops, throwStates, staticOperation, path); if (localData.secondPassData == null) { SecondPassData secondPassData = prepareSecondPass(localData, ret); @@ -1025,11 +1027,32 @@ public class Graph { propagateBreaks(ret); finalProcessStack(stack, ret, path); makeAllCommands(ret, stack); + + if (!hasEmptyStackPops.getVal()) { + promotePushItemsToCommands(ret); + } + finalProcessAll(null, ret, 0, getFinalData(localData, loops, throwStates), path); //fixSwitchEnds(ret); - handleSetTemporaryDeclarations(ret); + handleSetTemporaryDeclarations(ret); return ret; } + + private void promotePushItemsToCommands(List list) { + for (int i = 0; i < list.size(); i++) { + GraphTargetItem ti = list.get(i); + if (ti instanceof PushItem) { + PushItem pi = (PushItem) ti; + pi.asComment = true; + pi.comment = "unpopped"; + } + if (ti instanceof Block) { + for (List sub : ((Block) ti).getSubs()) { + promotePushItemsToCommands(sub); + } + } + } + } private void handleSetTemporaryDeclarations(List items) { for (int i = 0; i < items.size(); i++) { @@ -2373,6 +2396,7 @@ public class Graph { * Check before decompiling next section. Override this method to provide * custom behavior. * + * @param hasEmptyStackPops Has empty stack pops * @param currentRet Current return * @param foundGotos Found gotos * @param partCodes Part codes @@ -2396,7 +2420,7 @@ public class Graph { * further processing. Null to continue. * @throws InterruptedException On interrupt */ - 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 stopPartKind, List loops, List throwStates, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { + protected List check(Reference hasEmptyStackPops, 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 stopPartKind, List loops, List throwStates, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { return null; } @@ -3118,6 +3142,7 @@ public class Graph { /** * Check before processing with output. * + * @param hasEmptyStackPops Has empty stack pops * @param currentRet Current return * @param foundGotos Found gotos * @param partCodes Part codes @@ -3140,7 +3165,7 @@ public class Graph { * @return True to stop processing. False to continue. * @throws InterruptedException On interrupt */ - 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 stopPartKind, List loops, List throwStates, Loop currentLoop, int staticOperation, String path, int recursionLevel) throws InterruptedException { + protected boolean checkPartOutput(Reference hasEmptyStackPops, 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 stopPartKind, List loops, List throwStates, Loop currentLoop, int staticOperation, String path, int recursionLevel) throws InterruptedException { return false; } @@ -3227,6 +3252,7 @@ public class Graph { /** * Walks graph parts and converts them to target items. * + * @param hasEmptyStackPops Has empty stack pops * @param foundGotos Found gotos * @param partCodes Part codes * @param partCodePos Part code position @@ -3245,13 +3271,14 @@ public class Graph { * @return List of GraphTargetItems * @throws InterruptedException On interrupt */ - protected final List printGraph(List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List stopPartKind, List loops, List throwStates, int staticOperation, String path) throws InterruptedException { - return printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, parent, part, stopPart, stopPartKind, loops, throwStates, null, staticOperation, path, 0); + protected final List printGraph(Reference hasEmptyStackPops, List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List stopPartKind, List loops, List throwStates, int staticOperation, String path) throws InterruptedException { + return printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, parent, part, stopPart, stopPartKind, loops, throwStates, null, staticOperation, path, 0); } /** * Walks graph parts and converts them to target items. * + * @param hasEmptyStackPops Has empty stack pops * @param foundGotos Found gotos * @param partCodes Part codes * @param partCodePos Part code position @@ -3272,7 +3299,7 @@ public class Graph { * @return List of GraphTargetItems * @throws InterruptedException On interrupt */ - protected final List printGraph(List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List stopPartKind, List loops, List throwStates, List ret, int staticOperation, String path, int recursionLevel) throws InterruptedException { + protected final List printGraph(Reference hasEmptyStackPops, List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, TranslateStack stack, Set allParts, GraphPart parent, GraphPart part, List stopPart, List stopPartKind, List loops, List throwStates, List ret, int staticOperation, String path, int recursionLevel) throws InterruptedException { if (ret == null) { ret = new GraphPartMarkedArrayList<>(); @@ -3526,7 +3553,7 @@ public class Graph { for (Loop el : loops) { loopPhases.add(el.phase); } - precontinueCommands = printGraph(foundGotos, partCodes, partCodePos, subVisited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, stopPartKind2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); + precontinueCommands = printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, subVisited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, stopPartKind2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); currentLoop.loopPreContinue = backup; checkContinueAtTheEnd(precontinueCommands, currentLoop); @@ -3583,7 +3610,7 @@ public class Graph { ((GraphPartMarkedArrayList) currentRet).startPart(part); } stack.setConnectedOutput(0, currentRet, localData); - if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, currentLoop, staticOperation, path, recursionLevel)) { + if (checkPartOutput(hasEmptyStackPops, currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, currentLoop, staticOperation, path, recursionLevel)) { parseNext = false; } else { boolean exHappened = false; @@ -3592,7 +3619,10 @@ public class Graph { exHappened = false; try { stack.setConnectedOutput(currentRet.size(), output, localData); - code.translatePart(output, this, part, localData, stack, ipStart, part.end, staticOperation, path); + code.translatePart(output, this, part, localData, stack, ipStart, part.end, staticOperation, path); + if (stack.emptyPopCount > 0) { + hasEmptyStackPops.setVal(true); + } } catch (GraphPartChangeException ex) { //Special case for ifFrameLoaded when it's over multiple parts //output.addAll(ex.getOutput()); for (GraphPart p : allParts) { @@ -3620,7 +3650,7 @@ public class Graph { } if (parseNext) { - List retCheck = check(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, output, currentLoop, staticOperation, path); + List retCheck = check(hasEmptyStackPops, currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, output, currentLoop, staticOperation, path); if (retCheck != null) { if (!retCheck.isEmpty()) { currentRet.addAll(retCheck); @@ -3817,7 +3847,7 @@ public class Graph { Reference tiRef = new Reference<>(null); makeAllCommands(currentRet, stack); SwitchItem sw = handleSwitch(switchedItem, originalSwitchedItem.getSrc(), foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, stopPartKind, loops, throwStates, localData, staticOperation, path, - caseValues, defaultPart, caseBodyParts, nextRef, tiRef); + caseValues, defaultPart, caseBodyParts, nextRef, tiRef, hasEmptyStackPops); sw.additionalDefaultPosition = additionalDefaultPosition; sw.additionalDefaultValues = additionalDefaultValues; GraphPart next = nextRef.getVal(); @@ -3827,7 +3857,7 @@ public class Graph { if (tiRef.getVal() != null) { ret.add(tiRef.getVal()); } else { - printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, stopPartKind, loops, throwStates, currentRet, staticOperation, path, recursionLevel + 1); + printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, stopPartKind, loops, throwStates, currentRet, staticOperation, path, recursionLevel + 1); } } pos++; @@ -3919,7 +3949,7 @@ public class Graph { if (currentLoop != null) { //System.err.println("handling parent loop"); - handleLoop(loopItem, li, currentLoop, loopTypeFound, doWhileCandidate, precontinueCommands, foundGotos, partCodes, partCodePos, visited, localData, allParts, null /*??*/, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel, sPreLoop); + handleLoop(hasEmptyStackPops, loopItem, li, currentLoop, loopTypeFound, doWhileCandidate, precontinueCommands, foundGotos, partCodes, partCodePos, visited, localData, allParts, null /*??*/, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel, sPreLoop); currentLoop.phase = 1; } loopItem = newLoopItem; @@ -3949,7 +3979,7 @@ public class Graph { TranslateStack trueStack = (TranslateStack) stack.clone(); TranslateStack falseStack = (TranslateStack) stack.clone(); - + //hack for as1/2 for..in to get enumeration through GraphTargetItem topBsr = !stack.isEmpty() && (stack.peek() instanceof BranchStackResistant) ? stack.peek() : null; trueStack.clear(); @@ -3984,17 +4014,17 @@ 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, stopPartKind2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); + onTrue = printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, stopPartKind2, 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, stopPartKind2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); + onFalse = printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, stopPartKind2, loops, throwStates, null, staticOperation, path, recursionLevel + 1); } //List out2 = new ArrayList<>(); //makeAllCommands(out2, stack); makeAllCommands(onTrue, trueStack); - makeAllCommands(onFalse, falseStack); + makeAllCommands(onFalse, falseStack); GraphTargetItem addAfterIf = null; if (!onTrue.isEmpty() && !onFalse.isEmpty() && (onTrue.get(onTrue.size() - 1) instanceof ContinueItem) @@ -4133,7 +4163,7 @@ public class Graph { } //currentRet.addAll(out2); if (next != null) { - printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, stopPartKind, loops, throwStates, currentRet, staticOperation, path, recursionLevel + 1); + printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, stopPartKind, loops, throwStates, currentRet, staticOperation, path, recursionLevel + 1); //currentRet.addAll(); } } @@ -4147,19 +4177,19 @@ public class Graph { } if (nextOnePart != null) { - printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, getNextParts(localData, part).get(0), stopPart, stopPartKind, loops, throwStates, currentRet, staticOperation, path, recursionLevel + 1); + printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, part, getNextParts(localData, part).get(0), stopPart, stopPartKind, loops, throwStates, currentRet, staticOperation, path, recursionLevel + 1); } } if (isLoop && loopItem != null && currentLoop != null) { - handleLoop(loopItem, li, currentLoop, loopTypeFound, doWhileCandidate, precontinueCommands, foundGotos, partCodes, partCodePos, visited, localData, allParts, part, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel, sPreLoop); + handleLoop(hasEmptyStackPops, loopItem, li, currentLoop, loopTypeFound, doWhileCandidate, precontinueCommands, foundGotos, partCodes, partCodePos, visited, localData, allParts, part, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel, sPreLoop); } break; } return originalRet; } - private void handleLoop(UniversalLoopItem loopItem, LoopItem li, Loop currentLoop, boolean loopTypeFound, boolean doWhileCandidate, List precontinueCommands, + private void handleLoop(Reference hasEmptyStackPops, UniversalLoopItem loopItem, LoopItem li, Loop currentLoop, boolean loopTypeFound, boolean doWhileCandidate, List precontinueCommands, List foundGotos, Map> partCodes, Map partCodePos, Set visited, BaseLocalData localData, Set allParts, GraphPart part, List stopPart, List stopPartKind, List loops, List throwStates, List ret, int staticOperation, String path, int recursionLevel, TranslateStack sPreLoop ) throws InterruptedException { @@ -4388,7 +4418,7 @@ public class Graph { } if (currentLoop.loopBreak != null) { - printGraph(foundGotos, partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel + 1); + printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, stopPartKind, loops, throwStates, ret, staticOperation, path, recursionLevel + 1); } } @@ -4677,7 +4707,7 @@ public class Graph { int tsize = tree.size(); if (!tree.isEmpty() && (tree.get(tree.size() - 1) instanceof ScriptEndItem)) { tsize--; - } + } for (int i = 0; i < tsize; i++) { GraphTargetItem ti = tree.get(i); if (!ti.isEmpty()) { @@ -4686,6 +4716,9 @@ public class Graph { } ti.toStringSemicoloned(writer, localData); if (!ti.handlesNewLine()) { + if (!ti.comment.isEmpty()) { + writer.append(" //").append(ti.comment); + } writer.newLine(); } lastNewLine = false; @@ -4694,7 +4727,7 @@ public class Graph { lastNewLine = true; } } - } + } return writer; } @@ -4793,12 +4826,13 @@ public class Graph { * @param caseBodyParts Case body parts * @param nextRef Next reference * @param tiRef Target item reference + * @param hasEmptyStackPops Has empty stack pops * @return Switch item * @throws InterruptedException On interrupt */ protected SwitchItem handleSwitch(GraphTargetItem switchedObject, GraphSourceItem switchStartItem, List foundGotos, Map> partCodes, Map partCodePos, Set visited, Set allParts, TranslateStack stack, List stopPart, List stopPartKind, List loops, List throwStates, BaseLocalData localData, int staticOperation, String path, - List caseValuesMap, GraphPart defaultPart, List caseBodyParts, Reference nextRef, Reference tiRef) throws InterruptedException { + List caseValuesMap, GraphPart defaultPart, List caseBodyParts, Reference nextRef, Reference tiRef, Reference hasEmptyStackPops) throws InterruptedException { boolean hasDefault = false; /* @@ -4950,7 +4984,7 @@ public class Graph { stopPartKind2x.add(StopPartKind.OTHER); } TranslateStack subStack = (TranslateStack) stack.clone(); - currentCaseCommands = printGraph(foundGotos, partCodes, partCodePos, visited, localData, subStack, allParts, null, caseBodies.get(i), stopPart2x, stopPartKind2x, loops, throwStates, staticOperation, path); + currentCaseCommands = printGraph(hasEmptyStackPops, foundGotos, partCodes, partCodePos, visited, localData, subStack, allParts, null, caseBodies.get(i), stopPart2x, stopPartKind2x, loops, throwStates, staticOperation, path); if (willHaveBreak) { if (!currentCaseCommands.isEmpty()) { GraphTargetItem last = currentCaseCommands.get(currentCaseCommands.size() - 1); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java index 480a12381..d317cb875 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java @@ -141,6 +141,11 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { * report bugs. */ public int line; + + /** + * Comment + */ + public String comment = ""; /** * Gets the line start item @@ -1060,17 +1065,30 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { writer.startBlock(); } boolean first = true; + GraphTargetItem prevTi = null; for (GraphTargetItem ti : commands) { - if (!ti.isEmpty()) { - //Use stored line information if available to place commands on same line + if (!ti.isEmpty()) { if (!first && (!useLineInfo || (ti.getLine() < 1 || prevLine < 1 || (prevLine >= 1 && prevLine != ti.getLine())))) { + //Use stored line information if available to place commands on same line + + if (prevTi != null && !prevTi.comment.isEmpty()) { + writer.append(" //").append(prevTi.comment); + } writer.newLine(); + } else { + if (prevTi != null && !prevTi.comment.isEmpty()) { + writer.append(" /*").append(prevTi.comment).append(" */ "); + } } prevLine = ti.getLine(); first = false; ti.toStringSemicoloned(writer, localData); + prevTi = ti; } } + if (prevTi != null && !prevTi.comment.isEmpty()) { + writer.append(" //").append(prevTi.comment); + } if (asBlock) { if (!first) { writer.newLine(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/TranslateStack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/TranslateStack.java index 7d855a41b..07fc2cf9a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/TranslateStack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/TranslateStack.java @@ -64,7 +64,9 @@ public class TranslateStack extends Stack { public List outputQueue = new ArrayList<>(); public BaseLocalData localData = null; - + + public int emptyPopCount = 0; + @Override public synchronized Object clone() { TranslateStack st = (TranslateStack) super.clone(); @@ -300,6 +302,7 @@ public class TranslateStack extends Stack { PopItem oldpop = getPop(); pop = null; Logger.getLogger(TranslateStack.class.getName()).log(Level.FINE, "{0}: Attempt to Pop empty stack", path); + emptyPopCount++; return oldpop; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/PushItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/PushItem.java index 8c3e4938b..e3cee7fed 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/PushItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/PushItem.java @@ -33,6 +33,8 @@ import java.util.Objects; */ public class PushItem extends GraphTargetItem { + public boolean asComment = false; + /** * Constructor. * @param value Value to push @@ -43,13 +45,16 @@ public class PushItem extends GraphTargetItem { @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { - //Logger.getLogger(PushItem.class.getName()).log(Level.WARNING, "Push item left in the source code"); + if (asComment) { + value.appendTry(writer, localData); + return writer; + } writer.append("§§push("); value.appendTry(writer, localData); writer.append(")"); return writer; - } - + } + @Override public boolean hasReturnValue() { return false; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ClassesTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ClassesTest.java index e9dd21a05..8c7ebb667 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ClassesTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ClassesTest.java @@ -241,10 +241,11 @@ public class ActionScript2ClassesTest extends ActionScript2TestBase { + " var c = true;\n" + " function TestUnpopped()\n" + " {\n" + + " \n" + " }\n" + " function run()\n" + " {\n" - + " §§push(this.a);\n" + + " this.a; //unpopped\n" + " trace(\"b\");\n" + " if(this.c)\n" + " {\n"