1855 id = jmeths[idnum+1]; // Look up the id (may be NULL) |
1857 id = jmeths[idnum+1]; // Look up the id (may be NULL) |
1856 } |
1858 } |
1857 return id; |
1859 return id; |
1858 } |
1860 } |
1859 |
1861 |
1860 int nmethodBucket::decrement() { |
1862 inline DependencyContext InstanceKlass::dependencies() { |
1861 return Atomic::add(-1, (volatile int *)&_count); |
1863 DependencyContext dep_context(&_dep_context); |
1862 } |
1864 return dep_context; |
1863 |
1865 } |
1864 // |
|
1865 // Walk the list of dependent nmethods searching for nmethods which |
|
1866 // are dependent on the changes that were passed in and mark them for |
|
1867 // deoptimization. Returns the number of nmethods found. |
|
1868 // |
|
1869 int nmethodBucket::mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes) { |
|
1870 assert_locked_or_safepoint(CodeCache_lock); |
|
1871 int found = 0; |
|
1872 for (nmethodBucket* b = deps; b != NULL; b = b->next()) { |
|
1873 nmethod* nm = b->get_nmethod(); |
|
1874 // since dependencies aren't removed until an nmethod becomes a zombie, |
|
1875 // the dependency list may contain nmethods which aren't alive. |
|
1876 if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) { |
|
1877 if (TraceDependencies) { |
|
1878 ResourceMark rm; |
|
1879 tty->print_cr("Marked for deoptimization"); |
|
1880 changes.print(); |
|
1881 nm->print(); |
|
1882 nm->print_dependencies(); |
|
1883 } |
|
1884 nm->mark_for_deoptimization(); |
|
1885 found++; |
|
1886 } |
|
1887 } |
|
1888 return found; |
|
1889 } |
|
1890 |
|
1891 // |
|
1892 // Add an nmethodBucket to the list of dependencies for this nmethod. |
|
1893 // It's possible that an nmethod has multiple dependencies on this klass |
|
1894 // so a count is kept for each bucket to guarantee that creation and |
|
1895 // deletion of dependencies is consistent. Returns new head of the list. |
|
1896 // |
|
1897 nmethodBucket* nmethodBucket::add_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { |
|
1898 assert_locked_or_safepoint(CodeCache_lock); |
|
1899 for (nmethodBucket* b = deps; b != NULL; b = b->next()) { |
|
1900 if (nm == b->get_nmethod()) { |
|
1901 b->increment(); |
|
1902 return deps; |
|
1903 } |
|
1904 } |
|
1905 return new nmethodBucket(nm, deps); |
|
1906 } |
|
1907 |
|
1908 // |
|
1909 // Decrement count of the nmethod in the dependency list and remove |
|
1910 // the bucket completely when the count goes to 0. This method must |
|
1911 // find a corresponding bucket otherwise there's a bug in the |
|
1912 // recording of dependencies. Returns true if the bucket was deleted, |
|
1913 // or marked ready for reclaimation. |
|
1914 bool nmethodBucket::remove_dependent_nmethod(nmethodBucket** deps, nmethod* nm, bool delete_immediately) { |
|
1915 assert_locked_or_safepoint(CodeCache_lock); |
|
1916 |
|
1917 nmethodBucket* first = *deps; |
|
1918 nmethodBucket* last = NULL; |
|
1919 |
|
1920 for (nmethodBucket* b = first; b != NULL; b = b->next()) { |
|
1921 if (nm == b->get_nmethod()) { |
|
1922 int val = b->decrement(); |
|
1923 guarantee(val >= 0, "Underflow: %d", val); |
|
1924 if (val == 0) { |
|
1925 if (delete_immediately) { |
|
1926 if (last == NULL) { |
|
1927 *deps = b->next(); |
|
1928 } else { |
|
1929 last->set_next(b->next()); |
|
1930 } |
|
1931 delete b; |
|
1932 } |
|
1933 } |
|
1934 return true; |
|
1935 } |
|
1936 last = b; |
|
1937 } |
|
1938 |
|
1939 #ifdef ASSERT |
|
1940 tty->print_raw_cr("### can't find dependent nmethod"); |
|
1941 nm->print(); |
|
1942 #endif // ASSERT |
|
1943 ShouldNotReachHere(); |
|
1944 return false; |
|
1945 } |
|
1946 |
|
1947 // Convenience overload, for callers that don't want to delete the nmethodBucket entry. |
|
1948 bool nmethodBucket::remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { |
|
1949 nmethodBucket** deps_addr = &deps; |
|
1950 return remove_dependent_nmethod(deps_addr, nm, false /* Don't delete */); |
|
1951 } |
|
1952 |
|
1953 // |
|
1954 // Reclaim all unused buckets. Returns new head of the list. |
|
1955 // |
|
1956 nmethodBucket* nmethodBucket::clean_dependent_nmethods(nmethodBucket* deps) { |
|
1957 nmethodBucket* first = deps; |
|
1958 nmethodBucket* last = NULL; |
|
1959 nmethodBucket* b = first; |
|
1960 |
|
1961 while (b != NULL) { |
|
1962 assert(b->count() >= 0, "bucket count: %d", b->count()); |
|
1963 nmethodBucket* next = b->next(); |
|
1964 if (b->count() == 0) { |
|
1965 if (last == NULL) { |
|
1966 first = next; |
|
1967 } else { |
|
1968 last->set_next(next); |
|
1969 } |
|
1970 delete b; |
|
1971 // last stays the same. |
|
1972 } else { |
|
1973 last = b; |
|
1974 } |
|
1975 b = next; |
|
1976 } |
|
1977 return first; |
|
1978 } |
|
1979 |
|
1980 #ifndef PRODUCT |
|
1981 void nmethodBucket::print_dependent_nmethods(nmethodBucket* deps, bool verbose) { |
|
1982 int idx = 0; |
|
1983 for (nmethodBucket* b = deps; b != NULL; b = b->next()) { |
|
1984 nmethod* nm = b->get_nmethod(); |
|
1985 tty->print("[%d] count=%d { ", idx++, b->count()); |
|
1986 if (!verbose) { |
|
1987 nm->print_on(tty, "nmethod"); |
|
1988 tty->print_cr(" } "); |
|
1989 } else { |
|
1990 nm->print(); |
|
1991 nm->print_dependencies(); |
|
1992 tty->print_cr("--- } "); |
|
1993 } |
|
1994 } |
|
1995 } |
|
1996 |
|
1997 bool nmethodBucket::is_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { |
|
1998 for (nmethodBucket* b = deps; b != NULL; b = b->next()) { |
|
1999 if (nm == b->get_nmethod()) { |
|
2000 #ifdef ASSERT |
|
2001 int count = b->count(); |
|
2002 assert(count >= 0, "count shouldn't be negative: %d", count); |
|
2003 #endif |
|
2004 return true; |
|
2005 } |
|
2006 } |
|
2007 return false; |
|
2008 } |
|
2009 #endif //PRODUCT |
|
2010 |
1866 |
2011 int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { |
1867 int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { |
2012 assert_locked_or_safepoint(CodeCache_lock); |
1868 return dependencies().mark_dependent_nmethods(changes); |
2013 return nmethodBucket::mark_dependent_nmethods(_dependencies, changes); |
|
2014 } |
|
2015 |
|
2016 void InstanceKlass::clean_dependent_nmethods() { |
|
2017 assert_locked_or_safepoint(CodeCache_lock); |
|
2018 |
|
2019 if (has_unloaded_dependent()) { |
|
2020 _dependencies = nmethodBucket::clean_dependent_nmethods(_dependencies); |
|
2021 set_has_unloaded_dependent(false); |
|
2022 } |
|
2023 #ifdef ASSERT |
|
2024 else { |
|
2025 // Verification |
|
2026 for (nmethodBucket* b = _dependencies; b != NULL; b = b->next()) { |
|
2027 assert(b->count() >= 0, "bucket count: %d", b->count()); |
|
2028 assert(b->count() != 0, "empty buckets need to be cleaned"); |
|
2029 } |
|
2030 } |
|
2031 #endif |
|
2032 } |
1869 } |
2033 |
1870 |
2034 void InstanceKlass::add_dependent_nmethod(nmethod* nm) { |
1871 void InstanceKlass::add_dependent_nmethod(nmethod* nm) { |
2035 assert_locked_or_safepoint(CodeCache_lock); |
1872 dependencies().add_dependent_nmethod(nm); |
2036 _dependencies = nmethodBucket::add_dependent_nmethod(_dependencies, nm); |
|
2037 } |
1873 } |
2038 |
1874 |
2039 void InstanceKlass::remove_dependent_nmethod(nmethod* nm, bool delete_immediately) { |
1875 void InstanceKlass::remove_dependent_nmethod(nmethod* nm, bool delete_immediately) { |
2040 assert_locked_or_safepoint(CodeCache_lock); |
1876 dependencies().remove_dependent_nmethod(nm, delete_immediately); |
2041 |
|
2042 if (nmethodBucket::remove_dependent_nmethod(&_dependencies, nm, delete_immediately)) { |
|
2043 set_has_unloaded_dependent(true); |
|
2044 } |
|
2045 } |
1877 } |
2046 |
1878 |
2047 #ifndef PRODUCT |
1879 #ifndef PRODUCT |
2048 void InstanceKlass::print_dependent_nmethods(bool verbose) { |
1880 void InstanceKlass::print_dependent_nmethods(bool verbose) { |
2049 nmethodBucket::print_dependent_nmethods(_dependencies, verbose); |
1881 dependencies().print_dependent_nmethods(verbose); |
2050 } |
1882 } |
2051 |
1883 |
2052 bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { |
1884 bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { |
2053 return nmethodBucket::is_dependent_nmethod(_dependencies, nm); |
1885 return dependencies().is_dependent_nmethod(nm); |
2054 } |
1886 } |
2055 #endif //PRODUCT |
1887 #endif //PRODUCT |
2056 |
1888 |
2057 void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive) { |
1889 void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive) { |
2058 clean_implementors_list(is_alive); |
1890 clean_implementors_list(is_alive); |
2059 clean_method_data(is_alive); |
1891 clean_method_data(is_alive); |
2060 |
1892 |
2061 clean_dependent_nmethods(); |
1893 // Since GC iterates InstanceKlasses sequentially, it is safe to remove stale entries here. |
|
1894 DependencyContext dep_context(&_dep_context); |
|
1895 dep_context.expunge_stale_entries(); |
2062 } |
1896 } |
2063 |
1897 |
2064 void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { |
1898 void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { |
2065 assert(class_loader_data()->is_alive(is_alive), "this klass should be live"); |
1899 assert(class_loader_data()->is_alive(is_alive), "this klass should be live"); |
2066 if (is_interface()) { |
1900 if (is_interface()) { |
3559 } |
3397 } |
3560 |
3398 |
3561 unsigned char * InstanceKlass::get_cached_class_file_bytes() { |
3399 unsigned char * InstanceKlass::get_cached_class_file_bytes() { |
3562 return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file); |
3400 return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file); |
3563 } |
3401 } |
3564 |
|
3565 |
|
3566 /////////////// Unit tests /////////////// |
|
3567 |
|
3568 #ifndef PRODUCT |
|
3569 |
|
3570 class TestNmethodBucketContext { |
|
3571 public: |
|
3572 nmethod* _nmethodLast; |
|
3573 nmethod* _nmethodMiddle; |
|
3574 nmethod* _nmethodFirst; |
|
3575 |
|
3576 nmethodBucket* _bucketLast; |
|
3577 nmethodBucket* _bucketMiddle; |
|
3578 nmethodBucket* _bucketFirst; |
|
3579 |
|
3580 nmethodBucket* _bucketList; |
|
3581 |
|
3582 TestNmethodBucketContext() { |
|
3583 CodeCache_lock->lock_without_safepoint_check(); |
|
3584 |
|
3585 _nmethodLast = reinterpret_cast<nmethod*>(0x8 * 0); |
|
3586 _nmethodMiddle = reinterpret_cast<nmethod*>(0x8 * 1); |
|
3587 _nmethodFirst = reinterpret_cast<nmethod*>(0x8 * 2); |
|
3588 |
|
3589 _bucketLast = new nmethodBucket(_nmethodLast, NULL); |
|
3590 _bucketMiddle = new nmethodBucket(_nmethodMiddle, _bucketLast); |
|
3591 _bucketFirst = new nmethodBucket(_nmethodFirst, _bucketMiddle); |
|
3592 |
|
3593 _bucketList = _bucketFirst; |
|
3594 } |
|
3595 |
|
3596 ~TestNmethodBucketContext() { |
|
3597 delete _bucketLast; |
|
3598 delete _bucketMiddle; |
|
3599 delete _bucketFirst; |
|
3600 |
|
3601 CodeCache_lock->unlock(); |
|
3602 } |
|
3603 }; |
|
3604 |
|
3605 class TestNmethodBucket { |
|
3606 public: |
|
3607 static void testRemoveDependentNmethodFirstDeleteImmediately() { |
|
3608 TestNmethodBucketContext c; |
|
3609 |
|
3610 nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodFirst, true /* delete */); |
|
3611 |
|
3612 assert(c._bucketList == c._bucketMiddle, "check"); |
|
3613 assert(c._bucketList->next() == c._bucketLast, "check"); |
|
3614 assert(c._bucketList->next()->next() == NULL, "check"); |
|
3615 |
|
3616 // Cleanup before context is deleted. |
|
3617 c._bucketFirst = NULL; |
|
3618 } |
|
3619 |
|
3620 static void testRemoveDependentNmethodMiddleDeleteImmediately() { |
|
3621 TestNmethodBucketContext c; |
|
3622 |
|
3623 nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodMiddle, true /* delete */); |
|
3624 |
|
3625 assert(c._bucketList == c._bucketFirst, "check"); |
|
3626 assert(c._bucketList->next() == c._bucketLast, "check"); |
|
3627 assert(c._bucketList->next()->next() == NULL, "check"); |
|
3628 |
|
3629 // Cleanup before context is deleted. |
|
3630 c._bucketMiddle = NULL; |
|
3631 } |
|
3632 |
|
3633 static void testRemoveDependentNmethodLastDeleteImmediately() { |
|
3634 TestNmethodBucketContext c; |
|
3635 |
|
3636 nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodLast, true /* delete */); |
|
3637 |
|
3638 assert(c._bucketList == c._bucketFirst, "check"); |
|
3639 assert(c._bucketList->next() == c._bucketMiddle, "check"); |
|
3640 assert(c._bucketList->next()->next() == NULL, "check"); |
|
3641 |
|
3642 // Cleanup before context is deleted. |
|
3643 c._bucketLast = NULL; |
|
3644 } |
|
3645 |
|
3646 static void testRemoveDependentNmethodFirstDeleteDeferred() { |
|
3647 TestNmethodBucketContext c; |
|
3648 |
|
3649 nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodFirst, false /* delete */); |
|
3650 |
|
3651 assert(c._bucketList == c._bucketFirst, "check"); |
|
3652 assert(c._bucketList->next() == c._bucketMiddle, "check"); |
|
3653 assert(c._bucketList->next()->next() == c._bucketLast, "check"); |
|
3654 assert(c._bucketList->next()->next()->next() == NULL, "check"); |
|
3655 |
|
3656 assert(c._bucketFirst->count() == 0, "check"); |
|
3657 assert(c._bucketMiddle->count() == 1, "check"); |
|
3658 assert(c._bucketLast->count() == 1, "check"); |
|
3659 } |
|
3660 |
|
3661 static void testRemoveDependentNmethodMiddleDeleteDeferred() { |
|
3662 TestNmethodBucketContext c; |
|
3663 |
|
3664 nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodMiddle, false /* delete */); |
|
3665 |
|
3666 assert(c._bucketList == c._bucketFirst, "check"); |
|
3667 assert(c._bucketList->next() == c._bucketMiddle, "check"); |
|
3668 assert(c._bucketList->next()->next() == c._bucketLast, "check"); |
|
3669 assert(c._bucketList->next()->next()->next() == NULL, "check"); |
|
3670 |
|
3671 assert(c._bucketFirst->count() == 1, "check"); |
|
3672 assert(c._bucketMiddle->count() == 0, "check"); |
|
3673 assert(c._bucketLast->count() == 1, "check"); |
|
3674 } |
|
3675 |
|
3676 static void testRemoveDependentNmethodLastDeleteDeferred() { |
|
3677 TestNmethodBucketContext c; |
|
3678 |
|
3679 nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodLast, false /* delete */); |
|
3680 |
|
3681 assert(c._bucketList == c._bucketFirst, "check"); |
|
3682 assert(c._bucketList->next() == c._bucketMiddle, "check"); |
|
3683 assert(c._bucketList->next()->next() == c._bucketLast, "check"); |
|
3684 assert(c._bucketList->next()->next()->next() == NULL, "check"); |
|
3685 |
|
3686 assert(c._bucketFirst->count() == 1, "check"); |
|
3687 assert(c._bucketMiddle->count() == 1, "check"); |
|
3688 assert(c._bucketLast->count() == 0, "check"); |
|
3689 } |
|
3690 |
|
3691 static void testRemoveDependentNmethodConvenienceFirst() { |
|
3692 TestNmethodBucketContext c; |
|
3693 |
|
3694 nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodFirst); |
|
3695 |
|
3696 assert(c._bucketList == c._bucketFirst, "check"); |
|
3697 assert(c._bucketList->next() == c._bucketMiddle, "check"); |
|
3698 assert(c._bucketList->next()->next() == c._bucketLast, "check"); |
|
3699 assert(c._bucketList->next()->next()->next() == NULL, "check"); |
|
3700 |
|
3701 assert(c._bucketFirst->count() == 0, "check"); |
|
3702 assert(c._bucketMiddle->count() == 1, "check"); |
|
3703 assert(c._bucketLast->count() == 1, "check"); |
|
3704 } |
|
3705 |
|
3706 static void testRemoveDependentNmethodConvenienceMiddle() { |
|
3707 TestNmethodBucketContext c; |
|
3708 |
|
3709 nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodMiddle); |
|
3710 |
|
3711 assert(c._bucketList == c._bucketFirst, "check"); |
|
3712 assert(c._bucketList->next() == c._bucketMiddle, "check"); |
|
3713 assert(c._bucketList->next()->next() == c._bucketLast, "check"); |
|
3714 assert(c._bucketList->next()->next()->next() == NULL, "check"); |
|
3715 |
|
3716 assert(c._bucketFirst->count() == 1, "check"); |
|
3717 assert(c._bucketMiddle->count() == 0, "check"); |
|
3718 assert(c._bucketLast->count() == 1, "check"); |
|
3719 } |
|
3720 |
|
3721 static void testRemoveDependentNmethodConvenienceLast() { |
|
3722 TestNmethodBucketContext c; |
|
3723 |
|
3724 nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodLast); |
|
3725 |
|
3726 assert(c._bucketList == c._bucketFirst, "check"); |
|
3727 assert(c._bucketList->next() == c._bucketMiddle, "check"); |
|
3728 assert(c._bucketList->next()->next() == c._bucketLast, "check"); |
|
3729 assert(c._bucketList->next()->next()->next() == NULL, "check"); |
|
3730 |
|
3731 assert(c._bucketFirst->count() == 1, "check"); |
|
3732 assert(c._bucketMiddle->count() == 1, "check"); |
|
3733 assert(c._bucketLast->count() == 0, "check"); |
|
3734 } |
|
3735 |
|
3736 static void testRemoveDependentNmethod() { |
|
3737 testRemoveDependentNmethodFirstDeleteImmediately(); |
|
3738 testRemoveDependentNmethodMiddleDeleteImmediately(); |
|
3739 testRemoveDependentNmethodLastDeleteImmediately(); |
|
3740 |
|
3741 testRemoveDependentNmethodFirstDeleteDeferred(); |
|
3742 testRemoveDependentNmethodMiddleDeleteDeferred(); |
|
3743 testRemoveDependentNmethodLastDeleteDeferred(); |
|
3744 |
|
3745 testRemoveDependentNmethodConvenienceFirst(); |
|
3746 testRemoveDependentNmethodConvenienceMiddle(); |
|
3747 testRemoveDependentNmethodConvenienceLast(); |
|
3748 } |
|
3749 |
|
3750 static void test() { |
|
3751 testRemoveDependentNmethod(); |
|
3752 } |
|
3753 }; |
|
3754 |
|
3755 void TestNmethodBucket_test() { |
|
3756 TestNmethodBucket::test(); |
|
3757 } |
|
3758 |
|
3759 #endif |
|