原创

解析Class文件之创建InstanceKlass对象

ClassFileParser::parseClassFile()方法会将解析Class文件的大部分结果保存到instanceKlass对象中。创建instanceKlass对象的代码如下:

int total_oop_map_size2 = InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count);

// ReferenceType是枚举类,定义如下:
/*enum ReferenceType {
      REF_NONE,      // Regular class
      REF_OTHER,     // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below
      REF_SOFT,      // Subclass of java/lang/ref/SoftReference
      REF_WEAK,      // Subclass of java/lang/ref/WeakReference
      REF_FINAL,     // Subclass of java/lang/ref/FinalReference
      REF_PHANTOM    // Subclass of java/lang/ref/PhantomReference
}; */
// Compute reference type
ReferenceType rt; // 与强引用、弱引用等有关
if (super_klass() == NULL) {
       rt = REF_NONE;
} else {
       rt = super_klass->reference_type();
}

// We can now create the basic Klass* for this klass
InstanceKlass*  skc = super_klass();
bool            isnotnull = !host_klass.is_null();
_klass = InstanceKlass::allocate_instance_klass(loader_data,
                                                    vtable_size,
                                                    itable_size,
                                                    info.static_field_size, // 注意 info.static_field_size 会被传进去,用于分配空间。
                                                    total_oop_map_size2,
                                                    rt,
                                                    access_flags,
                                                    name,
                                                    skc,
                            isnotnull,
                                                    CHECK_(nullHandle));
instanceKlassHandle   this_klass(THREAD, _klass);

调用InstanceKlass::allocate_instance_klass()方法创建InstanceKlass对象,需要传入itable与vtable的大小,另外还需要传入static_field_size与OopMapBlock。这些都是在创建相关对象时计算内存占用大小所必须的参数。方法的实现如下:


InstanceKlass* InstanceKlass::allocate_instance_klass(
    ClassLoaderData* loader_data,
    int           vtable_len,
    int           itable_len,
    int           static_field_size,
    int           nonstatic_oop_map_size,
    ReferenceType rt,
    AccessFlags   access_flags,
    Symbol*       name,
    Klass*        super_klass,
    bool          is_anonymous,
    TRAPS
){
  bool  isinterf = access_flags.is_interface();
  int   size = InstanceKlass::size(vtable_len,
                                 itable_len,
                                 nonstatic_oop_map_size,
                                 isinterf,
                                 is_anonymous);

  // Allocation
  InstanceKlass* ik;
  ///////////////////////////////////////////////////////////////////////
  if (rt == REF_NONE) {
    if (name == vmSymbols::java_lang_Class()) {
      ik = new (loader_data, size, THREAD) InstanceMirrorKlass(
                       vtable_len,
                       itable_len,
                       static_field_size,
                       nonstatic_oop_map_size,
                       rt,
                       access_flags,
                       is_anonymous);
    } else if (
          name == vmSymbols::java_lang_ClassLoader() ||
          (
             SystemDictionary::ClassLoader_klass_loaded() &&
             super_klass != NULL &&
             // ClassLoader_klass为java_lang_ClassLoader
             super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass())
          )
    ){
      ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(
                       vtable_len,
                       itable_len,
                       static_field_size,
                       nonstatic_oop_map_size,
                       rt,
                       access_flags,
                       is_anonymous);
    } else {
      // normal class
      ik = new (loader_data, size, THREAD) InstanceKlass(
                vtable_len, itable_len,
                static_field_size,
                nonstatic_oop_map_size,
                rt,
                access_flags,
                is_anonymous);
    }
  }
  ///////////////////////////////////////////////////////////////////////
  else {
    // reference klass
    ik = new (loader_data, size, THREAD) InstanceRefKlass(
                vtable_len, itable_len,
                static_field_size,
                nonstatic_oop_map_size,
                rt,
                access_flags,
                is_anonymous);
  }
  ///////////////////////////////////////////////////////////////////////

  // 添加所有类型到我们内部类加载器列表中,包括在根加载器中的类
  // Add all classes to our internal class loader list here,
  // including classes in the bootstrap (NULL) class loader.
  // loader_data的类型为ClassLoaderData*,通过ClassLoaderData中的_klasses保持通过InstanceKlass._next_link属性保持的列表
  loader_data->add_class(ik);
  return ik;
}

这个方法之前在介绍InstanceKlass对象时详细介绍过。

