We know that Java’s most famous slogan is “Write Once, Run Anywhere,” and its platform-independence is dependent on the JVM. All Java files are compiled into bytecode files, and the virtual machine only needs to know bytecode files. This is an essential part of understanding virtual machines and the class loading mechanism.

JVM

A Class file is a set of 8-byte binary streams in which all data is arranged without spacing. Multi-byte data is stored in a big-endian order. The Class file stores data structures in a pseudo-code form that is close to the structures in C, and contains only unsigned and table data structures:

  • Unsigned numbers :u1, U2, U4, u8 table 1, 2, 4, 8 byte unsigned numbers respectively
  • Table: A compound data type consisting of unsigned numbers or other tables. The Class file is itself a table.

Class table structure:

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}Copy the code

Referring to the data structure above, the Class file consists of 10 parts: 1. Magic number 2. Primary and secondary versions of Class files 3. Constant pool 4. Access flag 5. Current class name 6. Parent class name 7. Inherited interface name 8. Number of fields included + number of fields 9. Number of methods included + method 10. The number of all attributes contained + attributes

Let’s analyze each part in turn:

1. The magic number

The Magic number is used to determine the type of file. This is the Class file that checks whether the file is acceptable to the virtual machine. Many files use magic numbers to determine file types, not extensions (which can be changed at will). See my in-depth understanding of program construction (I).

The magic number of the Class file is “0xcafebabe”, coffee babe? Java itself is also a kind of Java coffee. Here I also write a small test program, to see its binary stream:

package com.shuqing28;

public class TestClass {
    private int m;
    public int inc() {
        returnm+1; }}Copy the code

We compiled to a.class file using javac, which can be opened with WinHex on Windows or hexdump on Linux, using the following command:

