OSDN Git Service

add control flow extractor
[stigmata/stigmata-plugins.git] / opcodes / src / main / java / jp / sourceforge / stigmata / birthmarks / ControlFlowGraph.java
1 package jp.sourceforge.stigmata.birthmarks;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.HashSet;\r
5 import java.util.List;\r
6 import java.util.Set;\r
7 \r
8 import org.objectweb.asm.tree.AbstractInsnNode;\r
9 import org.objectweb.asm.tree.JumpInsnNode;\r
10 import org.objectweb.asm.tree.LabelNode;\r
11 import org.objectweb.asm.tree.LookupSwitchInsnNode;\r
12 import org.objectweb.asm.tree.MethodNode;\r
13 import org.objectweb.asm.tree.TableSwitchInsnNode;\r
14 import org.objectweb.asm.tree.TryCatchBlockNode;\r
15 \r
16 public class ControlFlowGraph {\r
17     private String name;\r
18     private boolean includeException;\r
19     private MethodNode method;\r
20     private BasicBlock[] blocks;\r
21 \r
22     public ControlFlowGraph(String name, MethodNode node){\r
23         this(name, node, false);\r
24     }\r
25 \r
26     public ControlFlowGraph(String name, MethodNode node, boolean includeException){\r
27         this.includeException = includeException;\r
28         this.name = name;\r
29         this.method = node;\r
30         parse(method);\r
31     }\r
32 \r
33     public String getName(){\r
34         return name;\r
35     }\r
36 \r
37     public int getBasicBlockSize(){\r
38         return blocks.length;\r
39     }\r
40 \r
41     public boolean isIncludingExceptionFlow(){\r
42         return includeException;\r
43     }\r
44 \r
45     public void setIncludingExceptionFlow(boolean includeException){\r
46         boolean oldvalue = this.includeException;\r
47         this.includeException = includeException;\r
48         if(oldvalue != includeException){\r
49             parse(method);\r
50         }\r
51     }\r
52 \r
53     private void separateBasicBlock(MethodNode node){\r
54         Set<LabelNode> jumpedTarget = new HashSet<LabelNode>();\r
55         int size = node.instructions.size();\r
56 \r
57         for(int i = 0; i < size; i++){\r
58             AbstractInsnNode inst = node.instructions.get(i);\r
59             switch(inst.getType()){\r
60             case AbstractInsnNode.JUMP_INSN:\r
61                 jumpedTarget.add(((JumpInsnNode)inst).label);\r
62                 break;\r
63             case AbstractInsnNode.LOOKUPSWITCH_INSN:\r
64             {\r
65                 LookupSwitchInsnNode lookup = (LookupSwitchInsnNode)inst;\r
66                 jumpedTarget.add(lookup.dflt);\r
67                 for(Object label: lookup.labels){\r
68                     jumpedTarget.add((LabelNode)label);\r
69                 }\r
70             }\r
71             case AbstractInsnNode.TABLESWITCH_INSN:\r
72             {\r
73                 TableSwitchInsnNode lookup = (TableSwitchInsnNode)inst;\r
74                 jumpedTarget.add(lookup.dflt);\r
75                 for(Object label: lookup.labels){\r
76                     jumpedTarget.add((LabelNode)label);\r
77                 }\r
78             }\r
79             }\r
80         }\r
81         if(isIncludingExceptionFlow()){\r
82             for(Object object: node.tryCatchBlocks){\r
83                 jumpedTarget.add(((TryCatchBlockNode)object).handler);\r
84             }\r
85         }\r
86 \r
87         List<BasicBlock> blockList = new ArrayList<BasicBlock>();\r
88         BasicBlock block = new BasicBlock();\r
89         for(int i = 0; i < size; i++){\r
90             AbstractInsnNode inst = node.instructions.get(i);\r
91             if(jumpedTarget.contains(inst)){\r
92                 blockList.add(block);\r
93                 block = new BasicBlock();\r
94             }\r
95 \r
96             block.addNode(inst);\r
97 \r
98             if(inst.getType() == AbstractInsnNode.JUMP_INSN\r
99                     || inst.getType() == AbstractInsnNode.TABLESWITCH_INSN\r
100                     || inst.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN){\r
101                 blockList.add(block);\r
102                 block = new BasicBlock();\r
103             }\r
104         }\r
105         this.blocks = blockList.toArray(new BasicBlock[blockList.size()]);\r
106     }\r
107 \r
108     /**\r
109      * \83R\83\93\83g\83\8d\81[\83\8b\83t\83\8d\81[\83O\83\89\83t\82ð\8dì\90¬\82·\82é\81D\r
110      */\r
111     private void parse(MethodNode node){\r
112         separateBasicBlock(node);\r
113     }\r
114 }\r