--- old/src/share/vm/code/nmethod.cpp 2014-07-14 12:14:47.847792339 +0200 +++ new/src/share/vm/code/nmethod.cpp 2014-07-14 12:14:47.719792343 +0200 @@ -1718,6 +1718,24 @@ 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. @@ -1753,15 +1771,33 @@ 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); - clean_ic_if_metadata_is_dead(ic, is_alive); + 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; + } } } } @@ -1880,10 +1916,24 @@ 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;