Mercurial > hg > graal-jvmci-8
comparison src/share/vm/prims/jvmtiExport.cpp @ 2195:bf8517f4e4d0
6766644: Redefinition of compiled method fails with assertion "Can not load classes with the Compiler thread"
Summary: Defer posting events from the compiler thread: use service thread
Reviewed-by: coleenp, dholmes, never, dcubed
author | kamg |
---|---|
date | Wed, 02 Feb 2011 14:38:01 -0500 |
parents | 3582bf76420e |
children | f91db74a6810 |
comparison
equal
deleted
inserted
replaced
2194:face83fc8882 | 2195:bf8517f4e4d0 |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
748 /////////////////////////////////////////////////////////////// | 748 /////////////////////////////////////////////////////////////// |
749 // | 749 // |
750 // pending CompiledMethodUnload support | 750 // pending CompiledMethodUnload support |
751 // | 751 // |
752 | 752 |
753 bool JvmtiExport::_have_pending_compiled_method_unload_events; | 753 void JvmtiExport::post_compiled_method_unload( |
754 GrowableArray<jmethodID>* JvmtiExport::_pending_compiled_method_unload_method_ids; | 754 jmethodID method, const void *code_begin) { |
755 GrowableArray<const void *>* JvmtiExport::_pending_compiled_method_unload_code_begins; | 755 JavaThread* thread = JavaThread::current(); |
756 JavaThread* JvmtiExport::_current_poster; | |
757 | |
758 void JvmtiExport::post_compiled_method_unload_internal(JavaThread* self, jmethodID method, const void *code_begin) { | |
759 EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD, | 756 EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD, |
760 ("JVMTI [%s] method compile unload event triggered", | 757 ("JVMTI [%s] method compile unload event triggered", |
761 JvmtiTrace::safe_get_thread_name(self))); | 758 JvmtiTrace::safe_get_thread_name(thread))); |
762 | 759 |
763 // post the event for each environment that has this event enabled. | 760 // post the event for each environment that has this event enabled. |
764 JvmtiEnvIterator it; | 761 JvmtiEnvIterator it; |
765 for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { | 762 for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { |
766 if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_UNLOAD)) { | 763 if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_UNLOAD)) { |
767 | 764 |
768 EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD, | 765 EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD, |
769 ("JVMTI [%s] class compile method unload event sent jmethodID " PTR_FORMAT, | 766 ("JVMTI [%s] class compile method unload event sent jmethodID " PTR_FORMAT, |
770 JvmtiTrace::safe_get_thread_name(self), method)); | 767 JvmtiTrace::safe_get_thread_name(thread), method)); |
771 | 768 |
772 ResourceMark rm(self); | 769 ResourceMark rm(thread); |
773 | 770 |
774 JvmtiEventMark jem(self); | 771 JvmtiEventMark jem(thread); |
775 JvmtiJavaThreadEventTransition jet(self); | 772 JvmtiJavaThreadEventTransition jet(thread); |
776 jvmtiEventCompiledMethodUnload callback = env->callbacks()->CompiledMethodUnload; | 773 jvmtiEventCompiledMethodUnload callback = env->callbacks()->CompiledMethodUnload; |
777 if (callback != NULL) { | 774 if (callback != NULL) { |
778 (*callback)(env->jvmti_external(), method, code_begin); | 775 (*callback)(env->jvmti_external(), method, code_begin); |
779 } | 776 } |
780 } | |
781 } | |
782 } | |
783 | |
784 // post any pending CompiledMethodUnload events | |
785 | |
786 void JvmtiExport::post_pending_compiled_method_unload_events() { | |
787 JavaThread* self = JavaThread::current(); | |
788 assert(!self->owns_locks(), "can't hold locks"); | |
789 | |
790 // Indicates if this is the first activiation of this function. | |
791 // In theory the profiler's callback could call back into VM and provoke | |
792 // another CompiledMethodLoad event to be posted from this thread. As the | |
793 // stack rewinds we need to ensure that the original activation does the | |
794 // completion and notifies any waiters. | |
795 bool first_activation = false; | |
796 | |
797 // the jmethodID (may not be valid) to be used for a single event | |
798 jmethodID method; | |
799 const void *code_begin; | |
800 | |
801 // grab the monitor and check if another thread is already posting | |
802 // events. If there is another thread posting events then we wait | |
803 // until it completes. (In theory we could check the pending events to | |
804 // see if any of the addresses overlap with the event that we want to | |
805 // post but as it will happen so rarely we just block any thread waiting | |
806 // to post a CompiledMethodLoad or DynamicCodeGenerated event until all | |
807 // pending CompiledMethodUnload events have been posted). | |
808 // | |
809 // If another thread isn't posting we examine the list of pending jmethodIDs. | |
810 // If the list is empty then we are done. If it's not empty then this thread | |
811 // (self) becomes the pending event poster and we remove the top (last) | |
812 // event from the list. Note that this means we remove the newest event first | |
813 // but as they are all CompiledMethodUnload events the order doesn't matter. | |
814 // Once we have removed a jmethodID then we exit the monitor. Any other thread | |
815 // wanting to post a CompiledMethodLoad or DynamicCodeGenerated event will | |
816 // be forced to wait on the monitor. | |
817 { | |
818 MutexLocker mu(JvmtiPendingEvent_lock); | |
819 if (_current_poster != self) { | |
820 while (_current_poster != NULL) { | |
821 JvmtiPendingEvent_lock->wait(); | |
822 } | |
823 } | |
824 if ((_pending_compiled_method_unload_method_ids == NULL) || | |
825 (_pending_compiled_method_unload_method_ids->length() == 0)) { | |
826 return; | |
827 } | |
828 if (_current_poster == NULL) { | |
829 _current_poster = self; | |
830 first_activation = true; | |
831 } else { | |
832 // re-entrant | |
833 guarantee(_current_poster == self, "checking"); | |
834 } | |
835 method = _pending_compiled_method_unload_method_ids->pop(); | |
836 code_begin = _pending_compiled_method_unload_code_begins->pop(); | |
837 } | |
838 | |
839 // This thread is the pending event poster so it first posts the CompiledMethodUnload | |
840 // event for the jmethodID that has been removed from the list. Once posted it | |
841 // re-grabs the monitor and checks the list again. If the list is empty then and this | |
842 // is the first activation of the function then we reset the _have_pending_events | |
843 // flag, cleanup _current_poster to indicate that no thread is now servicing the | |
844 // pending events list, and finally notify any thread that might be waiting. | |
845 for (;;) { | |
846 post_compiled_method_unload_internal(self, method, code_begin); | |
847 | |
848 // event posted, now re-grab monitor and get the next event | |
849 // If there's no next event then we are done. If this is the first | |
850 // activiation of this function by this thread notify any waiters | |
851 // so that they can post. | |
852 { | |
853 MutexLocker ml(JvmtiPendingEvent_lock); | |
854 if (_pending_compiled_method_unload_method_ids->length() == 0) { | |
855 if (first_activation) { | |
856 _have_pending_compiled_method_unload_events = false; | |
857 _current_poster = NULL; | |
858 JvmtiPendingEvent_lock->notify_all(); | |
859 } | |
860 return; | |
861 } | |
862 method = _pending_compiled_method_unload_method_ids->pop(); | |
863 code_begin = _pending_compiled_method_unload_code_begins->pop(); | |
864 } | 777 } |
865 } | 778 } |
866 } | 779 } |
867 | 780 |
868 /////////////////////////////////////////////////////////////// | 781 /////////////////////////////////////////////////////////////// |
1828 } | 1741 } |
1829 return record; | 1742 return record; |
1830 } | 1743 } |
1831 | 1744 |
1832 void JvmtiExport::post_compiled_method_load(nmethod *nm) { | 1745 void JvmtiExport::post_compiled_method_load(nmethod *nm) { |
1833 // If there are pending CompiledMethodUnload events then these are | |
1834 // posted before this CompiledMethodLoad event. We "lock" the nmethod and | |
1835 // maintain a handle to the methodOop to ensure that the nmethod isn't | |
1836 // flushed or unloaded while posting the events. | |
1837 JavaThread* thread = JavaThread::current(); | 1746 JavaThread* thread = JavaThread::current(); |
1838 if (have_pending_compiled_method_unload_events()) { | |
1839 methodHandle mh(thread, nm->method()); | |
1840 nmethodLocker nml(nm); | |
1841 post_pending_compiled_method_unload_events(); | |
1842 } | |
1843 | 1747 |
1844 EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, | 1748 EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, |
1845 ("JVMTI [%s] method compile load event triggered", | 1749 ("JVMTI [%s] method compile load event triggered", |
1846 JvmtiTrace::safe_get_thread_name(thread))); | 1750 JvmtiTrace::safe_get_thread_name(thread))); |
1847 | 1751 |
1852 EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, | 1756 EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, |
1853 ("JVMTI [%s] class compile method load event sent %s.%s ", | 1757 ("JVMTI [%s] class compile method load event sent %s.%s ", |
1854 JvmtiTrace::safe_get_thread_name(thread), | 1758 JvmtiTrace::safe_get_thread_name(thread), |
1855 (nm->method() == NULL) ? "NULL" : nm->method()->klass_name()->as_C_string(), | 1759 (nm->method() == NULL) ? "NULL" : nm->method()->klass_name()->as_C_string(), |
1856 (nm->method() == NULL) ? "NULL" : nm->method()->name()->as_C_string())); | 1760 (nm->method() == NULL) ? "NULL" : nm->method()->name()->as_C_string())); |
1857 | |
1858 ResourceMark rm(thread); | 1761 ResourceMark rm(thread); |
1762 HandleMark hm(thread); | |
1859 | 1763 |
1860 // Add inlining information | 1764 // Add inlining information |
1861 jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm); | 1765 jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm); |
1862 // Pass inlining information through the void pointer | 1766 // Pass inlining information through the void pointer |
1863 JvmtiCompiledMethodLoadEventMark jem(thread, nm, inlinerecord); | 1767 JvmtiCompiledMethodLoadEventMark jem(thread, nm, inlinerecord); |
1894 if (callback != NULL) { | 1798 if (callback != NULL) { |
1895 (*callback)(env->jvmti_external(), method, | 1799 (*callback)(env->jvmti_external(), method, |
1896 length, code_begin, map_length, | 1800 length, code_begin, map_length, |
1897 map, NULL); | 1801 map, NULL); |
1898 } | 1802 } |
1899 } | |
1900 } | |
1901 | |
1902 // used at a safepoint to post a CompiledMethodUnload event | |
1903 void JvmtiExport::post_compiled_method_unload(jmethodID mid, const void *code_begin) { | |
1904 if (SafepointSynchronize::is_at_safepoint()) { | |
1905 // Class unloading can cause nmethod unloading which is reported | |
1906 // by the VMThread. These must be batched to be processed later. | |
1907 if (_pending_compiled_method_unload_method_ids == NULL) { | |
1908 // create list lazily | |
1909 _pending_compiled_method_unload_method_ids = new (ResourceObj::C_HEAP) GrowableArray<jmethodID>(10,true); | |
1910 _pending_compiled_method_unload_code_begins = new (ResourceObj::C_HEAP) GrowableArray<const void *>(10,true); | |
1911 } | |
1912 _pending_compiled_method_unload_method_ids->append(mid); | |
1913 _pending_compiled_method_unload_code_begins->append(code_begin); | |
1914 _have_pending_compiled_method_unload_events = true; | |
1915 } else { | |
1916 // Unloading caused by the sweeper can be reported synchronously. | |
1917 if (have_pending_compiled_method_unload_events()) { | |
1918 post_pending_compiled_method_unload_events(); | |
1919 } | |
1920 post_compiled_method_unload_internal(JavaThread::current(), mid, code_begin); | |
1921 } | 1803 } |
1922 } | 1804 } |
1923 | 1805 |
1924 void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) { | 1806 void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) { |
1925 JavaThread* thread = JavaThread::current(); | 1807 JavaThread* thread = JavaThread::current(); |
1951 if (phase == JVMTI_PHASE_PRIMORDIAL || phase == JVMTI_PHASE_START) { | 1833 if (phase == JVMTI_PHASE_PRIMORDIAL || phase == JVMTI_PHASE_START) { |
1952 post_dynamic_code_generated_internal(name, code_begin, code_end); | 1834 post_dynamic_code_generated_internal(name, code_begin, code_end); |
1953 return; | 1835 return; |
1954 } | 1836 } |
1955 | 1837 |
1956 if (have_pending_compiled_method_unload_events()) { | 1838 // Blocks until everything now in the queue has been posted |
1957 post_pending_compiled_method_unload_events(); | 1839 JvmtiDeferredEventQueue::flush_queue(Thread::current()); |
1958 } | 1840 |
1959 post_dynamic_code_generated_internal(name, code_begin, code_end); | 1841 post_dynamic_code_generated_internal(name, code_begin, code_end); |
1960 } | 1842 } |
1961 | 1843 |
1962 | 1844 |
1963 // post a DYNAMIC_CODE_GENERATED event for a given environment | 1845 // post a DYNAMIC_CODE_GENERATED event for a given environment |