< 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"
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.
#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.
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 >