Merge "Enable concurrent sweeping for non-concurrent GC."
diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h
index ed140e0..646fce6 100644
--- a/runtime/gc/accounting/space_bitmap-inl.h
+++ b/runtime/gc/accounting/space_bitmap-inl.h
@@ -70,7 +70,7 @@
 template<size_t kAlignment> template<typename Visitor>
 inline void SpaceBitmap<kAlignment>::VisitMarkedRange(uintptr_t visit_begin, uintptr_t visit_end,
                                                       const Visitor& visitor) const {
-  DCHECK_LT(visit_begin, visit_end);
+  DCHECK_LE(visit_begin, visit_end);
 #if 0
   for (uintptr_t i = visit_begin; i < visit_end; i += kAlignment) {
     mirror::Object* obj = reinterpret_cast<mirror::Object*>(i);
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index 5c7cce2..a805809 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -65,8 +65,9 @@
     return offset / kAlignment / kBitsPerWord;
   }
 
-  static uintptr_t IndexToOffset(size_t index) ALWAYS_INLINE {
-    return static_cast<uintptr_t>(index * kAlignment * kBitsPerWord);
+  template<typename T>
+  static T IndexToOffset(T index) {
+    return static_cast<T>(index * kAlignment * kBitsPerWord);
   }
 
   // Bits are packed in the obvious way.
@@ -158,8 +159,8 @@
   }
 
   // Size in bytes of the memory that the bitmaps spans.
-  size_t HeapSize() const {
-    return IndexToOffset(Size() / kWordSize);
+  uint64_t HeapSize() const {
+    return IndexToOffset<uint64_t>(Size() / kWordSize);
   }
 
   uintptr_t HeapBegin() const {
@@ -167,8 +168,8 @@
   }
 
   // The maximum address which the bitmap can span. (HeapBegin() <= object < HeapLimit()).
-  uintptr_t HeapLimit() const {
-    return HeapBegin() + static_cast<uintptr_t>(HeapSize());
+  uint64_t HeapLimit() const {
+    return static_cast<uint64_t>(HeapBegin()) + HeapSize();
   }
 
   // Set the max address which can covered by the bitmap.
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index ab26a9c..ce7c75a 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -33,10 +33,7 @@
 
   ~ConcurrentCopying() {}
 
-  virtual void InitializePhase() OVERRIDE {}
-  virtual void MarkingPhase() OVERRIDE {}
-  virtual void ReclaimPhase() OVERRIDE {}
-  virtual void FinishPhase() OVERRIDE {}
+  virtual void RunPhases() OVERRIDE {}
   virtual GcType GetGcType() const OVERRIDE {
     return kGcTypePartial;
   }
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 615ec98..f9a6abe 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -14,10 +14,7 @@
  * limitations under the License.
  */
 
-#define ATRACE_TAG ATRACE_TAG_DALVIK
-
 #include <stdio.h>
-#include <cutils/trace.h>
 
 #include "garbage_collector.h"
 
@@ -46,9 +43,6 @@
   ResetCumulativeStatistics();
 }
 
-void GarbageCollector::PausePhase() {
-}
-
 void GarbageCollector::RegisterPause(uint64_t nano_length) {
   pause_times_.push_back(nano_length);
 }
@@ -62,7 +56,6 @@
 }
 
 void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) {
-  ThreadList* thread_list = Runtime::Current()->GetThreadList();
   Thread* self = Thread::Current();
   uint64_t start_time = NanoTime();
   timings_.Reset();
@@ -70,88 +63,12 @@
   duration_ns_ = 0;
   clear_soft_references_ = clear_soft_references;
   gc_cause_ = gc_cause;
-
   // Reset stats.
   freed_bytes_ = 0;
   freed_large_object_bytes_ = 0;
   freed_objects_ = 0;
   freed_large_objects_ = 0;
-
-  CollectorType collector_type = GetCollectorType();
-  switch (collector_type) {
-    case kCollectorTypeMS:      // Fall through.
-    case kCollectorTypeSS:      // Fall through.
-    case kCollectorTypeGSS: {
-      InitializePhase();
-      // Pause is the entire length of the GC.
-      uint64_t pause_start = NanoTime();
-      ATRACE_BEGIN("Application threads suspended");
-      // Mutator lock may be already exclusively held when we do garbage collections for changing
-      // the current collector / allocator during process state updates.
-      if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
-        // PreGcRosAllocVerification() is called in Heap::TransitionCollector().
-        RevokeAllThreadLocalBuffers();
-        MarkingPhase();
-        PausePhase();
-        ReclaimPhase();
-        // PostGcRosAllocVerification() is called in Heap::TransitionCollector().
-      } else {
-        ATRACE_BEGIN("Suspending mutator threads");
-        thread_list->SuspendAll();
-        ATRACE_END();
-        GetHeap()->PreGcRosAllocVerification(&timings_);
-        RevokeAllThreadLocalBuffers();
-        MarkingPhase();
-        PausePhase();
-        ReclaimPhase();
-        GetHeap()->PostGcRosAllocVerification(&timings_);
-        ATRACE_BEGIN("Resuming mutator threads");
-        thread_list->ResumeAll();
-        ATRACE_END();
-      }
-      ATRACE_END();
-      RegisterPause(NanoTime() - pause_start);
-      FinishPhase();
-      break;
-    }
-    case kCollectorTypeCMS: {
-      InitializePhase();
-      CHECK(!Locks::mutator_lock_->IsExclusiveHeld(self));
-      {
-        ReaderMutexLock mu(self, *Locks::mutator_lock_);
-        MarkingPhase();
-      }
-      uint64_t pause_start = NanoTime();
-      ATRACE_BEGIN("Suspending mutator threads");
-      thread_list->SuspendAll();
-      ATRACE_END();
-      ATRACE_BEGIN("All mutator threads suspended");
-      GetHeap()->PreGcRosAllocVerification(&timings_);
-      PausePhase();
-      RevokeAllThreadLocalBuffers();
-      GetHeap()->PostGcRosAllocVerification(&timings_);
-      ATRACE_END();
-      uint64_t pause_end = NanoTime();
-      ATRACE_BEGIN("Resuming mutator threads");
-      thread_list->ResumeAll();
-      ATRACE_END();
-      RegisterPause(pause_end - pause_start);
-      {
-        ReaderMutexLock mu(self, *Locks::mutator_lock_);
-        ReclaimPhase();
-      }
-      FinishPhase();
-      break;
-    }
-    case kCollectorTypeCC: {
-      // To be implemented.
-      break;
-    }
-    default: {
-      LOG(FATAL) << "Unreachable collector type=" << static_cast<size_t>(collector_type);
-      break;
-    }
-  }
+  RunPhases();  // Run all the GC phases.
   // Add the current timings to the cumulative timings.
   cumulative_timings_.AddLogger(timings_);
   // Update cumulative statistics with how many bytes the GC iteration freed.
