fuente de paquetes de flujo interno núcleo JaCoCo

Hay jacoco nivel de clase, nivel de método, el nivel lógico y el nivel de rama de línea para hacer un proceso de envasado especial. internal.analysis.flow clase Específicamente encapsulado

Interfaz IFrame

import org.objectweb.asm.MethodVisitor;

/**
 * 当前的 stackmap frame 内容的表示
 */
public interface IFrame {

	/**
	 * 向给定的访问者发出具有当前内容的 frame 事件
	 *
	 * @param mv 向该方法发出 frame 事件的method visitor
	 */
	void accept(MethodVisitor mv);
}

Las clases están involucrados ClassprobesAdapter.java (nivel de clase), Instruction.java (nivel de instrucción), LabelFlowAnalysis.java (nivel lógico rama) y MethodProbesAdapter.java (nivel de método).

ClassprobesAdapter

publicfinal MethodVisitor visitMethod(intaccess, String name, String desc, String signature, String[] exceptions)
  {
    MethodProbesVisitor mv =this.cv.visitMethod(access, name, desc, signature, exceptions);

    MethodProbesVisitor methodProbes;

    final MethodProbesVisitor methodProbes;

    if (mv == null) {

      methodProbes =EMPTY_METHOD_PROBES_VISITOR;

    } else {

      methodProbes = mv;

    }
    new MethodSanitizer(null, access, name,desc, signature, exceptions)
    {
      public void visitEnd()

      {
        super.visitEnd();

        LabelFlowAnalyzer.markLabels(this);

        MethodProbesAdapter probesAdapter = newMethodProbesAdapter(methodProbes, ClassProbesAdapter.this);

        if(ClassProbesAdapter.this.trackFrames)

        {
          AnalyzerAdapter analyzer = new AnalyzerAdapter(ClassProbesAdapter.this.name,this.access, this.name, this.desc, probesAdapter);       probesAdapter.setAnalyzer(analyzer);

          accept(analyzer);

        }
        else
        {
          accept(probesAdapter);
        }
      }
    };
  }

la cobertura de las clases visuales es en realidad incrustada métodos de clase de código de bytes cada rama de la lógica incrustada hacer, siempre y cuando el método de registro de las líneas de cobertura de la clase llamada, clase natural se cubrió con las estadísticas.

MethodProbesAdapter

@Override

    public void visitLabel(final Label label) {

        if (LabelInfo.needsProbe(label)) {

            if(tryCatchProbeLabels.containsKey(label)) {

                probesVisitor.visitLabel(tryCatchProbeLabels.get(label));
            }
            probesVisitor.visitProbe(idGenerator.nextId());

        }
        probesVisitor.visitLabel(label);
    }

    @Override
    public void visitInsn(final int opcode) {

        switch (opcode) {

        case Opcodes.IRETURN:

        case Opcodes.LRETURN:

        case Opcodes.FRETURN:

        case Opcodes.DRETURN:

        case Opcodes.ARETURN:

        case Opcodes.RETURN:

        case Opcodes.ATHROW:
            probesVisitor.visitInsnWithProbe(opcode,idGenerator.nextId());
            break;

        default:
            probesVisitor.visitInsn(opcode);
            break;
        }
    }

    @Override
    public void visitJumpInsn(final int opcode, final Label label) {
        if (LabelInfo.isMultiTarget(label)) {
            probesVisitor.visitJumpInsnWithProbe(opcode,label,
                    idGenerator.nextId(), frame(jumpPopCount(opcode)));
        } else {
            probesVisitor.visitJumpInsn(opcode,label);
        }
    }

    private int jumpPopCount(final int opcode) {
        switch (opcode) {
        case Opcodes.GOTO:
            return 0;
        case Opcodes.IFEQ:

        case Opcodes.IFNE:

        case Opcodes.IFLT:

        case Opcodes.IFGE:

        case Opcodes.IFGT:

        case Opcodes.IFLE:

        case Opcodes.IFNULL:

        case Opcodes.IFNONNULL:

            return 1;

        default: // IF_CMPxx and IF_ACMPxx
            return 2;
        }
    }

    @Override
    public void visitLookupSwitchInsn(final Label dflt, final int[]keys,
            final Label[] labels) {
        if (markLabels(dflt, labels)) {
            probesVisitor.visitLookupSwitchInsnWithProbes(dflt,keys, labels,
                    frame(1));
        } else {
            probesVisitor.visitLookupSwitchInsn(dflt,keys, labels);
        }
    }

    @Override
    public void visitTableSwitchInsn(final int min, final int max,
            final Label dflt, final Label...labels) {
        if (markLabels(dflt, labels)) {
            probesVisitor.visitTableSwitchInsnWithProbes(min,max, dflt,
                    labels, frame(1));
        } else {
            probesVisitor.visitTableSwitchInsn(min,max, dflt, labels);
        }
    }
