Implement ObjectReference.MonitorInfo.

Change-Id: Iefc276939b9e569f4ea4d7a5af9a28276a3fb632
diff --git a/src/debugger.cc b/src/debugger.cc
index d43291e..e549f21 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -639,6 +639,36 @@
   return JDWP::ERR_NONE;
 }
 
+JDWP::JdwpError Dbg::GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  Object* o = gRegistry->Get<Object*>(object_id);
+  if (o == NULL || o == kInvalidObject) {
+    return JDWP::ERR_INVALID_OBJECT;
+  }
+
+  // Ensure all threads are suspended while we read objects' lock words.
+  Thread* self = Thread::Current();
+  Locks::mutator_lock_->SharedUnlock(self);
+  Locks::mutator_lock_->ExclusiveLock(self);
+
+  MonitorInfo monitor_info(o);
+
+  Locks::mutator_lock_->ExclusiveUnlock(self);
+  Locks::mutator_lock_->SharedLock(self);
+
+  if (monitor_info.owner != NULL) {
+    expandBufAddObjectId(reply, gRegistry->Add(monitor_info.owner->GetPeer()));
+  } else {
+    expandBufAddObjectId(reply, gRegistry->Add(NULL));
+  }
+  expandBufAdd4BE(reply, monitor_info.entry_count);
+  expandBufAdd4BE(reply, monitor_info.waiters.size());
+  for (size_t i = 0; i < monitor_info.waiters.size(); ++i) {
+    expandBufAddObjectId(reply, gRegistry->Add(monitor_info.waiters[i]->GetPeer()));
+  }
+  return JDWP::ERR_NONE;
+}
+
 JDWP::JdwpError Dbg::GetReflectedType(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply) {
   JDWP::JdwpError status;
   Class* c = DecodeClass(class_id, status);
@@ -1688,8 +1718,6 @@
 }
 
 JDWP::JdwpError Dbg::SuspendThread(JDWP::ObjectId thread_id, bool request_suspension) {
-
-  bool timeout;
   ScopedLocalRef<jobject> peer(Thread::Current()->GetJniEnv(), NULL);
   {
     ScopedObjectAccess soa(Thread::Current());
@@ -1700,10 +1728,11 @@
     return JDWP::ERR_THREAD_NOT_ALIVE;
   }
   // Suspend thread to build stack trace.
-  Thread* thread = Thread::SuspendForDebugger(peer.get(), request_suspension, &timeout);
+  bool timed_out;
+  Thread* thread = Thread::SuspendForDebugger(peer.get(), request_suspension, &timed_out);
   if (thread != NULL) {
     return JDWP::ERR_NONE;
-  } else if (timeout) {
+  } else if (timed_out) {
     return JDWP::ERR_INTERNAL;
   } else {
     return JDWP::ERR_THREAD_NOT_ALIVE;
diff --git a/src/debugger.h b/src/debugger.h
index a07cb11..fac828a 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -151,6 +151,9 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static size_t GetTagWidth(JDWP::JdwpTag tag);
 
+  static JDWP::JdwpError GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   static JDWP::JdwpError GetArrayLength(JDWP::ObjectId array_id, int& length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError OutputArray(JDWP::ObjectId array_id, int offset, int count,
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 1732ea5..97e6304 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -330,13 +330,13 @@
  */
 static JdwpError VM_Capabilities(JdwpState*, const uint8_t*, int, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  expandBufAdd1(pReply, false);   /* canWatchFieldModification */
-  expandBufAdd1(pReply, false);   /* canWatchFieldAccess */
-  expandBufAdd1(pReply, false);   /* canGetBytecodes */
-  expandBufAdd1(pReply, true);    /* canGetSyntheticAttribute */
-  expandBufAdd1(pReply, false);   /* canGetOwnedMonitorInfo */
-  expandBufAdd1(pReply, false);   /* canGetCurrentContendedMonitor */
-  expandBufAdd1(pReply, false);   /* canGetMonitorInfo */
+  expandBufAdd1(pReply, false);   // canWatchFieldModification
+  expandBufAdd1(pReply, false);   // canWatchFieldAccess
+  expandBufAdd1(pReply, false);   // canGetBytecodes
+  expandBufAdd1(pReply, true);    // canGetSyntheticAttribute
+  expandBufAdd1(pReply, false);   // canGetOwnedMonitorInfo
+  expandBufAdd1(pReply, false);   // canGetCurrentContendedMonitor
+  expandBufAdd1(pReply, true);    // canGetMonitorInfo
   return ERR_NONE;
 }
 
@@ -376,27 +376,27 @@
  */
 static JdwpError VM_CapabilitiesNew(JdwpState*, const uint8_t*, int, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  expandBufAdd1(pReply, false);   /* canWatchFieldModification */
-  expandBufAdd1(pReply, false);   /* canWatchFieldAccess */
-  expandBufAdd1(pReply, false);   /* canGetBytecodes */
-  expandBufAdd1(pReply, true);    /* canGetSyntheticAttribute */
-  expandBufAdd1(pReply, false);   /* canGetOwnedMonitorInfo */
-  expandBufAdd1(pReply, false);   /* canGetCurrentContendedMonitor */
-  expandBufAdd1(pReply, false);   /* canGetMonitorInfo */
-  expandBufAdd1(pReply, false);   /* canRedefineClasses */
-  expandBufAdd1(pReply, false);   /* canAddMethod */
-  expandBufAdd1(pReply, false);   /* canUnrestrictedlyRedefineClasses */
-  expandBufAdd1(pReply, false);   /* canPopFrames */
-  expandBufAdd1(pReply, false);   /* canUseInstanceFilters */
-  expandBufAdd1(pReply, false);   /* canGetSourceDebugExtension */
-  expandBufAdd1(pReply, false);   /* canRequestVMDeathEvent */
-  expandBufAdd1(pReply, false);   /* canSetDefaultStratum */
-  expandBufAdd1(pReply, false);   /* 1.6: canGetInstanceInfo */
-  expandBufAdd1(pReply, false);   /* 1.6: canRequestMonitorEvents */
-  expandBufAdd1(pReply, false);   /* 1.6: canGetMonitorFrameInfo */
-  expandBufAdd1(pReply, false);   /* 1.6: canUseSourceNameFilters */
-  expandBufAdd1(pReply, false);   /* 1.6: canGetConstantPool */
-  expandBufAdd1(pReply, false);   /* 1.6: canForceEarlyReturn */
+  expandBufAdd1(pReply, false);   // canWatchFieldModification
+  expandBufAdd1(pReply, false);   // canWatchFieldAccess
+  expandBufAdd1(pReply, false);   // canGetBytecodes
+  expandBufAdd1(pReply, true);    // canGetSyntheticAttribute
+  expandBufAdd1(pReply, false);   // canGetOwnedMonitorInfo
+  expandBufAdd1(pReply, false);   // canGetCurrentContendedMonitor
+  expandBufAdd1(pReply, true);    // canGetMonitorInfo
+  expandBufAdd1(pReply, false);   // canRedefineClasses
+  expandBufAdd1(pReply, false);   // canAddMethod
+  expandBufAdd1(pReply, false);   // canUnrestrictedlyRedefineClasses
+  expandBufAdd1(pReply, false);   // canPopFrames
+  expandBufAdd1(pReply, false);   // canUseInstanceFilters
+  expandBufAdd1(pReply, false);   // canGetSourceDebugExtension
+  expandBufAdd1(pReply, false);   // canRequestVMDeathEvent
+  expandBufAdd1(pReply, false);   // canSetDefaultStratum
+  expandBufAdd1(pReply, false);   // 1.6: canGetInstanceInfo
+  expandBufAdd1(pReply, false);   // 1.6: canRequestMonitorEvents
+  expandBufAdd1(pReply, false);   // 1.6: canGetMonitorFrameInfo
+  expandBufAdd1(pReply, false);   // 1.6: canUseSourceNameFilters
+  expandBufAdd1(pReply, false);   // 1.6: canGetConstantPool
+  expandBufAdd1(pReply, false);   // 1.6: canForceEarlyReturn
 
   /* fill in reserved22 through reserved32; note count started at 1 */
   for (int i = 22; i <= 32; i++) {
@@ -837,6 +837,12 @@
   return ERR_NONE;
 }
 
+static JdwpError OR_MonitorInfo(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ObjectId object_id = ReadObjectId(&buf);
+  return Dbg::GetMonitorInfo(object_id, reply);
+}
+
 /*
  * Invoke an instance method.  The invocation must occur in the specified
  * thread, which must have been suspended by an event.
@@ -1518,47 +1524,47 @@
  */
 static const JdwpHandlerMap gHandlerMap[] = {
   /* VirtualMachine command set (1) */
-  { 1,    1,  VM_Version,       "VirtualMachine.Version" },
-  { 1,    2,  VM_ClassesBySignature, "VirtualMachine.ClassesBySignature" },
-  { 1,    3,  VM_AllClasses,    "VirtualMachine.AllClasses" },
-  { 1,    4,  VM_AllThreads,    "VirtualMachine.AllThreads" },
-  { 1,    5,  VM_TopLevelThreadGroups, "VirtualMachine.TopLevelThreadGroups" },
-  { 1,    6,  VM_Dispose,       "VirtualMachine.Dispose" },
-  { 1,    7,  VM_IDSizes,       "VirtualMachine.IDSizes" },
-  { 1,    8,  VM_Suspend,       "VirtualMachine.Suspend" },
-  { 1,    9,  VM_Resume,        "VirtualMachine.Resume" },
-  { 1,    10, VM_Exit,          "VirtualMachine.Exit" },
-  { 1,    11, VM_CreateString,  "VirtualMachine.CreateString" },
-  { 1,    12, VM_Capabilities,  "VirtualMachine.Capabilities" },
-  { 1,    13, VM_ClassPaths,    "VirtualMachine.ClassPaths" },
-  { 1,    14, VM_DisposeObjects, "VirtualMachine.DisposeObjects" },
-  { 1,    15, NULL, "VirtualMachine.HoldEvents" },
-  { 1,    16, NULL, "VirtualMachine.ReleaseEvents" },
-  { 1,    17, VM_CapabilitiesNew, "VirtualMachine.CapabilitiesNew" },
-  { 1,    18, NULL, "VirtualMachine.RedefineClasses" },
-  { 1,    19, NULL, "VirtualMachine.SetDefaultStratum" },
+  { 1,    1,  VM_Version,               "VirtualMachine.Version" },
+  { 1,    2,  VM_ClassesBySignature,    "VirtualMachine.ClassesBySignature" },
+  { 1,    3,  VM_AllClasses,            "VirtualMachine.AllClasses" },
+  { 1,    4,  VM_AllThreads,            "VirtualMachine.AllThreads" },
+  { 1,    5,  VM_TopLevelThreadGroups,  "VirtualMachine.TopLevelThreadGroups" },
+  { 1,    6,  VM_Dispose,               "VirtualMachine.Dispose" },
+  { 1,    7,  VM_IDSizes,               "VirtualMachine.IDSizes" },
+  { 1,    8,  VM_Suspend,               "VirtualMachine.Suspend" },
+  { 1,    9,  VM_Resume,                "VirtualMachine.Resume" },
+  { 1,    10, VM_Exit,                  "VirtualMachine.Exit" },
+  { 1,    11, VM_CreateString,          "VirtualMachine.CreateString" },
+  { 1,    12, VM_Capabilities,          "VirtualMachine.Capabilities" },
+  { 1,    13, VM_ClassPaths,            "VirtualMachine.ClassPaths" },
+  { 1,    14, VM_DisposeObjects,        "VirtualMachine.DisposeObjects" },
+  { 1,    15, NULL,                     "VirtualMachine.HoldEvents" },
+  { 1,    16, NULL,                     "VirtualMachine.ReleaseEvents" },
+  { 1,    17, VM_CapabilitiesNew,       "VirtualMachine.CapabilitiesNew" },
+  { 1,    18, NULL,                     "VirtualMachine.RedefineClasses" },
+  { 1,    19, NULL,                     "VirtualMachine.SetDefaultStratum" },
   { 1,    20, VM_AllClassesWithGeneric, "VirtualMachine.AllClassesWithGeneric" },
-  { 1,    21, NULL, "VirtualMachine.InstanceCounts" },
+  { 1,    21, NULL,                     "VirtualMachine.InstanceCounts" },
 
   /* ReferenceType command set (2) */
-  { 2,    1,  RT_Signature,     "ReferenceType.Signature" },
-  { 2,    2,  RT_ClassLoader,   "ReferenceType.ClassLoader" },
-  { 2,    3,  RT_Modifiers,     "ReferenceType.Modifiers" },
-  { 2,    4,  RT_Fields,        "ReferenceType.Fields" },
-  { 2,    5,  RT_Methods,       "ReferenceType.Methods" },
-  { 2,    6,  RT_GetValues,     "ReferenceType.GetValues" },
-  { 2,    7,  RT_SourceFile,    "ReferenceType.SourceFile" },
-  { 2,    8,  NULL, "ReferenceType.NestedTypes" },
-  { 2,    9,  RT_Status,        "ReferenceType.Status" },
-  { 2,    10, RT_Interfaces,    "ReferenceType.Interfaces" },
-  { 2,    11, RT_ClassObject,   "ReferenceType.ClassObject" },
+  { 2,    1,  RT_Signature,            "ReferenceType.Signature" },
+  { 2,    2,  RT_ClassLoader,          "ReferenceType.ClassLoader" },
+  { 2,    3,  RT_Modifiers,            "ReferenceType.Modifiers" },
+  { 2,    4,  RT_Fields,               "ReferenceType.Fields" },
+  { 2,    5,  RT_Methods,              "ReferenceType.Methods" },
+  { 2,    6,  RT_GetValues,            "ReferenceType.GetValues" },
+  { 2,    7,  RT_SourceFile,           "ReferenceType.SourceFile" },
+  { 2,    8,  NULL,                    "ReferenceType.NestedTypes" },
+  { 2,    9,  RT_Status,               "ReferenceType.Status" },
+  { 2,    10, RT_Interfaces,           "ReferenceType.Interfaces" },
+  { 2,    11, RT_ClassObject,          "ReferenceType.ClassObject" },
   { 2,    12, RT_SourceDebugExtension, "ReferenceType.SourceDebugExtension" },
   { 2,    13, RT_SignatureWithGeneric, "ReferenceType.SignatureWithGeneric" },
-  { 2,    14, RT_FieldsWithGeneric, "ReferenceType.FieldsWithGeneric" },
-  { 2,    15, RT_MethodsWithGeneric, "ReferenceType.MethodsWithGeneric" },
-  { 2,    16, NULL, "ReferenceType.Instances" },
-  { 2,    17, NULL, "ReferenceType.ClassFileVersion" },
-  { 2,    18, NULL, "ReferenceType.ConstantPool" },
+  { 2,    14, RT_FieldsWithGeneric,    "ReferenceType.FieldsWithGeneric" },
+  { 2,    15, RT_MethodsWithGeneric,   "ReferenceType.MethodsWithGeneric" },
+  { 2,    16, NULL,                    "ReferenceType.Instances" },
+  { 2,    17, NULL,                    "ReferenceType.ClassFileVersion" },
+  { 2,    18, NULL,                    "ReferenceType.ConstantPool" },
 
   /* ClassType command set (3) */
   { 3,    1,  CT_Superclass,    "ClassType.Superclass" },
@@ -1572,44 +1578,44 @@
   /* InterfaceType command set (5) */
 
   /* Method command set (6) */
-  { 6,    1,  M_LineTable,      "Method.LineTable" },
-  { 6,    2,  M_VariableTable,  "Method.VariableTable" },
-  { 6,    3,  NULL, "Method.Bytecodes" },
-  { 6,    4,  NULL, "Method.IsObsolete" },
+  { 6,    1,  M_LineTable,                "Method.LineTable" },
+  { 6,    2,  M_VariableTable,            "Method.VariableTable" },
+  { 6,    3,  NULL,                       "Method.Bytecodes" },
+  { 6,    4,  NULL,                       "Method.IsObsolete" },
   { 6,    5,  M_VariableTableWithGeneric, "Method.VariableTableWithGeneric" },
 
   /* Field command set (8) */
 
   /* ObjectReference command set (9) */
-  { 9,    1,  OR_ReferenceType, "ObjectReference.ReferenceType" },
-  { 9,    2,  OR_GetValues,     "ObjectReference.GetValues" },
-  { 9,    3,  OR_SetValues,     "ObjectReference.SetValues" },
-  { 9,    4,  NULL, "ObjectReference.UNUSED" },
-  { 9,    5,  NULL, "ObjectReference.MonitorInfo" },
-  { 9,    6,  OR_InvokeMethod,  "ObjectReference.InvokeMethod" },
+  { 9,    1,  OR_ReferenceType,     "ObjectReference.ReferenceType" },
+  { 9,    2,  OR_GetValues,         "ObjectReference.GetValues" },
+  { 9,    3,  OR_SetValues,         "ObjectReference.SetValues" },
+  { 9,    4,  NULL,                 "ObjectReference.UNUSED" },
+  { 9,    5,  OR_MonitorInfo,       "ObjectReference.MonitorInfo" },
+  { 9,    6,  OR_InvokeMethod,      "ObjectReference.InvokeMethod" },
   { 9,    7,  OR_DisableCollection, "ObjectReference.DisableCollection" },
-  { 9,    8,  OR_EnableCollection, "ObjectReference.EnableCollection" },
-  { 9,    9,  OR_IsCollected,   "ObjectReference.IsCollected" },
-  { 9,    10, NULL, "ObjectReference.ReferringObjects" },
+  { 9,    8,  OR_EnableCollection,  "ObjectReference.EnableCollection" },
+  { 9,    9,  OR_IsCollected,       "ObjectReference.IsCollected" },
+  { 9,    10, NULL,                 "ObjectReference.ReferringObjects" },
 
   /* StringReference command set (10) */
   { 10,   1,  SR_Value,         "StringReference.Value" },
 
   /* ThreadReference command set (11) */
-  { 11,   1,  TR_Name,          "ThreadReference.Name" },
-  { 11,   2,  TR_Suspend,       "ThreadReference.Suspend" },
-  { 11,   3,  TR_Resume,        "ThreadReference.Resume" },
-  { 11,   4,  TR_Status,        "ThreadReference.Status" },
-  { 11,   5,  TR_ThreadGroup,   "ThreadReference.ThreadGroup" },
-  { 11,   6,  TR_Frames,        "ThreadReference.Frames" },
-  { 11,   7,  TR_FrameCount,    "ThreadReference.FrameCount" },
-  { 11,   8,  NULL, "ThreadReference.OwnedMonitors" },
+  { 11,   1,  TR_Name,                    "ThreadReference.Name" },
+  { 11,   2,  TR_Suspend,                 "ThreadReference.Suspend" },
+  { 11,   3,  TR_Resume,                  "ThreadReference.Resume" },
+  { 11,   4,  TR_Status,                  "ThreadReference.Status" },
+  { 11,   5,  TR_ThreadGroup,             "ThreadReference.ThreadGroup" },
+  { 11,   6,  TR_Frames,                  "ThreadReference.Frames" },
+  { 11,   7,  TR_FrameCount,              "ThreadReference.FrameCount" },
+  { 11,   8,  NULL,                       "ThreadReference.OwnedMonitors" },
   { 11,   9,  TR_CurrentContendedMonitor, "ThreadReference.CurrentContendedMonitor" },
-  { 11,   10, NULL, "ThreadReference.Stop" },
-  { 11,   11, NULL, "ThreadReference.Interrupt" },
-  { 11,   12, TR_DebugSuspendCount, "ThreadReference.SuspendCount" },
-  { 11,   13, NULL, "ThreadReference.OwnedMonitorsStackDepthInfo" },
-  { 11,   14, NULL, "ThreadReference.ForceEarlyReturn" },
+  { 11,   10, NULL,                       "ThreadReference.Stop" },
+  { 11,   11, NULL,                       "ThreadReference.Interrupt" },
+  { 11,   12, TR_DebugSuspendCount,       "ThreadReference.SuspendCount" },
+  { 11,   13, NULL,                       "ThreadReference.OwnedMonitorsStackDepthInfo" },
+  { 11,   14, NULL,                       "ThreadReference.ForceEarlyReturn" },
 
   /* ThreadGroupReference command set (12) */
   { 12,   1,  TGR_Name,         "ThreadGroupReference.Name" },
@@ -1627,19 +1633,19 @@
   /* EventRequest command set (15) */
   { 15,   1,  ER_Set,           "EventRequest.Set" },
   { 15,   2,  ER_Clear,         "EventRequest.Clear" },
-  { 15,   3,  NULL, "EventRequest.ClearAllBreakpoints" },
+  { 15,   3,  NULL,             "EventRequest.ClearAllBreakpoints" },
 
   /* StackFrame command set (16) */
   { 16,   1,  SF_GetValues,     "StackFrame.GetValues" },
   { 16,   2,  SF_SetValues,     "StackFrame.SetValues" },
   { 16,   3,  SF_ThisObject,    "StackFrame.ThisObject" },
-  { 16,   4,  NULL, "StackFrame.PopFrames" },
+  { 16,   4,  NULL,             "StackFrame.PopFrames" },
 
   /* ClassObjectReference command set (17) */
   { 17,   1,  COR_ReflectedType, "ClassObjectReference.ReflectedType" },
 
   /* Event command set (64) */
-  { 64,  100, NULL, "Event.Composite" }, // sent from VM to debugger, never received by VM
+  { 64, 100,  NULL, "Event.Composite" }, // sent from VM to debugger, never received by VM
 
   { 199,  1,  DDM_Chunk,        "DDM.Chunk" },
 };
diff --git a/src/monitor.cc b/src/monitor.cc
index 70dfd24..df09522 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -77,6 +77,9 @@
  * TODO: the various members of monitor are not SMP-safe.
  */
 
+// The shape is the bottom bit; either LW_SHAPE_THIN or LW_SHAPE_FAT.
+#define LW_SHAPE_MASK 0x1
+#define LW_SHAPE(x) static_cast<int>((x) & LW_SHAPE_MASK)
 
 /*
  * Monitor accessor.  Extracts a monitor structure pointer from a fat
@@ -976,4 +979,24 @@
   }
 }
 
+MonitorInfo::MonitorInfo(Object* o) : owner(NULL), entry_count(0) {
+  uint32_t lock_word = *o->GetRawLockWordAddress();
+  if (LW_SHAPE(lock_word) == LW_SHAPE_THIN) {
+    uint32_t owner_thin_lock_id = LW_LOCK_OWNER(lock_word);
+    if (owner_thin_lock_id != 0) {
+      owner = Runtime::Current()->GetThreadList()->FindThreadByThinLockId(owner_thin_lock_id);
+      entry_count = 1 + LW_LOCK_COUNT(lock_word);
+    }
+    // Thin locks have no waiters.
+  } else {
+    CHECK_EQ(LW_SHAPE(lock_word), LW_SHAPE_FAT);
+    Monitor* monitor = LW_MONITOR(lock_word);
+    owner = monitor->owner_;
+    entry_count = 1 + monitor->lock_count_;
+    for (Thread* waiter = monitor->wait_set_; waiter != NULL; waiter = waiter->wait_next_) {
+      waiters.push_back(waiter);
+    }
+  }
+}
+
 }  // namespace art
diff --git a/src/monitor.h b/src/monitor.h
index 977a7f1..b546289 100644
--- a/src/monitor.h
+++ b/src/monitor.h
@@ -22,6 +22,7 @@
 
 #include <iosfwd>
 #include <list>
+#include <vector>
 
 #include "base/mutex.h"
 #include "heap.h"
@@ -34,8 +35,6 @@
  */
 #define LW_SHAPE_THIN 0
 #define LW_SHAPE_FAT 1
-#define LW_SHAPE_MASK 0x1
-#define LW_SHAPE(x) ((x) & LW_SHAPE_MASK)
 
 /*
  * Hash state field.  Used to signify that an object has had its
@@ -159,6 +158,7 @@
   const AbstractMethod* locking_method_ GUARDED_BY(monitor_lock_);
   uint32_t locking_dex_pc_ GUARDED_BY(monitor_lock_);
 
+  friend class MonitorInfo;
   friend class MonitorList;
   friend class Object;
   DISALLOW_COPY_AND_ASSIGN(Monitor);
@@ -181,6 +181,21 @@
   DISALLOW_COPY_AND_ASSIGN(MonitorList);
 };
 
+// Collects information about the current state of an object's monitor.
+// This is very unsafe, and must only be called when all threads are suspended.
+// For use only by the JDWP implementation.
+class MonitorInfo {
+ public:
+  MonitorInfo(Object* o) EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  Thread* owner;
+  size_t entry_count;
+  std::vector<Thread*> waiters;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MonitorInfo);
+};
+
 }  // namespace art
 
 #endif  // ART_SRC_MONITOR_H_
diff --git a/src/native/dalvik_system_VMStack.cc b/src/native/dalvik_system_VMStack.cc
index 8ce022d..cd28b5d 100644
--- a/src/native/dalvik_system_VMStack.cc
+++ b/src/native/dalvik_system_VMStack.cc
@@ -24,7 +24,6 @@
 namespace art {
 
 static jobject GetThreadStack(JNIEnv* env, jobject peer) {
-  bool timeout;
   {
     ScopedObjectAccess soa(env);
     if (soa.Decode<Object*>(peer) == soa.Self()->GetPeer()) {
@@ -32,7 +31,8 @@
     }
   }
   // Suspend thread to build stack trace.
-  Thread* thread = Thread::SuspendForDebugger(peer, true, &timeout);
+  bool timed_out;
+  Thread* thread = Thread::SuspendForDebugger(peer, true, &timed_out);
   if (thread != NULL) {
     jobject trace;
     {
@@ -43,7 +43,7 @@
     Runtime::Current()->GetThreadList()->Resume(thread, true);
     return trace;
   } else {
-    if (timeout) {
+    if (timed_out) {
       LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
           "generous timeout.";
     }
diff --git a/src/native/java_lang_Thread.cc b/src/native/java_lang_Thread.cc
index 8db217e..473369e 100644
--- a/src/native/java_lang_Thread.cc
+++ b/src/native/java_lang_Thread.cc
@@ -119,15 +119,15 @@
   // Suspend thread to avoid it from killing itself while we set its name. We don't just hold the
   // thread list lock to avoid this, as setting the thread name causes mutator to lock/unlock
   // in the DDMS send code.
-  bool timeout;
-  Thread* thread = Thread::SuspendForDebugger(peer, true, &timeout);
+  bool timed_out;
+  Thread* thread = Thread::SuspendForDebugger(peer, true, &timed_out);
   if (thread != NULL) {
     {
       ScopedObjectAccess soa(env);
       thread->SetThreadName(name.c_str());
     }
     Runtime::Current()->GetThreadList()->Resume(thread, true);
-  } else if (timeout) {
+  } else if (timed_out) {
     LOG(ERROR) << "Trying to set thread name to '" << name.c_str() << "' failed as the thread "
         "failed to suspend within a generous timeout.";
   }
diff --git a/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index a6588b4..5ba2994 100644
--- a/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -39,48 +39,27 @@
   return Dbg::IsAllocTrackingEnabled();
 }
 
-static jobject FindThreadByThinLockId(JNIEnv* env, uint32_t thin_lock_id) {
-  struct ThreadFinder {
-    explicit ThreadFinder(uint32_t thin_lock_id) : thin_lock_id(thin_lock_id), thread(NULL) {
-    }
-
-    static void Callback(Thread* t, void* context) {
-      ThreadFinder* finder = reinterpret_cast<ThreadFinder*>(context);
-      if (t->GetThinLockId() == finder->thin_lock_id) {
-        finder->thread = t;
-      }
-    }
-
-    uint32_t thin_lock_id;
-    Thread* thread;
-  };
-  ThreadFinder finder(thin_lock_id);
-  {
-    Thread* self = static_cast<JNIEnvExt*>(env)->self;
-    MutexLock mu(self, *Locks::thread_list_lock_);
-    Runtime::Current()->GetThreadList()->ForEach(ThreadFinder::Callback, &finder);
-  }
-  if (finder.thread != NULL) {
-    ScopedObjectAccess soa(env);
-    return soa.AddLocalReference<jobject>(finder.thread->GetPeer());
-  } else {
-    return NULL;
-  }
-}
-
 /*
  * Get a stack trace as an array of StackTraceElement objects.  Returns
  * NULL on failure, e.g. if the threadId couldn't be found.
  */
 static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
-  ScopedLocalRef<jobject> peer(env,
-                               FindThreadByThinLockId(env, static_cast<uint32_t>(thin_lock_id)));
+  ScopedLocalRef<jobject> peer(env, NULL);
+  {
+    Thread* t = Runtime::Current()->GetThreadList()->FindThreadByThinLockId(thin_lock_id);
+    if (t == NULL) {
+      return NULL;
+    }
+    ScopedObjectAccess soa(env);
+    peer.reset(soa.AddLocalReference<jobject>(t->GetPeer()));
+  }
   if (peer.get() == NULL) {
     return NULL;
   }
-  bool timeout;
+
   // Suspend thread to build stack trace.
-  Thread* thread = Thread::SuspendForDebugger(peer.get(), true, &timeout);
+  bool timed_out;
+  Thread* thread = Thread::SuspendForDebugger(peer.get(), true, &timed_out);
   if (thread != NULL) {
     jobject trace;
     {
@@ -91,7 +70,7 @@
     Runtime::Current()->GetThreadList()->Resume(thread, true);
     return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
   } else {
-    if (timeout) {
+    if (timed_out) {
       LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
           "within a generous timeout.";
     }
diff --git a/src/thread.cc b/src/thread.cc
index 439e8f6..5acc611 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -668,12 +668,12 @@
   return static_cast<ThreadState>(old_state);
 }
 
-Thread* Thread::SuspendForDebugger(jobject peer, bool request_suspension, bool* timeout) {
+Thread* Thread::SuspendForDebugger(jobject peer, bool request_suspension, bool* timed_out) {
   static const useconds_t kTimeoutUs = 30 * 1000000; // 30s.
   useconds_t total_delay_us = 0;
   useconds_t delay_us = 0;
   bool did_suspend_request = false;
-  *timeout = false;
+  *timed_out = false;
   while (true) {
     Thread* thread;
     {
@@ -707,7 +707,7 @@
           if (did_suspend_request) {
             thread->ModifySuspendCount(soa.Self(), -1, true /* for_debugger */);
           }
-          *timeout = true;
+          *timed_out = true;
           return NULL;
         }
       }
diff --git a/src/thread.h b/src/thread.h
index 7bfc2e8..352da27 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -201,7 +201,7 @@
   // Wait for a debugger suspension on the thread associated with the given peer. Returns the
   // thread on success, else NULL. If the thread should be suspended then request_suspension should
   // be true on entry. If the suspension times out then *timeout is set to true.
-  static Thread* SuspendForDebugger(jobject peer,  bool request_suspension, bool* timeout)
+  static Thread* SuspendForDebugger(jobject peer,  bool request_suspension, bool* timed_out)
       LOCKS_EXCLUDED(Locks::mutator_lock_,
                      Locks::thread_list_lock_,
                      Locks::thread_suspend_count_lock_);
@@ -752,6 +752,7 @@
   Object* monitor_enter_object_;
 
   friend class Monitor;
+  friend class MonitorInfo;
 
   // Top of linked list of stack indirect reference tables or NULL for none
   StackIndirectReferenceTable* top_sirt_;
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 3ca4cd4..13c965c 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -612,4 +612,14 @@
   allocated_ids_.reset(id);
 }
 
+Thread* ThreadList::FindThreadByThinLockId(uint32_t thin_lock_id) {
+  MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
+  for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
+    if ((*it)->GetThinLockId() == thin_lock_id) {
+      return *it;
+    }
+  }
+  return NULL;
+}
+
 }  // namespace art
diff --git a/src/thread_list.h b/src/thread_list.h
index 2335fa8..7ded5e3 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -95,6 +95,8 @@
     return list_;
   }
 
+  Thread* FindThreadByThinLockId(uint32_t thin_lock_id);
+
  private:
   typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto