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

 

 

 

posted @ 2021-03-29 09:47  张艳涛&java  阅读(569)  评论(0编辑  收藏  举报