# HG changeset patch # User Tom Rodriguez # Date 1395951077 25200 # Node ID 8762b6b8fbb64f122a615de89ccfd33b5783c487 # Parent 4f5c312d676e0060977f84d2ece6b5cf13e1d19d fix scanning of method data for redefined methods diff -r 4f5c312d676e -r 8762b6b8fbb6 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Thu Mar 27 18:35:55 2014 +0100 +++ b/src/share/vm/oops/instanceKlass.cpp Thu Mar 27 13:11:17 2014 -0700 @@ -3411,6 +3411,10 @@ ("purge: %s(%s): prev method @%d in version @%d is alive", method->name()->as_C_string(), method->signature()->as_C_string(), j, i)); + if (method->method_data() != NULL) { + // Clean out any weak method links + method->method_data()->clean_weak_method_links(); + } } } } @@ -3420,6 +3424,14 @@ ("purge: previous version stats: live=%d, deleted=%d", live_count, deleted_count)); } + + Array* methods = ik->methods(); + int num_methods = methods->length(); + for (int index2 = 0; index2 < num_methods; ++index2) { + if (methods->at(index2)->method_data() != NULL) { + methods->at(index2)->method_data()->clean_weak_method_links(); + } + } } // External interface for use during class unloading. diff -r 4f5c312d676e -r 8762b6b8fbb6 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Thu Mar 27 18:35:55 2014 +0100 +++ b/src/share/vm/oops/methodData.cpp Thu Mar 27 13:11:17 2014 -0700 @@ -426,6 +426,16 @@ } } } + +void VirtualCallData::clean_weak_method_links() { + ReceiverTypeData::clean_weak_method_links(); + for (uint row = 0; row < method_row_limit(); row++) { + Method* p = method(row); + if (p != NULL && !p->on_stack()) { + clear_method_row(row); + } + } +} #endif // GRAAL #ifndef PRODUCT @@ -1693,3 +1703,85 @@ clean_extra_data(is_alive); verify_extra_data_clean(is_alive); } + +// Remove SpeculativeTrapData entries that reference a redefined +// method +void MethodData::clean_weak_method_extra_data() { + DataLayout* dp = extra_data_base(); + DataLayout* end = extra_data_limit(); + + int shift = 0; + for (; dp < end; dp = next_extra(dp)) { + switch(dp->tag()) { + case DataLayout::speculative_trap_data_tag: { + SpeculativeTrapData* data = new SpeculativeTrapData(dp); + Method* m = data->method(); + assert(m != NULL, "should have a method"); + if (!m->on_stack()) { + // "shift" accumulates the number of cells for dead + // SpeculativeTrapData entries that have been seen so + // far. Following entries must be shifted left by that many + // cells to remove the dead SpeculativeTrapData entries. + shift += (int)((intptr_t*)next_extra(dp) - (intptr_t*)dp); + } else { + // Shift this entry left if it follows dead + // SpeculativeTrapData entries + clean_extra_data_helper(dp, shift); + } + break; + } + case DataLayout::bit_data_tag: + // Shift this entry left if it follows dead SpeculativeTrapData + // entries + clean_extra_data_helper(dp, shift); + continue; + case DataLayout::no_tag: + case DataLayout::arg_info_data_tag: + // We are at end of the live trap entries. The previous "shift" + // cells contain entries that are either dead or were shifted + // left. They need to be reset to no_tag + clean_extra_data_helper(dp, shift, true); + return; + default: + fatal(err_msg("unexpected tag %d", dp->tag())); + } + } +} + +// Verify there's no redefined method referenced by a +// SpeculativeTrapData entry +void MethodData::verify_weak_method_extra_data_clean() { +#ifdef ASSERT + DataLayout* dp = extra_data_base(); + DataLayout* end = extra_data_limit(); + + for (; dp < end; dp = next_extra(dp)) { + switch(dp->tag()) { + case DataLayout::speculative_trap_data_tag: { + SpeculativeTrapData* data = new SpeculativeTrapData(dp); + Method* m = data->method(); + assert(m != NULL && m->on_stack(), "Method should exist"); + break; + } + case DataLayout::bit_data_tag: + continue; + case DataLayout::no_tag: + case DataLayout::arg_info_data_tag: + return; + default: + fatal(err_msg("unexpected tag %d", dp->tag())); + } + } +#endif +} + +void MethodData::clean_weak_method_links() { + for (ProfileData* data = first_data(); + is_valid(data); + data = next_data(data)) { + data->clean_weak_method_links(); + } + + clean_weak_method_extra_data(); + verify_weak_method_extra_data_clean(); +} diff -r 4f5c312d676e -r 8762b6b8fbb6 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Thu Mar 27 18:35:55 2014 +0100 +++ b/src/share/vm/oops/methodData.hpp Thu Mar 27 13:11:17 2014 -0700 @@ -257,6 +257,9 @@ // GC support void clean_weak_klass_links(BoolObjectClosure* cl); + + // Redefinition support + void clean_weak_method_links(); }; @@ -514,6 +517,9 @@ // GC support virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {} + // Redefinition support + virtual void clean_weak_method_links() {} + // CI translation: ProfileData can represent both MethodDataOop data // as well as CIMethodData data. This function is provided for translating // an oop in a ProfileData to the ci equivalent. Generally speaking, @@ -1429,6 +1435,9 @@ // GC support virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); + + // Redefinition support + virtual void clean_weak_method_links(); #endif #ifndef PRODUCT @@ -2294,6 +2303,10 @@ void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false); void verify_extra_data_clean(BoolObjectClosure* is_alive); + // Redefinition support + void clean_weak_method_extra_data(); + void verify_weak_method_extra_data_clean(); + public: static int header_size() { return sizeof(MethodData)/wordSize; @@ -2572,6 +2585,8 @@ static bool profile_return_jsr292_only(); void clean_method_data(BoolObjectClosure* is_alive); + + void clean_weak_method_links(); }; #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP