< prev index next >

src/hotspot/share/prims/jvmtiExport.cpp

Print this page
rev 50392 : JEP 331

@@ -1026,16 +1026,16 @@
     }
   }
   return k;
 }
 
-class JvmtiVMObjectAllocEventMark : public JvmtiClassEventMark  {
+class JvmtiObjectAllocEventMark : public JvmtiClassEventMark  {
  private:
    jobject _jobj;
    jlong    _size;
  public:
-   JvmtiVMObjectAllocEventMark(JavaThread *thread, oop obj) : JvmtiClassEventMark(thread, oop_to_klass(obj)) {
+   JvmtiObjectAllocEventMark(JavaThread *thread, oop obj) : JvmtiClassEventMark(thread, oop_to_klass(obj)) {
      _jobj = (jobject)to_jobject(obj);
      _size = obj->size() * wordSize;
    };
    jobject jni_jobject() { return _jobj; }
    jlong size() { return _size; }

@@ -1196,10 +1196,11 @@
 bool              JvmtiExport::_should_post_garbage_collection_start      = false;
 bool              JvmtiExport::_should_post_garbage_collection_finish     = false;
 bool              JvmtiExport::_should_post_object_free                   = false;
 bool              JvmtiExport::_should_post_resource_exhausted            = false;
 bool              JvmtiExport::_should_post_vm_object_alloc               = false;
+bool              JvmtiExport::_should_post_sampled_object_alloc          = false;
 bool              JvmtiExport::_should_post_on_exceptions                 = false;
 
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 

@@ -2278,11 +2279,11 @@
     // Can not take safepoint here.
     NoSafepointVerifier no_sfpt;
     // Can not take safepoint here so can not use state_for to get
     // jvmti thread state.
     JvmtiThreadState *state = ((JavaThread*)thread)->jvmti_thread_state();
-    if (state != NULL ) {
+    if (state != NULL) {
       // state is non NULL when VMObjectAllocEventCollector is enabled.
       JvmtiVMObjectAllocEventCollector *collector;
       collector = state->get_vm_object_alloc_event_collector();
       if (collector != NULL && collector->is_enabled()) {
         // Don't record classes as these will be notified via the ClassLoad

@@ -2293,10 +2294,31 @@
       }
     }
   }
 }
 
+// Collect all the sampled allocated objects.
+void JvmtiExport::record_sampled_internal_object_allocation(oop obj) {
+  Thread* thread = Thread::current_or_null();
+  if (thread != NULL && thread->is_Java_thread())  {
+    // Can not take safepoint here.
+    NoSafepointVerifier no_sfpt;
+    // Can not take safepoint here so can not use state_for to get
+    // jvmti thread state.
+    JvmtiThreadState *state = ((JavaThread*)thread)->jvmti_thread_state();
+    if (state != NULL) {
+      // state is non NULL when SampledObjectAllocEventCollector is enabled.
+      JvmtiSampledObjectAllocEventCollector *collector;
+      collector = state->get_sampled_object_alloc_event_collector();
+
+      if (collector != NULL && collector->is_enabled()) {
+        collector->record_allocation(obj);
+      }
+    }
+  }
+}
+
 void JvmtiExport::post_garbage_collection_finish() {
   Thread *thread = Thread::current(); // this event is posted from VM-Thread.
   EVT_TRIG_TRACE(JVMTI_EVENT_GARBAGE_COLLECTION_FINISH,
                  ("[%s] garbage collection finish event triggered",
                   JvmtiTrace::safe_get_thread_name(thread)));

@@ -2482,11 +2504,10 @@
       }
     }
   }
 }
 
-
 void JvmtiExport::post_vm_object_alloc(JavaThread *thread,  oop object) {
   EVT_TRIG_TRACE(JVMTI_EVENT_VM_OBJECT_ALLOC, ("[%s] Trg vm object alloc triggered",
                       JvmtiTrace::safe_get_thread_name(thread)));
   if (object == NULL) {
     return;

@@ -2498,21 +2519,49 @@
     if (env->is_enabled(JVMTI_EVENT_VM_OBJECT_ALLOC)) {
       EVT_TRACE(JVMTI_EVENT_VM_OBJECT_ALLOC, ("[%s] Evt vmobject alloc sent %s",
                                          JvmtiTrace::safe_get_thread_name(thread),
                                          object==NULL? "NULL" : object->klass()->external_name()));
 
-      JvmtiVMObjectAllocEventMark jem(thread, h());
+      JvmtiObjectAllocEventMark jem(thread, h());
       JvmtiJavaThreadEventTransition jet(thread);
       jvmtiEventVMObjectAlloc callback = env->callbacks()->VMObjectAlloc;
       if (callback != NULL) {
         (*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread(),
                     jem.jni_jobject(), jem.jni_class(), jem.size());
       }
     }
   }
 }
 
+void JvmtiExport::post_sampled_object_alloc(JavaThread *thread, oop object) {
+  EVT_TRIG_TRACE(JVMTI_EVENT_SAMPLED_OBJECT_ALLOC,
+                 ("[%s] Trg sampled object alloc triggered",
+                  JvmtiTrace::safe_get_thread_name(thread)));
+  if (object == NULL) {
+    return;
+  }
+  HandleMark hm(thread);
+  Handle h(thread, object);
+  JvmtiEnvIterator it;
+  for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
+    if (env->is_enabled(JVMTI_EVENT_SAMPLED_OBJECT_ALLOC)) {
+      EVT_TRACE(JVMTI_EVENT_SAMPLED_OBJECT_ALLOC,
+                ("[%s] Evt sampled object alloc sent %s",
+                 JvmtiTrace::safe_get_thread_name(thread),
+                 object == NULL ? "NULL" : object->klass()->external_name()));
+
+      JvmtiObjectAllocEventMark jem(thread, h());
+      JvmtiJavaThreadEventTransition jet(thread);
+      jvmtiEventSampledObjectAlloc callback = env->callbacks()->SampledObjectAlloc;
+      if (callback != NULL) {
+        (*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread(),
+                    jem.jni_jobject(), jem.jni_class(), jem.size());
+      }
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 void JvmtiExport::cleanup_thread(JavaThread* thread) {
   assert(JavaThread::current() == thread, "thread is not current");
   MutexLocker mu(JvmtiThreadState_lock);

@@ -2534,11 +2583,11 @@
   }
 }
 
 void JvmtiExport::oops_do(OopClosure* f) {
   JvmtiCurrentBreakpoints::oops_do(f);
-  JvmtiVMObjectAllocEventCollector::oops_do_for_all_threads(f);
+  JvmtiObjectAllocEventCollector::oops_do_for_all_threads(f);
 }
 
 void JvmtiExport::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
   JvmtiTagMap::weak_oops_do(is_alive, f);
 }

@@ -2667,34 +2716,55 @@
     _prev = state->get_vm_object_alloc_event_collector();
     state->set_vm_object_alloc_event_collector((JvmtiVMObjectAllocEventCollector *)this);
   } else if (is_dynamic_code_event()) {
     _prev = state->get_dynamic_code_event_collector();
     state->set_dynamic_code_event_collector((JvmtiDynamicCodeEventCollector *)this);
+  } else if (is_sampled_object_alloc_event()) {
+    JvmtiSampledObjectAllocEventCollector *prev = state->get_sampled_object_alloc_event_collector();
+
+    if (prev) {
+      // JvmtiSampledObjectAllocEventCollector wants only one active collector
+      // enabled. This allows to have a collector detect a user code requiring
+      // a sample in the callback.
+      return;
   }
+    state->set_sampled_object_alloc_event_collector((JvmtiSampledObjectAllocEventCollector*) this);
+  }
+
+  _unset_jvmti_thread_state = true;
 }
 
 // Unset current event collection in this thread and reset it with previous
 // collector.
 void JvmtiEventCollector::unset_jvmti_thread_state() {
+  if (!_unset_jvmti_thread_state) {
+    return;
+  }
+
   JvmtiThreadState* state = JavaThread::current()->jvmti_thread_state();
   if (state != NULL) {
     // restore the previous event collector (if any)
     if (is_vm_object_alloc_event()) {
       if (state->get_vm_object_alloc_event_collector() == this) {
         state->set_vm_object_alloc_event_collector((JvmtiVMObjectAllocEventCollector *)_prev);
       } else {
         // this thread's jvmti state was created during the scope of
         // the event collector.
       }
-    } else {
-      if (is_dynamic_code_event()) {
+    } else if (is_dynamic_code_event()) {
         if (state->get_dynamic_code_event_collector() == this) {
           state->set_dynamic_code_event_collector((JvmtiDynamicCodeEventCollector *)_prev);
         } else {
           // this thread's jvmti state was created during the scope of
           // the event collector.
         }
+    } else if (is_sampled_object_alloc_event()) {
+      if (state->get_sampled_object_alloc_event_collector() == this) {
+        state->set_sampled_object_alloc_event_collector((JvmtiSampledObjectAllocEventCollector*)_prev);
+      } else {
+        // this thread's jvmti state was created during the scope of
+        // the event collector.
       }
     }
   }
 }
 

@@ -2728,66 +2798,66 @@
  }
  _code_blobs->append(new JvmtiCodeBlobDesc(name, start, end));
 }
 
 // Setup current thread to record vm allocated objects.
