public class DetectDuplicatedCodeClassVisitor extends org.objectweb.asm.ClassVisitor
173: public void methodWithFinishBlock(FinishReturnTypeEnum f){ 174: try { 175: switch (f) { 176: case BY_RETURN: 177: System.out.println("will return"); 178: return; 179: case BY_THROW: 180: System.out.println("will throw"); 181: throw new IllegalStateException("Expected exception"); 182: default: 183: System.out.println("default"); 184: } 185: } finally { 186: if (f != null) { //This piece of code is generated in ASM 3 times. We should merge it into one block 187: System.out.println("Finish with: f="+f); 188: } 189: } 190}effects in generation such a JVM code:
// access flags 1 public methodWithFinishBlock(Ltest/performance/Test1$FinishReturnTypeEnum;)V TRYCATCHBLOCK L0 L1 L2 TRYCATCHBLOCK L3 L2 L2 L0 LINENUMBER 175 L0 INVOKESTATIC test/performance/Test1.$SWITCH_TABLE$test$performance$Test1$FinishReturnTypeEnum()[I ALOAD 1 INVOKEVIRTUAL test/performance/Test1$FinishReturnTypeEnum.ordinal()I IALOAD TABLESWITCH 1: L4 2: L3 default: L5 L4 LINENUMBER 177 L4 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "will return" INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V L1 LINENUMBER 186 L1 ALOAD 1 IFNULL L6 L7 LINENUMBER 187 L7 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; NEW java/lang/StringBuilder DUP LDC "Finish with: f=" INVOKESPECIAL java/lang/StringBuilder.(Ljava/lang/String;)V ALOAD 1 INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V L6 LINENUMBER 178 L6 RETURN L3 LINENUMBER 180 L3 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "will throw" INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V L8 LINENUMBER 181 L8 NEW java/lang/IllegalStateException DUP LDC "Expected exception" INVOKESPECIAL java/lang/IllegalStateException. (Ljava/lang/String;)V ATHROW L5 LINENUMBER 183 L5 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "default" INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V GOTO L9 L2 LINENUMBER 185 L2 ASTORE 2 L10 LINENUMBER 186 L10 ALOAD 1 IFNULL L11 L12 LINENUMBER 187 L12 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; NEW java/lang/StringBuilder DUP LDC "Finish with: f=" INVOKESPECIAL java/lang/StringBuilder. (Ljava/lang/String;)V ALOAD 1 INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V L11 LINENUMBER 189 L11 ALOAD 2 ATHROW L9 LINENUMBER 186 L9 ALOAD 1 IFNULL L13 L14 LINENUMBER 187 L14 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; NEW java/lang/StringBuilder DUP LDC "Finish with: f=" INVOKESPECIAL java/lang/StringBuilder. (Ljava/lang/String;)V ALOAD 1 INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V L13 LINENUMBER 190 L13 RETURN L15 LOCALVARIABLE this Ltest/performance/Test1; L0 L15 0 LOCALVARIABLE f Ltest/performance/Test1$FinishReturnTypeEnum; L0 L15 1 MAXSTACK = 4 MAXLOCALS = 3
Note that 'LINENUMBER 186' instruction occurs many times and code after that instruction is nearly identical
(see CodeFootstamp
criteria of 'identity').
On the other hand duplicated 'LINENUMBER 186' instruction could happened for for example for 'for' loop. In this case the code after this instruction is different.
The goal of this class is to provide duplicatedLinesCollector
that is map of:
(line number -> (duplicated lineId -> origin lineId)).
Modifier and Type | Field and Description |
---|---|
private java.lang.String |
className
Name (internal asm) of currently processed class
|
private java.util.Map<java.lang.Integer,java.util.Map<java.lang.Integer,java.lang.Integer>> |
duplicatedLinesCollector
map of (line number -> (duplicated lineId -> origin lineId))
|
private java.util.concurrent.atomic.AtomicInteger |
lineIdGenerator
Every LINENUMBER instruction will have generated it's lineId.
|
Constructor and Description |
---|
DetectDuplicatedCodeClassVisitor(org.objectweb.asm.ClassVisitor cv) |
Modifier and Type | Method and Description |
---|---|
java.util.Map<java.lang.Integer,java.util.Map<java.lang.Integer,java.lang.Integer>> |
getDuplicatesLinesCollector()
Returns map of (line number -> (duplicated lineId -> origin lineId))
|
void |
visit(int version,
int access,
java.lang.String name,
java.lang.String signature,
java.lang.String superName,
java.lang.String[] interfaces) |
org.objectweb.asm.MethodVisitor |
visitMethod(int access,
java.lang.String methodName,
java.lang.String description,
java.lang.String signature,
java.lang.String[] exceptions) |
private java.util.Map<java.lang.Integer,java.util.Map<java.lang.Integer,java.lang.Integer>> duplicatedLinesCollector
private java.lang.String className
private final java.util.concurrent.atomic.AtomicInteger lineIdGenerator
AbstractFindTouchPointsClassInstrumenter.lineIdGenerator
)public DetectDuplicatedCodeClassVisitor(org.objectweb.asm.ClassVisitor cv)
public void visit(int version, int access, java.lang.String name, java.lang.String signature, java.lang.String superName, java.lang.String[] interfaces)
visit
in class org.objectweb.asm.ClassVisitor
public org.objectweb.asm.MethodVisitor visitMethod(int access, java.lang.String methodName, java.lang.String description, java.lang.String signature, java.lang.String[] exceptions)
visitMethod
in class org.objectweb.asm.ClassVisitor
public java.util.Map<java.lang.Integer,java.util.Map<java.lang.Integer,java.lang.Integer>> getDuplicatesLinesCollector()