Implement ThreadReference.CurrentContendedMonitor and ThreadReference.Interrupt.

The JDWP test for CurrentContendedMonitor also uses Interrupt.

Change-Id: Id1f6add29b578a0494da672d21dd54f23e866475
diff --git a/src/debugger.cc b/src/debugger.cc
index 958fd38..8724327 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -713,6 +713,24 @@
   return JDWP::ERR_NONE;
 }
 
+JDWP::JdwpError Dbg::GetContendedMonitor(JDWP::ObjectId thread_id, JDWP::ObjectId& contended_monitor)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedObjectAccessUnchecked soa(Thread::Current());
+  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+  Thread* thread;
+  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  if (error != JDWP::ERR_NONE) {
+    return error;
+  }
+  if (!IsSuspendedForDebugger(soa, thread)) {
+    return JDWP::ERR_THREAD_NOT_SUSPENDED;
+  }
+
+  contended_monitor = gRegistry->Add(Monitor::GetContendedMonitor(thread));
+
+  return JDWP::ERR_NONE;
+}
+
 JDWP::JdwpError Dbg::GetReflectedType(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply) {
   JDWP::JdwpError status;
   Class* c = DecodeClass(class_id, status);
@@ -1574,6 +1592,18 @@
   return JDWP::ERR_NONE;
 }
 
+JDWP::JdwpError Dbg::Interrupt(JDWP::ObjectId thread_id) {
+  ScopedObjectAccess soa(Thread::Current());
+  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+  Thread* thread;
+  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  if (error != JDWP::ERR_NONE) {
+    return error;
+  }
+  thread->Interrupt();
+  return JDWP::ERR_NONE;
+}
+
 void Dbg::GetThreads(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& thread_ids) {
   class ThreadListVisitor {
    public:
diff --git a/src/debugger.h b/src/debugger.h
index c58fd4f..b033ace 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -155,6 +155,8 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError GetOwnedMonitors(JDWP::ObjectId thread_id, std::vector<JDWP::ObjectId>& monitors)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static JDWP::JdwpError GetContendedMonitor(JDWP::ObjectId thread_id, JDWP::ObjectId& contended_monitor)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static JDWP::JdwpError GetArrayLength(JDWP::ObjectId array_id, int& length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -275,6 +277,8 @@
                             JDWP::JdwpTag tag, uint64_t value, size_t width)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  static JDWP::JdwpError Interrupt(JDWP::ObjectId thread_id);
+
   /*
    * Debugger notification
    */
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index f205c95..f0bb0b8 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -374,7 +374,7 @@
   expandBufAdd1(reply, false);   // canGetBytecodes
   expandBufAdd1(reply, true);    // canGetSyntheticAttribute
   expandBufAdd1(reply, true);    // canGetOwnedMonitorInfo
-  expandBufAdd1(reply, false);   // canGetCurrentContendedMonitor
+  expandBufAdd1(reply, true);    // canGetCurrentContendedMonitor
   expandBufAdd1(reply, true);    // canGetMonitorInfo
   return ERR_NONE;
 }
@@ -1079,17 +1079,22 @@
   return ERR_NONE;
 }
 
-/*
- * Get the monitor that the thread is waiting on.
- */
-static JdwpError TR_CurrentContendedMonitor(JdwpState*, const uint8_t* buf, int, ExpandBuf*)
+static JdwpError TR_CurrentContendedMonitor(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ReadObjectId(&buf);  // thread_id
+  ObjectId thread_id = ReadObjectId(&buf);
 
-  // TODO: create an Object to represent the monitor (we're currently
-  // just using a raw Monitor struct in the VM)
+  ObjectId contended_monitor;
+  JdwpError rc = Dbg::GetContendedMonitor(thread_id, contended_monitor);
+  if (rc != ERR_NONE) {
+    return rc;
+  }
+  return WriteTaggedObject(reply, contended_monitor);
+}
 
-  return ERR_NOT_IMPLEMENTED;
+static JdwpError TR_Interrupt(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ObjectId thread_id = ReadObjectId(&buf);
+  return Dbg::Interrupt(thread_id);
 }
 
 /*
@@ -1623,7 +1628,7 @@
   { 11,   8,  TR_OwnedMonitors,           "ThreadReference.OwnedMonitors" },
   { 11,   9,  TR_CurrentContendedMonitor, "ThreadReference.CurrentContendedMonitor" },
   { 11,   10, NULL,                       "ThreadReference.Stop" },
-  { 11,   11, NULL,                       "ThreadReference.Interrupt" },
+  { 11,   11, TR_Interrupt,               "ThreadReference.Interrupt" },
   { 11,   12, TR_DebugSuspendCount,       "ThreadReference.SuspendCount" },
   { 11,   13, NULL,                       "ThreadReference.OwnedMonitorsStackDepthInfo" },
   { 11,   14, NULL,                       "ThreadReference.ForceEarlyReturn" },
diff --git a/src/monitor.cc b/src/monitor.cc
index 80618e1..6673d19 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -823,8 +823,7 @@
 }
 
 void Monitor::DescribeWait(std::ostream& os, const Thread* thread) {
-  ThreadState state;
-  state = thread->GetState();
+  ThreadState state = thread->GetState();
 
   Object* object = NULL;
   uint32_t lock_owner = ThreadList::kInvalidId;
@@ -835,7 +834,8 @@
       os << "  - waiting on ";
     }
     {
-      MutexLock mu(Thread::Current(), *thread->wait_mutex_);
+      Thread* self = Thread::Current();
+      MutexLock mu(self, *thread->wait_mutex_);
       Monitor* monitor = thread->wait_monitor_;
       if (monitor != NULL) {
         object = monitor->obj_;
@@ -863,6 +863,24 @@
   os << "\n";
 }
 
+Object* Monitor::GetContendedMonitor(Thread* thread) {
+  // This is used to implement JDWP's ThreadReference.CurrentContendedMonitor, and has a bizarre
+  // definition of contended that includes a monitor a thread is trying to enter...
+  Object* result = thread->monitor_enter_object_;
+  if (result != NULL) {
+    return result;
+  }
+  // ...but also a monitor that the thread is waiting on.
+  {
+    MutexLock mu(Thread::Current(), *thread->wait_mutex_);
+    Monitor* monitor = thread->wait_monitor_;
+    if (monitor != NULL) {
+      return monitor->obj_;
+    }
+  }
+  return NULL;
+}
+
 void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(Object*, void*), void* callback_context) {
   AbstractMethod* m = stack_visitor->GetMethod();
   CHECK(m != NULL);
diff --git a/src/monitor.h b/src/monitor.h
index 66db42e..1b5ab76 100644
--- a/src/monitor.h
+++ b/src/monitor.h
@@ -88,6 +88,9 @@
       LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  // Used to implement JDWP's ThreadReference.CurrentContendedMonitor.
+  static Object* GetContendedMonitor(Thread* thread);
+
   // Calls 'callback' once for each lock held in the single stack frame represented by
   // the current state of 'stack_visitor'.
   static void VisitLocks(StackVisitor* stack_visitor, void (*callback)(Object*, void*), void* callback_context)