转载:https://github.com/jacoco/jacoco/wiki/CharacterRangeTable

This page discusses a not yet available feature!

The CharacterRangeTable is a non-standard (not defined in The Java Virtual Machine Specification) optional variable-length attribute in the attributes table of a Code attribute.

Compilers

Can be produced by javac from OracleJDK 1.5 - 1.9 and IBM JDK 1.5 - 1.8 with help of non-standard undocumented option "-Xjcov", which is ignored by Eclipse Compiler.

Support of this attribute is unlikely to disappear soon:

  • OpenJDK JCov can use it for some scenarios

  • javap starting from OpenJDK 7 decodes content of this attribute

  • it receives fixes in recent versions of OpenJDK - JDK-8059453

  • JDK-8020204

Format

See com/sun/tools/classfile/CharacterRangeTable_attribute.java

CharacterRangeTable_attribute {
  u2 start_pc;
  u2 end_pc;
  u4 character_range_start;
  u4 character_range_end;
  u2 flags;
}

Each character_range encodes line and column as following:  

line = character_range >> 10
column = character_range & 0x03ff

How can be used

Condition coverage

Ranges with flags CRT_BRANCH_TRUE (0x0080) and CRT_BRANCH_FALSE (0x0100) are of particular interest, because could be used to map bytecode branches back to conditions in source code.

Logical and

Source

package com.test19;

public class Test05 {
	void example(int a, int b) {
		if (a == 1 && b == 1)
			nop();
	}
	void nop(){};
}

  

生成的class文件如下:

public class com.test19.Test05
  SourceFile: "Test05.java"
  Utf8 1533252190610Utf8 1533252242529minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#20         //  java/lang/Object."<init>":()V
   #2 = Methodref          #3.#21         //  com/test19/Test05.nop:()V
   #3 = Class              #22            //  com/test19/Test05
   #4 = Class              #23            //  java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               CharacterRangeTable
  #10 = Utf8               example
  #11 = Utf8               (II)V
  #12 = Utf8               StackMapTable
  #13 = Utf8               nop
  #14 = Utf8               SourceFile
  #15 = Utf8               Test05.java
  #16 = Utf8               SourceID
  #17 = Utf8               1533252190610
  #18 = Utf8               CompilationID
  #19 = Utf8               1533252242529
  #20 = NameAndType        #5:#6          //  "<init>":()V
  #21 = NameAndType        #13:#6         //  nop:()V
  #22 = Utf8               com/test19/Test05
  #23 = Utf8               java/lang/Object
{
  public com.test19.Test05();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>                          ":()V
         4: return
      LineNumberTable:
        line 3: 0
      CharacterRangeTable:

  void example(int, int);
    flags:
    Code:
      stack=2, locals=3, args_size=3
         0: iload_1
         1: iconst_1
         2: if_icmpne     14
         5: iload_2
         6: iconst_1
         7: if_icmpne     14
        10: aload_0
        11: invokevirtual #2                  // Method nop:()V
        14: return
      LineNumberTable:
        line 5: 0
        line 6: 10
        line 7: 14
      CharacterRangeTable:
       0,  1,   1407,   140d,    8  //  0,  1,    5:07,    5:13, flow-controller
       2,  4,   1407,   140d,  100  //  2,  4,    5:07,    5:13, branch-false
       5,  6,   1411,   1417,   10  //  5,  6,    5:17,    5:23, flow-target
       0,  6,   1407,   1417,    8  //  0,  6,    5:07,    5:23, flow-controller
       7,  9,   1407,   1417,  100  //  7,  9,    5:07,    5:23, branch-false
      10, 13,   1804,   180a,   11  // 10, 13,    6:04,    6:10, statement, flow-target
       0, 13,   1403,   180a,    1  //  0, 13,    5:03,    6:10, statement
       0, 14,   101d,   1c02,    2  //  0, 14,    4:29,    7:02, block
      StackMapTable: number_of_entries = 1
           frame_type = 14 /* same */

  void nop();
    flags:
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 8: 0
      CharacterRangeTable:
         0,  0,   200c,   200d,    2 //  0,  0,    8:12,    8:13, block
}

  

