From 763784dbf3c8d276c4e189fa73ec2942c37b1b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 28 Feb 2021 16:53:36 +0100 Subject: [PATCH] Improved goto handling --- .../src/com/jpexs/decompiler/graph/Graph.java | 85 ++++++++--- .../graph/GraphPartMarkedArrayList.java | 133 ++++++++++++++++++ 2 files changed, 200 insertions(+), 18 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartMarkedArrayList.java diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 965646c6b..222f79ae6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -537,7 +537,8 @@ public class Graph { List ret = printGraph(gotos, new HashMap<>(), new HashMap<>(), new HashSet<>(), localData, stack, allParts, null, heads.get(0), null, null, loops, throwStates, staticOperation, path); - processIfGotos(gotos, ret); + processIfGotos2(new ArrayList<>(), gotos, ret, ret); + processIfGotos(gotos, ret, ret); Map usages = new HashMap<>(); Map lastUsage = new HashMap<>(); @@ -809,6 +810,40 @@ public class Graph { } } + private void processIfGotos2(List> alreadyProcessedBlocks, List allGotos, List list, List rootList) { + for (int i = 0; i < list.size(); i++) { + GraphTargetItem item = list.get(i); + if (item instanceof Block) { + List> subs = ((Block) item).getSubs(); + for (List sub : subs) { + processIfGotos2(alreadyProcessedBlocks, allGotos, sub, rootList); + } + } + if (item instanceof GotoItem) { + GotoItem gi = (GotoItem) item; + loopblk: + for (List blk : alreadyProcessedBlocks) { + for (int j = 0; j < blk.size(); j++) { + GraphTargetItem ti = blk.get(j); + if (ti instanceof LabelItem) { + LabelItem label = (LabelItem) ti; + if (label.labelName.equals(gi.labelName)) { + if (blk.get(blk.size() - 1) instanceof ExitItem) { + int siz = blk.size(); + for (int k = 0; k < siz - j; k++) { + list.add(i + 1 + k, blk.remove(j)); + } + blk.add(j, list.remove(i)); + } + break loopblk; + } + } + } + } + } + } + alreadyProcessedBlocks.add(list); + } /** * if (xxx) { y ; goto a } else { z ; goto a } * @@ -817,30 +852,17 @@ public class Graph { * if (xxx) { y } else { z } goto a * */ - private void processIfGotos(List allGotos, List list) { + private void processIfGotos(List allGotos, List list, List rootList) { for (int i = 0; i < list.size(); i++) { GraphTargetItem item = list.get(i); if (item instanceof Block) { List> subs = ((Block) item).getSubs(); for (List sub : subs) { - processIfGotos(allGotos, sub); + processIfGotos(allGotos, sub, rootList); } } if (item instanceof IfItem) { IfItem ii = (IfItem) item; - if (!ii.onTrue.isEmpty() && ii.onFalse.isEmpty()) { - if (ii.onTrue.get(ii.onTrue.size() - 1) instanceof GotoItem) { - if (i + 1 < list.size()) { - if (list.get(i + 1) instanceof GotoItem) { - GotoItem g1 = (GotoItem) ii.onTrue.get(ii.onTrue.size() - 1); - GotoItem g2 = (GotoItem) list.get(i + 1); - if (g1.labelName.equals(g2.labelName)) { - ii.onTrue.remove(ii.onTrue.size() - 1); - } - } - } - } - } if (!ii.onTrue.isEmpty() && !ii.onFalse.isEmpty()) { if (ii.onTrue.get(ii.onTrue.size() - 1) instanceof GotoItem) { if (ii.onFalse.get(ii.onFalse.size() - 1) instanceof GotoItem) { @@ -879,6 +901,20 @@ public class Graph { } } } + if (!ii.onTrue.isEmpty() && ii.onFalse.isEmpty()) { + if (ii.onTrue.get(ii.onTrue.size() - 1) instanceof GotoItem) { + GotoItem g1 = (GotoItem) ii.onTrue.get(ii.onTrue.size() - 1); + if (i + 1 < list.size()) { + if (list.get(i + 1) instanceof GotoItem) { + + GotoItem g2 = (GotoItem) list.get(i + 1); + if (g1.labelName.equals(g2.labelName)) { + ii.onTrue.remove(ii.onTrue.size() - 1); + } + } + } + } + } } } } @@ -1652,7 +1688,7 @@ public class Graph { } if (ret == null) { - ret = new ArrayList<>(); + ret = new GraphPartMarkedArrayList<>(); } //try { @@ -1806,6 +1842,15 @@ public class Graph { if (firstCodePos > firstCode.size()) { firstCodePos = firstCode.size(); } + if (firstCode instanceof GraphPartMarkedArrayList) { + GraphPartMarkedArrayList markedFirstCode = (GraphPartMarkedArrayList) firstCode; + firstCodePos = markedFirstCode.indexOfPart(part); + if (firstCodePos == -1) { + firstCodePos = firstCode.size(); + } + ((GraphPartMarkedArrayList) firstCode).startPart(part); + } + if (firstCode.size() > firstCodePos && (firstCode.get(firstCodePos) instanceof LabelItem)) { labelName = ((LabelItem) firstCode.get(firstCodePos)).labelName; } else { @@ -1842,8 +1887,12 @@ public class Graph { boolean parseNext = true; //****************************DECOMPILING PART************* - List output = new ArrayList<>(); + GraphPartMarkedArrayList output = new GraphPartMarkedArrayList<>(); + output.startPart(part); + if (currentRet instanceof GraphPartMarkedArrayList) { + ((GraphPartMarkedArrayList) currentRet).startPart(part); + } if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, currentLoop, staticOperation, path, recursionLevel)) { parseNext = false; } else { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartMarkedArrayList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartMarkedArrayList.java new file mode 100644 index 000000000..e007c710b --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphPartMarkedArrayList.java @@ -0,0 +1,133 @@ +package com.jpexs.decompiler.graph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class GraphPartMarkedArrayList extends ArrayList { + + private List listParts = new ArrayList<>(); + private GraphPart currentPart = null; + + public GraphPartMarkedArrayList(Collection collection) { + super(collection); + if (collection instanceof GraphPartMarkedArrayList) { + for (int i = 0; i < collection.size(); i++) { + listParts.add((GraphPart) ((GraphPartMarkedArrayList) collection).listParts.get(i)); + } + currentPart = ((GraphPartMarkedArrayList) collection).currentPart; + } else { + for (int i = 0; i < collection.size(); i++) { + listParts.add(currentPart); + } + } + } + + public GraphPartMarkedArrayList() { + } + + public void startPart(GraphPart part) { + currentPart = part; + } + + @Override + public boolean add(E e) { + listParts.add(currentPart); + return super.add(e); + } + + @Override + public void add(int index, E element) { + listParts.add(index, currentPart); + super.add(index, element); + } + + public GraphPart getPartAt(int index) { + return listParts.get(index); + } + + public int indexOfPart(GraphPart part) { + return listParts.indexOf(part); + } + + @Override + public boolean addAll(Collection c) { + if (c instanceof GraphPartMarkedArrayList) { + for (int i = 0; i < c.size(); i++) { + listParts.add((GraphPart) ((GraphPartMarkedArrayList) c).listParts.get(i)); + } + } else { + for (int i = 0; i < c.size(); i++) { + listParts.add(currentPart); + } + } + return super.addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + if (c instanceof GraphPartMarkedArrayList) { + for (int i = 0; i < c.size(); i++) { + listParts.add(index + i, (GraphPart) ((GraphPartMarkedArrayList) c).listParts.get(i)); + } + } else { + for (int i = 0; i < c.size(); i++) { + listParts.add(index + i, currentPart); + } + } + return super.addAll(index, c); + } + + @Override + public boolean remove(Object o) { + if (contains(o)) { + listParts.remove(indexOf(o)); + } + return super.remove(o); + } + + @Override + public E remove(int index) { + listParts.remove(index); + return super.remove(index); + } + + @Override + public void clear() { + listParts.clear(); + super.clear(); + } + + @Override + public List subList(int fromIndex, int toIndex) { + GraphPartMarkedArrayList ret = new GraphPartMarkedArrayList(this); + for (int i = size(); i > toIndex; i--) { + ret.remove(i); + } + for (int i = 0; i < fromIndex; i++) { + ret.remove(i); + } + return ret; + } + + @Override + public Object clone() { + return new GraphPartMarkedArrayList<>(this); + } + + @Override + public boolean removeAll(Collection c) { + for (Object o : c) { + if (contains(o)) { + listParts.remove(indexOf(o)); + } + } + + return super.removeAll(c); + } + +}