From dc18fad2b3d64f9f2cce981701ca383f8283b885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 17 Jan 2021 21:52:33 +0100 Subject: [PATCH] Improved for continue / goto detection --- .../flash/abc/avm2/graph/AVM2Graph.java | 31 +- .../decompiler/flash/action/ActionGraph.java | 18 +- .../src/com/jpexs/decompiler/graph/Graph.java | 318 +++++++++++------- .../com/jpexs/decompiler/graph/GraphPart.java | 9 +- .../jpexs/decompiler/graph/GraphPartEdge.java | 68 ++++ .../decompiler/graph/GraphTargetItem.java | 20 +- .../src/com/jpexs/decompiler/graph/Loop.java | 2 + .../decompiler/graph/model/GotoItem.java | 60 +++- 8 files changed, 376 insertions(+), 150 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartEdge.java 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 a6fd8492f..eba081d0a 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 @@ -55,6 +55,7 @@ import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphPart; +import com.jpexs.decompiler.graph.GraphPartEdge; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; @@ -65,6 +66,7 @@ import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.ContinueItem; import com.jpexs.decompiler.graph.model.DefaultItem; import com.jpexs.decompiler.graph.model.ExitItem; +import com.jpexs.decompiler.graph.model.GotoItem; import com.jpexs.decompiler.graph.model.IfItem; import com.jpexs.decompiler.graph.model.LoopItem; import com.jpexs.decompiler.graph.model.NotItem; @@ -79,6 +81,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.logging.Logger; /** * @@ -152,6 +155,7 @@ public class AVM2Graph extends Graph { } for (GraphPart p : allBlocks) { if (avm2code.pos2adr(p.start) >= ex.start && avm2code.pos2adr(p.end) <= ex.end && target != null) { + //Logger.getLogger(Graph.class.getName()).fine("ADDING throwpart " + target + " to " + p); p.throwParts.add(target); target.refs.add(p); } @@ -160,7 +164,7 @@ public class AVM2Graph extends Graph { } @Override - protected List check(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 foundGotos, List gotoTargets, 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 { List ret = null; AVM2LocalData aLocalData = (AVM2LocalData) localData; @@ -282,7 +286,7 @@ public class AVM2Graph extends Graph { finallyJumps.clear(); ignoredSwitches.put(e, swPos); st.push(new PopItem(null, aLocalData.lineStartInstruction)); - finallyCommands = printGraph(partCodes, partCodePos, localData, st, allParts, parent, fpart, null, loops, staticOperation, path); + finallyCommands = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, st, allParts, parent, fpart, null, loops, staticOperation, path); //ignoredSwitches.remove(igs_size-1); finallyJumps.putAll(oldFinallyJumps); if (!finallyJumps.containsKey(e)) { @@ -341,7 +345,7 @@ public class AVM2Graph extends Graph { stopPart2.add(retPart); } - List ncatchedCommands = printGraph(partCodes, partCodePos, localData2, st2, allParts, parent, npart, stopPart2, loops, staticOperation, path); + List ncatchedCommands = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData2, st2, allParts, parent, npart, stopPart2, loops, staticOperation, path); if (catchedExceptions.get(e).isFinally() && (catchedExceptions.size() > 1 || hasFinally)) { catchedExceptions.remove(e); e--; @@ -381,7 +385,7 @@ public class AVM2Graph extends Graph { } TranslateStack st = (TranslateStack) stack.clone(); st.clear(); - List tryCommands = printGraph(partCodes, partCodePos, localData, st, allParts, parent, part, stopPart2, loops, staticOperation, path); + List tryCommands = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, st, allParts, parent, part, stopPart2, loops, staticOperation, path); if (retPart != null && avm2code.code.get(retPart.start).isExit() && !(!tryCommands.isEmpty() && (tryCommands.get(tryCommands.size() - 1) instanceof ExitItem))) { avm2code.code.get(retPart.start).translate(localData, st, tryCommands, staticOperation, path); } @@ -417,7 +421,7 @@ public class AVM2Graph extends Graph { TranslateStack st = (TranslateStack) stack.clone(); st.clear(); - ret.addAll(printGraph(partCodes, partCodePos, localData, st, allParts, null, part, stopPart, loops, staticOperation, path)); + ret.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, st, allParts, null, part, stopPart, loops, staticOperation, path)); } else { ret.add(lop); } @@ -466,7 +470,8 @@ public class AVM2Graph extends Graph { StrictEqAVM2Item set = (StrictEqAVM2Item) stack.pop(); caseValuesMapLeft.add(set.leftSide); caseValuesMapRight.add(set.rightSide); - + + GraphPart origPart = part; List caseBodyParts = new ArrayList<>(); caseBodyParts.add(part.nextParts.get(0)); GraphTargetItem top = null; @@ -576,7 +581,7 @@ public class AVM2Graph extends 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)) { + if (caseBodyParts.get(i).leadsTo(localData, this, code, defaultPart, loops, new ArrayList<>())) { DefaultItem di = new DefaultItem(); caseValuesMap.add(i + 1, di); caseBodyParts.add(i + 1, defaultPart); @@ -597,7 +602,7 @@ public class AVM2Graph extends Graph { trace("2"); */ for (int i = 0; i < caseBodyParts.size(); i++) { - if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops)) { + if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops, new ArrayList<>())) { DefaultItem di = new DefaultItem(); caseValuesMap.add(i, di); caseBodyParts.add(i, defaultPart); @@ -620,7 +625,9 @@ public class AVM2Graph extends Graph { caseBodyParts.add(defaultPart); } - GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops); + GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops, new ArrayList<>()); + removeEdgeToFromList(gotoTargets, breakPart); + List> caseCommands = new ArrayList<>(); GraphPart next = breakPart; @@ -645,7 +652,7 @@ public class AVM2Graph extends Graph { GraphPart nextCase = next; if (next != null) { if (i < caseBodies.size() - 1) { - if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops)) { + if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops, new ArrayList<>())) { currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id)); } else { nextCase = caseBodies.get(i + 1); @@ -661,7 +668,7 @@ public class AVM2Graph extends Graph { if (breakPart != null) { stopPart2x.add(breakPart); } - currentCaseCommands.addAll(0, printGraph(partCodes, partCodePos, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, staticOperation, path)); + currentCaseCommands.addAll(0, printGraph(foundGotos, gotoTargets, 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)) { @@ -714,7 +721,7 @@ public class AVM2Graph extends Graph { if (ti != null) { ret.add(ti); } else { - ret.addAll(printGraph(partCodes, partCodePos, localData, stack, allParts, null, next, stopPart, loops, staticOperation, path)); + ret.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, stack, allParts, null, next, stopPart, loops, 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 e99285d33..e4a975e75 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 @@ -45,6 +45,7 @@ import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphPart; +import com.jpexs.decompiler.graph.GraphPartEdge; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphSourceItemContainer; @@ -54,6 +55,7 @@ import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.ContinueItem; import com.jpexs.decompiler.graph.model.DefaultItem; +import com.jpexs.decompiler.graph.model.GotoItem; import com.jpexs.decompiler.graph.model.IfItem; import com.jpexs.decompiler.graph.model.SwitchItem; import com.jpexs.decompiler.graph.model.UniversalLoopItem; @@ -331,7 +333,7 @@ public class ActionGraph extends Graph { } @Override - protected List check(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 foundGotos, List gotoTargets, 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 { if (!output.isEmpty()) { if (output.get(output.size() - 1) instanceof StoreRegisterActionItem) { StoreRegisterActionItem str = (StoreRegisterActionItem) output.get(output.size() - 1); @@ -420,7 +422,7 @@ public class ActionGraph extends 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)) { + if (caseBodyParts.get(i).leadsTo(localData, this, code, defaultPart, loops, new ArrayList<>())) { DefaultItem di = new DefaultItem(); caseValuesMap.add(i + 1, di); caseBodyParts.add(i + 1, defaultPart); @@ -441,7 +443,7 @@ public class ActionGraph extends Graph { trace("2"); */ for (int i = 0; i < caseBodyParts.size(); i++) { - if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops)) { + if (defaultPart.leadsTo(localData, this, code, caseBodyParts.get(i), loops, new ArrayList<>())) { DefaultItem di = new DefaultItem(); caseValuesMap.add(i, di); caseBodyParts.add(i, defaultPart); @@ -464,7 +466,8 @@ public class ActionGraph extends Graph { caseBodyParts.add(defaultPart); } - GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops); + GraphPart breakPart = getMostCommonPart(localData, caseBodyParts, loops, new ArrayList<>()); + removeEdgeToFromList(gotoTargets, breakPart); List> caseCommands = new ArrayList<>(); GraphPart next = breakPart; @@ -479,6 +482,7 @@ public class ActionGraph extends Graph { 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)); @@ -489,7 +493,7 @@ public class ActionGraph extends Graph { GraphPart nextCase = next; if (next != null) { if (i < caseBodies.size() - 1) { - if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops)) { + if (!caseBodies.get(i).leadsTo(localData, this, code, caseBodies.get(i + 1), loops, new ArrayList<>())) { currentCaseCommands.add(new BreakItem(null, localData.lineStartInstruction, currentLoop.id)); } else { nextCase = caseBodies.get(i + 1); @@ -505,7 +509,7 @@ public class ActionGraph extends Graph { if (breakPart != null) { stopPart2x.add(breakPart); } - currentCaseCommands.addAll(0, printGraph(partCodes, partCodePos, localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops, staticOperation, path)); + currentCaseCommands.addAll(0, printGraph(foundGotos, gotoTargets, 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)) { @@ -558,7 +562,7 @@ public class ActionGraph extends Graph { if (ti != null) { ret.add(ti); } else { - ret.addAll(printGraph(partCodes, partCodePos, localData, stack, allParts, null, next, stopPart, loops, staticOperation, path)); + ret.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, localData, stack, allParts, null, next, stopPart, loops, 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 5202090bb..8989f05df 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -315,13 +315,12 @@ public class Graph { } } - private void getReachableParts(GraphPart part, LinkedHashSet ret, List loops) { + private void getReachableParts(GraphPart part, LinkedHashSet ret, List loops, List gotoParts) { // use LinkedHashSet to preserve order - getReachableParts(part, ret, loops, true); + getReachableParts(part, ret, loops, true, gotoParts); } - private void getReachableParts(GraphPart part, LinkedHashSet ret, List loops, boolean first) { - + private void getReachableParts(GraphPart part, LinkedHashSet ret, List loops, boolean first, List gotoParts) { // todo: honfika: why call with first = true parameter always? Stack stack = new Stack<>(); GraphPartQueue queue = new GraphPartQueue(); @@ -376,6 +375,9 @@ public class Graph { GraphPartQueue newParts = new GraphPartQueue(); loopnext: for (GraphPart next : part.nextParts) { + if (gotoParts.contains(new GraphPartEdge(part, next))) { + continue; + } for (Loop l : loops) { if ((l.phase == 1) || (l.reachableMark == 1)) { if (l.loopContinue == next) { @@ -406,12 +408,12 @@ public class Graph { } } - public GraphPart getNextCommonPart(BaseLocalData localData, GraphPart part, List loops) throws InterruptedException { - return getCommonPart(localData, part.nextParts, loops); + public GraphPart getNextCommonPart(BaseLocalData localData, GraphPart part, List loops, List gotoParts) throws InterruptedException { + return getCommonPart(localData, part.nextParts, loops, gotoParts); } //TODO: Make this faster! - public GraphPart getCommonPart(BaseLocalData localData, List parts, List loops) throws InterruptedException { + public GraphPart getCommonPart(BaseLocalData localData, List parts, List loops, List gotoParts) throws InterruptedException { if (parts.isEmpty()) { return null; } @@ -427,12 +429,15 @@ public class Graph { if (loopContinues.contains(p)) { break; } + if (gotoParts.contains(p)) { + break; + } boolean common = true; for (GraphPart q : parts) { if (q == p) { continue; } - if (!q.leadsTo(localData, this, code, p, loops)) { + if (!q.leadsTo(localData, this, code, p, loops, gotoParts)) { common = false; break; } @@ -444,7 +449,7 @@ public class Graph { List> reachable = new ArrayList<>(); for (GraphPart p : parts) { LinkedHashSet r1 = new LinkedHashSet<>(); - getReachableParts(p, r1, loops); + getReachableParts(p, r1, loops, gotoParts); r1.add(p); reachable.add(r1); } @@ -471,7 +476,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 gotoParts) throws InterruptedException { if (parts.isEmpty()) { return null; } @@ -496,7 +501,7 @@ public class Graph { if (q == p) { continue; } - if (!q.leadsTo(localData, this, code, p, loops)) { + if (!q.leadsTo(localData, this, code, p, loops, gotoParts)) { common = false; break; } @@ -512,7 +517,7 @@ public class Graph { if (j == i) { continue; } - if (parts.get(i).leadsTo(localData, this, code, parts.get(j), loops)) { + if (parts.get(i).leadsTo(localData, this, code, parts.get(j), loops, gotoParts)) { parts.remove(i); i--; continue loopi; @@ -522,7 +527,7 @@ public class Graph { List> reachable = new ArrayList<>(); for (GraphPart p : parts) { LinkedHashSet r1 = new LinkedHashSet<>(); - getReachableParts(p, r1, loops); + getReachableParts(p, r1, loops, gotoParts); Set r2 = new LinkedHashSet<>(); r2.add(p); r2.addAll(r1); @@ -685,70 +690,46 @@ public class Graph { } //TODO: Make getPrecontinues faster - getBackEdges(localData, loops); + getBackEdges(localData, loops, new ArrayList<>()); //getPrecontinues(path, localData, null, heads.get(0), allParts, loops, null); //getPrecontinues2(path, localData, null, heads.get(0), allParts, loops, null); - getPrecontinues3(path, localData, null, heads.get(0), allParts, loops); - + List gotoTargets = new ArrayList<>(); + findGotoTargets(path, heads.get(0), loops, gotoTargets); + /*for (Loop l : loops) { + if (l.loopBreak != null) { + if (gotoTargets.contains(l.loopBreak)) { + gotoTargets.remove(l.loopBreak); + } + } + }*/ + //System.err.println("gotoTargets.SIZE=" + gotoTargets.size()); /*System.err.println(""); for (Loop el : loops) { System.err.println(el); } System.err.println("");//*/ - List ret = printGraph(new HashMap<>(), new HashMap<>(), localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path); + List gotos = new ArrayList<>(); + List ret = printGraph(gotos, gotoTargets, new HashMap<>(), new HashMap<>(), localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path); + Map usages = new HashMap<>(); + Map lastUsage = new HashMap<>(); + for (GotoItem gi : gotos) { + if (!usages.containsKey(gi.labelName)) { + usages.put(gi.labelName, 0); + } + usages.put(gi.labelName, usages.get(gi.labelName) + 1); + lastUsage.put(gi.labelName, gi); + } + for (String labelName : usages.keySet()) { + if (usages.get(labelName) == 1) { + lastUsage.get(labelName).labelName = null; + } + } processIfs(ret); finalProcessStack(stack, ret, path); finalProcessAll(ret, 0, new FinalProcessLocalData(loops), path); return ret; } - private static class Edge { - - public GraphPart from; - public GraphPart to; - - public Edge(GraphPart from, GraphPart to) { - this.from = from; - this.to = to; - } - - @Override - public String toString() { - return from.toString() + " -> " + to.toString(); - } - - - @Override - public int hashCode() { - int hash = 7; - hash = 37 * hash + Objects.hashCode(this.from); - hash = 37 * hash + Objects.hashCode(this.to); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Edge other = (Edge) obj; - if (!Objects.equals(this.from, other.from)) { - return false; - } - if (!Objects.equals(this.to, other.to)) { - return false; - } - return true; - } - - } - private List getCommonPrefix(List> listOfLists) { List result = new ArrayList<>(); if (listOfLists.isEmpty()) { @@ -835,29 +816,29 @@ public class Graph { } } - private void getPrecontinues3(String path, BaseLocalData localData, GraphPart parent, GraphPart startPart, Set allParts, List loops) { + private void findGotoTargets(String path, GraphPart startPart, List loops, List gotoTargets) { if (!path.equals("classes.tests/ForTest1.test")) { //return; } - logger.info("GETTING precontinues of " + path + " ================="); + //logger.info("GETTING precontinues of " + path + " ================="); Set opened = new HashSet<>(); Set closed = new HashSet<>(); Set closedBranches = new HashSet<>(); - Set exitEdges = new HashSet<>(); - Set backEdges = new HashSet<>(); + Set exitEdges = new HashSet<>(); + Set backEdges = new HashSet<>(); for (Loop el : loops) { for (GraphPart g : el.backEdges) { - backEdges.add(new Edge(g, el.loopContinue)); + backEdges.add(new GraphPartEdge(g, el.loopContinue)); } } - Map> edgeToBranches = new HashMap<>(); + Map> edgeToBranches = new HashMap<>(); opened.add(startPart); GraphPart start = startPart; - Stack walkStack = new Stack<>(); - walkStack.push(new Edge(startPart, startPart)); + Stack walkStack = new Stack<>(); + walkStack.push(new GraphPartEdge(startPart, startPart)); loopwalk: while (!walkStack.isEmpty()) { - Edge e = walkStack.pop(); + GraphPartEdge e = walkStack.pop(); GraphPart p = e.to; if (closed.contains(p)) { logger.fine("part " + p + " is already closed, skipping"); @@ -872,13 +853,17 @@ public class Graph { List refs = getUnicatePartList(p.refs); List> comparedPaths = new ArrayList<>(); - List comparedPathsEdges = new ArrayList<>(); + List comparedPathsEdges = new ArrayList<>(); for (GraphPart r : refs) { - Edge re = new Edge(r, p); + GraphPartEdge re = new GraphPartEdge(r, p); if (backEdges.contains(re)) { logger.fine("ref edge " + re + " is backedge, ignored"); continue; } + if (r.start == -1) { + logger.fine("ref edge " + re + " is alternatestart, ignored"); + continue; + } if (!edgeToBranches.containsKey(re)) { //edge not yet processed logger.fine("ref edge " + re + " NOT yet processed"); @@ -905,13 +890,34 @@ public class Graph { i--; continue loopi; } - //remove last path component - int last = i > j ? i : j; - int first = i < j ? i : j; + logger.fine("merged paths:" + pathToString(comparedPaths.get(i))); - comparedPaths.get(first).remove(comparedPaths.get(first).size() - 1); - comparedPaths.remove(last); - comparedPathsEdges.remove(last); + + GraphPart decision = comparedPaths.get(i).get(comparedPaths.get(i).size() - 1); + if (decision.nextParts.size() > 2) { + int removedCount = 0; + for (int k = comparedPaths.size() - 1; k >= 0; k--) { + if (k == i) { + continue; + } + if (comparedPaths.get(i).equals(comparedPaths.get(k))) { + comparedPaths.remove(k); + comparedPathsEdges.remove(k); + removedCount++; + } + if (removedCount == decision.nextParts.size() - 1) { + break; + } + } + comparedPaths.get(i).remove(comparedPaths.get(i).size() - 1); + } else { + //remove last path component + int last = i > j ? i : j; + int first = i < j ? i : j; + comparedPaths.get(first).remove(comparedPaths.get(first).size() - 1); + comparedPaths.remove(last); + comparedPathsEdges.remove(last); + } i = -1; continue loopi; } @@ -928,10 +934,10 @@ public class Graph { for (int i = 0; i < comparedPaths.size(); i++) { for (int j = prefix.size(); j < comparedPaths.get(i).size(); j++) { GraphPart partToClose = comparedPaths.get(i).get(j); - Edge edgeToClose = comparedPathsEdges.get(i); + GraphPartEdge edgeToClose = comparedPathsEdges.get(i); if (!closedBranches.contains(partToClose)) { - logger.info("on part " + p); - logger.info("closing branch " + partToClose); + logger.fine("on part " + p); + logger.fine("closing branch " + partToClose); partsToClose.add(partToClose); } else { logger.fine("probably break edge: " + edgeToClose); @@ -947,7 +953,11 @@ public class Graph { if (isEndOfBlock) { //GraphPart blockStartPart = getDominator(startPart, p, loops); - logger.info("found breaks to to " + p); + logger.fine("found breaks to to " + p); + for (GraphPart r : p.refs) { + gotoTargets.add(new GraphPartEdge(r, p)); + } + //gotoTargets.add(new GraphPartEdge(e.from, e.to)); } } @@ -957,7 +967,7 @@ public class Graph { //filter out backedges List nexts = new ArrayList<>(); for (GraphPart n : p.nextParts) { - Edge ne = new Edge(p, n); + GraphPartEdge ne = new GraphPartEdge(p, n); if (!backEdges.contains(ne)) { nexts.add(n); } else { @@ -965,13 +975,23 @@ public class Graph { } } + int sizeNextsNoThrow = nexts.size(); + for (GraphPart t : p.throwParts) { + GraphPartEdge te = new GraphPartEdge(p, t); + if (!backEdges.contains(te)) { + nexts.add(t); + } else { + logger.fine("throw edge " + te + " is backedge, ignored"); + } + } + closed.add(p); logger.fine("processing nextparts of " + p); for (GraphPart n : nexts) { - Edge ne = new Edge(p, n); + GraphPartEdge ne = new GraphPartEdge(p, n); List subBranches = branches; - if (nexts.size() > 1) { + if (sizeNextsNoThrow > 1) { subBranches = new ArrayList<>(branches); subBranches.add(p); } @@ -1112,13 +1132,13 @@ public class Graph { /**/ //if (ref.nextParts) - private void getBackEdges(BaseLocalData localData, List loops) throws InterruptedException { + private void getBackEdges(BaseLocalData localData, List loops, List gotoParts) 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)) { + if (el.loopContinue.leadsTo(localData, this, code, r, loops, gotoParts)) { el.backEdges.add(r); } } @@ -1183,6 +1203,16 @@ public class Graph { } protected void finalProcessAfter(List list, int level, FinalProcessLocalData localData, String path) { + if (!list.isEmpty() && (list.get(list.size() - 1) instanceof GotoItem)) { + GotoItem gi = (GotoItem) list.get(list.size() - 1); + if (gi.targetCommands != null) { + list.remove(gi); + if (gi.labelName != null) { + list.add(new LabelItem(null, gi.lineStartItem, gi.labelName)); + } + list.addAll(gi.targetCommands); + } + } if (list.size() >= 2) { if (list.get(list.size() - 1) instanceof ExitItem) { ExitItem e = (ExitItem) list.get(list.size() - 1); @@ -1277,10 +1307,6 @@ public class Graph { } private void processIfs(List list) { - - if (true) { - return; //FIXMe - } for (int i = 0; i < list.size(); i++) { GraphTargetItem item = list.get(i); if ((item instanceof LoopItem) && (item instanceof Block)) { @@ -1433,7 +1459,7 @@ public class Graph { return false; } - protected List check(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 foundGotos, List gotoTargets, 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 { return null; } @@ -1509,8 +1535,8 @@ public class Graph { list.remove(list.size() - 1); } - protected List printGraph(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(partCodes, partCodePos, new HashSet<>(), localData, stack, allParts, parent, part, stopPart, loops, null, staticOperation, path, 0); + protected List printGraph(List foundGotos, List gotoTargets, 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, gotoTargets, partCodes, partCodePos, new HashSet<>(), localData, stack, allParts, parent, part, stopPart, loops, null, staticOperation, path, 0); } protected GraphTargetItem checkLoop(LoopItem loopItem, BaseLocalData localData, List loops) { @@ -1573,7 +1599,7 @@ public class Graph { //loopContinues2.remove(lastP1.loopContinue); List loops2 = new ArrayList<>(loops); loops2.remove(lastP1); - if (!part.leadsTo(localData, this, code, lastP1.loopContinue, loops2)) { + if (!part.leadsTo(localData, this, code, lastP1.loopContinue, loops2, new ArrayList<>())) { if (lastP1.breakCandidatesLocked == 0) { if (debugGetLoops) { System.err.println("added breakCandidate " + part + " to " + lastP1); @@ -1598,7 +1624,7 @@ public class Graph { } part.level = level; - boolean isLoop = part.leadsTo(localData, this, code, part, loops); + boolean isLoop = part.leadsTo(localData, this, code, part, loops, new ArrayList<>()); Loop currentLoop = null; if (isLoop) { currentLoop = new Loop(loops.size(), part, null); @@ -1618,7 +1644,7 @@ public class Graph { }*/ nps = part.nextParts; - GraphPart next = getCommonPart(localData, nps, loops);//part.getNextPartPath(loopContinues); + GraphPart next = getCommonPart(localData, nps, loops, new ArrayList<>());//part.getNextPartPath(loopContinues); List stopPart2 = stopPart == null ? new ArrayList<>() : new ArrayList<>(stopPart); if (next != null) { stopPart2.add(next); @@ -1633,7 +1659,7 @@ public class Graph { getLoops(localData, next, loops, stopPart, false, level, visited); } } else if (part.nextParts.size() > 2) { - GraphPart next = getNextCommonPart(localData, part, loops); + GraphPart next = getNextCommonPart(localData, part, loops, new ArrayList<>()); for (GraphPart p : part.nextParts) { List stopPart2 = stopPart == null ? new ArrayList<>() : new ArrayList<>(stopPart); @@ -1690,7 +1716,7 @@ public class Graph { if (cand == cand2) { continue; } - if (cand.leadsTo(localData, this, code, cand2, loops)) { + if (cand.leadsTo(localData, this, code, cand2, loops, new ArrayList<>())) { int lev1 = Integer.MAX_VALUE; int lev2 = Integer.MAX_VALUE; for (int i = 0; i < currentLoop.breakCandidates.size(); i++) { @@ -1809,7 +1835,7 @@ public class Graph { } } - protected List printGraph(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 List printGraph(List foundGotos, List gotoTargets, 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 { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } @@ -1933,12 +1959,13 @@ public class Graph { return ret; } - if (visited.contains(part)) { + GraphPartEdge edge = new GraphPartEdge(parent, part); + if (gotoTargets.contains(edge)) { if (debugPrintGraph) { - System.err.println("Already visited part " + part + ", adding goto"); + //System.err.println("Already visited part " + part + ", adding goto"); } String labelName = "addr" + part.start; - List firstCode = partCodes.get(part); + /*List firstCode = partCodes.get(part); int firstCodePos = partCodePos.get(part); if (firstCodePos > firstCode.size()) { firstCodePos = firstCode.size(); @@ -1947,8 +1974,40 @@ public class Graph { labelName = ((LabelItem) firstCode.get(firstCodePos)).labelName; } else { firstCode.add(firstCodePos, new LabelItem(null, localData.lineStartInstruction, labelName)); + }*/ + GotoItem gi = new GotoItem(null, localData.lineStartInstruction, labelName); + boolean targetCommandsFound = false; + for (int r = foundGotos.size() - 1; r >= 0; r--) { + GotoItem gi2 = foundGotos.get(r); + if (labelName.equals(gi2.labelName)) { + gi.targetCommands = gi2.targetCommands; + gi2.targetCommands = null; + targetCommandsFound = true; + break; + } } - ret.add(new GotoItem(null, localData.lineStartInstruction, labelName)); + if (!targetCommandsFound) { + List newGotoTargets = new ArrayList<>(gotoTargets); + removeEdgeToFromList(newGotoTargets, part); + gi.targetCommands = printGraph(foundGotos, newGotoTargets, partCodes, partCodePos, localData, stack, allParts, parent, part, stopPart, loops, staticOperation, path); + processIfs(gi.targetCommands); + if (!gi.targetCommands.isEmpty() && (gi.targetCommands.get(gi.targetCommands.size() - 1) instanceof ContinueItem)) { + ContinueItem cnt = (ContinueItem) gi.targetCommands.get(gi.targetCommands.size() - 1); + for (Loop l : loops) { + if (l.id == cnt.loopId) { + gi.targetCommands.remove(cnt); + l.precontinueCommands = gi.targetCommands; + l.loopPreContinue = part; + gotoTargets.remove(part); + ret.add(cnt); + return ret; + } + } + } + } + foundGotos.add(gi); + ret.add(gi); + return ret; } else { visited.add(part); @@ -1997,7 +2056,7 @@ public class Graph { } if (parseNext) { - List retCheck = check(partCodes, partCodePos, code, localData, allParts, stack, parent, part, stopPart, loops, output, currentLoop, staticOperation, path); + List retCheck = check(foundGotos, gotoTargets, partCodes, partCodePos, code, localData, allParts, stack, parent, part, stopPart, loops, output, currentLoop, staticOperation, path); if (retCheck != null) { if (!retCheck.isEmpty()) { currentRet.addAll(retCheck); @@ -2012,7 +2071,7 @@ public class Graph { if (parseNext) { if (part.nextParts.size() > 2) { - GraphPart next = getMostCommonPart(localData, part.nextParts, loops); + GraphPart next = getMostCommonPart(localData, part.nextParts, loops, new ArrayList<>()); List vis = new ArrayList<>(); GraphTargetItem switchedItem = stack.pop(); makeAllCommands(currentRet, stack); @@ -2021,6 +2080,7 @@ public class Graph { List> caseCommands = new ArrayList<>(); List valueMappings = new ArrayList<>(); Loop swLoop = new Loop(loops.size(), null, next); + gotoTargets.remove(next); swLoop.phase = 1; loops.add(swLoop); boolean first = false; @@ -2111,8 +2171,12 @@ public class Graph { first = true; pos = 0; List nextCommands = new ArrayList<>(); + for (int i = 1; i < part.nextParts.size(); i++) { + gotoTargets.remove(part.nextParts.get(i)); + } for (int i = 1; i < part.nextParts.size(); i++) { GraphPart p = part.nextParts.get(i); + /*if (pos == ignoredBranch) { pos++; continue; @@ -2146,7 +2210,7 @@ public class Graph { { TranslateStack s2 = (TranslateStack) stack.clone(); s2.clear(); - nextCommands = printGraph(partCodes, partCodePos, visited, prepareBranchLocalData(localData), s2, allParts, part, p, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + nextCommands = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, prepareBranchLocalData(localData), s2, allParts, part, p, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); makeAllCommands(nextCommands, s2); caseCommands.add(nextCommands); vis.add(p); @@ -2197,7 +2261,7 @@ public class Graph { currentRet.add(sw); swLoop.phase = 2; if (next != null) { - currentRet.addAll(printGraph(partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, null, staticOperation, path, recursionLevel + 1)); + currentRet.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, null, staticOperation, path, recursionLevel + 1)); } pos++; } //else @@ -2215,7 +2279,8 @@ public class Graph { nps = part.nextParts; boolean isEmpty = nps.get(0) == nps.get(1); - GraphPart next = getCommonPart(localData, nps, loops); + GraphPart next = getCommonPart(localData, nps, loops, gotoTargets); + //System.err.println("on part " + part + ", next: " + next); TranslateStack trueStack = (TranslateStack) stack.clone(); TranslateStack falseStack = (TranslateStack) stack.clone(); @@ -2241,12 +2306,12 @@ public class Graph { List onTrue = new ArrayList<>(); if (!isEmpty && hasOntrue) { - onTrue = printGraph(partCodes, partCodePos, visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + onTrue = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, prepareBranchLocalData(localData), trueStack, allParts, part, nps.get(1), stopPart2, loops, null, staticOperation, path, recursionLevel + 1); } List onFalse = new ArrayList<>(); if (!isEmpty && hasOnFalse) { - onFalse = printGraph(partCodes, partCodePos, visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + onFalse = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, prepareBranchLocalData(localData), falseStack, allParts, part, nps.get(0), stopPart2, loops, null, staticOperation, path, recursionLevel + 1); } //List out2 = new ArrayList<>(); //makeAllCommands(out2, stack); @@ -2309,7 +2374,7 @@ public class Graph { } //currentRet.addAll(out2); if (next != null) { - printGraph(partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1); + printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, stack, allParts, part, next, stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1); //currentRet.addAll(); } } @@ -2318,7 +2383,7 @@ public class Graph { nextOnePart = part.nextParts.get(0); } if (nextOnePart != null) { - printGraph(partCodes, partCodePos, visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1); + printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, stack, allParts, part, part.nextParts.get(0), stopPart, loops, currentRet, staticOperation, path, recursionLevel + 1); } } @@ -2343,7 +2408,7 @@ public class Graph { stopContPart.add(currentLoop.loopContinue); GraphPart precoBackup = currentLoop.loopPreContinue; currentLoop.loopPreContinue = null; - loopItem.commands.addAll(printGraph(partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, precoBackup, stopContPart, loops, null, staticOperation, path, recursionLevel + 1)); + loopItem.commands.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, precoBackup, stopContPart, loops, null, staticOperation, path, recursionLevel + 1)); } } @@ -2400,14 +2465,17 @@ public class Graph { commands.addAll(loopItem.commands); checkContinueAtTheEnd(commands, currentLoop); List finalComm = new ArrayList<>(); - if (currentLoop.loopPreContinue != null) { + /*if (currentLoop.loopPreContinue != null) { GraphPart backup = currentLoop.loopPreContinue; currentLoop.loopPreContinue = null; List stopPart2 = new ArrayList<>(stopPart); stopPart2.add(currentLoop.loopContinue); - finalComm = printGraph(partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + finalComm = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); currentLoop.loopPreContinue = backup; checkContinueAtTheEnd(finalComm, currentLoop); + }*/ + if (currentLoop.precontinueCommands != null) { + finalComm.addAll(currentLoop.precontinueCommands); } if (!finalComm.isEmpty()) { ret.add(index, li = new ForItem(expr.getSrc(), expr.getLineStartItem(), currentLoop, new ArrayList<>(), exprList.get(exprList.size() - 1), finalComm, commands)); @@ -2478,7 +2546,7 @@ public class Graph { currentLoop.loopPreContinue = null; List stopPart2 = new ArrayList<>(stopPart); stopPart2.add(currentLoop.loopContinue); - List finalComm = printGraph(partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); + List finalComm = printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1); currentLoop.loopPreContinue = backup; checkContinueAtTheEnd(finalComm, currentLoop); @@ -2528,7 +2596,7 @@ public class Graph { } if (currentLoop.loopBreak != null) { - ret.addAll(printGraph(partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, loops, null, staticOperation, path, recursionLevel + 1)); + ret.addAll(printGraph(foundGotos, gotoTargets, partCodes, partCodePos, visited, localData, sPreLoop, allParts, part, currentLoop.loopBreak, stopPart, loops, null, staticOperation, path, recursionLevel + 1)); } } @@ -2806,4 +2874,12 @@ public class Graph { } } } + + protected void removeEdgeToFromList(List edges, GraphPart to) { + for (int i = edges.size() - 1; i >= 0; i--) { + if (edges.get(i).to.equals(to)) { + edges.remove(i); + } + } + } } 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 0b1f559b9..21055bafc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPart.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPart.java @@ -12,12 +12,14 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.graph; import com.jpexs.decompiler.flash.BaseLocalData; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -184,7 +186,10 @@ public class GraphPart implements Serializable { return false; } - public boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart part, List loops) throws InterruptedException { + public boolean leadsTo(BaseLocalData localData, Graph gr, GraphSource code, GraphPart part, List loops, List gotoParts) throws InterruptedException { + if (gotoParts.contains(new GraphPartEdge(this, part))) { + return false; + } for (Loop l : loops) { l.leadsToMark = 0; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartEdge.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartEdge.java new file mode 100644 index 000000000..0ce0e57a1 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartEdge.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010-2018 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.graph; + +import java.util.Objects; + +/** + * + * @author JPEXS + */ +public class GraphPartEdge { + public GraphPart from; + public GraphPart to; + + public GraphPartEdge(GraphPart from, GraphPart to) { + this.from = from; + this.to = to; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 79 * hash + Objects.hashCode(this.from); + hash = 79 * hash + Objects.hashCode(this.to); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final GraphPartEdge other = (GraphPartEdge) obj; + if (!Objects.equals(this.from, other.from)) { + return false; + } + if (!Objects.equals(this.to, other.to)) { + return false; + } + return true; + } + + @Override + public String toString() { + return from.toString() + " -> " + to.toString(); + } + +} 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 ec0cce224..1befc7368 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphTargetItem.java @@ -557,13 +557,15 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { return new NotItem(src, getLineStartItem(), this); } - public GraphTextWriter appendBlock(GraphTargetItem prevLineItem, GraphTextWriter writer, LocalData localData, List commands) throws InterruptedException { + public GraphTextWriter appendCommands(GraphTargetItem prevLineItem, GraphTextWriter writer, LocalData localData, List commands, boolean asBlock) throws InterruptedException { //This may be useful in the future, but we must handle obfuscated SWFs where there is only one debugline instruction on the beggining. final boolean useLineInfo = false; int prevLine = prevLineItem == null ? 0 : prevLineItem.getLine(); - writer.startBlock(); + if (asBlock) { + writer.startBlock(); + } boolean first = true; for (GraphTargetItem ti : commands) { if (!ti.isEmpty()) { @@ -576,10 +578,18 @@ public abstract class GraphTargetItem implements Serializable, Cloneable { ti.toStringSemicoloned(writer, localData); } } - if (!first) { - writer.newLine(); + if (asBlock) { + if (!first) { + writer.newLine(); + } + + writer.endBlock(); } - writer.endBlock(); + return writer; + } + + public GraphTextWriter appendBlock(GraphTargetItem prevLineItem, GraphTextWriter writer, LocalData localData, List commands) throws InterruptedException { + appendCommands(prevLineItem, writer, localData, commands, true); return writer; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Loop.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Loop.java index 435f9cd20..4faf66156 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Loop.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Loop.java @@ -50,6 +50,8 @@ public class Loop implements Serializable { public int breakCandidatesLocked = 0; + public List precontinueCommands = null; + public Loop(long id, GraphPart loopContinue, GraphPart loopBreak) { this.loopContinue = loopContinue; this.loopBreak = loopBreak; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/GotoItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/GotoItem.java index 67a695fed..971a22008 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/GotoItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/model/GotoItem.java @@ -12,22 +12,28 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.graph.model; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.Block; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TypeItem; +import java.util.ArrayList; +import java.util.List; /** * * @author JPEXS */ -public class GotoItem extends GraphTargetItem { +public class GotoItem extends GraphTargetItem implements Block { public String labelName; + public List targetCommands = null; + public GotoItem(GraphSourceItem src, GraphSourceItem lineStartIns, String labelName) { super(src, lineStartIns, PRECEDENCE_PRIMARY); this.labelName = labelName; @@ -35,10 +41,35 @@ public class GotoItem extends GraphTargetItem { @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { - writer.append("§§goto(").append(labelName).append(")"); + if (targetCommands != null) { + if (labelName != null) { + writer.append(labelName); + writer.append(":"); + writer.newLine(); + } + appendCommands(value, writer, localData, targetCommands, false); + } else { + writer.append("§§goto(").append(labelName).append(")"); + } return writer; } + @Override + public boolean needsSemicolon() { + if (targetCommands != null) { + return false; + } + return super.needsSemicolon(); + } + + @Override + public boolean needsNewLine() { + if (targetCommands != null) { + return false; + } + return super.needsNewLine(); + } + @Override public boolean hasReturnValue() { return false; @@ -53,4 +84,27 @@ public class GotoItem extends GraphTargetItem { public Object getResult() { return null; } + + @Override + public List getContinues() { + List ret = new ArrayList<>(); + if (targetCommands == null) { + return ret; + } + for (GraphTargetItem c : targetCommands) { + if (c instanceof ContinueItem) { + ret.add((ContinueItem) c); + } + } + return ret; + } + + @Override + public List> getSubs() { + List> ret = new ArrayList<>(); + if (targetCommands != null) { + ret.add(targetCommands); + } + return ret; + } }