CharacterRangeTable

 

 

转载: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
CharacterRangeTable_第1张图片

 

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."":()V
   #2 = Methodref          #3.#21         //  com/test19/Test05.nop:()V
   #3 = Class              #22            //  com/test19/Test05
   #4 = Class              #23            //  java/lang/Object
   #5 = Utf8               
   #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          //  "":()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."                          ":()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() {}
}

  

CharacterRangeTable_第2张图片

 

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."":()V
   #2 = Methodref          #3.#21         //  com/test19/Test05.nop:()V
   #3 = Class              #22            //  com/test19/Test05
   #4 = Class              #23            //  java/lang/Object
   #5 = Utf8               
   #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          //  "":()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."                          ":()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
CharacterRangeTable_第3张图片

 

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."":()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               
   #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          //  "":()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."":()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
CharacterRangeTable_第4张图片

 

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."":()V
   #2 = Methodref          #3.#21         //  com/test19/Test05.nop:()V
   #3 = Class              #22            //  com/test19/Test05
   #4 = Class              #23            //  java/lang/Object
   #5 = Utf8               
   #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          //  "":()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."":()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)