之前分析的已经加载的.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这个属性
TheConstantValue attribute has the following format:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
Theitems 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
Thevalue 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个,这个是第三个.
那么分析:
1、 access_flags是privatestaticfinal;
2、 属性名字叫serialVersionUID,156是是常量池的索引;
3、 descriptor_index是J那么解析出来就是LONG类型;
4、 有一个ConatantValue的属性;
1、 158就是 ConatantValue;
2、 attribte_length必须是2;
3、 值的索引指向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中的存储明天在说了