--- old/src/share/vm/oops/klassVtable.cpp 2013-08-19 07:39:06.000000000 -0400 +++ new/src/share/vm/oops/klassVtable.cpp 2013-08-19 07:39:06.000000000 -0400 @@ -111,7 +111,7 @@ } int klassVtable::index_of(Method* m, int len) const { - assert(m->vtable_index() >= 0, "do not ask this of non-vtable methods"); + assert(m->has_vtable_index(), "do not ask this of non-vtable methods"); return m->vtable_index(); } @@ -248,12 +248,6 @@ return superk; } -// Methods that are "effectively" final don't need vtable entries. -bool method_is_effectively_final( - AccessFlags klass_flags, methodHandle target) { - return target->is_final() || klass_flags.is_final() && !target->is_overpass(); -} - // Update child's copy of super vtable for overrides // OR return true if a new vtable entry is required // Only called for InstanceKlass's, i.e. not for arrays @@ -263,6 +257,7 @@ ResourceMark rm; bool allocate_new = true; assert(klass->oop_is_instance(), "must be InstanceKlass"); + assert(klass == target_method()->method_holder(), "caller resp."); // Initialize the method's vtable index to "nonvirtual". // If we allocate a vtable entry, we will update it to a non-negative number. @@ -273,11 +268,17 @@ return false; } - if (method_is_effectively_final(klass->access_flags(), target_method)) { + if (target_method->is_final_method(klass->access_flags())) { // 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 allocate_new = false; + } else if (klass->is_interface()) { + allocate_new = false; // see note below in needs_new_vtable_entry + // An interface never allocates new vtable slots, only inherits old ones. + // This method will either be assigned its own itable index later, + // or be assigned an inherited vtable index in the loop below. + target_method()->set_vtable_index(Method::pending_itable_index); } // we need a new entry if there is no superclass @@ -411,8 +412,14 @@ Symbol* classname, AccessFlags class_flags, TRAPS) { + if (class_flags.is_interface()) { + // 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 (method_is_effectively_final(class_flags, target_method) || + if (target_method->is_final_method(class_flags) || // 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 @@ -723,6 +730,12 @@ // Initialization void klassItable::initialize_itable(bool checkconstraints, TRAPS) { + if (_klass->is_interface()) { + // This needs to go after vtable indexes are assigned but + // before implementors need to know the number of itable indexes. + assign_itable_indexes_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() || @@ -754,45 +767,87 @@ } +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; // or + // Some methods might get assigned vtable indexes, but we cannot predict this. + //if (m->has_vtable_index()) return false; // e.g., CharSequence.toString (from initialize_vtable) + return true; +} + +int klassItable::assign_itable_indexes_for_interface(Klass* klass) { + // an interface does not have an itable, but its methods need to be numbered + if (TraceItables) tty->print_cr("%3d: Initializing itable for interface %s", ++initialize_count, + klass->name()->as_C_string()); + Array* 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()) { + 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; +} + +int klassItable::method_count_for_interface(Klass* interf) { + assert(interf->oop_is_instance(), "must be"); + assert(interf->is_interface(), "must be"); + Array* 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; +#ifdef ASSERT + while (nof_methods = 0) { + m = methods->at(--nof_methods); + assert(!m->has_itable_index() || m->itable_index() < length, ""); + } +#endif //ASSERT + return length; // return the rightmost itable index, plus one + } + nof_methods -= 1; + } + // no methods have itable indexes + return 0; +} + + void klassItable::initialize_itable_for_interface(int method_table_offset, KlassHandle interf_h, bool checkconstraints, TRAPS) { Array* methods = InstanceKlass::cast(interf_h())->methods(); int nof_methods = methods->length(); HandleMark hm; - KlassHandle klass = _klass; 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_num = 0; - - // Skip first Method* if it is a class initializer - int i = methods->at(0)->is_static_initializer() ? 1 : 0; - // m, method_name, method_signature, klass reset each loop so they - // don't need preserving across check_signature_loaders call - // methods needs a handle in case of gc from check_signature_loaders - for(; i < nof_methods; i++) { + int ime_count = method_count_for_interface(interf_h()); + for (int i = 0; i < nof_methods; i++) { Method* m = methods->at(i); - Symbol* method_name = m->name(); - Symbol* method_signature = m->signature(); - - // This is same code as in Linkresolver::lookup_instance_method_in_klasses - Method* target = klass->uncached_lookup_method(method_name, method_signature); - while (target != NULL && target->is_static()) { - // continue with recursive lookup through the superclass - Klass* super = target->method_holder()->super(); - target = (super == NULL) ? (Method*)NULL : super->uncached_lookup_method(method_name, method_signature); + methodHandle target; + if (m->has_itable_index()) { + LinkResolver::lookup_instance_method_in_klasses(target, _klass, m->name(), m->signature(), CHECK); } if (target == NULL || !target->is_public() || target->is_abstract()) { // Entry do not resolve. Leave it empty } else { // Entry did resolve, check loader constraints before initializing // if checkconstraints requested - methodHandle target_h (THREAD, target); // preserve across gc if (checkconstraints) { Handle method_holder_loader (THREAD, target->method_holder()->class_loader()); if (method_holder_loader() != interface_loader()) { ResourceMark rm(THREAD); Symbol* failed_type_symbol = - SystemDictionary::check_signature_loaders(method_signature, + SystemDictionary::check_signature_loaders(m->signature(), method_holder_loader, interface_loader, true, CHECK); @@ -803,9 +858,9 @@ "and the class loader (instance of %s) for interface " "%s have different Class objects for the type %s " "used in the signature"; - char* sig = target_h()->name_and_sig_as_C_string(); + char* sig = target()->name_and_sig_as_C_string(); const char* loader1 = SystemDictionary::loader_name(method_holder_loader()); - char* current = klass->name()->as_C_string(); + char* current = _klass->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(interface_loader()); char* iface = InstanceKlass::cast(interf_h())->name()->as_C_string(); char* failed_type_name = failed_type_symbol->as_C_string(); @@ -821,10 +876,10 @@ } // ime may have moved during GC so recalculate address - itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target_h()); + int ime_num = m->itable_index(); + assert(ime_num < ime_count, "oob"); + itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target()); } - // Progress to next entry - ime_num++; } } @@ -913,20 +968,22 @@ virtual void doit(Klass* intf, int method_count) = 0; }; -// Visit all interfaces with at-least one method (excluding ) +// Visit all interfaces with at least one itable method void visit_all_interfaces(Array* transitive_intf, InterfaceVisiterClosure *blk) { // Handle array argument for(int i = 0; i < transitive_intf->length(); i++) { Klass* intf = transitive_intf->at(i); assert(intf->is_interface(), "sanity check"); - // Find no. of methods excluding a - int method_count = InstanceKlass::cast(intf)->methods()->length(); - if (method_count > 0) { - Method* m = InstanceKlass::cast(intf)->methods()->at(0); - assert(m != NULL && m->is_method(), "sanity check"); - if (m->name() == vmSymbols::object_initializer_name()) { - method_count--; + // Find no. of itable methods + int method_count = 0; + // method_count = klassItable::method_count_for_interface(intf); + Array* methods = InstanceKlass::cast(intf)->methods(); + if (methods->length() > 0) { + for (int i = methods->length(); --i >= 0; ) { + if (interface_method_needs_itable_index(methods->at(i))) { + method_count++; + } } } @@ -1024,40 +1081,26 @@ } -// m must be a method in an interface -int klassItable::compute_itable_index(Method* m) { - InstanceKlass* intf = m->method_holder(); - assert(intf->is_interface(), "sanity check"); - Array* methods = intf->methods(); - int index = 0; - while(methods->at(index) != m) { - index++; - assert(index < methods->length(), "should find index for resolve_invoke"); - } - // Adjust for , which is left out of table if first method - if (methods->length() > 0 && methods->at(0)->is_static_initializer()) { - index--; - } - return index; -} - - -// inverse to compute_itable_index +// inverse to itable_index Method* klassItable::method_for_itable_index(Klass* intf, int itable_index) { assert(InstanceKlass::cast(intf)->is_interface(), "sanity check"); + assert(intf->verify_itable_index(itable_index), ""); Array* methods = InstanceKlass::cast(intf)->methods(); - int index = itable_index; - // Adjust for , which is left out of table if first method - if (methods->length() > 0 && methods->at(0)->is_static_initializer()) { - index++; - } - - if (itable_index < 0 || index >= methods->length()) + if (itable_index < 0 || itable_index >= method_count_for_interface(intf)) return NULL; // help caller defend against bad indexes + int index = itable_index; Method* m = methods->at(index); - assert(compute_itable_index(m) == itable_index, "correct inverse"); + int index2 = -1; + while (!m->has_itable_index() || + (index2 = m->itable_index()) != itable_index) { + assert(index2 < itable_index, "monotonic"); + if (++index == methods->length()) + return NULL; + m = methods->at(index); + } + assert(m->itable_index() == itable_index, "correct inverse"); return m; }