summaryrefslogtreecommitdiff
path: root/openjdkjvmti/events.cc
diff options
context:
space:
mode:
Diffstat (limited to 'openjdkjvmti/events.cc')
-rw-r--r--openjdkjvmti/events.cc221
1 files changed, 167 insertions, 54 deletions
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 00c81e2b3b..32dd69e0e6 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -31,10 +31,13 @@
#include "events-inl.h"
+#include <array>
+
#include "art_field-inl.h"
#include "art_jvmti.h"
#include "art_method-inl.h"
#include "base/logging.h"
+#include "dex_file_types.h"
#include "gc/allocation_listener.h"
#include "gc/gc_pause_listener.h"
#include "gc/heap.h"
@@ -45,6 +48,7 @@
#include "jni_internal.h"
#include "mirror/class.h"
#include "mirror/object-inl.h"
+#include "monitor.h"
#include "nativehelper/ScopedLocalRef.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -189,6 +193,25 @@ static bool IsThreadControllable(ArtJvmtiEvent event) {
}
}
+template<typename Type>
+static Type AddLocalRef(art::JNIEnvExt* e, art::mirror::Object* obj)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ return (obj == nullptr) ? nullptr : e->AddLocalReference<Type>(obj);
+}
+
+template<ArtJvmtiEvent kEvent, typename ...Args>
+static void RunEventCallback(EventHandler* handler,
+ art::Thread* self,
+ art::JNIEnvExt* jnienv,
+ Args... args)
+ REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ ScopedLocalRef<jthread> thread_jni(jnienv, AddLocalRef<jthread>(jnienv, self->GetPeer()));
+ handler->DispatchEvent<kEvent>(self,
+ static_cast<JNIEnv*>(jnienv),
+ thread_jni.get(),
+ args...);
+}
+
class JvmtiAllocationListener : public art::gc::AllocationListener {
public:
explicit JvmtiAllocationListener(EventHandler* handler) : handler_(handler) {}
@@ -208,26 +231,17 @@ class JvmtiAllocationListener : public art::gc::AllocationListener {
// jclass object_klass,
// jlong size
art::JNIEnvExt* jni_env = self->GetJniEnv();
-
- jthread thread_peer;
- if (self->IsStillStarting()) {
- thread_peer = nullptr;
- } else {
- thread_peer = jni_env->AddLocalReference<jthread>(self->GetPeer());
- }
-
- ScopedLocalRef<jthread> thread(jni_env, thread_peer);
ScopedLocalRef<jobject> object(
jni_env, jni_env->AddLocalReference<jobject>(*obj));
ScopedLocalRef<jclass> klass(
jni_env, jni_env->AddLocalReference<jclass>(obj->Ptr()->GetClass()));
- handler_->DispatchEvent<ArtJvmtiEvent::kVmObjectAlloc>(self,
- reinterpret_cast<JNIEnv*>(jni_env),
- thread.get(),
- object.get(),
- klass.get(),
- static_cast<jlong>(byte_count));
+ RunEventCallback<ArtJvmtiEvent::kVmObjectAlloc>(handler_,
+ self,
+ jni_env,
+ object.get(),
+ klass.get(),
+ static_cast<jlong>(byte_count));
}
}
@@ -247,6 +261,95 @@ static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener,
}
}
+class JvmtiMonitorListener : public art::MonitorCallback {
+ public:
+ explicit JvmtiMonitorListener(EventHandler* handler) : handler_(handler) {}
+
+ void MonitorContendedLocking(art::Monitor* m)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMonitorContendedEnter)) {
+ art::Thread* self = art::Thread::Current();
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ ScopedLocalRef<jobject> mon(jnienv, AddLocalRef<jobject>(jnienv, m->GetObject()));
+ RunEventCallback<ArtJvmtiEvent::kMonitorContendedEnter>(
+ handler_,
+ self,
+ jnienv,
+ mon.get());
+ }
+ }
+
+ void MonitorContendedLocked(art::Monitor* m)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMonitorContendedEntered)) {
+ art::Thread* self = art::Thread::Current();
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ ScopedLocalRef<jobject> mon(jnienv, AddLocalRef<jobject>(jnienv, m->GetObject()));
+ RunEventCallback<ArtJvmtiEvent::kMonitorContendedEntered>(
+ handler_,
+ self,
+ jnienv,
+ mon.get());
+ }
+ }
+
+ void ObjectWaitStart(art::Handle<art::mirror::Object> obj, int64_t timeout)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMonitorWait)) {
+ art::Thread* self = art::Thread::Current();
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ ScopedLocalRef<jobject> mon(jnienv, AddLocalRef<jobject>(jnienv, obj.Get()));
+ RunEventCallback<ArtJvmtiEvent::kMonitorWait>(
+ handler_,
+ self,
+ jnienv,
+ mon.get(),
+ static_cast<jlong>(timeout));
+ }
+ }
+
+
+ // Our interpretation of the spec is that the JVMTI_EVENT_MONITOR_WAITED will be sent immediately
+ // after a thread has woken up from a sleep caused by a call to Object#wait. If the thread will
+ // never go to sleep (due to not having the lock, having bad arguments, or having an exception
+ // propogated from JVMTI_EVENT_MONITOR_WAIT) we will not send this event.
+ //
+ // This does not fully match the RI semantics. Specifically, we will not send the
+ // JVMTI_EVENT_MONITOR_WAITED event in one situation where the RI would, there was an exception in
+ // the JVMTI_EVENT_MONITOR_WAIT event but otherwise the call was fine. In that case the RI would
+ // send this event and return without going to sleep.
+ //
+ // See b/65558434 for more discussion.
+ void MonitorWaitFinished(art::Monitor* m, bool timeout)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMonitorWaited)) {
+ art::Thread* self = art::Thread::Current();
+ art::JNIEnvExt* jnienv = self->GetJniEnv();
+ ScopedLocalRef<jobject> mon(jnienv, AddLocalRef<jobject>(jnienv, m->GetObject()));
+ RunEventCallback<ArtJvmtiEvent::kMonitorWaited>(
+ handler_,
+ self,
+ jnienv,
+ mon.get(),
+ static_cast<jboolean>(timeout));
+ }
+ }
+
+ private:
+ EventHandler* handler_;
+};
+
+static void SetupMonitorListener(art::MonitorCallback* listener, bool enable) {
+ // We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For
+ // now, do a workaround: (possibly) acquire and release.
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ if (enable) {
+ art::Runtime::Current()->GetRuntimeCallbacks()->AddMonitorCallback(listener);
+ } else {
+ art::Runtime::Current()->GetRuntimeCallbacks()->RemoveMonitorCallback(listener);
+ }
+}
+
// Report GC pauses (see spec) as GARBAGE_COLLECTION_START and GARBAGE_COLLECTION_END.
class JvmtiGcPauseListener : public art::gc::GcPauseListener {
public:
@@ -301,33 +404,10 @@ static void SetupGcPauseTracking(JvmtiGcPauseListener* listener, ArtJvmtiEvent e
}
}
-template<typename Type>
-static Type AddLocalRef(art::JNIEnvExt* e, art::mirror::Object* obj)
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- return (obj == nullptr) ? nullptr : e->AddLocalReference<Type>(obj);
-}
-
class JvmtiMethodTraceListener FINAL : public art::instrumentation::InstrumentationListener {
public:
explicit JvmtiMethodTraceListener(EventHandler* handler) : event_handler_(handler) {}
- template<ArtJvmtiEvent kEvent, typename ...Args>
- void RunEventCallback(art::Thread* self, art::JNIEnvExt* jnienv, Args... args)
- REQUIRES_SHARED(art::Locks::mutator_lock_) {
- ScopedLocalRef<jthread> thread_jni(jnienv, AddLocalRef<jthread>(jnienv, self->GetPeer()));
- // Just give the event a good sized JNI frame. 100 should be fine.
- jnienv->PushFrame(100);
- {
- // Need to do trampoline! :(
- art::ScopedThreadSuspension sts(self, art::ThreadState::kNative);
- event_handler_->DispatchEvent<kEvent>(self,
- static_cast<JNIEnv*>(jnienv),
- thread_jni.get(),
- args...);
- }
- jnienv->PopFrame();
- }
-
// Call-back for when a method is entered.
void MethodEntered(art::Thread* self,
art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
@@ -337,7 +417,8 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
if (!method->IsRuntimeMethod() &&
event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMethodEntry)) {
art::JNIEnvExt* jnienv = self->GetJniEnv();
- RunEventCallback<ArtJvmtiEvent::kMethodEntry>(self,
+ RunEventCallback<ArtJvmtiEvent::kMethodEntry>(event_handler_,
+ self,
jnienv,
art::jni::EncodeArtMethod(method));
}
@@ -360,6 +441,7 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
ScopedLocalRef<jobject> return_jobj(jnienv, AddLocalRef<jobject>(jnienv, return_value.Get()));
val.l = return_jobj.get();
RunEventCallback<ArtJvmtiEvent::kMethodExit>(
+ event_handler_,
self,
jnienv,
art::jni::EncodeArtMethod(method),
@@ -386,6 +468,7 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
// the union.
val.j = return_value.GetJ();
RunEventCallback<ArtJvmtiEvent::kMethodExit>(
+ event_handler_,
self,
jnienv,
art::jni::EncodeArtMethod(method),
@@ -412,6 +495,7 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
CHECK(!old_exception.IsNull());
self->ClearException();
RunEventCallback<ArtJvmtiEvent::kMethodExit>(
+ event_handler_,
self,
jnienv,
art::jni::EncodeArtMethod(method),
@@ -442,11 +526,11 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
jlocation location = static_cast<jlocation>(new_dex_pc);
// Step event is reported first according to the spec.
if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kSingleStep)) {
- RunEventCallback<ArtJvmtiEvent::kSingleStep>(self, jnienv, jmethod, location);
+ RunEventCallback<ArtJvmtiEvent::kSingleStep>(event_handler_, self, jnienv, jmethod, location);
}
// Next we do the Breakpoint events. The Dispatch code will filter the individual
if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kBreakpoint)) {
- RunEventCallback<ArtJvmtiEvent::kBreakpoint>(self, jnienv, jmethod, location);
+ RunEventCallback<ArtJvmtiEvent::kBreakpoint>(event_handler_, self, jnienv, jmethod, location);
}
}
@@ -464,7 +548,8 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
ScopedLocalRef<jobject> fklass(jnienv,
AddLocalRef<jobject>(jnienv,
field->GetDeclaringClass().Ptr()));
- RunEventCallback<ArtJvmtiEvent::kFieldAccess>(self,
+ RunEventCallback<ArtJvmtiEvent::kFieldAccess>(event_handler_,
+ self,
jnienv,
art::jni::EncodeArtMethod(method),
static_cast<jlocation>(dex_pc),
@@ -492,6 +577,7 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
jvalue val;
val.l = fval.get();
RunEventCallback<ArtJvmtiEvent::kFieldModification>(
+ event_handler_,
self,
jnienv,
art::jni::EncodeArtMethod(method),
@@ -525,6 +611,7 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
// the union.
val.j = field_value.GetJ();
RunEventCallback<ArtJvmtiEvent::kFieldModification>(
+ event_handler_,
self,
jnienv,
art::jni::EncodeArtMethod(method),
@@ -541,16 +628,15 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
void WatchedFramePop(art::Thread* self, const art::ShadowFrame& frame)
REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
- if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kFramePop)) {
art::JNIEnvExt* jnienv = self->GetJniEnv();
- jboolean is_exception_pending = self->IsExceptionPending();
- RunEventCallback<ArtJvmtiEvent::kFramePop>(
- self,
- jnienv,
- art::jni::EncodeArtMethod(frame.GetMethod()),
- is_exception_pending,
- &frame);
- }
+ jboolean is_exception_pending = self->IsExceptionPending();
+ RunEventCallback<ArtJvmtiEvent::kFramePop>(
+ event_handler_,
+ self,
+ jnienv,
+ art::jni::EncodeArtMethod(frame.GetMethod()),
+ is_exception_pending,
+ &frame);
}
static void FindCatchMethodsFromThrow(art::Thread* self,
@@ -583,14 +669,14 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
if (!method->IsNative()) {
uint32_t cur_dex_pc = GetDexPc();
- if (cur_dex_pc == art::DexFile::kDexNoIndex) {
+ if (cur_dex_pc == art::dex::kDexNoIndex) {
// This frame looks opaque. Just keep on going.
return true;
}
bool has_no_move_exception = false;
uint32_t found_dex_pc = method->FindCatchBlock(
exception_class_, cur_dex_pc, &has_no_move_exception);
- if (found_dex_pc != art::DexFile::kDexNoIndex) {
+ if (found_dex_pc != art::dex::kDexNoIndex) {
// We found the catch. Store the result and return.
*catch_method_ptr_ = method;
*catch_dex_pc_ptr_ = found_dex_pc;
@@ -639,6 +725,7 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
ScopedLocalRef<jobject> exception(jnienv,
AddLocalRef<jobject>(jnienv, exception_object.Get()));
RunEventCallback<ArtJvmtiEvent::kException>(
+ event_handler_,
self,
jnienv,
art::jni::EncodeArtMethod(method),
@@ -664,6 +751,7 @@ class JvmtiMethodTraceListener FINAL : public art::instrumentation::Instrumentat
ScopedLocalRef<jobject> exception(jnienv,
AddLocalRef<jobject>(jnienv, exception_object.Get()));
RunEventCallback<ArtJvmtiEvent::kExceptionCatch>(
+ event_handler_,
self,
jnienv,
art::jni::EncodeArtMethod(method),
@@ -774,6 +862,23 @@ void EventHandler::HandleLocalAccessCapabilityAdded() {
art::Runtime::Current()->GetClassLinker()->VisitClasses(&visitor);
}
+bool EventHandler::OtherMonitorEventsEnabledAnywhere(ArtJvmtiEvent event) {
+ std::array<ArtJvmtiEvent, 4> events {
+ {
+ ArtJvmtiEvent::kMonitorContendedEnter,
+ ArtJvmtiEvent::kMonitorContendedEntered,
+ ArtJvmtiEvent::kMonitorWait,
+ ArtJvmtiEvent::kMonitorWaited
+ }
+ };
+ for (ArtJvmtiEvent e : events) {
+ if (e != event && IsEventEnabledAnywhere(e)) {
+ return true;
+ }
+ }
+ return false;
+}
+
// Handle special work for the given event type, if necessary.
void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) {
switch (event) {
@@ -814,7 +919,14 @@ void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) {
case ArtJvmtiEvent::kExceptionCatch:
SetupTraceListener(method_trace_listener_.get(), event, enable);
return;
-
+ case ArtJvmtiEvent::kMonitorContendedEnter:
+ case ArtJvmtiEvent::kMonitorContendedEntered:
+ case ArtJvmtiEvent::kMonitorWait:
+ case ArtJvmtiEvent::kMonitorWaited:
+ if (!OtherMonitorEventsEnabledAnywhere(event)) {
+ SetupMonitorListener(monitor_listener_.get(), enable);
+ }
+ return;
default:
break;
}
@@ -943,6 +1055,7 @@ EventHandler::EventHandler() {
alloc_listener_.reset(new JvmtiAllocationListener(this));
gc_pause_listener_.reset(new JvmtiGcPauseListener(this));
method_trace_listener_.reset(new JvmtiMethodTraceListener(this));
+ monitor_listener_.reset(new JvmtiMonitorListener(this));
}
EventHandler::~EventHandler() {