提交 b6ea71f0 编写于 作者: T thartmann

8134493: Cleaning inline caches of unloaded nmethods should be done in sweeper

Summary: Clean ICs of unloaded nmethods in sweeper to avoid impact on safepoint duration.
Reviewed-by: kvn, mdoerr
上级 e32f7c80
...@@ -521,13 +521,12 @@ void CodeCache::gc_prologue() { ...@@ -521,13 +521,12 @@ void CodeCache::gc_prologue() {
void CodeCache::gc_epilogue() { void CodeCache::gc_epilogue() {
assert_locked_or_safepoint(CodeCache_lock); assert_locked_or_safepoint(CodeCache_lock);
FOR_ALL_ALIVE_BLOBS(cb) { NOT_DEBUG(if (needs_cache_clean())) {
if (cb->is_nmethod()) { FOR_ALL_ALIVE_BLOBS(cb) {
nmethod *nm = (nmethod*)cb; if (cb->is_nmethod()) {
if (!nm->is_zombie()) { nmethod *nm = (nmethod*)cb;
if (needs_cache_clean()) { assert(!nm->is_unloaded(), "Tautology");
// Clean ICs of unloaded nmethods as well because they may reference other DEBUG_ONLY(if (needs_cache_clean())) {
// unloaded nmethods that may be flushed earlier in the sweeper cycle.
nm->cleanup_inline_caches(); nm->cleanup_inline_caches();
} }
DEBUG_ONLY(nm->verify()); DEBUG_ONLY(nm->verify());
......
...@@ -287,6 +287,7 @@ bool CompiledIC::is_call_to_compiled() const { ...@@ -287,6 +287,7 @@ bool CompiledIC::is_call_to_compiled() const {
assert( is_c1_method || assert( is_c1_method ||
!is_monomorphic || !is_monomorphic ||
is_optimized() || is_optimized() ||
!caller->is_alive() ||
(cached_metadata() != NULL && cached_metadata()->is_klass()), "sanity check"); (cached_metadata() != NULL && cached_metadata()->is_klass()), "sanity check");
#endif // ASSERT #endif // ASSERT
return is_monomorphic; return is_monomorphic;
...@@ -321,7 +322,7 @@ bool CompiledIC::is_call_to_interpreted() const { ...@@ -321,7 +322,7 @@ bool CompiledIC::is_call_to_interpreted() const {
} }
void CompiledIC::set_to_clean() { void CompiledIC::set_to_clean(bool in_use) {
assert(SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->is_locked() , "MT-unsafe call"); assert(SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->is_locked() , "MT-unsafe call");
if (TraceInlineCacheClearing || TraceICs) { if (TraceInlineCacheClearing || TraceICs) {
tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address())); tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address()));
...@@ -337,7 +338,7 @@ void CompiledIC::set_to_clean() { ...@@ -337,7 +338,7 @@ void CompiledIC::set_to_clean() {
// A zombie transition will always be safe, since the metadata has already been set to NULL, so // A zombie transition will always be safe, since the metadata has already been set to NULL, so
// we only need to patch the destination // we only need to patch the destination
bool safe_transition = is_optimized() || SafepointSynchronize::is_at_safepoint(); bool safe_transition = !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint();
if (safe_transition) { if (safe_transition) {
// Kill any leftover stub we might have too // Kill any leftover stub we might have too
......
...@@ -228,7 +228,7 @@ class CompiledIC: public ResourceObj { ...@@ -228,7 +228,7 @@ class CompiledIC: public ResourceObj {
// //
// They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full. // They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full.
// //
void set_to_clean(); void set_to_clean(bool in_use = true);
void set_to_monomorphic(CompiledICInfo& info); void set_to_monomorphic(CompiledICInfo& info);
void clear_ic_stub(); void clear_ic_stub();
......
...@@ -1191,7 +1191,7 @@ void nmethod::cleanup_inline_caches() { ...@@ -1191,7 +1191,7 @@ void nmethod::cleanup_inline_caches() {
if( cb != NULL && cb->is_nmethod() ) { if( cb != NULL && cb->is_nmethod() ) {
nmethod* nm = (nmethod*)cb; nmethod* nm = (nmethod*)cb;
// Clean inline caches pointing to zombie, non-entrant and unloaded methods // Clean inline caches pointing to zombie, non-entrant and unloaded methods
if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(); if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive());
} }
break; break;
} }
...@@ -1291,7 +1291,7 @@ void nmethod::mark_as_seen_on_stack() { ...@@ -1291,7 +1291,7 @@ void nmethod::mark_as_seen_on_stack() {
// Tell if a non-entrant method can be converted to a zombie (i.e., // Tell if a non-entrant method can be converted to a zombie (i.e.,
// there are no activations on the stack, not in use by the VM, // there are no activations on the stack, not in use by the VM,
// and not in use by the ServiceThread) // and not in use by the ServiceThread)
bool nmethod::can_not_entrant_be_converted() { bool nmethod::can_convert_to_zombie() {
assert(is_not_entrant(), "must be a non-entrant method"); assert(is_not_entrant(), "must be a non-entrant method");
// Since the nmethod sweeper only does partial sweep the sweeper's traversal // Since the nmethod sweeper only does partial sweep the sweeper's traversal
......
...@@ -605,7 +605,7 @@ public: ...@@ -605,7 +605,7 @@ public:
// See comment at definition of _last_seen_on_stack // See comment at definition of _last_seen_on_stack
void mark_as_seen_on_stack(); void mark_as_seen_on_stack();
bool can_not_entrant_be_converted(); bool can_convert_to_zombie();
// Evolution support. We make old (discarded) compiled methods point to new Method*s. // Evolution support. We make old (discarded) compiled methods point to new Method*s.
void set_method(Method* method) { _method = method; } void set_method(Method* method) { _method = method; }
......
...@@ -538,7 +538,7 @@ int NMethodSweeper::process_nmethod(nmethod *nm) { ...@@ -538,7 +538,7 @@ int NMethodSweeper::process_nmethod(nmethod *nm) {
} else if (nm->is_not_entrant()) { } else if (nm->is_not_entrant()) {
// If there are no current activations of this method on the // If there are no current activations of this method on the
// stack we can safely convert it to a zombie method // stack we can safely convert it to a zombie method
if (nm->can_not_entrant_be_converted()) { if (nm->can_convert_to_zombie()) {
if (PrintMethodFlushing && Verbose) { if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
} }
...@@ -571,6 +571,12 @@ int NMethodSweeper::process_nmethod(nmethod *nm) { ...@@ -571,6 +571,12 @@ int NMethodSweeper::process_nmethod(nmethod *nm) {
release_nmethod(nm); release_nmethod(nm);
_flushed_count++; _flushed_count++;
} else { } else {
{
// Clean ICs of unloaded nmethods as well because they may reference other
// unloaded nmethods that may be flushed earlier in the sweeper cycle.
MutexLocker cl(CompiledIC_lock);
nm->cleanup_inline_caches();
}
// Code cache state change is tracked in make_zombie() // Code cache state change is tracked in make_zombie()
nm->make_zombie(); nm->make_zombie();
_zombified_count++; _zombified_count++;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册