在ClassFileParser::parseClassFile()函数中会计算vtable和itable所需要的大小,因为vtable和itable是内嵌在Klass中的,parseClassFile()函数解析完Class文件后会创建instanceKlass来保存相关的信息,在创建instanceKlass时需要知道创建对象的大小,所以必须要把vtable和itable也计算出来。下面就来介绍一下vtable和itable大小的计算过程,这一篇只介绍vtable大小的计算过程,下一篇将介绍itable大小的计算过程。
在ClassFileParser::parseClassFile()函数中首先计算vtable的大小,如下:
// Size of Java vtable (in words) int vtable_size = 0; int itable_size = 0; int num_miranda_methods = 0; GrowableArray<Method*> all_mirandas(20); InstanceKlass* tmp = super_klass(); // 计算虚函数表的大小和mirandas方法的数量,这个虚函数表的值是什么时候进行填充的呢??? klassVtable::compute_vtable_size_and_num_mirandas( &vtable_size, &num_miranda_methods, &all_mirandas, tmp, methods, access_flags, class_loader, class_name, local_interfaces, CHECK_(nullHandle) );
调用方法时传递的methods就是调用parse_methods()方法后的返回值,数组中存储了类或接口中定义或声明的所有方法。
调用的compute_vtable_size_and_num_mirandas()方法的实现如下:
void klassVtable::compute_vtable_size_and_num_mirandas( int* vtable_length_ret, int* num_new_mirandas, GrowableArray<Method*>* all_mirandas, Klass* super, Array<Method*>* methods, AccessFlags class_flags, Handle classloader, Symbol* classname, Array<Klass*>* local_interfaces, TRAPS) { // set up default result values int vtable_length = 0; // start off with super's vtable length InstanceKlass* superklass = (InstanceKlass*)super; // 获取父类 vtable 的大小,并将当前类的 vtable 的大小设置为父类 vtable 的大小 vtable_length = super == NULL ? 0 : superklass->vtable_length(); // go thru each method in the methods table to see if it needs a new entry int len = methods->length(); for (int i = 0; i < len; i++) { methodHandle mh(THREAD, methods->at(i)); // 循环遍历当前 Java 类的每一个方法 ,调用 needs_new_vtable_entry()函数进行判断, // 如果判断的结果是 true ,则将 vtable 的大小增 1 if (needs_new_vtable_entry(mh, super, classloader, classname, class_flags, THREAD)) { vtable_length += vtableEntry::size(); // we need a new entry } } GrowableArray<Method*> new_mirandas(20); // compute the number of mirandas methods that must be added to the end get_mirandas(&new_mirandas, all_mirandas, super, methods, NULL, local_interfaces); *num_new_mirandas = new_mirandas.length(); // Interfaces do not need interface methods in their vtables // This includes miranda methods and during later processing, default methods if (!class_flags.is_interface()) { // 只有类才需要处理miranda方法,接口不需要处理 // 类的vtable大小要加上miranda方法的大小 vtable_length += *num_new_mirandas * vtableEntry::size(); } // 处理数组类时,其vtable_length应该等于Object的vtable_length,通常为5,因为Object中有5个方法需要动态绑定 if (Universe::is_bootstrapping() && vtable_length == 0) { // array classes don't have their superclass set correctly during bootstrapping vtable_length = Universe::base_vtable_size(); } *vtable_length_ret = vtable_length; }
vtable的大小通常都是由3部分计算得出:
父类vtable的大小+当前方法需要的vtable大小+mirandas需要的大小
下面会重点介绍needs_new_vtable_entry()方法和get_mirandas()方法,前一个方法对计算当前方法需要的vtable大小很重要,后一个方法是计算mirandas方法需要的大小。
1、needs_new_vtable_entry()方法
循环处理当前类中定义的方法,调用needs_new_vtable_entry()方法判断此方法是否需要新的vtable entry,因为有些方法可能不需要新的vtable entry,如重写父类方法时,当前类中的方法只需要更新拷贝自父类vtable中对应的vtable entry即可。调用的needs_new_entry()方法的实现如下:
源代码位置:hotspot/src/share/vm/oops/klassVtable.cpp // Find out if a method "m" with superclass "super", loader "classloader" and // name "classname" needs a new vtable entry. Let P be a class package defined // by "classloader" and "classname". // NOTE: The logic used here is very similar to the one used for computing // the vtables indices for a method. We cannot directly use that function because, // we allocate the InstanceKlass at load time, and that requires that the // superclass has been loaded. // However, the vtable entries are filled in at link time(在连接时才会被填充), and therefore // the superclass' vtable may not yet have been filled in. bool klassVtable::needs_new_vtable_entry(methodHandle target_method, Klass* super, Handle classloader, Symbol* classname, AccessFlags class_flags, TRAPS) { if (class_flags.is_interface()) { // 接口不需要vtable表 // Interfaces do not use vtables, so there is no point to assigning // a vtable index to any of their methods. If we refrain(克制; 节制; 避免;) from doing this, // we can use Method::_vtable_index to hold the itable index return false; } if (target_method->is_final_method(class_flags) || // final方法不需要一个新的entry // a final method never needs a new entry; final methods can be statically // resolved and they have to be present in the vtable only if they override // a super's method, in which case they re-use its entry ( target_method()->is_static() ) || // 静态方法不需要一个新的entry // static methods don't need to be in vtable ( target_method()->name() == vmSymbols::object_initializer_name() ) // <init>不会被动态绑定 // <init> is never called dynamically-bound ){ return false; } // Concrete interface methods do not need new entries, they override // abstract method entries using default inheritance rules if (target_method()->method_holder() != NULL && target_method()->method_holder()->is_interface() && !target_method()->is_abstract() ){ return false; } // we need a new entry if there is no superclass if (super == NULL) { return true; } // private methods in classes always have a new entry in the vtable // specification interpretation since classic has // private methods not overriding // JDK8 adds private methods in interfaces which require invokespecial if (target_method()->is_private()) { return true; } // 省略对miranda方法的判断逻辑 return true; // found no match; we need a new entry }
所有的私有方法都需要vtable entry。还有一类特殊的miranda方法也需要实现“晚绑定”,所以也会有vtable entry。miranda方法是为了解决早期HotSpot虚拟机的一个Bug,因为早期虚拟机在遍历Java类的方法时,只会遍历类及所有父类的方法,不会遍历Java类所实现的接口里的方法,这会导致一个问题,即如果Java类没有实现接口里的方法,那么接口中的方法将不会被遍历到。为了解决这个问题,Javac等前端编译器会向Java类中添加方法,这些方法就是miranda方法。举个例子如下:
public interface IA{ void test(); } public abstract class CA implements IA{ public CA(){ test(); } }
CA类实现了IA接口,但是并没有实现接口中定义的test()方法,源代码并没有任何问题,如果只遍历类及父类,那么是无法查找到test()方法的,所以早期的HotSpot需要Javac等编译器会为CA类合成一个miranda方法,如下:
public interface IA{ void test(); } public abstract class CA implements IA{ public CA(){ test(); } // miranda public abstract void test(); }
这样就解决了HotSpot不搜索接口的Bug。不过现在的虚拟机版本并不需要合成miranda方法(Class文件中不存在miranda方法),但是在填充类的vtable时,如果这个类实现的接口中有没有被实现的方法,那么仍然需要在vtable中新增vtable entry,其实也是起到了和之前一样的效果。
接着看needs_new_vtable_entry()方法中对miranda方法的判断逻辑,如下:
// search through the super class hierarchy to see if we need a new entry ResourceMark rm; Symbol* name = target_method()->name(); Symbol* signature = target_method()->signature(); Klass* k = super; Method* super_method = NULL; InstanceKlass *holder = NULL; Method* recheck_method = NULL; while (k != NULL) { // lookup through the hierarchy for a method with matching name and sign. super_method = InstanceKlass::cast(k)->lookup_method(name, signature); if (super_method == NULL) { break; // we still have to search for a matching miranda method } // get the class holding the matching method // make sure you use that class for is_override InstanceKlass* superk = super_method->method_holder(); // we want only instance method matches // pretend private methods are not in the super vtable // since we do override around them: e.g. a.m pub/b.m private/c.m pub, // ignore private, c.m pub does override a.m pub // For classes that were not javac'd together, we also do transitive overriding around // methods that have less accessibility if ( (!super_method->is_static()) && (!super_method->is_private()) ) { // super_method即不是静态也不是private的 if (superk->is_override(super_method, classloader, classname, THREAD)) { return false; // else keep looking for transitive overrides } } // Start with lookup result and continue to search up k = superk->super(); // haven't found an override match yet; continue to look } // end while // if the target method is public or protected it may have a matching // miranda method in the super, whose entry it should re-use. // Actually, to handle cases that javac would not generate, we need // this check for all access permissions. InstanceKlass *sk = InstanceKlass::cast(super); if (sk->has_miranda_methods()) { if (sk->lookup_method_in_all_interfaces(name, signature, false) != NULL) { return false; // found a matching miranda; we do not need a new entry } }
调用lookup_method()方法搜索父类中是否有匹配name和signature的方法。如果搜索到方法,那可能是重写的情况,在重写情况下不需要新为此方法增加vtableEntry,只需要更新即可;如果搜索不到也不一定说明需要一个新的vtableEntry,因为还有miranda方法的情况,当调用lookup_method_in_all_interfaces()方法搜索到相关方法时,表示不需要新的vtableEntry,举个例子如下:
interface IA { void test(); } abstract class CA implements IA{ } public abstract class MirandaTest extends CA { public abstract void test(); }
在处理MirandaTest类的test()方法时,从CA和Object父类中无法搜索到test()类,但是在处理CA时,由于CA类没有实现IA接口中的test()方法,所以CA类的vtable中含有代表test()方法的vtableEntry,那么MirandaTest类中的test()方法此时就不需要一个新的vtableEntry了,只需要更新即可,所以方法最终返回false。
方法中的lookup_method()的实现如下:
Method* lookup_method(Symbol* name, Symbol* signature) const { return uncached_lookup_method(name, signature); } // uncached_lookup_method searches both the local class methods array and all // superclasses methods arrays, skipping any overpass methods in superclasses. Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature) const { Klass* klass = const_cast<InstanceKlass*>(this); bool dont_ignore_overpasses = true; // For the class being searched, find its overpasses. while (klass != NULL) { Method* method = InstanceKlass::cast(klass)->find_method(name, signature); if ((method != NULL) && (dont_ignore_overpasses || !method->is_overpass())) { return method; } klass = InstanceKlass::cast(klass)->super(); dont_ignore_overpasses = false; // Ignore overpass methods in all superclasses. } return NULL; } // find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const { return InstanceKlass::find_method(methods(), name, signature); } // find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method(Array<Method*>* methods, Symbol* name, Symbol* signature) { int hit = find_method_index(methods, name, signature); return hit >= 0 ? methods->at(hit): NULL; }
其中的find_method_index()方法就是对methods进行二分算法来搜索名称为name和签名为signature的方法,这里不在介绍。
调用的is_override()方法的实现如下:
// Returns true iff super_method can be overridden by a method in targetclassname // See JSL 3rd edition 8.4.6.1 // Assumes name-signature match // "this" is InstanceKlass of super_method which must exist // note that the InstanceKlass of the method in the targetclassname has not always been created yet bool InstanceKlass::is_override(methodHandle super_method, Handle targetclassloader, Symbol* targetclassname, TRAPS) { // Private methods can not be overridden if (super_method->is_private()) { return false; } // If super method is accessible, then override if ((super_method->is_protected()) || (super_method->is_public())) { return true; } // Package-private methods are not inherited outside of package assert(super_method->is_package_private(), "must be package private"); return(is_same_class_package(targetclassloader(), targetclassname)); // 其中就是处理权限为default的方法 }
调用的lookup_method_in_all_interfaces()方法的实现如下:
// lookup a method in all the interfaces that this class implements // Do NOT return private or static methods, new in JDK8 which are not externally visible // They should only be found in the initial InterfaceMethodRef Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name, Symbol* signature, bool skip_default_methods) const { Array<Klass*>* all_ifs = transitive_interfaces(); int num_ifs = all_ifs->length(); InstanceKlass *ik = NULL; for (int i = 0; i < num_ifs; i++) { ik = InstanceKlass::cast(all_ifs->at(i)); Method* m = ik->lookup_method(name, signature); if (m != NULL && m->is_public() && !m->is_static() && (!skip_default_methods || !m->is_default_method())) { return m; } } return NULL; }
在函数中调用此方法时,skip_default_methods的值为false。逻辑实现比较简单,调用InstanceKlass类的lookup_method()方法查找接口中是否有名称为name、签名为signature的方法,如果查找到了public、非静态方法则直接返回,也就是说父类的vtable中已经存在了名称为name、签名为signature的方法的vtableEntry,所以当前类中并不再需要一个新的vtableEntry。
2、get_mirandas()方法
调用的get_mirandas()方法的实现如下:
void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas, Klass* super, Array<Method*>* class_methods, Array<Method*>* default_methods, Array<Klass*>* local_interfaces) { assert((new_mirandas->length() == 0) , "current mirandas must be 0"); // iterate thru the local interfaces looking for a miranda int num_local_ifs = local_interfaces->length(); for (int i = 0; i < num_local_ifs; i++) { InstanceKlass *ik = InstanceKlass::cast(local_interfaces->at(i)); add_new_mirandas_to_lists(new_mirandas, all_mirandas, ik->methods(), class_methods, default_methods, super); // iterate thru each local's super interfaces Array<Klass*>* super_ifs = ik->transitive_interfaces(); int num_super_ifs = super_ifs->length(); for (int j = 0; j < num_super_ifs; j++) { InstanceKlass *sik = InstanceKlass::cast(super_ifs->at(j)); add_new_mirandas_to_lists(new_mirandas, all_mirandas, sik->methods(), class_methods, default_methods, super); } } }
如上方法遍历当前类实现的接口以及接口所继承的所有接口,然后调用add_new_mirandas_to_lists()方法进行处理,此方法的实现如下:
// Scans current_interface_methods for miranda methods that do not // already appear in new_mirandas, or default methods, and are also not defined-and-non-private // in super (superclass). These mirandas are added to all_mirandas if it is // not null; in addition, those that are not duplicates of miranda methods // inherited by super from its interfaces are added to new_mirandas. // Thus, new_mirandas will be the set of mirandas that this class introduces, // all_mirandas will be the set of all mirandas applicable to this class // including all defined in superclasses. void klassVtable::add_new_mirandas_to_lists( GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas, Array<Method*>* current_interface_methods, Array<Method*>* class_methods, Array<Method*>* default_methods, Klass* super ){ // iterate thru the current interface's method to see if it a miranda int num_methods = current_interface_methods->length(); for (int i = 0; i < num_methods; i++) { Method* im = current_interface_methods->at(i); bool is_duplicate = false; int num_of_current_mirandas = new_mirandas->length(); // check for duplicate mirandas in different interfaces we implement for (int j = 0; j < num_of_current_mirandas; j++) { Method* miranda = new_mirandas->at(j); if ((im->name() == miranda->name()) && (im->signature() == miranda->signature()) ){ is_duplicate = true; break; } } if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable if (is_miranda(im, class_methods, default_methods, super)) { // is it a miranda at all? InstanceKlass *sk = InstanceKlass::cast(super); // check if it is a duplicate of a super's miranda if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), false) == NULL) { new_mirandas->append(im); } if (all_mirandas != NULL) { all_mirandas->append(im); } } } } // end for }
遍历当前类实现的接口(直接或间接)中定义的所有方法,如果这个方法还没有被判定为miranda方法(就是在new_mirandas数组中不存在),那么调用is_miranda()方法判断此方法是否为miranda()方法,如果是,那么还需要调用当前类的父类的lookup_method_in_all_interfaces()方法来进一步判断。举个例子如下:
interface IA { void test(); } abstract class CA implements IA{ }
在处理CA类时,由于CA实现的接口IA中的方法test()没有对应的实现,所以接口中定义的test()方法会添加到new_mirandas数组中,意思就是需要在当前CA类的vtable中添加对应的vtableEntry。再举个例子,如下:
interface IA { void test(); } abstract class CA implements IA{ } interface IB { void test(); } public abstract class MirandaTest extends CA implements IB{ }
如果当前类为MirandaTest,那么实现的IB接口中的test()方法没有对应的实现,但是并不一定会添加到new_mirandas数组中,所以也就意味着不一定会新增加vtableEntry,还需要调用lookup_method_in_all_interfaces()方法来判断,由于当前类的父类CA中已经有名称和签名都相等的test()方法对应的vtableEntry了,所以只需要重用此vtableEntry即可。
调用的is_miranda()方法的实现如下:
// check if a method is a miranda method, given a class's methods table, // its default_method table and its super // Miranda methods are calculated twice: // first: before vtable size calculation: including abstract and default // This is seen by default method creation // Second: recalculated during vtable initialization: only abstract // This is seen by link resolution and selection. // "miranda" means not static, not defined by this class. // private methods in interfaces do not belong in the miranda list. // the caller must make sure that the method belongs to an interface implemented by the class // Miranda methods only include public interface instance methods // Not private methods, not static methods, not default == concrete abstract // Miranda methods also do not include overpass methods in interfaces bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Array<Method*>* default_methods, Klass* super) { if (m->is_static() || m->is_private() || m->is_overpass()) { return false; } Symbol* name = m->name(); Symbol* signature = m->signature(); if (InstanceKlass::find_instance_method(class_methods, name, signature) == NULL) { // did not find it in the method table of the current class if ((default_methods == NULL) || InstanceKlass::find_method(default_methods, name, signature) == NULL) { // 当前类没有父类,那么接口中定义的方法肯定没有对应的实现,此接口中的方法是miranda方法 if (super == NULL) { // super doesn't exist return true; } // 需要从父类中找一个非静态的、名称为name、签名为signauture的方法,如果是静态方法,则 // 需要继续查找,因为静态方法不参与动态绑定,也就不需要判断是否重写与实现等特性 Method* mo = InstanceKlass::cast(super)->lookup_method(name, signature); while ( mo != NULL && mo->access_flags().is_static() && mo->method_holder() != NULL && mo->method_holder()->super() != NULL ){ mo = mo->method_holder()->super()->uncached_lookup_method(name, signature); } // 如果找不到或找到的是私有方法实现,那么说明接口中定义的方法没有对应的实现,此接口中的方法是miranda方法 if (mo == NULL || mo->access_flags().is_private() ) { // super class hierarchy does not implement it or protection is different return true; } } } return false; }
接口中的静态、私有等方法一定是非miranda方法,直接返回false。从class_methods数组中查找名称为name、签名为signature的方法,其中的class_methods就是当前分析的类中定义的所有方法,找不到说明没有实现对应的接口中定义的方法,有可能是miranda方法,需要继续进行判断。在判断miranda方法时传入的default_methods为NULL,所以需要继续从父类中判断。如果没有父类或父类中找不到对应的方法实现,那么方法会返回true,表示是miranda方法。
相关文章的链接如下:
1、在Ubuntu 16.04上编译OpenJDK8的源代码
13、类加载器
14、类的双亲委派机制
15、核心类的预装载
16、Java主类的装载
17、触发类的装载
18、类文件介绍
19、文件流
20、解析Class文件
21、常量池解析(1)
22、常量池解析(2)
23、字段解析(1)
24、字段解析之伪共享(2)
25、字段解析(3)
28、方法解析
29、klassVtable与klassItable类的介绍
作者持续维护的个人博客classloading.com。
关注公众号,有HotSpot源码剖析系列文章!