jvm源码解读--08 创建oop对象,将static静态变量放置在oop的96 offset处

时间:2022-03-27 02:12:45

之前分析的已经加载的.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

说的很清楚了,这个值需要是上述表格的中的类型

那就拿一个例子出来

jvm源码解读--08  创建oop对象,将static静态变量放置在oop的96 offset处

这个field 共有5个,这个是第三个.

那么分析:

  1. access_flags 是private static final
  2. 属性名字叫serialVersionUID,156是是常量池的索引
  3. descriptor_index  是J  那么解析出来就是LONG类型
  4. 有一个ConatantValue的属性
    1.  158 就是 ConatantValue
    2. attribte_length 必须是2
    3. 值的索引指向159,可以看到159是LONG类型的负数

jvm源码解读--08  创建oop对象,将static静态变量放置在oop的96 offset处

那么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));

这里就不粘贴源码了,附带参考书中的解释

jvm源码解读--08  创建oop对象,将static静态变量放置在oop的96 offset处

jvm源码解读--08  创建oop对象,将static静态变量放置在oop的96 offset处

这就清晰的过程,最后得到_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中的存储明天在说了