@@ -159,6 +76,12 @@
   total_freed_bytes_ += GetFreedBytes() + GetFreedLargeObjectBytes();
   uint64_t end_time = NanoTime();
   duration_ns_ = end_time - start_time;
+  if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
+    // The entire GC was paused, clear the fake pauses which might be in the pause times and add
+    // the whole GC duration.
+    pause_times_.clear();
+    RegisterPause(duration_ns_);
+  }
   total_time_ns_ += GetDurationNs();
   for (uint64_t pause_time : pause_times_) {
     pause_histogram_.AddValue(pause_time / 1000);
@@ -213,6 +136,16 @@
   total_freed_bytes_ = 0;
 }
 
+GarbageCollector::ScopedPause::ScopedPause(GarbageCollector* collector)
+    : start_time_(NanoTime()), collector_(collector) {
+  Runtime::Current()->GetThreadList()->SuspendAll();
+}
+
+GarbageCollector::ScopedPause::~ScopedPause() {
+  collector_->RegisterPause(NanoTime() - start_time_);
+  Runtime::Current()->GetThreadList()->ResumeAll();
+}
+
 }  // namespace collector
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index b19ac3f..ca4a1d5 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -35,6 +35,16 @@
 
 class GarbageCollector {
  public:
+  class SCOPED_LOCKABLE ScopedPause {
+   public:
+    explicit ScopedPause(GarbageCollector* collector) EXCLUSIVE_LOCK_FUNCTION(Locks::mutator_lock_);
+    ~ScopedPause() UNLOCK_FUNCTION();
+
+   private:
+    const uint64_t start_time_;
+    GarbageCollector* const collector_;
+  };
+
   GarbageCollector(Heap* heap, const std::string& name);
   virtual ~GarbageCollector() { }
 
@@ -125,20 +135,8 @@
   }
 
  protected:
-  // The initial phase. Done without mutators paused.
-  virtual void InitializePhase() = 0;
-
-  // Mark all reachable objects, done concurrently.
-  virtual void MarkingPhase() = 0;
-
-  // Phase of the GC which is run with mutator lock exclusively held.
-  virtual void PausePhase();
-
-  // Called with mutators running.
-  virtual void ReclaimPhase() = 0;
-
-  // Called after the GC is finished. Done without mutators paused.
-  virtual void FinishPhase() = 0;
+  // Run all of the GC phases.
+  virtual void RunPhases() = 0;
 
   // Revoke all the thread-local buffers.
   virtual void RevokeAllThreadLocalBuffers() = 0;
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 007eb23..9cd740e 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -130,9 +130,37 @@
     // Always clear soft references if a non-sticky collection.
     clear_soft_references_ = GetGcType() != collector::kGcTypeSticky;
   }
