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 /////////////////////////////////////////////////////////////// |
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(); |