diff -r d7819bedfaaf -r e9db10a375d9 src/hotspot/share/code/compiledMethod.cpp --- a/src/hotspot/share/code/compiledMethod.cpp Tue May 14 12:00:49 2019 +0200 +++ b/src/hotspot/share/code/compiledMethod.cpp Tue May 14 12:07:24 2019 +0200 @@ -468,39 +468,6 @@ return ic->set_to_clean(); } -// static_stub_Relocations may have dangling references to -// nmethods so trim them out here. Otherwise it looks like -// compiled code is maintaining a link to dead metadata. -void CompiledMethod::clean_ic_stubs() { -#ifdef ASSERT - address low_boundary = oops_reloc_begin(); - RelocIterator iter(this, low_boundary); - while (iter.next()) { - address static_call_addr = NULL; - if (iter.type() == relocInfo::opt_virtual_call_type) { - CompiledIC* cic = CompiledIC_at(&iter); - if (!cic->is_call_to_interpreted()) { - static_call_addr = iter.addr(); - } - } else if (iter.type() == relocInfo::static_call_type) { - CompiledStaticCall* csc = compiledStaticCall_at(iter.reloc()); - if (!csc->is_call_to_interpreted()) { - static_call_addr = iter.addr(); - } - } - if (static_call_addr != NULL) { - RelocIterator sciter(this, low_boundary); - while (sciter.next()) { - if (sciter.type() == relocInfo::static_stub_type && - sciter.static_stub_reloc()->static_call() == static_call_addr) { - sciter.static_stub_reloc()->clear_inline_cache(); - } - } - } - } -#endif -} - // Clean references to unloaded nmethods at addr from this one, which is not unloaded. template static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address addr, CompiledMethod* from, @@ -549,9 +516,6 @@ return false; } - // All static stubs need to be cleaned. - clean_ic_stubs(); - #ifdef ASSERT // Check that the metadata embedded in the nmethod is alive CheckClass check_class; @@ -581,6 +545,7 @@ // Find all calls in an nmethod and clear the ones that point to non-entrant, // zombie and unloaded nmethods. RelocIterator iter(this, oops_reloc_begin()); + bool is_in_static_stub = false; while(iter.next()) { switch (iter.type()) { @@ -611,6 +576,45 @@ } break; + case relocInfo::static_stub_type: { + is_in_static_stub = true; + break; + } + + case relocInfo::metadata_type: { + // Only the metadata relocations contained in static/opt virtual call stubs + // contains the Method* passed to c2i adapters. It is the only metadata + // relocation that needs to be walked, as it is the one metadata relocation + // that violates the invariant that all metadata relocations have an oop + // in the compiled method (due to deferred resolution and code patching). + + // This causes dead metadata to remain in compiled methods that are not + // unloading. Unless these slippery metadata relocations of the static + // stubs are at least cleared, subsequent class redefinition operations + // will access potentially free memory, and JavaThread execution + // concurrent to class unloading may call c2i adapters with dead methods. + if (!is_in_static_stub) { + // The first metadata relocation after a static stub relocation is the + // metadata relocation of the static stub used to pass the Method* to + // c2i adapters. + continue; + } + is_in_static_stub = false; + metadata_Relocation* r = iter.metadata_reloc(); + Metadata* md = r->metadata_value(); + if (md != NULL && md->is_method()) { + Method* method = static_cast(md); + if (!method->method_holder()->is_loader_alive()) { + Atomic::store((Method*)NULL, r->metadata_addr()); + + if (!r->metadata_is_immediate()) { + r->fix_metadata_relocation(); + } + } + } + break; + } + default: break; }