Add missing WaitForConcurrentGcToComplete calls.

Some calls to WaitForConcurrentGcToComplete were missing. This was enabling recursive GCs to occasionally occur.

Change-Id: I0dcce50ae1ebfb03681990ec3bffa7b227981383
diff --git a/src/heap.cc b/src/heap.cc
index 888c75d..0c4c6ff 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -477,6 +477,7 @@
   // Fail impossible allocations
   if (alloc_size > space->Capacity()) {
     // On failure collect soft references
+    WaitForConcurrentGcToComplete();
     CollectGarbageInternal(false, true);
     return NULL;
   }
@@ -504,6 +505,8 @@
     ++Runtime::Current()->GetStats()->gc_for_alloc_count;
     ++Thread::Current()->GetStats()->gc_for_alloc_count;
   }
+  // We don't need a WaitForConcurrentGcToComplete here since we checked
+  // is_gc_running_ earlier and we are in a heap lock.
   CollectGarbageInternal(false, false);
   ptr = space->AllocWithoutGrowth(alloc_size);
   if (ptr != NULL) {
@@ -529,6 +532,7 @@
 
   // OLD-TODO: wait for the finalizers from the previous GC to finish
   VLOG(gc) << "Forcing collection of SoftReferences for " << PrettySize(alloc_size) << " allocation";
+  // We don't need a WaitForConcurrentGcToComplete here either.
   CollectGarbageInternal(false, true);
   ptr = space->AllocWithGrowth(alloc_size);
   if (ptr != NULL) {
@@ -592,7 +596,11 @@
 
 void Heap::CollectGarbage(bool clear_soft_references) {
   ScopedHeapLock heap_lock;
-  CollectGarbageInternal(false, clear_soft_references);
+  // If we just waited for a GC to complete then we do not need to do another
+  // GC unless we clear soft references.
+  if (!WaitForConcurrentGcToComplete() || clear_soft_references) {
+    CollectGarbageInternal(false, clear_soft_references);
+  }
 }
 
 void Heap::CollectGarbageInternal(bool concurrent, bool clear_soft_references) {
@@ -723,7 +731,7 @@
   condition_->Broadcast();
 }
 
-void Heap::WaitForConcurrentGcToComplete() {
+bool Heap::WaitForConcurrentGcToComplete() {
   lock_->AssertHeld();
 
   // Busy wait for GC to finish
@@ -737,7 +745,10 @@
     if (wait_time > MsToNs(5)) {
       LOG(INFO) << "WaitForConcurrentGcToComplete blocked for " << PrettyDuration(wait_time);
     }
+    DCHECK(!is_gc_running_);
+    return true;
   }
+  return false;
 }
 
 void Heap::DumpForSigQuit(std::ostream& os) {
@@ -932,7 +943,10 @@
 
 void Heap::ConcurrentGC() {
   ScopedHeapLock heap_lock;
-  WaitForConcurrentGcToComplete();
+  // We shouldn't need a WaitForConcurrentGcToComplete here since only
+  // concurrent GC resumes threads before the GC is completed and this function
+  // is only called within the GC daemon thread.
+  CHECK(!is_gc_running_);
   // Current thread needs to be runnable or else we can't suspend all threads.
   ScopedThreadStateChange tsc(Thread::Current(), kRunnable);
   CollectGarbageInternal(true, false);
diff --git a/src/heap.h b/src/heap.h
index 96a9ee6..23053f5 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -120,8 +120,9 @@
   // from the system. Doesn't allow the space to exceed its growth limit.
   void SetIdealFootprint(size_t max_allowed_footprint);
 
-  // Blocks the caller until the garbage collector becomes idle.
-  void WaitForConcurrentGcToComplete();
+  // Blocks the caller until the garbage collector becomes idle and returns
+  // true if we waited for the GC to complete.
+  bool WaitForConcurrentGcToComplete();
 
   pid_t GetLockOwner(); // For SignalCatcher.
   void AssertLockHeld() {