JaCoCo core.internal.flow包源码(中)

简介: JaCoCo core.internal.flow包源码(中)

4 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;
        }
    }

退出方法是return 指令:

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;
        }
    }
逻辑跳转的有switch,if
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);
        }
    }

If分支:

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;
……

如果没有跳转指令 GOTO LABEL或者jump,那么指令值按顺序执行的,所以我们只要在开始的时候添加一个探针就好,只要探针指令执行了,那么下面的指令一定会被执行的,除非有了跳转逻辑。因此我们只要在每一个跳转的开始和结束添加探针就好,就可以完全实现统计代码块的覆盖,而没有必要每一行都要植入探针。


目录
相关文章
|
9月前
|
Cloud Native Java Go
解决 Spring Boot 和 Gradle Java 版本兼容性问题:A problem occurred configuring root project ‘demo1‘. > Could n
解决 Spring Boot 和 Gradle Java 版本兼容性问题:A problem occurred configuring root project ‘demo1‘. > Could n
596 0
|
12月前
|
Java
SpringBoot导入第三方jar方法打包报错Failed to load ApplicationContext Failed to determine a suitable driver cla
这是第一篇博客,很早想写了,只不过每次解决问题后都觉得人家写的蛮好的,自己无须再写了,不过昨天打包时遇到的这个问题,自己找半天解决了,看很多博客也是许久才解决,不说了我的方法如下:
117 0
|
XML 存储 Java
maven报错:com.qiniu:qiniu-java-sdk/maven-metadata.xmlfailed to transfer from http://0.0.0.0/
maven报错:com.qiniu:qiniu-java-sdk/maven-metadata.xmlfailed to transfer from http://0.0.0.0/
1607 0
导入第三方库 版本冲突 TaskExecutionException: Execution failed for task ':latte_ec:compileDebugJavaWithJavac'.
导入第三方库 版本冲突 TaskExecutionException: Execution failed for task ':latte_ec:compileDebugJavaWithJavac'.
导入第三方库 版本冲突 TaskExecutionException: Execution failed for task ':latte_ec:compileDebugJavaWithJavac'.
|
Java Maven
使用maven构建项目报错Cannot change version of project facet Dynamic Web Module to 3.0解决方案
使用maven构建项目报错Cannot change version of project facet Dynamic Web Module to 3.0解决方案
使用maven构建项目报错Cannot change version of project facet Dynamic Web Module to 3.0解决方案
|
IDE Java 开发工具
IDE gradle 同步报错 IDE gradle 同步报错 Unable to find method ''org.gradle.api.tasks.TaskInputs org.gradle.api.tasks.TaskInputs.file
IDE gradle 同步报错 IDE gradle 同步报错 Unable to find method ''org.gradle.api.tasks.TaskInputs org.gradle.api.tasks.TaskInputs.file
898 0
|
Java Android开发
Eclipse中项目报Target runtime com.genuitec.runtime.generic.jee60 is not defined异常的解决方法
Eclipse中项目报Target runtime com.genuitec.runtime.generic.jee60 is not defined异常的解决
504 0
Eclipse中项目报Target runtime com.genuitec.runtime.generic.jee60 is not defined异常的解决方法
|
存储 Java API
JaCoCo core.internal.flow包源码(下)
JaCoCo core.internal.flow包源码(下)
138 0
JaCoCo core.internal.flow包源码(下)
jacoco core.runtime包源码分析
jacoco core.runtime包源码分析
228 0
jacoco core.runtime包源码分析
|
Java API
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(上)
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(上)
269 0
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(上)