Improved for continue / goto detection

This commit is contained in:
Jindra Petřík
2021-01-17 21:52:33 +01:00
parent 96f3aee198
commit dc18fad2b3
8 changed files with 376 additions and 150 deletions

View File

@@ -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<GraphTargetItem> check(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, Set<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
protected List<GraphTargetItem> check(List<GotoItem> foundGotos, List<GraphPartEdge> gotoTargets, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, Set<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
List<GraphTargetItem> 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<GraphTargetItem> ncatchedCommands = printGraph(partCodes, partCodePos, localData2, st2, allParts, parent, npart, stopPart2, loops, staticOperation, path);
List<GraphTargetItem> 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<GraphTargetItem> tryCommands = printGraph(partCodes, partCodePos, localData, st, allParts, parent, part, stopPart2, loops, staticOperation, path);
List<GraphTargetItem> 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<GraphPart> 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<List<GraphTargetItem>> 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));
}
}
}

View File

@@ -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<GraphTargetItem> check(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, Set<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
protected List<GraphTargetItem> check(List<GotoItem> foundGotos, List<GraphPartEdge> gotoTargets, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, Set<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> 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<List<GraphTargetItem>> 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));
}
}
}

View File

@@ -315,13 +315,12 @@ public class Graph {
}
}
private void getReachableParts(GraphPart part, LinkedHashSet<GraphPart> ret, List<Loop> loops) {
private void getReachableParts(GraphPart part, LinkedHashSet<GraphPart> ret, List<Loop> loops, List<GraphPartEdge> gotoParts) {
// use LinkedHashSet to preserve order
getReachableParts(part, ret, loops, true);
getReachableParts(part, ret, loops, true, gotoParts);
}
private void getReachableParts(GraphPart part, LinkedHashSet<GraphPart> ret, List<Loop> loops, boolean first) {
private void getReachableParts(GraphPart part, LinkedHashSet<GraphPart> ret, List<Loop> loops, boolean first, List<GraphPartEdge> gotoParts) {
// todo: honfika: why call with first = true parameter always?
Stack<GraphPartQueue> 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<Loop> loops) throws InterruptedException {
return getCommonPart(localData, part.nextParts, loops);
public GraphPart getNextCommonPart(BaseLocalData localData, GraphPart part, List<Loop> loops, List<GraphPartEdge> gotoParts) throws InterruptedException {
return getCommonPart(localData, part.nextParts, loops, gotoParts);
}
//TODO: Make this faster!
public GraphPart getCommonPart(BaseLocalData localData, List<GraphPart> parts, List<Loop> loops) throws InterruptedException {
public GraphPart getCommonPart(BaseLocalData localData, List<GraphPart> parts, List<Loop> loops, List<GraphPartEdge> 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<Set<GraphPart>> reachable = new ArrayList<>();
for (GraphPart p : parts) {
LinkedHashSet<GraphPart> 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<GraphPart> parts, List<Loop> loops) throws InterruptedException {
public GraphPart getMostCommonPart(BaseLocalData localData, List<GraphPart> parts, List<Loop> loops, List<GraphPartEdge> 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<Set<GraphPart>> reachable = new ArrayList<>();
for (GraphPart p : parts) {
LinkedHashSet<GraphPart> r1 = new LinkedHashSet<>();
getReachableParts(p, r1, loops);
getReachableParts(p, r1, loops, gotoParts);
Set<GraphPart> 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<GraphPartEdge> 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("<loopspre>");
for (Loop el : loops) {
System.err.println(el);
}
System.err.println("</loopspre>");//*/
List<GraphTargetItem> ret = printGraph(new HashMap<>(), new HashMap<>(), localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path);
List<GotoItem> gotos = new ArrayList<>();
List<GraphTargetItem> ret = printGraph(gotos, gotoTargets, new HashMap<>(), new HashMap<>(), localData, stack, allParts, null, heads.get(0), null, loops, staticOperation, path);
Map<String, Integer> usages = new HashMap<>();
Map<String, GotoItem> 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<GraphPart> getCommonPrefix(List<List<GraphPart>> listOfLists) {
List<GraphPart> 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<GraphPart> allParts, List<Loop> loops) {
private void findGotoTargets(String path, GraphPart startPart, List<Loop> loops, List<GraphPartEdge> gotoTargets) {
if (!path.equals("classes.tests/ForTest1.test")) {
//return;
}
logger.info("GETTING precontinues of " + path + " =================");
//logger.info("GETTING precontinues of " + path + " =================");
Set<GraphPart> opened = new HashSet<>();
Set<GraphPart> closed = new HashSet<>();
Set<GraphPart> closedBranches = new HashSet<>();
Set<Edge> exitEdges = new HashSet<>();
Set<Edge> backEdges = new HashSet<>();
Set<GraphPartEdge> exitEdges = new HashSet<>();
Set<GraphPartEdge> 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<Edge, List<GraphPart>> edgeToBranches = new HashMap<>();
Map<GraphPartEdge, List<GraphPart>> edgeToBranches = new HashMap<>();
opened.add(startPart);
GraphPart start = startPart;
Stack<Edge> walkStack = new Stack<>();
walkStack.push(new Edge(startPart, startPart));
Stack<GraphPartEdge> 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<GraphPart> refs = getUnicatePartList(p.refs);
List<List<GraphPart>> comparedPaths = new ArrayList<>();
List<Edge> comparedPathsEdges = new ArrayList<>();
List<GraphPartEdge> 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<GraphPart> 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<GraphPart> 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<Loop> loops) throws InterruptedException {
private void getBackEdges(BaseLocalData localData, List<Loop> loops, List<GraphPartEdge> gotoParts) throws InterruptedException {
clearLoops(loops);
for (Loop el : loops) {
el.backEdges.clear();
Set<GraphPart> 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<GraphTargetItem> 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<GraphTargetItem> 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<GraphTargetItem> check(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, Set<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> output, Loop currentLoop, int staticOperation, String path) throws InterruptedException {
protected List<GraphTargetItem> check(List<GotoItem> foundGotos, List<GraphPartEdge> gotoTargets, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, GraphSource code, BaseLocalData localData, Set<GraphPart> allParts, TranslateStack stack, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> 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<GraphTargetItem> printGraph(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, BaseLocalData localData, TranslateStack stack, Set<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> 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<GraphTargetItem> printGraph(List<GotoItem> foundGotos, List<GraphPartEdge> gotoTargets, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, BaseLocalData localData, TranslateStack stack, Set<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> 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<Loop> loops) {
@@ -1573,7 +1599,7 @@ public class Graph {
//loopContinues2.remove(lastP1.loopContinue);
List<Loop> 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<GraphPart> 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<GraphPart> 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<GraphTargetItem> printGraph(Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> visited, BaseLocalData localData, TranslateStack stack, Set<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> ret, int staticOperation, String path, int recursionLevel) throws InterruptedException {
protected List<GraphTargetItem> printGraph(List<GotoItem> foundGotos, List<GraphPartEdge> gotoTargets, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> visited, BaseLocalData localData, TranslateStack stack, Set<GraphPart> allParts, GraphPart parent, GraphPart part, List<GraphPart> stopPart, List<Loop> loops, List<GraphTargetItem> 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<GraphTargetItem> firstCode = partCodes.get(part);
/*List<GraphTargetItem> 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<GraphPartEdge> 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<GraphTargetItem> retCheck = check(partCodes, partCodePos, code, localData, allParts, stack, parent, part, stopPart, loops, output, currentLoop, staticOperation, path);
List<GraphTargetItem> 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<GraphPart> vis = new ArrayList<>();
GraphTargetItem switchedItem = stack.pop();
makeAllCommands(currentRet, stack);
@@ -2021,6 +2080,7 @@ public class Graph {
List<List<GraphTargetItem>> caseCommands = new ArrayList<>();
List<Integer> 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<GraphTargetItem> 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<GraphTargetItem> 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<GraphTargetItem> 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<GraphTargetItem> 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<GraphTargetItem> finalComm = new ArrayList<>();
if (currentLoop.loopPreContinue != null) {
/*if (currentLoop.loopPreContinue != null) {
GraphPart backup = currentLoop.loopPreContinue;
currentLoop.loopPreContinue = null;
List<GraphPart> 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<GraphPart> stopPart2 = new ArrayList<>(stopPart);
stopPart2.add(currentLoop.loopContinue);
List<GraphTargetItem> finalComm = printGraph(partCodes, partCodePos, visited, localData, new TranslateStack(path), allParts, null, backup, stopPart2, loops, null, staticOperation, path, recursionLevel + 1);
List<GraphTargetItem> 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<GraphPartEdge> edges, GraphPart to) {
for (int i = edges.size() - 1; i >= 0; i--) {
if (edges.get(i).to.equals(to)) {
edges.remove(i);
}
}
}
}

View File

@@ -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<Loop> loops, List<GraphPartEdge> gotoParts) throws InterruptedException {
if (gotoParts.contains(new GraphPartEdge(this, part))) {
return false;
}
for (Loop l : loops) {
l.leadsToMark = 0;
}

View File

@@ -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();
}
}

View File

@@ -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<GraphTargetItem> commands) throws InterruptedException {
public GraphTextWriter appendCommands(GraphTargetItem prevLineItem, GraphTextWriter writer, LocalData localData, List<GraphTargetItem> 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<GraphTargetItem> commands) throws InterruptedException {
appendCommands(prevLineItem, writer, localData, commands, true);
return writer;
}

View File

@@ -50,6 +50,8 @@ public class Loop implements Serializable {
public int breakCandidatesLocked = 0;
public List<GraphTargetItem> precontinueCommands = null;
public Loop(long id, GraphPart loopContinue, GraphPart loopBreak) {
this.loopContinue = loopContinue;
this.loopBreak = loopBreak;

View File

@@ -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 implements Block {
public String labelName;
public List<GraphTargetItem> 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 {
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
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<ContinueItem> getContinues() {
List<ContinueItem> 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<List<GraphTargetItem>> getSubs() {
List<List<GraphTargetItem>> ret = new ArrayList<>();
if (targetCommands != null) {
ret.add(targetCommands);
}
return ret;
}
}