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