< prev index next >
src/share/vm/oops/instanceKlass.cpp
Print this page
@@ -1828,160 +1828,177 @@
//
// 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) {
+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.
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.
+// 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) {
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) {
+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;
}
- 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()) {
if (ClassUnloading) {
Klass* impl = implementor();
< prev index next >