Check point root marking.

Added thread list checkpoint function, this goes through every thread and runs
the checkpoint on each thread. Threads that are runnable run the checkpoint
callback themselves in the next suspend check, while suspended threads are
left suspended but have the callback called on them.

Added a checkpoint visitor member to each thread, this visitor called when the
checkpoint request flag is set during transitions to suspended from runnable.

Using the checkpoint to mark the roots reduces the first pause of partial /
full gc to around 1 ms.

Change-Id: I97239cc72ee0e4a3397e9138a62ee559268dce0a
diff --git a/src/gc/barrier.cc b/src/gc/barrier.cc
new file mode 100644
index 0000000..aa9433b
--- /dev/null
+++ b/src/gc/barrier.cc
@@ -0,0 +1,46 @@
+#include "barrier.h"
+#include "../mutex.h"
+#include "thread.h"
+
+namespace art {
+
+Barrier::Barrier()
+    : count_(0),
+      lock_("GC barrier lock"),
+      condition_("GC barrier condition", lock_) {
+}
+
+void Barrier::Pass(Thread* self) {
+  MutexLock mu(self, lock_);
+  SetCountLocked(self, count_ - 1);
+}
+
+void Barrier::Wait(Thread* self) {
+  Increment(self, -1);
+}
+
+void Barrier::Init(Thread* self, int count) {
+  MutexLock mu(self, lock_);
+  SetCountLocked(self, count);
+}
+
+void Barrier::Increment(Thread* self, int delta) {
+  MutexLock mu(self, lock_);
+  SetCountLocked(self, count_ + delta);
+  if (count_ != 0) {
+    condition_.Wait(self);
+  }
+}
+
+void Barrier::SetCountLocked(Thread* self, int count) {
+  count_ = count;
+  if (count_ == 0) {
+    condition_.Broadcast(self);
+  }
+}
+
+Barrier::~Barrier() {
+  CHECK(!count_) << "Attempted to destory barrier with non zero count";
+}
+
+}
diff --git a/src/gc/barrier.h b/src/gc/barrier.h
new file mode 100644
index 0000000..207536a
--- /dev/null
+++ b/src/gc/barrier.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_BARRIER_H_
+#define ART_SRC_GC_BARRIER_H_
+
+#include "../mutex.h"
+#include "locks.h"
+#include "UniquePtr.h"
+
+namespace art {
+
+class Barrier {
+ public:
+  Barrier();
+  virtual ~Barrier();
+
+  // Pass through the barrier, decrements the count but does not block.
+  void Pass(Thread* self);
+
+  // Wait on the barrier, decrement the count.
+  void Wait(Thread* self);
+
+  // Set the count to a new value, if the value is 0 then everyone waiting on the condition
+  // variable is resumed.
+  void Init(Thread* self, int count);
+
+  // Increment the count by delta, wait on condition if count is non zero.
+  void Increment(Thread* self, int delta);
+
+ private:
+  void SetCountLocked(Thread* self, int count) EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  // Counter, when this reaches 0 all people blocked on the barrier are signalled.
+  int count_ GUARDED_BY(lock_);
+
+  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  ConditionVariable condition_ GUARDED_BY(lock_);
+};
+
+}  // namespace art
+#endif  // ART_SRC_GC_BARRIER_H_
+
diff --git a/src/gc/card_table.h b/src/gc/card_table.h
index 2715f52..035c073 100644
--- a/src/gc/card_table.h
+++ b/src/gc/card_table.h
@@ -160,4 +160,4 @@
 };
 
 }  // namespace art
-#endif  // DALVIK_ALLOC_CARDTABLE_H_
+#endif  // ART_SRC_GC_CARDTABLE_H_
diff --git a/src/gc/mark_sweep.cc b/src/gc/mark_sweep.cc
index 980eed1..8637370 100644
--- a/src/gc/mark_sweep.cc
+++ b/src/gc/mark_sweep.cc
@@ -19,6 +19,7 @@
 #include <climits>
 #include <vector>
 
+#include "barrier.h"
 #include "card_table.h"
 #include "class_loader.h"
 #include "dex_cache.h"
@@ -37,10 +38,10 @@
 #include "thread.h"
 #include "thread_list.h"
 
