src/share/vm/code/nmethod.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File
*** old/src/share/vm/code/nmethod.cpp	Mon Jul 14 12:14:47 2014
--- new/src/share/vm/code/nmethod.cpp	Mon Jul 14 12:14:47 2014

*** 1716,1725 **** --- 1716,1743 ---- } ic->set_to_clean(); } + /** + * Checks if the to-interpreter stub of an optimized compiled IC or a compiled + * static call contains a reference to dead Method* metadata. + */ + bool nmethod::stub_contains_dead_metadata(BoolObjectClosure* is_alive, address stub) { + RelocIterator iter(this, stub, stub + CompiledStaticCall::to_interp_stub_size()); + while (iter.next()) { + if (iter.type() == relocInfo::metadata_type) { + Metadata* md = iter.metadata_reloc()->metadata_value(); + // Check if class loader of holder Klass is alive + if (md != NULL && md->is_method() && !((Method*)md)->method_holder()->is_loader_alive(is_alive)) { + return true; + } + } + } + return false; + } + // This is called at the end of the strong tracing/marking phase of a // GC to unload an nmethod if it contains otherwise unreachable // oops. void nmethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred) {
*** 1751,1769 **** --- 1769,1805 ---- // Exception cache clean_exception_cache(is_alive); // If class unloading occurred we first iterate over all inline caches and ! // clear ICs where the cached oop is referring to an unloaded klass or method. // The remaining live cached oops will be traversed in the relocInfo::oop_type // iteration below. ! // clear ICs where the cached oop or the to-interpreter stub (if in use) is + // referring to an unloaded klass or method. The to-interpreter stubs of + // compiled static calls are checked as well. The remaining live cached oops + // will be traversed in the relocInfo::oop_type iteration below. if (unloading_occurred) { RelocIterator iter(this, low_boundary); while(iter.next()) { ! if (iter.type() == relocInfo::virtual_call_type) { CompiledIC *ic = CompiledIC_at(&iter); ! switch (iter.type()) { + case relocInfo::virtual_call_type: { + CompiledIC* ic = CompiledIC_at(&iter); clean_ic_if_metadata_is_dead(ic, is_alive); + break; + } + case relocInfo::opt_virtual_call_type: { + CompiledIC* ic = CompiledIC_at(&iter); + if (ic->is_call_to_interpreted() && stub_contains_dead_metadata(is_alive, ic->ic_destination())) { + ic->set_to_clean(); + } + break; + } + case relocInfo::static_call_type: { + CompiledStaticCall* csc = compiledStaticCall_at(iter.reloc()); + if (csc->is_call_to_interpreted() && stub_contains_dead_metadata(is_alive, csc->destination())) { + csc->set_to_clean(); + } + break; + } } } } // Compiled code
*** 1878,1891 **** --- 1914,1941 ---- postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this); break; case relocInfo::opt_virtual_call_type: + if (unloading_occurred) { + // Clear IC if it calls a to-interpreter stub that refers to an unloaded method + CompiledIC* ic = CompiledIC_at(&iter); + if (ic->is_call_to_interpreted() && stub_contains_dead_metadata(is_alive, ic->ic_destination())) { + ic->set_to_clean(); + } + } postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this); break; case relocInfo::static_call_type: + if (unloading_occurred) { + // Clear call if it targets a to-interpreter stub that refers to an unloaded method + CompiledStaticCall* csc = compiledStaticCall_at(iter.reloc()); + if (csc->is_call_to_interpreted() && stub_contains_dead_metadata(is_alive, csc->destination())) { + csc->set_to_clean(); + } + } postponed |= clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), is_alive, this); break; case relocInfo::oop_type: if (!is_unloaded) {

src/share/vm/code/nmethod.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File