$ hexdump -C TestClass.class 00000000 ca fe ba be 00 00 00 34 00 16 0a 00 04 00 12 09 |....... 4... | 00000010 00 03 00 13 07 00 14 07 00 15 01 00 01 6d 01 00 |............. m.. | 00000020 01 49 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29 |.I... <init>... ()| 00000030 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e |V... Code... LineN| 00000040 75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63 |umberTable... Loc| 00000050 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01 |alVariableTable.| 00000060 00 04 74 68 69 73 01 00 19 4c 63 6f 6d 2f 73 68 |.. this... Lcom/sh| 00000070 75 71 69 6e 67 32 38 2f 54 65 73 74 43 6c 61 73 |uqing28/TestClas| 00000080 73 3b 01 00 03 69 6e 63 01  00 03 28 29 49 01 00 |s; . inc... ()I.. | 00000090 0a 53 6f 75 72 63 65 46 69 6c 65 01 00 0e 54 65 |.SourceFile... Te| 000000a0 73 74 43 6c 61 73 73 2e 6a 61 76 61 0c 00 07 00 |stClass.java.... | 000000b0 08 0c 00 05 00 06 01 00 17 63 6f 6d 2f 73 68 75 |......... com/shu| 000000c0 71 69 6e 67 32 38 2f 54 65 73 74 43 6c 61 73 73 |qing28/TestClass| 000000d0 01 00 10 6a 61 76 61 2f 6c  61 6e 67 2f 4f 62 6a |... java/lang/Obj| 000000e0 65 63 74 00 21 00 03 00 04 00 00 00 01 00 02 00 |ect.! . | 000000f0 05 00 06 00 00 00 02 00 01 00 07 00 08 00 01 00 |................ | 00000100 09 00 00 00 2f 00 01 00 01 00 00 00 05 2a b7 00 |.... /... *.. | 00000110 01 b1 00 00 00 02 00 0a 00 00 00 06 00 01 00 00 |................ | 00000120 00 03 00 0b 00 00 00 0c 00 01 00 00 00 05 00 0c |................ | 00000130 00 0d 00 00 00 01 00 0e 00 0f 00 01 00 09 00 00 |................ | 00000140 00 31 00 02 00 01 00 00 00 07 2a b4 00 02 04 60 |.1........ *... `| 00000150 ac 00 00 00 02 00 0a 00 00 00 06 00 01 00 00 00 |................ | 00000160 06 00 0b 00 00 00 0c 00 01 00 00 00 07 00 0c 00 |................ | 00000170 0d 00 00 00 01 00 10 00 00 00 02 00 11 |............. | 0000017dCopy the code

See the first four bytes on the first line are 0xcafebabe in hexadecimal, so the file type is indeed a.class file.

2. The version number

Bytes 5 and 6 are Minor versions, and bytes 7 and 8 are Major versions. Our major version number is 0x0034 (52).

JDK 1.6 =50 JDK 1.5 = 49 JDK 1.4 = 48 JDK 1.3 = 47 JDK 1.2 = 46 JDK 1.1 = 45

You can see that I’m using Java 8-compiled code.

3. The constant pool

Let’s continue with the first line of the binary:

00000000 ca fe ba be 00 00 00 34 00 16 0a 00 04 00 12 09 |....... 4... |Copy the code

After the major version number 0x0034 is 0x0016, which represents the capacity of the constant pool. A constant pool can be thought of as a resource repository for Class files. The data structure contained in the constant pool looks like this:

cp_info {
    u1 tag;
    u1 info[];
}Copy the code

Each item in the constant pool contains a cp_INFO object starting with a tag that represents the constant type, and info has its own structure depending on the type. There are currently 14 constant types:

Constant Type Value
CONSTANT_Class 7
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_String 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
CONSTANT_MethodHandle 15
CONSTANT_MethodType 16
CONSTANT_InvokeDynamic 18

The above 0x0016 translates to 22 in decimal, so there are 21 constants in the constant pool. Since the index in the constant pool is counted from 1, the constant indexes range from 1 to 21.

00000000 ca fe ba be 00 00 00 34 00 16 0a 00 04 00 12 09 |....... 4... |Copy the code

CONSTANT_Methodref (tag = 0x0a, tag = 0x0a); Here you can refer to The official Oracle document The Class File Format.

CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}Copy the code

Since.class files are unspaced binaries, continue reading:

  • tag: 0x0aCONSTANT_Methodref, as mentioned above
  • Class_index: points to a constant of type CONSTANT_Class_info in the constant pool, representing the name of the method above
  • Name_and_type_index: refers to the CONSTANT_NameAndType_info constant in the constant pool and is a description of the method

Since class_index is two bytes, 0x0004, or 4, points to the fourth constant in the constant pool, and name_AND_type_index is 0x0012, which points to the 18th constant. Constants 4 and 18 will be analyzed later.

Read on until you get to the end of the first line, which is 0x09, indicating CONSTANT_Fieldref, which indicates the following definition of a field, in the official documentation, in the format:

CONSTANT_Fieldref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}Copy the code

The structure is the same as CONSTANT_Methodref_info, at which point the second line is read:

00000010 00 03 00 13 07 00 14 07 00 15 01 00 01 6d 01 00 |............. m.. |Copy the code

Class_index is 0x0003, pointing to the third constant, and name_AND_type_index is 0x0013, pointing to the 13th constant. At this point, I continue reading until I reach the third constant. A constant of this type represents a symbolic reference to a class or interface. The structure of the CONSTANT_Class is as follows:

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}Copy the code

Tag is 7, name_index is 0x0014, and decimal is 20, pointing to the 20th constant, so we’ve read many bytes. However, it is very tiring to parse. Fortunately, Java comes with javap tools that can help us analyze the content of bytecode. Execute the following statement:

javap -verbose TestClass.classCopy the code

We can get:

Last modified Nov 14, 2017; size 381 bytes
  MD5 checksum 102d643185c4823ef103931ff3e34462
  Compiled from "TestClass.java"
public class com.shuqing28.TestClass
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref #4.#18 // java/lang/Object."
      
       ":()V
      
   #2 = Fieldref #3.#19 // com/shuqing28/TestClass.m:I
   #3 = Class #20 // com/shuqing28/TestClass
   #4 = Class #21 // java/lang/Object
   #5 = Utf8 m
   #6 = Utf8 I
   #7 = Utf8 
      
   #8 = Utf8 ()V
   #9 = Utf8 Code
  #10 = Utf8 LineNumberTable
  #11 = Utf8 LocalVariableTable
  #12 = Utf8 this
  #13 = Utf8 Lcom/shuqing28/TestClass;
  #14 = Utf8 inc
  #15 = Utf8 ()I
  #16 = Utf8 SourceFile
  #17 = Utf8 TestClass.java
  #18 = NameAndType #7:#8 // "
      
       ":()V
      
  #19 = NameAndType #5:#6 // m:I
  #20 = Utf8 com/shuqing28/TestClass
  #21 = Utf8 java/lang/Object{ public com.shuqing28.TestClass(); descriptor: ()V flags: ACC_PUBLIC ... / / to omitCopy the code

Constant pool = Methodref (Methodref); class_index (Methodref); CONSTANT_Class (Methodref); Name_index is a constant of type CONSTANT_Utf8. Name_index is a constant of type CONSTANT_Utf8.

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}Copy the code

The first tag is 1, length indicates the length of the character array, and bytes[length] is a utF-8 encoded string that resolves to com/ shuqing28/testClass, the fully qualified name of the class.

Continuing back to the first Methodref constant, whose name_AND_type_index value is 18, continue to find the 18th constant, which is of type CONSTANT_NameAndType_info and represents information about a method:

CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}Copy the code

Name_index refers to the constant 7, #7 = Utf8

, is a CONSTANT_Utf8_info type, and its value is, this is the method name, descriptor_index refers to the constant 8, #8 = Utf8 ()V, is the description of the method, What this expression means will be explained below. So we can analyze all 21 constants one by one.

The Class file starts with a list of constants, followed by indexes that refer to constants in the previous constant pool to describe the entire Class definition. Just like we have a dictionary, we use the words in the dictionary to make our sentences, but the Class file has strict formatting rules, and the following content basically describes the contents of a Class in a fixed format, without spacing.

4. Access flags

The next two bytes after the constant pool end represent access_flags, which are used to identify access information about a Class or interface, including whether the Class is a Class or an interface, public, abstract, and final. The meanings of access tags are as follows:

Sign the name Flag values meaning
ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its package.
ACC_FINAL 0x0010 Declared final; no subclasses allowed.
ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the invokespecial instruction.
ACC_INTERFACE 0x0200 Is an interface, not a class.
ACC_ABSTRACT 0x0400 Declared abstract; must not be instantiated.
ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code.
ACC_ANNOTATION 0x2000 Declared as an annotation type.
ACC_ENUM 0x4000 Declared as an enum type.

TestClass is of type public and compiled with a compiler later than JDK1.2 (this value is true for all compiler later than JDK1.2). All flags are false. So access_flags values should be: 0 x0001 x0021 | 0 x0020 = 0. We find the last line of the constant pool:

000000e0 65 63 74 00 21 00 03 00 04 00 00 00 01 00 02 00 |ect.! . |Copy the code

65, 63, 74 correspond to ECT respectively, followed by 0x0021, which is consistent with our analysis results.

5. Class index, parent index, and interface index collection

Referring to the data structure of the ClassFile at the beginning of this article, these three are defined as:

    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];Copy the code

Both the class index and the superclass index are u2-type data, whereas the interface index gives the number of interfaces first, followed by an array of interfaces. These three values reveal the inheritance of a class.

000000e0 65 63 74 00 21 00 03 00 04 00 00 00 01 00 02 00 |ect.! . |Copy the code

#3 = Class #20 // com/ shuqing28/testclass #3 = Class #20 // com/ shuqing28/testclass The 20th constant is a CONSTANT_Utf8 variable with a value of com/ shuqing28/testclass, which represents the fully qualified name string of the class. #4 = Class #21 // Java /lang/Object and #21 // Java /lang/Object. Object is the parent of all classes. Next is 0x0000, so TestClass does not implement any interface.

6. Set of field tables

Field tables are used to describe variables declared in interfaces or classes. Fields include class-level variables as well as instance-level variables, but do not include local variables within methods. A Java field can include information about the field’s scope, whether it is an instance variable or a class variable, whether it is final, whether it is concurrently visible (volatile), whether it can be serialized (transient), and the field data type. The following is the specific structure of the field table:

field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}Copy the code

Access_flags can take the following values:

Sign the name Flag values meaning
ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its package.
ACC_PRIVATE 0x0002 Declared private; usable only within the defining class.
ACC_PROTECTED 0x0004 Declared protected; may be accessed within subclasses.
ACC_STATIC 0x0008 Declared static.
ACC_FINAL 0x0010 Declared final; never directly assigned to after object construction (JLS §17.5).
ACC_VOLATILE 0x0040 Declared volatile; cannot be cached.
ACC_TRANSIENT 0x0080 Declared transient; not written or read by a persistent object manager.
ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code.
ACC_ENUM 0x4000 Declared as an element of an enum.

Generally speaking, only one ACC_PUBLIC, ACC_PRIVATE, and ACC_PROTECTED flag can exist at most. The other flags are based on the nature of Java language itself.

After the access_flags flag are the two index values name_index and Descriptor_index, both indexes to the constant pool, representing the simple name of the field and the field and method descriptors, respectively.

Fully qualified names: the previously mentioned com/ shuqing28/testclass is a fully qualified name, which replaces all “.” in Java code with “/”, usually using “;”. At the end. Simple name: The name of a method or field without type or modifier, such as “inc” and “m” in the code above. A method descriptor describes the data type, the method’s argument list, and the return value. We know that in C++ when we overload a function, we actually change the name of the function to include arguments to the function, such as add(int x, int y), which might be Add_Int_Int when compiled, but in Java we use an uppercase character for basic data types, Object classes are represented by fully qualified names of L+ objects.

Description Identifier character meaning:

Identification character meaning
B byte
C char
D double
F float
I int
J long
S short
Z boolean
V void
L Object, such as Ljava/lang/Object

[[Java /lang/String, int[] is recorded as [I. When describing methods with descriptors, they are described in the order of the returned values in the argument list, which also needs to be enclosed in parentheses. For example, the “() V” mentioned above represents a method with an empty argument and a return value of void, i.e. the void inc() method in the code.

To do a more complicated one, int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, Int fromIndex), whose descriptor is ([CII[CIII) I.

Continuing with the binary code of the program we mentioned earlier:

000000e0 65 63 74 00 21 00 03 00 04 00 00 00 01 00 02 00 |ect.! . | 000000f0 05 00 06 00 00 00 02 00 01 00 07 00 08 00 01 00 |................ |Copy the code

In the previous section, we looked at 0x0000 in the first line, and then 0x01. This value actually represents the number of fields in the table. Our code contains only one field. #5 = Utf8 m, then descriptor_index (0x0006), access_private (0x0002), ACC_PRIVATE (#5 = Utf8 m), then descriptor_index (0x0006), #6 = Utf8 I private int m;

Generally, after decriptor_index, there is a set of attributes to store some additional information, with 0x0000 representing no attribute fields. Private static int m = 123; You may have a ConstantValue attribute that points to the ConstantValue 123.

7. Method table collection

The method table collection is very similar to the field table collection, with the same structure:

method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}Copy the code

There are just different options for accessing flags and property sheet collections. For example, access_flags has the following optional values:

Sign the name Flag values meaning
ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its package.
ACC_PRIVATE 0x0002 Declaredprivate; accessible only within the defining class.
ACC_PROTECTED 0x0004 Declaredprotected; may be accessed within subclasses.
ACC_STATIC 0x0008 Declaredstatic.
ACC_FINAL 0x0010 Declaredfinal; must not be overridden
ACC_SYNCHRONIZED 0x0020 Declaredsynchronized; invocation is wrapped by a monitor use.
ACC_BRIDGE 0x0040 A bridge method, generated by the compiler.
ACC_VARARGS 0x0080 Declared with variable number of arguments.
ACC_NATIVE 0x0100 Declarednative; implemented in a language other than Java.
ACC_ABSTRACT 0x0400 Declaredabstract; no implementation is provided.
ACC_STRICT 0x0800 Declaredstrictfp; floating-point mode is FP-strict.
ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code.

As you can see, Methods such as ACC_SYNCHRONIZED,ACC_NATIVE,ACC_STRICT and ACC_ABSTRACT are added, corresponding to synchronized, native, strictFP and abstract, which can only modify methods.

Now we can continue to analyze the binary code of our program.

000000f0 05 00 06 00 00 00 02 00 01 00 07 00 08 00 01 00 |................ | 00000100 09 00 00 00 2f 00 01 00 01 00 00 00 05 2a b7 00 |.... /... *.. |Copy the code

In the previous section we just parsed 0x0000 on line 000000f0, followed by 0x0002, which means there are two methods, and the next few bytes are

  • 0x0001The access tag is ACC_PUBLIC
  • 0x0007The: name index points to the 7th constant:
  • 0x0008The: descriptor index points to the eighth constant: ()V
  • 0x0001The: property has one
  • 0x0009The: property points to the ninth constant, Code

Now that we have the method definition, where is the method body? The answer is the last Code analyzed above. The next section looks at the various possibilities for property sheet collections.

8. Property sheet collection

Attribute_info has been mentioned several times before. Class files, field tables, and method tables can all carry their own set of attribute_info tables to describe information transferred from certain scenarios. Property lists are not strictly ordered, and any compiler implementing them can add their own property information as long as they do not duplicate existing property names. Here are some of the predefined properties:

The attribute name Use location meaning
SourceFile ClassFile Record the name of the source file
InnerClasses ClassFile Inner class list
EnclosingMethod ClassFile Inner classes have this property, which identifies the enclosing method of the class
SourceDebugExtension ClassFile Used to store additional debugging information. New in JDK1.6
BootstrapMethods ClassFile Bootstrap method qualifier for storing invokeddynamic instruction references, new in JDK1.7
ConstantValue field_info Constant value defined by the final keyword
Code method_info Bytecode instructions compiled into Java code
Exceptions method_info Method throws an exception
RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations method_info Specifying which parameters are and are not visible at runtime is new in JDK1.5
AnnotationDefault method_info Record the default value of the annotation class element, new in JDK1.5
MethodParameters method_info Logging method parameter information, such as their name, access level, new in JDK1.8
Synthetic ClassFile, field_info, method_info Presentation methods or fields are automatically generated by the compiler
Deprecated ClassFile, field_info, method_info Field declared as deprecated
Signature ClassFile, field_info, method_info In the Java language, the Signature attribute records generic Signature information for any class, interface, initializer, or member whose generic Signature contains a type variable or parameterized type. Because Java generics are implemented by erasure, this property is required to record relevant information in the generics to avoid signature confusion when type information is erased. JDK1.5 new in
RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations ClassFile, field_info, method_info Support for dynamic annotations, indicating which annotations are and are not visible at runtime, is new in JDK1.5
LineNumberTable Code The mapping of Java source line numbers to bytecode instructions
LocalVariableTable Code Method local variable description
LocalVariableTypeTable Code The use of characteristic signatures instead of descriptors was added in JDK1.5 to describe generic parameterized types after the introduction of generic syntax
StackMapTable Code A new Type Checker for checking and processing whether the local variables of a target method match the types required by the operation stack
RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations ClassFile, field_info, method_info, Code Records the visibility of annotations on runtime types, including the visibility of annotations on runtime type parameters

Here are some of the more important attributes:

Code attributes

Let’s start with the structure of the Code attribute:

Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1 code[code_length];
    u2 exception_table_length;
    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}Copy the code
  • Attribute_name_index: two bytes, pointing to the constant CONSTANT_Utf8_info, the name of the attribute, which is always “Code”.
  • Attribute_length: Indicates the length of the attribute value. Since attribute_name_index and attribute_length are 6 bytes, attribute_length is the length of the attribute list minus 6 bytes
  • Max_statck: The maximum depth of the operand stack that cannot be exceeded during method execution
  • max_locals: Storage space required by local variables. Max_locals unit is Slot, Slot is the smallest unit of virtual machine to a local variable distribution, for byte, char, and float, int, short, such as Boolean and returnAddress length less than 32-bit data types, occupies only a Slot, Data of 64 bytes, such as double and long, need to occupy two slots. Method parameters (including hiddenthis), exception handler parameters and local variables defined by the method body need to be stored in the local variable table. However, max_locals is not the sum of slots occupied by all local variables, because slots can be reused. When a variable goes out of scope, the slot is used by other local variables, and the compiler calculates max_locals based on the scope.
  • Code_length: Length of bytecode compiled by the compiler
  • code: A series of bytes used to store the bytecode instruction, each instruction is a type of u1 single-byte, when the virtual machine to read the bytes, you can know what instruction, know what is the instruction, knew instruction operands are needed, it is ok to continue to read, here is similar to the assembly, the scope of u1 is 0 ~ 255, can express 256 instructions. The Java Virtual Machine specification defines about 200 Instructions. See Instructions. I will write a blog about this later.
  • Exception_table_length: Specifies the length of the exception table
  • Exception_table: The exception table is not required for Code to exist, so the above length can also be 0. The exception table has four attributes, representing that if an exception of type catch_type occurs between start_PC and end_PC, it will jump to the line pointed to by handler_PC for processing.

Exceptions properties

The Exceptions attribute is at the same level as the Code attribute in the method table. Notice that unlike the Code table above, the Exceptions attribute lists the Exceptions that the method may throw. The structure of the Exceptions attribute table is:

Exceptions_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_exceptions;
    u2 exception_index_table[number_of_exceptions];
}Copy the code
  • Number_of_exceptions: Number of possible exceptions that can be thrown
  • Exception_index_table: Points to the index CONSTANT_Class_info in the constant pool

LineNumberTable properties

LineNumber is used to record the mapping between Java source code and bytecode line numbers. We can also use -g: None or -g: line to ungenerate this property when compiling code, but we can’t see line numbers or break points when debugging code.

The data structure of LineNumberTable is as follows:

LineNumberTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 line_number_table_length;
    {   u2 start_pc;
        u2 line_number;    
    } line_number_table[line_number_table_length];
}Copy the code

Let’s look at line_number_table, start_PC is the bytecode line number, and line_number is the Java source line number.

LocalVariableTable properties

The LocalVariableTable attribute is used to describe the relationship between variables in the LocalVariableTable in the stack frame and variables defined in the Java source code. We can also use -g: none or -g: Vars to ungenerate this attribute, but if it is cancelled, the IDE will replace the parameter names with arguments such as arg0 and arg1, resulting in unclear debugging. The data structure of LocalVariableTable is as follows:

LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {   u2 start_pc;
        u2 length;
        u2 name_index;
        u2 descriptor_index;
        u2 index;
    } local_variable_table[local_variable_table_length];
}Copy the code

Local_variable_table local_variable_table

  • Start_pc and length: represent the bytecode offset at the beginning of the life cycle of this local variable and the length of scope coverage, respectively
  • Name_index and Descriptor_index: Points to constants representing local variable names and local variable descriptors, respectively
  • Index: indicates the slot position of the local variable in the local variable table. If the variable is of type double or long, the two slots are index and index+1.

ConstantValue properties

ConstantValue is a fixed-length property that informs the VM to assign a static variable value if int x=3 is also defined. And the static int y = 3; For x, the assignment is done in the instance constructor

, while for static variables, the assignment is done in the class constructor

method or using the ConstantValue property. The current rule of the Javac compiler is that if there are both final and static modifiers, the ConstantValue property is used, which is initialized in < Clinit > when there is only static and the variable type is primitive or String.

InnerClasses attribute

If an inner class is defined in a class, the InnerClasses attribute is used to record the relationship between the inner class and the host. The data structure for InnerClasses is as follows:

InnerClasses_attribute { u2 attribute_name_index; u4 attribute_length; u2 number_of_classes; // Record how many inner classes {u2 inner_class_info_index; u2 outer_class_info_index; u2 inner_name_index; u2 inner_class_access_flags; } classes[number_of_classes]; }Copy the code

Outer_class_info_index points to the symbolic reference of the host class. Inner_name_index points to the name of the inner class, or 0 if it’s an anonymous inner class. Inner_class_access_flags is the access flag for the inner class, as shown in the following table:

Sign the name Flag values meaning
ACC_PUBLIC 0x0001 Marked or implicitly public in source.
ACC_PRIVATE 0x0002 Marked private in source.
ACC_PROTECTED 0x0004 Marked protected in source.
ACC_STATIC 0x0008 Marked or implicitly static in source.
ACC_FINAL 0x0010 Marked final in source.
ACC_INTERFACE 0x0200 Was an interface in source.
ACC_ABSTRACT 0x0400 Marked or implicitly abstract in source.
ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code.
ACC_ANNOTATION 0x2000 Declared as an annotation type.
ACC_ENUM 0x4000 Declared as an enum type.

There are other attributes that you can see in Resources if you want to know more about them.

References:

  1. Java Virtual Machine Specification
  2. Java Virtual Machine: Advanced JVM features and best practices