方法调用InstanceKlass::size()计算内存占用的大小,然后创建对应的C++对象来表示Java类型。

当rt等于REF_NONE时,也就是rt为非Reference类型时,会根据类名创建对应C++类的对象。Class类通过InstanceMirrorKlass对象表示、ClassLoader类或ClassLoader的子类通过InstanceClassLoaderKlass对象表示、普通类通过InstanceKlass对象表示。当rt不为REF_NONE时,也就是rt为Referece类型时,通过InstanceRefKlass对象来表示。这里只看InstanceKlass对象的创建过程,调用的构造函数如下:


InstanceKlass::InstanceKlass(
     int vtable_len,
     int itable_len,
     int static_field_size, // 注意这个静态变量大小的分配
     int nonstatic_oop_map_size,
     ReferenceType rt,
     AccessFlags access_flags,
     bool is_anonymous
) {
  No_Safepoint_Verifier no_safepoint; // until k becomes parsable
  bool tmp = access_flags.is_interface();
  int iksize = InstanceKlass::size(vtable_len,
                                   itable_len,
                                   nonstatic_oop_map_size,
                                   tmp,
                                   is_anonymous);

  set_vtable_length(vtable_len);
  set_itable_length(itable_len);
  set_static_field_size(static_field_size);
  set_nonstatic_oop_map_size(nonstatic_oop_map_size);
  set_access_flags(access_flags);
  _misc_flags = 0;  // initialize to zero
  set_is_anonymous(is_anonymous);
  assert(size() == iksize, "wrong size for object");

  // ...
  set_init_state(InstanceKlass::allocated);   // 注意在这里设置了类的状态为分配
  // ...

  // initialize the non-header words to zero
  intptr_t* p = (intptr_t*)this;
  for (int index = InstanceKlass::header_size(); index < iksize; index++) {
    p[index] = NULL_WORD;
  }

  // Set temporary value until parseClassFile updates it with the real instance size.
  jint tti = Klass::instance_layout_helper(0, true);
  set_layout_helper(tti);
}

可以看到在创建InstanceKlass时初始化了许多参数,也就是说解析Class文件的相关信息大多都会通过InstanceKlass等对象的属性保存起来,以支持虚拟机后续的运行。在构造函数中还需会将除header外的字初始化为NULL_WORD,将此类代表的Java类所创建出来的Java对象的大小初始化为0,后续会在parseClassFile()方法中更新这个值。

在创建instanceKlass实例时,通过向构造函数中传递一些参数来初始化相关参数,另外还会调用相关set方法来设置参数,重要的参数如下:

jint lh = Klass::instance_layout_helper(info.instance_size, false);
this_klass->set_layout_helper(lh);

// Not yet(还没有,还没): supers are done below to support the new subtype-checking fields
this_klass->set_class_loader_data(loader_data);
this_klass->set_nonstatic_field_size(info.nonstatic_field_size);
this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields);
this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]);
// 有对_local_interfaces与_transitive_interfaces等属性的设置逻辑
apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL);

if (has_final_method) {
  this_klass->set_has_final_method();
}
this_klass->copy_method_ordering(method_ordering, CHECK_NULL);
// The InstanceKlass::_methods_jmethod_ids cache
// is managed on the assumption that the initial cache
// size is equal to the number of methods in the class. If
// that changes, then InstanceKlass::idnum_can_increment()
// has to be changed accordingly.
this_klass->set_initial_method_idnum(methods->length());
this_klass->set_name(cp->klass_name_at(this_class_index));
if (is_anonymous()){  // I am well known to myself
  cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
}
this_klass->set_minor_version(minor_version);
this_klass->set_major_version(major_version);
this_klass->set_has_default_methods(has_default_methods);

// Set up Method*::intrinsic_id as soon as(一...就...) we know the names of methods.
// (We used to do this lazily, but now we query it in Rewriter,
// which is eagerly done for every method, so we might as well(也;同样) do it now,
// when everything is fresh in memory.)
if (Method::klass_id_for_intrinsics(this_klass()) != vmSymbols::NO_SID) {
  for (int j = 0; j < methods->length(); j++) {
     Method* md = methods->at(j);
     md->init_intrinsic_id();
  }
}

// ...

// Miranda methods
if ( (num_miranda_methods > 0) ||
     // if this class introduced new miranda methods or
     (
        super_klass.not_null() &&
        (super_klass->has_miranda_methods())
     )
     // super class exists and this class inherited miranda methods
){
   this_klass->set_has_miranda_methods(); // then set a flag
}

