diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java b/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java index 5b7f60b77..f2f4bd943 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/Graph.java @@ -18,6 +18,10 @@ package com.jpexs.decompiler.flash.graph; import com.jpexs.decompiler.flash.abc.avm2.treemodel.CommentTreeItem; import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.graph.cfg.BBType; +import com.jpexs.decompiler.flash.graph.cfg.BasicBlock; +import com.jpexs.decompiler.flash.graph.cfg.CFG; +import com.jpexs.decompiler.flash.graph.cfg.StructType; import com.jpexs.decompiler.flash.helpers.Highlighting; import java.util.ArrayList; import java.util.HashMap; @@ -37,10 +41,17 @@ public class Graph { public List heads; protected GraphSource code; + public List headsCFG; public Graph(GraphSource code, List alternateEntries) { this.code = code; + headsCFG = new ArrayList<>(); heads = makeGraph(code, new ArrayList(), alternateEntries); + List blocks=new ArrayList<>(); + List headsbb = makeCFG(code, blocks, alternateEntries); + CFG cfg=new CFG(blocks, headsbb.get(0)); + cfg.structure(); + headsCFG.add(cfg); for (GraphPart head : heads) { fixGraph(head); makeMulti(head, new ArrayList()); @@ -399,16 +410,51 @@ public class Graph { Graph g = new Graph(code, alternateEntries); return g.translate(localData); } + + private List getLoopsFromCFG(){ + List ret=new ArrayList<>(); + List allParts=new ArrayList<>(); + for(GraphPart h:heads){ + populateParts(h, allParts); + } + for(CFG cfg:headsCFG){ + for(BasicBlock bb:cfg.m_listBB){ + if(bb.getStructType()== StructType.Loop + || bb.getStructType()== StructType.LoopCond){ + GraphPart loopContinue=null; + GraphPart loopBreak=null; + for(GraphPart p:allParts){ + if(p.start==bb.startAddress){ + loopContinue=p; + break; + } + } + if(bb.loopFollow!=null){ + for(GraphPart p:allParts){ + if(p.start==bb.loopFollow.startAddress){ + loopBreak=p; + break; + } + } + } + ret.add(new Loop(ret.size(),loopContinue,loopBreak)); + } + } + } + return ret; + } public List translate(List localData) { + try{ List allParts = new ArrayList<>(); for (GraphPart head : heads) { populateParts(head, allParts); } Stack stack = new Stack<>(); List loops = new ArrayList<>(); - /*getLoops(heads.get(0), loops, null); - System.out.println(""); + loops=getLoopsFromCFG(); + //getLoops(heads.get(0), loops, null); + /*System.out.println(""); for (Loop el : loops) { System.out.println(el); } @@ -419,11 +465,19 @@ public class Graph { 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); finalProcessAll(ret, 0); return ret; + } catch (StackOverflowError soe) { + List ret =new ArrayList<>(); + ret.add(new CommentTreeItem(null, "StackOverflowError")); + Logger.getLogger(Graph.class.getName()).log(Level.SEVERE, "error during printGraph", soe); + return ret; + } + } public void finalProcessStack(Stack stack, List output) { @@ -690,10 +744,8 @@ public class Graph { stopPart = new ArrayList<>(); } - //System.err.println("prec part:"+part); for (Loop el : loops) { if (el.phase != 1) { - //System.err.println("Ignored loop "+el); continue; } if (el.loopContinue == part) { @@ -1021,7 +1073,7 @@ public class Graph { if (ret == null) { ret = new ArrayList<>(); } - try { + //try { boolean debugMode = false; if (debugMode) { @@ -1058,10 +1110,6 @@ public class Graph { } - - //System.out.println("part:" + part); - - /* if ((parent != null) && (part.path.length() < parent.path.length())) { boolean can = true; for (Loop el : loops) { @@ -1418,25 +1466,7 @@ public class Graph { //Loop with condition at the beginning (While) 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; @@ -1531,11 +1561,11 @@ public class Graph { List commands = new ArrayList<>(); loopItem.commands.remove(loopItem.commands.size() - 1); if (!bodyBranch.isEmpty()) { - exprList.addAll(loopItem.commands); + /*exprList.addAll(loopItem.commands); commands.addAll(bodyBranch); exprList.add(expr); checkContinueAtTheEnd(commands, currentLoop); - ret.add(index, li = new WhileItem(null, currentLoop, exprList, commands)); + ret.add(index, li = new WhileItem(null, currentLoop, exprList, commands));*/ } else { commands.addAll(loopItem.commands); commands.addAll(bodyBranch); @@ -1548,7 +1578,7 @@ public class Graph { } } } - + if (!loopTypeFound) { if (currentLoop.loopPreContinue != null) { loopTypeFound = true; @@ -1615,11 +1645,7 @@ public class Graph { } return ret; - } catch (StackOverflowError soe) { - ret.add(new CommentTreeItem(null, "StackOverflowError")); - Logger.getLogger(Graph.class.getName()).log(Level.SEVERE, "error during printGraph", soe); - return ret; - } + } private List makeGraph(GraphSource code, List allBlocks, List alternateEntries) { @@ -1634,11 +1660,27 @@ public class Graph { } return ret; } + + private List makeCFG(GraphSource code, List allBlocks, List alternateEntries) { + HashMap> refs = code.visitCode(alternateEntries); + List ret = new ArrayList<>(); + boolean visited[] = new boolean[code.size()]; + ret.add(makeCFG(null, new GraphPath(), code, 0, 0, allBlocks, refs, visited)); + for (int pos : alternateEntries) { + BasicBlock e1 = new BasicBlock(); + e1.startAddress=-1; + e1.endAddress=-1; + //e1.path = new GraphPath("e"); + ret.add(makeCFG(e1, new GraphPath("e"), code, pos, pos, allBlocks, refs, visited)); + } + return ret; + } protected int checkIp(int ip) { return ip; } + private GraphPart makeGraph(GraphPart parent, GraphPath path, GraphSource code, int startip, int lastIp, List allBlocks, HashMap> refs, boolean visited2[]) { int ip = startip; @@ -1742,6 +1784,125 @@ public class Graph { } return ret; } + + private BasicBlock makeCFG(BasicBlock parent, GraphPath path, GraphSource code, int startip, int lastIp, List allBlocks, HashMap> refs, boolean visited2[]) { + + int ip = startip; + for (BasicBlock p : allBlocks) { + if (p.startAddress == ip) { + p.addInEdge(parent); + return p; + } + } + BasicBlock g; + BasicBlock ret = new BasicBlock(); + ret.startAddress=ip; + ret.endAddress=-1; + //ret.path = path; + BasicBlock part = ret; + while (ip < code.size()) { + if (visited2[ip] || ((ip != startip) && (refs.get(ip).size() > 1))) { + part.endAddress = lastIp; + BasicBlock found = null; + for (BasicBlock p : allBlocks) { + if (p.startAddress == ip) { + found = p; + break; + } + } + + allBlocks.add(part); + + if (found != null) { + part.addOutEdge(found); + found.addInEdge(part); + break; + } else { + BasicBlock gp = new BasicBlock(); + gp.startAddress=ip; + gp.endAddress=-1; + //gp.path = path; + part.addOutEdge(gp); + gp.addInEdge(part); + part = gp; + } + } + + ip = checkIp(ip); + lastIp = ip; + GraphSourceItem ins = code.get(ip); + if (ins.isIgnored()) { + ip++; + continue; + } + if (ins instanceof GraphSourceItemContainer) { + GraphSourceItemContainer cnt = (GraphSourceItemContainer) ins; + if (ins instanceof Action) { //TODO: Remove dependency of AVM1 + long endAddr = ((Action) ins).getAddress() + cnt.getHeaderSize(); + for (long size : cnt.getContainerSizes()) { + endAddr += size; + } + ip = code.adr2pos(endAddr); + } + continue; + } else if (ins.isExit()) { + part.endAddress = ip; + allBlocks.add(part); + part.setType(BBType.RET); + break; + } else if (ins.isJump()) { + part.endAddress = ip; + allBlocks.add(part); + part.setType(BBType.ONEWAY); + ip = ins.getBranches(code).get(0); + part.addOutEdge(g = makeCFG(part, path, code, ip, lastIp, allBlocks, refs, visited2)); + g.addInEdge(part); + + break; + } else if (ins.isBranch()) { + part.endAddress = ip; + + + allBlocks.add(part); + List branches = ins.getBranches(code); + if(branches.size()==2){ + part.setType(BBType.TWOWAY); + }else{ + part.setType(BBType.NWAY); + } + for (int i = 0; i < branches.size(); i++) { + part.addOutEdge(g = makeCFG(part, path.sub(i, ip), code, branches.get(i), ip, allBlocks, refs, visited2)); + g.addInEdge(part); + } + break; + } + ip++; + } + if ((part.endAddress == -1) && (ip >= code.size())) { + if (part.startAddress == code.size()) { + part.endAddress = code.size(); + allBlocks.add(part); + } else { + part.endAddress = ip - 1; + for (BasicBlock p : allBlocks) { + if (p.startAddress == ip) { + p.addInEdge(part); + part.addOutEdge(p); + allBlocks.add(part); + return ret; + } + } + BasicBlock gp = new BasicBlock(); + gp.startAddress=ip; + gp.endAddress=ip; + allBlocks.add(gp); + gp.addInEdge(part); + part.addOutEdge(gp); + allBlocks.add(part); + } + } + return ret; + } /** * String used to indent line when converting to string */ diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/BBType.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/BBType.java new file mode 100644 index 000000000..ba5626b74 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/BBType.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.graph.cfg; + +/** + * Adapted from Boomerang, basicblock.h Copyright (C) 1997-2000, The University + * of Queensland Copyright (C) 2000-2001, Sun Microsystems, Inc Copyright (C) + * 2002, Trent Waddington + */ +/** + * + * @author JPEXS + */ +public enum BBType { + + ONEWAY, // unconditional branch + TWOWAY, // conditional branch + NWAY, // case branch + CALL, // procedure call + RET, // return + FALL, // fall-through node + COMPJUMP, // computed jump + COMPCALL, // computed call + INVALID // invalid instruction +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/BasicBlock.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/BasicBlock.java new file mode 100644 index 000000000..c33f361aa --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/BasicBlock.java @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/** + * Adapted from Boomerang, basicblock.cpp + * Copyright (C) 1997-2000, The University of Queensland + * Copyright (C) 2000-2001, Sun Microsystems, Inc + * Copyright (C) 2002, Trent Waddington + */ +package com.jpexs.decompiler.flash.graph.cfg; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class BasicBlock { + + public int m_DFTfirst; // depth-first traversal first visit + public int m_DFTlast; // depth-first traversal last visit + public int m_DFTrevfirst; // reverse depth-first traversal first visit + public int m_DFTrevlast; // reverse depth-first traversal last visit + + /* high level structuring */ + public SBBType m_structType; // structured type of this node + public SBBType m_loopCondType; // type of conditional to treat this loop header as (if any) + public BasicBlock m_loopHead; // head of the most nested enclosing loop + public BasicBlock m_caseHead; // head of the most nested enclosing case + public BasicBlock m_condFollow; // follow of a conditional header + public BasicBlock m_loopFollow; // follow of a loop header + public BasicBlock m_latchNode; // latch node of a loop header + //protected: + /* general basic block information */ + public BBType m_nodeType; // type of basic block + //std::list* m_pRtls; // Ptr to list of RTLs + public int m_iLabelNum; // Nonzero if start of BB needs label + public String m_labelStr; // string label of this bb. + public boolean m_labelneeded; + public boolean m_bIncomplete; // True if not yet complete + public boolean m_bJumpReqd; // True if jump required for "fall through" + + /* in-edges and out-edges */ + public List m_InEdges = new ArrayList<>(); // Vector of in-edges + public List m_OutEdges = new ArrayList<>();// Vector of out-edges + public int m_iNumInEdges; // We need these two because GCC doesn't + public int m_iNumOutEdges; // support resize() of vectors! + + /* for traversal */ + public boolean m_iTraversed; // traversal marker + + /* Liveness */ + //LocationSet liveIn; // Set of locations live at BB start + //protected: + /* Control flow analysis stuff, lifted from Doug Simon's honours thesis. + */ + public int ord; // node's position within the ordering structure + public int revOrd; // position within ordering structure for the reverse graph + public int inEdgesVisited; // counts the number of in edges visited during a DFS + public int numForwardInEdges; // inedges to this node that aren't back edges + public int loopStamps[] = new int[2]; + public int revLoopStamps[] = new int[2]; // used for structuring analysis + public TravType traversed; // traversal flag for the numerous DFS's + public boolean hllLabel; // emit a label for this node when generating HL code? + public String labelStr; // the high level label for this node (if needed) + public int indentLevel; // the indentation level of this node in the final code + // analysis information + public BasicBlock immPDom; // immediate post dominator + public BasicBlock loopHead; // head of the most nested enclosing loop + public BasicBlock condFollow; // follow of a conditional header + public BasicBlock loopFollow; // follow of a loop header + public BasicBlock latchNode; // latching node of a loop header + // Structured type of the node + public StructType sType; // the structuring class (Loop, Cond , etc) + public UnStructType usType; // the restructured type of a conditional header + public LoopType lType; // the loop type of a loop header + public CondType cType; // the conditional type of a conditional header + // true if processing for overlapped registers on statements in this BB + // has been completed. + public int startAddress; + public int endAddress; + public static final int BTHEN = 0; + public static final int BELSE = 1; + + public BasicBlock() { + m_DFTfirst = 0; + m_DFTlast = 0; + m_structType = SBBType.NONE; + m_loopCondType = SBBType.NONE; + m_loopHead = null; + m_caseHead = null; + m_condFollow = null; + m_loopFollow = null; + m_latchNode = null; + m_nodeType = BBType.INVALID; + //m_pRtls=null; + m_iLabelNum = 0; + m_labelneeded = false; + m_bIncomplete = true; + m_bJumpReqd = false; + m_iNumInEdges = 0; + m_iNumOutEdges = 0; + m_iTraversed = false; + // From Doug's code + ord = -1; + revOrd = -1; + inEdgesVisited = 0; + numForwardInEdges = -1; + traversed = TravType.UNTRAVERSED; + hllLabel = false; + indentLevel = 0; + immPDom = null; + loopHead = null; + condFollow = null; + loopFollow = null; + latchNode = null; + sType = StructType.Seq; + usType = UnStructType.Structured; + // Others + } + + public BasicBlock(BasicBlock bb) { + m_DFTfirst = 0; + m_DFTlast = 0; + m_structType = bb.m_structType; + m_loopCondType = bb.m_loopCondType; + m_loopHead = bb.m_loopHead; + m_caseHead = bb.m_caseHead; + m_condFollow = bb.m_condFollow; + m_loopFollow = bb.m_loopFollow; + m_latchNode = bb.m_latchNode; + m_nodeType = bb.m_nodeType; + //m_pRtls=null; + m_iLabelNum = bb.m_iLabelNum; + m_labelneeded = false; + m_bIncomplete = bb.m_bIncomplete; + m_bJumpReqd = bb.m_bJumpReqd; + m_InEdges = bb.m_InEdges; + m_OutEdges = bb.m_OutEdges; + m_iNumInEdges = bb.m_iNumInEdges; + m_iNumOutEdges = bb.m_iNumOutEdges; + m_iTraversed = false; +// From Doug's code + ord = bb.ord; + revOrd = bb.revOrd; + inEdgesVisited = bb.inEdgesVisited; + numForwardInEdges = bb.numForwardInEdges; + traversed = (bb.traversed); + hllLabel = (bb.hllLabel); + indentLevel = (bb.indentLevel); + immPDom = (bb.immPDom); + loopHead = (bb.loopHead); + condFollow = (bb.condFollow); + loopFollow = (bb.loopFollow); + latchNode = (bb.latchNode); + sType = (bb.sType); + usType = (bb.usType); + + //setRTLs(bb.m_pRtls); + } + + public int getLabel() { + return m_iLabelNum; + } + + public boolean isTraversed() { + return m_iTraversed; + } + + public void setTraversed(boolean bTraversed) { + m_iTraversed = bTraversed; + } + + public BBType getType() { + return m_nodeType; + } + + public void updateType(BBType bbType, int iNumOutEdges) { + m_nodeType = bbType; + m_iNumOutEdges = iNumOutEdges; + } + + public void setJumpReqd() { + m_bJumpReqd = true; + } + + public boolean isJumpReqd() { + return m_bJumpReqd; + } + + public boolean isBackEdge(int inEdge) { + BasicBlock in = m_InEdges.get(inEdge); + return this == in || (m_DFTfirst < in.m_DFTfirst && m_DFTlast > in.m_DFTlast); + } + + public List getInEdges() { + return m_InEdges; + } + + public List getOutEdges() { + return m_OutEdges; + } + + public void setInEdge(int i, BasicBlock pNewInEdge) { + m_InEdges.set(i, pNewInEdge); + } + + public void setOutEdge(int i, BasicBlock pNewOutEdge) { + if (m_OutEdges.isEmpty()) { + assert (i == 0); + m_OutEdges.add(pNewOutEdge); + } else { + assert (i < (int) m_OutEdges.size()); + m_OutEdges.set(i, pNewOutEdge); + } + } + + public BasicBlock getOutEdge(int i) { + if (i < m_OutEdges.size()) { + return m_OutEdges.get(i); + } else { + return null; + } + } + + public int getLowAddr() { + return startAddress; + } + + public int getHiAddr() { + return endAddress; + } + + BasicBlock getCorrectOutEdge(int a) { + for (BasicBlock b : m_OutEdges) { + if (b.getLowAddr() == a) { + return b; + } + } + return null; + } + + public void addInEdge(BasicBlock pNewInEdge) { + m_InEdges.add(pNewInEdge); + m_iNumInEdges++; + } + + public void addOutEdge(BasicBlock pNewOutEdge) { + m_OutEdges.add(pNewOutEdge); + m_iNumOutEdges++; + } + + public void deleteInEdge(List blocks) { + m_InEdges.removeAll(blocks); + m_iNumInEdges--; + } + + public void deleteInEdge(BasicBlock edge) { + if (m_InEdges.contains(edge)) { + m_InEdges.remove(edge); + m_iNumInEdges--; + } + } + + public void deleteEdge(BasicBlock edge) { + edge.deleteInEdge(this); + if (m_OutEdges.contains(edge)) { + m_OutEdges.remove(edge); + m_iNumOutEdges--; + } + } + + public int DFTOrder(RefInt first, RefInt last) { + first.value++; + m_DFTfirst = first.value; + + int numTraversed = 1; + m_iTraversed = true; + + for (BasicBlock child : m_OutEdges) { + if (child.m_iTraversed == false) { + numTraversed = numTraversed + child.DFTOrder(first, last); + } + } + + last.value++; + m_DFTlast = last.value; + + return numTraversed; + } + + public int RevDFTOrder(RefInt first, RefInt last) { + first.value++; + m_DFTrevfirst = first.value; + + int numTraversed = 1; + m_iTraversed = true; + + for (BasicBlock parent : m_InEdges) { + if (parent.m_iTraversed == false) { + numTraversed = numTraversed + parent.RevDFTOrder(first, last); + } + } + + last.value++; + m_DFTrevlast = last.value; + + return numTraversed; + } + + public boolean lessAddress(BasicBlock bb1, BasicBlock bb2) { + return bb1.getLowAddr() < bb2.getLowAddr(); + } + + public boolean lessFirstDFT(BasicBlock bb1, BasicBlock bb2) { + return bb1.m_DFTfirst < bb2.m_DFTfirst; + } + + public boolean lessLastDFT(BasicBlock bb1, BasicBlock bb2) { + return bb1.m_DFTlast < bb2.m_DFTlast; + } + //getCallDest() + //getCallDestProc() + + BasicBlock getLoopBody() { + assert (m_structType == SBBType.PRETESTLOOP || m_structType == SBBType.POSTTESTLOOP || m_structType == SBBType.ENDLESSLOOP); + assert (m_iNumOutEdges == 2); + if (m_OutEdges.get(0) != m_loopFollow) { + return m_OutEdges.get(0); + } + return m_OutEdges.get(1); + } + + public boolean isAncestorOf(BasicBlock other) { + return ((loopStamps[0] < other.loopStamps[0] + && loopStamps[1] > other.loopStamps[1]) + || (revLoopStamps[0] < other.revLoopStamps[0] + && revLoopStamps[1] > other.revLoopStamps[1])); + } + + public boolean hasBackEdgeTo(BasicBlock dest) { +// assert(HasEdgeTo(dest) || dest == this); + return dest == this || dest.isAncestorOf(this); + } + + // had its code generated + public boolean allParentsGenerated() { + for (int i = 0; i < m_InEdges.size(); i++) { + if (!m_InEdges.get(i).hasBackEdgeTo(this) + && m_InEdges.get(i).traversed != TravType.DFS_CODEGEN) { + return false; + } + } + return true; + } + //emitGotoAndLabel + + public void setLoopStamps(RefInt time, List order) { + // timestamp the current node with the current time and set its traversed + // flag + traversed = TravType.DFS_LNUM; + loopStamps[0] = time.value; + + // recurse on unvisited children and set inedges for all children + for (int i = 0; i < m_OutEdges.size(); i++) { + // set the in edge from this child to its parent (the current node) + // (not done here, might be a problem) + // outEdges[i].inEdges.Add(this); + + // recurse on this child if it hasn't already been visited + if (m_OutEdges.get(i).traversed != TravType.DFS_LNUM) { + time.value++; + m_OutEdges.get(i).setLoopStamps(time, order); + } + } + + // set the the second loopStamp value + time.value++; + loopStamps[1] = time.value; + + // add this node to the ordering structure as well as recording its position within the ordering + ord = order.size(); + order.add(this); + } + + public void setRevLoopStamps(RefInt time) { + // timestamp the current node with the current time and set its traversed flag + traversed = TravType.DFS_RNUM; + revLoopStamps[0] = time.value; + + // recurse on the unvisited children in reverse order + for (int i = m_OutEdges.size() - 1; i >= 0; i--) { + // recurse on this child if it hasn't already been visited + if (m_OutEdges.get(i).traversed != TravType.DFS_RNUM) { + time.value++; + m_OutEdges.get(i).setRevLoopStamps(time); + } + } + + // set the the second loopStamp value + time.value++; + revLoopStamps[1] = time.value; + } + + public void setRevOrder(List order) { + // Set this node as having been traversed during the post domimator DFS ordering traversal + traversed = TravType.DFS_PDOM; + + // recurse on unvisited children + for (int i = 0; i < m_InEdges.size(); i++) { + if (m_InEdges.get(i).traversed != TravType.DFS_PDOM) { + m_InEdges.get(i).setRevOrder(order); + } + } + + // add this node to the ordering structure and record the post dom. order of this node as its index within this + // ordering structure + revOrd = order.size(); + order.add(this); + } + + //setCaseHead + public void setStructType(StructType s) { + // if this is a conditional header, determine exactly which type of conditional header it is (i.e. switch, if-then, + // if-then-else etc.) + if (s == StructType.Cond) { + if (getType() == BBType.NWAY) { + cType = CondType.Case; + } else if (m_OutEdges.get(BELSE) == condFollow) { + cType = CondType.IfThen; + } else if (m_OutEdges.get(BTHEN) == condFollow) { + cType = CondType.IfElse; + } else { + cType = CondType.IfThenElse; + } + } + + sType = s; + } + + public void setUnstructType(UnStructType us) { + assert ((sType == StructType.Cond || sType == StructType.LoopCond) && cType != CondType.Case); + usType = us; + } + + public UnStructType getUnstructType() { + assert ((sType == StructType.Cond || sType == StructType.LoopCond) && cType != CondType.Case); + return usType; + } + + public void setLoopType(LoopType l) { + assert (sType == StructType.Loop || sType == StructType.LoopCond); + lType = l; + + // set the structured class (back to) just Loop if the loop type is PreTested OR it's PostTested and is a single + // block loop + if (lType == LoopType.PreTested || (lType == LoopType.PostTested && this == latchNode)) { + sType = StructType.Loop; + } + } + + public LoopType getLoopType() { + assert (sType == StructType.Loop || sType == StructType.LoopCond); + return lType; + } + + public void setCondType(CondType c) { + assert (sType == StructType.Cond || sType == StructType.LoopCond); + cType = c; + } + + public CondType getCondType() { + assert (sType == StructType.Cond || sType == StructType.LoopCond); + return cType; + } + + public boolean inLoop(BasicBlock header, BasicBlock latch) { + assert (header.latchNode == latch); + assert (header == latch + || ((header.loopStamps[0] > latch.loopStamps[0] && latch.loopStamps[1] > header.loopStamps[1]) + || (header.loopStamps[0] < latch.loopStamps[0] && latch.loopStamps[1] < header.loopStamps[1]))); + // this node is in the loop if it is the latch node OR + // this node is within the header and the latch is within this when using the forward loop stamps OR + // this node is within the header and the latch is within this when using the reverse loop stamps + return this == latch + || (header.loopStamps[0] < loopStamps[0] && loopStamps[1] < header.loopStamps[1] + && loopStamps[0] < latch.loopStamps[0] && latch.loopStamps[1] < loopStamps[1]) + || (header.revLoopStamps[0] < revLoopStamps[0] && revLoopStamps[1] < header.revLoopStamps[1] + && revLoopStamps[0] < latch.revLoopStamps[0] && latch.revLoopStamps[1] < revLoopStamps[1]); + } + +//////////////////////////////////////////////////// +// Basically the "whichPred" function as per Briggs, Cooper, et al (and presumably "Cryton, Ferante, Rosen, Wegman, and +// Zadek"). Return -1 if not found + public int whichPred(BasicBlock pred) { + int n = m_InEdges.size(); + for (int i = 0; i < n; i++) { + if (m_InEdges.get(i) == pred) { + return i; + } + } + assert false; + return -1; + } + + public boolean hasBackEdge() { + for (int i = 0; i < m_OutEdges.size(); i++) { + if (hasBackEdgeTo(m_OutEdges.get(i))) { + return true; + } + } + return false; + } + + public void setCondFollow(BasicBlock other) { + condFollow = other; + } + + public BasicBlock getCondFollow() { + return condFollow; + } + + public void setLoopHead(BasicBlock head) { + loopHead = head; + } + + public BasicBlock getLoopHead() { + return loopHead; + } + + public void setLatchNode(BasicBlock latch) { + latchNode = latch; + } + + public boolean isLatchNode() { + return loopHead != null && loopHead.latchNode == this; + } + + public BasicBlock getLatchNode() { + return latchNode; + } + + public StructType getStructType() { + return sType; + } + + public void setLoopFollow(BasicBlock other) { + loopFollow = other; + } + + public BasicBlock getLoopFollow() { + return loopFollow; + } + + public void setType(BBType type) { + this.m_nodeType = type; + } + + @Override + public String toString() { + return (startAddress + 1) + "-" + (endAddress + 1); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/CFG.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/CFG.java new file mode 100644 index 000000000..155c08ec0 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/CFG.java @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/** + * Adapted from Boomerang, cfg.cpp + * Copyright (C) 1997-2000, The University of Queensland + * Copyright (C) 2000-2001, Sun Microsystems, Inc + * Copyright (C) 2002, Trent Waddington + */ +package com.jpexs.decompiler.flash.graph.cfg; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class CFG { + /* + * The list of pointers to BBs. + */ + + public List m_listBB; + + /* + * Ordering of BBs for control flow structuring + */ + public List Ordering = new ArrayList<>(); + public List revOrdering = new ArrayList<>(); + + /* + * The ADDRESS to BasicBlock map. + */ + //MABasicBlock m_maBasicBlock; + + /* + * The entry and exit BBs. + */ + public BasicBlock entryBB; + public BasicBlock exitBB; + + /* + * True if well formed. + */ + public boolean m_bWellFormed, structured; + /* + * Last label (positive integer) used by any BB this Cfg + */ + public int lastLabel; + + public void setTimeStamps() { + // set DFS tag + for (BasicBlock it : m_listBB) { + it.traversed = TravType.DFS_TAG; + } + + // set the parenthesis for the nodes as well as setting the post-order ordering between the nodes + RefInt time = new RefInt(); + time.value = 1; + Ordering.clear(); + entryBB.setLoopStamps(time, Ordering); + + // set the reverse parenthesis for the nodes + time.value = 1; + entryBB.setRevLoopStamps(time); + + BasicBlock retNode = findRetNode(); + assert (retNode != null); + revOrdering.clear(); + retNode.setRevOrder(revOrdering); + } + + public void getReachableBlocks(BasicBlock b, List ret) { + if (ret.contains(b)) { + return; + } + ret.add(b); + for (BasicBlock next : b.m_OutEdges) { + getReachableBlocks(next, ret); + } + } + + public BasicBlock getCommonBlock(List parts, List visited) { + if (parts.isEmpty()) { + return null; + } + + List> reachable = new ArrayList<>(); + for (BasicBlock p : parts) { + List r1 = new ArrayList<>(); + getReachableBlocks(p, r1); + r1.add(p); + reachable.add(r1); + } + List first = reachable.get(0); + for (BasicBlock 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; + } + + BasicBlock findRetNode() { + BasicBlock retNode = null; + for (BasicBlock it : m_listBB) { + if (it.getType() == BBType.RET) { + retNode = it; + break; + } + } + return retNode; + } + + public void findImmedPDom() { + BasicBlock curNode, succNode; // the current Node and its successor + + // traverse the nodes in order (i.e from the bottom up) + int i; + for (i = revOrdering.size() - 1; i >= 0; i--) { + curNode = revOrdering.get(i); + List oEdges = curNode.getOutEdges(); + for (int j = 0; j < oEdges.size(); j++) { + succNode = oEdges.get(j); + if (succNode.revOrd > curNode.revOrd) { + curNode.immPDom = commonPDom(curNode.immPDom, succNode); + } + } + } + + // make a second pass but consider the original CFG ordering this time + int u; + for (u = 0; u < Ordering.size(); u++) { + curNode = Ordering.get(u); + List oEdges = curNode.getOutEdges(); + if (oEdges.size() > 1) { + for (int j = 0; j < oEdges.size(); j++) { + succNode = oEdges.get(j); + curNode.immPDom = commonPDom(curNode.immPDom, succNode); + } + } + } + + // one final pass to fix up nodes involved in a loop + for (u = 0; u < Ordering.size(); u++) { + curNode = Ordering.get(u); + List oEdges = curNode.getOutEdges(); + if (oEdges.size() > 1) { + for (int j = 0; j < oEdges.size(); j++) { + succNode = oEdges.get(j); + if (curNode.hasBackEdgeTo(succNode) && (curNode.getOutEdges().size() > 1) + && (succNode.immPDom != null) + && (succNode.immPDom.ord < curNode.immPDom.ord)) { + curNode.immPDom = commonPDom(succNode.immPDom, curNode.immPDom); + } else { + curNode.immPDom = commonPDom(curNode.immPDom, succNode); + } + } + } + } + } + + // Finds the common post dominator of the current immediate post dominator and its successor's immediate post dominator + public BasicBlock commonPDom(BasicBlock curImmPDom, BasicBlock succImmPDom) { + if (curImmPDom == null) { + return succImmPDom; + } + if (succImmPDom == null) { + return curImmPDom; + } + if (curImmPDom.revOrd == succImmPDom.revOrd) { + return curImmPDom; // ordering hasn't been done + } + BasicBlock oldCurImmPDom = curImmPDom; + BasicBlock oldSuccImmPDom = succImmPDom; + + int giveup = 0; + final int GIVEUP = 10000; + while (giveup < GIVEUP && (curImmPDom != null) && (succImmPDom != null) && (curImmPDom != succImmPDom)) { + if (curImmPDom.revOrd > succImmPDom.revOrd) { + succImmPDom = succImmPDom.immPDom; + } else { + curImmPDom = curImmPDom.immPDom; + } + giveup++; + } + + if (giveup >= GIVEUP) { + /*if (VERBOSE) + LOG << "failed to find commonPDom for " << oldCurImmPDom.getLowAddr() << " and " << + oldSuccImmPDom.getLowAddr() << "\n";*/ + return oldCurImmPDom; // no change + } + + return curImmPDom; + } + + // Structures all conditional headers (i.e. nodes with more than one outedge) + public void structConds() { + // Process the nodes in order + for (int i = 0; i < Ordering.size(); i++) { + BasicBlock curNode = Ordering.get(i); + + // does the current node have more than one out edge? + if (curNode.getOutEdges().size() > 1) { + // if the current conditional header is a two way node and has a back edge, then it won't have a follow + if (curNode.hasBackEdge() && curNode.getType() == BBType.TWOWAY) { + curNode.setStructType(StructType.Cond); + continue; + } + + // set the follow of a node to be its immediate post dominator + curNode.setCondFollow(curNode.immPDom); + + // set the structured type of this node + curNode.setStructType(StructType.Cond); + + // if this is an nway header, then we have to tag each of the nodes within the body of the nway subgraph + //if (curNode.getCondType() == CondType.Case) + //curNode.setCaseHead(curNode,curNode.getCondFollow()); + } + } + } + +// Pre: The graph for curProc has been built. +// Post: Each node is tagged with the header of the most nested loop of which it is a member (possibly none). +// The header of each loop stores information on the latching node as well as the type of loop it heads. + public void structLoops() { + for (int i = Ordering.size() - 1; i >= 0; i--) { + BasicBlock curNode = Ordering.get(i); // the current node under investigation + BasicBlock latch = null; // the latching node of the loop + + // If the current node has at least one back edge into it, it is a loop header. If there are numerous back edges + // into the header, determine which one comes form the proper latching node. + // The proper latching node is defined to have the following properties: + // i) has a back edge to the current node + // ii) has the same case head as the current node + // iii) has the same loop head as the current node + // iv) is not an nway node + // v) is not the latch node of an enclosing loop + // vi) has a lower ordering than all other suitable candiates + // If no nodes meet the above criteria, then the current node is not a loop header + List iEdges = curNode.getInEdges(); + for (int j = 0; j < iEdges.size(); j++) { + BasicBlock pred = iEdges.get(j); + if (/*pred.getCaseHead() == curNode.getCaseHead() && // ii)*//*pred.getLoopHead() == curNode.getLoopHead() &&*/ // iii) + ((latch == null) || latch.ord > pred.ord) && // vi) + !((pred.getLoopHead() != null) + && pred.getLoopHead().getLatchNode() == pred) && // v) + pred.hasBackEdgeTo(curNode)) // i) + { + latch = pred; + } + } + + // if a latching node was found for the current node then it is a loop header. + if (latch != null) { + // define the map that maps each node to whether or not it is within the current loop + boolean loopNodes[] = new boolean[Ordering.size()]; + for (int j = 0; j < Ordering.size(); j++) { + loopNodes[j] = false; + } + + curNode.setLatchNode(latch); + + // the latching node may already have been structured as a conditional header. If it is not also the loop + // header (i.e. the loop is over more than one block) then reset it to be a sequential node otherwise it + // will be correctly set as a loop header only later + if (latch != curNode && latch.getStructType() == StructType.Cond) { + latch.setStructType(StructType.Seq); + } + + // set the structured type of this node + curNode.setStructType(StructType.Loop); + + // tag the members of this loop + tagNodesInLoop(curNode, loopNodes); + + // calculate the type of this loop + determineLoopType(curNode, loopNodes); + + // calculate the follow node of this loop + findLoopFollow(curNode, loopNodes); + + // delete the space taken by the loopnodes map + //delete[] loopNodes; + } + } + } + +// Pre: The loop induced by (head,latch) has already had all its member nodes tagged +// Post: The type of loop has been deduced + public void determineLoopType(BasicBlock header, boolean loopNodes[]) { + assert (header.getLatchNode() != null); + + // if the latch node is a two way node then this must be a post tested loop + if (header.getLatchNode().getType() == BBType.TWOWAY) { + header.setLoopType(LoopType.PostTested); + + // if the head of the loop is a two way node and the loop spans more than one block then it must also be a + // conditional header + if (header.getType() == BBType.TWOWAY && header != header.getLatchNode()) { + header.setStructType(StructType.LoopCond); + } + } // otherwise it is either a pretested or endless loop + else if (header.getType() == BBType.TWOWAY) { + // if the header is a two way node then it must have a conditional follow (since it can't have any backedges + // leading from it). If this follow is within the loop then this must be an endless loop + if ((header.getCondFollow() != null) && loopNodes[header.getCondFollow().ord]) { + header.setLoopType(LoopType.Endless); + + // retain the fact that this is also a conditional header + header.setStructType(StructType.LoopCond); + } else { + header.setLoopType(LoopType.PreTested); + } + } // both the header and latch node are one way nodes so this must be an endless loop + else { + header.setLoopType(LoopType.Endless); + } + } + +// Pre: The loop headed by header has been induced and all it's member nodes have been tagged +// Post: The follow of the loop has been determined. + void findLoopFollow(BasicBlock header, boolean loopNodes[]) { + assert (header.getStructType() == StructType.Loop || header.getStructType() == StructType.LoopCond); + LoopType lType = header.getLoopType(); + BasicBlock latch = header.getLatchNode(); + + if (lType == LoopType.PreTested) { + // if the 'while' loop's true child is within the loop, then its false child is the loop follow + if (loopNodes[header.getOutEdges().get(0).ord]) { + header.setLoopFollow(header.getOutEdges().get(1)); + } else { + header.setLoopFollow(header.getOutEdges().get(0)); + } + } else if (lType == LoopType.PostTested) { + // the follow of a post tested ('repeat') loop is the node on the end of the non-back edge from the latch node + if (latch.getOutEdges().get(0) == header) { + header.setLoopFollow(latch.getOutEdges().get(1)); + } else { + header.setLoopFollow(latch.getOutEdges().get(0)); + } + } else { + // endless loop + BasicBlock follow = null; + List follows = new ArrayList<>(); + + // traverse the ordering array between the header and latch nodes. + //BasicBlock latch = header.getLatchNode(); + for (int i = header.ord - 1; i > latch.ord; i--) { + BasicBlock desc = Ordering.get(i); + // the follow for an endless loop will have the following + // properties: + // i) it will have a parent that is a conditional header inside the loop whose follow is outside the + // loop + // ii) it will be outside the loop according to its loop stamp pair + // iii) have the highest ordering of all suitable follows (i.e. highest in the graph) + + if (desc.getStructType() == StructType.Cond && (desc.getCondFollow() != null) + && desc.getLoopHead() == header) { + if (loopNodes[desc.getCondFollow().ord]) { + // if the conditional's follow is in the same loop AND is lower in the loop, jump to this follow + if (desc.ord > desc.getCondFollow().ord) { + i = desc.getCondFollow().ord; + } // otherwise there is a backward jump somewhere to a node earlier in this loop. We don't need to any + // nodes below this one as they will all have a conditional within the loop. + else { + break; + } + } else { + // otherwise find the child (if any) of the conditional header that isn't inside the same loop + BasicBlock succ = desc.getOutEdges().get(0); + if (loopNodes[succ.ord]) { + if (!loopNodes[desc.getOutEdges().get(1).ord]) { + succ = desc.getOutEdges().get(1); + } else { + succ = null; + } + } + // if a potential follow was found, compare its ordering with the currently found follow + if (succ != null) { + follows.add(succ); + } + /*if ((succ != null) && ((follow == null) || succ.ord > follow.ord)) { + follow = succ; + }*/ + } + } + } + // if a follow was found, assign it to be the follow of the loop under + // investigation + follow = getCommonBlock(follows, new ArrayList()); + if (follow != null) { + header.setLoopFollow(follow); + } + } + } + + public void tagNodesInLoop(BasicBlock header, boolean loopNodes[]) { + assert (header.getLatchNode() != null); + + // traverse the ordering structure from the header to the latch node tagging the nodes determined to be within the + // loop. These are nodes that satisfy the following: + // i) header.loopStamps encloses curNode.loopStamps and curNode.loopStamps encloses latch.loopStamps + // OR + // ii) latch.revLoopStamps encloses curNode.revLoopStamps and curNode.revLoopStamps encloses header.revLoopStamps + // OR + // iii) curNode is the latch node + + BasicBlock latch = header.getLatchNode(); + for (int i = header.ord - 1; i >= latch.ord; i--) { + if (Ordering.get(i).inLoop(header, latch)) { + // update the membership map to reflect that this node is within the loop + loopNodes[i] = true; + + Ordering.get(i).setLoopHead(header); + } + } + } + + public void structure() { + setTimeStamps(); + findImmedPDom(); + structConds(); + structLoops(); + } + + public CFG(List blocks, BasicBlock entry) { + this.m_listBB = blocks; + this.entryBB = entry; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/CondType.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/CondType.java new file mode 100644 index 000000000..7d2caa5bf --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/CondType.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.graph.cfg; + +/** + * Adapted from Boomerang, basicblock.h + * Copyright (C) 1997-2000, The University of Queensland + * Copyright (C) 2000-2001, Sun Microsystems, Inc + * Copyright (C) 2002, Trent Waddington + */ +/** + * + * @author JPEXS + */ +public enum CondType { + + IfThen, // conditional with only a then clause + IfThenElse, // conditional with a then and an else clause + IfElse, // conditional with only an else clause + Case, // nway conditional header (case statement) +}; diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/LoopType.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/LoopType.java new file mode 100644 index 000000000..2b78f6d1a --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/LoopType.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.graph.cfg; + +/** + * Adapted from Boomerang, basicblock.h + * Copyright (C) 1997-2000, The University of Queensland + * Copyright (C) 2000-2001, Sun Microsystems, Inc + * Copyright (C) 2002, Trent Waddington + */ +/** + * + * @author JPEXS + */ +public enum LoopType { + + PreTested, // Header of a while loop + PostTested, // Header of a repeat loop + Endless // Header of an endless loop +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/RefInt.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/RefInt.java new file mode 100644 index 000000000..5d5076fcf --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/RefInt.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.graph.cfg; + +/** + * + * @author JPEXS + */ +public class RefInt { + + public int value; +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/SBBType.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/SBBType.java new file mode 100644 index 000000000..29d58875a --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/SBBType.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.graph.cfg; + +/** + * Adapted from Boomerang, basicblock.h + * Copyright (C) 1997-2000, The University of Queensland + * Copyright (C) 2000-2001, Sun Microsystems, Inc + * Copyright (C) 2002, Trent Waddington + */ +/** + * + * @author JPEXS + */ +public enum SBBType { + + NONE, // not structured + PRETESTLOOP, // header of a loop + POSTTESTLOOP, + ENDLESSLOOP, + JUMPINOUTLOOP, // an unstructured jump in or out of a loop + JUMPINTOCASE, // an unstructured jump into a case statement + IFGOTO, // unstructured conditional + IFTHEN, // conditional with then clause + IFTHENELSE, // conditional with then and else clauses + IFELSE, // conditional with else clause only + CASE // case statement (switch) +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/StructType.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/StructType.java new file mode 100644 index 000000000..2e96c76d0 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/StructType.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.graph.cfg; + +/** + * Adapted from Boomerang, basicblock.h + * Copyright (C) 1997-2000, The University of Queensland + * Copyright (C) 2000-2001, Sun Microsystems, Inc + * Copyright (C) 2002, Trent Waddington + */ +/** + * + * @author JPEXS + */ +public enum StructType { + + Loop, // Header of a loop only + Cond, // Header of a conditional only (if-then-else or switch) + LoopCond, // Header of a loop and a conditional + Seq // sequential statement (default) +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/TravType.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/TravType.java new file mode 100644 index 000000000..f3621ca3a --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/TravType.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.graph.cfg; + +/** + * Adapted from Boomerang, basicblock.h + * Copyright (C) 1997-2000, The University of Queensland + * Copyright (C) 2000-2001, Sun Microsystems, Inc + * Copyright (C) 2002, Trent Waddington + */ +/** + * + * @author JPEXS + */ +public enum TravType { + + UNTRAVERSED, // Initial value + DFS_TAG, // Remove redundant nodes pass + DFS_LNUM, // DFS loop stamping pass + DFS_RNUM, // DFS reverse loop stamping pass + DFS_CASE, // DFS case head tagging traversal + DFS_PDOM, // DFS post dominator ordering + DFS_CODEGEN // Code generating pass +} diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/cfg/UnStructType.java b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/UnStructType.java new file mode 100644 index 000000000..ea9dc4176 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/graph/cfg/UnStructType.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.graph.cfg; + +/** + * Adapted from Boomerang, basicblock.h + * Copyright (C) 1997-2000, The University of Queensland + * Copyright (C) 2000-2001, Sun Microsystems, Inc + * Copyright (C) 2002, Trent Waddington + */ +/** + * + * @author JPEXS + */ +public enum UnStructType { + + Structured, + JumpInOutLoop, + JumpIntoCase +}