if branch 2 was taken, then condition 3:09-3:15 (a == 1) evaluates to false,
if branch 7 was taken, then condition 3:09-3:25 (a == 1 && b == 1) evaluates to false.

Logical or

Source
package com.test19;

public class Test05 {
	void example(int a, int b) {
		if (a == 1 || b == 1) {
			nop();
		}
	}
	void nop() {}
}

  

public class com.test19.Test05
  SourceFile: "Test05.java"
  Utf8 1533253036302Utf8 1533253190932minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#20         //  java/lang/Object."<init>":()V
   #2 = Methodref          #3.#21         //  com/test19/Test05.nop:()V
   #3 = Class              #22            //  com/test19/Test05
   #4 = Class              #23            //  java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               CharacterRangeTable
  #10 = Utf8               example
  #11 = Utf8               (II)V
  #12 = Utf8               StackMapTable
  #13 = Utf8               nop
  #14 = Utf8               SourceFile
  #15 = Utf8               Test05.java
  #16 = Utf8               SourceID
  #17 = Utf8               1533253036302
  #18 = Utf8               CompilationID
  #19 = Utf8               1533253190932
  #20 = NameAndType        #5:#6          //  "<init>":()V
  #21 = NameAndType        #13:#6         //  nop:()V
  #22 = Utf8               com/test19/Test05
  #23 = Utf8               java/lang/Object
{
  public com.test19.Test05();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>                          ":()V
         4: return
      LineNumberTable:
        line 3: 0
      CharacterRangeTable:

  void example(int, int);
    flags:
    Code:
      stack=2, locals=3, args_size=3
         0: iload_1
         1: iconst_1
         2: if_icmpeq     10
         5: iload_2
         6: iconst_1
         7: if_icmpne     14
        10: aload_0
        11: invokevirtual #2                  // Method nop:()V
        14: return
      LineNumberTable:
        line 5: 0
        line 6: 10
        line 8: 14
      CharacterRangeTable:
        0,  1,   1407,   140d,    8   //  0,  1,    5:07,    5:13, flow-controller
        2,  4,   1407,   140d,   80   //  2,  4,    5:07,    5:13, branch-true
        5,  6,   1411,   1417,   10   //  5,  6,    5:17,    5:23, flow-target
        0,  6,   1407,   1417,    8   //  0,  6,    5:07,    5:23, flow-controller
        7,  9,   1407,   1417,  100   //  7,  9,    5:07,    5:23, branch-false
       10, 13,   1804,   180a,    1   // 10, 13,    6:04,    6:10, statement
       10, 13,   1419,   1c03,   13   // 10, 13,    5:25,    7:03, statement, block, flow-target
        0, 13,   1403,   1c03,    1   //  0, 13,    5:03,    7:03, statement
        0, 14,   101d,   2002,    2   //  0, 14,    4:29,    8:02, block
      StackMapTable: number_of_entries = 2
           frame_type = 10 /* same */
           frame_type = 3 /* same */

  void nop();
    flags:
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 9: 0
      CharacterRangeTable:
             0,  0,   240d,   240e,    2        //  0,  0,    9:13,    9:14, blo                          ck
}

  

if branch 2 was taken, then condition 3:09-3:15 (a == 1) evaluates to true,
if branch 7 was taken, then condition 3:09-3:25 (a == 1 || b == 1) evaluates to false.

Conditional operator

Source

package com.test19;

