转载: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. day8 异常处理

    异常和错误 part1:程序中难免出现错误,而错误分成两种 1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正) 2.逻辑错误(逻辑错误) part2:什么是异常 ...

  2. (KMP)剪花布条 -- hdu -- 2087

    http://acm.hdu.edu.cn/showproblem.php?pid=2087 剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory ...

  3. Activity生命流程

    做Android的同学说起 Activity,那绝对是熟悉的不能再熟悉了,但是越熟悉的东西往往越陌生.我们真的了解她吗?她是我们所认识的那样吗?或许是,或许不是!了解与否, 让我们往下看.首先借And ...

  4. hdu 1266 Reverse Number

    题目 一道水题,但是超时了几次(Time Limit Exceeded) 题中说:then n 32-bit integers follow.私以为可以用int来做,结果就一直超时,博客之,发现全是用 ...

  5. Bitcoin

    看李笑来老师的2013演讲——Bitcoin is not virtual currency,it is a real world. 1.由于bitcoin的算法中进行有上限量的发布,所以这是不会出现 ...

  6. Python学习-21.Python的代码注释

    在Python中有两种注释,一种是普通注释,另一种是文档注释. 普通注释是使用#开头 print('output something') # here is comment 而Python中多行注释也 ...

  7. Visual Studio模板

    转载自MSDN,此文仅作参考. http://msdn.microsoft.com/zh-cn/library/6db0hwky(VS.80).aspx 1. 如何导入“项目模板(Project Te ...

  8. 从 exe.config 读取appSettings 中的配置数据

    右键解决方案,添加引用--> System.Configuration.dll 在exe.config 中添加数据 <appSettings> <add key=" ...

  9. 深入浅出“跨视图粒度计算”--3、EXCLUDE表达式

    本文由  网易云发布. 深入嵌入“跨视图粒度计算”的前面两篇分别讲了 1.理解数据的粒度 2.INCLUDE表达式 这一篇讲一下EXCLUDE表达式的用法. EXCLUDE,中文译为“排除”,顾名思义 ...

  10. python 以行为单位进行字符串的切割

    可以使用str 的 splitlines() 方法 实现以行为单位 进行字符串的切割, keepends=False 不保留\n符号, kendends=True 保留\n符号 my_str = &q ...