-JvmtiVMObjectAllocEventCollector::JvmtiVMObjectAllocEventCollector() : _allocated(NULL) {
-  if (JvmtiExport::should_post_vm_object_alloc()) {
-    _enable = true;
-    setup_jvmti_thread_state();
-  } else {
-    _enable = false;
-  }
+JvmtiObjectAllocEventCollector::JvmtiObjectAllocEventCollector() :
+    _allocated(NULL), _enable(false), _post_callback(NULL) {
 }
 
 // Post vm_object_alloc event for vm allocated objects visible to java
 // world.
-JvmtiVMObjectAllocEventCollector::~JvmtiVMObjectAllocEventCollector() {
-  if (_allocated != NULL) {
+void JvmtiObjectAllocEventCollector::generate_call_for_allocated() {
+  if (_allocated) {
     set_enabled(false);
     for (int i = 0; i < _allocated->length(); i++) {
       oop obj = _allocated->at(i);
-      JvmtiExport::post_vm_object_alloc(JavaThread::current(), obj);
+      _post_callback(JavaThread::current(), obj);
     }
-    delete _allocated;
+    delete _allocated, _allocated = NULL;
   }
-  unset_jvmti_thread_state();
 }
 
-void JvmtiVMObjectAllocEventCollector::record_allocation(oop obj) {
-  assert(is_enabled(), "VM object alloc event collector is not enabled");
+void JvmtiObjectAllocEventCollector::record_allocation(oop obj) {
+  assert(is_enabled(), "Object alloc event collector is not enabled");
   if (_allocated == NULL) {
     _allocated = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<oop>(1, true);
   }
   _allocated->push(obj);
 }
 
 // GC support.
-void JvmtiVMObjectAllocEventCollector::oops_do(OopClosure* f) {
-  if (_allocated != NULL) {
-    for(int i=_allocated->length() - 1; i >= 0; i--) {
+void JvmtiObjectAllocEventCollector::oops_do(OopClosure* f) {
+  if (_allocated) {
+    for(int i = _allocated->length() - 1; i >= 0; i--) {
       if (_allocated->at(i) != NULL) {
         f->do_oop(_allocated->adr_at(i));
       }
     }
   }
 }
 
-void JvmtiVMObjectAllocEventCollector::oops_do_for_all_threads(OopClosure* f) {
+void JvmtiObjectAllocEventCollector::oops_do_for_all_threads(OopClosure* f) {
   // no-op if jvmti not enabled
   if (!JvmtiEnv::environments_might_exist()) {
     return;
   }
 
   for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jthr = jtiwh.next(); ) {
     JvmtiThreadState *state = jthr->jvmti_thread_state();
     if (state != NULL) {
-      JvmtiVMObjectAllocEventCollector *collector;
+      JvmtiObjectAllocEventCollector *collector;
       collector = state->get_vm_object_alloc_event_collector();
       while (collector != NULL) {
         collector->oops_do(f);
-        collector = (JvmtiVMObjectAllocEventCollector *)collector->get_prev();
+        collector = (JvmtiObjectAllocEventCollector*) collector->get_prev();
+      }
+
+      collector = state->get_sampled_object_alloc_event_collector();
+      while (collector != NULL) {
+        collector->oops_do(f);
+        collector = (JvmtiObjectAllocEventCollector*) collector->get_prev();
       }
     }
   }
 }
 

@@ -2818,10 +2888,67 @@
   if (was_enabled()) {
     _collector->set_enabled(true);
   }
 };
 
+// Setup current thread to record vm allocated objects.
+JvmtiVMObjectAllocEventCollector::JvmtiVMObjectAllocEventCollector() {
+  if (JvmtiExport::should_post_vm_object_alloc()) {
+    _enable = true;
+    setup_jvmti_thread_state();
+    _post_callback = JvmtiExport::post_vm_object_alloc;
+  }
+}
+
+JvmtiVMObjectAllocEventCollector::~JvmtiVMObjectAllocEventCollector() {
+  if (_enable) {
+    generate_call_for_allocated();
+  }
+  unset_jvmti_thread_state();
+}
+
+bool JvmtiSampledObjectAllocEventCollector::object_alloc_is_safe_to_sample() {
+  Thread* thread = Thread::current();
+  // Really only sample allocations if this is a JavaThread and not the compiler
+  // thread.
+  if (!thread->is_Java_thread() || thread->is_Compiler_thread()) {
+    return false;
+  }
+
+  if (Compile_lock->owner() == thread ||
+      MultiArray_lock->owner() == thread) {
+    return false;
+  }
+  return true;
+}
+
+// Setup current thread to record sampled allocated objects.
+JvmtiSampledObjectAllocEventCollector::JvmtiSampledObjectAllocEventCollector() {
+  if (JvmtiExport::should_post_sampled_object_alloc()) {
+    if (!object_alloc_is_safe_to_sample()) {
+      return;
+    }
+
+    _enable = true;
+    setup_jvmti_thread_state();
+    _post_callback = JvmtiExport::post_sampled_object_alloc;
+  }
+}
+
+JvmtiSampledObjectAllocEventCollector::~JvmtiSampledObjectAllocEventCollector() {
+  if (!_enable) {
+    return;
+  }
+
+  generate_call_for_allocated();
+  unset_jvmti_thread_state();
+
+  // Unset the sampling collector as present in assertion mode only.
+  assert(Thread::current()->is_Java_thread(),
+         "Should always be in a Java thread");
+}
+
 JvmtiGCMarker::JvmtiGCMarker() {
   // if there aren't any JVMTI environments then nothing to do
   if (!JvmtiEnv::environments_might_exist()) {
     return;
   }
< prev index next >