public class Test05 {
	void example(int a, int b) {
		nop(a == 1 ? 2 : 3);
	}
	void nop(int x) {}
}
public class com.test19.Test05
  SourceFile: "Test05.java"
  Utf8 1533253525422Utf8 1533253540376minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#22         //  java/lang/Object."<init>":()V
   #2 = Methodref          #3.#23         //  com/test19/Test05.nop:(I)V
   #3 = Class              #24            //  com/test19/Test05
   #4 = Class              #25            //  java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               CharacterRangeTable
  #10 = Utf8               example
  #11 = Utf8               (II)V
  #12 = Utf8               StackMapTable
  #13 = Class              #24            //  com/test19/Test05
  #14 = Utf8               nop
  #15 = Utf8               (I)V
  #16 = Utf8               SourceFile
  #17 = Utf8               Test05.java
  #18 = Utf8               SourceID
  #19 = Utf8               1533253525422
  #20 = Utf8               CompilationID
  #21 = Utf8               1533253540376
  #22 = NameAndType        #5:#6          //  "<init>":()V
  #23 = NameAndType        #14:#15        //  nop:(I)V
  #24 = Utf8               com/test19/Test05
  #25 = Utf8               java/lang/Object
{
  public com.test19.Test05();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      CharacterRangeTable:

  void example(int, int);
    flags:
    Code:
      stack=3, locals=3, args_size=3
         0: aload_0
         1: iload_1
         2: iconst_1
         3: if_icmpne     10
         6: iconst_2
         7: goto          11
        10: iconst_3
        11: invokevirtual #2                  // Method nop:(I)V
        14: return
      LineNumberTable:
        line 5: 0
        line 6: 14
      CharacterRangeTable:
        1,  2,   1407,   140d,    8   //  1,  2,    5:07,    5:13, flow-controller
        3,  5,   1407,   140d,  100   //  3,  5,    5:07,    5:13, branch-false
        6,  6,   1410,   1411,   10   //  6,  6,    5:16,    5:17, flow-target
       10, 10,   1414,   1415,   10   // 10, 10,    5:20,    5:21, flow-target
        0, 13,   1403,   1417,    1   //  0, 13,    5:03,    5:23, statement
        0, 14,   101d,   1802,    2   //  0, 14,    4:29,    6:02, block
      StackMapTable: number_of_entries = 2
           frame_type = 74 /* same_locals_1_stack_item */
          stack = [ class com/test19/Test05 ]
           frame_type = 255 /* full_frame */
          offset_delta = 0
          locals = [ class com/test19/Test05, int, int ]
          stack = [ class com/test19/Test05, int ]

  void nop(int);
    flags:
    Code:
      stack=0, locals=2, args_size=2
         0: return
      LineNumberTable:
        line 7: 0
      CharacterRangeTable:
             0,  0,   1c12,   1c13,    2        //  0,  0,    7:18,    7:19, block
}

  

if branch 2 was taken, then condition 3:09-3:15 (a == 1) evaluates to false.

Filtering

Ranges with flag CRT_BLOCK (0x0002) could be used to filter synthetic compiler constructs.

Duplicated finally blocks

Source

package com.test19;

public class Test05 {
	void example() {
		try {
			nop();
		} finally {
			nop();
		}
	}

	void nop() {}
}

  

