原创

初始化itable

在InstanceKlass::link_class_impl()方法中完成方法连接后会继续初始化vtable与itable,之前已经介绍过vtable与itable,并且在类解析过程中已经完成了大小的计算并且也为相关信息的存储开辟了对应的内存空间,也就是在InstanceKlass本身需要占用的内存空间之后紧接着存储vtable,vtable后接着存储itable。这一篇将介绍itable的初始化。在InstanceKlass::link_class_impl()方法中的调用语句如下:

klassItable* ki = this_oop->itable();
ki->initialize_itable(true, CHECK_false);

调用itable()方法及相关调用链上的方法的实现如下:


klassItable* InstanceKlass::itable() const {
  return new klassItable(instanceKlassHandle(this));
}

klassItable::klassItable(instanceKlassHandle klass) {
  _klass = klass;

  if (klass->itable_length() > 0) {
    itableOffsetEntry* offset_entry = (itableOffsetEntry*)klass->start_of_itable();
    if (offset_entry  != NULL && offset_entry->interface_klass() != NULL) { // Check that itable is initialized
      // First offset entry points to the first method_entry
      intptr_t* method_entry  = (intptr_t *)(((address)klass()) + offset_entry->offset());
      intptr_t* end         = klass->end_of_itable();

      _table_offset      = (intptr_t*)offset_entry - (intptr_t*)klass();
      _size_offset_table = (method_entry - ((intptr_t*)offset_entry)) / itableOffsetEntry::size();
      _size_method_table = (end - method_entry)                  / itableMethodEntry::size();
      assert(_table_offset >= 0 && _size_offset_table >= 0 && _size_method_table >= 0, "wrong computation");
      return;
    }
  }

  // The length of the itable was either zero, or it has not yet been initialized.
  _table_offset      = 0;
  _size_offset_table = 0;
  _size_method_table = 0;
}
intptr_t* start_of_itable() const        {
      return start_of_vtable() + align_object_offset(vtable_length());
}

intptr_t* end_of_itable() const          {
      return start_of_itable() + itable_length();
}

如上各个属性的说明如下图所示。
file

构造函数中根据现有的信息初始化了klassItable中的各个属性,这几个属性在之前已经介绍过,如下:

class klassItable : public ResourceObj {
 private:
  instanceKlassHandle  _klass;             // my klass
  int                  _table_offset;      // offset of start of itable data within klass (in words)
  int                  _size_offset_table; // size of offset table (in itableOffset entries)
  int                  _size_method_table; // size of methodtable (in itableMethodEntry entries)
  ...
}

接下来在在InstanceKlass::link_class_impl()方法中调用klassItable::initialize_itable()方法对itable进行初始化,如下:

// Initialization
void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
  if (_klass->is_interface()) {
    // This needs to go after vtable indices are assigned but
    // before implementors need to know the number of itable indices.
    assign_itable_indices_for_interface(_klass());
  }

  // Cannot be setup doing bootstrapping, interfaces don't have
  // itables, and klass with only ones entry have empty itables
  if (
      Universe::is_bootstrapping() ||
      _klass->is_interface() ||
      _klass->itable_length() == itableOffsetEntry::size()
  ){
      return;
  }

  // There's alway an extra itable entry so we can null-terminate it.
  guarantee(size_offset_table() >= 1, "too small");
  int num_interfaces = size_offset_table() - 1;
  if (num_interfaces > 0) {
    // Iterate through all interfaces
    int i;
    for(i = 0; i < num_interfaces; i++) {
      itableOffsetEntry* ioe = offset_entry(i);
      HandleMark hm(THREAD);
      KlassHandle interf_h (THREAD, ioe->interface_klass());
      assert(interf_h() != NULL && ioe->offset() != 0, "bad offset entry in itable");
      initialize_itable_for_interface(ioe->offset(), interf_h, checkconstraints, CHECK);
    }

  }
}

此方法调用的方法比较多,完成的逻辑也比较多,下面详细介绍。  

1、assign_itable_indices_for_interface()方法

如果当前处理的是接口,那么会调用klassItable::assign_itable_indices_for_interface()方法为接口中的方法指定itableEntry索引,方法的实现如下:

