< prev index next >

src/hotspot/share/code/compiledMethod.cpp

 #include "precompiled.hpp"
 #include "code/compiledIC.hpp"
 #include "code/compiledMethod.inline.hpp"
 #include "code/scopeDesc.hpp"
 #include "code/codeCache.hpp"
+#include "code/icBuffer.hpp"
 #include "gc/shared/barrierSet.hpp"
 #include "gc/shared/gcBehaviours.hpp"
 #include "interpreter/bytecode.inline.hpp"
 #include "logging/log.hpp"
 #include "logging/logTag.hpp"

@@ -428,39 +429,39 assert(klass->is_loader_alive(), "must be alive"); } #endif // ASSERT -void CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic) { +bool CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic) { if (ic->is_icholder_call()) { // The only exception is compiledICHolder metdata which may // yet be marked below. (We check this further below). CompiledICHolder* cichk_metdata = ic->cached_icholder(); if (cichk_metdata->is_loader_alive()) { - return; + return true; } } else { Metadata* ic_metdata = ic->cached_metadata(); if (ic_metdata != NULL) { if (ic_metdata->is_klass()) { if (((Klass*)ic_metdata)->is_loader_alive()) { - return; + return true; } } else if (ic_metdata->is_method()) { Method* method = (Method*)ic_metdata; assert(!method->is_old(), "old method should have been cleaned"); if (method->method_holder()->is_loader_alive()) { - return; + return true; } } else { ShouldNotReachHere(); } } } - ic->set_to_clean(); + 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.
@@ -494,61 +495,78 #endif } // Clean references to unloaded nmethods at addr from this one, which is not unloaded. template <class CompiledICorStaticCall> -static void clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address addr, CompiledMethod* from, +static bool clean_if_nmethod_is_unloaded(CompiledICorStaticCall *ic, address addr, CompiledMethod* from, bool clean_all) { // Ok, to lookup references to zombies here CodeBlob *cb = CodeCache::find_blob_unsafe(addr); CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL; if (nm != NULL) { // Clean inline caches pointing to both zombie and not_entrant methods if (clean_all || !nm->is_in_use() || nm->is_unloading() || (nm->method()->code() != nm)) { - ic->set_to_clean(from->is_alive()); + if (!ic->set_to_clean(from->is_alive())) { + return false; + } assert(ic->is_clean(), "nmethod " PTR_FORMAT "not clean %s", p2i(from), from->method()->name_and_sig_as_C_string()); } } + return true; } -static void clean_if_nmethod_is_unloaded(CompiledIC *ic, CompiledMethod* from, +static bool clean_if_nmethod_is_unloaded(CompiledIC *ic, CompiledMethod* from, bool clean_all) { - clean_if_nmethod_is_unloaded(ic, ic->ic_destination(), from, clean_all); + return clean_if_nmethod_is_unloaded(ic, ic->ic_destination(), from, clean_all); } -static void clean_if_nmethod_is_unloaded(CompiledStaticCall *csc, CompiledMethod* from, +static bool clean_if_nmethod_is_unloaded(CompiledStaticCall *csc, CompiledMethod* from, bool clean_all) { - clean_if_nmethod_is_unloaded(csc, csc->destination(), from, clean_all); + return clean_if_nmethod_is_unloaded(csc, csc->destination(), from, clean_all); } // Cleans caches in nmethods that point to either classes that are unloaded // or nmethods that are unloaded. // // Can be called either in parallel by G1 currently or after all // nmethods are unloaded. Return postponed=true in the parallel case for // inline caches found that point to nmethods that are not yet visited during // the do_unloading walk. -void CompiledMethod::unload_nmethod_caches(bool unloading_occurred) { +bool CompiledMethod::unload_nmethod_caches(bool unloading_occurred) { ResourceMark rm; // Exception cache only needs to be called if unloading occurred if (unloading_occurred) { clean_exception_cache(); } - cleanup_inline_caches_impl(unloading_occurred, false); + if (!cleanup_inline_caches_impl(unloading_occurred, false)) { + return false; + } // All static stubs need to be cleaned. clean_ic_stubs(); // Check that the metadata embedded in the nmethod is alive DEBUG_ONLY(metadata_do(check_class)); + return true; +} + +void CompiledMethod::cleanup_inline_caches(bool clean_all) { + for (;;) { + { CompiledICLocker ic_locker(this); + if (cleanup_inline_caches_impl(false, clean_all)) { + return; + } + } + InlineCacheBuffer::refill_ic_stubs(); + } } // Called to clean up after class unloading for live nmethods and from the sweeper // for all methods. -void CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) { +bool CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) { assert(CompiledICLocker::is_safe(this), "mt unsafe call"); ResourceMark rm; // Find all calls in an nmethod and clear the ones that point to non-entrant, // zombie and unloaded nmethods.
@@ -559,34 +577,38 case relocInfo::virtual_call_type: if (unloading_occurred) { // If class unloading occurred we first clear ICs where the cached metadata // is referring to an unloaded klass or method. - clean_ic_if_metadata_is_dead(CompiledIC_at(&iter)); + if (!clean_ic_if_metadata_is_dead(CompiledIC_at(&iter))) { + return false; + } } - clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all); + if (!clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all)) { + return false; + } break; case relocInfo::opt_virtual_call_type: - clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all); + if (!clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all)) { + return false; + } break; case relocInfo::static_call_type: - clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), this, clean_all); - break; - - case relocInfo::oop_type: + if (!clean_if_nmethod_is_unloaded(compiledStaticCall_at(iter.reloc()), this, clean_all)) { + return false; + } break; - case relocInfo::metadata_type: - break; // nothing to do. - default: break; } } + + return true; } // Iterating over all nmethods, e.g. with the help of CodeCache::nmethods_do(fun) was found // to not be inherently safe. There is a chance that fields are seen which are not properly // initialized. This happens despite the fact that nmethods_do() asserts the CodeCache_lock
< prev index next >