Mercurial > hg > truffle
view src/share/vm/oops/instanceKlassKlass.cpp @ 452:00b023ae2d78
6722113: CMS: Incorrect overflow handling during precleaning of Reference lists
Summary: When we encounter marking stack overflow during precleaning of Reference lists, we were using the overflow list mechanism, which can cause problems on account of mutating the mark word of the header because of conflicts with mutator accesses and updates of that field. Instead we should use the usual mechanism for overflow handling in concurrent phases, namely dirtying of the card on which the overflowed object lies. Since precleaning effectively does a form of discovered list processing, albeit with discovery enabled, we needed to adjust some code to be correct in the face of interleaved processing and discovery.
Reviewed-by: apetrusenko, jcoomes
author | ysr |
---|---|
date | Thu, 20 Nov 2008 12:27:41 -0800 |
parents | a45484ea312d |
children | c89f86385056 |
line wrap: on
line source
/* * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ # include "incls/_precompiled.incl" # include "incls/_instanceKlassKlass.cpp.incl" klassOop instanceKlassKlass::create_klass(TRAPS) { instanceKlassKlass o; KlassHandle h_this_klass(THREAD, Universe::klassKlassObj()); KlassHandle k = base_create_klass(h_this_klass, header_size(), o.vtbl_value(), CHECK_NULL); // Make sure size calculation is right assert(k()->size() == align_object_size(header_size()), "wrong size for object"); java_lang_Class::create_mirror(k, CHECK_NULL); // Allocate mirror return k(); } int instanceKlassKlass::oop_size(oop obj) const { assert(obj->is_klass(), "must be klass"); return instanceKlass::cast(klassOop(obj))->object_size(); } bool instanceKlassKlass::oop_is_parsable(oop obj) const { assert(obj->is_klass(), "must be klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); return (!ik->null_vtbl()) && ik->object_is_parsable(); } void instanceKlassKlass::iterate_c_heap_oops(instanceKlass* ik, OopClosure* closure) { if (ik->oop_map_cache() != NULL) { ik->oop_map_cache()->oop_iterate(closure); } if (ik->jni_ids() != NULL) { ik->jni_ids()->oops_do(closure); } } void instanceKlassKlass::oop_follow_contents(oop obj) { assert(obj->is_klass(),"must be a klass"); assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->follow_static_fields(); { HandleMark hm; ik->vtable()->oop_follow_contents(); ik->itable()->oop_follow_contents(); } MarkSweep::mark_and_push(ik->adr_array_klasses()); MarkSweep::mark_and_push(ik->adr_methods()); MarkSweep::mark_and_push(ik->adr_method_ordering()); MarkSweep::mark_and_push(ik->adr_local_interfaces()); MarkSweep::mark_and_push(ik->adr_transitive_interfaces()); MarkSweep::mark_and_push(ik->adr_fields()); MarkSweep::mark_and_push(ik->adr_constants()); MarkSweep::mark_and_push(ik->adr_class_loader()); MarkSweep::mark_and_push(ik->adr_source_file_name()); MarkSweep::mark_and_push(ik->adr_source_debug_extension()); MarkSweep::mark_and_push(ik->adr_inner_classes()); MarkSweep::mark_and_push(ik->adr_protection_domain()); MarkSweep::mark_and_push(ik->adr_host_klass()); MarkSweep::mark_and_push(ik->adr_signers()); MarkSweep::mark_and_push(ik->adr_generic_signature()); MarkSweep::mark_and_push(ik->adr_class_annotations()); MarkSweep::mark_and_push(ik->adr_fields_annotations()); MarkSweep::mark_and_push(ik->adr_methods_annotations()); MarkSweep::mark_and_push(ik->adr_methods_parameter_annotations()); MarkSweep::mark_and_push(ik->adr_methods_default_annotations()); // We do not follow adr_implementors() here. It is followed later // in instanceKlass::follow_weak_klass_links() klassKlass::oop_follow_contents(obj); iterate_c_heap_oops(ik, &MarkSweep::mark_and_push_closure); } #ifndef SERIALGC void instanceKlassKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { assert(obj->is_klass(),"must be a klass"); assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->follow_static_fields(cm); ik->vtable()->oop_follow_contents(cm); ik->itable()->oop_follow_contents(cm); PSParallelCompact::mark_and_push(cm, ik->adr_array_klasses()); PSParallelCompact::mark_and_push(cm, ik->adr_methods()); PSParallelCompact::mark_and_push(cm, ik->adr_method_ordering()); PSParallelCompact::mark_and_push(cm, ik->adr_local_interfaces()); PSParallelCompact::mark_and_push(cm, ik->adr_transitive_interfaces()); PSParallelCompact::mark_and_push(cm, ik->adr_fields()); PSParallelCompact::mark_and_push(cm, ik->adr_constants()); PSParallelCompact::mark_and_push(cm, ik->adr_class_loader()); PSParallelCompact::mark_and_push(cm, ik->adr_source_file_name()); PSParallelCompact::mark_and_push(cm, ik->adr_source_debug_extension()); PSParallelCompact::mark_and_push(cm, ik->adr_inner_classes()); PSParallelCompact::mark_and_push(cm, ik->adr_protection_domain()); PSParallelCompact::mark_and_push(cm, ik->adr_host_klass()); PSParallelCompact::mark_and_push(cm, ik->adr_signers()); PSParallelCompact::mark_and_push(cm, ik->adr_generic_signature()); PSParallelCompact::mark_and_push(cm, ik->adr_class_annotations()); PSParallelCompact::mark_and_push(cm, ik->adr_fields_annotations()); PSParallelCompact::mark_and_push(cm, ik->adr_methods_annotations()); PSParallelCompact::mark_and_push(cm, ik->adr_methods_parameter_annotations()); PSParallelCompact::mark_and_push(cm, ik->adr_methods_default_annotations()); // We do not follow adr_implementor() here. It is followed later // in instanceKlass::follow_weak_klass_links() klassKlass::oop_follow_contents(cm, obj); PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm); iterate_c_heap_oops(ik, &mark_and_push_closure); } #endif // SERIALGC int instanceKlassKlass::oop_oop_iterate(oop obj, OopClosure* blk) { assert(obj->is_klass(),"must be a klass"); assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); // Get size before changing pointers. // Don't call size() or oop_size() since that is a virtual call. int size = ik->object_size(); ik->iterate_static_fields(blk); ik->vtable()->oop_oop_iterate(blk); ik->itable()->oop_oop_iterate(blk); blk->do_oop(ik->adr_array_klasses()); blk->do_oop(ik->adr_methods()); blk->do_oop(ik->adr_method_ordering()); blk->do_oop(ik->adr_local_interfaces()); blk->do_oop(ik->adr_transitive_interfaces()); blk->do_oop(ik->adr_fields()); blk->do_oop(ik->adr_constants()); blk->do_oop(ik->adr_class_loader()); blk->do_oop(ik->adr_protection_domain()); blk->do_oop(ik->adr_host_klass()); blk->do_oop(ik->adr_signers()); blk->do_oop(ik->adr_source_file_name()); blk->do_oop(ik->adr_source_debug_extension()); blk->do_oop(ik->adr_inner_classes()); for (int i = 0; i < instanceKlass::implementors_limit; i++) { blk->do_oop(&ik->adr_implementors()[i]); } blk->do_oop(ik->adr_generic_signature()); blk->do_oop(ik->adr_class_annotations()); blk->do_oop(ik->adr_fields_annotations()); blk->do_oop(ik->adr_methods_annotations()); blk->do_oop(ik->adr_methods_parameter_annotations()); blk->do_oop(ik->adr_methods_default_annotations()); klassKlass::oop_oop_iterate(obj, blk); if(ik->oop_map_cache() != NULL) ik->oop_map_cache()->oop_iterate(blk); return size; } int instanceKlassKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { assert(obj->is_klass(),"must be a klass"); assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); // Get size before changing pointers. // Don't call size() or oop_size() since that is a virtual call. int size = ik->object_size(); ik->iterate_static_fields(blk, mr); ik->vtable()->oop_oop_iterate_m(blk, mr); ik->itable()->oop_oop_iterate_m(blk, mr); oop* adr; adr = ik->adr_array_klasses(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_methods(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_method_ordering(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_local_interfaces(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_transitive_interfaces(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_fields(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_constants(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_class_loader(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_protection_domain(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_host_klass(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_signers(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_source_file_name(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_source_debug_extension(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_inner_classes(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_implementors(); for (int i = 0; i < instanceKlass::implementors_limit; i++) { if (mr.contains(&adr[i])) blk->do_oop(&adr[i]); } adr = ik->adr_generic_signature(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_class_annotations(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_fields_annotations(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_methods_annotations(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_methods_parameter_annotations(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_methods_default_annotations(); if (mr.contains(adr)) blk->do_oop(adr); klassKlass::oop_oop_iterate_m(obj, blk, mr); if(ik->oop_map_cache() != NULL) ik->oop_map_cache()->oop_iterate(blk, mr); return size; } int instanceKlassKlass::oop_adjust_pointers(oop obj) { assert(obj->is_klass(),"must be a klass"); assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->adjust_static_fields(); ik->vtable()->oop_adjust_pointers(); ik->itable()->oop_adjust_pointers(); MarkSweep::adjust_pointer(ik->adr_array_klasses()); MarkSweep::adjust_pointer(ik->adr_methods()); MarkSweep::adjust_pointer(ik->adr_method_ordering()); MarkSweep::adjust_pointer(ik->adr_local_interfaces()); MarkSweep::adjust_pointer(ik->adr_transitive_interfaces()); MarkSweep::adjust_pointer(ik->adr_fields()); MarkSweep::adjust_pointer(ik->adr_constants()); MarkSweep::adjust_pointer(ik->adr_class_loader()); MarkSweep::adjust_pointer(ik->adr_protection_domain()); MarkSweep::adjust_pointer(ik->adr_host_klass()); MarkSweep::adjust_pointer(ik->adr_signers()); MarkSweep::adjust_pointer(ik->adr_source_file_name()); MarkSweep::adjust_pointer(ik->adr_source_debug_extension()); MarkSweep::adjust_pointer(ik->adr_inner_classes()); for (int i = 0; i < instanceKlass::implementors_limit; i++) { MarkSweep::adjust_pointer(&ik->adr_implementors()[i]); } MarkSweep::adjust_pointer(ik->adr_generic_signature()); MarkSweep::adjust_pointer(ik->adr_class_annotations()); MarkSweep::adjust_pointer(ik->adr_fields_annotations()); MarkSweep::adjust_pointer(ik->adr_methods_annotations()); MarkSweep::adjust_pointer(ik->adr_methods_parameter_annotations()); MarkSweep::adjust_pointer(ik->adr_methods_default_annotations()); iterate_c_heap_oops(ik, &MarkSweep::adjust_root_pointer_closure); return klassKlass::oop_adjust_pointers(obj); } #ifndef SERIALGC void instanceKlassKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { assert(!pm->depth_first(), "invariant"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->copy_static_fields(pm); oop* loader_addr = ik->adr_class_loader(); if (PSScavenge::should_scavenge(loader_addr)) { pm->claim_or_forward_breadth(loader_addr); } oop* pd_addr = ik->adr_protection_domain(); if (PSScavenge::should_scavenge(pd_addr)) { pm->claim_or_forward_breadth(pd_addr); } oop* hk_addr = ik->adr_host_klass(); if (PSScavenge::should_scavenge(hk_addr)) { pm->claim_or_forward_breadth(hk_addr); } oop* sg_addr = ik->adr_signers(); if (PSScavenge::should_scavenge(sg_addr)) { pm->claim_or_forward_breadth(sg_addr); } klassKlass::oop_copy_contents(pm, obj); } void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(pm->depth_first(), "invariant"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->push_static_fields(pm); oop* loader_addr = ik->adr_class_loader(); if (PSScavenge::should_scavenge(loader_addr)) { pm->claim_or_forward_depth(loader_addr); } oop* pd_addr = ik->adr_protection_domain(); if (PSScavenge::should_scavenge(pd_addr)) { pm->claim_or_forward_depth(pd_addr); } oop* hk_addr = ik->adr_host_klass(); if (PSScavenge::should_scavenge(hk_addr)) { pm->claim_or_forward_depth(hk_addr); } oop* sg_addr = ik->adr_signers(); if (PSScavenge::should_scavenge(sg_addr)) { pm->claim_or_forward_depth(sg_addr); } klassKlass::oop_copy_contents(pm, obj); } int instanceKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { assert(obj->is_klass(),"must be a klass"); assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->update_static_fields(); ik->vtable()->oop_update_pointers(cm); ik->itable()->oop_update_pointers(cm); oop* const beg_oop = ik->oop_block_beg(); oop* const end_oop = ik->oop_block_end(); for (oop* cur_oop = beg_oop; cur_oop < end_oop; ++cur_oop) { PSParallelCompact::adjust_pointer(cur_oop); } OopClosure* closure = PSParallelCompact::adjust_root_pointer_closure(); iterate_c_heap_oops(ik, closure); klassKlass::oop_update_pointers(cm, obj); return ik->object_size(); } int instanceKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj, HeapWord* beg_addr, HeapWord* end_addr) { assert(obj->is_klass(),"must be a klass"); assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->update_static_fields(beg_addr, end_addr); ik->vtable()->oop_update_pointers(cm, beg_addr, end_addr); ik->itable()->oop_update_pointers(cm, beg_addr, end_addr); oop* const beg_oop = MAX2((oop*)beg_addr, ik->oop_block_beg()); oop* const end_oop = MIN2((oop*)end_addr, ik->oop_block_end()); for (oop* cur_oop = beg_oop; cur_oop < end_oop; ++cur_oop) { PSParallelCompact::adjust_pointer(cur_oop); } // The oop_map_cache, jni_ids and jni_id_map are allocated from the C heap, // and so don't lie within any 'Chunk' boundaries. Update them when the // lowest addressed oop in the instanceKlass 'oop_block' is updated. if (beg_oop == ik->oop_block_beg()) { OopClosure* closure = PSParallelCompact::adjust_root_pointer_closure(); iterate_c_heap_oops(ik, closure); } klassKlass::oop_update_pointers(cm, obj, beg_addr, end_addr); return ik->object_size(); } #endif // SERIALGC klassOop instanceKlassKlass::allocate_instance_klass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, TRAPS) { int size = instanceKlass::object_size(align_object_offset(vtable_len) + align_object_offset(itable_len) + static_field_size + nonstatic_oop_map_size); // Allocation KlassHandle h_this_klass(THREAD, as_klassOop()); KlassHandle k; if (rt == REF_NONE) { // regular klass instanceKlass o; k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL); } else { // reference klass instanceRefKlass o; k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL); } { No_Safepoint_Verifier no_safepoint; // until k becomes parsable instanceKlass* ik = (instanceKlass*) k()->klass_part(); assert(!k()->is_parsable(), "not expecting parsability yet."); // The sizes of these these three variables are used for determining the // size of the instanceKlassOop. It is critical that these are set to the right // sizes before the first GC, i.e., when we allocate the mirror. ik->set_vtable_length(vtable_len); ik->set_itable_length(itable_len); ik->set_static_field_size(static_field_size); ik->set_nonstatic_oop_map_size(nonstatic_oop_map_size); assert(k()->size() == size, "wrong size for object"); ik->set_array_klasses(NULL); ik->set_methods(NULL); ik->set_method_ordering(NULL); ik->set_local_interfaces(NULL); ik->set_transitive_interfaces(NULL); ik->init_implementor(); ik->set_fields(NULL); ik->set_constants(NULL); ik->set_class_loader(NULL); ik->set_protection_domain(NULL); ik->set_host_klass(NULL); ik->set_signers(NULL); ik->set_source_file_name(NULL); ik->set_source_debug_extension(NULL); ik->set_inner_classes(NULL); ik->set_static_oop_field_size(0); ik->set_nonstatic_field_size(0); ik->set_is_marked_dependent(false); ik->set_init_state(instanceKlass::allocated); ik->set_init_thread(NULL); ik->set_reference_type(rt); ik->set_oop_map_cache(NULL); ik->set_jni_ids(NULL); ik->set_osr_nmethods_head(NULL); ik->set_breakpoints(NULL); ik->init_previous_versions(); ik->set_generic_signature(NULL); ik->release_set_methods_jmethod_ids(NULL); ik->release_set_methods_cached_itable_indices(NULL); ik->set_class_annotations(NULL); ik->set_fields_annotations(NULL); ik->set_methods_annotations(NULL); ik->set_methods_parameter_annotations(NULL); ik->set_methods_default_annotations(NULL); ik->set_enclosing_method_indices(0, 0); ik->set_jvmti_cached_class_field_map(NULL); ik->set_initial_method_idnum(0); assert(k()->is_parsable(), "should be parsable here."); // initialize the non-header words to zero intptr_t* p = (intptr_t*)k(); for (int index = instanceKlass::header_size(); index < size; index++) { p[index] = NULL_WORD; } // To get verify to work - must be set to partial loaded before first GC point. k()->set_partially_loaded(); } // GC can happen here java_lang_Class::create_mirror(k, CHECK_NULL); // Allocate mirror return k(); } #ifndef PRODUCT // Printing static const char* state_names[] = { "unparseable_by_gc", "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error" }; void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); klassKlass::oop_print_on(obj, st); st->print(" - instance size: %d", ik->size_helper()); st->cr(); st->print(" - klass size: %d", ik->object_size()); st->cr(); st->print(" - access: "); ik->access_flags().print_on(st); st->cr(); st->print(" - state: "); st->print_cr(state_names[ik->_init_state]); st->print(" - name: "); ik->name()->print_value_on(st); st->cr(); st->print(" - super: "); ik->super()->print_value_on(st); st->cr(); st->print(" - sub: "); Klass* sub = ik->subklass(); int n; for (n = 0; sub != NULL; n++, sub = sub->next_sibling()) { if (n < MaxSubklassPrintSize) { sub->as_klassOop()->print_value_on(st); st->print(" "); } } if (n >= MaxSubklassPrintSize) st->print("(%d more klasses...)", n - MaxSubklassPrintSize); st->cr(); if (ik->is_interface()) { st->print_cr(" - nof implementors: %d", ik->nof_implementors()); int print_impl = 0; for (int i = 0; i < instanceKlass::implementors_limit; i++) { if (ik->implementor(i) != NULL) { if (++print_impl == 1) st->print_cr(" - implementor: "); st->print(" "); ik->implementor(i)->print_value_on(st); } } if (print_impl > 0) st->cr(); } st->print(" - arrays: "); ik->array_klasses()->print_value_on(st); st->cr(); st->print(" - methods: "); ik->methods()->print_value_on(st); st->cr(); if (Verbose) { objArrayOop methods = ik->methods(); for(int i = 0; i < methods->length(); i++) { tty->print("%d : ", i); methods->obj_at(i)->print_value(); tty->cr(); } } st->print(" - method ordering: "); ik->method_ordering()->print_value_on(st); st->cr(); st->print(" - local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr(); st->print(" - trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr(); st->print(" - constants: "); ik->constants()->print_value_on(st); st->cr(); st->print(" - class loader: "); ik->class_loader()->print_value_on(st); st->cr(); st->print(" - protection domain: "); ik->protection_domain()->print_value_on(st); st->cr(); st->print(" - host class: "); ik->host_klass()->print_value_on(st); st->cr(); st->print(" - signers: "); ik->signers()->print_value_on(st); st->cr(); if (ik->source_file_name() != NULL) { st->print(" - source file: "); ik->source_file_name()->print_value_on(st); st->cr(); } if (ik->source_debug_extension() != NULL) { st->print(" - source debug extension: "); ik->source_debug_extension()->print_value_on(st); st->cr(); } st->print_cr(" - previous version: "); { ResourceMark rm; // PreviousVersionInfo objects returned via PreviousVersionWalker // contain a GrowableArray of handles. We have to clean up the // GrowableArray _after_ the PreviousVersionWalker destructor // has destroyed the handles. { PreviousVersionWalker pvw(ik); for (PreviousVersionInfo * pv_info = pvw.next_previous_version(); pv_info != NULL; pv_info = pvw.next_previous_version()) { pv_info->prev_constant_pool_handle()()->print_value_on(st); } st->cr(); } // pvw is cleaned up } // rm is cleaned up if (ik->generic_signature() != NULL) { st->print(" - generic signature: "); ik->generic_signature()->print_value_on(st); } st->print(" - inner classes: "); ik->inner_classes()->print_value_on(st); st->cr(); st->print(" - java mirror: "); ik->java_mirror()->print_value_on(st); st->cr(); st->print(" - vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr(); st->print(" - itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr(); st->print_cr(" - static fields:"); FieldPrinter print_static_field(st); ik->do_local_static_fields(&print_static_field); st->print_cr(" - non-static fields:"); FieldPrinter print_nonstatic_field(st, obj); ik->do_nonstatic_fields(&print_nonstatic_field); st->print(" - static oop maps: "); if (ik->static_oop_field_size() > 0) { int first_offset = ik->offset_of_static_fields(); st->print("%d-%d", first_offset, first_offset + ik->static_oop_field_size() - 1); } st->cr(); st->print(" - non-static oop maps: "); OopMapBlock* map = ik->start_of_nonstatic_oop_maps(); OopMapBlock* end_map = map + ik->nonstatic_oop_map_size(); while (map < end_map) { st->print("%d-%d ", map->offset(), map->offset() + heapOopSize*(map->length() - 1)); map++; } st->cr(); } void instanceKlassKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); ik->name()->print_value_on(st); } #endif // PRODUCT const char* instanceKlassKlass::internal_name() const { return "{instance class}"; } // Verification class VerifyFieldClosure: public OopClosure { protected: template <class T> void do_oop_work(T* p) { guarantee(Universe::heap()->is_in(p), "should be in heap"); oop obj = oopDesc::load_decode_heap_oop(p); guarantee(obj->is_oop_or_null(), "should be in heap"); } public: virtual void do_oop(oop* p) { VerifyFieldClosure::do_oop_work(p); } virtual void do_oop(narrowOop* p) { VerifyFieldClosure::do_oop_work(p); } }; void instanceKlassKlass::oop_verify_on(oop obj, outputStream* st) { klassKlass::oop_verify_on(obj, st); if (!obj->partially_loaded()) { Thread *thread = Thread::current(); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); #ifndef PRODUCT // Avoid redundant verifies if (ik->_verify_count == Universe::verify_count()) return; ik->_verify_count = Universe::verify_count(); #endif // Verify that klass is present in SystemDictionary if (ik->is_loaded() && !ik->is_anonymous()) { symbolHandle h_name (thread, ik->name()); Handle h_loader (thread, ik->class_loader()); Handle h_obj(thread, obj); SystemDictionary::verify_obj_klass_present(h_obj, h_name, h_loader); } // Verify static fields VerifyFieldClosure blk; ik->iterate_static_fields(&blk); // Verify vtables if (ik->is_linked()) { ResourceMark rm(thread); // $$$ This used to be done only for m/s collections. Doing it // always seemed a valid generalization. (DLD -- 6/00) ik->vtable()->verify(st); } // Verify oop map cache if (ik->oop_map_cache() != NULL) { ik->oop_map_cache()->verify(); } // Verify first subklass if (ik->subklass_oop() != NULL) { guarantee(ik->subklass_oop()->is_perm(), "should be in permspace"); guarantee(ik->subklass_oop()->is_klass(), "should be klass"); } // Verify siblings klassOop super = ik->super(); Klass* sib = ik->next_sibling(); int sib_count = 0; while (sib != NULL) { if (sib == ik) { fatal1("subclass cycle of length %d", sib_count); } if (sib_count >= 100000) { fatal1("suspiciously long subclass list %d", sib_count); } guarantee(sib->as_klassOop()->is_klass(), "should be klass"); guarantee(sib->as_klassOop()->is_perm(), "should be in permspace"); guarantee(sib->super() == super, "siblings should have same superklass"); sib = sib->next_sibling(); } // Verify implementor fields bool saw_null_impl = false; for (int i = 0; i < instanceKlass::implementors_limit; i++) { klassOop im = ik->implementor(i); if (im == NULL) { saw_null_impl = true; continue; } guarantee(!saw_null_impl, "non-nulls must preceded all nulls"); guarantee(ik->is_interface(), "only interfaces should have implementor set"); guarantee(i < ik->nof_implementors(), "should only have one implementor"); guarantee(im->is_perm(), "should be in permspace"); guarantee(im->is_klass(), "should be klass"); guarantee(!Klass::cast(klassOop(im))->is_interface(), "implementors cannot be interfaces"); } // Verify local interfaces objArrayOop local_interfaces = ik->local_interfaces(); guarantee(local_interfaces->is_perm(), "should be in permspace"); guarantee(local_interfaces->is_objArray(), "should be obj array"); int j; for (j = 0; j < local_interfaces->length(); j++) { oop e = local_interfaces->obj_at(j); guarantee(e->is_klass() && Klass::cast(klassOop(e))->is_interface(), "invalid local interface"); } // Verify transitive interfaces objArrayOop transitive_interfaces = ik->transitive_interfaces(); guarantee(transitive_interfaces->is_perm(), "should be in permspace"); guarantee(transitive_interfaces->is_objArray(), "should be obj array"); for (j = 0; j < transitive_interfaces->length(); j++) { oop e = transitive_interfaces->obj_at(j); guarantee(e->is_klass() && Klass::cast(klassOop(e))->is_interface(), "invalid transitive interface"); } // Verify methods objArrayOop methods = ik->methods(); guarantee(methods->is_perm(), "should be in permspace"); guarantee(methods->is_objArray(), "should be obj array"); for (j = 0; j < methods->length(); j++) { guarantee(methods->obj_at(j)->is_method(), "non-method in methods array"); } for (j = 0; j < methods->length() - 1; j++) { methodOop m1 = methodOop(methods->obj_at(j)); methodOop m2 = methodOop(methods->obj_at(j + 1)); guarantee(m1->name()->fast_compare(m2->name()) <= 0, "methods not sorted correctly"); } // Verify method ordering typeArrayOop method_ordering = ik->method_ordering(); guarantee(method_ordering->is_perm(), "should be in permspace"); guarantee(method_ordering->is_typeArray(), "should be type array"); int length = method_ordering->length(); if (JvmtiExport::can_maintain_original_method_order()) { guarantee(length == methods->length(), "invalid method ordering length"); jlong sum = 0; for (j = 0; j < length; j++) { int original_index = method_ordering->int_at(j); guarantee(original_index >= 0 && original_index < length, "invalid method ordering index"); sum += original_index; } // Verify sum of indices 0,1,...,length-1 guarantee(sum == ((jlong)length*(length-1))/2, "invalid method ordering sum"); } else { guarantee(length == 0, "invalid method ordering length"); } // Verify JNI static field identifiers if (ik->jni_ids() != NULL) { ik->jni_ids()->verify(ik->as_klassOop()); } // Verify other fields if (ik->array_klasses() != NULL) { guarantee(ik->array_klasses()->is_perm(), "should be in permspace"); guarantee(ik->array_klasses()->is_klass(), "should be klass"); } guarantee(ik->fields()->is_perm(), "should be in permspace"); guarantee(ik->fields()->is_typeArray(), "should be type array"); guarantee(ik->constants()->is_perm(), "should be in permspace"); guarantee(ik->constants()->is_constantPool(), "should be constant pool"); guarantee(ik->inner_classes()->is_perm(), "should be in permspace"); guarantee(ik->inner_classes()->is_typeArray(), "should be type array"); if (ik->source_file_name() != NULL) { guarantee(ik->source_file_name()->is_perm(), "should be in permspace"); guarantee(ik->source_file_name()->is_symbol(), "should be symbol"); } if (ik->source_debug_extension() != NULL) { guarantee(ik->source_debug_extension()->is_perm(), "should be in permspace"); guarantee(ik->source_debug_extension()->is_symbol(), "should be symbol"); } if (ik->protection_domain() != NULL) { guarantee(ik->protection_domain()->is_oop(), "should be oop"); } if (ik->host_klass() != NULL) { guarantee(ik->host_klass()->is_oop(), "should be oop"); } if (ik->signers() != NULL) { guarantee(ik->signers()->is_objArray(), "should be obj array"); } if (ik->generic_signature() != NULL) { guarantee(ik->generic_signature()->is_perm(), "should be in permspace"); guarantee(ik->generic_signature()->is_symbol(), "should be symbol"); } if (ik->class_annotations() != NULL) { guarantee(ik->class_annotations()->is_typeArray(), "should be type array"); } if (ik->fields_annotations() != NULL) { guarantee(ik->fields_annotations()->is_objArray(), "should be obj array"); } if (ik->methods_annotations() != NULL) { guarantee(ik->methods_annotations()->is_objArray(), "should be obj array"); } if (ik->methods_parameter_annotations() != NULL) { guarantee(ik->methods_parameter_annotations()->is_objArray(), "should be obj array"); } if (ik->methods_default_annotations() != NULL) { guarantee(ik->methods_default_annotations()->is_objArray(), "should be obj array"); } } } bool instanceKlassKlass::oop_partially_loaded(oop obj) const { assert(obj->is_klass(), "object must be klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); assert(ik->oop_is_instance(), "object must be instanceKlass"); return ik->transitive_interfaces() == (objArrayOop) obj; // Check whether transitive_interfaces points to self } // The transitive_interfaces is the last field set when loading an object. void instanceKlassKlass::oop_set_partially_loaded(oop obj) { assert(obj->is_klass(), "object must be klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); // Set the layout helper to a place-holder value, until fuller initialization. // (This allows asserts in oop_is_instance to succeed.) ik->set_layout_helper(Klass::instance_layout_helper(0, true)); assert(ik->oop_is_instance(), "object must be instanceKlass"); assert(ik->transitive_interfaces() == NULL, "just checking"); ik->set_transitive_interfaces((objArrayOop) obj); // Temporarily set transitive_interfaces to point to self }