在MethodProbesAdapter中明显看到字节码指令信息,对于一个方法的进入,jvm中是一个方法栈的创建,入口指令是入栈指令,退出是return:

privateint jumpPopCount(finalint opcode) {

        switch (opcode) {

        case Opcodes.GOTO:

            return0;

        caseOpcodes.IFEQ:

        caseOpcodes.IFNE:

        caseOpcodes.IFLT:

        caseOpcodes.IFGE:

        caseOpcodes.IFGT:

        caseOpcodes.IFLE:

        caseOpcodes.IFNULL:

        caseOpcodes.IFNONNULL:

            return1;

        default:// IF_CMPxx and IF_ACMPxx

            return2;

        }

    }

El método de salida es a las instrucciones de devolución:

publicvoid visitInsn(finalint opcode) {

        switch (opcode) {

        case Opcodes.IRETURN:

        caseOpcodes.LRETURN:

        caseOpcodes.FRETURN:

        caseOpcodes.DRETURN:

        caseOpcodes.ARETURN:

        caseOpcodes.RETURN:

        caseOpcodes.ATHROW:

            probesVisitor.visitInsnWithProbe(opcode,idGenerator.nextId());

            break;

        default:

            probesVisitor.visitInsn(opcode);

            break;

        }

    }

逻辑跳转的有switchif

publicvoid visitTableSwitchInsn(finalint min, final int max,

            final Label dflt, final Label...labels) {

        if (markLabels(dflt, labels)) {

            probesVisitor.visitTableSwitchInsnWithProbes(min,max, dflt,

                    labels, frame(1));

        } else {

            probesVisitor.visitTableSwitchInsn(min,max, dflt, labels);

        }

    }

Si las ramas:

case Opcodes.GOTO:

            return0;

        caseOpcodes.IFEQ:

        caseOpcodes.IFNE:

        caseOpcodes.IFLT:

        caseOpcodes.IFGE:

        caseOpcodes.IFGT:

        caseOpcodes.IFLE:

        caseOpcodes.IFNULL:

        caseOpcodes.IFNONNULL:

            return1;

        default:// IF_CMPxx and IF_ACMPxx

            return2;

        } 

LabelFlowAnalysis主要实现代码:

@Override
    public void visitJumpInsn(final int opcode, final Label label) {
        LabelInfo.setTarget(label);
        if (opcode == Opcodes.JSR) {
            thrownew AssertionError("Subroutines not supported.");
        }
        successor = opcode != Opcodes.GOTO;
        first = false;
    }

    @Override
    public void visitLabel(final Label label) {
        if (first) {
            LabelInfo.setTarget(label);
        }
        if (successor) {
            LabelInfo.setSuccessor(label);
        }
    }

    @Override
    public void visitLineNumber(final int line, final Label start) {
        lineStart = start;
    }

    @Override
    public void visitTableSwitchInsn(final int min, final int max,
      final Label dflt, final Label...labels) {
       visitSwitchInsn(dflt, labels);
    }

    @Override
    public void visitLookupSwitchInsn(final Label dflt, final int[]keys,
            final Label[] labels) {
        visitSwitchInsn(dflt, labels);
    }
    @Override
    public void visitInsn(final int opcode) {

        switch (opcode) {

        case Opcodes.RET:

            throw new AssertionError("Subroutinesnot supported.");

        case Opcodes.IRETURN:

        case Opcodes.LRETURN:

        case Opcodes.FRETURN:

        case Opcodes.DRETURN:

        case Opcodes.ARETURN:

        case Opcodes.RETURN:

        case Opcodes.ATHROW:
            successor = false;
            break;

        default:
            successor = true;
            break;
        }
        first = false;
    }
首先要知道对于一串指令比如:

iLoad A;

iLoad B;

Add A,B;

iStore;

……

Si usted no salta la instrucción goto etiqueta o saltar, entonces el valor de comandos con el fin de llevar a cabo, por lo que sólo tiene que añadir una sonda en el buen comienzo, siempre y cuando se ejecuta la instrucción de la sonda, a continuación, el siguiente comando se ejecutará a menos que el con la lógica de salto. Así que acaba de saltar en cada principio y al final de una sonda como añadir, puede bloquear completamente de código para lograr estadísticas de cobertura, pero no hay necesidad de que cada fila para ser implantados sondas.

Publicados 406 artículos originales · ganado elogios 1032 · Vistas de 510.000 +

Supongo que te gusta

Origin blog.csdn.net/qq_33589510/article/details/105249899
Recomendado
Clasificación