OSDN Git Service

コントロールフローを抽出可能にした.
[stigmata/stigmata-plugins.git] / opcodes / src / main / java / jp / sourceforge / stigmata / birthmarks / ControlFlowGraph.java
index 9dddd84..4b382c4 100755 (executable)
@@ -2,9 +2,11 @@ package jp.sourceforge.stigmata.birthmarks;
 \r
 import java.util.ArrayList;\r
 import java.util.HashSet;\r
+import java.util.Iterator;\r
 import java.util.List;\r
 import java.util.Set;\r
 \r
+import org.objectweb.asm.Label;\r
 import org.objectweb.asm.tree.AbstractInsnNode;\r
 import org.objectweb.asm.tree.JumpInsnNode;\r
 import org.objectweb.asm.tree.LabelNode;\r
@@ -13,6 +15,8 @@ import org.objectweb.asm.tree.MethodNode;
 import org.objectweb.asm.tree.TableSwitchInsnNode;\r
 import org.objectweb.asm.tree.TryCatchBlockNode;\r
 \r
+import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes;\r
+\r
 public class ControlFlowGraph {\r
     private String name;\r
     private boolean includeException;\r
@@ -30,6 +34,25 @@ public class ControlFlowGraph {
         parse(method);\r
     }\r
 \r
+    public int[][] getGraphMatrix(){\r
+        int[][] matrix = new int[blocks.length][blocks.length];\r
+\r
+        for(int i = 0; i < blocks.length; i++){\r
+            for(int j = 0; j < blocks.length; j++){\r
+                int nextValue = 0;\r
+                for(Iterator<BasicBlock> iter = blocks[i].nextIterator(); iter.hasNext(); ){\r
+                    BasicBlock nextBlock = iter.next();\r
+                    if(nextBlock == blocks[j]){\r
+                        nextValue = 1;\r
+                        break;\r
+                    }\r
+                }\r
+                matrix[i][j] = nextValue;\r
+            }\r
+        }\r
+        return matrix;\r
+    }\r
+\r
     public String getName(){\r
         return name;\r
     }\r
@@ -50,16 +73,18 @@ public class ControlFlowGraph {
         }\r
     }\r
 \r
-    private void separateBasicBlock(MethodNode node){\r
+    private Set<LabelNode> collectLabels(MethodNode node){\r
         Set<LabelNode> jumpedTarget = new HashSet<LabelNode>();\r
         int size = node.instructions.size();\r
-\r
         for(int i = 0; i < size; i++){\r
             AbstractInsnNode inst = node.instructions.get(i);\r
             switch(inst.getType()){\r
             case AbstractInsnNode.JUMP_INSN:\r
-                jumpedTarget.add(((JumpInsnNode)inst).label);\r
+            {\r
+                JumpInsnNode jump = (JumpInsnNode)inst;\r
+                jumpedTarget.add(jump.label);\r
                 break;\r
+            }\r
             case AbstractInsnNode.LOOKUPSWITCH_INSN:\r
             {\r
                 LookupSwitchInsnNode lookup = (LookupSwitchInsnNode)inst;\r
@@ -67,6 +92,7 @@ public class ControlFlowGraph {
                 for(Object label: lookup.labels){\r
                     jumpedTarget.add((LabelNode)label);\r
                 }\r
+                break;\r
             }\r
             case AbstractInsnNode.TABLESWITCH_INSN:\r
             {\r
@@ -75,6 +101,7 @@ public class ControlFlowGraph {
                 for(Object label: lookup.labels){\r
                     jumpedTarget.add((LabelNode)label);\r
                 }\r
+                break;\r
             }\r
             }\r
         }\r
@@ -83,32 +110,63 @@ public class ControlFlowGraph {
                 jumpedTarget.add(((TryCatchBlockNode)object).handler);\r
             }\r
         }\r
+        return jumpedTarget;\r
+    }\r
+\r
+    private BasicBlock[] separateBasicBlock(MethodNode node, Set<LabelNode> jumpedTarget){\r
+        int size = node.instructions.size();\r
 \r
         List<BasicBlock> blockList = new ArrayList<BasicBlock>();\r
         BasicBlock block = new BasicBlock();\r
         for(int i = 0; i < size; i++){\r
             AbstractInsnNode inst = node.instructions.get(i);\r
+\r
             if(jumpedTarget.contains(inst)){\r
-                blockList.add(block);\r
-                block = new BasicBlock();\r
+                if(!block.isEmpty()){\r
+                    blockList.add(block);\r
+                    block = new BasicBlock();\r
+                }\r
             }\r
-\r
             block.addNode(inst);\r
-\r
             if(inst.getType() == AbstractInsnNode.JUMP_INSN\r
                     || inst.getType() == AbstractInsnNode.TABLESWITCH_INSN\r
                     || inst.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN){\r
-                blockList.add(block);\r
-                block = new BasicBlock();\r
+                if(!block.isEmpty()){\r
+                    blockList.add(block);\r
+                    BasicBlock block2 = new BasicBlock();\r
+                    if(inst.getOpcode() != Opcodes.GOTO && inst.getOpcode() != Opcodes.JSR){\r
+                        block2.setPrev(block);\r
+                    }\r
+                    block = block2;\r
+                }\r
             }\r
         }\r
-        this.blocks = blockList.toArray(new BasicBlock[blockList.size()]);\r
+        blockList.add(block);\r
+        return blockList.toArray(new BasicBlock[blockList.size()]);\r
+    }\r
+\r
+    private BasicBlock[] joinBasicBlocks(BasicBlock[] blocks){\r
+        for(int i = 0; i < blocks.length; i++){\r
+            Label[] labels = blocks[i].getTargets();\r
+            for(int j = 0; j < labels.length; j++){\r
+                for(int k = 0; k < blocks.length; k++){\r
+                    if(i != k && blocks[k].hasLabel(labels[j])){\r
+                        blocks[i].setNext(blocks[k]);\r
+                        break;\r
+                    }\r
+                }\r
+            }\r
+            if(labels.length == 0 && (i + 1) < blocks.length){\r
+                blocks[i].setNext(blocks[i + 1]);\r
+            }\r
+        }\r
+\r
+        return blocks;\r
     }\r
 \r
-    /**\r
-     * \83R\83\93\83g\83\8d\81[\83\8b\83t\83\8d\81[\83O\83\89\83t\82ð\8dì\90¬\82·\82é\81D\r
-     */\r
     private void parse(MethodNode node){\r
-        separateBasicBlock(node);\r
+        Set<LabelNode> jumpedTarget = collectLabels(node);\r
+        BasicBlock[] blocks = separateBasicBlock(node, jumpedTarget);\r
+        this.blocks = joinBasicBlocks(blocks);\r
     }\r
 }\r