// Fill in information needed to compute superclasses.
Klass* sk = super_klass();
this_klass->initialize_supers(sk, CHECK_(nullHandle));

// Initialize itable offset tables
klassItable::setup_itable_offset_table(this_klass);

// Compute transitive closure(闭包) of interfaces this class implements
// Do final class setup
fill_oop_maps(this_klass,
        info.nonstatic_oop_map_count,
        info.nonstatic_oop_offsets,
        info.nonstatic_oop_counts);

// Fill in  has_finalizer/has_vanilla_constructor/layout_helper
set_precomputed_flags(this_klass);


// Allocate mirror and initialize static fields
java_lang_Class::create_mirror(this_klass, protection_domain, CHECK_(nullHandle));

这里我们看到了许多之前介绍过的点,比如initialize_supers()方法、klassItable::setup_itable_offset_table()方法、fill_oop_maps()方法等。另外也更新了_layout_helper中的值,将此类代表的Java类所创建的Java实例的大小更新为info.instance_size,这个值是在之前计算字段布局时计算出来的,这里不再介绍。

调用的create_mirror()方法的实现如下:


oop java_lang_Class::create_mirror(KlassHandle k, Handle protection_domain, TRAPS) {
  assert(k->java_mirror() == NULL, "should only assign mirror once");
  // ...

  // Class_klass has to be loaded because it is used to allocate the mirror.
  ////////////////////////////////////////////////////////////////////////////////
  if (SystemDictionary::Class_klass_loaded()) {
    // 注意 allocate_instance 内部会根据 k 中的信息,计算需要分配的空间,包含静态变量的大小。然后对 mirror 的空间进行分配。
    // Allocate mirror (java.lang.Class instance)
    InstanceMirrorKlass* imk = InstanceMirrorKlass::cast(SystemDictionary::Class_klass());
    Handle               mirror = imk->allocate_instance(k, CHECK_0); // 返回的是instanceOop对象

    // mirror是instanceOop对象,而mirror->klass()就是InstanceMirrorKlass*类型
    InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass()); // mk代表的是java.lang.Class类
    oop                  moop = mirror(); // moop代表的是java.lang.Class对象
    int                  sofc = mk->compute_static_oop_field_count(moop);
    java_lang_Class::set_static_oop_field_count(moop, sofc);

    // It might also have a component mirror.  This mirror must already exist.
    if (k->oop_is_array()) {       // 数组
      Handle comp_mirror;
      if (k->oop_is_typeArray()) { // 基本类型数组
        BasicType type = TypeArrayKlass::cast(k())->element_type();
        comp_mirror = Universe::java_mirror(type); // oop转换为Handle类型,会调用转换构造函数
      } else {                     // 对象类型数组
        assert(k->oop_is_objArray(), "Must be");
        Klass* element_klass = ObjArrayKlass::cast(k())->element_klass();
        assert(element_klass != NULL, "Must have an element klass");
        comp_mirror = element_klass->java_mirror(); // oop转换为Handle类型,会调用转换构造函数
      }
      assert(comp_mirror.not_null(), "must have a mirror");

      // Two-way link between the array klass and its component mirror:
      oop tmp = comp_mirror();
      ArrayKlass::cast(k())->set_component_mirror(tmp);
      set_array_klass(tmp, k());
    } else {
      assert(k->oop_is_instance(), "Must be");
      // ...
      // do_local_static_fields 会对静态字段进行初始化。 注意此是传入的函数指针表示的 initialize_static_field 函数,
      // do_local_static_fields 会在内部遍历所有静态字段,然后调用这个函数对他们进行初始化。
      // Initialize static fields
      InstanceKlass* ik = InstanceKlass::cast(k());
      ik->do_local_static_fields(&initialize_static_field, CHECK_NULL);
    }
    return mirror();
  }
  ////////////////////////////////////////////////////////////////////////////////
  else {
    if (fixup_mirror_list() == NULL) {
      GrowableArray<Klass*>* list = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Klass*>(40, true);
      set_fixup_mirror_list(list);
    }
    GrowableArray<Klass*>* list = fixup_mirror_list();
    Klass* kls = k();
    list->push(kls);
    return NULL;
  }
  ////////////////////////////////////////////////////////////////////////////////
}

