--- old/src/share/vm/oops/instanceKlass.cpp 2015-05-14 15:17:33.000000000 +0300 +++ new/src/share/vm/oops/instanceKlass.cpp 2015-05-14 15:17:33.000000000 +0300 @@ -1830,11 +1830,10 @@ // 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) { +int nmethodBucket::mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes) { assert_locked_or_safepoint(CodeCache_lock); int found = 0; - nmethodBucket* b = _dependencies; - while (b != NULL) { + 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. @@ -1842,7 +1841,6 @@ 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(); @@ -1850,105 +1848,82 @@ 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. +// deletion of dependencies is consistent. Returns new head of the list. // -void InstanceKlass::add_dependent_nmethod(nmethod* nm) { +nmethodBucket* nmethodBucket::add_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); - nmethodBucket* b = _dependencies; - nmethodBucket* last = NULL; - while (b != NULL) { + for (nmethodBucket* b = deps; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { b->increment(); - return; + return deps; } - b = b->next(); } - _dependencies = new nmethodBucket(nm, _dependencies); + return new nmethodBucket(nm, deps); } - // // Decrement count of the nmethod in the dependency list and remove -// the bucket competely when the count goes to 0. This method must +// 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 dependecies. +// recording of dependencies. Returns true if the bucket is ready for reclamation. // -void InstanceKlass::remove_dependent_nmethod(nmethod* nm) { +bool nmethodBucket::remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); - nmethodBucket* b = _dependencies; - nmethodBucket* last = NULL; - while (b != NULL) { + + 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)); - if (val == 0) { - set_has_unloaded_dependent(true); - } - return; + return (val == 0); } - last = b; - b = b->next(); } #ifdef ASSERT - tty->print_cr("### %s can't find dependent nmethod:", this->external_name()); + 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 InstanceKlass::print_dependent_nmethods(bool verbose) { - nmethodBucket* b = _dependencies; +void nmethodBucket::print_dependent_nmethods(nmethodBucket* deps, bool verbose) { int idx = 0; - while (b != NULL) { + for (nmethodBucket* b = deps; b != NULL; b = b->next()) { nmethod* nm = b->get_nmethod(); tty->print("[%d] count=%d { ", idx++, b->count()); if (!verbose) { @@ -1959,14 +1934,11 @@ nm->print_dependencies(); tty->print_cr("--- } "); } - b = b->next(); } } - -bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { - nmethodBucket* b = _dependencies; - while (b != NULL) { +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(); @@ -1974,12 +1946,57 @@ #endif return true; } - b = b->next(); } 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()) {