Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(下)

简介: Java代码覆盖率框架JaCoCo的core-instr core.internal.instr 包类源码解析(下)

DuplicateFrameEliminator

消除了导致ASM创建无效类文件的连续 stackmap frames 定义。 当原始类文件在意外偏移处包含其他 stackmap frames 时,就会发生这种情况,某些使用ECJ编译的类文件就是这种情况。


ProbeInserter - 探针植入类

16.png

内部实用程序,用于将探针添加到方法的控制流中。

探针的代码只是将布尔数组的某个插槽设置为true。

另外,必须在方法开始时检索探针数组并将其存储在局部变量中。

构造方法

  • 创建一个新的ProbeInserter
  /**
   *
   * @param access
   *            access flags of the adapted method
   * @param name
   *            the method's name
   * @param desc
   *            the method's descriptor
   * @param mv
   *            the method visitor to which this adapter delegates calls
   * @param arrayStrategy
   *            callback to create the code that retrieves the reference to
   *            the probe array
   */

17.png

visitmax

探针代码的最大堆栈大小为3,这可以增加到原始堆栈大小,具体取决于探针位置。 访问者堆栈大小是绝对最大值,因为当堆栈大小为空时,访问者代码会在每种方法的开头插入。

  @Override
  public void visitMaxs(final int maxStack, final int maxLocals) {
    final int increasedStack = Math.max(maxStack + 3, accessorStackSize);
    mv.visitMaxs(increasedStack, maxLocals + 1);
  }

insertProbe - 插入具有给定id的探针

18.png

19.png

visitIincInsn - 访问 IINC 指令

21.png

visitLocalVariable - 访问局部变量声明

Visits a local variable declaration.

22.png

    private void visitInsn() {
        final Instruction insn = newInstruction(currentNode, currentLine);
        nodeToInstruction.put(currentNode,insn);
        instructions.add(insn);
        if (lastInsn != null) {
            insn.setPredecessor(lastInsn, 0);
        }
        final int labelCount =currentLabel.size();
        if (labelCount > 0) {
            for (int i = labelCount; --i >=0;) {
                LabelInfo.setInstruction(currentLabel.get(i),insn);
            }
            currentLabel.clear();
        }
        lastInsn = insn;
    }

大致就是,在对应字节码的执行入口和跳转入口处,置放 probe,是一个数值(该数值和probe id有关),入栈后加1,则记录一次执行

  • 所有放入的探针对应一个boolean[]
  • 探针入栈之后,那么boolean[] 对应的位置变成true,记录执行了。

InstrSupport 类原理

Constants and utilities for byte code instrumentation

字节码检测的常量和实用程序。

属性

public static final int ASM_API_VERSION = Opcodes.ASM7;

接口初始化方法的名称。

static final String CLINIT_NAME = "<clinit>";

存储类的boolean[]数组的coverage信息的字段的数据类型

public static final String DATAFIELD_DESC = "[Z";

初始化方法的名称。

public static final String INITMETHOD_NAME = "$jacocoInit";

初始化方法的描述符。

public static final String INITMETHOD_DESC = "()[Z";
  /**
   * Access modifiers of the initialization method.
   */
  public static final int INITMETHOD_ACC = Opcodes.ACC_SYNTHETIC
      | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;

needsFrames

  /**
   * 确定给定的 class 文件版本是否需要 stackmap frames.
   *
   * @param version
   *            class file version
   * @return <code>true</code> if frames are required
   */
  public static boolean needsFrames(final int version) {
    // consider major version only (due to 1.1 anomaly)
    return (version & 0xFFFF) >= Opcodes.V1_6;
  }

classReaderFor

  /**
   * Creates a {@link ClassReader} instance for given bytes of class even if
   * its version not yet supported by ASM.
   *
   * @param b
   *            bytes of class
   * @return {@link ClassReader}
   */
  public static ClassReader classReaderFor(final byte[] b) {
    final int originalVersion = getMajorVersion(b);
    if (originalVersion == Opcodes.V14 + 1) {
      // temporarily downgrade version to bypass check in ASM
      setMajorVersion(Opcodes.V14, b);
    }
    final ClassReader classReader = new ClassReader(b);
    setMajorVersion(originalVersion, b);
    return classReader;
  }

assertNotInstrumented

Ensures that the given member does not correspond to a internal member created by the instrumentation process. This would mean that the class is already instrumented.

