Fix a heap lock/thread list lock deadlock.

We had an uncaught OOME whose uncaught exception handler -- running
with the thread lock held -- was trying to cause a GC while some
other thread had the heap lock and was waiting for the thread list
lock.

Change-Id: I22177129562268837127d9edcc63ef5e93054bdf
diff --git a/src/thread.cc b/src/thread.cc
index d68d1db..af6c29d 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -751,34 +751,9 @@
   }
 
   if (peer_ != NULL) {
-    Object* group = gThread_group->GetObject(peer_);
-
-    // Handle any pending exception.
-    if (IsExceptionPending()) {
-      // Get and clear the exception.
-      Object* exception = GetException();
-      ClearException();
-
-      // If the thread has its own handler, use that.
-      Object* handler = gThread_uncaughtHandler->GetObject(peer_);
-      if (handler == NULL) {
-        // Otherwise use the thread group's default handler.
-        handler = group;
-      }
-
-      // Call the handler.
-      Method* m = handler->GetClass()->FindVirtualMethodForVirtualOrInterface(gUncaughtExceptionHandler_uncaughtException);
-      Object* args[2];
-      args[0] = peer_;
-      args[1] = exception;
-      m->Invoke(this, handler, reinterpret_cast<byte*>(&args), NULL);
-
-      // If the handler threw, clear that exception too.
-      ClearException();
-    }
-
     // this.group.removeThread(this);
     // group can be null if we're in the compiler or a test.
+    Object* group = gThread_group->GetObject(peer_);
     if (group != NULL) {
       Method* m = group->GetClass()->FindVirtualMethodForVirtualOrInterface(gThreadGroup_removeThread);
       Object* args = peer_;
@@ -816,6 +791,35 @@
   delete long_jump_context_;
 }
 
+void Thread::HandleUncaughtExceptions() {
+  if (!IsExceptionPending()) {
+    return;
+  }
+
+  ScopedThreadStateChange tsc(this, Thread::kRunnable);
+
+  // Get and clear the exception.
+  Object* exception = GetException();
+  ClearException();
+
+  // If the thread has its own handler, use that.
+  Object* handler = gThread_uncaughtHandler->GetObject(peer_);
+  if (handler == NULL) {
+    // Otherwise use the thread group's default handler.
+    handler = gThread_group->GetObject(peer_);
+  }
+
+  // Call the handler.
+  Method* m = handler->GetClass()->FindVirtualMethodForVirtualOrInterface(gUncaughtExceptionHandler_uncaughtException);
+  Object* args[2];
+  args[0] = peer_;
+  args[1] = exception;
+  m->Invoke(this, handler, reinterpret_cast<byte*>(&args), NULL);
+
+  // If the handler threw, clear that exception too.
+  ClearException();
+}
+
 size_t Thread::NumSirtReferences() {
   size_t count = 0;
   for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
@@ -1186,13 +1190,22 @@
       msg, (throwing_OutOfMemoryError_ ? " (recursive case)" : ""));
   if (!throwing_OutOfMemoryError_) {
     throwing_OutOfMemoryError_ = true;
-    ThrowNewException("Ljava/lang/OutOfMemoryError;", msg);
+    ThrowNewException("Ljava/lang/OutOfMemoryError;", NULL);
   } else {
     SetException(pre_allocated_OutOfMemoryError_);
   }
   throwing_OutOfMemoryError_ = false;
 }
 
+
+Thread* Thread::CurrentFromGdb() const {
+  return Thread::Current();
+}
+
+void Thread::DumpFromGdb() const {
+  Dump(std::cerr);
+}
+
 class CatchBlockStackVisitor : public Thread::StackVisitor {
  public:
   CatchBlockStackVisitor(Class* to_find, Context* ljc)