--- a/src/hotspot/share/prims/jvmtiExport.cpp Mon Jun 11 15:28:24 2018 +0200
+++ b/src/hotspot/share/prims/jvmtiExport.cpp Fri Jun 15 00:49:54 2018 -0700
@@ -1028,12 +1028,12 @@
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;
};
@@ -1198,6 +1198,7 @@
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;
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -2280,7 +2281,7 @@
// 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();
@@ -2295,6 +2296,27 @@
}
}
+// 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,
@@ -2484,8 +2506,7 @@
}
}
-
-void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) {
+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) {
@@ -2500,7 +2521,7 @@
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) {
@@ -2511,6 +2532,34 @@
}
}
+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) {
@@ -2536,7 +2585,7 @@
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) {
@@ -2669,12 +2718,28 @@
} 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)
@@ -2685,14 +2750,19 @@
// this thread's jvmti state was created during the scope of
// the event collector.
}
- } 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_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.
}
}
}
@@ -2730,31 +2800,25 @@
}
// 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);
}
@@ -2762,9 +2826,9 @@
}
// 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));
}
@@ -2772,7 +2836,7 @@
}
}
-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;
@@ -2781,11 +2845,17 @@
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();
}
}
}
@@ -2820,6 +2890,63 @@
}
};
+// 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()) {