Graph refactoring

This commit is contained in:
Jindra Petk
2013-02-10 14:19:53 +01:00
parent 92b02e3b56
commit c8f8fbc177
11 changed files with 208 additions and 231 deletions

View File

@@ -20,7 +20,7 @@ import com.jpexs.asdec.Main;
import com.jpexs.asdec.abc.ABC;
import com.jpexs.asdec.abc.ABCInputStream;
import com.jpexs.asdec.abc.CopyOutputStream;
import com.jpexs.asdec.abc.avm2.flowgraph.Graph;
import com.jpexs.asdec.abc.avm2.graph.AVM2Graph;
import com.jpexs.asdec.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.asdec.abc.avm2.instructions.IfTypeIns;
import com.jpexs.asdec.abc.avm2.instructions.InstructionDefinition;
@@ -1901,7 +1901,7 @@ public class AVM2Code implements Serializable {
//try {
try{
list = Graph.translateViaGraph(path,this, abc, body);
list = AVM2Graph.translateViaGraph(path,this, abc, body);
}catch(Exception ex2){
Logger.getLogger(AVM2Code.class.getName()).log(Level.SEVERE, "Decompilation error in "+path,ex2);
return "/*\r\n * Decompilation error\r\n * Code may be obfuscated\r\n * Error Message: " + ex2.getMessage() + "\r\n */";

View File

@@ -14,8 +14,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.asdec.abc.avm2.flowgraph;
package com.jpexs.asdec.abc.avm2.graph;
import com.jpexs.asdec.graph.Graph;
import com.jpexs.asdec.graph.GraphPart;
import com.jpexs.asdec.graph.Loop;
import com.jpexs.asdec.graph.GraphPartMulti;
import com.jpexs.asdec.abc.ABC;
import com.jpexs.asdec.abc.avm2.AVM2Code;
import com.jpexs.asdec.abc.avm2.ConvertException;
@@ -85,69 +89,26 @@ import java.util.logging.Logger;
*
* @author JPEXS
*/
public class Graph {
public class AVM2Graph extends Graph{
public List<GraphPart> heads;
private AVM2Code code;
private ABC abc;
private MethodBody body;
public Graph(AVM2Code code, ABC abc, MethodBody body) {
public AVM2Graph(AVM2Code code, ABC abc, MethodBody body) {
heads = makeGraph(code, new ArrayList<GraphPart>(), body);
this.code = code;
this.abc = abc;
this.body = body;
for (GraphPart head : heads) {
fixGraph(head);
//makeMulti(head, new ArrayList<GraphPart>());
fixGraph(head);
}
}
private void makeMulti(GraphPart part, List<GraphPart> visited) {
if (visited.contains(part)) {
return;
}
visited.add(part);
GraphPart p = part;
List<GraphPart> multiList = new ArrayList<GraphPart>();
multiList.add(p);
while ((p.nextParts.size() == 1) && (p.nextParts.get(0).refs.size() == 1)) {
p = p.nextParts.get(0);
multiList.add(p);
}
if (multiList.size() > 1) {
GraphPartMulti gpm = new GraphPartMulti(multiList);
gpm.refs = part.refs;
GraphPart lastPart = multiList.get(multiList.size() - 1);
gpm.nextParts = lastPart.nextParts;
for (GraphPart next : gpm.nextParts) {
int index = next.refs.indexOf(lastPart);
if (index == -1) {
continue;
}
next.refs.remove(lastPart);
next.refs.add(index, gpm);
}
for (GraphPart parent : part.refs) {
if (parent.start == -1) {
continue;
}
int index = parent.nextParts.indexOf(part);
if (index == -1) {
continue;
}
parent.nextParts.remove(part);
parent.nextParts.add(index, gpm);
}
}
for (int i = 0; i < part.nextParts.size(); i++) {
makeMulti(part.nextParts.get(i), visited);
}
}
public static List<TreeItem> translateViaGraph(String path, AVM2Code code, ABC abc, MethodBody body) {
Graph g = new Graph(code, abc, body);
AVM2Graph g = new AVM2Graph(code, abc, body);
List<GraphPart> allParts = new ArrayList<GraphPart>();
for (GraphPart head : g.heads) {
populateParts(head, allParts);
@@ -155,37 +116,7 @@ public class Graph {
return g.printGraph(path, new Stack<TreeItem>(), new Stack<TreeItem>(), allParts, new ArrayList<ABCException>(), new ArrayList<Integer>(), 0, null, g.heads.get(0), null, new ArrayList<Loop>(), new HashMap<Integer, TreeItem>(), body, new ArrayList<Integer>());
}
private static void populateParts(GraphPart part, List<GraphPart> allParts) {
if (allParts.contains(part)) {
return;
}
allParts.add(part);
for (GraphPart p : part.nextParts) {
populateParts(p, allParts);
}
}
private String strOfChars(int len, String chars) {
String ret = "";
for (int i = 0; i < len; i++) {
ret += chars;
}
return ret;
}
private static final String TAB = " ";
private String printOutput(int level, List<TreeItem> output, List<String> fqn, HashMap<Integer, String> lrn) {
String s = Highlighting.stripHilights(code.listToString(output, abc.constants, lrn, fqn));
String parts[] = s.split("\n");
String ret = "";
for (String p : parts) {
if (p.trim().equals("")) {
continue;
}
ret += (strOfChars(level, TAB) + p.trim()) + "\r\n";
}
return ret;
}
private TreeItem checkLoop(GraphPart part, GraphPart stopPart, List<Loop> loops) {
if (part == stopPart) {
@@ -394,7 +325,7 @@ public class Graph {
//((IfTypeIns)ins.definition).translateInverted(new HashMap<Integer,TreeItem>(), co.stack, ins);
}
} catch (ConvertException ex) {
Logger.getLogger(Graph.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(AVM2Graph.class.getName()).log(Level.SEVERE, null, ex);
}
int ip = part.start;
@@ -615,8 +546,11 @@ public class Graph {
}
finalPart = fex.continuePart;
isFor = true;
for (ContinueTreeItem cti : finalPart.forContinues) {
cti.loopPos = breakIp;
for (Object o : finalPart.forContinues) {
if(o instanceof ContinueTreeItem)
{
((ContinueTreeItem)o).loopPos = breakIp;
}
}
}
if (isFor) {
@@ -867,135 +801,7 @@ public class Graph {
return ret;
}
private void fixGraph(GraphPart part) {
while (fixGraphOnce(part, new ArrayList<GraphPart>(), false)) {
}
}
private boolean fixGraphOnce(GraphPart part, List<GraphPart> visited, boolean doChildren) {
if (visited.contains(part)) {
return false;
}
visited.add(part);
boolean fixed = false;
/*System.out.print("Part " + part.start + "-" + part.end + " refs:");
for (GraphPart gp : part.refs) {
System.out.print(gp.path + " ");
}
System.out.println("");*/
int i = 1;
String lastpref = null;
boolean modify = true;
int prvni = -1;
if (!doChildren) {
List<GraphPart> uniqueRefs = new ArrayList<GraphPart>();
for (GraphPart r : part.refs) {
if (!uniqueRefs.contains(r)) {
uniqueRefs.add(r);
}
}
loopi:
for (; i <= part.path.length(); i++) {
lastpref = null;
int pos = -1;
for (GraphPart r : uniqueRefs) {
pos++;
if (r.path.startsWith("e")) {
continue;
}
if (part.leadsTo(r, new ArrayList<GraphPart>())) {
//modify=false;
//continue;
}
prvni = pos;
if (i > r.path.length()) {
i--;
break loopi;
}
if (lastpref == null) {
lastpref = r.path.substring(0, i);
} else {
if (!r.path.startsWith(lastpref)) {
i--;
break loopi;
}
}
}
}
if (i > part.path.length()) {
i = part.path.length();
}
if (modify && ((uniqueRefs.size() > 1) && (prvni >= 0))) {
String newpath = uniqueRefs.get(prvni).path.substring(0, i);
if (!part.path.equals(newpath)) {
if (part.path.startsWith(newpath)) {
String origPath = part.path;
GraphPart p = part;
part.path = newpath;
while (p.nextParts.size() == 1) {
p = p.nextParts.get(0);
if (!p.path.equals(origPath)) {
break;
}
p.path = newpath;
}
fixGraphOnce(part, new ArrayList<GraphPart>(), true);
fixed = true;
}
}
}
} else {
if (!fixed) {
if (part.nextParts.size() == 1) {
if (!(part.path.startsWith("e") && (!part.nextParts.get(0).path.startsWith("e")))) {
if (part.nextParts.get(0).path.length() > part.path.length()) {
part.nextParts.get(0).path = part.path;
fixed = true;
}
}
}
if (part.nextParts.size() > 1) {
for (int j = 0; j < part.nextParts.size(); j++) {
GraphPart npart = part.nextParts.get(j);
if (npart.path.length() > part.path.length() + 1) {
npart.path = part.path + "" + j;
fixed = true;
}
}
}
}
}
/* if (part.nextParts.size() == 2) {
GraphPart left = part.nextParts.get(0);
GraphPart right = part.nextParts.get(1);
if ((left.nextParts.size() == 1) && (right.nextParts.size() == 1)) {
if (left.nextParts.get(0) == right.nextParts.get(0)) {
if (!left.nextParts.get(0).path.equals(part.path)) {
String origPath = left.nextParts.get(0).path;
GraphPart p = left;
while (p.nextParts.size() == 1) {
p = p.nextParts.get(0);
if (!p.path.equals(origPath)) {
break;
}
p.path = part.path;
}
fixed = true;
}
}
}
}*/
for (GraphPart p : part.nextParts) {
fixGraphOnce(p, visited, doChildren);
}
return fixed;
}
private List<GraphPart> makeGraph(AVM2Code code, List<GraphPart> allBlocks, MethodBody body) {
HashMap<Integer, List<Integer>> refs = code.visitCode(body);

View File

@@ -1,5 +1,6 @@
package com.jpexs.asdec.abc.avm2.flowgraph;
package com.jpexs.asdec.abc.avm2.graph;
import com.jpexs.asdec.graph.GraphPart;
import com.jpexs.asdec.abc.avm2.treemodel.TreeItem;
import java.util.List;

View File

@@ -19,7 +19,7 @@ package com.jpexs.asdec.abc.gui;
import com.jpexs.asdec.abc.ABC;
import com.jpexs.asdec.abc.avm2.AVM2Code;
import com.jpexs.asdec.abc.avm2.ConstantPool;
import com.jpexs.asdec.abc.avm2.flowgraph.Graph;
import com.jpexs.asdec.abc.avm2.graph.AVM2Graph;
import com.jpexs.asdec.abc.avm2.parser.ASM3Parser;
import com.jpexs.asdec.abc.avm2.parser.ParseException;
import com.jpexs.asdec.helpers.Highlighting;
@@ -73,7 +73,7 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretLi
}
public void graph() {
Graph gr = new Graph(abc.bodies[bodyIndex].code,abc,abc.bodies[bodyIndex]);
AVM2Graph gr = new AVM2Graph(abc.bodies[bodyIndex].code,abc,abc.bodies[bodyIndex]);
(new GraphFrame(gr, "")).setVisible(true);
}

View File

@@ -16,8 +16,8 @@
*/
package com.jpexs.asdec.abc.gui;
import com.jpexs.asdec.abc.avm2.flowgraph.Graph;
import com.jpexs.asdec.abc.avm2.flowgraph.GraphPart;
import com.jpexs.asdec.abc.avm2.graph.AVM2Graph;
import com.jpexs.asdec.graph.GraphPart;
import com.jpexs.asdec.gui.View;
import java.awt.*;
import java.util.ArrayList;
@@ -41,9 +41,9 @@ public class GraphFrame extends JFrame {
private static final int SPACE_HORIZONTAL = 10;
private static final int BLOCK_WIDTH = 200;
private static final int BLOCK_HEIGHT = 20;
private Graph graph;
private AVM2Graph graph;
public GraphPanel(Graph graph) {
public GraphPanel(AVM2Graph graph) {
this.graph = graph;
setPreferredSize(new Dimension((BLOCK_WIDTH + SPACE_HORIZONTAL) * getPartWidth(graph.heads.get(0), new HashSet<GraphPart>()), (BLOCK_HEIGHT + SPACE_VERTICAL) * getPartHeight(graph.heads.get(0), new ArrayList<GraphPart>())));
}
@@ -121,7 +121,7 @@ public class GraphFrame extends JFrame {
}
}
public GraphFrame(Graph graph, String name) {
public GraphFrame(AVM2Graph graph, String name) {
setSize(500, 500);
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());

View File

@@ -16,8 +16,8 @@
*/
package com.jpexs.asdec.abc.gui;
import com.jpexs.asdec.abc.avm2.flowgraph.Graph;
import com.jpexs.asdec.abc.avm2.flowgraph.GraphPart;
import com.jpexs.asdec.abc.avm2.graph.AVM2Graph;
import com.jpexs.asdec.graph.GraphPart;
import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JFrame;
@@ -34,7 +34,7 @@ public class GraphTreeFrame extends JFrame {
public JTree graphTree;
public GraphTreeFrame(final Graph graph) {
public GraphTreeFrame(final AVM2Graph graph) {
setSize(400, 400);
graphTree = new JTree(new TreeModel() {
public Object getRoot() {

View File

@@ -17,7 +17,7 @@
package com.jpexs.asdec.abc.types.traits;
import com.jpexs.asdec.abc.ABC;
import com.jpexs.asdec.abc.avm2.flowgraph.Graph;
import com.jpexs.asdec.abc.avm2.graph.AVM2Graph;
import com.jpexs.asdec.abc.avm2.treemodel.TreeItem;
import com.jpexs.asdec.abc.types.MethodBody;
import com.jpexs.asdec.helpers.Helper;

View File

@@ -0,0 +1,170 @@
package com.jpexs.asdec.graph;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
public abstract class Graph {
public List<GraphPart> heads;
protected static void populateParts(GraphPart part, List<GraphPart> allParts) {
if (allParts.contains(part)) {
return;
}
allParts.add(part);
for (GraphPart p : part.nextParts) {
populateParts(p, allParts);
}
}
protected void fixGraph(GraphPart part) {
while (fixGraphOnce(part, new ArrayList<GraphPart>(), false)) {
}
}
private boolean fixGraphOnce(GraphPart part, List<GraphPart> visited, boolean doChildren) {
if (visited.contains(part)) {
return false;
}
visited.add(part);
boolean fixed = false;
int i = 1;
String lastpref = null;
boolean modify = true;
int prvni = -1;
if (!doChildren) {
List<GraphPart> uniqueRefs = new ArrayList<GraphPart>();
for (GraphPart r : part.refs) {
if (!uniqueRefs.contains(r)) {
uniqueRefs.add(r);
}
}
loopi:
for (; i <= part.path.length(); i++) {
lastpref = null;
int pos = -1;
for (GraphPart r : uniqueRefs) {
pos++;
if (r.path.startsWith("e")) {
continue;
}
if (part.leadsTo(r, new ArrayList<GraphPart>())) {
//modify=false;
//continue;
}
prvni = pos;
if (i > r.path.length()) {
i--;
break loopi;
}
if (lastpref == null) {
lastpref = r.path.substring(0, i);
} else {
if (!r.path.startsWith(lastpref)) {
i--;
break loopi;
}
}
}
}
if (i > part.path.length()) {
i = part.path.length();
}
if (modify && ((uniqueRefs.size() > 1) && (prvni >= 0))) {
String newpath = uniqueRefs.get(prvni).path.substring(0, i);
if (!part.path.equals(newpath)) {
if (part.path.startsWith(newpath)) {
String origPath = part.path;
GraphPart p = part;
part.path = newpath;
while (p.nextParts.size() == 1) {
p = p.nextParts.get(0);
if (!p.path.equals(origPath)) {
break;
}
p.path = newpath;
}
fixGraphOnce(part, new ArrayList<GraphPart>(), true);
fixed = true;
}
}
}
} else {
if (!fixed) {
if (part.nextParts.size() == 1) {
if (!(part.path.startsWith("e") && (!part.nextParts.get(0).path.startsWith("e")))) {
if (part.nextParts.get(0).path.length() > part.path.length()) {
part.nextParts.get(0).path = part.path;
fixed = true;
}
}
}
if (part.nextParts.size() > 1) {
for (int j = 0; j < part.nextParts.size(); j++) {
GraphPart npart = part.nextParts.get(j);
if (npart.path.length() > part.path.length() + 1) {
npart.path = part.path + "" + j;
fixed = true;
}
}
}
}
}
for (GraphPart p : part.nextParts) {
fixGraphOnce(p, visited, doChildren);
}
return fixed;
}
protected void makeMulti(GraphPart part, List<GraphPart> visited) {
if (visited.contains(part)) {
return;
}
visited.add(part);
GraphPart p = part;
List<GraphPart> multiList = new ArrayList<GraphPart>();
multiList.add(p);
while ((p.nextParts.size() == 1) && (p.nextParts.get(0).refs.size() == 1)) {
p = p.nextParts.get(0);
multiList.add(p);
}
if (multiList.size() > 1) {
GraphPartMulti gpm = new GraphPartMulti(multiList);
gpm.refs = part.refs;
GraphPart lastPart = multiList.get(multiList.size() - 1);
gpm.nextParts = lastPart.nextParts;
for (GraphPart next : gpm.nextParts) {
int index = next.refs.indexOf(lastPart);
if (index == -1) {
continue;
}
next.refs.remove(lastPart);
next.refs.add(index, gpm);
}
for (GraphPart parent : part.refs) {
if (parent.start == -1) {
continue;
}
int index = parent.nextParts.indexOf(part);
if (index == -1) {
continue;
}
parent.nextParts.remove(part);
parent.nextParts.add(index, gpm);
}
}
for (int i = 0; i < part.nextParts.size(); i++) {
makeMulti(part.nextParts.get(i), visited);
}
}
}

View File

@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.asdec.abc.avm2.flowgraph;
package com.jpexs.asdec.graph;
import com.jpexs.asdec.abc.avm2.treemodel.ContinueTreeItem;
import java.util.ArrayList;
@@ -37,7 +37,7 @@ public class GraphPart {
public String path="";
public List<GraphPart> refs=new ArrayList<GraphPart>();
public boolean ignored=false;
public List<ContinueTreeItem> forContinues=new ArrayList<ContinueTreeItem>();
public List<Object> forContinues=new ArrayList<Object>();
private boolean leadsTo(GraphPart part,List<GraphPart> visited,List<GraphPart> ignored){
if(visited.contains(this)){

View File

@@ -1,4 +1,4 @@
package com.jpexs.asdec.abc.avm2.flowgraph;
package com.jpexs.asdec.graph;
import java.util.List;
@@ -8,7 +8,7 @@ import java.util.List;
*/
public class GraphPartMulti extends GraphPart {
List<GraphPart> parts;
public List<GraphPart> parts;
public GraphPartMulti(List<GraphPart> parts) {
super(parts.get(0).start, parts.get(parts.size() - 1).end);

View File

@@ -1,4 +1,4 @@
package com.jpexs.asdec.abc.avm2.flowgraph;
package com.jpexs.asdec.graph;
/**
*