jvm源码解读--04 常量池 常量项的解析CONSTANT_Class_info
接上篇的继续
ConstantPool* constant_pool = ConstantPool::allocate(_loader_data, length, CHECK_(nullHandle)); _cp = constant_pool; // save in case of errors constantPoolHandle cp (THREAD, constant_pool); // parsing constant pool entries parse_constant_pool_entries(length, CHECK_(nullHandle));
分析橘色的
上面是一个构造方法
定义中是带宏的,先看gdb打印类 (gdb) ptype cp type = /* real type = constantPoolHandle */ class constantPoolHandle : public StackObj { private: ConstantPool *_value; Thread *_thread; protected: ConstantPool * obj(void) const; ConstantPool * non_null_obj(void) const; public: constantPoolHandle(void); constantPoolHandle(ConstantPool *); constantPoolHandle(Thread *, ConstantPool *); constantPoolHandle(const constantPoolHandle &); constantPoolHandle & operator=(const constantPoolHandle &); ~constantPoolHandle(); void remove(void); ConstantPool * operator()(void) const; ConstantPool * operator->(void) const; bool operator==(ConstantPool *) const; bool operator==(const constantPoolHandle &) const; bool is_null(void) const; bool not_null(void) const; }
接着看宏定义
在程序中是用宏定义的 DEF_METADATA_HANDLE_FN(constantPool, ConstantPool) 看下面的宏定义 // Constructors for metadata handles #define DEF_METADATA_HANDLE_FN(name, type) \\这里是初始化列表的构造方法, inline name##Handle::name##Handle(type* obj) : _value(obj), _thread(NULL) { if (obj != NULL) { \ assert(((Metadata*)obj)->is_valid(), "obj is valid"); \ _thread = Thread::current(); \ assert (_thread->is_in_stack((address)this), "not on stack?"); \ _thread->metadata_handles()->push((Metadata*)obj); \ } \ } \ inline name##Handle::name##Handle(Thread* thread, type* obj) : _value(obj), _thread(thread) { \ if (obj != NULL) { \ assert(((Metadata*)obj)->is_valid(), "obj is valid"); \ assert(_thread == Thread::current(), "thread must be current"); \ assert (_thread->is_in_stack((address)this), "not on stack?"); \ _thread->metadata_handles()->push((Metadata*)obj); \ } \ }
在看实际解析
(gdb) p cp $2 = (constantPoolHandle) { <StackObj> = {<AllocatedObj> = {_vptr.AllocatedObj = 0x7f2586b44390 <vtable for constantPoolHandle+16>}, <No data fields>}, _value = 0x7f2563800108, _thread = 0x7f258000b800}
接着进入的常量池条目解析
// parsing constant pool entries parse_constant_pool_entries(length, CHECK_(nullHandle)); //经典的 对象和指针 ClassFileStream* cfs0 = stream(); ClassFileStream cfs1 = *cfs0; ClassFileStream* cfs = &cfs1;
先提供些定义
enum { JVM_CONSTANT_Utf8 = 1, JVM_CONSTANT_Unicode, /* unused */ JVM_CONSTANT_Integer, // 3 JVM_CONSTANT_Float, // 4 JVM_CONSTANT_Long, JVM_CONSTANT_Double, JVM_CONSTANT_Class, JVM_CONSTANT_String, JVM_CONSTANT_Fieldref, JVM_CONSTANT_Methodref, JVM_CONSTANT_InterfaceMethodref, JVM_CONSTANT_NameAndType, JVM_CONSTANT_MethodHandle = 15, // JSR 292 JVM_CONSTANT_MethodType = 16, // JSR 292 //JVM_CONSTANT_(unused) = 17, // JSR 292 early drafts only JVM_CONSTANT_InvokeDynamic = 18, // JSR 292 JVM_CONSTANT_ExternalMax = 18 // Last tag found in classfiles };
还有
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
CONSTANT_MethodHandle_info {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index;
}
CONSTANT_InvokeDynamic_info {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
进入函数
// parsing Index 0 is unused for (int index = 1; index < length; index++) { // Each of the following case guarantees one more byte in the stream // for the following tag or the access_flags following constant pool, // so we don't need bounds-check for reading tag. u1 tag = cfs->get_u1_fast(); switch (tag) { case JVM_CONSTANT_Class : { cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); _cp->klass_index_at_put(index, name_index); } break; case JVM_CONSTANT_Fieldref : { cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); _cp->field_at_put(index, class_index, name_and_type_index); } break; .... }
蓝色的过程就是取出tag的值
看执行前
先看下cfs 对象 (gdb) p cfs $4 = (ClassFileStream *) 0x7f2587845460 (gdb) p * cfs $5 = (ClassFileStream) {<ResourceObj> = {<AllocatedObj> = {_vptr.AllocatedObj = 0x7f2586b588b0 <vtable for ClassFileStream+16>}, _allocation_t = {18446604274545437599, 0}}, _buffer_start = 0x7f258000ea28 "\312\376\272\276", _buffer_end = 0x7f258000f0ee "\253\253\253\253\253\253\253\253\253\253\260\210\265\206%\177", _current = 0x7f258000ea32 "\a", _source = 0x7f258006eb98 "/home/atzhang/atzhang/openjdksource/openjdk8/openjdk/build/linux-x86_64-normal-server-slowdebug/jdk/classes", _need_verify = false} (gdb) x/10x cfs->_current 0x7f258000ea32: 0x0a3a0007 0x3b000100 0x0012000a 0x3d000a3c 0x7f258000ea42: 0x000a3e00 0x083f0001 0x000a4000 0x0a410012 0x7f258000ea52: 0x43004200 0x0001000a
那么取出来u1 就是07
进入switch tag=7 对应的是
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
与下面的逻辑相应
case JVM_CONSTANT_Class : { cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); _cp->klass_index_at_put(index, name_index); }
取u2 =58 对应内存标注蓝色的0x3a
进入黄色函数之前的定义有
enum { // See jvm.h for shared JVM_CONSTANT_XXX tags // NOTE: replicated in SA in vm/agent/sun/jvm/hotspot/utilities/ConstantTag.java // Hotspot specific tags JVM_CONSTANT_Invalid = 0, // For bad value initialization JVM_CONSTANT_InternalMin = 100, // First implementation tag (aside from bad value of course) JVM_CONSTANT_UnresolvedClass = 100, // Temporary tag until actual use JVM_CONSTANT_ClassIndex = 101, // Temporary tag while constructing constant pool JVM_CONSTANT_StringIndex = 102, // Temporary tag while constructing constant pool JVM_CONSTANT_UnresolvedClassInError = 103, // Error tag due to resolution error JVM_CONSTANT_MethodHandleInError = 104, // Error tag due to resolution error JVM_CONSTANT_MethodTypeInError = 105, // Error tag due to resolution error JVM_CONSTANT_InternalMax = 105 // Last implementation tag };
进入黄色函数
// For temporary use while constructing constant pool void klass_index_at_put(int which, int name_index) { tag_at_put(which, JVM_CONSTANT_ClassIndex); *int_at_addr(which) = name_index; } void tag_at_put(int which, jbyte t) { tags()->at_put(which, t); } Array<u1>* tags() const { return _tags; } void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); _data[i] = x; }
能看到粉色函数是将tags数组索引为1的值设为了101 (JVM_CONSTANT_ClassIndex = 101)
使用内存验证
执行前 (gdb) x/10x _data 0x7f25638000ac: 0x00000000 0x00000000 0x00000000 0x00000000 0x7f25638000bc: 0x00000000 0x00000000 0x00000000 0x00000000 0x7f25638000cc: 0x00000000 0x00000000 执行后 (gdb) x/10x _tags._data 0x7f25638000ac: 0x00006500 0x00000000 0x00000000 0x00000000 0x7f25638000bc: 0x00000000 0x00000000 0x00000000 0x00000000 0x7f25638000cc: 0x00000000 0x00000000
进入灰色函数
jint* int_at_addr(int which) const { assert(is_within_bounds(which), "index out of bounds"); return (jint*) &base()[which]; } intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); }
解析这个,
//解释 (gdb) p this
//$16 = (const ConstantPool * const) 0x7f2563800108
这里要转换,转换为(char*)指针类型的做加法 + {sizeof(ConstantPool)=88} 就是加88个字节,要是 (long*)类型的加法就会+88*8 了
(gdb) p (jint*) &base()[0]
$20 = (jint *) 0x7f2563800160
(gdb) p (jint*) &base()[which]
$19 = (jint *) 0x7f2563800168 ,这里which等于1,所以移动了8位
实际实现的就是将index=58 存放到了0x7f2563800168,这个地方了,这个地方之前,内存分配的时候为87个变量每个变量分配了一个8字节的空间
那么就是将58 这个变量放到了那个地址中
内存情况
(gdb) p *0x7f2563800168 $21 = 0 执行后 (gdb) p *0x7f2563800168 $22 = 58