< prev index next >

src/share/vm/oops/instanceKlass.cpp

Print this page

        

*** 1828,1987 **** // // Walk the list of dependent nmethods searching for nmethods which // are dependent on the changes that were passed in and mark them for // deoptimization. Returns the number of nmethods found. // ! int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { assert_locked_or_safepoint(CodeCache_lock); int found = 0; ! nmethodBucket* b = _dependencies; ! while (b != NULL) { nmethod* nm = b->get_nmethod(); // since dependencies aren't removed until an nmethod becomes a zombie, // the dependency list may contain nmethods which aren't alive. if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) { if (TraceDependencies) { ResourceMark rm; tty->print_cr("Marked for deoptimization"); - tty->print_cr(" context = %s", this->external_name()); changes.print(); nm->print(); nm->print_dependencies(); } nm->mark_for_deoptimization(); found++; } - b = b->next(); } return found; } - void InstanceKlass::clean_dependent_nmethods() { - assert_locked_or_safepoint(CodeCache_lock); - - if (has_unloaded_dependent()) { - nmethodBucket* b = _dependencies; - nmethodBucket* last = NULL; - while (b != NULL) { - assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); - - nmethodBucket* next = b->next(); - - if (b->count() == 0) { - if (last == NULL) { - _dependencies = next; - } else { - last->set_next(next); - } - delete b; - // last stays the same. - } else { - last = b; - } - - b = next; - } - set_has_unloaded_dependent(false); - } - #ifdef ASSERT - else { - // Verification - for (nmethodBucket* b = _dependencies; b != NULL; b = b->next()) { - assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); - assert(b->count() != 0, "empty buckets need to be cleaned"); - } - } - #endif - } - // // Add an nmethodBucket to the list of dependencies for this nmethod. // It's possible that an nmethod has multiple dependencies on this klass // so a count is kept for each bucket to guarantee that creation and ! // deletion of dependencies is consistent. // ! void InstanceKlass::add_dependent_nmethod(nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); ! nmethodBucket* b = _dependencies; ! nmethodBucket* last = NULL; ! while (b != NULL) { if (nm == b->get_nmethod()) { b->increment(); ! return; } - b = b->next(); } ! _dependencies = new nmethodBucket(nm, _dependencies); } - // // Decrement count of the nmethod in the dependency list and remove ! // the bucket competely when the count goes to 0. This method must // find a corresponding bucket otherwise there's a bug in the ! // recording of dependecies. // ! void InstanceKlass::remove_dependent_nmethod(nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); ! nmethodBucket* b = _dependencies; ! nmethodBucket* last = NULL; ! while (b != NULL) { if (nm == b->get_nmethod()) { int val = b->decrement(); guarantee(val >= 0, err_msg("Underflow: %d", val)); ! if (val == 0) { ! set_has_unloaded_dependent(true); ! } ! return; } - last = b; - b = b->next(); } #ifdef ASSERT ! tty->print_cr("### %s can't find dependent nmethod:", this->external_name()); nm->print(); #endif // ASSERT ShouldNotReachHere(); } #ifndef PRODUCT ! void InstanceKlass::print_dependent_nmethods(bool verbose) { ! nmethodBucket* b = _dependencies; int idx = 0; ! while (b != NULL) { nmethod* nm = b->get_nmethod(); tty->print("[%d] count=%d { ", idx++, b->count()); if (!verbose) { nm->print_on(tty, "nmethod"); tty->print_cr(" } "); } else { nm->print(); nm->print_dependencies(); tty->print_cr("--- } "); } - b = b->next(); } } ! ! bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { ! nmethodBucket* b = _dependencies; ! while (b != NULL) { if (nm == b->get_nmethod()) { #ifdef ASSERT int count = b->count(); assert(count >= 0, err_msg("count shouldn't be negative: %d", count)); #endif return true; } - b = b->next(); } return false; } #endif //PRODUCT void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { assert(class_loader_data()->is_alive(is_alive), "this klass should be live"); if (is_interface()) { if (ClassUnloading) { Klass* impl = implementor(); --- 1828,2004 ---- // // Walk the list of dependent nmethods searching for nmethods which // are dependent on the changes that were passed in and mark them for // deoptimization. Returns the number of nmethods found. // ! int nmethodBucket::mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes) { assert_locked_or_safepoint(CodeCache_lock); int found = 0; ! for (nmethodBucket* b = deps; b != NULL; b = b->next()) { nmethod* nm = b->get_nmethod(); // since dependencies aren't removed until an nmethod becomes a zombie, // the dependency list may contain nmethods which aren't alive. if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) { if (TraceDependencies) { ResourceMark rm; tty->print_cr("Marked for deoptimization"); changes.print(); nm->print(); nm->print_dependencies(); } nm->mark_for_deoptimization(); found++; } } return found; } // // Add an nmethodBucket to the list of dependencies for this nmethod. // It's possible that an nmethod has multiple dependencies on this klass // so a count is kept for each bucket to guarantee that creation and ! // deletion of dependencies is consistent. Returns new head of the list. // ! nmethodBucket* nmethodBucket::add_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); ! for (nmethodBucket* b = deps; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { b->increment(); ! return deps; } } ! return new nmethodBucket(nm, deps); } // // Decrement count of the nmethod in the dependency list and remove ! // the bucket completely when the count goes to 0. This method must // find a corresponding bucket otherwise there's a bug in the ! // recording of dependencies. Returns true if the bucket is ready for reclamation. // ! bool nmethodBucket::remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); ! ! for (nmethodBucket* b = deps; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { int val = b->decrement(); guarantee(val >= 0, err_msg("Underflow: %d", val)); ! return (val == 0); } } #ifdef ASSERT ! tty->print_raw_cr("### can't find dependent nmethod"); nm->print(); #endif // ASSERT ShouldNotReachHere(); + return false; } + // + // Reclaim all unused buckets. Returns new head of the list. + // + nmethodBucket* nmethodBucket::clean_dependent_nmethods(nmethodBucket* deps) { + nmethodBucket* first = deps; + nmethodBucket* last = NULL; + nmethodBucket* b = first; + + while (b != NULL) { + assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); + nmethodBucket* next = b->next(); + if (b->count() == 0) { + if (last == NULL) { + first = next; + } else { + last->set_next(next); + } + delete b; + // last stays the same. + } else { + last = b; + } + b = next; + } + return first; + } #ifndef PRODUCT ! void nmethodBucket::print_dependent_nmethods(nmethodBucket* deps, bool verbose) { int idx = 0; ! for (nmethodBucket* b = deps; b != NULL; b = b->next()) { nmethod* nm = b->get_nmethod(); tty->print("[%d] count=%d { ", idx++, b->count()); if (!verbose) { nm->print_on(tty, "nmethod"); tty->print_cr(" } "); } else { nm->print(); nm->print_dependencies(); tty->print_cr("--- } "); } } } ! bool nmethodBucket::is_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { ! for (nmethodBucket* b = deps; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { #ifdef ASSERT int count = b->count(); assert(count >= 0, err_msg("count shouldn't be negative: %d", count)); #endif return true; } } return false; } #endif //PRODUCT + int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { + assert_locked_or_safepoint(CodeCache_lock); + return nmethodBucket::mark_dependent_nmethods(_dependencies, changes); + } + + void InstanceKlass::clean_dependent_nmethods() { + assert_locked_or_safepoint(CodeCache_lock); + + if (has_unloaded_dependent()) { + _dependencies = nmethodBucket::clean_dependent_nmethods(_dependencies); + set_has_unloaded_dependent(false); + } + #ifdef ASSERT + else { + // Verification + for (nmethodBucket* b = _dependencies; b != NULL; b = b->next()) { + assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); + assert(b->count() != 0, "empty buckets need to be cleaned"); + } + } + #endif + } + + void InstanceKlass::add_dependent_nmethod(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + _dependencies = nmethodBucket::add_dependent_nmethod(_dependencies, nm); + } + + void InstanceKlass::remove_dependent_nmethod(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + + if (nmethodBucket::remove_dependent_nmethod(_dependencies, nm)) { + set_has_unloaded_dependent(true); + } + } + + #ifndef PRODUCT + void InstanceKlass::print_dependent_nmethods(bool verbose) { + nmethodBucket::print_dependent_nmethods(_dependencies, verbose); + } + + bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { + return nmethodBucket::is_dependent_nmethod(_dependencies, nm); + } + #endif //PRODUCT + void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { assert(class_loader_data()->is_alive(is_alive), "this klass should be live"); if (is_interface()) { if (ClassUnloading) { Klass* impl = implementor();
< prev index next >