Enable / disable CMS runtime options.

Enable or disable CMS by doing -Xgc:noconcurrent or Xgc:concurrent. Defaults to enabled.

Change-Id: Ib18687ba6aa6534323531d761133ce410c69f426
diff --git a/src/heap.cc b/src/heap.cc
index 1303d7d..7261670 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -914,8 +914,11 @@
 }
 
 void Heap::RequestConcurrentGC() {
-  // Make sure that our Daemon threads are started
-  if (requesting_gc_ || !Runtime::Current()->IsFinishedStarting() || Runtime::Current()->IsShuttingDown()) {
+  // Make sure that we can do a concurrent GC.
+  if (requesting_gc_ ||
+      !Runtime::Current()->IsFinishedStarting() ||
+      Runtime::Current()->IsShuttingDown() ||
+      !Runtime::Current()->IsConcurrentGcEnabled()) {
     return;
   }
 
diff --git a/src/runtime.cc b/src/runtime.cc
index fdbd70a..d7bef1e 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -56,6 +56,7 @@
 Runtime::Runtime()
     : is_compiler_(false),
       is_zygote_(false),
+      is_concurrent_gc_enabled_(true),
       default_stack_size_(0),
       heap_(NULL),
       monitor_list_(NULL),
@@ -317,6 +318,7 @@
 
   parsed->is_compiler_ = false;
   parsed->is_zygote_ = false;
+  parsed->is_concurrent_gc_enabled_ = true;
 
   parsed->jni_globals_max_ = 0;
   parsed->lock_profiling_threshold_ = 0;
@@ -424,6 +426,18 @@
       parsed->is_compiler_ = true;
     } else if (option == "-Xzygote") {
       parsed->is_zygote_ = true;
+    } else if (StartsWith(option, "-Xgc:")) {
+      std::vector<std::string> gc_options;
+      Split(option.substr(strlen("-Xgc:")), ',', gc_options);
+      for (size_t i = 0; i < gc_options.size(); ++i) {
+        if (gc_options[i] == "noconcurrent") {
+          parsed->is_concurrent_gc_enabled_ = false;
+        } else if (gc_options[i] == "concurrent") {
+          parsed->is_concurrent_gc_enabled_ = true;
+        } else {
+          LOG(WARNING) << "Ignoring unknown -Xgc option: " << gc_options[i];
+        }
+      }
     } else if (StartsWith(option, "-verbose:")) {
       std::vector<std::string> verbose_options;
       Split(option.substr(strlen("-verbose:")), ',', verbose_options);
@@ -643,6 +657,7 @@
 
   is_compiler_ = options->is_compiler_;
   is_zygote_ = options->is_zygote_;
+  is_concurrent_gc_enabled_ = options->is_concurrent_gc_enabled_;
 
   vfprintf_ = options->hook_vfprintf_;
   exit_ = options->hook_exit_;
diff --git a/src/runtime.h b/src/runtime.h
index 9181f1f..698f0c5 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -70,6 +70,7 @@
     std::string jni_trace_;
     bool is_compiler_;
     bool is_zygote_;
+    bool is_concurrent_gc_enabled_;
     size_t heap_initial_size_;
     size_t heap_maximum_size_;
     size_t heap_growth_limit_;
@@ -101,6 +102,10 @@
     return is_zygote_;
   }
 
+  bool IsConcurrentGcEnabled() const {
+    return is_concurrent_gc_enabled_;
+  }
+
   const std::string& GetHostPrefix() const {
     DCHECK(!IsStarted());
     return host_prefix_;
@@ -329,6 +334,7 @@
 
   bool is_compiler_;
   bool is_zygote_;
+  bool is_concurrent_gc_enabled_;
 
   // The host prefix is used during cross compilation. It is removed
   // from the start of host paths such as: