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

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

目录
相关文章
|
2月前
|
Java 开发者
Java并发编程:CountDownLatch实战解析
Java并发编程:CountDownLatch实战解析
437 100
|
1月前
|
存储 安全 Java
《数据之美》:Java集合框架全景解析
Java集合框架是数据管理的核心工具,涵盖List、Set、Map等体系,提供丰富接口与实现类,支持高效的数据操作与算法处理。
|
2月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
1月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
345 2
|
8月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
830 29
|
8月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
331 4
|
8月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
|
8月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。

推荐镜像

更多
  • DNS