确保给定成员与 instrumentation 过程创建的内部成员不对应。 这意味着该类已经被检测。

23.png

push

Generates the instruction to push the given int value on the stack.


Implementation taken from org.objectweb.asm.commons.GeneratorAdapter#push(int)

生成指令以将给定的int值压入堆栈。

取自org.objectweb.asm.commons.GeneratorAdapter#push(int)的实现

25.png

Push是用来对于不同的变量值入栈的不同方式,当int取值

  • -1 ~ 5,JVM采用iconst指令将常量压入栈中
  • -128 ~ 127,bipush
  • -32768 ~ 32767,sipush
  • -2147483648~2147483647,ldc

主要作为单例的使用,ClassInstrumenter, ClassAnalyzer调用InstrSupport

ClassAnalyzer 类调用如下:

public static final String DATAFIELD_DESC = "[Z";
  // === Init Method ===
  /**
   * Name of the initialization method.
   */
  public static final String INITMETHOD_NAME = "$jacocoInit";
  /**
   * Descriptor of the initialization method.
   */
  public static final String INITMETHOD_DESC = "()[Z";
        public static void assertNotInstrumented(final String member,
      final String owner) throws IllegalStateException {
    if (member.equals(DATAFIELD_NAME) || member.equals(INITMETHOD_NAME)) {
      throw new IllegalStateException(format(
          "Class %s is already instrumented.", owner));
    }
  }

IProbeArrayStrategy

检索类型内每个方法的探针数组实例的策略。 这种抽象是必需的,因为我们需要根据所检测的类型是类还是接口来遵循不同的策略。

storeInstance

  /**
   * Creates code that stores the probe array instance in the given variable.
   *
   * @param mv
   *            visitor to create code
   * @param clinit
   *            true in case of {@code <clinit>} method
   * @param variable
   *            variable index to store probe array to
   * @return maximum stack size required by the generated code
   */
  int storeInstance(MethodVisitor mv, boolean clinit, int variable);

创建将探针数组实例存储在给定变量中的代码。

目录
相关文章
|
23小时前
|
安全 Java 开发者
Java一分钟之-文件与目录操作:Path与Files类
【5月更文挑战第13天】Java 7 引入`java.nio.file`包,`Path`和`Files`类提供文件和目录操作。`Path`表示路径,不可变。`Files`包含静态方法,支持创建、删除、读写文件和目录。常见问题包括:忽略异常处理、路径解析错误和权限问题。在使用时,注意异常处理、正确格式化路径和考虑权限,以保证代码稳定和安全。结合具体需求,这些方法将使文件操作更高效。
10 2
|
1天前
|
安全 Java 开发者
Java一分钟之-Optional类:优雅处理null值
【5月更文挑战第13天】Java 8的`Optional`类旨在减少`NullPointerException`,提供优雅的空值处理。本文介绍`Optional`的基本用法、创建、常见操作,以及如何避免错误,如直接调用`get()`、误用`if (optional != null)`检查和过度使用`Optional`。正确使用`Optional`能提高代码可读性和健壮性,建议结合实际场景灵活应用。
16 3
|
1天前
|
存储 Java ice
【Java开发指南 | 第十六篇】Java数组及Arrays类
【Java开发指南 | 第十六篇】Java数组及Arrays类
8 3
|
1天前
|
Java 编译器 ice
【Java开发指南 | 第十五篇】Java Character 类、String 类
【Java开发指南 | 第十五篇】Java Character 类、String 类
11 1
|
1天前
|
存储 Java ice
【Java开发指南 | 第十四篇】Java Number类及Math类
【Java开发指南 | 第十四篇】Java Number类及Math类
9 1
|
1天前
|
存储 缓存 Java
【Java开发指南 | 第六篇】Java成员变量(实例变量)、 类变量(静态变量)
【Java开发指南 | 第六篇】Java成员变量(实例变量)、 类变量(静态变量)
9 2
|
1天前
|
Java 编译器
【Java开发指南 | 第一篇】类、对象基础概念及Java特征
【Java开发指南 | 第一篇】类、对象基础概念及Java特征
9 4
|
3天前
PandasTA 源码解析(二十三)
PandasTA 源码解析(二十三)
28 0
|
3天前
PandasTA 源码解析(二十二)(3)
PandasTA 源码解析(二十二)
24 0
|
3天前
PandasTA 源码解析(二十二)(2)
PandasTA 源码解析(二十二)
22 2

推荐镜像

更多