diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 330496b73..f9084c372 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -1154,7 +1154,7 @@ public class AVM2Graph extends Graph { }*/ @Override - protected List check(GraphSource srcCode, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output) { + protected List check(GraphSource srcCode, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List output) { List ret = null; @@ -1234,7 +1234,9 @@ public class AVM2Graph extends Graph { } //code.code.get(f).ignored = true; ignoredSwitches.add(f); - finallyCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, fpart, fepart, loops); + List stopPart2=new ArrayList<>(stopPart); + stopPart2.add(fepart); + finallyCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, fpart, stopPart2, loops); returnPos = f + 1; break; } @@ -1281,7 +1283,9 @@ public class AVM2Graph extends Graph { List localData2 = new ArrayList<>(); localData2.addAll(localData); localData2.set(DATA_SCOPESTACK, new Stack()); - catchedCommands.add(printGraph(new ArrayList(), localData2, stack, allParts, parent, npart, nepart, loops)); + List stopPart2=new ArrayList<>(stopPart); + stopPart2.add(nepart); + catchedCommands.add(printGraph(new ArrayList(), localData2, stack, allParts, parent, npart, stopPart2, loops)); } GraphPart nepart = null; @@ -1292,7 +1296,9 @@ public class AVM2Graph extends Graph { break; } } - List tryCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, part, nepart, loops); + List stopPart2=new ArrayList<>(stopPart); + stopPart2.add(nepart); + List tryCommands = printGraph(new ArrayList(), localData, stack, allParts, parent, part, stopPart2, loops); output.clear(); output.add(new TryTreeItem(tryCommands, catchedExceptions, catchedCommands, finallyCommands)); @@ -1440,6 +1446,7 @@ public class AVM2Graph extends Graph { GraphTargetItem ti = checkLoop(next, stopPart, loops); Loop currentLoop = new Loop(loops.size(), null, next); + currentLoop.phase=1; currentLoop.used = true; loops.add(currentLoop); //switchLoc.getNextPartPath(new ArrayList()); @@ -1457,7 +1464,9 @@ public class AVM2Graph extends Graph { GraphPart defaultPart = null; if (hasDefault) { defaultPart = switchLoc.nextParts.get(switchLoc.nextParts.size() - 1); - defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, switchLoc, defaultPart, next, loops); + List stopPart2=new ArrayList<>(stopPart); + stopPart2.add(next); + defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, switchLoc, defaultPart,stopPart2 , loops); if (!defaultCommands.isEmpty()) { if (defaultCommands.get(defaultCommands.size() - 1) instanceof BreakItem) { if (((BreakItem) defaultCommands.get(defaultCommands.size() - 1)).loopId == currentLoop.id) { @@ -1478,32 +1487,35 @@ public class AVM2Graph extends Graph { nextCase = next; if (next != null) { if (i < caseBodies.size() - 1) { - if (!caseBodies.get(i).leadsTo(srcCode, caseBodies.get(i + 1), ignored)) { + if (!caseBodies.get(i).leadsTo(srcCode, caseBodies.get(i + 1), loops)) { //cc.add(new BreakItem(null, currentLoop.id)); } else { nextCase = caseBodies.get(i + 1); } } else if (hasDefault) { - if (!caseBodies.get(i).leadsTo(srcCode, defaultPart, ignored)) { + if (!caseBodies.get(i).leadsTo(srcCode, defaultPart, loops)) { //cc.add(new BreakItem(null, currentLoop.id)); } else { nextCase = defaultPart; } } } - cc.addAll(0, printGraph(new ArrayList(), localData, stack, allParts, switchLoc, caseBodies.get(i), nextCase, loops)); + List stopPart2=new ArrayList<>(stopPart); + stopPart2.add(nextCase); + cc.addAll(0, printGraph(new ArrayList(), localData, stack, allParts, switchLoc, caseBodies.get(i), stopPart2, loops)); caseCommands.add(cc); } SwitchItem sti = new SwitchItem(null, currentLoop, switchedObject, caseValues, caseCommands, defaultCommands, valuesMapping); ret.add(sti); - loops.remove(currentLoop); + //loops.remove(currentLoop); if (next != null) { - if (ti != null) { + /*if (ti != null) { ret.add(ti); - } else { + } else {*/ + currentLoop.phase=2; ret.addAll(printGraph(new ArrayList(), localData, stack, allParts, null, next, stopPart, loops)); - } + //} } } return ret; diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetPropertyIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetPropertyIns.java index 0a16c366c..44dd74cc1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetPropertyIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetPropertyIns.java @@ -58,6 +58,7 @@ public class SetPropertyIns extends InstructionDefinition implements SetTypeIns if (insideProp.propertyName.compareSame(multiname)) { GraphTargetItem insideObj = obj.getThroughDuplicate(); if (insideObj instanceof LocalRegTreeItem) { + if(((LocalRegTreeItem) insideObj).computedValue!=null) insideObj = ((LocalRegTreeItem) insideObj).computedValue.getThroughNotCompilable().getThroughDuplicate(); } if (insideProp.object.getThroughDuplicate() == insideObj) { @@ -88,6 +89,7 @@ public class SetPropertyIns extends InstructionDefinition implements SetTypeIns if (insideProp.propertyName.compareSame(multiname)) { GraphTargetItem insideObj = obj.getThroughDuplicate(); if (insideObj instanceof LocalRegTreeItem) { + if(((LocalRegTreeItem) insideObj).computedValue!=null) insideObj = ((LocalRegTreeItem) insideObj).computedValue.getThroughNotCompilable().getThroughDuplicate(); } if (insideProp.object.getThroughDuplicate() == insideObj) { diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/FullMultinameTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/FullMultinameTreeItem.java index 8f0ce5de9..a8087ec55 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/FullMultinameTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/FullMultinameTreeItem.java @@ -101,6 +101,7 @@ public class FullMultinameTreeItem extends TreeItem { name = name.getThroughDuplicate(); } while (tiName instanceof LocalRegTreeItem) { + if(((LocalRegTreeItem) tiName).computedValue!=null) tiName = ((LocalRegTreeItem) tiName).computedValue.getThroughNotCompilable().getThroughDuplicate(); } @@ -109,6 +110,7 @@ public class FullMultinameTreeItem extends TreeItem { tiName2 = tiName2.getThroughDuplicate(); } while (tiName2 instanceof LocalRegTreeItem) { + if(((LocalRegTreeItem) tiName2).computedValue!=null) tiName2 = ((LocalRegTreeItem) tiName2).computedValue.getThroughNotCompilable().getThroughDuplicate(); } if (tiName != tiName2) { @@ -120,6 +122,7 @@ public class FullMultinameTreeItem extends TreeItem { tiNameSpace = tiNameSpace.getThroughDuplicate(); } while (tiNameSpace instanceof LocalRegTreeItem) { + if(((LocalRegTreeItem) tiNameSpace).computedValue!=null) tiNameSpace = ((LocalRegTreeItem) tiNameSpace).computedValue.getThroughNotCompilable().getThroughDuplicate(); } @@ -128,6 +131,7 @@ public class FullMultinameTreeItem extends TreeItem { tiNameSpace2 = tiNameSpace2.getThroughDuplicate(); } while (tiNameSpace2 instanceof LocalRegTreeItem) { + if(((LocalRegTreeItem) tiNameSpace2).computedValue!=null) tiNameSpace2 = ((LocalRegTreeItem) tiNameSpace2).computedValue.getThroughNotCompilable().getThroughDuplicate(); } if (tiNameSpace != tiNameSpace2) { diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/LocalRegTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/LocalRegTreeItem.java index c3d725062..76045c439 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/LocalRegTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/LocalRegTreeItem.java @@ -33,7 +33,7 @@ public class LocalRegTreeItem extends TreeItem { super(instruction, PRECEDENCE_PRIMARY); this.regIndex = regIndex; if (computedValue == null) { - computedValue = new UndefinedTreeItem(instruction); + //computedValue = new UndefinedTreeItem(instruction); } this.computedValue = computedValue; } @@ -48,21 +48,33 @@ public class LocalRegTreeItem extends TreeItem { @Override public GraphTargetItem getThroughRegister() { + if(computedValue == null){ + return this; + } return computedValue.getThroughRegister(); } @Override public double toNumber() { + if(computedValue==null){ + return 0; + } return computedValue.toNumber(); } @Override public boolean toBoolean() { + if(computedValue==null){ + return false; + } return computedValue.toBoolean(); } @Override public boolean isCompileTime() { + if(computedValue==null){ + return false; + } return computedValue.isCompileTime(); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/TreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/TreeItem.java index 85a7335d6..241b40af9 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/TreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/TreeItem.java @@ -79,8 +79,10 @@ public abstract class TreeItem extends GraphTargetItem { obStr = "(" + obStr + ")"; } if (object instanceof LocalRegTreeItem) { - if (((LocalRegTreeItem) object).computedValue.getThroughNotCompilable() instanceof FindPropertyTreeItem) { - obStr = ""; + if(((LocalRegTreeItem) object).computedValue!=null){ + if (((LocalRegTreeItem) object).computedValue.getThroughNotCompilable() instanceof FindPropertyTreeItem) { + obStr = ""; + } } } if (obStr.equals("")) { diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java index b87465ace..11b5bd71e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java @@ -63,8 +63,13 @@ public class TraitMethodGetterSetter extends Trait { String bodyStr = ""; int bodyIndex = abc.findBodyIndex(method_info); - if ((bodyIndex != -1) && Configuration.DO_DECOMPILE) { + if ((bodyIndex != -1) && (Configuration.DO_DECOMPILE)) { + try{ bodyStr = ABC.addTabs(abc.bodies[bodyIndex].toString(path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames), pcode, isStatic, scriptIndex, classIndex, abc, abc.constants, abc.method_info, new Stack(), false, highlight, fullyQualifiedNames, null), 3); + }catch(StackOverflowError er){ + er.printStackTrace(); + bodyStr="//StackOverflowError"; + } } return ABC.IDENT_STRING + ABC.IDENT_STRING + header + ((classIndex != -1 && abc.instance_info[classIndex].isInterface()) ? ";" : " {\r\n" + bodyStr + "\r\n" + ABC.IDENT_STRING + ABC.IDENT_STRING + "}"); } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java index 8d9e7a4d5..b247d3f71 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/Traits.java @@ -128,8 +128,7 @@ public class Traits implements Serializable { Future future = executor.submit(new TraitConvertTask(traits[t], makePackages, path, abcTags, abc, isStatic, pcode, scriptIndex, classIndex, highlighting, fullyQualifiedNames, t)); futureResults.add(future); } - executor.shutdown(); - + for (int f = 0; f < futureResults.size(); f++) { if (f > 0) { s += "\r\n\r\n"; @@ -140,7 +139,7 @@ public class Traits implements Serializable { Logger.getLogger(Traits.class.getName()).log(Level.SEVERE, "Errod during traits converting", ex); } } - + executor.shutdown(); return s; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java index 52c693690..019757c32 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -124,7 +124,7 @@ public class ActionGraph extends Graph { } @Override - protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output) { + protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List output) { if (!output.isEmpty()) { if (output.get(output.size() - 1) instanceof StoreRegisterTreeItem) { StoreRegisterTreeItem str = (StoreRegisterTreeItem) output.get(output.size() - 1); @@ -184,11 +184,12 @@ public class ActionGraph extends Graph { defaultAndLastPart.add(defaultPart); defaultAndLastPart.add(caseBodyParts.get(caseBodyParts.size() - 1)); - GraphPart defaultPart2 = getCommonPart(defaultAndLastPart); + GraphPart defaultPart2 = getCommonPart(defaultAndLastPart,new ArrayList()); List defaultCommands = new ArrayList<>(); - - defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, null, defaultPart, defaultPart2, loops); + List stopPart2=new ArrayList<>(stopPart); + stopPart2.add(defaultPart2); + defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, null, defaultPart, stopPart2, loops); List loopContinues = new ArrayList<>(); @@ -201,7 +202,7 @@ public class ActionGraph extends Graph { List breakParts = new ArrayList<>(); for (int g = 0; g < caseBodyParts.size(); g++) { if (g < caseBodyParts.size() - 1) { - if (caseBodyParts.get(g).leadsTo(code, caseBodyParts.get(g + 1), loopContinues)) { + if (caseBodyParts.get(g).leadsTo(code, caseBodyParts.get(g + 1), loops)) { continue; } } @@ -260,7 +261,9 @@ public class ActionGraph extends Graph { defaultPart = null; } if ((defaultPart != null) && (defaultCommands.isEmpty())) { - defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, null, defaultPart, next, loops); + List stopPart2x=new ArrayList<>(stopPart); + stopPart2x.add(next); + defaultCommands = printGraph(new ArrayList(), localData, stack, allParts, null, defaultPart, stopPart2x, loops); } List ignored = new ArrayList<>(); @@ -274,20 +277,22 @@ public class ActionGraph extends Graph { nextCase = next; if (next != null) { if (i < caseBodies.size() - 1) { - if (!caseBodies.get(i).leadsTo(code, caseBodies.get(i + 1), ignored)) { + if (!caseBodies.get(i).leadsTo(code, caseBodies.get(i + 1), loops)) { cc.add(new BreakItem(null, currentLoop.id)); } else { nextCase = caseBodies.get(i + 1); } } else if (!defaultCommands.isEmpty()) { - if (!caseBodies.get(i).leadsTo(code, defaultPart, ignored)) { + if (!caseBodies.get(i).leadsTo(code, defaultPart, loops)) { cc.add(new BreakItem(null, currentLoop.id)); } else { nextCase = defaultPart; } } } - cc.addAll(0, printGraph(new ArrayList(), localData, stack, allParts, null, caseBodies.get(i), nextCase, loops)); + List stopPart2x=new ArrayList<>(stopPart); + stopPart2.add(nextCase); + cc.addAll(0, printGraph(new ArrayList(), localData, stack, allParts, null, caseBodies.get(i), stopPart2x, loops)); if (cc.size() >= 2) { if (cc.get(cc.size() - 1) instanceof BreakItem) { if ((cc.get(cc.size() - 2) instanceof ContinueItem) || (cc.get(cc.size() - 2) instanceof BreakItem)) { diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java b/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java index d9bb11057..5b7f60b77 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java @@ -21,8 +21,10 @@ import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.helpers.Highlighting; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; @@ -89,9 +91,9 @@ public class Graph { if (r.path.rootName.equals("e") && !part.path.rootName.equals("e")) { continue; } - if (part.leadsTo(code, r, new ArrayList())) { - //modify=false; - //continue; + if (part.leadsTo(code, r, new ArrayList())) { + modify = false; + continue; } prvni = pos; @@ -158,7 +160,7 @@ public class Graph { } if (part.nextParts.size() == 2) { - if (part.nextParts.get(1).leadsTo(code, part.nextParts.get(0), visited)) { + if (part.nextParts.get(1).leadsTo(code, part.nextParts.get(0), new ArrayList() /*visited*/)) { fixGraphOnce(part.nextParts.get(1), visited, doChildren); fixGraphOnce(part.nextParts.get(0), visited, doChildren); } else { @@ -175,6 +177,7 @@ public class Graph { } private void makeMulti(GraphPart part, List visited) { + if(true) return; if (visited.contains(part)) { return; } @@ -256,37 +259,130 @@ public class Graph { } } - public GraphPart getCommonPart(List parts) { - GraphPart head = new GraphPart(0, 0); - head.nextParts.addAll(parts); - List allVisited = new ArrayList<>(); - head = deepCopy(head, allVisited, null); - for (int g = 0; g < head.nextParts.size(); g++) { - GraphPart gr = head.nextParts.get(g); - for (GraphPart r : gr.refs) { - r.nextParts.remove(gr); + private void getReachableParts(GraphPart part, List ret, List loops) { + getReachableParts(part, ret, loops, true); + } + + private void getReachableParts(GraphPart part, List ret, List loops, boolean first) { + + if (first) { + for (Loop l : loops) { + l.reachableMark = 0; } - gr.refs.clear(); - gr.refs.add(head); } - head.path = new GraphPath(); - resetGraph(head, new ArrayList()); - fixGraph(head); + Loop currentLoop = null; - /*Graph gr=new Graph(); - gr.heads=new ArrayList(); - gr.heads.add(head); - GraphFrame gf=new GraphFrame(gr, ""); - gf.setVisible(true); - */ + for (Loop l : loops) { + if ((l.phase == 1) || (l.reachableMark == 1)) { + if (l.loopContinue == part) { + return; + } + if (l.loopBreak == part) { + return; + } + if (l.loopPreContinue == part) { + return; + } + } + if (l.reachableMark == 0) { + if (l.loopContinue == part) { + l.reachableMark = 1; + currentLoop = l; + } + } + } - GraphPart next = head.getNextPartPath(new ArrayList()); - if (next == null) { + List newparts = new ArrayList<>(); + loopnext: + for (GraphPart next : part.nextParts) { + for (Loop l : loops) { + if ((l.phase == 1) || (l.reachableMark == 1)) { + if (l.loopContinue == next) { + continue loopnext; + } + if (l.loopBreak == next) { + continue loopnext; + } + if (l.loopPreContinue == next) { + continue loopnext; + } + } + + } + if (!ret.contains(next)) { + newparts.add(next); + } + } + + ret.addAll(newparts); + for (GraphPart next : newparts) { + getReachableParts(next, ret, loops); + } + + if (currentLoop != null) { + if (currentLoop.loopBreak != null) { + if (!ret.contains(currentLoop.loopBreak)) { + ret.add(currentLoop.loopBreak); + currentLoop.reachableMark = 2; + getReachableParts(currentLoop.loopBreak, ret, loops); + } + } + } + } + + /* public GraphPart getNextCommonPart(GraphPart part, List loops) { + return getNextCommonPart(part, new ArrayList(),loops); + }*/ + public GraphPart getNextCommonPart(GraphPart part, List loops) { + return getCommonPart(part.nextParts, loops); + } + + public GraphPart getCommonPart(List parts, List loops) { + if (parts.isEmpty()) { return null; } - for (GraphPart g : allVisited) { - if (g.start == next.start) { - return g; + + List loopContinues = getLoopsContinues(loops); + + for (GraphPart p : parts) { + if (loopContinues.contains(p)) { + break; + } + boolean common = true; + for (GraphPart q : parts) { + if (q == p) { + continue; + } + if (!q.leadsTo(code, p, loops)) { + common = false; + break; + } + } + if (common) { + return p; + } + } + List> reachable = new ArrayList<>(); + for (GraphPart p : parts) { + List r1 = new ArrayList<>(); + getReachableParts(p, r1, loops); + r1.add(p); + reachable.add(r1); + } + List first = reachable.get(0); + for (GraphPart p : first) { + /*if (ignored.contains(p)) { + continue; + }*/ + boolean common = true; + for (List r : reachable) { + if (!r.contains(p)) { + common = false; + break; + } + } + if (common) { + return p; } } return null; @@ -311,18 +407,18 @@ public class Graph { } Stack stack = new Stack<>(); List loops = new ArrayList<>(); - getLoops(heads.get(0), loops, null); - /*System.out.println(""); - for (Loop el : loops) { - System.out.println(el); - } - System.out.println("");*/ + /*getLoops(heads.get(0), loops, null); + System.out.println(""); + for (Loop el : loops) { + System.out.println(el); + } + System.out.println("");*/ getPrecontinues(null, heads.get(0), loops, null); /*System.out.println(""); - for (Loop el : loops) { - System.out.println(el); - } - System.out.println("");*/ + for (Loop el : loops) { + System.out.println(el); + } + System.out.println("");*/ List ret = printGraph(new ArrayList(), localData, stack, allParts, null, heads.get(0), null, loops); processIfs(ret); finalProcessStack(stack, ret); @@ -349,6 +445,7 @@ public class Graph { } private void processIfs(List list) { + //if(true) return; for (int i = 0; i < list.size(); i++) { GraphTargetItem item = list.get(i); if (item instanceof Block) { @@ -402,6 +499,35 @@ public class Graph { } + protected List getLoopsContinuesPreAndBreaks(List loops) { + List ret = new ArrayList<>(); + for (Loop l : loops) { + if (l.loopContinue != null) { + ret.add(l.loopContinue); + } + if (l.loopPreContinue != null) { + ret.add(l.loopPreContinue); + } + if (l.loopBreak != null) { + ret.add(l.loopBreak); + } + } + return ret; + } + + protected List getLoopsContinuesAndPre(List loops) { + List ret = new ArrayList<>(); + for (Loop l : loops) { + if (l.loopContinue != null) { + ret.add(l.loopContinue); + } + if (l.loopPreContinue != null) { + ret.add(l.loopPreContinue); + } + } + return ret; + } + protected List getLoopsContinues(List loops) { List ret = new ArrayList<>(); for (Loop l : loops) { @@ -415,8 +541,8 @@ public class Graph { return ret; } - protected GraphTargetItem checkLoop(GraphPart part, GraphPart stopPart, List loops) { - if (part == stopPart) { + protected GraphTargetItem checkLoop(GraphPart part, List stopPart, List loops) { + if (stopPart.contains(part)) { return null; } for (Loop l : loops) { @@ -467,7 +593,7 @@ public class Graph { return false; } - protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List output) { + protected List check(GraphSource code, List localData, List allParts, Stack stack, GraphPart parent, GraphPart part, List stopPart, List loops, List output) { return null; } @@ -543,7 +669,7 @@ public class Graph { list.remove(list.size() - 1); } - protected List printGraph(List visited, List localData, Stack stack, List allParts, GraphPart parent, GraphPart part, GraphPart stopPart, List loops) { + protected List printGraph(List visited, List localData, Stack stack, List allParts, GraphPart parent, GraphPart part, List stopPart, List loops) { return printGraph(visited, localData, stack, allParts, parent, part, stopPart, loops, null); } @@ -551,16 +677,23 @@ public class Graph { return loopItem; } - private void getPrecontinues(GraphPart parent, GraphPart part, List loops, List stopParts) { - if (stopParts == null) { - stopParts = new ArrayList<>(); + private void getPrecontinues(GraphPart parent, GraphPart part, List loops, List stopPart) { + clearLoops(loops); + getPrecontinues(parent, part, loops, stopPart, 0, new ArrayList()); + clearLoops(loops); + } + + + private void getPrecontinues(GraphPart parent, GraphPart part, List loops, List stopPart, int level, List visited) { + + if (stopPart == null) { + stopPart = new ArrayList<>(); } - - - + //System.err.println("prec part:"+part); for (Loop el : loops) { - if (el.precoPhase != 1) { + if (el.phase != 1) { + //System.err.println("Ignored loop "+el); continue; } if (el.loopContinue == part) { @@ -573,119 +706,138 @@ public class Graph { return; } } + if (stopPart.contains(part)) { + return; + } - if ((parent != null) && (part.path.length() < parent.path.length())) { - if (part.refs.size() > 1) { - List nextList = new ArrayList<>(); - populateParts(part, nextList); - Loop nearestLoop = null; - loopn: - for (GraphPart n : nextList) { - if ((!stopParts.isEmpty()) && stopParts.get(stopParts.size() - 1) == n) { - break; + if (visited.contains(part)) { //(part.level > level) { + List nextList = new ArrayList<>(); + populateParts(part, nextList); + Loop nearestLoop = null; + loopn: + for (GraphPart n : nextList) { + for (Loop l : loops) { + if (l.loopContinue == n) { + nearestLoop = l; + break loopn; } - for (Loop l : loops) { - if (l.loopContinue == n) { - nearestLoop = l; - break loopn; - } - } - } - - if ((nearestLoop != null) && (nearestLoop.loopContinue != part)) {// && (nearestLoop.loopBreak != null)) { - if (nearestLoop.precoPhase == 1) { - if ((nearestLoop.loopPreContinue == null) || (nearestLoop.loopPreContinue.leadsTo(code, part, getLoopsContinues(loops)))) { - nearestLoop.loopPreContinue = part; - } - } - return; } } + if ((nearestLoop != null) && (nearestLoop.loopContinue != part)) {// && (nearestLoop.loopBreak != null)) { + if (nearestLoop.phase == 1) { + if ((nearestLoop.loopPreContinue == null)) {// || (nearestLoop.loopPreContinue.leadsTo(code, part, getLoopsContinues(loops)))) { + nearestLoop.loopPreContinue = part; + return; + } + } + } } - - if (stopParts.contains(part)) { - return; + part.level = level; + if (!visited.contains(part)) { + visited.add(part); } List loopContinues = getLoopsContinues(loops); boolean isLoop = false; Loop currentLoop = null; for (Loop el : loops) { - if ((el.precoPhase == 0) && (el.loopContinue == part)) { + if ((el.phase == 0) && (el.loopContinue == part)) { isLoop = true; currentLoop = el; + el.phase = 1; break; } } - if (isLoop) { - currentLoop.precoPhase = 1; - } if (part.nextParts.size() == 2) { - GraphPart next = part.getNextPartPath(new ArrayList()); - List stopParts2 = new ArrayList<>(/*stopParts*/); + GraphPart next = getNextCommonPart(part, loops);//part.getNextPartPath(new ArrayList()); + List stopParts2 = new ArrayList<>(stopPart); if (next != null) { stopParts2.add(next); } - getPrecontinues(part, part.nextParts.get(0), loops, next == null ? stopParts : stopParts2); - getPrecontinues(part, part.nextParts.get(1), loops, next == null ? stopParts : stopParts2); + if (next != part.nextParts.get(0)) { + getPrecontinues(part, part.nextParts.get(0), loops, next == null ? stopPart : stopParts2, level + 1, visited); + } + if (next != part.nextParts.get(1)) { + getPrecontinues(part, part.nextParts.get(1), loops, next == null ? stopPart : stopParts2, level + 1, visited); + } if (next != null) { - getPrecontinues(part, next, loops, stopParts); + getPrecontinues(part, next, loops, stopPart, level, visited); } } if (part.nextParts.size() > 2) { - GraphPart next = getCommonPart(part.nextParts); - List stopParts2 = new ArrayList<>(/*stopParts*/); + GraphPart next = getNextCommonPart(part, loops); + List stopParts2 = new ArrayList<>(stopPart); if (next != null) { stopParts2.add(next); } - for (GraphPart p : part.nextParts) { - getPrecontinues(part, p, loops, next == null ? stopParts : stopParts2); + if (next != p) { + getPrecontinues(part, p, loops, next == null ? stopPart : stopParts2, level + 1, visited); + } } if (next != null) { - getPrecontinues(part, next, loops, stopParts); + getPrecontinues(part, next, loops, stopPart, level, visited); } } if (part.nextParts.size() == 1) { - getPrecontinues(part, part.nextParts.get(0), loops, stopParts); + getPrecontinues(part, part.nextParts.get(0), loops, stopPart, level, visited); } if (isLoop) { if (currentLoop.loopBreak != null) { - currentLoop.precoPhase = 2; - getPrecontinues(null, currentLoop.loopBreak, loops, stopParts); + currentLoop.phase = 2; + getPrecontinues(null, currentLoop.loopBreak, loops, stopPart, level, visited); } } } - private void getLoops(GraphPart part, List loops, GraphPart stopPart) { + private void clearLoops(List loops) { + for (Loop l : loops) { + l.phase = 0; + } + } + private void getLoops(GraphPart part, List loops, List stopPart) { + clearLoops(loops); + getLoops(part, loops, stopPart, true); + clearLoops(loops); + } + + private void getLoops(GraphPart part, List loops, List stopPart, boolean first) { + if(stopPart==null){ + stopPart=new ArrayList<>(); + } if (part == null) { return; } - List loopContinues = getLoopsContinues(loops); - + Loop lastP1=null; for (Loop el : loops) { - if (el.loopBreak == null) { //break not found yet + if ((el.phase==1) && el.loopBreak == null) { //break not found yet if (el.loopContinue != part) { - if (el.breakCandidates.contains(part)) { - el.breakCandidates.add(part); - return; - } else { - List loopContinues2 = new ArrayList<>(loopContinues); - loopContinues2.remove(el.loopContinue); - if (!part.leadsTo(code, el.loopContinue, loopContinues2)) { - el.breakCandidates.add(part); - return; - } - } + lastP1=el; + } } } + if(lastP1!=null){ + if (lastP1.breakCandidates.contains(part)) { + lastP1.breakCandidates.add(part); + return; + } else { + List loopContinues2 = new ArrayList<>(loopContinues); + loopContinues2.remove(lastP1.loopContinue); + List loops2 = new ArrayList<>(loops); + loops2.remove(lastP1); + if (!part.leadsTo(code, lastP1.loopContinue, loops2)) { + lastP1.breakCandidates.add(part); + return; + } + } + } for (Loop el : loops) { if (el.loopContinue == part) { @@ -697,65 +849,123 @@ public class Graph { return; } - - boolean isLoop = part.leadsTo(code, part, loopContinues); + boolean isLoop = part.leadsTo(code, part, loops); Loop currentLoop = null; if (isLoop) { currentLoop = new Loop(loops.size(), part, null); + currentLoop.phase = 1; loops.add(currentLoop); loopContinues.add(part); } if (part.nextParts.size() == 2) { - GraphPart next = part.getNextPartPath(loopContinues); - getLoops(part.nextParts.get(0), loops, next == null ? stopPart : next); - getLoops(part.nextParts.get(1), loops, next == null ? stopPart : next); + GraphPart next = getNextCommonPart(part, loops);//part.getNextPartPath(loopContinues); + List stopPart2=new ArrayList<>(stopPart); + if(next!=null){ + stopPart2.add(next); + } + getLoops(part.nextParts.get(0), loops, stopPart2, false); + getLoops(part.nextParts.get(1), loops, stopPart2, false); if (next != null) { - getLoops(next, loops, stopPart); + getLoops(next, loops, stopPart, false); } } if (part.nextParts.size() > 2) { - //GraphPart next=getCommonPart(part.nextParts); + GraphPart next = getNextCommonPart(part, loops); + List stopPart2=new ArrayList<>(stopPart); + if(next!=null){ + stopPart2.add(next); + } for (GraphPart p : part.nextParts) { - getLoops(p, loops, stopPart); + getLoops(p, loops, stopPart2, false); + } + if (next != null) { + getLoops(next, loops, stopPart, false); } } if (part.nextParts.size() == 1) { - getLoops(part.nextParts.get(0), loops, stopPart); + getLoops(part.nextParts.get(0), loops, stopPart, false); } if (isLoop) { + GraphPart found; + List backupCandidates=new ArrayList<>(); + for(int i=currentLoop.breakCandidates.size()-1;i>=0;i--){ + if(stopPart.contains(currentLoop.breakCandidates.get(i))){ + backupCandidates.add(currentLoop.breakCandidates.remove(i)); + } + } + Set removed=new HashSet<>(); + /* + Set newcommon=new HashSet<>(); + for (GraphPart cand : currentLoop.breakCandidates) { + for (GraphPart cand2 : currentLoop.breakCandidates) { + if(cand==cand2){ + continue; + } + List c=new ArrayList<>(); + c.add(cand); + c.add(cand2); + + GraphPart common=getCommonPart(c, loops); + if(common!=null){ + if(!currentLoop.breakCandidates.contains(common)){ + newcommon.add(common); + } + } + } + } + currentLoop.breakCandidates.addAll(newcommon);*/ do { found = null; loopcand: for (GraphPart cand : currentLoop.breakCandidates) { for (GraphPart cand2 : currentLoop.breakCandidates) { - if (cand.leadsTo(code, cand2, loopContinues)) { - if (cand.path.equals(cand2.path)) { + if (cand.leadsTo(code, cand2, loops)) { + /*if (cand.path.equals(cand2.path)) { found = cand2; - } else { - found = cand; - } + } else {*/ + found = cand; + //} break loopcand; } } } if (found != null) { currentLoop.breakCandidates.remove(found); + removed.add(found); } } while (found != null); Map count = new HashMap<>(); GraphPart winner = null; int winnerCount = 0; + boolean winnerBreakCandidate=true; for (GraphPart cand : currentLoop.breakCandidates) { + if (!count.containsKey(cand)) { count.put(cand, 0); } count.put(cand, count.get(cand) + 1); - if (count.get(cand) > winnerCount) { + boolean otherBreakCandidate=false; + for(Loop el:loops){ + if(el==currentLoop) continue; + if(el.breakCandidates.contains(cand)){ + otherBreakCandidate=true; + break; + } + } + /*if(winnerBreakCandidate && !otherBreakCandidate){ + winnerCount = count.get(cand); + winner = cand; + winnerBreakCandidate=otherBreakCandidate; + }else if(!winnerBreakCandidate && otherBreakCandidate){ + */ + if(otherBreakCandidate){ + + }else if (count.get(cand) > winnerCount) { winnerCount = count.get(cand); winner = cand; } else if (count.get(cand) == winnerCount) { @@ -764,13 +974,45 @@ public class Graph { } } } + if(winner==null){ + if(!backupCandidates.isEmpty()){ + winner=backupCandidates.get(backupCandidates.size()-1); + } + } currentLoop.loopBreak = winner; - - getLoops(currentLoop.loopBreak, loops, stopPart); + currentLoop.phase = 2; + boolean start=false; + for(int l=0;l printGraph(List visited, List localData, Stack stack, List allParts, GraphPart parent, GraphPart part, GraphPart stopPart, List loops, List ret) { + protected List printGraph(List visited, List localData, Stack stack, List allParts, GraphPart parent, GraphPart part, List stopPart, List loops, List ret) { + if (stopPart == null) { + stopPart = new ArrayList<>(); + } if (visited.contains(part)) { //return new ArrayList(); } else { @@ -869,8 +1111,9 @@ public class Graph { boolean isLoop = false; //part.leadsTo(code, part, loopContinues); Loop currentLoop = null; for (Loop el : loops) { - if ((el.loopContinue == part) && (!el.used)) { + if ((el.loopContinue == part) && (el.phase == 0)) { currentLoop = el; + currentLoop.phase = 1; isLoop = true; break; } @@ -885,10 +1128,13 @@ public class Graph { for (int l = loops.size() - 1; l >= 0; l--) { Loop el = loops.get(l); - if (!el.used) { + if (el == currentLoop) { continue; } - if ((el.loopBreak == part) && (!el.finished)) { + if (el.phase != 1) { + continue; + } + if (el.loopBreak == part) { ret.add(new BreakItem(null, el.id)); return ret; } @@ -902,12 +1148,14 @@ public class Graph { } } - if ((part != null) && (code.size() <= part.start)) { - ret.add(new ScriptEndItem()); + + + if (stopPart.contains(part)) { return ret; } - - if (part == stopPart) { + + if ((part != null) && (code.size() <= part.start)) { + ret.add(new ScriptEndItem()); return ret; } @@ -915,6 +1163,7 @@ public class Graph { currentLoop.used = true; } + List currentRet = ret; UniversalLoopItem loopItem = null; if (isLoop) { @@ -981,9 +1230,9 @@ public class Graph { GraphPart sp1 = getNextNoJump(part.nextParts.get(1)); boolean reversed = false; loopContinues = getLoopsContinues(loops); - loopContinues.add(part); - if (sp1.leadsTo(code, sp0, loopContinues)) { - } else if (sp0.leadsTo(code, sp1, loopContinues)) { + loopContinues.add(part);//??? + if (sp1.leadsTo(code, sp0, loops)) { + } else if (sp0.leadsTo(code, sp1, loops)) { reversed = true; } GraphPart next = reversed ? sp0 : sp1; @@ -991,8 +1240,9 @@ public class Graph { if ((ti = checkLoop(next, stopPart, loops)) != null) { currentRet.add(ti); } else { - - printGraph(visited, localData, stack, allParts, parent, next, reversed ? sp1 : sp0, new ArrayList()/*ignore loops*/); + List stopPart2 = new ArrayList<>(stopPart); + stopPart2.add(reversed ? sp1 : sp0); + printGraph(visited, localData, stack, allParts, parent, next, stopPart2, new ArrayList()/*ignore loops*/); GraphTargetItem second = stack.pop(); GraphTargetItem first = stack.pop(); @@ -1032,9 +1282,9 @@ public class Graph { GraphPart sp1 = getNextNoJump(part.nextParts.get(1)); boolean reversed = false; loopContinues = getLoopsContinues(loops); - loopContinues.add(part); - if (sp1.leadsTo(code, sp0, loopContinues)) { - } else if (sp0.leadsTo(code, sp1, loopContinues)) { + loopContinues.add(part);//??? + if (sp1.leadsTo(code, sp0, loops)) { + } else if (sp0.leadsTo(code, sp1, loops)) { reversed = true; } GraphPart next = reversed ? sp0 : sp1; @@ -1042,7 +1292,9 @@ public class Graph { if ((ti = checkLoop(next, stopPart, loops)) != null) { currentRet.add(ti); } else { - printGraph(visited, localData, stack, allParts, parent, next, reversed ? sp1 : sp0, new ArrayList()/*ignore loops*/); + List stopPart2 = new ArrayList<>(stopPart); + stopPart2.add(reversed ? sp1 : sp0); + printGraph(visited, localData, stack, allParts, parent, next, stopPart2, new ArrayList()/*ignore loops*/); GraphTargetItem second = stack.pop(); GraphTargetItem first = stack.pop(); @@ -1095,7 +1347,6 @@ public class Graph { if (part.nextParts.size() == 2) { //List ignore = new ArrayList<>(); //ignore.addAll(loopContinues); - GraphPart next = part.getNextPartPath(loopContinues); //loopContinues); /*for (Loop el : loops) { if (el.loopContinue == next) { @@ -1114,6 +1365,8 @@ public class Graph { } else { expr = new NotItem(null, expr); } + GraphPart next = getNextCommonPart(part, loops);//part.getNextPartPath(loopContinues); //loopContinues); + @SuppressWarnings("unchecked") Stack trueStack = (Stack) stack.clone(); @SuppressWarnings("unchecked") @@ -1127,12 +1380,17 @@ public class Graph { next = part.nextParts.get(0); } + List stopPart2 = new ArrayList<>(stopPart); + if (next != null) { + stopPart2.add(next); + } if (!isEmpty) { - onTrue = printGraph(visited, localData, trueStack, allParts, part, part.nextParts.get(1), next == null ? stopPart : next, loops); + onTrue = printGraph(visited, localData, trueStack, allParts, part, part.nextParts.get(1), stopPart2, loops); } List onFalse = new ArrayList<>(); + if (!isEmpty) { - onFalse = printGraph(visited, localData, falseStack, allParts, part, part.nextParts.get(0), next == null ? stopPart : next, loops); + onFalse = printGraph(visited, localData, falseStack, allParts, part, part.nextParts.get(0), stopPart2, loops); } if (isEmpty(onTrue) && isEmpty(onFalse) && (trueStack.size() > trueStackSizeBefore) && (falseStack.size() > falseStackSizeBefore)) { stack.push(new TernarOpItem(null, expr, trueStack.pop(), falseStack.pop())); @@ -1150,6 +1408,7 @@ public class Graph { } if (isLoop) { + currentLoop.phase = 2; LoopItem li = loopItem; boolean loopTypeFound = false; @@ -1160,6 +1419,26 @@ public class Graph { if (!loopTypeFound && (!loopItem.commands.isEmpty())) { if (loopItem.commands.get(0) instanceof IfItem) { IfItem ifi = (IfItem) loopItem.commands.get(0); + + /*if(loopItem.commands.get(loopItem.commands.size()-1) instanceof BreakItem){ + BreakItem bi = (BreakItem)loopItem.commands.get(loopItem.commands.size()-1); + if(bi.loopId==currentLoop.id){ + if(!ifi.onFalse.isEmpty()){ + if(ifi.onFalse.get(ifi.onFalse.size()-1) instanceof ContinueItem){ + ContinueItem ci=(ContinueItem)ifi.onFalse.get(ifi.onFalse.size()-1); + if(ci.loopId==currentLoop.id){ + if(ifi.onTrue.isEmpty()){ + while(1 bodyBranch = null; boolean inverted = false; if ((ifi.onTrue.size() == 1) && (ifi.onTrue.get(0) instanceof BreakItem)) { @@ -1196,7 +1475,9 @@ public class Graph { if (currentLoop.loopPreContinue != null) { GraphPart backup = currentLoop.loopPreContinue; currentLoop.loopPreContinue = null; - finalComm = printGraph(visited, localData, new Stack(), allParts, null, backup, currentLoop.loopContinue, loops); + List stopPart2 = new ArrayList<>(stopPart); + stopPart2.add(currentLoop.loopContinue); + finalComm = printGraph(visited, localData, new Stack(), allParts, null, backup, stopPart2, loops); currentLoop.loopPreContinue = backup; checkContinueAtTheEnd(finalComm, currentLoop); } @@ -1273,7 +1554,9 @@ public class Graph { loopTypeFound = true; GraphPart backup = currentLoop.loopPreContinue; currentLoop.loopPreContinue = null; - List finalComm = printGraph(visited, localData, new Stack(), allParts, null, backup, currentLoop.loopContinue, loops); + List stopPart2 = new ArrayList<>(stopPart); + stopPart2.add(currentLoop.loopContinue); + List finalComm = printGraph(visited, localData, new Stack(), allParts, null, backup, stopPart2, loops); currentLoop.loopPreContinue = backup; checkContinueAtTheEnd(finalComm, currentLoop); @@ -1327,7 +1610,6 @@ public class Graph { //loops.remove(currentLoop); if (currentLoop.loopBreak != null) { - currentLoop.finished = true; ret.addAll(printGraph(visited, localData, stack, allParts, part, currentLoop.loopBreak, stopPart, loops)); } } @@ -1586,4 +1868,5 @@ public class Graph { public List prepareBranchLocalData(List localData) { return localData; } + } diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/GraphPart.java b/trunk/src/com/jpexs/decompiler/flash/graph/GraphPart.java index b971b3842..4848ff630 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/GraphPart.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/GraphPart.java @@ -35,14 +35,57 @@ public class GraphPart { public List refs = new ArrayList<>(); public boolean ignored = false; public List forContinues = new ArrayList<>(); - - private boolean leadsTo(GraphSource code, GraphPart part, List visited, List ignored) { + public int level; + + public int discoveredTime; + public int finishedTime; + public int order; + + + public int setTime(int time,List ordered,List visited){ + discoveredTime = time; + visited.add(this); + for(GraphPart next:nextParts){ + if(!visited.contains(next)){ + time=next.setTime(time+1, ordered, visited); + } + } + time++; + finishedTime = time; + order=ordered.size(); + ordered.add(this); + return time; + } + + private boolean leadsTo(GraphSource code, GraphPart part, List visited, List loops) { + Loop currentLoop=null; + for(Loop l:loops){ + /*if(l.phase==0){ + if(l.loopContinue==this){ + l.leadsToMark = 1; + next = l.loopBreak; + currentLoop = l; + continue; + } + }*/ + if(l.phase==1){ + if(l.loopContinue==this){ + return false; + } + if(l.loopPreContinue==this){ + return false; + } + if(l.loopBreak==this){ + return false; + } + } + } if (visited.contains(this)) { return false; } - if (ignored.contains(this)) { + /*if (loops.contains(this)) { return false; - } + }*/ visited.add(this); if (end < code.size() && code.get(end).isBranch() && (code.get(end).ignoredLoops())) { return false; @@ -51,7 +94,7 @@ public class GraphPart { if (p == part) { return true; } else { - if (p.leadsTo(code, part, visited, ignored)) { + if (p.leadsTo(code, part, visited, loops)) { return true; } } @@ -59,8 +102,11 @@ public class GraphPart { return false; } - public boolean leadsTo(GraphSource code, GraphPart part, List ignored) { - return leadsTo(code, part, new ArrayList(), ignored); + public boolean leadsTo(GraphSource code, GraphPart part, List loops) { + for(Loop l:loops){ + l.leadsToMark = 0; + } + return leadsTo(code, part, new ArrayList(), loops); } public GraphPart(int start, int end) { diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/Loop.java b/trunk/src/com/jpexs/decompiler/flash/graph/Loop.java index dc3dd9dec..047784e39 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/Loop.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/Loop.java @@ -28,11 +28,13 @@ public class Loop { public GraphPart loopContinue; public GraphPart loopBreak; public GraphPart loopPreContinue; - public int precoPhase; public List breakCandidates = new ArrayList<>(); public long id; public boolean used = false; public boolean finished = false; + public int leadsToMark; + public int reachableMark; + public int phase; public Loop(long id, GraphPart loopContinue, GraphPart loopBreak) { this.loopContinue = loopContinue; @@ -42,6 +44,6 @@ public class Loop { @Override public String toString() { - return "loop(id:" + id + (loopPreContinue != null ? ",precontinue:" + loopPreContinue : "") + ",continue:" + loopContinue + ", break:" + loopBreak + ")"; + return "loop(id:" + id + (loopPreContinue != null ? ",precontinue:" + loopPreContinue : "") + ",continue:" + loopContinue + ", break:" + loopBreak + ", phase:"+phase+")"; } }