int klassItable::assign_itable_indices_for_interface(Klass* klass) {
  // an interface does not have an itable, but its methods need to be numbered
  Array<Method*>*  methods = InstanceKlass::cast(klass)->methods();
  int              nof_methods = methods->length();
  int              ime_num = 0;
  for (int i = 0; i < nof_methods; i++) {
    Method* m = methods->at(i);
    if (interface_method_needs_itable_index(m)) {
      assert(!m->is_final_method(), "no final interface methods");
      // If m is already assigned a vtable index, do not disturb it.
      if (!m->has_vtable_index()) { // 当_vtable_index>=0时,表示指定了vtable index
        assert(m->vtable_index() == Method::pending_itable_index, "set by initialize_vtable");
        m->set_itable_index(ime_num);
        // Progress to next itable entry
        ime_num++;
      }
    }
  }
  assert(ime_num == method_count_for_interface(klass), "proper sizing");
  return ime_num;
}


inline bool interface_method_needs_itable_index(Method* m) {
  if (m->is_static())
      return false;   // e.g., Stream.empty
  if (m->is_initializer())
      return false;   // <init> or <clinit>
  // If an interface redeclares a method from java.lang.Object,
  // it should already have a vtable index, don't touch it.
  // e.g., CharSequence.toString (from initialize_vtable)
  // if (m->has_vtable_index())  return false; // NO!
  return true;
}

对于需要itableEntry的方法来说,为其指定itable index。

2、initialize_itable_for_interface()方法

对于类实现的每个接口,调用klassItable::initialize_itable_for_interface()方法进行处理,如下:

void klassItable::initialize_itable_for_interface(int method_table_offset, KlassHandle interf_h, bool checkconstraints, TRAPS) {
  Array<Method*>* methods = InstanceKlass::cast(interf_h())->methods();
  int nof_methods = methods->length();
  HandleMark hm;
  assert(nof_methods > 0, "at least one method must exist for interface to be in vtable");
  Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader());

  int ime_count = method_count_for_interface(interf_h());
  for (int i = 0; i < nof_methods; i++) {
    Method* m = methods->at(i);
    methodHandle target;
    if (m->has_itable_index()) {
      // This search must match the runtime resolution, i.e. selection search for invokeinterface
      // to correctly enforce loader constraints for interface method inheritance
      LinkResolver::lookup_instance_method_in_klasses(target, _klass, m->name(), m->signature(), CHECK);
    }
    if (target == NULL || !target->is_public() || target->is_abstract()) {
      // Entry does not resolve. Leave it empty for AbstractMethodError.
        if (!(target == NULL) && !target->is_public()) {
          // Stuff an IllegalAccessError throwing method in there instead.
          itableOffsetEntry::method_entry(_klass(), method_table_offset)[m->itable_index()].
              initialize(Universe::throw_illegal_access_error());
        }
    } else {
      // ime may have moved during GC so recalculate address
      int ime_num = m->itable_index();
      assert(ime_num < ime_count, "oob");
      itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target());
    }
  }
}

int klassItable::method_count_for_interface(Klass* interf) {
  assert(interf->oop_is_instance(), "must be");
  assert(interf->is_interface(), "must be");
  Array<Method*>* methods = InstanceKlass::cast(interf)->methods();
  int nof_methods = methods->length();
  while (nof_methods > 0) {
    Method* m = methods->at(nof_methods-1);
    if (m->has_itable_index()) {
      int length = m->itable_index() + 1;
      return length;  // return the rightmost itable index, plus one
    }
    nof_methods -= 1;
  }
  // no methods have itable indices
  return 0;
}

遍历接口中的每个方法,如果方法指定了itable index,调用 LinkResolver::lookup_instance_method_in_klasses()方法进行处理,这个方法的实现如下:

// returns first instance method
// Looks up method in classes, then looks up local default methods
void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
  Method* result_oop = klass->uncached_lookup_method(name, signature);
  result = methodHandle(THREAD, result_oop);
  // 循环查找方法的接口实现
  while (!result.is_null() && result->is_static() && result->method_holder()->super() != NULL) {
    KlassHandle super_klass = KlassHandle(THREAD, result->method_holder()->super());
    result = methodHandle(THREAD, super_klass->uncached_lookup_method(name, signature));
  }

  // 当从拥有Itable的类或父类中找到接口中方法的实现时,result不为NULL,否则为NULL,这时候就要查找默认的方法了
  if (result.is_null()) {
    Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
    if (default_methods != NULL) {
      result = methodHandle(InstanceKlass::find_method(default_methods, name, signature));
      assert(result.is_null() || !result->is_static(), "static defaults not allowed");
    }
  }
}

在klassItable::initialize_itable_for_interface()方法中调用的initialize()方法的实现如下:  

// Initialize a itableMethodEntry
void itableMethodEntry::initialize(Method* m) {
  if (m == NULL)
      return;
  _method = m;
}

初始化itableMethodEntry类中定义的唯一属性_method。

正文到此结束