--- old/src/share/vm/oops/cpCacheOop.cpp Mon Feb 4 12:52:59 2013 +++ new/src/share/vm/oops/cpCacheOop.cpp Mon Feb 4 12:52:59 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. 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 @@ -575,6 +575,24 @@ return false; } +// a constant pool cache entry should never contain old or obsolete methods +bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() { + if (is_vfinal()) { + // virtual and final so _f2 contains method ptr instead of vtable index + methodOop m = (methodOop)_f2; + // Return false if _f2 refers to an old or an obsolete method. + // _f2 == NULL || !m->is_method() are just as unexpected here. + return (m != NULL && m->is_method() && !m->is_old() && !m->is_obsolete()); + } else if ((oop)_f1 == NULL || !((oop)_f1)->is_method()) { + // _f1 == NULL || !_f1->is_method() are OK here + return true; + } + + methodOop m = (methodOop)_f1; + // return false if _f1 refers to an old or an obsolete method + return (!m->is_old() && !m->is_obsolete()); +} + bool ConstantPoolCacheEntry::is_interesting_method_entry(klassOop k) { if (!is_method_entry()) { // not a method entry so not interesting by default @@ -598,7 +616,7 @@ } assert(m != NULL && m->is_method(), "sanity check"); - if (m == NULL || !m->is_method() || m->method_holder() != k) { + if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) { // robustness for above sanity checks or method is not in // the interesting class return false; @@ -682,4 +700,23 @@ } } } +} + +// the constant pool cache should never contain old or obsolete methods +bool constantPoolCacheOopDesc::check_no_old_or_obsolete_entries() { + for (int i = 1; i < length(); i++) { + if (entry_at(i)->is_interesting_method_entry(NULL) && + !entry_at(i)->check_no_old_or_obsolete_entries()) { + return false; + } + } + return true; +} + +void constantPoolCacheOopDesc::dump_cache() { + for (int i = 1; i < length(); i++) { + if (entry_at(i)->is_interesting_method_entry(NULL)) { + entry_at(i)->print(tty, i); + } + } } --- old/src/share/vm/oops/cpCacheOop.hpp Mon Feb 4 12:53:00 2013 +++ new/src/share/vm/oops/cpCacheOop.hpp Mon Feb 4 12:53:00 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. 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 @@ -363,6 +363,7 @@ // group don't print the klass name. bool adjust_method_entry(methodOop old_method, methodOop new_method, bool * trace_name_printed); + bool check_no_old_or_obsolete_entries(); bool is_interesting_method_entry(klassOop k); // Debugging & Printing @@ -492,6 +493,8 @@ // group don't print the klass name. void adjust_method_entries(methodOop* old_methods, methodOop* new_methods, int methods_length, bool * trace_name_printed); + bool check_no_old_or_obsolete_entries(); + void dump_cache(); }; #endif // SHARE_VM_OOPS_CPCACHEOOP_HPP --- old/src/share/vm/oops/klassVtable.cpp Mon Feb 4 12:53:01 2013 +++ new/src/share/vm/oops/klassVtable.cpp Mon Feb 4 12:53:01 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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 @@ -640,11 +640,37 @@ new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } + // cannot 'break' here; see for-loop comment above. } } } } +// a vtable should never contain old or obsolete methods +bool klassVtable::check_no_old_or_obsolete_entries() { + for (int i = 0; i < length(); i++) { + methodOop m = unchecked_method_at(i); + if (m != NULL && (m->is_old() || m->is_obsolete())) { + return false; + } + } + return true; +} + +void klassVtable::dump_vtable() { + tty->print_cr("vtable dump --"); + for (int i = 0; i < length(); i++) { + methodOop m = unchecked_method_at(i); + if (m != NULL) { + tty->print(" (%5d) ", i); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + } +} + // CDS/RedefineClasses support - clear vtables so they can be reinitialized void klassVtable::clear_vtable() { for (int i = 0; i < _length; i++) table()[i].clear(); @@ -994,7 +1020,7 @@ new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } - break; + // cannot 'break' here; see for-loop comment above. } ime++; } @@ -1001,7 +1027,36 @@ } } +// an itable should never contain old or obsolete methods +bool klassItable::check_no_old_or_obsolete_entries() { + itableMethodEntry* ime = method_entry(0); + for (int i = 0; i < _size_method_table; i++) { + methodOop m = ime->method(); + if (m != NULL && (m->is_old() || m->is_obsolete())) { + return false; + } + ime++; + } + return true; +} +void klassItable::dump_itable() { + itableMethodEntry* ime = method_entry(0); + tty->print_cr("itable dump --"); + for (int i = 0; i < _size_method_table; i++) { + methodOop m = ime->method(); + if (m != NULL) { + tty->print(" (%5d) ", i); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + ime++; + } +} + + // Setup class InterfaceVisiterClosure : public StackObj { public: @@ -1287,33 +1342,6 @@ tty->print_cr("%6d bytes total", total); } -bool klassVtable::check_no_old_entries() { - // Check that there really is no entry - for (int i = 0; i < length(); i++) { - methodOop m = unchecked_method_at(i); - if (m != NULL) { - if (m->is_old()) { - return false; - } - } - } - return true; -} - -void klassVtable::dump_vtable() { - tty->print_cr("vtable dump --"); - for (int i = 0; i < length(); i++) { - methodOop m = unchecked_method_at(i); - if (m != NULL) { - tty->print(" (%5d) ", i); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } - } -} - int klassItable::_total_classes; // Total no. of classes with itables long klassItable::_total_size; // Total no. of bytes used for itables --- old/src/share/vm/oops/klassVtable.hpp Mon Feb 4 12:53:01 2013 +++ new/src/share/vm/oops/klassVtable.hpp Mon Feb 4 12:53:01 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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 @@ -98,6 +98,8 @@ // group don't print the klass name. void adjust_method_entries(methodOop* old_methods, methodOop* new_methods, int methods_length, bool * trace_name_printed); + bool check_no_old_or_obsolete_entries(); + void dump_vtable(); // Garbage collection void oop_follow_contents(); @@ -118,11 +120,6 @@ void verify(outputStream* st, bool force = false); static void print_statistics() PRODUCT_RETURN; -#ifndef PRODUCT - bool check_no_old_entries(); - void dump_vtable(); -#endif - protected: friend class vtableEntry; private: @@ -292,6 +289,8 @@ // group don't print the klass name. void adjust_method_entries(methodOop* old_methods, methodOop* new_methods, int methods_length, bool * trace_name_printed); + bool check_no_old_or_obsolete_entries(); + void dump_itable(); // Garbage collection void oop_follow_contents(); --- old/src/share/vm/oops/methodOop.cpp Mon Feb 4 12:53:02 2013 +++ new/src/share/vm/oops/methodOop.cpp Mon Feb 4 12:53:02 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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 @@ -1328,10 +1328,6 @@ } -//----------------------------------------------------------------------------------- -// Non-product code - -#ifndef PRODUCT class SignatureTypePrinter : public SignatureTypeNames { private: outputStream* _st; @@ -1368,6 +1364,10 @@ } +//----------------------------------------------------------------------------------- +// Non-product code + +#ifndef PRODUCT void methodOopDesc::print_codes_on(outputStream* st) const { print_codes_on(0, code_size(), st); } --- old/src/share/vm/oops/methodOop.hpp Mon Feb 4 12:53:03 2013 +++ new/src/share/vm/oops/methodOop.hpp Mon Feb 4 12:53:02 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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 @@ -714,8 +714,8 @@ static bool has_unloaded_classes_in_signature(methodHandle m, TRAPS); // Printing - void print_short_name(outputStream* st = tty) /*PRODUCT_RETURN*/; // prints as klassname::methodname; Exposed so field engineers can debug VM - void print_name(outputStream* st = tty) PRODUCT_RETURN; // prints as "virtual void foo(int)" + void print_short_name(outputStream* st = tty); // prints as klassname::methodname; Exposed so field engineers can debug VM + void print_name(outputStream* st = tty); // prints as "virtual void foo(int)"; exposed for TraceRedefineClasses // Helper routine used for method sorting static void sort_methods(objArrayOop methods, --- old/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Feb 4 12:53:03 2013 +++ new/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Feb 4 12:53:03 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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 @@ -129,9 +129,16 @@ // See jvmtiExport.hpp for detailed explanation. JvmtiExport::set_has_redefined_a_class(); -#ifdef ASSERT - SystemDictionary::classes_do(check_class, thread); +// check_class() is optionally called for product bits, but is +// always called for non-product bits. +#ifdef PRODUCT + if (RC_TRACE_ENABLED(0x00004000)) { #endif + RC_TRACE_WITH_THREAD(0x00004000, thread, ("calling check_class")); + SystemDictionary::classes_do(check_class, thread); +#ifdef PRODUCT + } +#endif } void VM_RedefineClasses::doit_epilogue() { @@ -3351,7 +3358,6 @@ } } -#ifndef PRODUCT void VM_RedefineClasses::check_class(klassOop k_oop, oop initiating_loader, TRAPS) { Klass *k = k_oop->klass_part(); @@ -3358,69 +3364,110 @@ if (k->oop_is_instance()) { HandleMark hm(THREAD); instanceKlass *ik = (instanceKlass *) k; + bool no_old_methods = true; // be optimistic + ResourceMark rm(THREAD); - if (ik->vtable_length() > 0) { - ResourceMark rm(THREAD); - if (!ik->vtable()->check_no_old_entries()) { - tty->print_cr("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); + // a vtable should never contain old or obsolete methods + if (ik->vtable_length() > 0 && + !ik->vtable()->check_no_old_or_obsolete_entries()) { + if (RC_TRACE_ENABLED(0x00004000)) { + RC_TRACE_WITH_THREAD(0x00004000, THREAD, + ("klassVtable::check_no_old_or_obsolete_entries failure" + " -- OLD or OBSOLETE method found -- class: %s", + ik->signature_name())); ik->vtable()->dump_vtable(); + } + no_old_methods = false; + } + + // an itable should never contain old or obsolete methods + if (ik->itable_length() > 0 && + !ik->itable()->check_no_old_or_obsolete_entries()) { + if (RC_TRACE_ENABLED(0x00004000)) { + RC_TRACE_WITH_THREAD(0x00004000, THREAD, + ("klassItable::check_no_old_or_obsolete_entries failure" + " -- OLD or OBSOLETE method found -- class: %s", + ik->signature_name())); + ik->itable()->dump_itable(); + } + no_old_methods = false; + } + + // the constant pool cache should never contain old or obsolete methods + if (ik->constants() != NULL && + ik->constants()->cache() != NULL && + !ik->constants()->cache()->check_no_old_or_obsolete_entries()) { + if (RC_TRACE_ENABLED(0x00004000)) { + RC_TRACE_WITH_THREAD(0x00004000, THREAD, + ("cp-cache::check_no_old_or_obsolete_entries failure" + " -- OLD or OBSOLETE method found -- class: %s", + ik->signature_name())); + ik->constants()->cache()->dump_cache(); + } + no_old_methods = false; + } + + if (!no_old_methods) { + if (RC_TRACE_ENABLED(0x00004000)) { dump_methods(); - assert(false, "OLD method found"); + } else { + tty->print_cr("INFO: use the '-XX:TraceRedefineClasses=16384' option " + "to see more info about the following guarantee() failure."); } + guarantee(false, "OLD and/or OBSOLETE method(s) found"); } } } void VM_RedefineClasses::dump_methods() { - int j; - tty->print_cr("_old_methods --"); - for (j = 0; j < _old_methods->length(); ++j) { - methodOop m = (methodOop) _old_methods->obj_at(j); - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } - tty->print_cr("_new_methods --"); - for (j = 0; j < _new_methods->length(); ++j) { - methodOop m = (methodOop) _new_methods->obj_at(j); - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } - tty->print_cr("_matching_(old/new)_methods --"); - for (j = 0; j < _matching_methods_length; ++j) { - methodOop m = _matching_old_methods[j]; - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - m = _matching_new_methods[j]; - tty->print(" (%5d) ", m->vtable_index()); - m->access_flags().print_on(tty); - tty->cr(); - } - tty->print_cr("_deleted_methods --"); - for (j = 0; j < _deleted_methods_length; ++j) { - methodOop m = _deleted_methods[j]; - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } - tty->print_cr("_added_methods --"); - for (j = 0; j < _added_methods_length; ++j) { - methodOop m = _added_methods[j]; - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } + int j; + RC_TRACE(0x00004000, ("_old_methods --")); + for (j = 0; j < _old_methods->length(); ++j) { + methodOop m = (methodOop) _old_methods->obj_at(j); + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + RC_TRACE(0x00004000, ("_new_methods --")); + for (j = 0; j < _new_methods->length(); ++j) { + methodOop m = (methodOop) _new_methods->obj_at(j); + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + RC_TRACE(0x00004000, ("_matching_(old/new)_methods --")); + for (j = 0; j < _matching_methods_length; ++j) { + methodOop m = _matching_old_methods[j]; + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + m = _matching_new_methods[j]; + RC_TRACE_NO_CR(0x00004000, (" (%5d) ", m->vtable_index())); + m->access_flags().print_on(tty); + tty->cr(); + } + RC_TRACE(0x00004000, ("_deleted_methods --")); + for (j = 0; j < _deleted_methods_length; ++j) { + methodOop m = _deleted_methods[j]; + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + RC_TRACE(0x00004000, ("_added_methods --")); + for (j = 0; j < _added_methods_length; ++j) { + methodOop m = _added_methods[j]; + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } } -#endif --- old/src/share/vm/prims/jvmtiRedefineClasses.hpp Mon Feb 4 12:53:04 2013 +++ new/src/share/vm/prims/jvmtiRedefineClasses.hpp Mon Feb 4 12:53:04 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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 @@ -478,10 +478,9 @@ void flush_dependent_code(instanceKlassHandle k_h, TRAPS); - static void check_class(klassOop k_oop, oop initiating_loader, TRAPS) PRODUCT_RETURN; + static void check_class(klassOop k_oop, oop initiating_loader, TRAPS); + static void dump_methods(); - static void dump_methods() PRODUCT_RETURN; - public: VM_RedefineClasses(jint class_count, const jvmtiClassDefinition *class_defs, --- old/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Mon Feb 4 12:53:04 2013 +++ new/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Mon Feb 4 12:53:04 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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 @@ -54,7 +54,7 @@ // 0x00000800 | 2048 - previous class breakpoint mgmt // 0x00001000 | 4096 - detect calls to obsolete methods // 0x00002000 | 8192 - fail a guarantee() in addition to detection -// 0x00004000 | 16384 - unused +// 0x00004000 | 16384 - detect old/obsolete methods in metadata // 0x00008000 | 32768 - old/new method matching/add/delete // 0x00010000 | 65536 - impl details: CP size info // 0x00020000 | 131072 - impl details: CP merge pass info @@ -82,6 +82,13 @@ tty->print_cr args; \ } while (0) +#define RC_TRACE_NO_CR(level, args) \ + if ((TraceRedefineClasses & level) != 0) { \ + ResourceMark rm; \ + tty->print("RedefineClasses-0x%x: ", level); \ + tty->print args; \ + } while (0) + #define RC_TRACE_WITH_THREAD(level, thread, args) \ if ((TraceRedefineClasses & level) != 0) { \ ResourceMark rm(thread); \ --- old/src/share/vm/utilities/accessFlags.cpp Mon Feb 4 12:53:05 2013 +++ new/src/share/vm/utilities/accessFlags.cpp Mon Feb 4 12:53:05 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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 @@ -59,8 +59,6 @@ } while(f != old_flags); } -#ifndef PRODUCT - void AccessFlags::print_on(outputStream* st) const { if (is_public ()) st->print("public " ); if (is_private ()) st->print("private " ); @@ -79,8 +77,6 @@ if (is_obsolete ()) st->print("{obsolete} " ); } -#endif - void accessFlags_init() { assert(sizeof(AccessFlags) == sizeof(jint), "just checking size of flags"); } --- old/src/share/vm/utilities/accessFlags.hpp Mon Feb 4 12:53:05 2013 +++ new/src/share/vm/utilities/accessFlags.hpp Mon Feb 4 12:53:05 2013 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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 @@ -229,7 +229,7 @@ inline friend AccessFlags accessFlags_from(jint flags); // Printing/debugging - void print_on(outputStream* st) const PRODUCT_RETURN; + void print_on(outputStream* st) const; }; inline AccessFlags accessFlags_from(jint flags) {