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


目录
相关文章
|
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
924 0
|
缓存 IDE Go
已解决Gradle错误:“Unable to load class ‘org.gradle.api.plugins.MavenPlugin‘
已解决Gradle错误:“Unable to load class ‘org.gradle.api.plugins.MavenPlugin‘
1318 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/
2078 0
|
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
1007 0
|
存储 Java API
JaCoCo core.internal.flow包源码(下)
JaCoCo core.internal.flow包源码(下)
156 0
JaCoCo core.internal.flow包源码(下)
jacoco core.runtime包源码分析
jacoco core.runtime包源码分析
254 0
jacoco core.runtime包源码分析
|
存储 Java
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(下)
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(下)
609 0
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(下)
|
Java API
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(上)
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(上)
289 0
Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(上)
JaCoCo core.internal.flow包源码(上)
JaCoCo core.internal.flow包源码(上)
170 0