Implement JVMTI GetCurrentContendedMonitor

Adds the JVMTI can_get_current_contended_monitor capability and
implements all associated functions and behaviors.

Test: ./test.py --host -j50
Bug: 62821960
Bug: 34415266
Change-Id: Ia3f19f0fbb21125bc85fb71f55e52ec61141c4ec
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index adaa48c..f92d81e 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -37,10 +37,13 @@
 #include <mutex>
 
 #include "art_jvmti.h"
+#include "monitor.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-current-inl.h"
 #include "ti_thread.h"
+#include "thread.h"
+#include "thread_pool.h"
 
 namespace openjdkjvmti {
 
@@ -323,4 +326,77 @@
   return ERR(NONE);
 }
 
+jvmtiError MonitorUtil::GetCurrentContendedMonitor(jvmtiEnv* env ATTRIBUTE_UNUSED,
+                                                   jthread thread,
+                                                   jobject* monitor) {
+  if (monitor == nullptr) {
+    return ERR(NULL_POINTER);
+  }
+  art::Thread* self = art::Thread::Current();
+  art::ScopedObjectAccess soa(self);
+  art::MutexLock mu(self, *art::Locks::thread_list_lock_);
+  art::Thread* target = ThreadUtil::GetNativeThread(thread, soa);
+  if (target == nullptr && thread == nullptr) {
+    return ERR(INVALID_THREAD);
+  }
+  if (target == nullptr) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
+  struct GetContendedMonitorClosure : public art::Closure {
+   public:
+    explicit GetContendedMonitorClosure(art::Thread* current, jobject* out)
+        : result_thread_(current), out_(out) {}
+
+    void Run(art::Thread* target_thread) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+      switch (target_thread->GetState()) {
+        // These three we are actually currently waiting on a monitor and have sent the appropriate
+        // events (if anyone is listening).
+        case art::kBlocked:
+        case art::kTimedWaiting:
+        case art::kWaiting: {
+          art::mirror::Object* mon = art::Monitor::GetContendedMonitor(target_thread);
+          *out_ = (mon == nullptr) ? nullptr
+                                   : result_thread_->GetJniEnv()->AddLocalReference<jobject>(mon);
+          return;
+        }
+        case art::kTerminated:
+        case art::kRunnable:
+        case art::kSleeping:
+        case art::kWaitingForLockInflation:
+        case art::kWaitingForTaskProcessor:
+        case art::kWaitingForGcToComplete:
+        case art::kWaitingForCheckPointsToRun:
+        case art::kWaitingPerformingGc:
+        case art::kWaitingForDebuggerSend:
+        case art::kWaitingForDebuggerToAttach:
+        case art::kWaitingInMainDebuggerLoop:
+        case art::kWaitingForDebuggerSuspension:
+        case art::kWaitingForJniOnLoad:
+        case art::kWaitingForSignalCatcherOutput:
+        case art::kWaitingInMainSignalCatcherLoop:
+        case art::kWaitingForDeoptimization:
+        case art::kWaitingForMethodTracingStart:
+        case art::kWaitingForVisitObjects:
+        case art::kWaitingForGetObjectsAllocated:
+        case art::kWaitingWeakGcRootRead:
+        case art::kWaitingForGcThreadFlip:
+        case art::kStarting:
+        case art::kNative:
+        case art::kSuspended: {
+          // We aren't currently (explicitly) waiting for a monitor anything so just return null.
+          *out_ = nullptr;
+          return;
+        }
+      }
+    }
+
+   private:
+    art::Thread* result_thread_;
+    jobject* out_;
+  };
+  GetContendedMonitorClosure closure(self, monitor);
+  target->RequestSynchronousCheckpoint(&closure);
+  return OK;
+}
+
 }  // namespace openjdkjvmti