duke@435: /* jrose@1100: * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: #include "incls/_precompiled.incl" duke@435: #include "incls/_klassVtable.cpp.incl" duke@435: duke@435: inline instanceKlass* klassVtable::ik() const { duke@435: Klass* k = _klass()->klass_part(); duke@435: assert(k->oop_is_instance(), "not an instanceKlass"); duke@435: return (instanceKlass*)k; duke@435: } duke@435: duke@435: duke@435: // this function computes the vtable size (including the size needed for miranda duke@435: // methods) and the number of miranda methods in this class duke@435: // Note on Miranda methods: Let's say there is a class C that implements duke@435: // interface I. Let's say there is a method m in I that neither C nor any duke@435: // of its super classes implement (i.e there is no method of any access, with duke@435: // the same name and signature as m), then m is a Miranda method which is duke@435: // entered as a public abstract method in C's vtable. From then on it should duke@435: // treated as any other public method in C for method over-ride purposes. duke@435: void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length, duke@435: int &num_miranda_methods, duke@435: klassOop super, duke@435: objArrayOop methods, duke@435: AccessFlags class_flags, duke@435: oop classloader, duke@435: symbolOop classname, duke@435: objArrayOop local_interfaces duke@435: ) { duke@435: duke@435: No_Safepoint_Verifier nsv; duke@435: duke@435: // set up default result values duke@435: vtable_length = 0; duke@435: num_miranda_methods = 0; duke@435: duke@435: // start off with super's vtable length duke@435: instanceKlass* sk = (instanceKlass*)super->klass_part(); duke@435: vtable_length = super == NULL ? 0 : sk->vtable_length(); duke@435: duke@435: // go thru each method in the methods table to see if it needs a new entry duke@435: int len = methods->length(); duke@435: for (int i = 0; i < len; i++) { duke@435: assert(methods->obj_at(i)->is_method(), "must be a methodOop"); duke@435: methodOop m = methodOop(methods->obj_at(i)); duke@435: duke@435: if (needs_new_vtable_entry(m, super, classloader, classname, class_flags)) { duke@435: vtable_length += vtableEntry::size(); // we need a new entry duke@435: } duke@435: } duke@435: duke@435: // compute the number of mirandas methods that must be added to the end duke@435: num_miranda_methods = get_num_mirandas(super, methods, local_interfaces); duke@435: vtable_length += (num_miranda_methods * vtableEntry::size()); duke@435: duke@435: if (Universe::is_bootstrapping() && vtable_length == 0) { duke@435: // array classes don't have their superclass set correctly during duke@435: // bootstrapping duke@435: vtable_length = Universe::base_vtable_size(); duke@435: } duke@435: duke@435: if (super == NULL && !Universe::is_bootstrapping() && duke@435: vtable_length != Universe::base_vtable_size()) { duke@435: // Someone is attempting to redefine java.lang.Object incorrectly. The duke@435: // only way this should happen is from duke@435: // SystemDictionary::resolve_from_stream(), which will detect this later duke@435: // and throw a security exception. So don't assert here to let duke@435: // the exception occur. duke@435: vtable_length = Universe::base_vtable_size(); duke@435: } duke@435: assert(super != NULL || vtable_length == Universe::base_vtable_size(), duke@435: "bad vtable size for class Object"); duke@435: assert(vtable_length % vtableEntry::size() == 0, "bad vtable length"); duke@435: assert(vtable_length >= Universe::base_vtable_size(), "vtable too small"); duke@435: } duke@435: duke@435: int klassVtable::index_of(methodOop m, int len) const { duke@435: assert(m->vtable_index() >= 0, "do not ask this of non-vtable methods"); duke@435: return m->vtable_index(); duke@435: } duke@435: duke@435: int klassVtable::initialize_from_super(KlassHandle super) { duke@435: if (super.is_null()) { duke@435: return 0; duke@435: } else { duke@435: // copy methods from superKlass duke@435: // can't inherit from array class, so must be instanceKlass duke@435: assert(super->oop_is_instance(), "must be instance klass"); duke@435: instanceKlass* sk = (instanceKlass*)super()->klass_part(); duke@435: klassVtable* superVtable = sk->vtable(); duke@435: assert(superVtable->length() <= _length, "vtable too short"); duke@435: #ifdef ASSERT duke@435: superVtable->verify(tty, true); duke@435: #endif duke@435: superVtable->copy_vtable_to(table()); duke@435: #ifndef PRODUCT duke@435: if (PrintVtables && Verbose) { duke@435: tty->print_cr("copy vtable from %s to %s size %d", sk->internal_name(), klass()->internal_name(), _length); duke@435: } duke@435: #endif duke@435: return superVtable->length(); duke@435: } duke@435: } duke@435: duke@435: // Revised lookup semantics introduced 1.3 (Kestral beta) duke@435: void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) { duke@435: duke@435: // Note: Arrays can have intermediate array supers. Use java_super to skip them. duke@435: KlassHandle super (THREAD, klass()->java_super()); duke@435: int nofNewEntries = 0; duke@435: duke@435: duke@435: if (PrintVtables && !klass()->oop_is_array()) { duke@435: ResourceMark rm(THREAD); duke@435: tty->print_cr("Initializing: %s", _klass->name()->as_C_string()); duke@435: } duke@435: duke@435: #ifdef ASSERT duke@435: oop* end_of_obj = (oop*)_klass() + _klass()->size(); duke@435: oop* end_of_vtable = (oop*)&table()[_length]; duke@435: assert(end_of_vtable <= end_of_obj, "vtable extends beyond end"); duke@435: #endif duke@435: duke@435: if (Universe::is_bootstrapping()) { duke@435: // just clear everything duke@435: for (int i = 0; i < _length; i++) table()[i].clear(); duke@435: return; duke@435: } duke@435: duke@435: int super_vtable_len = initialize_from_super(super); duke@435: if (klass()->oop_is_array()) { duke@435: assert(super_vtable_len == _length, "arrays shouldn't introduce new methods"); duke@435: } else { duke@435: assert(_klass->oop_is_instance(), "must be instanceKlass"); duke@435: duke@435: objArrayHandle methods(THREAD, ik()->methods()); duke@435: int len = methods()->length(); duke@435: int initialized = super_vtable_len; duke@435: duke@435: // update_super_vtable can stop for gc - ensure using handles duke@435: for (int i = 0; i < len; i++) { duke@435: HandleMark hm(THREAD); duke@435: assert(methods()->obj_at(i)->is_method(), "must be a methodOop"); duke@435: methodHandle mh(THREAD, (methodOop)methods()->obj_at(i)); duke@435: duke@435: bool needs_new_entry = update_super_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK); duke@435: duke@435: if (needs_new_entry) { duke@435: put_method_at(mh(), initialized); duke@435: mh()->set_vtable_index(initialized); // set primary vtable index duke@435: initialized++; duke@435: } duke@435: } duke@435: duke@435: // add miranda methods; it will also update the value of initialized duke@435: fill_in_mirandas(initialized); duke@435: duke@435: // In class hierachieswhere the accesibility is not increasing (i.e., going from private -> duke@435: // package_private -> publicprotected), the vtable might actually be smaller than our initial duke@435: // calculation. duke@435: assert(initialized <= _length, "vtable initialization failed"); duke@435: for(;initialized < _length; initialized++) { duke@435: put_method_at(NULL, initialized); duke@435: } duke@435: NOT_PRODUCT(verify(tty, true)); duke@435: } duke@435: } duke@435: duke@435: // Interates through the vtables to find the broadest access level. This duke@435: // will always be monotomic for valid Java programs - but not neccesarily duke@435: // for incompatible class files. duke@435: klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) { duke@435: // This vtable is not implementing the specific method duke@435: if (i >= length()) return acc_private; duke@435: duke@435: // Compute AccessType for current method. public or protected we are done. duke@435: methodOop m = method_at(i); duke@435: if (m->is_protected() || m->is_public()) return acc_publicprotected; duke@435: duke@435: AccessType acc = m->is_package_private() ? acc_package_private : acc_private; duke@435: duke@435: // Compute AccessType for method in super classes duke@435: klassOop super = klass()->super(); duke@435: AccessType super_acc = (super != NULL) ? instanceKlass::cast(klass()->super())->vtable()->vtable_accessibility_at(i) duke@435: : acc_private; duke@435: duke@435: // Merge duke@435: return (AccessType)MAX2((int)acc, (int)super_acc); duke@435: } duke@435: duke@435: duke@435: // Update child's copy of super vtable for overrides duke@435: // OR return true if a new vtable entry is required duke@435: // Only called for instanceKlass's, i.e. not for arrays duke@435: // If that changed, could not use _klass as handle for klass duke@435: bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS) { duke@435: ResourceMark rm; duke@435: bool allocate_new = true; duke@435: assert(klass->oop_is_instance(), "must be instanceKlass"); duke@435: duke@435: // Initialize the method's vtable index to "nonvirtual". duke@435: // If we allocate a vtable entry, we will update it to a non-negative number. duke@435: target_method()->set_vtable_index(methodOopDesc::nonvirtual_vtable_index); duke@435: duke@435: // Static and methods are never in duke@435: if (target_method()->is_static() || target_method()->name() == vmSymbols::object_initializer_name()) { duke@435: return false; duke@435: } duke@435: duke@435: if (klass->is_final() || target_method()->is_final()) { duke@435: // a final method never needs a new entry; final methods can be statically duke@435: // resolved and they have to be present in the vtable only if they override duke@435: // a super's method, in which case they re-use its entry duke@435: allocate_new = false; duke@435: } duke@435: duke@435: // we need a new entry if there is no superclass duke@435: if (klass->super() == NULL) { duke@435: return allocate_new; duke@435: } duke@435: duke@435: // private methods always have a new entry in the vtable duke@435: if (target_method()->is_private()) { duke@435: return allocate_new; duke@435: } duke@435: duke@435: // search through the vtable and update overridden entries duke@435: // Since check_signature_loaders acquires SystemDictionary_lock duke@435: // which can block for gc, once we are in this loop, use handles, not duke@435: // unhandled oops unless they are reinitialized for each loop duke@435: // handles for name, signature, klass, target_method duke@435: // not for match_method, holder duke@435: duke@435: symbolHandle name(THREAD,target_method()->name()); duke@435: symbolHandle signature(THREAD,target_method()->signature()); duke@435: for(int i = 0; i < super_vtable_len; i++) { duke@435: methodOop match_method = method_at(i); duke@435: // Check if method name matches duke@435: if (match_method->name() == name() && match_method->signature() == signature()) { duke@435: duke@435: instanceKlass* holder = (THREAD, instanceKlass::cast(match_method->method_holder())); duke@435: duke@435: // Check if the match_method is accessable from current class duke@435: duke@435: bool same_package_init = false; duke@435: bool same_package_flag = false; duke@435: bool simple_match = match_method->is_public() || match_method->is_protected(); duke@435: if (!simple_match) { duke@435: same_package_init = true; duke@435: same_package_flag = holder->is_same_class_package(_klass->class_loader(), _klass->name()); duke@435: duke@435: simple_match = match_method->is_package_private() && same_package_flag; duke@435: } duke@435: // match_method is the superclass' method. Note we can't override duke@435: // and shouldn't access superclass' ACC_PRIVATE methods duke@435: // (although they have been copied into our vtable) duke@435: // A simple form of this statement is: duke@435: // if ( (match_method->is_public() || match_method->is_protected()) || duke@435: // (match_method->is_package_private() && holder->is_same_class_package(klass->class_loader(), klass->name()))) { duke@435: // duke@435: // The complexity is introduced it avoid recomputing 'is_same_class_package' which is expensive. duke@435: if (simple_match) { duke@435: // Check if target_method and match_method has same level of accessibility. The accesibility of the duke@435: // match method is the "most-general" visibility of all entries at it's particular vtable index for duke@435: // all superclasses. This check must be done before we override the current entry in the vtable. duke@435: AccessType at = vtable_accessibility_at(i); duke@435: bool same_access = false; duke@435: duke@435: if ( (at == acc_publicprotected && (target_method()->is_public() || target_method()->is_protected()) duke@435: || (at == acc_package_private && (target_method()->is_package_private() && duke@435: (( same_package_init && same_package_flag) || duke@435: (!same_package_init && holder->is_same_class_package(_klass->class_loader(), _klass->name()))))))) { duke@435: same_access = true; duke@435: } duke@435: duke@435: if (checkconstraints) { duke@435: // Override vtable entry if passes loader constraint check duke@435: // if loader constraint checking requested duke@435: // No need to visit his super, since he and his super duke@435: // have already made any needed loader constraints. duke@435: // Since loader constraints are transitive, it is enough duke@435: // to link to the first super, and we get all the others. duke@435: symbolHandle signature(THREAD, target_method()->signature()); duke@435: Handle this_loader(THREAD, _klass->class_loader()); duke@435: instanceKlassHandle super_klass(THREAD, _klass->super()); duke@435: Handle super_loader(THREAD, super_klass->class_loader()); duke@435: duke@435: if (this_loader() != super_loader()) { duke@435: ResourceMark rm(THREAD); duke@435: char* failed_type_name = duke@435: SystemDictionary::check_signature_loaders(signature, this_loader, duke@435: super_loader, true, duke@435: CHECK_(false)); duke@435: if (failed_type_name != NULL) { duke@435: const char* msg = "loader constraint violation: when resolving " duke@435: "overridden method \"%s\" the class loader (instance" duke@435: " of %s) of the current class, %s, and its superclass loader " duke@435: "(instance of %s), have different Class objects for the type " duke@435: "%s used in the signature"; duke@435: char* sig = target_method()->name_and_sig_as_C_string(); duke@435: const char* loader1 = SystemDictionary::loader_name(this_loader()); duke@435: char* current = _klass->name()->as_C_string(); duke@435: const char* loader2 = SystemDictionary::loader_name(super_loader()); duke@435: size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + duke@435: strlen(current) + strlen(loader2) + strlen(failed_type_name); duke@435: char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); duke@435: jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2, duke@435: failed_type_name); duke@435: THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false); duke@435: } duke@435: } duke@435: } duke@435: put_method_at(target_method(), i); duke@435: duke@435: duke@435: if (same_access) { duke@435: // target and match has same accessiblity - share entry duke@435: allocate_new = false; duke@435: target_method()->set_vtable_index(i); duke@435: #ifndef PRODUCT duke@435: if (PrintVtables && Verbose) { duke@435: AccessType targetacc; duke@435: if (target_method()->is_protected() || duke@435: target_method()->is_public()) { duke@435: targetacc = acc_publicprotected; duke@435: } else { duke@435: targetacc = target_method()->is_package_private() ? acc_package_private : acc_private; duke@435: } duke@435: tty->print_cr("overriding with %s::%s index %d, original flags: %x overriders flags: %x", duke@435: _klass->internal_name(), (target_method() != NULL) ? duke@435: target_method()->name()->as_C_string() : "", i, duke@435: at, targetacc); duke@435: } duke@435: #endif /*PRODUCT*/ duke@435: } else { duke@435: #ifndef PRODUCT duke@435: if (PrintVtables && Verbose) { duke@435: AccessType targetacc; duke@435: if (target_method()->is_protected() || duke@435: target_method()->is_public()) { duke@435: targetacc = acc_publicprotected; duke@435: } else { duke@435: targetacc = target_method()->is_package_private() ? acc_package_private : acc_private; duke@435: } duke@435: tty->print_cr("override %s %s::%s at index %d, original flags: %x overriders flags: %x", duke@435: allocate_new ? "+ new" : "only", duke@435: _klass->internal_name(), (target_method() != NULL) ? duke@435: target_method()->name()->as_C_string() : "", i, duke@435: at, targetacc); duke@435: } duke@435: #endif /*PRODUCT*/ duke@435: } duke@435: } duke@435: } duke@435: } duke@435: return allocate_new; duke@435: } duke@435: duke@435: duke@435: duke@435: void klassVtable::put_method_at(methodOop m, int index) { duke@435: assert(m->is_oop_or_null(), "Not an oop or null"); duke@435: #ifndef PRODUCT duke@435: if (PrintVtables && Verbose) { duke@435: tty->print_cr("adding %s::%s at index %d", _klass->internal_name(), duke@435: (m != NULL) ? m->name()->as_C_string() : "", index); duke@435: } duke@435: assert(unchecked_method_at(index)->is_oop_or_null(), "Not an oop or null"); duke@435: #endif duke@435: table()[index].set(m); duke@435: } duke@435: duke@435: // Find out if a method "m" with superclass "super", loader "classloader" and duke@435: // name "classname" needs a new vtable entry. Let P be a class package defined duke@435: // by "classloader" and "classname". duke@435: // NOTE: The logic used here is very similar to the one used for computing duke@435: // the vtables indices for a method. We cannot directly use that function because, duke@435: // when the Universe is boostrapping, a super's vtable might not be initialized. duke@435: bool klassVtable::needs_new_vtable_entry(methodOop target_method, duke@435: klassOop super, duke@435: oop classloader, duke@435: symbolOop classname, duke@435: AccessFlags class_flags) { duke@435: if ((class_flags.is_final() || target_method->is_final()) || duke@435: // a final method never needs a new entry; final methods can be statically duke@435: // resolved and they have to be present in the vtable only if they override duke@435: // a super's method, in which case they re-use its entry duke@435: (target_method->is_static()) || duke@435: // static methods don't need to be in vtable duke@435: (target_method->name() == vmSymbols::object_initializer_name()) duke@435: // is never called dynamically-bound duke@435: ) { duke@435: return false; duke@435: } duke@435: duke@435: // we need a new entry if there is no superclass duke@435: if (super == NULL) { duke@435: return true; duke@435: } duke@435: duke@435: // private methods always have a new entry in the vtable duke@435: if (target_method->is_private()) { duke@435: return true; duke@435: } duke@435: duke@435: // search through the super class hierarchy to see if we need duke@435: // a new entry duke@435: symbolOop name = target_method->name(); duke@435: symbolOop signature = target_method->signature(); duke@435: klassOop k = super; duke@435: methodOop match_method = NULL; duke@435: instanceKlass *holder = NULL; duke@435: while (k != NULL) { duke@435: // lookup through the hierarchy for a method with matching name and sign. duke@435: match_method = instanceKlass::cast(k)->lookup_method(name, signature); duke@435: if (match_method == NULL) { duke@435: break; // we still have to search for a matching miranda method duke@435: } duke@435: // get the class holding the matching method duke@435: holder = instanceKlass::cast(match_method->method_holder()); duke@435: duke@435: if (!match_method->is_static()) { // we want only instance method matches duke@435: if ((target_method->is_public() || target_method->is_protected()) && duke@435: (match_method->is_public() || match_method->is_protected())) { duke@435: // target and match are public/protected; we do not need a new entry duke@435: return false; duke@435: } duke@435: duke@435: if (target_method->is_package_private() && duke@435: match_method->is_package_private() && duke@435: holder->is_same_class_package(classloader, classname)) { duke@435: // target and match are P private; we do not need a new entry duke@435: return false; duke@435: } duke@435: } duke@435: duke@435: k = holder->super(); // haven't found a match yet; continue to look duke@435: } duke@435: duke@435: // if the target method is public or protected it may have a matching duke@435: // miranda method in the super, whose entry it should re-use. duke@435: if (target_method->is_public() || target_method->is_protected()) { duke@435: instanceKlass *sk = instanceKlass::cast(super); duke@435: if (sk->has_miranda_methods()) { duke@435: if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) { duke@435: return false; // found a matching miranda; we do not need a new entry duke@435: } duke@435: } duke@435: } duke@435: duke@435: return true; // found no match; we need a new entry duke@435: } duke@435: duke@435: // Support for miranda methods duke@435: duke@435: // get the vtable index of a miranda method with matching "name" and "signature" duke@435: int klassVtable::index_of_miranda(symbolOop name, symbolOop signature) { duke@435: // search from the bottom, might be faster duke@435: for (int i = (length() - 1); i >= 0; i--) { duke@435: methodOop m = table()[i].method(); duke@435: if (is_miranda_entry_at(i) && duke@435: m->name() == name && m->signature() == signature) { duke@435: return i; duke@435: } duke@435: } duke@435: return methodOopDesc::invalid_vtable_index; duke@435: } duke@435: duke@435: // check if an entry is miranda duke@435: bool klassVtable::is_miranda_entry_at(int i) { duke@435: methodOop m = method_at(i); duke@435: klassOop method_holder = m->method_holder(); duke@435: instanceKlass *mhk = instanceKlass::cast(method_holder); duke@435: duke@435: // miranda methods are interface methods in a class's vtable duke@435: if (mhk->is_interface()) { duke@435: assert(m->is_public() && m->is_abstract(), "should be public and abstract"); duke@435: assert(ik()->implements_interface(method_holder) , "this class should implement the interface"); duke@435: assert(is_miranda(m, ik()->methods(), ik()->super()), "should be a miranda_method"); duke@435: return true; duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: // check if a method is a miranda method, given a class's methods table and it's super duke@435: // the caller must make sure that the method belongs to an interface implemented by the class duke@435: bool klassVtable::is_miranda(methodOop m, objArrayOop class_methods, klassOop super) { duke@435: symbolOop name = m->name(); duke@435: symbolOop signature = m->signature(); duke@435: if (instanceKlass::find_method(class_methods, name, signature) == NULL) { duke@435: // did not find it in the method table of the current class duke@435: if (super == NULL) { duke@435: // super doesn't exist duke@435: return true; duke@435: } else { duke@435: if (instanceKlass::cast(super)->lookup_method(name, signature) == NULL) { duke@435: // super class hierarchy does not implement it duke@435: return true; duke@435: } duke@435: } duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: void klassVtable::add_new_mirandas_to_list(GrowableArray* list_of_current_mirandas, duke@435: objArrayOop current_interface_methods, duke@435: objArrayOop class_methods, duke@435: klassOop super) { duke@435: // iterate thru the current interface's method to see if it a miranda duke@435: int num_methods = current_interface_methods->length(); duke@435: for (int i = 0; i < num_methods; i++) { duke@435: methodOop im = methodOop(current_interface_methods->obj_at(i)); duke@435: bool is_duplicate = false; duke@435: int num_of_current_mirandas = list_of_current_mirandas->length(); duke@435: // check for duplicate mirandas in different interfaces we implement duke@435: for (int j = 0; j < num_of_current_mirandas; j++) { duke@435: methodOop miranda = list_of_current_mirandas->at(j); duke@435: if ((im->name() == miranda->name()) && duke@435: (im->signature() == miranda->signature())) { duke@435: is_duplicate = true; duke@435: break; duke@435: } duke@435: } duke@435: duke@435: if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable duke@435: if (is_miranda(im, class_methods, super)) { // is it a miranda at all? duke@435: instanceKlass *sk = instanceKlass::cast(super); duke@435: // check if it is a duplicate of a super's miranda duke@435: if (sk->lookup_method_in_all_interfaces(im->name(), im->signature()) == NULL) { duke@435: list_of_current_mirandas->append(im); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: } duke@435: duke@435: void klassVtable::get_mirandas(GrowableArray* mirandas, duke@435: klassOop super, objArrayOop class_methods, duke@435: objArrayOop local_interfaces) { duke@435: assert((mirandas->length() == 0) , "current mirandas must be 0"); duke@435: duke@435: // iterate thru the local interfaces looking for a miranda duke@435: int num_local_ifs = local_interfaces->length(); duke@435: for (int i = 0; i < num_local_ifs; i++) { duke@435: instanceKlass *ik = instanceKlass::cast(klassOop(local_interfaces->obj_at(i))); duke@435: add_new_mirandas_to_list(mirandas, ik->methods(), class_methods, super); duke@435: // iterate thru each local's super interfaces duke@435: objArrayOop super_ifs = ik->transitive_interfaces(); duke@435: int num_super_ifs = super_ifs->length(); duke@435: for (int j = 0; j < num_super_ifs; j++) { duke@435: instanceKlass *sik = instanceKlass::cast(klassOop(super_ifs->obj_at(j))); duke@435: add_new_mirandas_to_list(mirandas, sik->methods(), class_methods, super); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // get number of mirandas duke@435: int klassVtable::get_num_mirandas(klassOop super, objArrayOop class_methods, objArrayOop local_interfaces) { duke@435: ResourceMark rm; duke@435: GrowableArray* mirandas = new GrowableArray(20); duke@435: get_mirandas(mirandas, super, class_methods, local_interfaces); duke@435: return mirandas->length(); duke@435: } duke@435: duke@435: // fill in mirandas duke@435: void klassVtable::fill_in_mirandas(int& initialized) { duke@435: ResourceMark rm; duke@435: GrowableArray* mirandas = new GrowableArray(20); duke@435: instanceKlass *this_ik = ik(); duke@435: get_mirandas(mirandas, this_ik->super(), this_ik->methods(), this_ik->local_interfaces()); duke@435: int num_mirandas = mirandas->length(); duke@435: for (int i = 0; i < num_mirandas; i++) { duke@435: put_method_at(mirandas->at(i), initialized); duke@435: initialized++; duke@435: } duke@435: } duke@435: duke@435: void klassVtable::copy_vtable_to(vtableEntry* start) { duke@435: Copy::disjoint_words((HeapWord*)table(), (HeapWord*)start, _length * vtableEntry::size()); duke@435: } duke@435: duke@435: void klassVtable::adjust_method_entries(methodOop* old_methods, methodOop* new_methods, duke@435: int methods_length, bool * trace_name_printed) { duke@435: // search the vtable for uses of either obsolete or EMCP methods duke@435: for (int j = 0; j < methods_length; j++) { duke@435: methodOop old_method = old_methods[j]; duke@435: methodOop new_method = new_methods[j]; duke@435: duke@435: // In the vast majority of cases we could get the vtable index duke@435: // by using: old_method->vtable_index() duke@435: // However, there are rare cases, eg. sun.awt.X11.XDecoratedPeer.getX() duke@435: // in sun.awt.X11.XFramePeer where methods occur more than once in the duke@435: // vtable, so, alas, we must do an exhaustive search. duke@435: for (int index = 0; index < length(); index++) { duke@435: if (unchecked_method_at(index) == old_method) { duke@435: put_method_at(new_method, index); duke@435: duke@435: if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { duke@435: if (!(*trace_name_printed)) { duke@435: // RC_TRACE_MESG macro has an embedded ResourceMark duke@435: RC_TRACE_MESG(("adjust: name=%s", duke@435: Klass::cast(old_method->method_holder())->external_name())); duke@435: *trace_name_printed = true; duke@435: } duke@435: // RC_TRACE macro has an embedded ResourceMark duke@435: RC_TRACE(0x00100000, ("vtable method update: %s(%s)", duke@435: new_method->name()->as_C_string(), duke@435: new_method->signature()->as_C_string())); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: // Garbage collection duke@435: void klassVtable::oop_follow_contents() { duke@435: int len = length(); duke@435: for (int i = 0; i < len; i++) { duke@435: MarkSweep::mark_and_push(adr_method_at(i)); duke@435: } duke@435: } duke@435: duke@435: #ifndef SERIALGC duke@435: void klassVtable::oop_follow_contents(ParCompactionManager* cm) { duke@435: int len = length(); duke@435: for (int i = 0; i < len; i++) { duke@435: PSParallelCompact::mark_and_push(cm, adr_method_at(i)); duke@435: } duke@435: } duke@435: #endif // SERIALGC duke@435: duke@435: void klassVtable::oop_adjust_pointers() { duke@435: int len = length(); duke@435: for (int i = 0; i < len; i++) { duke@435: MarkSweep::adjust_pointer(adr_method_at(i)); duke@435: } duke@435: } duke@435: duke@435: #ifndef SERIALGC duke@435: void klassVtable::oop_update_pointers(ParCompactionManager* cm) { duke@435: const int n = length(); duke@435: for (int i = 0; i < n; i++) { duke@435: PSParallelCompact::adjust_pointer(adr_method_at(i)); duke@435: } duke@435: } duke@435: duke@435: void klassVtable::oop_update_pointers(ParCompactionManager* cm, duke@435: HeapWord* beg_addr, HeapWord* end_addr) { duke@435: const int n = length(); duke@435: const int entry_size = vtableEntry::size(); duke@435: duke@435: int beg_idx = 0; duke@435: HeapWord* const method_0 = (HeapWord*)adr_method_at(0); duke@435: if (beg_addr > method_0) { duke@435: // it's safe to use cast, as we have guarantees on vtable size to be sane duke@435: beg_idx = int((pointer_delta(beg_addr, method_0) + entry_size - 1) / entry_size); duke@435: } duke@435: duke@435: oop* const beg_oop = adr_method_at(beg_idx); duke@435: oop* const end_oop = MIN2((oop*)end_addr, adr_method_at(n)); duke@435: for (oop* cur_oop = beg_oop; cur_oop < end_oop; cur_oop += entry_size) { duke@435: PSParallelCompact::adjust_pointer(cur_oop); duke@435: } duke@435: } duke@435: #endif // SERIALGC duke@435: duke@435: // Iterators duke@435: void klassVtable::oop_oop_iterate(OopClosure* blk) { duke@435: int len = length(); duke@435: for (int i = 0; i < len; i++) { duke@435: blk->do_oop(adr_method_at(i)); duke@435: } duke@435: } duke@435: duke@435: void klassVtable::oop_oop_iterate_m(OopClosure* blk, MemRegion mr) { duke@435: int len = length(); duke@435: int i; duke@435: for (i = 0; i < len; i++) { duke@435: if ((HeapWord*)adr_method_at(i) >= mr.start()) break; duke@435: } duke@435: for (; i < len; i++) { duke@435: oop* adr = adr_method_at(i); duke@435: if ((HeapWord*)adr < mr.end()) blk->do_oop(adr); duke@435: } duke@435: } duke@435: duke@435: //----------------------------------------------------------------------------------------- duke@435: // Itable code duke@435: duke@435: // Initialize a itableMethodEntry duke@435: void itableMethodEntry::initialize(methodOop m) { duke@435: if (m == NULL) return; duke@435: duke@435: _method = m; duke@435: } duke@435: duke@435: klassItable::klassItable(instanceKlassHandle klass) { duke@435: _klass = klass; duke@435: duke@435: if (klass->itable_length() > 0) { duke@435: itableOffsetEntry* offset_entry = (itableOffsetEntry*)klass->start_of_itable(); duke@435: if (offset_entry != NULL && offset_entry->interface_klass() != NULL) { // Check that itable is initialized duke@435: // First offset entry points to the first method_entry duke@435: intptr_t* method_entry = (intptr_t *)(((address)klass->as_klassOop()) + offset_entry->offset()); duke@435: intptr_t* end = klass->end_of_itable(); duke@435: duke@435: _table_offset = (intptr_t*)offset_entry - (intptr_t*)klass->as_klassOop(); duke@435: _size_offset_table = (method_entry - ((intptr_t*)offset_entry)) / itableOffsetEntry::size(); duke@435: _size_method_table = (end - method_entry) / itableMethodEntry::size(); duke@435: assert(_table_offset >= 0 && _size_offset_table >= 0 && _size_method_table >= 0, "wrong computation"); duke@435: return; duke@435: } duke@435: } duke@435: dcubed@451: // The length of the itable was either zero, or it has not yet been initialized. duke@435: _table_offset = 0; duke@435: _size_offset_table = 0; duke@435: _size_method_table = 0; duke@435: } duke@435: duke@435: // Garbage Collection duke@435: duke@435: void klassItable::oop_follow_contents() { duke@435: // offset table duke@435: itableOffsetEntry* ioe = offset_entry(0); duke@435: for(int i = 0; i < _size_offset_table; i++) { duke@435: MarkSweep::mark_and_push((oop*)&ioe->_interface); duke@435: ioe++; duke@435: } duke@435: duke@435: // method table duke@435: itableMethodEntry* ime = method_entry(0); duke@435: for(int j = 0; j < _size_method_table; j++) { duke@435: MarkSweep::mark_and_push((oop*)&ime->_method); duke@435: ime++; duke@435: } duke@435: } duke@435: duke@435: #ifndef SERIALGC duke@435: void klassItable::oop_follow_contents(ParCompactionManager* cm) { duke@435: // offset table duke@435: itableOffsetEntry* ioe = offset_entry(0); duke@435: for(int i = 0; i < _size_offset_table; i++) { duke@435: PSParallelCompact::mark_and_push(cm, (oop*)&ioe->_interface); duke@435: ioe++; duke@435: } duke@435: duke@435: // method table duke@435: itableMethodEntry* ime = method_entry(0); duke@435: for(int j = 0; j < _size_method_table; j++) { duke@435: PSParallelCompact::mark_and_push(cm, (oop*)&ime->_method); duke@435: ime++; duke@435: } duke@435: } duke@435: #endif // SERIALGC duke@435: duke@435: void klassItable::oop_adjust_pointers() { duke@435: // offset table duke@435: itableOffsetEntry* ioe = offset_entry(0); duke@435: for(int i = 0; i < _size_offset_table; i++) { duke@435: MarkSweep::adjust_pointer((oop*)&ioe->_interface); duke@435: ioe++; duke@435: } duke@435: duke@435: // method table duke@435: itableMethodEntry* ime = method_entry(0); duke@435: for(int j = 0; j < _size_method_table; j++) { duke@435: MarkSweep::adjust_pointer((oop*)&ime->_method); duke@435: ime++; duke@435: } duke@435: } duke@435: duke@435: #ifndef SERIALGC duke@435: void klassItable::oop_update_pointers(ParCompactionManager* cm) { duke@435: // offset table duke@435: itableOffsetEntry* ioe = offset_entry(0); duke@435: for(int i = 0; i < _size_offset_table; i++) { duke@435: PSParallelCompact::adjust_pointer((oop*)&ioe->_interface); duke@435: ioe++; duke@435: } duke@435: duke@435: // method table duke@435: itableMethodEntry* ime = method_entry(0); duke@435: for(int j = 0; j < _size_method_table; j++) { duke@435: PSParallelCompact::adjust_pointer((oop*)&ime->_method); duke@435: ime++; duke@435: } duke@435: } duke@435: duke@435: void klassItable::oop_update_pointers(ParCompactionManager* cm, duke@435: HeapWord* beg_addr, HeapWord* end_addr) { duke@435: // offset table duke@435: itableOffsetEntry* ioe = offset_entry(0); duke@435: for(int i = 0; i < _size_offset_table; i++) { duke@435: oop* p = (oop*)&ioe->_interface; duke@435: PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); duke@435: ioe++; duke@435: } duke@435: duke@435: // method table duke@435: itableMethodEntry* ime = method_entry(0); duke@435: for(int j = 0; j < _size_method_table; j++) { duke@435: oop* p = (oop*)&ime->_method; duke@435: PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); duke@435: ime++; duke@435: } duke@435: } duke@435: #endif // SERIALGC duke@435: duke@435: // Iterators duke@435: void klassItable::oop_oop_iterate(OopClosure* blk) { duke@435: // offset table duke@435: itableOffsetEntry* ioe = offset_entry(0); duke@435: for(int i = 0; i < _size_offset_table; i++) { duke@435: blk->do_oop((oop*)&ioe->_interface); duke@435: ioe++; duke@435: } duke@435: duke@435: // method table duke@435: itableMethodEntry* ime = method_entry(0); duke@435: for(int j = 0; j < _size_method_table; j++) { duke@435: blk->do_oop((oop*)&ime->_method); duke@435: ime++; duke@435: } duke@435: } duke@435: duke@435: void klassItable::oop_oop_iterate_m(OopClosure* blk, MemRegion mr) { duke@435: // offset table duke@435: itableOffsetEntry* ioe = offset_entry(0); duke@435: for(int i = 0; i < _size_offset_table; i++) { duke@435: oop* adr = (oop*)&ioe->_interface; duke@435: if (mr.contains(adr)) blk->do_oop(adr); duke@435: ioe++; duke@435: } duke@435: duke@435: // method table duke@435: itableMethodEntry* ime = method_entry(0); duke@435: for(int j = 0; j < _size_method_table; j++) { duke@435: oop* adr = (oop*)&ime->_method; duke@435: if (mr.contains(adr)) blk->do_oop(adr); duke@435: ime++; duke@435: } duke@435: } duke@435: duke@435: duke@435: static int initialize_count = 0; duke@435: duke@435: // Initialization duke@435: void klassItable::initialize_itable(bool checkconstraints, TRAPS) { dcubed@451: // Cannot be setup doing bootstrapping, interfaces don't have dcubed@451: // itables, and klass with only ones entry have empty itables dcubed@451: if (Universe::is_bootstrapping() || dcubed@451: _klass->is_interface() || dcubed@451: _klass->itable_length() == itableOffsetEntry::size()) return; duke@435: dcubed@451: // There's alway an extra itable entry so we can null-terminate it. dcubed@451: guarantee(size_offset_table() >= 1, "too small"); dcubed@451: int num_interfaces = size_offset_table() - 1; duke@435: if (num_interfaces > 0) { dcubed@451: if (TraceItables) tty->print_cr("%3d: Initializing itables for %s", ++initialize_count, dcubed@451: _klass->name()->as_C_string()); duke@435: duke@435: duke@435: // Interate through all interfaces duke@435: int i; duke@435: for(i = 0; i < num_interfaces; i++) { duke@435: itableOffsetEntry* ioe = offset_entry(i); duke@435: KlassHandle interf_h (THREAD, ioe->interface_klass()); duke@435: assert(interf_h() != NULL && ioe->offset() != 0, "bad offset entry in itable"); duke@435: initialize_itable_for_interface(ioe->offset(), interf_h, checkconstraints, CHECK); duke@435: } duke@435: duke@435: } dcubed@451: // Check that the last entry is empty dcubed@451: itableOffsetEntry* ioe = offset_entry(size_offset_table() - 1); dcubed@451: guarantee(ioe->interface_klass() == NULL && ioe->offset() == 0, "terminator entry missing"); duke@435: } duke@435: duke@435: duke@435: void klassItable::initialize_itable_for_interface(int method_table_offset, KlassHandle interf_h, bool checkconstraints, TRAPS) { duke@435: objArrayHandle methods(THREAD, instanceKlass::cast(interf_h())->methods()); duke@435: int nof_methods = methods()->length(); duke@435: HandleMark hm; duke@435: KlassHandle klass = _klass; duke@435: assert(nof_methods > 0, "at least one method must exist for interface to be in vtable") duke@435: Handle interface_loader (THREAD, instanceKlass::cast(interf_h())->class_loader()); duke@435: int ime_num = 0; duke@435: duke@435: // Skip first methodOop if it is a class initializer duke@435: int i = ((methodOop)methods()->obj_at(0))->name() != vmSymbols::class_initializer_name() ? 0 : 1; duke@435: duke@435: // m, method_name, method_signature, klass reset each loop so they duke@435: // don't need preserving across check_signature_loaders call duke@435: // methods needs a handle in case of gc from check_signature_loaders duke@435: for(; i < nof_methods; i++) { duke@435: methodOop m = (methodOop)methods()->obj_at(i); duke@435: symbolOop method_name = m->name(); duke@435: symbolOop method_signature = m->signature(); duke@435: duke@435: // This is same code as in Linkresolver::lookup_instance_method_in_klasses duke@435: methodOop target = klass->uncached_lookup_method(method_name, method_signature); duke@435: while (target != NULL && target->is_static()) { duke@435: // continue with recursive lookup through the superclass duke@435: klassOop super = Klass::cast(target->method_holder())->super(); duke@435: target = (super == NULL) ? methodOop(NULL) : Klass::cast(super)->uncached_lookup_method(method_name, method_signature); duke@435: } duke@435: if (target == NULL || !target->is_public() || target->is_abstract()) { duke@435: // Entry do not resolve. Leave it empty duke@435: } else { duke@435: // Entry did resolve, check loader constraints before initializing duke@435: // if checkconstraints requested duke@435: methodHandle target_h (THREAD, target); // preserve across gc duke@435: if (checkconstraints) { duke@435: Handle method_holder_loader (THREAD, instanceKlass::cast(target->method_holder())->class_loader()); duke@435: if (method_holder_loader() != interface_loader()) { duke@435: ResourceMark rm(THREAD); duke@435: char* failed_type_name = duke@435: SystemDictionary::check_signature_loaders(method_signature, duke@435: method_holder_loader, duke@435: interface_loader, duke@435: true, CHECK); duke@435: if (failed_type_name != NULL) { duke@435: const char* msg = "loader constraint violation in interface " duke@435: "itable initialization: when resolving method \"%s\" the class" duke@435: " loader (instance of %s) of the current class, %s, " duke@435: "and the class loader (instance of %s) for interface " duke@435: "%s have different Class objects for the type %s " duke@435: "used in the signature"; duke@435: char* sig = target_h()->name_and_sig_as_C_string(); duke@435: const char* loader1 = SystemDictionary::loader_name(method_holder_loader()); duke@435: char* current = klass->name()->as_C_string(); duke@435: const char* loader2 = SystemDictionary::loader_name(interface_loader()); duke@435: char* iface = instanceKlass::cast(interf_h())->name()->as_C_string(); duke@435: size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + duke@435: strlen(current) + strlen(loader2) + strlen(iface) + duke@435: strlen(failed_type_name); duke@435: char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); duke@435: jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2, duke@435: iface, failed_type_name); duke@435: THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // ime may have moved during GC so recalculate address duke@435: itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target_h()); duke@435: } duke@435: // Progress to next entry duke@435: ime_num++; duke@435: } duke@435: } duke@435: dcubed@451: // Update entry for specific methodOop duke@435: void klassItable::initialize_with_method(methodOop m) { duke@435: itableMethodEntry* ime = method_entry(0); duke@435: for(int i = 0; i < _size_method_table; i++) { duke@435: if (ime->method() == m) { duke@435: ime->initialize(m); duke@435: } duke@435: ime++; duke@435: } duke@435: } duke@435: duke@435: void klassItable::adjust_method_entries(methodOop* old_methods, methodOop* new_methods, duke@435: int methods_length, bool * trace_name_printed) { duke@435: // search the itable for uses of either obsolete or EMCP methods duke@435: for (int j = 0; j < methods_length; j++) { duke@435: methodOop old_method = old_methods[j]; duke@435: methodOop new_method = new_methods[j]; duke@435: itableMethodEntry* ime = method_entry(0); duke@435: dcubed@1045: // The itable can describe more than one interface and the same dcubed@1045: // method signature can be specified by more than one interface. dcubed@1045: // This means we have to do an exhaustive search to find all the dcubed@1045: // old_method references. duke@435: for (int i = 0; i < _size_method_table; i++) { duke@435: if (ime->method() == old_method) { duke@435: ime->initialize(new_method); duke@435: duke@435: if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { duke@435: if (!(*trace_name_printed)) { duke@435: // RC_TRACE_MESG macro has an embedded ResourceMark duke@435: RC_TRACE_MESG(("adjust: name=%s", duke@435: Klass::cast(old_method->method_holder())->external_name())); duke@435: *trace_name_printed = true; duke@435: } duke@435: // RC_TRACE macro has an embedded ResourceMark duke@435: RC_TRACE(0x00200000, ("itable method update: %s(%s)", duke@435: new_method->name()->as_C_string(), duke@435: new_method->signature()->as_C_string())); duke@435: } duke@435: } duke@435: ime++; duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: // Setup duke@435: class InterfaceVisiterClosure : public StackObj { duke@435: public: duke@435: virtual void doit(klassOop intf, int method_count) = 0; duke@435: }; duke@435: duke@435: // Visit all interfaces with at-least one method (excluding ) duke@435: void visit_all_interfaces(objArrayOop transitive_intf, InterfaceVisiterClosure *blk) { duke@435: // Handle array argument duke@435: for(int i = 0; i < transitive_intf->length(); i++) { duke@435: klassOop intf = (klassOop)transitive_intf->obj_at(i); duke@435: assert(Klass::cast(intf)->is_interface(), "sanity check"); duke@435: duke@435: // Find no. of methods excluding a duke@435: int method_count = instanceKlass::cast(intf)->methods()->length(); duke@435: if (method_count > 0) { duke@435: methodOop m = (methodOop)instanceKlass::cast(intf)->methods()->obj_at(0); duke@435: assert(m != NULL && m->is_method(), "sanity check"); duke@435: if (m->name() == vmSymbols::object_initializer_name()) { duke@435: method_count--; duke@435: } duke@435: } duke@435: duke@435: // Only count interfaces with at least one method duke@435: if (method_count > 0) { duke@435: blk->doit(intf, method_count); duke@435: } duke@435: } duke@435: } duke@435: duke@435: class CountInterfacesClosure : public InterfaceVisiterClosure { duke@435: private: duke@435: int _nof_methods; duke@435: int _nof_interfaces; duke@435: public: duke@435: CountInterfacesClosure() { _nof_methods = 0; _nof_interfaces = 0; } duke@435: duke@435: int nof_methods() const { return _nof_methods; } duke@435: int nof_interfaces() const { return _nof_interfaces; } duke@435: duke@435: void doit(klassOop intf, int method_count) { _nof_methods += method_count; _nof_interfaces++; } duke@435: }; duke@435: duke@435: class SetupItableClosure : public InterfaceVisiterClosure { duke@435: private: duke@435: itableOffsetEntry* _offset_entry; duke@435: itableMethodEntry* _method_entry; duke@435: address _klass_begin; duke@435: public: duke@435: SetupItableClosure(address klass_begin, itableOffsetEntry* offset_entry, itableMethodEntry* method_entry) { duke@435: _klass_begin = klass_begin; duke@435: _offset_entry = offset_entry; duke@435: _method_entry = method_entry; duke@435: } duke@435: duke@435: itableMethodEntry* method_entry() const { return _method_entry; } duke@435: duke@435: void doit(klassOop intf, int method_count) { duke@435: int offset = ((address)_method_entry) - _klass_begin; duke@435: _offset_entry->initialize(intf, offset); duke@435: _offset_entry++; duke@435: _method_entry += method_count; duke@435: } duke@435: }; duke@435: duke@435: int klassItable::compute_itable_size(objArrayHandle transitive_interfaces) { duke@435: // Count no of interfaces and total number of interface methods duke@435: CountInterfacesClosure cic; duke@435: visit_all_interfaces(transitive_interfaces(), &cic); duke@435: dcubed@451: // There's alway an extra itable entry so we can null-terminate it. dcubed@451: int itable_size = calc_itable_size(cic.nof_interfaces() + 1, cic.nof_methods()); duke@435: duke@435: // Statistics duke@435: update_stats(itable_size * HeapWordSize); duke@435: duke@435: return itable_size; duke@435: } duke@435: duke@435: duke@435: // Fill out offset table and interface klasses into the itable space duke@435: void klassItable::setup_itable_offset_table(instanceKlassHandle klass) { duke@435: if (klass->itable_length() == 0) return; duke@435: assert(!klass->is_interface(), "Should have zero length itable"); duke@435: duke@435: // Count no of interfaces and total number of interface methods duke@435: CountInterfacesClosure cic; duke@435: visit_all_interfaces(klass->transitive_interfaces(), &cic); duke@435: int nof_methods = cic.nof_methods(); duke@435: int nof_interfaces = cic.nof_interfaces(); duke@435: dcubed@451: // Add one extra entry so we can null-terminate the table dcubed@451: nof_interfaces++; duke@435: duke@435: assert(compute_itable_size(objArrayHandle(klass->transitive_interfaces())) == duke@435: calc_itable_size(nof_interfaces, nof_methods), duke@435: "mismatch calculation of itable size"); duke@435: duke@435: // Fill-out offset table duke@435: itableOffsetEntry* ioe = (itableOffsetEntry*)klass->start_of_itable(); duke@435: itableMethodEntry* ime = (itableMethodEntry*)(ioe + nof_interfaces); duke@435: intptr_t* end = klass->end_of_itable(); coleenp@548: assert((oop*)(ime + nof_methods) <= (oop*)klass->start_of_static_fields(), "wrong offset calculation (1)"); coleenp@548: assert((oop*)(end) == (oop*)(ime + nof_methods), "wrong offset calculation (2)"); duke@435: duke@435: // Visit all interfaces and initialize itable offset table duke@435: SetupItableClosure sic((address)klass->as_klassOop(), ioe, ime); duke@435: visit_all_interfaces(klass->transitive_interfaces(), &sic); duke@435: duke@435: #ifdef ASSERT duke@435: ime = sic.method_entry(); duke@435: oop* v = (oop*) klass->end_of_itable(); duke@435: assert( (oop*)(ime) == v, "wrong offset calculation (2)"); duke@435: #endif duke@435: } duke@435: duke@435: duke@435: // m must be a method in an interface duke@435: int klassItable::compute_itable_index(methodOop m) { duke@435: klassOop intf = m->method_holder(); duke@435: assert(instanceKlass::cast(intf)->is_interface(), "sanity check"); duke@435: objArrayOop methods = instanceKlass::cast(intf)->methods(); duke@435: int index = 0; duke@435: while(methods->obj_at(index) != m) { duke@435: index++; duke@435: assert(index < methods->length(), "should find index for resolve_invoke"); duke@435: } duke@435: // Adjust for , which is left out of table if first method duke@435: if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->name() == vmSymbols::class_initializer_name()) { duke@435: index--; duke@435: } duke@435: return index; duke@435: } duke@435: jrose@1100: jrose@1100: // inverse to compute_itable_index jrose@1100: methodOop klassItable::method_for_itable_index(klassOop intf, int itable_index) { jrose@1100: assert(instanceKlass::cast(intf)->is_interface(), "sanity check"); jrose@1100: objArrayOop methods = instanceKlass::cast(intf)->methods(); jrose@1100: jrose@1100: int index = itable_index; jrose@1100: // Adjust for , which is left out of table if first method jrose@1100: if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->name() == vmSymbols::class_initializer_name()) { jrose@1100: index++; jrose@1100: } jrose@1100: jrose@1100: if (itable_index < 0 || index >= methods->length()) jrose@1100: return NULL; // help caller defend against bad indexes jrose@1100: jrose@1100: methodOop m = (methodOop)methods->obj_at(index); jrose@1100: assert(compute_itable_index(m) == itable_index, "correct inverse"); jrose@1100: jrose@1100: return m; jrose@1100: } jrose@1100: duke@435: void klassVtable::verify(outputStream* st, bool forced) { duke@435: // make sure table is initialized duke@435: if (!Universe::is_fully_initialized()) return; duke@435: #ifndef PRODUCT duke@435: // avoid redundant verifies duke@435: if (!forced && _verify_count == Universe::verify_count()) return; duke@435: _verify_count = Universe::verify_count(); duke@435: #endif duke@435: oop* end_of_obj = (oop*)_klass() + _klass()->size(); duke@435: oop* end_of_vtable = (oop *)&table()[_length]; duke@435: if (end_of_vtable > end_of_obj) { duke@435: fatal1("klass %s: klass object too short (vtable extends beyond end)", duke@435: _klass->internal_name()); duke@435: } duke@435: duke@435: for (int i = 0; i < _length; i++) table()[i].verify(this, st); duke@435: // verify consistency with superKlass vtable duke@435: klassOop super = _klass->super(); duke@435: if (super != NULL) { duke@435: instanceKlass* sk = instanceKlass::cast(super); duke@435: klassVtable* vt = sk->vtable(); duke@435: for (int i = 0; i < vt->length(); i++) { duke@435: verify_against(st, vt, i); duke@435: } duke@435: } duke@435: } duke@435: duke@435: void klassVtable::verify_against(outputStream* st, klassVtable* vt, int index) { duke@435: vtableEntry* vte = &vt->table()[index]; duke@435: if (vte->method()->name() != table()[index].method()->name() || duke@435: vte->method()->signature() != table()[index].method()->signature()) { duke@435: fatal("mismatched name/signature of vtable entries"); duke@435: } duke@435: } duke@435: duke@435: #ifndef PRODUCT duke@435: void klassVtable::print() { duke@435: ResourceMark rm; duke@435: tty->print("klassVtable for klass %s (length %d):\n", _klass->internal_name(), length()); duke@435: for (int i = 0; i < length(); i++) { duke@435: table()[i].print(); duke@435: tty->cr(); duke@435: } duke@435: } duke@435: #endif duke@435: duke@435: void vtableEntry::verify(klassVtable* vt, outputStream* st) { duke@435: NOT_PRODUCT(FlagSetting fs(IgnoreLockingAssertions, true)); duke@435: assert(method() != NULL, "must have set method"); duke@435: method()->verify(); duke@435: // we sub_type, because it could be a miranda method duke@435: if (!vt->klass()->is_subtype_of(method()->method_holder())) { duke@435: #ifndef PRODUCT duke@435: print(); duke@435: #endif duke@435: fatal1("vtableEntry %#lx: method is from subclass", this); duke@435: } duke@435: } duke@435: duke@435: #ifndef PRODUCT duke@435: duke@435: void vtableEntry::print() { duke@435: ResourceMark rm; duke@435: tty->print("vtableEntry %s: ", method()->name()->as_C_string()); duke@435: if (Verbose) { duke@435: tty->print("m %#lx ", (address)method()); duke@435: } duke@435: } duke@435: duke@435: class VtableStats : AllStatic { duke@435: public: duke@435: static int no_klasses; // # classes with vtables duke@435: static int no_array_klasses; // # array classes duke@435: static int no_instance_klasses; // # instanceKlasses duke@435: static int sum_of_vtable_len; // total # of vtable entries duke@435: static int sum_of_array_vtable_len; // total # of vtable entries in array klasses only duke@435: static int fixed; // total fixed overhead in bytes duke@435: static int filler; // overhead caused by filler bytes duke@435: static int entries; // total bytes consumed by vtable entries duke@435: static int array_entries; // total bytes consumed by array vtable entries duke@435: duke@435: static void do_class(klassOop k) { duke@435: Klass* kl = k->klass_part(); duke@435: klassVtable* vt = kl->vtable(); duke@435: if (vt == NULL) return; duke@435: no_klasses++; duke@435: if (kl->oop_is_instance()) { duke@435: no_instance_klasses++; duke@435: kl->array_klasses_do(do_class); duke@435: } duke@435: if (kl->oop_is_array()) { duke@435: no_array_klasses++; duke@435: sum_of_array_vtable_len += vt->length(); duke@435: } duke@435: sum_of_vtable_len += vt->length(); duke@435: } duke@435: duke@435: static void compute() { duke@435: SystemDictionary::classes_do(do_class); duke@435: fixed = no_klasses * oopSize; // vtable length duke@435: // filler size is a conservative approximation duke@435: filler = oopSize * (no_klasses - no_instance_klasses) * (sizeof(instanceKlass) - sizeof(arrayKlass) - 1); duke@435: entries = sizeof(vtableEntry) * sum_of_vtable_len; duke@435: array_entries = sizeof(vtableEntry) * sum_of_array_vtable_len; duke@435: } duke@435: }; duke@435: duke@435: int VtableStats::no_klasses = 0; duke@435: int VtableStats::no_array_klasses = 0; duke@435: int VtableStats::no_instance_klasses = 0; duke@435: int VtableStats::sum_of_vtable_len = 0; duke@435: int VtableStats::sum_of_array_vtable_len = 0; duke@435: int VtableStats::fixed = 0; duke@435: int VtableStats::filler = 0; duke@435: int VtableStats::entries = 0; duke@435: int VtableStats::array_entries = 0; duke@435: duke@435: void klassVtable::print_statistics() { duke@435: ResourceMark rm; duke@435: HandleMark hm; duke@435: VtableStats::compute(); duke@435: tty->print_cr("vtable statistics:"); duke@435: tty->print_cr("%6d classes (%d instance, %d array)", VtableStats::no_klasses, VtableStats::no_instance_klasses, VtableStats::no_array_klasses); duke@435: int total = VtableStats::fixed + VtableStats::filler + VtableStats::entries; duke@435: tty->print_cr("%6d bytes fixed overhead (refs + vtable object header)", VtableStats::fixed); duke@435: tty->print_cr("%6d bytes filler overhead", VtableStats::filler); duke@435: tty->print_cr("%6d bytes for vtable entries (%d for arrays)", VtableStats::entries, VtableStats::array_entries); duke@435: tty->print_cr("%6d bytes total", total); duke@435: } duke@435: duke@435: bool klassVtable::check_no_old_entries() { duke@435: // Check that there really is no entry duke@435: for (int i = 0; i < length(); i++) { duke@435: methodOop m = unchecked_method_at(i); duke@435: if (m != NULL) { duke@435: if (m->is_old()) { duke@435: return false; duke@435: } duke@435: } duke@435: } duke@435: return true; duke@435: } duke@435: duke@435: void klassVtable::dump_vtable() { duke@435: tty->print_cr("vtable dump --"); duke@435: for (int i = 0; i < length(); i++) { duke@435: methodOop m = unchecked_method_at(i); duke@435: if (m != NULL) { duke@435: tty->print(" (%5d) ", i); duke@435: m->access_flags().print_on(tty); duke@435: tty->print(" -- "); duke@435: m->print_name(tty); duke@435: tty->cr(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: int klassItable::_total_classes; // Total no. of classes with itables duke@435: long klassItable::_total_size; // Total no. of bytes used for itables duke@435: duke@435: void klassItable::print_statistics() { duke@435: tty->print_cr("itable statistics:"); duke@435: tty->print_cr("%6d classes with itables", _total_classes); duke@435: tty->print_cr("%6d K uses for itables (average by class: %d bytes)", _total_size / K, _total_size / _total_classes); duke@435: } duke@435: duke@435: #endif // PRODUCT