Allocate interrupted exception before re-acquiring lock

Allocating the monitor exception after acquiring the lock can cause
a deadlock in the following scenario:

Reference queue daemon interrupted from wait() on
ReferenceQueue.class. Tries to allocate exception and starts a GC
that blocks on WaitForGcToComplete.

Some other thread is already doing a GC, and tries to enqueue the
cleared refereneces. This deadlocks trying to lock Reference.class
in ReferenceQueue.add.

Bug: 27508829
Change-Id: Icbc18b6b8d1e906c3f7413810d6cefdda06eb921
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 1ce5841..a262c7a 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -497,6 +497,24 @@
     self->SetWaitMonitor(nullptr);
   }
 
+  // Allocate the interrupted exception not holding the monitor lock since it may cause a GC.
+  // If the GC requires acquiring the monitor for enqueuing cleared references, this would
+  // cause a deadlock if the monitor is held.
+  if (was_interrupted && interruptShouldThrow) {
+    /*
+     * We were interrupted while waiting, or somebody interrupted an
+     * un-interruptible thread earlier and we're bailing out immediately.
+     *
+     * The doc sayeth: "The interrupted status of the current thread is
+     * cleared when this exception is thrown."
+     */
+    {
+      MutexLock mu(self, *self->GetWaitMutex());
+      self->SetInterruptedLocked(false);
+    }
+    self->ThrowNewException("Ljava/lang/InterruptedException;", nullptr);
+  }
+
   // Re-acquire the monitor and lock.
   Lock(self);
   monitor_lock_.Lock(self);
@@ -516,21 +534,6 @@
   RemoveFromWaitSet(self);
 
   monitor_lock_.Unlock(self);
-
-  if (was_interrupted && interruptShouldThrow) {
-    /*
-     * We were interrupted while waiting, or somebody interrupted an
-     * un-interruptible thread earlier and we're bailing out immediately.
-     *
-     * The doc sayeth: "The interrupted status of the current thread is
-     * cleared when this exception is thrown."
-     */
-    {
-      MutexLock mu(self, *self->GetWaitMutex());
-      self->SetInterruptedLocked(false);
-    }
-    self->ThrowNewException("Ljava/lang/InterruptedException;", nullptr);
-  }
 }
 
 void Monitor::Notify(Thread* self) {