< prev index next >

src/share/vm/oops/instanceKlass.cpp

Print this page

        

*** 1905,1934 **** // // 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, "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; --- 1905,1955 ---- // // 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 was deleted, ! // or marked ready for reclaimation. ! bool nmethodBucket::remove_dependent_nmethod(nmethodBucket** deps, nmethod* nm, bool delete_immediately) { assert_locked_or_safepoint(CodeCache_lock); ! nmethodBucket* first = *deps; ! nmethodBucket* last = NULL; ! ! for (nmethodBucket* b = first; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { int val = b->decrement(); guarantee(val >= 0, "Underflow: %d", val); ! if (val == 0) { ! if (delete_immediately) { ! if (last == NULL) { ! *deps = b->next(); ! } else { ! last->set_next(b->next()); ! } ! delete b; ! } ! } ! return true; } + last = b; } + #ifdef ASSERT tty->print_raw_cr("### can't find dependent nmethod"); nm->print(); #endif // ASSERT ShouldNotReachHere(); return false; } + // Convenience overload, for callers that don't want to delete the nmethodBucket entry. + bool nmethodBucket::remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { + nmethodBucket** deps_addr = &deps; + return remove_dependent_nmethod(deps_addr, nm, false /* Don't delete */); + } + // // Reclaim all unused buckets. Returns new head of the list. // nmethodBucket* nmethodBucket::clean_dependent_nmethods(nmethodBucket* deps) { nmethodBucket* first = deps;
*** 2011,2024 **** 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 --- 2032,2045 ---- 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, bool delete_immediately) { assert_locked_or_safepoint(CodeCache_lock); ! if (nmethodBucket::remove_dependent_nmethod(&_dependencies, nm, delete_immediately)) { set_has_unloaded_dependent(true); } } #ifndef PRODUCT
*** 2029,2038 **** --- 2050,2066 ---- bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { return nmethodBucket::is_dependent_nmethod(_dependencies, nm); } #endif //PRODUCT + void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive) { + clean_implementors_list(is_alive); + clean_method_data(is_alive); + + clean_dependent_nmethods(); + } + 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();
*** 3544,3548 **** --- 3572,3772 ---- } unsigned char * InstanceKlass::get_cached_class_file_bytes() { return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file); } + + + /////////////// Unit tests /////////////// + + #ifndef PRODUCT + + class TestNmethodBucketContext { + public: + nmethod* _nmethodLast; + nmethod* _nmethodMiddle; + nmethod* _nmethodFirst; + + nmethodBucket* _bucketLast; + nmethodBucket* _bucketMiddle; + nmethodBucket* _bucketFirst; + + nmethodBucket* _bucketList; + + TestNmethodBucketContext() { + CodeCache_lock->lock_without_safepoint_check(); + + _nmethodLast = reinterpret_cast<nmethod*>(0x8 * 0); + _nmethodMiddle = reinterpret_cast<nmethod*>(0x8 * 1); + _nmethodFirst = reinterpret_cast<nmethod*>(0x8 * 2); + + _bucketLast = new nmethodBucket(_nmethodLast, NULL); + _bucketMiddle = new nmethodBucket(_nmethodMiddle, _bucketLast); + _bucketFirst = new nmethodBucket(_nmethodFirst, _bucketMiddle); + + _bucketList = _bucketFirst; + } + + ~TestNmethodBucketContext() { + delete _bucketLast; + delete _bucketMiddle; + delete _bucketFirst; + + CodeCache_lock->unlock(); + } + }; + + class TestNmethodBucket { + public: + static void testRemoveDependentNmethodFirstDeleteImmediately() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodFirst, true /* delete */); + + assert(c._bucketList == c._bucketMiddle, "check"); + assert(c._bucketList->next() == c._bucketLast, "check"); + assert(c._bucketList->next()->next() == NULL, "check"); + + // Cleanup before context is deleted. + c._bucketFirst = NULL; + } + + static void testRemoveDependentNmethodMiddleDeleteImmediately() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodMiddle, true /* delete */); + + assert(c._bucketList == c._bucketFirst, "check"); + assert(c._bucketList->next() == c._bucketLast, "check"); + assert(c._bucketList->next()->next() == NULL, "check"); + + // Cleanup before context is deleted. + c._bucketMiddle = NULL; + } + + static void testRemoveDependentNmethodLastDeleteImmediately() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodLast, true /* delete */); + + assert(c._bucketList == c._bucketFirst, "check"); + assert(c._bucketList->next() == c._bucketMiddle, "check"); + assert(c._bucketList->next()->next() == NULL, "check"); + + // Cleanup before context is deleted. + c._bucketLast = NULL; + } + + static void testRemoveDependentNmethodFirstDeleteDeferred() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodFirst, false /* delete */); + + assert(c._bucketList == c._bucketFirst, "check"); + assert(c._bucketList->next() == c._bucketMiddle, "check"); + assert(c._bucketList->next()->next() == c._bucketLast, "check"); + assert(c._bucketList->next()->next()->next() == NULL, "check"); + + assert(c._bucketFirst->count() == 0, "check"); + assert(c._bucketMiddle->count() == 1, "check"); + assert(c._bucketLast->count() == 1, "check"); + } + + static void testRemoveDependentNmethodMiddleDeleteDeferred() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodMiddle, false /* delete */); + + assert(c._bucketList == c._bucketFirst, "check"); + assert(c._bucketList->next() == c._bucketMiddle, "check"); + assert(c._bucketList->next()->next() == c._bucketLast, "check"); + assert(c._bucketList->next()->next()->next() == NULL, "check"); + + assert(c._bucketFirst->count() == 1, "check"); + assert(c._bucketMiddle->count() == 0, "check"); + assert(c._bucketLast->count() == 1, "check"); + } + + static void testRemoveDependentNmethodLastDeleteDeferred() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodLast, false /* delete */); + + assert(c._bucketList == c._bucketFirst, "check"); + assert(c._bucketList->next() == c._bucketMiddle, "check"); + assert(c._bucketList->next()->next() == c._bucketLast, "check"); + assert(c._bucketList->next()->next()->next() == NULL, "check"); + + assert(c._bucketFirst->count() == 1, "check"); + assert(c._bucketMiddle->count() == 1, "check"); + assert(c._bucketLast->count() == 0, "check"); + } + + static void testRemoveDependentNmethodConvenienceFirst() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodFirst); + + assert(c._bucketList == c._bucketFirst, "check"); + assert(c._bucketList->next() == c._bucketMiddle, "check"); + assert(c._bucketList->next()->next() == c._bucketLast, "check"); + assert(c._bucketList->next()->next()->next() == NULL, "check"); + + assert(c._bucketFirst->count() == 0, "check"); + assert(c._bucketMiddle->count() == 1, "check"); + assert(c._bucketLast->count() == 1, "check"); + } + + static void testRemoveDependentNmethodConvenienceMiddle() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodMiddle); + + assert(c._bucketList == c._bucketFirst, "check"); + assert(c._bucketList->next() == c._bucketMiddle, "check"); + assert(c._bucketList->next()->next() == c._bucketLast, "check"); + assert(c._bucketList->next()->next()->next() == NULL, "check"); + + assert(c._bucketFirst->count() == 1, "check"); + assert(c._bucketMiddle->count() == 0, "check"); + assert(c._bucketLast->count() == 1, "check"); + } + + static void testRemoveDependentNmethodConvenienceLast() { + TestNmethodBucketContext c; + + nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodLast); + + assert(c._bucketList == c._bucketFirst, "check"); + assert(c._bucketList->next() == c._bucketMiddle, "check"); + assert(c._bucketList->next()->next() == c._bucketLast, "check"); + assert(c._bucketList->next()->next()->next() == NULL, "check"); + + assert(c._bucketFirst->count() == 1, "check"); + assert(c._bucketMiddle->count() == 1, "check"); + assert(c._bucketLast->count() == 0, "check"); + } + + static void testRemoveDependentNmethod() { + testRemoveDependentNmethodFirstDeleteImmediately(); + testRemoveDependentNmethodMiddleDeleteImmediately(); + testRemoveDependentNmethodLastDeleteImmediately(); + + testRemoveDependentNmethodFirstDeleteDeferred(); + testRemoveDependentNmethodMiddleDeleteDeferred(); + testRemoveDependentNmethodLastDeleteDeferred(); + + testRemoveDependentNmethodConvenienceFirst(); + testRemoveDependentNmethodConvenienceMiddle(); + testRemoveDependentNmethodConvenienceLast(); + } + + static void test() { + testRemoveDependentNmethod(); + } + }; + + void TestNmethodBucket_test() { + TestNmethodBucket::test(); + } + + #endif
< prev index next >