package net.sourceforge.cobertura.instrument.pass3;
import net.sourceforge.cobertura.coveragedata.LightClassmapListener;
import net.sourceforge.cobertura.coveragedata.TouchCollector;
import net.sourceforge.cobertura.instrument.tp.*;
import org.objectweb.asm.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
public abstract class AbstractCodeProvider implements CodeProvider {
public static final int FAKE_COUNTER_ID = 0;
public AbstractCodeProvider() {
super();
}
public void generateCodeThatSetsJumpCounterIdVariable(
MethodVisitor nextMethodVisitor, int new_value,
int lastJumpIdVariableIndex) {
nextMethodVisitor.visitLdcInsn(new_value);
nextMethodVisitor.visitVarInsn(Opcodes.ISTORE, lastJumpIdVariableIndex);
}
public void generateCodeThatZeroJumpCounterIdVariable(
MethodVisitor nextMethodVisitor, int lastJumpIdVariableIndex) {
generateCodeThatSetsJumpCounterIdVariable(nextMethodVisitor,
FAKE_COUNTER_ID, lastJumpIdVariableIndex);
}
public void generateCodeThatIncrementsCoberturaCounterIfVariableEqualsAndCleanVariable(
MethodVisitor nextMethodVisitor,
Integer neededJumpCounterIdVariableValue,
Integer counterIdToIncrement, int lastJumpIdVariableIndex,
String className) {
nextMethodVisitor.visitLdcInsn((int) neededJumpCounterIdVariableValue);
nextMethodVisitor.visitVarInsn(Opcodes.ILOAD, lastJumpIdVariableIndex);
Label afterJump = new Label();
nextMethodVisitor.visitJumpInsn(Opcodes.IF_ICMPNE, afterJump);
generateCodeThatIncrementsCoberturaCounter(nextMethodVisitor,
counterIdToIncrement, className);
generateCodeThatZeroJumpCounterIdVariable(nextMethodVisitor,
lastJumpIdVariableIndex);
nextMethodVisitor.visitLabel(afterJump);
}
protected void generateRegisterClass(MethodVisitor mv, String className) {
mv.visitLdcInsn(className);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type
.getInternalName(TouchCollector.class), "registerClass",
"(Ljava/lang/String;)V");
}
final String CLASSMAP_LISTENER_INTERNALNAME = Type
.getInternalName(LightClassmapListener.class);
public void generateCoberturaClassMapMethod(ClassVisitor cv,
ClassMap classMap) {
LinkedList<TouchPointDescriptor> touchPointDescriptors = new LinkedList<TouchPointDescriptor>(
classMap.getTouchPointsInLineOrder());
int parts = 0;
for (int j = 0; touchPointDescriptors.size() > 0; j++) {
List<TouchPointDescriptor> bufor = new LinkedList<TouchPointDescriptor>();
for (int i = 0; i < 1000 && touchPointDescriptors.size() > 0; i++) {
bufor.add(touchPointDescriptors.removeFirst());
}
classMapContent(cv, j, bufor);
parts++;
}
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC
| Opcodes.ACC_STATIC, COBERTURA_CLASSMAP_METHOD_NAME, "("
+ Type.getType(LightClassmapListener.class).toString() + ")V",
null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn(classMap.getClassName());
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
CLASSMAP_LISTENER_INTERNALNAME, "setClazz",
"(Ljava/lang/String;)V");
if (classMap.getSource() != null) {
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn(classMap.getSource());
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
CLASSMAP_LISTENER_INTERNALNAME, "setSource",
"(Ljava/lang/String;)V");
}
for (int i = 0; i < parts; i++) {
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, classMap.getClassName(),
COBERTURA_CLASSMAP_METHOD_NAME + "_" + i, "("
+ Type.getType(LightClassmapListener.class)
.toString() + ")V");
}
mv.visitInsn(Opcodes.POP);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
enum Abcd {
A, B, C;
}
private void classMapContent(ClassVisitor cv, int nr,
List<TouchPointDescriptor> touchPointDescriptors) {
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC
| Opcodes.ACC_STATIC,
COBERTURA_CLASSMAP_METHOD_NAME + "_" + nr, "("
+ Type.getType(LightClassmapListener.class).toString()
+ ")V", null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
for (TouchPointDescriptor tpd : touchPointDescriptors) {
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn(tpd.getLineNumber());
if (tpd instanceof LineTouchPointDescriptor) {
mv
.visitLdcInsn(((LineTouchPointDescriptor) tpd)
.getCounterId());
mv.visitLdcInsn(((LineTouchPointDescriptor) tpd)
.getMethodName());
mv.visitLdcInsn(((LineTouchPointDescriptor) tpd)
.getMethodSignature());
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
CLASSMAP_LISTENER_INTERNALNAME, "putLineTouchPoint",
"(IILjava/lang/String;Ljava/lang/String;)V");
} else if (tpd instanceof JumpTouchPointDescriptor) {
mv.visitLdcInsn(((JumpTouchPointDescriptor) tpd)
.getCounterIdForTrue());
mv.visitLdcInsn(((JumpTouchPointDescriptor) tpd)
.getCounterIdForFalse());
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
CLASSMAP_LISTENER_INTERNALNAME, "putJumpTouchPoint",
"(III)V");
} else if (tpd instanceof SwitchTouchPointDescriptor) {
SwitchTouchPointDescriptor stpd = (SwitchTouchPointDescriptor) tpd;
final String enum_sign = ((SwitchTouchPointDescriptor) tpd)
.getEnumType();
if (enum_sign == null) {
mv.visitLdcInsn(Integer.MAX_VALUE);
} else {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, enum_sign,
"values", "()[L" + enum_sign + ";");
mv.visitInsn(Opcodes.ARRAYLENGTH);
}
Collection<Integer> ci = stpd.getCountersForLabels();
mv.visitLdcInsn(ci.size());
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_INT);
int i = 0;
for (Integer counterId : ci) {
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn(i);
mv.visitLdcInsn(counterId);
mv.visitInsn(Opcodes.IASTORE);
i++;
}
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
CLASSMAP_LISTENER_INTERNALNAME, "putSwitchTouchPoint",
"(II[I)V");
}
}
mv.visitInsn(Opcodes.POP);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
protected abstract void generateCINITmethod(MethodVisitor mv,
String className, int counters_cnt);
public void generateCoberturaInitMethod(ClassVisitor cv, String className,
int countersCnt) {
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC
| Opcodes.ACC_STATIC, COBERTURA_INIT_METHOD_NAME, "()V", null,
null);
mv.visitCode();
generateCINITmethod(mv, className, countersCnt);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
public void generateCallCoberturaInitMethod(MethodVisitor mv,
String className) {
mv.visitCode();
mv.visitMethodInsn(Opcodes.INVOKESTATIC, className,
COBERTURA_INIT_METHOD_NAME, "()V");
}
}