-  // Do any pre GC verification.
-  timings_.NewSplit("PreGcVerification");
-  heap_->PreGcVerification(this);
+}
+
+void MarkSweep::RunPhases() {
+  Thread* self = Thread::Current();
+  InitializePhase();
+  Locks::mutator_lock_->AssertNotHeld(self);
+  if (IsConcurrent()) {
+    GetHeap()->PreGcVerification(this);
+    {
+      ReaderMutexLock mu(self, *Locks::mutator_lock_);
+      MarkingPhase();
+    }
+    ScopedPause pause(this);
+    GetHeap()->PrePauseRosAllocVerification(this);
+    PausePhase();
+    RevokeAllThreadLocalBuffers();
+  } else {
+    ScopedPause pause(this);
+    GetHeap()->PreGcVerificationPaused(this);
+    MarkingPhase();
+    GetHeap()->PrePauseRosAllocVerification(this);
+    PausePhase();
+    RevokeAllThreadLocalBuffers();
+  }
+  {
+    // Sweeping always done concurrently, even for non concurrent mark sweep.
+    ReaderMutexLock mu(self, *Locks::mutator_lock_);
+    ReclaimPhase();
+  }
+  GetHeap()->PostGcVerification(this);
+  FinishPhase();
 }
 
 void MarkSweep::ProcessReferences(Thread* self) {
@@ -166,7 +194,7 @@
   }
   ProcessReferences(self);
   {
-    timings_.NewSplit("SwapStacks");
+    TimingLogger::ScopedSplit split("SwapStacks", &timings_);
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
     heap_->SwapStacks(self);
     live_stack_freeze_size_ = heap_->GetLiveStack()->Size();
@@ -177,13 +205,11 @@
   timings_.StartSplit("PreSweepingGcVerification");
   heap_->PreSweepingGcVerification(this);
   timings_.EndSplit();
-  if (IsConcurrent()) {
-    // Disallow new system weaks to prevent a race which occurs when someone adds a new system
-    // weak before we sweep them. Since this new system weak may not be marked, the GC may
-    // incorrectly sweep it. This also fixes a race where interning may attempt to return a strong
-    // reference to a string that is about to be swept.
-    Runtime::Current()->DisallowNewSystemWeaks();
-  }
+  // Disallow new system weaks to prevent a race which occurs when someone adds a new system
+  // weak before we sweep them. Since this new system weak may not be marked, the GC may
+  // incorrectly sweep it. This also fixes a race where interning may attempt to return a strong
+  // reference to a string that is about to be swept.
+  Runtime::Current()->DisallowNewSystemWeaks();
 }
 
 void MarkSweep::PreCleanCards() {
@@ -265,9 +291,7 @@
   TimingLogger::ScopedSplit split("ReclaimPhase", &timings_);
   Thread* self = Thread::Current();
   SweepSystemWeaks(self);
-  if (IsConcurrent()) {
-    Runtime::Current()->AllowNewSystemWeaks();
-  }
+  Runtime::Current()->AllowNewSystemWeaks();
   {
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
 
@@ -1256,9 +1280,6 @@
 
 void MarkSweep::FinishPhase() {
   TimingLogger::ScopedSplit split("FinishPhase", &timings_);
-  // Can't enqueue references if we hold the mutator lock.
-  timings_.NewSplit("PostGcVerification");
-  heap_->PostGcVerification(this);
   if (kCountScannedTypes) {
     VLOG(gc) << "MarkSweep scanned classes=" << class_count_ << " arrays=" << array_count_
              << " other=" << other_count_;
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 41a7764..0c5a0da 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -56,11 +56,12 @@
 
   ~MarkSweep() {}
 
-  virtual void InitializePhase() OVERRIDE;
-  virtual void MarkingPhase() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  virtual void PausePhase() OVERRIDE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
-  virtual void ReclaimPhase() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  virtual void FinishPhase() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual void RunPhases() OVERRIDE NO_THREAD_SAFETY_ANALYSIS;
+  void InitializePhase();
+  void MarkingPhase() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void PausePhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void ReclaimPhase() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FinishPhase() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   virtual void MarkReachableObjects()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 3b9e853..65bbbd2 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -106,7 +106,37 @@
       bytes_promoted_since_last_whole_heap_collection_(0),
       whole_heap_collection_(true),
       whole_heap_collection_interval_counter_(0),
-      collector_name_(name_) {
+      collector_name_(name_),
+      swap_semi_spaces_(true) {
+}
+
+void SemiSpace::RunPhases() {
+  Thread* self = Thread::Current();
+  InitializePhase();
+  // Semi-space collector is special since it is sometimes called with the mutators suspended
+  // during the zygote creation and collector transitions. If we already exclusively hold the
+  // mutator lock, then we can't lock it again since it will cause a deadlock.
+  if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
+    GetHeap()->PreGcVerificationPaused(this);
+    GetHeap()->PrePauseRosAllocVerification(this);
+    MarkingPhase();
+    ReclaimPhase();
+    GetHeap()->PostGcVerificationPaused(this);
+  } else {
+    Locks::mutator_lock_->AssertNotHeld(self);
+    {
+      ScopedPause pause(this);
+      GetHeap()->PreGcVerificationPaused(this);
+      GetHeap()->PrePauseRosAllocVerification(this);
+      MarkingPhase();
+    }
+    {
+      ReaderMutexLock mu(self, *Locks::mutator_lock_);
+      ReclaimPhase();
+    }
+    GetHeap()->PostGcVerification(this);
+  }
+  FinishPhase();
 }
 
 void SemiSpace::InitializePhase() {
@@ -119,9 +149,6 @@
   bytes_moved_ = 0;
   objects_moved_ = 0;
   self_ = Thread::Current();
-  // Do any pre GC verification.
-  timings_.NewSplit("PreGcVerification");
-  heap_->PreGcVerification(this);
   CHECK(from_space_->CanMoveObjects()) << "Attempting to move from " << *from_space_;
   // Set the initial bitmap.
   to_space_live_bitmap_ = to_space_->GetLiveBitmap();
@@ -140,6 +167,7 @@
 }
 
 void SemiSpace::MarkingPhase() {
+  CHECK(Locks::mutator_lock_->IsExclusiveHeld(self_));
   if (kStoreStackTraces) {
     Locks::mutator_lock_->AssertExclusiveHeld(self_);
     // Store the stack traces into the runtime fault string in case we get a heap corruption
@@ -214,12 +242,51 @@
     heap_->RevokeAllThreadLocalAllocationStacks(self_);
   }
   heap_->SwapStacks(self_);
-  WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_);
-  MarkRoots();
-  // Mark roots of immune spaces.
-  UpdateAndMarkModUnion();
-  // Recursively mark remaining objects.
-  MarkReachableObjects();
+  {
+    WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_);
+    MarkRoots();
+    // Mark roots of immune spaces.
+    UpdateAndMarkModUnion();
+    // Recursively mark remaining objects.
+    MarkReachableObjects();
+  }
+  ProcessReferences(self_);
+  {
+    ReaderMutexLock mu(self_, *Locks::heap_bitmap_lock_);
+    SweepSystemWeaks();
+  }
+  timings_.NewSplit("RecordFree");
+  // Revoke buffers before measuring how many objects were moved since the TLABs need to be revoked
+  // before they are properly counted.
+  RevokeAllThreadLocalBuffers();
+  // Record freed memory.
+  uint64_t from_bytes = from_space_->GetBytesAllocated();
+  uint64_t to_bytes = bytes_moved_;
+  uint64_t from_objects = from_space_->GetObjectsAllocated();
+  uint64_t to_objects = objects_moved_;
+  CHECK_LE(to_objects, from_objects);
+  int64_t freed_bytes = from_bytes - to_bytes;
+  int64_t freed_objects = from_objects - to_objects;
+  freed_bytes_.FetchAndAdd(freed_bytes);
+  freed_objects_.FetchAndAdd(freed_objects);
+  // Note: Freed bytes can be negative if we copy form a compacted space to a free-list backed
+  // space.
+  heap_->RecordFree(freed_objects, freed_bytes);
+
+  // Clear and protect the from space.
+  from_space_->Clear();
+  VLOG(heap) << "Protecting space " << *from_space_;
+  if (kProtectFromSpace) {
+    from_space_->GetMemMap()->Protect(PROT_NONE);
+  } else {
+    from_space_->GetMemMap()->Protect(PROT_READ);
+  }
+  if (swap_semi_spaces_) {
+    heap_->SwapSemiSpaces();
+  }
+  timings_.StartSplit("PreSweepingGcVerification");
+  heap_->PreSweepingGcVerification(this);
+  timings_.EndSplit();
 }
 
 void SemiSpace::UpdateAndMarkModUnion() {
@@ -383,28 +450,6 @@
 
 void SemiSpace::ReclaimPhase() {
   TimingLogger::ScopedSplit split("ReclaimPhase", &timings_);
-  ProcessReferences(self_);
-  {
-    ReaderMutexLock mu(self_, *Locks::heap_bitmap_lock_);
-    SweepSystemWeaks();
-  }
-  // Record freed memory.
-  uint64_t from_bytes = from_space_->GetBytesAllocated();
-  uint64_t to_bytes = bytes_moved_;
-  uint64_t from_objects = from_space_->GetObjectsAllocated();
-  uint64_t to_objects = objects_moved_;
-  CHECK_LE(to_objects, from_objects);
-  int64_t freed_bytes = from_bytes - to_bytes;
-  int64_t freed_objects = from_objects - to_objects;
-  freed_bytes_.FetchAndAdd(freed_bytes);
-  freed_objects_.FetchAndAdd(freed_objects);
-  // Note: Freed bytes can be negative if we copy form a compacted space to a free-list backed
-  // space.
-  heap_->RecordFree(freed_objects, freed_bytes);
-
-  timings_.StartSplit("PreSweepingGcVerification");
-  heap_->PreSweepingGcVerification(this);
-  timings_.EndSplit();
   {
     WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_);
     // Reclaim unmarked objects.
@@ -419,16 +464,6 @@
     TimingLogger::ScopedSplit split("UnBindBitmaps", &timings_);
     GetHeap()->UnBindBitmaps();
   }
-  // TODO: Do this before doing verification since the from space may have objects which weren't
-  // moved and point to dead objects.
-  from_space_->Clear();
-  // Protect the from space.
-  VLOG(heap) << "Protecting space " << *from_space_;
-  if (kProtectFromSpace) {
-    from_space_->GetMemMap()->Protect(PROT_NONE);
-  } else {
-    from_space_->GetMemMap()->Protect(PROT_READ);
-  }
   if (saved_bytes_ > 0) {
     VLOG(heap) << "Avoided dirtying " << PrettySize(saved_bytes_);
   }
@@ -765,9 +800,6 @@
 
 void SemiSpace::FinishPhase() {
   TimingLogger::ScopedSplit split("FinishPhase", &timings_);
-  Heap* heap = GetHeap();
-  timings_.NewSplit("PostGcVerification");
-  heap->PostGcVerification(this);
   // Null the "to" and "from" spaces since compacting from one to the other isn't valid until
   // further action is done by the heap.
   to_space_ = nullptr;
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 51b0869..d468561 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -61,12 +61,13 @@
 
   ~SemiSpace() {}
 
-  virtual void InitializePhase() OVERRIDE;
-  virtual void MarkingPhase() OVERRIDE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
+  virtual void RunPhases() OVERRIDE NO_THREAD_SAFETY_ANALYSIS;
+  virtual void InitializePhase();
+  virtual void MarkingPhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
-  virtual void ReclaimPhase() OVERRIDE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
+  virtual void ReclaimPhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
-  virtual void FinishPhase() OVERRIDE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual void FinishPhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   void MarkReachableObjects()
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
   virtual GcType GetGcType() const OVERRIDE {
@@ -82,6 +83,12 @@
   // Set the space where we copy objects from.
   void SetFromSpace(space::ContinuousMemMapAllocSpace* from_space);
 
+  // Set whether or not we swap the semi spaces in the heap. This needs to be done with mutators
+  // suspended.
+  void SetSwapSemiSpaces(bool swap_semi_spaces) {
+    swap_semi_spaces_ = swap_semi_spaces;
+  }
+
   // Initializes internal structures.
   void Init();
 
@@ -253,6 +260,9 @@
   // collections.
   static constexpr int kDefaultWholeHeapCollectionInterval = 5;
 
+  // Whether or not we swap the semi spaces in the heap during the marking phase.
+  bool swap_semi_spaces_;
+
  private:
   friend class BitmapSetSlowPathVisitor;
   DISALLOW_COPY_AND_ASSIGN(SemiSpace);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index a9799b9..b57fc69 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -93,8 +93,9 @@
            CollectorType foreground_collector_type, CollectorType background_collector_type,
            size_t parallel_gc_threads, size_t conc_gc_threads, bool low_memory_mode,
            size_t long_pause_log_threshold, size_t long_gc_log_threshold,
-           bool ignore_max_footprint, bool use_tlab, bool verify_pre_gc_heap,
-           bool verify_post_gc_heap, bool verify_pre_gc_rosalloc,
+           bool ignore_max_footprint, bool use_tlab,
+           bool verify_pre_gc_heap, bool verify_pre_sweeping_heap, bool verify_post_gc_heap,
+           bool verify_pre_gc_rosalloc, bool verify_pre_sweeping_rosalloc,
            bool verify_post_gc_rosalloc)
     : non_moving_space_(nullptr),
       rosalloc_space_(nullptr),
@@ -136,9 +137,11 @@
       verify_missing_card_marks_(false),
       verify_system_weaks_(false),
       verify_pre_gc_heap_(verify_pre_gc_heap),
+      verify_pre_sweeping_heap_(verify_pre_sweeping_heap),
       verify_post_gc_heap_(verify_post_gc_heap),
       verify_mod_union_table_(false),
       verify_pre_gc_rosalloc_(verify_pre_gc_rosalloc),
+      verify_pre_sweeping_rosalloc_(verify_pre_sweeping_rosalloc),
       verify_post_gc_rosalloc_(verify_post_gc_rosalloc),
       allocation_rate_(0),
       /* For GC a lot mode, we limit the allocations stacks to be kGcAlotInterval allocations. This
@@ -1455,7 +1458,6 @@
     usleep(1000);
   }
   tl->SuspendAll();
-  PreGcRosAllocVerification(&semi_space_collector_->GetTimings());
   switch (collector_type) {
     case kCollectorTypeSS:
       // Fall-through.
@@ -1490,7 +1492,6 @@
     }
   }
   ChangeCollector(collector_type);
-  PostGcRosAllocVerification(&semi_space_collector_->GetTimings());
   tl->ResumeAll();
   // Can't call into java code with all threads suspended.
   EnqueueClearedReferences();
@@ -1805,6 +1806,8 @@
   CHECK(kMovingCollector);
   CHECK_NE(target_space, source_space) << "In-place compaction currently unsupported";
   if (target_space != source_space) {
+    // Don't swap spaces since this isn't a typical semi space collection.
+    semi_space_collector_->SetSwapSemiSpaces(false);
     semi_space_collector_->SetFromSpace(source_space);
     semi_space_collector_->SetToSpace(target_space);
     semi_space_collector_->Run(kGcCauseCollectorTransition, false);
@@ -1876,6 +1879,7 @@
       semi_space_collector_->SetFromSpace(bump_pointer_space_);
       semi_space_collector_->SetToSpace(temp_space_);
       collector = semi_space_collector_;
+      semi_space_collector_->SetSwapSemiSpaces(true);
     } else if (collector_type_ == kCollectorTypeCC) {
       gc_type = concurrent_copying_collector_->GetGcType();
       collector = concurrent_copying_collector_;
@@ -1895,14 +1899,7 @@
       << "Could not find garbage collector with collector_type="
       << static_cast<size_t>(collector_type_) << " and gc_type=" << gc_type;
   ATRACE_BEGIN(StringPrintf("%s %s GC", PrettyCause(gc_cause), collector->GetName()).c_str());
-  if (compacting_gc) {
-    runtime->GetThreadList()->SuspendAll();
-    collector->Run(gc_cause, clear_soft_references || runtime->IsZygote());
-    SwapSemiSpaces();
-    runtime->GetThreadList()->ResumeAll();
-  } else {
-    collector->Run(gc_cause, clear_soft_references || runtime->IsZygote());
-  }
+  collector->Run(gc_cause, clear_soft_references || runtime->IsZygote());
   total_objects_freed_ever_ += collector->GetFreedObjects();
   total_bytes_freed_ever_ += collector->GetFreedBytes();
   RequestHeapTrim();
@@ -1930,7 +1927,7 @@
     std::ostringstream pause_string;
     for (size_t i = 0; i < pause_times.size(); ++i) {
         pause_string << PrettyDuration((pause_times[i] / 1000) * 1000)
-                     << ((i != pause_times.size() - 1) ? ", " : "");
+                     << ((i != pause_times.size() - 1) ? "," : "");
     }
     LOG(INFO) << gc_cause << " " << collector->GetName()
               << " GC freed "  <<  collector->GetFreedObjects() << "("
@@ -2367,99 +2364,110 @@
 static void IdentityMarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>*, void*) {
 }
 
-void Heap::PreGcVerification(collector::GarbageCollector* gc) {
-  ThreadList* thread_list = Runtime::Current()->GetThreadList();
-  Thread* self = Thread::Current();
-
+void Heap::PreGcVerificationPaused(collector::GarbageCollector* gc) {
+  Thread* const self = Thread::Current();
+  TimingLogger* const timings = &gc->GetTimings();
   if (verify_pre_gc_heap_) {
-    thread_list->SuspendAll();
-    {
-      ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
-      if (!VerifyHeapReferences()) {
-        LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed";
-      }
+    TimingLogger::ScopedSplit split("PreGcVerifyHeapReferences", timings);
+    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    if (!VerifyHeapReferences()) {
+      LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed";
     }
-    thread_list->ResumeAll();
   }
-
   // Check that all objects which reference things in the live stack are on dirty cards.
   if (verify_missing_card_marks_) {
-    thread_list->SuspendAll();
-    {
-      ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
-      SwapStacks(self);
-      // Sort the live stack so that we can quickly binary search it later.
-      if (!VerifyMissingCardMarks()) {
-        LOG(FATAL) << "Pre " << gc->GetName() << " missing card mark verification failed";
-      }
-      SwapStacks(self);
+    TimingLogger::ScopedSplit split("PreGcVerifyMissingCardMarks", timings);
+    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    SwapStacks(self);
+    // Sort the live stack so that we can quickly binary search it later.
+    if (!VerifyMissingCardMarks()) {
+      LOG(FATAL) << "Pre " << gc->GetName() << " missing card mark verification failed";
     }
-    thread_list->ResumeAll();
+    SwapStacks(self);
   }
-
   if (verify_mod_union_table_) {
-    thread_list->SuspendAll();
+    TimingLogger::ScopedSplit split("PreGcVerifyModUnionTables", timings);
     ReaderMutexLock reader_lock(self, *Locks::heap_bitmap_lock_);
     for (const auto& table_pair : mod_union_tables_) {
       accounting::ModUnionTable* mod_union_table = table_pair.second;
       mod_union_table->UpdateAndMarkReferences(IdentityMarkHeapReferenceCallback, nullptr);
       mod_union_table->Verify();
     }
-    thread_list->ResumeAll();
+  }
+}
+
+void Heap::PreGcVerification(collector::GarbageCollector* gc) {
+  if (verify_pre_gc_heap_ || verify_missing_card_marks_ || verify_mod_union_table_ ||
+      verify_pre_gc_rosalloc_) {
+    collector::GarbageCollector::ScopedPause pause(gc);
+    PreGcVerificationPaused(gc);
+  }
+}
+
+void Heap::PrePauseRosAllocVerification(collector::GarbageCollector* gc) {
+  // TODO: Add a new runtime option for this?
+  if (verify_pre_gc_rosalloc_) {
+    RosAllocVerification(&gc->GetTimings(), "PreGcRosAllocVerification");
   }
 }
 
 void Heap::PreSweepingGcVerification(collector::GarbageCollector* gc) {
+  Thread* const self = Thread::Current();
+  TimingLogger* const timings = &gc->GetTimings();
   // Called before sweeping occurs since we want to make sure we are not going so reclaim any
   // reachable objects.
-  if (verify_post_gc_heap_) {
-    Thread* self = Thread::Current();
+  if (verify_pre_sweeping_heap_) {
+    TimingLogger::ScopedSplit split("PostSweepingVerifyHeapReferences", timings);
     CHECK_NE(self->GetState(), kRunnable);
-    {
-      WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-      // Swapping bound bitmaps does nothing.
-      gc->SwapBitmaps();
-      SwapSemiSpaces();
-      if (!VerifyHeapReferences()) {
-        LOG(FATAL) << "Pre sweeping " << gc->GetName() << " GC verification failed";
-      }
-      SwapSemiSpaces();
-      gc->SwapBitmaps();
+    WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    // Swapping bound bitmaps does nothing.
+    gc->SwapBitmaps();
+    SwapSemiSpaces();
+    if (!VerifyHeapReferences()) {
+      LOG(FATAL) << "Pre sweeping " << gc->GetName() << " GC verification failed";
+    }
+    SwapSemiSpaces();
+    gc->SwapBitmaps();
+  }
+  if (verify_pre_sweeping_rosalloc_) {
+    RosAllocVerification(timings, "PreSweepingRosAllocVerification");
+  }
+}
+
+void Heap::PostGcVerificationPaused(collector::GarbageCollector* gc) {
+  // Only pause if we have to do some verification.
+  Thread* const self = Thread::Current();
+  TimingLogger* const timings = &gc->GetTimings();
+  if (verify_system_weaks_) {
+    ReaderMutexLock mu2(self, *Locks::heap_bitmap_lock_);
+    collector::MarkSweep* mark_sweep = down_cast<collector::MarkSweep*>(gc);
+    mark_sweep->VerifySystemWeaks();
+  }
+  if (verify_post_gc_rosalloc_) {
+    RosAllocVerification(timings, "PostGcRosAllocVerification");
+  }
+  if (verify_post_gc_heap_) {
+    TimingLogger::ScopedSplit split("PostGcVerifyHeapReferences", timings);
+    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    if (!VerifyHeapReferences()) {
+      LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed";
     }
   }
 }
 
 void Heap::PostGcVerification(collector::GarbageCollector* gc) {
-  if (verify_system_weaks_) {
-    Thread* self = Thread::Current();
-    ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
-    collector::MarkSweep* mark_sweep = down_cast<collector::MarkSweep*>(gc);
-    mark_sweep->VerifySystemWeaks();
+  if (verify_system_weaks_ || verify_post_gc_rosalloc_ || verify_post_gc_heap_) {
+    collector::GarbageCollector::ScopedPause pause(gc);
+    PreGcVerificationPaused(gc);
   }
 }
 
-void Heap::PreGcRosAllocVerification(TimingLogger* timings) {
-  if (verify_pre_gc_rosalloc_) {
-    TimingLogger::ScopedSplit split("PreGcRosAllocVerification", timings);
-    for (const auto& space : continuous_spaces_) {
-      if (space->IsRosAllocSpace()) {
-        VLOG(heap) << "PreGcRosAllocVerification : " << space->GetName();
-        space::RosAllocSpace* rosalloc_space = space->AsRosAllocSpace();
-        rosalloc_space->Verify();
-      }
-    }
-  }
-}
-
-void Heap::PostGcRosAllocVerification(TimingLogger* timings) {
-  if (verify_post_gc_rosalloc_) {
-    TimingLogger::ScopedSplit split("PostGcRosAllocVerification", timings);
-    for (const auto& space : continuous_spaces_) {
-      if (space->IsRosAllocSpace()) {
-        VLOG(heap) << "PostGcRosAllocVerification : " << space->GetName();
-        space::RosAllocSpace* rosalloc_space = space->AsRosAllocSpace();
-        rosalloc_space->Verify();
-      }
+void Heap::RosAllocVerification(TimingLogger* timings, const char* name) {
+  TimingLogger::ScopedSplit split(name, timings);
+  for (const auto& space : continuous_spaces_) {
+    if (space->IsRosAllocSpace()) {
+      VLOG(heap) << name << " : " << space->GetName();
+      space->AsRosAllocSpace()->Verify();
     }
   }
 }
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index c37bb05..631397b 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -152,8 +152,9 @@
                 CollectorType foreground_collector_type, CollectorType background_collector_type,
                 size_t parallel_gc_threads, size_t conc_gc_threads, bool low_memory_mode,
                 size_t long_pause_threshold, size_t long_gc_threshold,
-                bool ignore_max_footprint, bool use_tlab, bool verify_pre_gc_heap,
-                bool verify_post_gc_heap, bool verify_pre_gc_rosalloc,
+                bool ignore_max_footprint, bool use_tlab,
+                bool verify_pre_gc_heap, bool verify_pre_sweeping_heap, bool verify_post_gc_heap,
+                bool verify_pre_gc_rosalloc, bool verify_pre_sweeping_rosalloc,
                 bool verify_post_gc_rosalloc);
 
   ~Heap();
@@ -449,10 +450,7 @@
   void RevokeRosAllocThreadLocalBuffers(Thread* thread);
   void RevokeAllThreadLocalBuffers();
   void AssertAllBumpPointerSpaceThreadLocalBuffersAreRevoked();
-
-  void PreGcRosAllocVerification(TimingLogger* timings)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void PostGcRosAllocVerification(TimingLogger* timings)
+  void RosAllocVerification(TimingLogger* timings, const char* name)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   accounting::HeapBitmap* GetLiveBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
@@ -666,11 +664,18 @@
                      Locks::heap_bitmap_lock_,
                      Locks::thread_suspend_count_lock_);
 
-  void PreGcVerification(collector::GarbageCollector* gc);
+  void PreGcVerification(collector::GarbageCollector* gc)
+      LOCKS_EXCLUDED(Locks::mutator_lock_);
+  void PreGcVerificationPaused(collector::GarbageCollector* gc)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void PrePauseRosAllocVerification(collector::GarbageCollector* gc)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   void PreSweepingGcVerification(collector::GarbageCollector* gc)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   void PostGcVerification(collector::GarbageCollector* gc)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+      LOCKS_EXCLUDED(Locks::mutator_lock_);
+  void PostGcVerificationPaused(collector::GarbageCollector* gc)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Update the watermark for the native allocated bytes based on the current number of native
   // bytes allocated and the target utilization ratio.
@@ -857,28 +862,35 @@
   const bool verify_missing_card_marks_;
   const bool verify_system_weaks_;
   const bool verify_pre_gc_heap_;
+  const bool verify_pre_sweeping_heap_;
   const bool verify_post_gc_heap_;
   const bool verify_mod_union_table_;
   bool verify_pre_gc_rosalloc_;
+  bool verify_pre_sweeping_rosalloc_;
   bool verify_post_gc_rosalloc_;
 
   // RAII that temporarily disables the rosalloc verification during
   // the zygote fork.
   class ScopedDisableRosAllocVerification {
    private:
-    Heap* heap_;
-    bool orig_verify_pre_gc_;
-    bool orig_verify_post_gc_;
+    Heap* const heap_;
+    const bool orig_verify_pre_gc_;
+    const bool orig_verify_pre_sweeping_;
+    const bool orig_verify_post_gc_;
+
    public:
     explicit ScopedDisableRosAllocVerification(Heap* heap)
         : heap_(heap),
           orig_verify_pre_gc_(heap_->verify_pre_gc_rosalloc_),
+          orig_verify_pre_sweeping_(heap_->verify_pre_sweeping_rosalloc_),
           orig_verify_post_gc_(heap_->verify_post_gc_rosalloc_) {
       heap_->verify_pre_gc_rosalloc_ = false;
+      heap_->verify_pre_sweeping_rosalloc_ = false;
       heap_->verify_post_gc_rosalloc_ = false;
     }
     ~ScopedDisableRosAllocVerification() {
       heap_->verify_pre_gc_rosalloc_ = orig_verify_pre_gc_;
+      heap_->verify_pre_sweeping_rosalloc_ = orig_verify_pre_sweeping_;
       heap_->verify_post_gc_rosalloc_ = orig_verify_post_gc_;
     }
   };
@@ -955,6 +967,7 @@
   const bool running_on_valgrind_;
   const bool use_tlab_;
 
+  friend class collector::GarbageCollector;
   friend class collector::MarkSweep;
   friend class collector::SemiSpace;
   friend class ReferenceQueue;
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index ce11b3d..dc2769e 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -94,9 +94,8 @@
   mark_bitmap_->CopyFrom(live_bitmap_.get());
 }
 
-// TODO: Use something cleaner than 0xFFFFFFFF.
 LargeObjectMapSpace::LargeObjectMapSpace(const std::string& name)
-    : LargeObjectSpace(name, reinterpret_cast<byte*>(0xFFFFFFFF), nullptr),
+    : LargeObjectSpace(name, nullptr, nullptr),
       lock_("large object map space lock", kAllocSpaceLock) {}
 
 LargeObjectMapSpace* LargeObjectMapSpace::Create(const std::string& name) {
@@ -123,7 +122,10 @@
   size_t allocation_size = mem_map->Size();
   DCHECK(bytes_allocated != nullptr);
   begin_ = std::min(begin_, reinterpret_cast<byte*>(obj));
-  end_ = std::max(end_, reinterpret_cast<byte*>(obj) + allocation_size);
+  byte* obj_end = reinterpret_cast<byte*>(obj) + allocation_size;
+  if (end_ == nullptr || obj_end > end_) {
+    end_ = obj_end;
+  }
   *bytes_allocated = allocation_size;
   if (usable_size != nullptr) {
     *usable_size = allocation_size;
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 084e8f6..c0dc94b 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -114,6 +114,50 @@
   }
 }
 
+bool ParsedOptions::ParseXGcOption(const std::string& option) {
+  std::vector<std::string> gc_options;
+  Split(option.substr(strlen("-Xgc:")), ',', gc_options);
+  for (const std::string& gc_option : gc_options) {
+    gc::CollectorType collector_type = ParseCollectorType(gc_option);
+    if (collector_type != gc::kCollectorTypeNone) {
+      collector_type_ = collector_type;
+    } else if (gc_option == "preverify") {
+      verify_pre_gc_heap_ = true;
+    } else if (gc_option == "nopreverify") {
+      verify_pre_gc_heap_ = false;
+    }  else if (gc_option == "presweepingverify") {
+      verify_pre_sweeping_heap_ = true;
+    } else if (gc_option == "nopresweepingverify") {
+      verify_pre_sweeping_heap_ = false;
+    } else if (gc_option == "postverify") {
+      verify_post_gc_heap_ = true;
+    } else if (gc_option == "nopostverify") {
+      verify_post_gc_heap_ = false;
+    } else if (gc_option == "preverify_rosalloc") {
+      verify_pre_gc_rosalloc_ = true;
+    } else if (gc_option == "nopreverify_rosalloc") {
+      verify_pre_gc_rosalloc_ = false;
+    } else if (gc_option == "presweepingverify_rosalloc") {
+      verify_pre_sweeping_rosalloc_ = true;
+    } else if (gc_option == "nopresweepingverify_rosalloc") {
+      verify_pre_sweeping_rosalloc_ = false;
+    } else if (gc_option == "postverify_rosalloc") {
+      verify_post_gc_rosalloc_ = true;
+    } else if (gc_option == "nopostverify_rosalloc") {
+      verify_post_gc_rosalloc_ = false;
+    } else if ((gc_option == "precise") ||
+               (gc_option == "noprecise") ||
+               (gc_option == "verifycardtable") ||
+               (gc_option == "noverifycardtable")) {
+      // Ignored for backwards compatibility.
+    } else {
+      Usage("Unknown -Xgc option %s\n", gc_option.c_str());
+      return false;
+    }
+  }
+  return true;
+}
+
 bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecognized) {
   const char* boot_class_path_string = getenv("BOOTCLASSPATH");
   if (boot_class_path_string != NULL) {
@@ -147,8 +191,11 @@
   low_memory_mode_ = false;
   use_tlab_ = false;
   verify_pre_gc_heap_ = false;
-  verify_post_gc_heap_ = kIsDebugBuild;
+  // Pre sweeping is the one that usually fails if the GC corrupted the heap.
+  verify_pre_sweeping_heap_ = kIsDebugBuild;
+  verify_post_gc_heap_ = false;
   verify_pre_gc_rosalloc_ = kIsDebugBuild;
+  verify_pre_sweeping_rosalloc_ = false;
   verify_post_gc_rosalloc_ = false;
 
   compiler_callbacks_ = nullptr;
@@ -370,37 +417,8 @@
     } else if (option == "-Xint") {
       interpreter_only_ = true;
     } else if (StartsWith(option, "-Xgc:")) {
-      std::vector<std::string> gc_options;
-      Split(option.substr(strlen("-Xgc:")), ',', gc_options);
-      for (const std::string& gc_option : gc_options) {
-        gc::CollectorType collector_type = ParseCollectorType(gc_option);
-        if (collector_type != gc::kCollectorTypeNone) {
-          collector_type_ = collector_type;
-        } else if (gc_option == "preverify") {
-          verify_pre_gc_heap_ = true;
-        } else if (gc_option == "nopreverify") {
-          verify_pre_gc_heap_ = false;
-        }  else if (gc_option == "postverify") {
-          verify_post_gc_heap_ = true;
-        } else if (gc_option == "nopostverify") {
-          verify_post_gc_heap_ = false;
-        } else if (gc_option == "preverify_rosalloc") {
-          verify_pre_gc_rosalloc_ = true;
-        } else if (gc_option == "nopreverify_rosalloc") {
-          verify_pre_gc_rosalloc_ = false;
-        } else if (gc_option == "postverify_rosalloc") {
-          verify_post_gc_rosalloc_ = true;
-        } else if (gc_option == "nopostverify_rosalloc") {
-          verify_post_gc_rosalloc_ = false;
-        } else if ((gc_option == "precise") ||
-                   (gc_option == "noprecise") ||
-                   (gc_option == "verifycardtable") ||
-                   (gc_option == "noverifycardtable")) {
-          // Ignored for backwards compatibility.
-        } else {
-          Usage("Unknown -Xgc option %s\n", gc_option.c_str());
-          return false;
-        }
+      if (!ParseXGcOption(option)) {
+        return false;
       }
     } else if (StartsWith(option, "-XX:BackgroundGC=")) {
       std::string substring;
@@ -727,7 +745,9 @@
 
   UsageMessage(stream, "The following unique to ART options are supported:\n");
   UsageMessage(stream, "  -Xgc:[no]preverify_rosalloc\n");
+  UsageMessage(stream, "  -Xgc:[no]postsweepingverify_rosalloc\n");
   UsageMessage(stream, "  -Xgc:[no]postverify_rosalloc\n");
+  UsageMessage(stream, "  -Xgc:[no]presweepingverify\n");
   UsageMessage(stream, "  -Ximage:filename\n");
   UsageMessage(stream, "  -XX:ParallelGCThreads=integervalue\n");
   UsageMessage(stream, "  -XX:ConcGCThreads=integervalue\n");
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 770e4ae..c02eb1d 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -41,8 +41,10 @@
   bool is_explicit_gc_disabled_;
   bool use_tlab_;
   bool verify_pre_gc_heap_;
+  bool verify_pre_sweeping_heap_;
   bool verify_post_gc_heap_;
   bool verify_pre_gc_rosalloc_;
+  bool verify_pre_sweeping_rosalloc_;
   bool verify_post_gc_rosalloc_;
   unsigned int long_pause_log_threshold_;
   unsigned int long_gc_log_threshold_;
@@ -100,6 +102,7 @@
   void Abort();
 
   bool Parse(const Runtime::Options& options,  bool ignore_unrecognized);
+  bool ParseXGcOption(const std::string& option);
   bool ParseStringAfterChar(const std::string& option, char after_char, std::string* parsed_value);
   bool ParseInteger(const std::string& option, char after_char, int* parsed_value);
   bool ParseUnsignedInteger(const std::string& option, char after_char, unsigned int* parsed_value);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 611ce0b..6bbfcee 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -577,8 +577,10 @@
                        options->ignore_max_footprint_,
                        options->use_tlab_,
                        options->verify_pre_gc_heap_,
+                       options->verify_pre_sweeping_heap_,
                        options->verify_post_gc_heap_,
                        options->verify_pre_gc_rosalloc_,
+                       options->verify_pre_sweeping_rosalloc_,
                        options->verify_post_gc_rosalloc_);
 
   dump_gc_performance_on_shutdown_ = options->dump_gc_performance_on_shutdown_;
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 6f93566..4eb580b 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -16,6 +16,9 @@
 
 #include "thread_list.h"
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+
+#include <cutils/trace.h>
 #include <dirent.h>
 #include <ScopedLocalRef.h>
 #include <ScopedUtfChars.h>
@@ -305,6 +308,8 @@
 
   VLOG(threads) << *self << " SuspendAll starting...";
 
+  ATRACE_BEGIN("Suspending mutator threads");
+
   Locks::mutator_lock_->AssertNotHeld(self);
   Locks::thread_list_lock_->AssertNotHeld(self);
   Locks::thread_suspend_count_lock_->AssertNotHeld(self);
@@ -341,6 +346,9 @@
     AssertThreadsAreSuspended(self, self);
   }
 
+  ATRACE_END();
+  ATRACE_BEGIN("Mutator threads suspended");
+
   VLOG(threads) << *self << " SuspendAll complete";
 }
 
@@ -349,6 +357,9 @@
 
   VLOG(threads) << *self << " ResumeAll starting";
 
+  ATRACE_END();
+  ATRACE_BEGIN("Resuming mutator threads");
+
   if (kDebugLocking) {
     // Debug check that all threads are suspended.
     AssertThreadsAreSuspended(self, self);
@@ -373,6 +384,7 @@
     VLOG(threads) << *self << " ResumeAll waking others";
     Thread::resume_cond_->Broadcast(self);
   }
+  ATRACE_END();
   VLOG(threads) << *self << " ResumeAll complete";
 }