public class com.test19.Test05
  SourceFile: "Test05.java"
  Utf8 1533253682139Utf8 1533253727858minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#20         //  java/lang/Object."<init>":()V
   #2 = Methodref          #3.#21         //  com/test19/Test05.nop:()V
   #3 = Class              #22            //  com/test19/Test05
   #4 = Class              #23            //  java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               CharacterRangeTable
  #10 = Utf8               example
  #11 = Utf8               StackMapTable
  #12 = Class              #24            //  java/lang/Throwable
  #13 = Utf8               nop
  #14 = Utf8               SourceFile
  #15 = Utf8               Test05.java
  #16 = Utf8               SourceID
  #17 = Utf8               1533253682139
  #18 = Utf8               CompilationID
  #19 = Utf8               1533253727858
  #20 = NameAndType        #5:#6          //  "<init>":()V
  #21 = NameAndType        #13:#6         //  nop:()V
  #22 = Utf8               com/test19/Test05
  #23 = Utf8               java/lang/Object
  #24 = Utf8               java/lang/Throwable
{
  public com.test19.Test05();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      CharacterRangeTable:

  void example();
    flags:
    Code:
      stack=1, locals=2, args_size=1
         0: aload_0
         1: invokevirtual #2                  // Method nop:()V
         4: aload_0
         5: invokevirtual #2                  // Method nop:()V
         8: goto          18
        11: astore_1
        12: aload_0
        13: invokevirtual #2                  // Method nop:()V
        16: aload_1
        17: athrow
        18: return
      Exception table:
         from    to  target type
            0     4    11   any
            11    12    11   any
      LineNumberTable:
        line 6: 0
        line 8: 4
        line 9: 8
        line 8: 11
        line 10: 18
      CharacterRangeTable:
       0,  3,   1804,   180a,    1   //  0,  3,    6:04,    6:10, statement
       0,  3,   1407,   1c03,    2   //  0,  3,    5:07,    7:03, block
       4,  7,   2004,   200a,    1   //  4,  7,    8:04,    8:10, statement
       4,  7,   1c0d,   2403,    2   //  4,  7,    7:13,    9:03, block
      12, 15,   2004,   200a,    1   // 12, 15,    8:04,    8:10, statement
      12, 15,   1c0d,   2403,    2   // 12, 15,    7:13,    9:03, block
       0, 17,   1403,   2403,    1   //  0, 17,    5:03,    9:03, statement
       0, 18,   1011,   2802,    2   //  0, 18,    4:17,   10:02, block
      StackMapTable: number_of_entries = 2
           frame_type = 75 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
           frame_type = 6 /* same */

  void nop();
    flags:
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 12: 0
      CharacterRangeTable:
       0,  0,   300d,   300e,    2        //  0,  0,   12:13,   12:14, block
}

same source code corresponds to instructions 3-5 and 10-12.  

  

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

CharacterRangeTable的更多相关文章

  1. Gen类的字符串操作

    public void t(String d){ final String str = "b"; String s = "a"+"c"+st ...

随机推荐

  1. 玩转Nodejs的集群

    在Nodejs中使用集群还是不容易的.Javascript的单线程属性让nodejs下的应用很难使用现代机器的多核特性.比如下面的代码实现了一个http服务器的主干部分.这部分代码只会执行在一个线程上 ...

  2. iOS 5 故事板进阶(2)

    让我们回到游戏排行窗口Ranking.创建一个 UITableViewController子类,命名为 RankingViewController. 编辑 RankingViewController. ...

  3. Latex中Matlab代码的环境

    需要用到listings宏包 使用方法: 导言区\usepackage{listings}\lstset{language=Matlab}      %代码语言使用的是matlab\lstset{br ...

  4. Dapper 嵌套对象查询

    我有这样一个一对一关系的表结构:User->UserInfo User: /// <summary> /// 用户 /// </summary> [Serializabl ...

  5. RESTful Android

    RESTful Android API 定义 约定 回复中默认包含标头: Content-Type: application/json;charset=UTF-8 异步操作以(*)号标记 大多数异步操 ...

  6. LinkServer--访问远程数据表三种方式

    在TSQL中访问远程数据库有三种方式:1.OPENROWSET2.OPENDATASOURCE3.LinkServer 在使用openrowset/opendatasource前搜先要启用Ad Hoc ...

  7. asp.net—策略模式

    一.什么是策略模式 定义:定义一系列算法,把一个个算法封装成独立类并实现同一个接口,使得它们之间可以相互替换. 二.怎么使用策略模式 首先模拟一个场景:有一个用户想买车.  可以有多种方式买车: (1 ...

  8. Tasks遇到的一些坑,关于在子线程中对线程权限认证。

    一般情况下,不应该在执行多线程认证的时候对其子线程进行身份认证,如:A线程的子线程B和子线程C. 当使用 Parallel.ForEach方法时,只有自身线程能够拥有相对应的权限,其子线程权限则为NU ...

  9. Day 38 Semaphore ,Event ,队列

    什么是信号量(multiprocess.Semaphore) 互斥锁同时只允许一个线程更改数据,而信号量semaphore是同时允许一定数量的线程更改数据. 假设商场里有4个迷你唱吧 ,所以通过同时可 ...

  10. [LeetCode] Minimum Number of K Consecutive Bit Flips 连续K位翻转的最小次数

    In an array A containing only 0s and 1s, a K-bit flip consists of choosing a (contiguous) subarray o ...