由于任何一个Java类都有一个Class对象来表示,所以在创建了表示普通Java类的InstanceKlass对象后,还需要创建对应的InstanceOop对象(代表Class对象)。如果java.lang.Class类还没有被解析,则将相关信息暂时存储到数组中,后续在类解析后会做处理,处理逻辑和当前类处理java.lang.Class类被加载时的逻辑基本一致。

调用的InstanceMirrorKlass::allocate_instance()方法创建的表示java中java.lang.Class对象的instanceOop实例。实现如下:

instanceOop InstanceMirrorKlass::allocate_instance(KlassHandle k, TRAPS) {
  // Query before forming handle.
  int          size = instance_size(k);
  KlassHandle  h_k(THREAD, this);
  instanceOop  i = (instanceOop) CollectedHeap::Class_obj_allocate(h_k, size, k, CHECK_NULL);
  return i;
}

oop CollectedHeap::Class_obj_allocate(KlassHandle klass, int size, KlassHandle real_klass, TRAPS) {

  HeapWord* obj;
  obj = common_mem_allocate_init(real_klass, size, CHECK_NULL); // 分配内存并初始化为0

  assert(Universe::is_bootstrapping() || !((oop)obj)->is_array(), "must not be an array");
  oop mirror = (oop)obj;

  java_lang_Class::set_oop_size(mirror, size);

  // Setup indirections
  if (!real_klass.is_null()) {
    java_lang_Class::set_klass(mirror, real_klass());
    real_klass->set_java_mirror(mirror);  
  }

  return mirror;
}

创建出表示了java.lang.Class对象的oop实例后,设置到InstanceKlass实例的_java_mirror属性中,同时也设置oop的_klass属性。如果当前类表示数组,那么在java_lang_Class::create_mirror()方法中还会设置表示数组的ArrayKlass对象的_component_mirror属性,同时也会设置表示当前数组的Class对象的_array_klass属性。

如果当前类是普通类,那么调用do_local_static_fields()方法,这个方法的实现如下:

void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAPS) {
  instanceKlassHandle h_this(THREAD, this);
  do_local_static_fields_impl(h_this, f, CHECK);
}

void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) {
  instanceKlassHandle ikh = this_oop();
  for (JavaFieldStream fs(ikh); !fs.done(); fs.next()) {
    if (fs.access_flags().is_static()) { // 只处理静态字段,因为只有静态字段的值存储到Class对象中
       fieldDescriptor& fd = fs.field_descriptor();
       f(&fd, CHECK);
    }
  }
}

调用的initialize_static_field()函数如下:

static void initialize_static_field(fieldDescriptor* fd, TRAPS) {
  InstanceKlass* fh = fd->field_holder();
  oop       tmp = fh->java_mirror();
  Handle    mirror( THREAD,tmp );
  assert(mirror.not_null() && fd->is_static(), "just checking");
  if (fd->has_initial_value()) {
    BasicType t = fd->field_type();
    switch (t) {
      case T_BYTE:
        mirror()->byte_field_put(fd->offset(), fd->int_initial_value());
        break;
      case T_BOOLEAN:
        mirror()->bool_field_put(fd->offset(), fd->int_initial_value());
        break;
      case T_CHAR:
        mirror()->char_field_put(fd->offset(), fd->int_initial_value());
        break;
      case T_SHORT:
        mirror()->short_field_put(fd->offset(), fd->int_initial_value());
        break;
      case T_INT:
        mirror()->int_field_put(fd->offset(), fd->int_initial_value());
        break;
      case T_FLOAT:
        mirror()->float_field_put(fd->offset(), fd->float_initial_value());
        break;
      case T_DOUBLE:
        mirror()->double_field_put(fd->offset(), fd->double_initial_value());
        break;
      case T_LONG:{
        jlong offset = fd->offset();
        jlong vo = fd->long_initial_value();
        oop mr = mirror();
        mr->long_field_put(offset,vo);
        break;
      }
      case T_OBJECT:
        {
          oop string = fd->string_initial_value(CHECK);
          mirror()->obj_field_put(fd->offset(), string);
        }
        break;
      default:
        THROW_MSG(vmSymbols::java_lang_ClassFormatError(),"Illegal ConstantValue attribute in class file");
    }// end switch
  }
}

do_local_static_fields()函数会对静态字段进行初始化,注意此时传入的函数指针指向initialize_static_field()函数,do_local_static_fields()会在内部遍历所有静态字段,然后调用这个函数对他们进行初始化。 

正文到此结束