Improve deterministic boot image compilation with CC collector.

Allow deterministic compilation with the read barrier configuration.

Test: Compare boot.art produced by different builds of the same tree.
Bug: 37442966
Change-Id: I6cc0d0d7fdfe4f954765764d9f7f3778b7307028
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index a9108e0e..5090c11 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -382,8 +382,6 @@
              "input dex file.");
   UsageError("");
   UsageError("  --force-determinism: force the compiler to emit a deterministic output.");
-  UsageError("      This option is incompatible with read barriers (e.g., if dex2oat has been");
-  UsageError("      built with the environment variable `ART_USE_READ_BARRIER` set to `true`).");
   UsageError("");
   UsageError("  --classpath-dir=<directory-path>: directory used to resolve relative class paths.");
   UsageError("");
@@ -915,9 +913,10 @@
     // Fill some values into the key-value store for the oat header.
     key_value_store_.reset(new SafeMap<std::string, std::string>());
 
-    // Automatically force determinism for the boot image in a host build if the default GC is CMS
-    // or MS and read barriers are not enabled, as the former switches the GC to a non-concurrent
-    // one by passing the option `-Xgc:nonconcurrent` (see below).
+    // Automatically force determinism for the boot image in a host build if read barriers
+    // are enabled, or if the default GC is CMS or MS. When the default GC is CMS
+    // (Concurrent Mark-Sweep), the GC is switched to a non-concurrent one by passing the
+    // option `-Xgc:nonconcurrent` (see below).
     if (!kIsTargetBuild && IsBootImage()) {
       if (SupportsDeterministicCompilation()) {
         force_determinism_ = true;
@@ -939,9 +938,9 @@
   }
 
   static bool SupportsDeterministicCompilation() {
-    return (gc::kCollectorTypeDefault == gc::kCollectorTypeCMS ||
-            gc::kCollectorTypeDefault == gc::kCollectorTypeMS) &&
-        !kEmitCompilerReadBarrier;
+    return (kUseReadBarrier ||
+            gc::kCollectorTypeDefault == gc::kCollectorTypeCMS ||
+            gc::kCollectorTypeDefault == gc::kCollectorTypeMS);
   }
 
   void ExpandOatAndImageFilenames() {
@@ -1233,7 +1232,7 @@
         no_inline_from_string_ = option.substr(strlen("--no-inline-from=")).data();
       } else if (option == "--force-determinism") {
         if (!SupportsDeterministicCompilation()) {
-          Usage("Cannot use --force-determinism with read barriers or non-CMS garbage collector");
+          Usage("Option --force-determinism requires read barriers or a CMS/MS garbage collector");
         }
         force_determinism_ = true;
       } else if (option.starts_with("--classpath-dir=")) {
@@ -2421,15 +2420,25 @@
     // foreground collector by default for dex2oat.
     raw_options.push_back(std::make_pair("-XX:DisableHSpaceCompactForOOM", nullptr));
 
-    // If we're asked to be deterministic, ensure non-concurrent GC for determinism. Also
-    // force the free-list implementation for large objects.
     if (compiler_options_->IsForceDeterminism()) {
+      // If we're asked to be deterministic, ensure non-concurrent GC for determinism.
+      //
+      // Note that with read barriers, this option is ignored, because Runtime::Init
+      // overrides the foreground GC to be gc::kCollectorTypeCC when instantiating
+      // gc::Heap. This is fine, as concurrent GC requests are not honored in dex2oat,
+      // which uses an unstarted runtime.
       raw_options.push_back(std::make_pair("-Xgc:nonconcurrent", nullptr));
+
+      // Also force the free-list implementation for large objects.
       raw_options.push_back(std::make_pair("-XX:LargeObjectSpace=freelist", nullptr));
 
       // We also need to turn off the nonmoving space. For that, we need to disable HSpace
       // compaction (done above) and ensure that neither foreground nor background collectors
       // are concurrent.
+      //
+      // Likewise, this option is ignored with read barriers because Runtime::Init
+      // overrides the background GC to be gc::kCollectorTypeCCBackground, but that's
+      // fine too, for the same reason (see above).
       raw_options.push_back(std::make_pair("-XX:BackgroundGC=nonconcurrent", nullptr));
 
       // To make identity hashcode deterministic, set a known seed.