1824 if (*p == Universe::non_oop_word()) continue; // skip non-oops |
1824 if (*p == Universe::non_oop_word()) continue; // skip non-oops |
1825 f->do_oop(p); |
1825 f->do_oop(p); |
1826 } |
1826 } |
1827 } |
1827 } |
1828 |
1828 |
1829 #define NMETHOD_SENTINEL ((nmethod*)badAddress) |
|
1830 |
|
1831 nmethod* volatile nmethod::_oops_do_mark_nmethods; |
1829 nmethod* volatile nmethod::_oops_do_mark_nmethods; |
1832 |
1830 |
1833 // An nmethod is "marked" if its _mark_link is set non-null. |
1831 void nmethod::oops_do_log_change(const char* state) { |
1834 // Even if it is the end of the linked list, it will have a non-null link value, |
1832 LogTarget(Trace, gc, nmethod) lt; |
1835 // as long as it is on the list. |
1833 if (lt.is_enabled()) { |
1836 // This code must be MP safe, because it is used from parallel GC passes. |
1834 LogStream ls(lt); |
1837 bool nmethod::test_set_oops_do_mark() { |
1835 CompileTask::print(&ls, this, state, true /* short_form */); |
1838 assert(nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called"); |
1836 } |
1839 if (_oops_do_mark_link == NULL) { |
1837 } |
1840 // Claim this nmethod for this thread to mark. |
1838 |
1841 if (Atomic::replace_if_null(NMETHOD_SENTINEL, &_oops_do_mark_link)) { |
1839 bool nmethod::oops_do_try_claim() { |
1842 // Atomically append this nmethod (now claimed) to the head of the list: |
1840 if (oops_do_try_claim_weak_request()) { |
1843 nmethod* observed_mark_nmethods = _oops_do_mark_nmethods; |
1841 nmethod* result = oops_do_try_add_to_list_as_weak_done(); |
1844 for (;;) { |
1842 assert(result == NULL, "adding to global list as weak done must always succeed."); |
1845 nmethod* required_mark_nmethods = observed_mark_nmethods; |
1843 return true; |
1846 _oops_do_mark_link = required_mark_nmethods; |
1844 } |
1847 observed_mark_nmethods = |
1845 return false; |
1848 Atomic::cmpxchg(this, &_oops_do_mark_nmethods, required_mark_nmethods); |
1846 } |
1849 if (observed_mark_nmethods == required_mark_nmethods) |
1847 |
1850 break; |
1848 bool nmethod::oops_do_try_claim_weak_request() { |
1851 } |
1849 assert(SafepointSynchronize::is_at_safepoint(), "only at safepoint"); |
1852 // Mark was clear when we first saw this guy. |
1850 |
1853 LogTarget(Trace, gc, nmethod) lt; |
1851 if ((_oops_do_mark_link == NULL) && |
1854 if (lt.is_enabled()) { |
1852 (Atomic::replace_if_null(mark_link(this, claim_weak_request_tag), &_oops_do_mark_link))) { |
1855 LogStream ls(lt); |
1853 oops_do_log_change("oops_do, mark weak request"); |
1856 CompileTask::print(&ls, this, "oops_do, mark", /*short_form:*/ true); |
1854 return true; |
1857 } |
1855 } |
1858 return false; |
1856 return false; |
1859 } |
1857 } |
1860 } |
1858 |
1861 // On fall through, another racing thread marked this nmethod before we did. |
1859 void nmethod::oops_do_set_strong_done(nmethod* old_head) { |
1862 return true; |
1860 _oops_do_mark_link = mark_link(old_head, claim_strong_done_tag); |
|
1861 } |
|
1862 |
|
1863 nmethod::oops_do_mark_link* nmethod::oops_do_try_claim_strong_done() { |
|
1864 assert(SafepointSynchronize::is_at_safepoint(), "only at safepoint"); |
|
1865 |
|
1866 oops_do_mark_link* old_next = Atomic::cmpxchg(mark_link(this, claim_strong_done_tag), &_oops_do_mark_link, mark_link(NULL, claim_weak_request_tag)); |
|
1867 if (old_next == NULL) { |
|
1868 oops_do_log_change("oops_do, mark strong done"); |
|
1869 } |
|
1870 return old_next; |
|
1871 } |
|
1872 |
|
1873 nmethod::oops_do_mark_link* nmethod::oops_do_try_add_strong_request(nmethod::oops_do_mark_link* next) { |
|
1874 assert(SafepointSynchronize::is_at_safepoint(), "only at safepoint"); |
|
1875 assert(next == mark_link(this, claim_weak_request_tag), "Should be claimed as weak"); |
|
1876 |
|
1877 oops_do_mark_link* old_next = Atomic::cmpxchg(mark_link(this, claim_strong_request_tag), &_oops_do_mark_link, next); |
|
1878 if (old_next == next) { |
|
1879 oops_do_log_change("oops_do, mark strong request"); |
|
1880 } |
|
1881 return old_next; |
|
1882 } |
|
1883 |
|
1884 bool nmethod::oops_do_try_claim_weak_done_as_strong_done(nmethod::oops_do_mark_link* next) { |
|
1885 assert(SafepointSynchronize::is_at_safepoint(), "only at safepoint"); |
|
1886 assert(extract_state(next) == claim_weak_done_tag, "Should be claimed as weak done"); |
|
1887 |
|
1888 oops_do_mark_link* old_next = Atomic::cmpxchg(mark_link(extract_nmethod(next), claim_strong_done_tag), &_oops_do_mark_link, next); |
|
1889 if (old_next == next) { |
|
1890 oops_do_log_change("oops_do, mark weak done -> mark strong done"); |
|
1891 return true; |
|
1892 } |
|
1893 return false; |
|
1894 } |
|
1895 |
|
1896 nmethod* nmethod::oops_do_try_add_to_list_as_weak_done() { |
|
1897 assert(SafepointSynchronize::is_at_safepoint(), "only at safepoint"); |
|
1898 |
|
1899 assert(extract_state(_oops_do_mark_link) == claim_weak_request_tag || |
|
1900 extract_state(_oops_do_mark_link) == claim_strong_request_tag, |
|
1901 "must be but is nmethod " PTR_FORMAT " %u", p2i(extract_nmethod(_oops_do_mark_link)), extract_state(_oops_do_mark_link)); |
|
1902 |
|
1903 nmethod* old_head = Atomic::xchg(this, &_oops_do_mark_nmethods); |
|
1904 // Self-loop if needed. |
|
1905 if (old_head == NULL) { |
|
1906 old_head = this; |
|
1907 } |
|
1908 // Try to install end of list and weak done tag. |
|
1909 if (Atomic::cmpxchg(mark_link(old_head, claim_weak_done_tag), &_oops_do_mark_link, mark_link(this, claim_weak_request_tag)) == mark_link(this, claim_weak_request_tag)) { |
|
1910 oops_do_log_change("oops_do, mark weak done"); |
|
1911 return NULL; |
|
1912 } else { |
|
1913 return old_head; |
|
1914 } |
|
1915 } |
|
1916 |
|
1917 void nmethod::oops_do_add_to_list_as_strong_done() { |
|
1918 assert(SafepointSynchronize::is_at_safepoint(), "only at safepoint"); |
|
1919 |
|
1920 nmethod* old_head = Atomic::xchg(this, &_oops_do_mark_nmethods); |
|
1921 // Self-loop if needed. |
|
1922 if (old_head == NULL) { |
|
1923 old_head = this; |
|
1924 } |
|
1925 assert(_oops_do_mark_link == mark_link(this, claim_strong_done_tag), "must be but is nmethod " PTR_FORMAT " state %u", |
|
1926 p2i(extract_nmethod(_oops_do_mark_link)), extract_state(_oops_do_mark_link)); |
|
1927 |
|
1928 oops_do_set_strong_done(old_head); |
|
1929 } |
|
1930 |
|
1931 void nmethod::oops_do_process_weak(OopsDoProcessor* p) { |
|
1932 if (!oops_do_try_claim_weak_request()) { |
|
1933 // Failed to claim for weak processing. |
|
1934 oops_do_log_change("oops_do, mark weak request fail"); |
|
1935 return; |
|
1936 } |
|
1937 |
|
1938 p->do_regular_processing(this); |
|
1939 |
|
1940 nmethod* old_head = oops_do_try_add_to_list_as_weak_done(); |
|
1941 if (old_head == NULL) { |
|
1942 return; |
|
1943 } |
|
1944 oops_do_log_change("oops_do, mark weak done fail"); |
|
1945 // Adding to global list failed, another thread added a strong request. |
|
1946 assert(extract_state(_oops_do_mark_link) == claim_strong_request_tag, |
|
1947 "must be but is %u", extract_state(_oops_do_mark_link)); |
|
1948 |
|
1949 oops_do_log_change("oops_do, mark weak request -> mark strong done"); |
|
1950 |
|
1951 oops_do_set_strong_done(old_head); |
|
1952 // Do missing strong processing. |
|
1953 p->do_remaining_strong_processing(this); |
|
1954 } |
|
1955 |
|
1956 void nmethod::oops_do_process_strong(OopsDoProcessor* p) { |
|
1957 oops_do_mark_link* next_raw = oops_do_try_claim_strong_done(); |
|
1958 if (next_raw == NULL) { |
|
1959 p->do_regular_processing(this); |
|
1960 oops_do_add_to_list_as_strong_done(); |
|
1961 return; |
|
1962 } |
|
1963 // Claim failed. Figure out why and handle it. |
|
1964 if (oops_do_has_weak_request(next_raw)) { |
|
1965 oops_do_mark_link* old = next_raw; |
|
1966 // Claim failed because being weak processed (state == "weak request"). |
|
1967 // Try to request deferred strong processing. |
|
1968 next_raw = oops_do_try_add_strong_request(old); |
|
1969 if (next_raw == old) { |
|
1970 // Successfully requested deferred strong processing. |
|
1971 return; |
|
1972 } |
|
1973 // Failed because of a concurrent transition. No longer in "weak request" state. |
|
1974 } |
|
1975 if (oops_do_has_any_strong_state(next_raw)) { |
|
1976 // Already claimed for strong processing or requested for such. |
|
1977 return; |
|
1978 } |
|
1979 if (oops_do_try_claim_weak_done_as_strong_done(next_raw)) { |
|
1980 // Successfully claimed "weak done" as "strong done". Do the missing marking. |
|
1981 p->do_remaining_strong_processing(this); |
|
1982 return; |
|
1983 } |
|
1984 // Claim failed, some other thread got it. |
1863 } |
1985 } |
1864 |
1986 |
1865 void nmethod::oops_do_marking_prologue() { |
1987 void nmethod::oops_do_marking_prologue() { |
|
1988 assert_at_safepoint(); |
|
1989 |
1866 log_trace(gc, nmethod)("oops_do_marking_prologue"); |
1990 log_trace(gc, nmethod)("oops_do_marking_prologue"); |
1867 assert(_oops_do_mark_nmethods == NULL, "must not call oops_do_marking_prologue twice in a row"); |
1991 assert(_oops_do_mark_nmethods == NULL, "must be empty"); |
1868 // We use cmpxchg instead of regular assignment here because the user |
|
1869 // may fork a bunch of threads, and we need them all to see the same state. |
|
1870 nmethod* observed = Atomic::cmpxchg(NMETHOD_SENTINEL, &_oops_do_mark_nmethods, (nmethod*)NULL); |
|
1871 guarantee(observed == NULL, "no races in this sequential code"); |
|
1872 } |
1992 } |
1873 |
1993 |
1874 void nmethod::oops_do_marking_epilogue() { |
1994 void nmethod::oops_do_marking_epilogue() { |
1875 assert(_oops_do_mark_nmethods != NULL, "must not call oops_do_marking_epilogue twice in a row"); |
1995 assert_at_safepoint(); |
1876 nmethod* cur = _oops_do_mark_nmethods; |
1996 |
1877 while (cur != NMETHOD_SENTINEL) { |
1997 nmethod* next = _oops_do_mark_nmethods; |
1878 assert(cur != NULL, "not NULL-terminated"); |
1998 _oops_do_mark_nmethods = NULL; |
1879 nmethod* next = cur->_oops_do_mark_link; |
1999 if (next == NULL) { |
|
2000 return; |
|
2001 } |
|
2002 nmethod* cur; |
|
2003 do { |
|
2004 cur = next; |
|
2005 next = extract_nmethod(cur->_oops_do_mark_link); |
1880 cur->_oops_do_mark_link = NULL; |
2006 cur->_oops_do_mark_link = NULL; |
1881 DEBUG_ONLY(cur->verify_oop_relocations()); |
2007 DEBUG_ONLY(cur->verify_oop_relocations()); |
1882 |
2008 |
1883 LogTarget(Trace, gc, nmethod) lt; |
2009 LogTarget(Trace, gc, nmethod) lt; |
1884 if (lt.is_enabled()) { |
2010 if (lt.is_enabled()) { |
1885 LogStream ls(lt); |
2011 LogStream ls(lt); |
1886 CompileTask::print(&ls, cur, "oops_do, unmark", /*short_form:*/ true); |
2012 CompileTask::print(&ls, cur, "oops_do, unmark", /*short_form:*/ true); |
1887 } |
2013 } |
1888 cur = next; |
2014 // End if self-loop has been detected. |
1889 } |
2015 } while (cur != next); |
1890 nmethod* required = _oops_do_mark_nmethods; |
|
1891 nmethod* observed = Atomic::cmpxchg((nmethod*)NULL, &_oops_do_mark_nmethods, required); |
|
1892 guarantee(observed == required, "no races in this sequential code"); |
|
1893 log_trace(gc, nmethod)("oops_do_marking_epilogue"); |
2016 log_trace(gc, nmethod)("oops_do_marking_epilogue"); |
1894 } |
2017 } |
1895 |
2018 |
1896 inline bool includes(void* p, void* from, void* to) { |
2019 inline bool includes(void* p, void* from, void* to) { |
1897 return from <= p && p < to; |
2020 return from <= p && p < to; |