-static const bool kUseMarkStackPrefetch = true;
-
 namespace art {
 
+static const bool kUseMarkStackPrefetch = true;
+
 class SetFingerVisitor {
  public:
   SetFingerVisitor(MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
@@ -68,7 +69,8 @@
       phantom_reference_list_(NULL),
       cleared_reference_list_(NULL),
       freed_bytes_(0), freed_objects_(0),
-      class_count_(0), array_count_(0), other_count_(0) {
+      class_count_(0), array_count_(0), other_count_(0),
+      gc_barrier_(new Barrier) {
   DCHECK(mark_stack_ != NULL);
 }
 
@@ -200,6 +202,10 @@
   Runtime::Current()->VisitNonConcurrentRoots(MarkObjectVisitor, this);
 }
 
+void MarkSweep::MarkNonThreadRoots() {
+  Runtime::Current()->VisitNonThreadRoots(MarkObjectVisitor, this);
+}
+
 void MarkSweep::MarkConcurrentRoots() {
   Runtime::Current()->VisitConcurrentRoots(MarkObjectVisitor, this);
 }
@@ -519,6 +525,38 @@
   Thread* self;
 };
 
+class CheckpointMarkThreadRoots : public Thread::CheckpointFunction {
+ public:
+  CheckpointMarkThreadRoots(MarkSweep* mark_sweep) : mark_sweep_(mark_sweep) {
+
+  }
+
+  virtual void Run(Thread* thread) NO_THREAD_SAFETY_ANALYSIS {
+    // Note: self is not necessarily equal to thread since thread may be suspended.
+    Thread* self = Thread::Current();
+    DCHECK(thread == self || thread->IsSuspended() || thread->GetState() == kWaitingPerformingGc);
+    WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    thread->VisitRoots(MarkSweep::MarkObjectVisitor, mark_sweep_);
+    mark_sweep_->GetBarrier().Pass(self);
+  }
+
+ private:
+  MarkSweep* mark_sweep_;
+};
+
+Barrier& MarkSweep::GetBarrier() {
+  return *gc_barrier_;
+}
+
+void MarkSweep::MarkRootsCheckpoint() {
+  UniquePtr<CheckpointMarkThreadRoots> check_point(new CheckpointMarkThreadRoots(this));
+  ThreadList* thread_list = Runtime::Current()->GetThreadList();
+  // Increment the count of the barrier. If all of the checkpoints have already been finished then
+  // will hit 0 and continue. Otherwise we are still waiting for some checkpoints, so the counter
+  // will go positive and we will unblock when it hits zero.
+  gc_barrier_->Increment(Thread::Current(), thread_list->RunCheckpoint(check_point.get()));
+}
+
 void MarkSweep::SweepCallback(size_t num_ptrs, Object** ptrs, void* arg) {
   size_t freed_objects = num_ptrs;
   size_t freed_bytes = 0;
@@ -538,8 +576,7 @@
     freed_bytes += space->FreeList(self, num_ptrs, ptrs);
   } else {
     for (size_t i = 0; i < num_ptrs; ++i) {
-      Object* obj = static_cast<Object*>(ptrs[i]);
-      freed_bytes += space->Free(self, obj);
+      freed_bytes += space->Free(self, ptrs[i]);
     }
   }
 
diff --git a/src/gc/mark_sweep.h b/src/gc/mark_sweep.h
index ed74f99..d64439f 100644
--- a/src/gc/mark_sweep.h
+++ b/src/gc/mark_sweep.h
@@ -25,6 +25,7 @@
 
 namespace art {
 
+class Barrier;
 class CheckObjectVisitor;
 class Class;
 class Heap;
@@ -52,9 +53,15 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void MarkNonThreadRoots()
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
   void MarkConcurrentRoots();
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
+  void MarkRootsCheckpoint();
+       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
   // Verify that image roots point to only marked objects within the alloc space.
   void VerifyImageRoots() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -183,6 +190,11 @@
     }
   }
 
+  static void MarkObjectVisitor(const Object* root, void* arg)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+  Barrier& GetBarrier();
+
  private:
   // Returns true if the object has its bit set in the mark bitmap.
   bool IsMarked(const Object* object) const;
@@ -193,9 +205,6 @@
   static bool IsMarkedArrayCallback(const Object* object, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  static void MarkObjectVisitor(const Object* root, void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
   static void ReMarkObjectVisitor(const Object* root, void* arg)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -417,6 +426,8 @@
   size_t array_count_;
   size_t other_count_;
 
+  UniquePtr<Barrier> gc_barrier_;
+
   friend class AddIfReachesAllocSpaceVisitor; // Used by mod-union table.
   friend class CheckBitmapVisitor;
   friend class CheckObjectVisitor;