--- /dev/null
+package jp.sourceforge.stigmata.birthmarks;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.objectweb.asm.tree.AbstractInsnNode;\r
+import org.objectweb.asm.tree.JumpInsnNode;\r
+import org.objectweb.asm.tree.LabelNode;\r
+import org.objectweb.asm.tree.LookupSwitchInsnNode;\r
+import org.objectweb.asm.tree.MethodNode;\r
+import org.objectweb.asm.tree.TableSwitchInsnNode;\r
+import org.objectweb.asm.tree.TryCatchBlockNode;\r
+\r
+public class ControlFlowGraph {\r
+ private String name;\r
+ private boolean includeException;\r
+ private MethodNode method;\r
+ private BasicBlock[] blocks;\r
+\r
+ public ControlFlowGraph(String name, MethodNode node){\r
+ this(name, node, false);\r
+ }\r
+\r
+ public ControlFlowGraph(String name, MethodNode node, boolean includeException){\r
+ this.includeException = includeException;\r
+ this.name = name;\r
+ this.method = node;\r
+ parse(method);\r
+ }\r
+\r
+ public String getName(){\r
+ return name;\r
+ }\r
+\r
+ public int getBasicBlockSize(){\r
+ return blocks.length;\r
+ }\r
+\r
+ public boolean isIncludingExceptionFlow(){\r
+ return includeException;\r
+ }\r
+\r
+ public void setIncludingExceptionFlow(boolean includeException){\r
+ boolean oldvalue = this.includeException;\r
+ this.includeException = includeException;\r
+ if(oldvalue != includeException){\r
+ parse(method);\r
+ }\r
+ }\r
+\r
+ private void separateBasicBlock(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
+ break;\r
+ case AbstractInsnNode.LOOKUPSWITCH_INSN:\r
+ {\r
+ LookupSwitchInsnNode lookup = (LookupSwitchInsnNode)inst;\r
+ jumpedTarget.add(lookup.dflt);\r
+ for(Object label: lookup.labels){\r
+ jumpedTarget.add((LabelNode)label);\r
+ }\r
+ }\r
+ case AbstractInsnNode.TABLESWITCH_INSN:\r
+ {\r
+ TableSwitchInsnNode lookup = (TableSwitchInsnNode)inst;\r
+ jumpedTarget.add(lookup.dflt);\r
+ for(Object label: lookup.labels){\r
+ jumpedTarget.add((LabelNode)label);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if(isIncludingExceptionFlow()){\r
+ for(Object object: node.tryCatchBlocks){\r
+ jumpedTarget.add(((TryCatchBlockNode)object).handler);\r
+ }\r
+ }\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
+ if(jumpedTarget.contains(inst)){\r
+ blockList.add(block);\r
+ block = new BasicBlock();\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
+ }\r
+ }\r
+ this.blocks = blockList.toArray(new BasicBlock[blockList.size()]);\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
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.stigmata.birthmarks;
+
+/*
+ * $Id$
+ */
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ *
+ *
+ * @author tamada
+ * @version $Revision$
+ */
+public class ControlFlowGraphExtractVisitor extends ClassAdapter{
+ private Map<String, MethodNode> opcodesMap = new LinkedHashMap<String, MethodNode>();
+
+ public ControlFlowGraphExtractVisitor(ClassVisitor visitor){
+ super(visitor);
+ }
+
+ public Iterator<String> getMethodNames(){
+ return opcodesMap.keySet().iterator();
+ }
+
+ public ControlFlowGraph getGraph(String name){
+ return buildControlFlow(name, opcodesMap.get(name));
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions){
+ MethodNode node = new MethodNode(access, name, descriptor, signature, exceptions);
+
+ opcodesMap.put(name + descriptor, node);
+
+ return node;
+ }
+
+ private ControlFlowGraph buildControlFlow(String methodName, MethodNode node){
+ return new ControlFlowGraph(methodName, node);
+ }
+}
--- /dev/null
+package jp.sourceforge.stigmata.birthmarks;\r
+\r
+import java.util.Iterator;\r
+\r
+import junit.framework.Assert;\r
+\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.objectweb.asm.ClassReader;\r
+import org.objectweb.asm.ClassWriter;\r
+\r
+public class ControlFlowGraphTest {\r
+ private ControlFlowGraphExtractVisitor visitor;\r
+\r
+ @Before\r
+ public void setUp() throws Exception{\r
+ ClassReader reader = new ClassReader(getClass().getResource("/resources/MyServer.class").openStream());\r
+\r
+ visitor = new ControlFlowGraphExtractVisitor(new ClassWriter(0));\r
+ reader.accept(visitor, 0);\r
+ }\r
+\r
+ @Test\r
+ public void testBasic() throws Exception{\r
+ Iterator<String> iterator = visitor.getMethodNames();\r
+\r
+ Assert.assertTrue(iterator.hasNext());\r
+ Assert.assertEquals("<init>(I)V", iterator.next());\r
+ Assert.assertFalse(iterator.hasNext());\r
+\r
+ ControlFlowGraph graph = visitor.getGraph("<init>(I)V");\r
+\r
+ Assert.assertEquals(6, graph.getBasicBlockSize());\r
+\r
+ graph.setIncludingExceptionFlow(true);\r
+ Assert.assertEquals(7, graph.getBasicBlockSize());\r
+ }\r
+}\r