jvm源码解读--08 创建oop对象,将static静态变量放置在oop的96 offset处
之前分析的已经加载的.Class文件中都没有Static 静态变量,所以也就没这部分的解析,自己也是不懂hotspot 将静态变量放哪里去了,追踪源码之后,看清楚了整个套路,总体上来说,可以举例来说对于,java.lang.String的Class文件进行解析,String类有5个变量,其中有俩个静态变量
private final char value[]; private int hash; // Default to 0 private static final long serialVersionUID = -6849794470754667710L; private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable { // use serialVersionUID from JDK 1.2.2 for interoperability private static final long serialVersionUID = 8575799808933029326L; public int compare(String s1, String s2) { int n1 = s1.length(); int n2 = s2.length(); int min = Math.min(n1, n2); for (int i = 0; i < min; i++) { char c1 = s1.charAt(i); char c2 = s2.charAt(i); if (c1 != c2) { c1 = Character.toUpperCase(c1); c2 = Character.toUpperCase(c2); if (c1 != c2) { c1 = Character.toLowerCase(c1); c2 = Character.toLowerCase(c2); if (c1 != c2) { // No overflow because of numeric promotion return c1 - c2; } } } } return n1 - n2; } /** Replaces the de-serialized object. */ private Object readResolve() { return CASE_INSENSITIVE_ORDER; } }
看到了有5个成员变量
private final char value[]; private int hash; private static final long serialVersionUID = -6849794470754667710L; private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); 第5个是一个内部类 private static class CaseInsensitiveComparator
先补充好,常量池的解析Field这部分知识
先看jvm规范对于field的定义
The structure has the following format:
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Table 4.5-A. Field access and property flags
Flag Name Value Interpretation |
ACC_PUBLIC 0x0001 Declared public; may be accessed from outside itspackage. |
ACC_PRIVATE 0x0002 Declared private; usable only within the definingclass. |
ACC_PROTECTED 0x0004 Declared protected; may be accessed withinsubclasses. |
ACC_STATIC 0x0008 Declared static. |
ACC_FINAL 0x0010 Declared final; never directly assigned to afterobject construction (JLS §17.5). |
ACC_VOLATILE 0x0040 Declared volatile; cannot be cached. |
ACC_TRANSIENT 0x0080 Declared transient; not written or read by apersistent object manager. |
ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code. |
ACC_ENUM 0x4000 Declared as an element of an enum. |
对这四部分进行说明
-
access_flags
- 说明,这个是变量的访问标识符,包含了,public private static ,final,voliat等,已经组合
-
name_index
-
便是变量的名字,指向常量池
-
-
descriptor_index
- 表示变量的类型信息 如int long Object ,ArrayType 等,下边的表中列出来BCDIJLSZ[ 等
-
attributes_count
-
属性值
-
-
attribute_info attributes[attributes_count];
-
属性,这里主要介绍 ConstantValue这个属性
-
Table 4.3-A. Interpretation of field descriptors
FieldType term Type Interpretation |
B byte signed byte |
C char Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16 |
D double double-precision floating-point value |
F float single-precision floating-point value |
I int integer |
J long long integer |
L ClassName ; reference an instance of class ClassName |
S short signed short |
Z boolean true or false |
[ reference one array dimension |
ConstantValue这个属性
The ConstantValue attribute has the following format:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
The items of the ConstantValue_attribute structure are as follows:
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index
must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string"ConstantValue".
attribute_length
The value of the attribute_length item of a ConstantValue_attribute structure must be two.
constantvalue_index
The value of the constantvalue_index item must be a valid index intothe constant_pool table. The constant_pool entry at that index gives the
constant value represented by this attribute. The constant_pool entry must beof a type appropriate to the field, as specified in Table 4.7.2-A.
Table 4.7.2-A. Constant value attribute types
Field Type Entry Type |
long CONSTANT_Long |
float CONSTANT_Float |
double CONSTANT_Double |
int, short, char, byte, boolean CONSTANT_Integer |
String CONSTANT_String |
说的很清楚了,这个值需要是上述表格的中的类型
那就拿一个例子出来
这个field 共有5个,这个是第三个.
那么分析:
- access_flags 是private static final
- 属性名字叫serialVersionUID,156是是常量池的索引
- descriptor_index 是J 那么解析出来就是LONG类型
- 有一个ConatantValue的属性
- 158 就是 ConatantValue
- attribte_length 必须是2
- 值的索引指向159,可以看到159是LONG类型的负数
那么hotspot中如何解析的呢?
在classFileParse.cpp中 u2 java_fields_count = 0; // Fields (offsets are filled in later) FieldAllocationCount fac; Array<u2>* fields = parse_fields(class_name, access_flags.is_interface(), &fac, &java_fields_count, CHECK_(nullHandle));
这里就不粘贴源码了,附带参考书中的解释
这就清晰的过程,最后得到_short变得就是以下结构
$49 = {26, 156, 157, 159, 33, 0}
class FieldInfo VALUE_OBJ_CLASS_SPEC { enum FieldOffset { access_flags_offset = 0, name_index_offset = 1, signature_index_offset = 2, initval_index_offset = 3, low_packed_offset = 4, high_packed_offset = 5, field_slots = 6 }; private: u2 _shorts[field_slots]; }
解析的变量信息,那就解析一下子
Array<u2>* ClassFileParser::parse_fields(Symbol* class_name, bool is_interface, FieldAllocationCount *fac, u2* java_fields_count_ptr, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); *java_fields_count_ptr = length; int num_injected = 0; InjectedField* injected = JavaClasses::get_injected(class_name, &num_injected); int total_fields = length + num_injected; // The field array starts with tuples of shorts 说明field array 由 shorts类型的元组组成,每个分别是 // [access, name index, sig index, initial value index, byte offset]. // A generic signature slot only exists for field with generic // signature attribute. And the access flag is set with // JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE for that field. The generic // signature slots are at the end of the field array and after all // other fields data. // // f1: [access, name index, sig index, initial value index, low_offset, high_offset] // f2: [access, name index, sig index, initial value index, low_offset, high_offset] // ... // fn: [access, name index, sig index, initial value index, low_offset, high_offset] // [generic signature index] // [generic signature index] // ... // // Allocate a temporary resource array for field data. For each field, // a slot is reserved in the temporary array for the generic signature // index. After parsing all fields, the data are copied to a permanent // array and any unused slots will be discarded. ResourceMark rm(THREAD); u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, total_fields * (FieldInfo::field_slots + 1)); // The generic signature slots start after all other fields' data. int generic_signature_slot = total_fields * FieldInfo::field_slots; int num_generic_signature = 0; for (int n = 0; n < length; n++) { cfs->guarantee_more(8, CHECK_NULL); // access_flags, name_index, descriptor_index, attributes_count AccessFlags access_flags; jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS; verify_legal_field_modifiers(flags, is_interface, CHECK_NULL); access_flags.set_flags(flags); u2 name_index = cfs->get_u2_fast(); int cp_size = _cp->length(); check_property(valid_symbol_at(name_index), "Invalid constant pool index %u for field name in class file %s", name_index, CHECK_NULL); Symbol* name = _cp->symbol_at(name_index); verify_legal_field_name(name, CHECK_NULL); u2 signature_index = cfs->get_u2_fast(); check_property(valid_symbol_at(signature_index), "Invalid constant pool index %u for field signature in class file %s", signature_index, CHECK_NULL); Symbol* sig = _cp->symbol_at(signature_index); verify_legal_field_signature(name, sig, CHECK_NULL); u2 constantvalue_index = 0; bool is_synthetic = false; u2 generic_signature_index = 0; bool is_static = access_flags.is_static(); FieldAnnotationCollector parsed_annotations(_loader_data); u2 attributes_count = cfs->get_u2_fast(); if (attributes_count > 0) { parse_field_attributes(attributes_count, is_static, signature_index, &constantvalue_index, &is_synthetic, &generic_signature_index, &parsed_annotations, CHECK_NULL); if (parsed_annotations.field_annotations() != NULL) { if (_fields_annotations == NULL) { _fields_annotations = MetadataFactory::new_array<AnnotationArray*>( _loader_data, length, NULL, CHECK_NULL); } _fields_annotations->at_put(n, parsed_annotations.field_annotations()); parsed_annotations.set_field_annotations(NULL); } if (parsed_annotations.field_type_annotations() != NULL) { if (_fields_type_annotations == NULL) { _fields_type_annotations = MetadataFactory::new_array<AnnotationArray*>( _loader_data, length, NULL, CHECK_NULL); } _fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations()); parsed_annotations.set_field_type_annotations(NULL); } if (is_synthetic) { access_flags.set_is_synthetic(); } if (generic_signature_index != 0) { access_flags.set_field_has_generic_signature(); fa[generic_signature_slot] = generic_signature_index; generic_signature_slot ++; num_generic_signature ++; } } FieldInfo* field = FieldInfo::from_field_array(fa, n); field->initialize(access_flags.as_short(), name_index, signature_index, constantvalue_index);
那么进入 field->initialize
void initialize(u2 access_flags, u2 name_index, u2 signature_index, u2 initval_index) { _shorts[access_flags_offset] = access_flags; _shorts[name_index_offset] = name_index; _shorts[signature_index_offset] = signature_index; _shorts[initval_index_offset] = initval_index; _shorts[low_packed_offset] = 0; _shorts[high_packed_offset] = 0; }
上述就是,看initval_index这个就是初始值,就是默认值
最终的field其实是这个东西
(gdb) p _shorts
$20 = {18, 152, 153, 0, 0, 0}
BasicType type = _cp->basic_type_for_signature_at(signature_index);
获取变量值
转换
// Convert a char from a classfile signature to a BasicType inline BasicType char2type(char c) { switch( c ) { case 'B': return T_BYTE; case 'C': return T_CHAR; case 'D': return T_DOUBLE; case 'F': return T_FLOAT; case 'I': return T_INT; case 'J': return T_LONG; case 'S': return T_SHORT; case 'Z': return T_BOOLEAN; case 'V': return T_VOID; case 'L': return T_OBJECT; case '[': return T_ARRAY; } return T_ILLEGAL; }
计算每种类型的变量总量
// Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(is_static, type); FieldAllocationType update(bool is_static, BasicType type) { FieldAllocationType atype = basic_type_to_atype(is_static, type); // Make sure there is no overflow with injected fields. assert(count[atype] < 0xFFFF, "More than 65535 fields"); count[atype]++; return atype; }
查看
(gdb) p atype
$21 = NONSTATIC_OOP
void set_allocation_type(int type) { //type=5 u2 lo = _shorts[low_packed_offset]; switch(lo & FIELDINFO_TAG_MASK) { case FIELDINFO_TAG_BLANK: _shorts[low_packed_offset] = ((type << FIELDINFO_TAG_SIZE)) & 0xFFFF; _shorts[low_packed_offset] &= ~FIELDINFO_TAG_MASK; _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_PLAIN; return; }
(gdb) p _shorts
$22 = {18, 152, 153, 0, 22, 0}
看出来将第5位置设置为0到22 即为0x16
那么
// Packed field has the tag, and can be either of: // hi bits <--------------------------- lo bits // |---------high---------|---------low---------| // ..........................................00 - blank // [------------------offset----------------]01 - real field offset // ......................[-------type-------]10 - plain field with type // [--contention_group--][-------type-------]11 - contended field with type and contention group
二进制为10110 那么这个就解析为 plain field with type, 这个5 就是
(gdb) p atype
$21 = NONSTATIC_OOP
enum FieldAllocationType { STATIC_OOP, // Oops STATIC_BYTE, // Boolean, Byte, char STATIC_SHORT, // shorts STATIC_WORD, // ints STATIC_DOUBLE, // aligned long or double NONSTATIC_OOP, NONSTATIC_BYTE, NONSTATIC_SHORT, NONSTATIC_WORD, NONSTATIC_DOUBLE, MAX_FIELD_ALLOCATION_TYPE, BAD_ALLOCATION_TYPE = -1 };
这就存在一个转换过程
FieldAllocationType atype = fac->update(is_static, type); FieldAllocationType update(bool is_static, BasicType type) { FieldAllocationType atype = basic_type_to_atype(is_static, type); // Make sure there is no overflow with injected fields. assert(count[atype] < 0xFFFF, "More than 65535 fields"); count[atype]++; return atype; } static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) { assert(type >= T_BOOLEAN && type < T_VOID, "only allowable values"); FieldAllocationType result = _basic_type_to_atype[type + (is_static ? (T_CONFLICT + 1) : 0)]; assert(result != BAD_ALLOCATION_TYPE, "bad type"); return result; } static FieldAllocationType _basic_type_to_atype[2 * (T_CONFLICT + 1)] = { BAD_ALLOCATION_TYPE, // 0 BAD_ALLOCATION_TYPE, // 1 BAD_ALLOCATION_TYPE, // 2 BAD_ALLOCATION_TYPE, // 3 NONSTATIC_BYTE , // T_BOOLEAN = 4, NONSTATIC_SHORT, // T_CHAR = 5, NONSTATIC_WORD, // T_FLOAT = 6, NONSTATIC_DOUBLE, // T_DOUBLE = 7, NONSTATIC_BYTE, // T_BYTE = 8, NONSTATIC_SHORT, // T_SHORT = 9, NONSTATIC_WORD, // T_INT = 10, NONSTATIC_DOUBLE, // T_LONG = 11, NONSTATIC_OOP, // T_OBJECT = 12, NONSTATIC_OOP, // T_ARRAY = 13, BAD_ALLOCATION_TYPE, // T_VOID = 14, BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, BAD_ALLOCATION_TYPE, // T_METADATA = 17, BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, BAD_ALLOCATION_TYPE, // 0 BAD_ALLOCATION_TYPE, // 1 BAD_ALLOCATION_TYPE, // 2 BAD_ALLOCATION_TYPE, // 3 STATIC_BYTE , // T_BOOLEAN = 4, STATIC_SHORT, // T_CHAR = 5, STATIC_WORD, // T_FLOAT = 6, STATIC_DOUBLE, // T_DOUBLE = 7, STATIC_BYTE, // T_BYTE = 8, STATIC_SHORT, // T_SHORT = 9, STATIC_WORD, // T_INT = 10, STATIC_DOUBLE, // T_LONG = 11, STATIC_OOP, // T_OBJECT = 12, STATIC_OOP, // T_ARRAY = 13, BAD_ALLOCATION_TYPE, // T_VOID = 14, BAD_ALLOCATION_TYPE, // T_ADDRESS = 15, BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16, BAD_ALLOCATION_TYPE, // T_METADATA = 17, BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18, BAD_ALLOCATION_TYPE, // T_CONFLICT = 19, };
完成了第一个变量的解析,现在执行到第三变量的解析 serialVersionUID ,他比前两个多了一个常数属性,那么主要看这个常数的解析
if (attributes_count > 0) { parse_field_attributes(attributes_count, is_static, signature_index, &constantvalue_index, &is_synthetic, &generic_signature_index, &parsed_annotations, CHECK_NULL); ...}
再看
//主干 void ClassFileParser::parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, ClassFileParser::FieldAnnotationCollector* parsed_annotations, TRAPS) { ... *constantvalue_index_addr = constantvalue_index; *is_synthetic_addr = is_synthetic; *generic_signature_index_addr = generic_signature_index; ..}
接着就是初始化field变量
FieldInfo* field = FieldInfo::from_field_array(fa, n); field->initialize(access_flags.as_short(), name_index, signature_index, constantvalue_index);
标记的是将常数给赋值了的操作
今天先到这里,具体的解析在oop中的存储明天在说了