< prev index next >

src/share/vm/oops/instanceKlass.cpp

Print this page

        

*** 1811,1833 **** id = jmeths[idnum+1]; // Look up the id (may be NULL) } return id; } ! int nmethodBucket::decrement() { return Atomic::add(-1, (volatile int *)&_count); } ! // ! // 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) { --- 1811,1827 ---- id = jmeths[idnum+1]; // Look up the id (may be NULL) } return id; } ! int nmethodBucketEntry::decrement() { return Atomic::add(-1, (volatile int *)&_count); } ! int nmethodBucketEntry::mark_dependent_nmethods(nmethodBucketEntry* deps, DepChange& changes) { ! int found = 0, total = 0; ! for (nmethodBucketEntry* b = deps; b != NULL; b = b->next(), total++) { 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) {
*** 1839,1903 **** } 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); --- 1833,1878 ---- } nm->mark_for_deoptimization(); found++; } } + Dependencies::_perf_dependencies_checked_count->inc(total); return found; } ! nmethodBucketEntry* nmethodBucketEntry::add_dependent_nmethod(nmethodBucketEntry* deps, nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); ! for (nmethodBucketEntry* b = deps; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { b->increment(); return deps; } } ! return new nmethodBucketEntry(nm, deps); } ! bool nmethodBucketEntry::remove_dependent_nmethod(nmethodBucketEntry* deps, nmethod* nm, bool& found) { assert_locked_or_safepoint(CodeCache_lock); ! for (nmethodBucketEntry* b = deps; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { int val = b->decrement(); guarantee(val >= 0, err_msg("Underflow: %d", val)); + found = true; return (val == 0); } } return false; } ! nmethodBucketEntry* nmethodBucketEntry::clean_dependent_nmethods(nmethodBucketEntry* deps) { ! nmethodBucketEntry* first = deps; ! nmethodBucketEntry* last = NULL; ! nmethodBucketEntry* b = first; while (b != NULL) { assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); ! nmethodBucketEntry* next = b->next(); if (b->count() == 0) { if (last == NULL) { first = next; } else { last->set_next(next);
*** 1911,1923 **** } 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(" } "); --- 1886,1905 ---- } return first; } #ifndef PRODUCT ! void nmethodBucketEntry::verify(nmethodBucketEntry* deps) { ! for (nmethodBucketEntry* b = deps; 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"); ! } ! } ! ! void nmethodBucketEntry::print_dependent_nmethods(nmethodBucketEntry* deps, bool verbose) { int idx = 0; ! for (nmethodBucketEntry* 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(" } ");
*** 1927,1938 **** 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 --- 1909,1920 ---- tty->print_cr("--- } "); } } } ! bool nmethodBucketEntry::is_dependent_nmethod(nmethodBucketEntry* deps, nmethod* nm) { ! for (nmethodBucketEntry* 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
*** 1941,1950 **** --- 1923,2075 ---- } return false; } #endif //PRODUCT + + int nmethodBucket::bucket_index(DepChange& changes) { + if (changes.is_klass_change()) return KlassBucket; + else if (changes.is_call_site_change()) return CallSiteBucket; + else if (changes.is_constant_field_change()) return ConstantFieldBucket; + else { + ShouldNotReachHere(); + return -1; + } + } + + // + // 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); + PerfTraceTime pt(Dependencies::_perf_dependency_checking_time); + int found = 0; + if (deps != NULL) { + int idx = bucket_index(changes); + nmethodBucketEntry* b = deps->_buckets[idx]; + found = nmethodBucketEntry::mark_dependent_nmethods(b, changes); + Dependencies::_perf_dependencies_context_traversals->inc(1); + Dependencies::_perf_dependencies_invalidated->inc(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* b, nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + if (b == NULL) { + b = new nmethodBucket(); + } + bool has_deps[Bucket_LIMIT]; + for (int i = FIRST_Bucket; i < Bucket_LIMIT; i++) { has_deps[i] = false; } + for (Dependencies::DepStream deps(nm); deps.next(); ) { + switch(deps.type()) { + case Dependencies::call_site_target_value: has_deps[CallSiteBucket] = true; break; + case Dependencies::constant_field_value_instance: // fallthru + case Dependencies::constant_field_value_klass: has_deps[ConstantFieldBucket] = true; break; + default: has_deps[KlassBucket] = true; break; + } + } + for (int i = FIRST_Bucket; i < Bucket_LIMIT; i++) { + if (has_deps[i]) { + b->_buckets[i] = nmethodBucketEntry::add_dependent_nmethod(b->_buckets[i], nm); + } + } + return b; + } + + // + // 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) { + if (deps != NULL) { + assert_locked_or_safepoint(CodeCache_lock); + bool found = false, removed = false; + for (int i = FIRST_Bucket; i < Bucket_LIMIT; i++) { + bool r = nmethodBucketEntry::remove_dependent_nmethod(deps->_buckets[i], nm, found); + removed = removed || r; + } + if (found) { + return removed; + } + } + #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) { + if (deps == NULL) return NULL; + for (int i = FIRST_Bucket; i < Bucket_LIMIT; i++) { + deps->_buckets[i] = nmethodBucketEntry::clean_dependent_nmethods(deps->_buckets[i]); + } + return deps; + } + + int nmethodBucket::release(nmethodBucket* deps) { + if (deps == NULL) return 0; + int marked = 0; + for (int i = FIRST_Bucket; i < Bucket_LIMIT; i++) { + nmethodBucketEntry* entry = deps->_buckets[i]; + while (entry != NULL) { + nmethod* nm = entry->get_nmethod(); + if (entry->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) { + nm->mark_for_deoptimization(); + marked++; + } + nmethodBucketEntry* next = entry->next(); + delete entry; + entry = next; + } + } + delete deps; + return marked; + } + + #ifndef PRODUCT + void nmethodBucket::verify(nmethodBucket* deps) { + if (deps == NULL) return; + for (int i = FIRST_Bucket; i < Bucket_LIMIT; i++) { + nmethodBucketEntry::verify(deps->_buckets[i]); + } + } + + void nmethodBucket::print_dependent_nmethods(nmethodBucket* deps, bool verbose) { + if (deps == NULL) return; + for (int i = FIRST_Bucket; i < Bucket_LIMIT; i++) { + tty->print_cr("Bucket #%d: ", i); + nmethodBucketEntry::print_dependent_nmethods(deps->_buckets[i], verbose); + } + } + + bool nmethodBucket::is_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { + if (deps == NULL) return false; + for (int i = FIRST_Bucket; i < Bucket_LIMIT; i++) { + if (nmethodBucketEntry::is_dependent_nmethod(deps->_buckets[i], nm)) { + 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); }
*** 1956,1969 **** 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) { --- 2081,2091 ---- set_has_unloaded_dependent(false); } #ifdef ASSERT else { // Verification ! nmethodBucket::verify(_dependencies); } #endif } void InstanceKlass::add_dependent_nmethod(nmethod* nm) {
*** 2160,2176 **** set_member_names(NULL); } } // release dependencies ! nmethodBucket* b = _dependencies; _dependencies = NULL; - while (b != NULL) { - nmethodBucket* next = b->next(); - delete b; - b = next; - } // Deallocate breakpoint records if (breakpoints() != 0x0) { methods_do(clear_all_breakpoints); assert(breakpoints() == 0x0, "should have cleared breakpoints"); --- 2282,2294 ---- set_member_names(NULL); } } // release dependencies ! int marked = nmethodBucket::release(_dependencies); ! assert(marked == 0, ""); _dependencies = NULL; // Deallocate breakpoint records if (breakpoints() != 0x0) { methods_do(clear_all_breakpoints); assert(breakpoints() == 0x0, "should have cleared breakpoints");
< prev index next >