Clear shared method bit when doing boot image profiling.

Otherwise, the profile saver thinks all methods in the boot image are
hot.

Test: 595-profile-saving
Bug: 223366272
Change-Id: Ieff95a6fe11cabfa9b3ccf1364b8dae080d08cf8
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 9b11c26..d8bd380 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -265,6 +265,15 @@
     }
   }
 
+  void ClearMemorySharedMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (IsIntrinsic() || IsAbstract()) {
+      return;
+    }
+    if (IsMemorySharedMethod()) {
+      ClearAccessFlags(kAccMemorySharedMethod);
+    }
+  }
+
   void ClearPreCompiled() REQUIRES_SHARED(Locks::mutator_lock_) {
     ClearAccessFlags(kAccPreCompiled | kAccCompileDontBother);
   }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 64adc55..c8dbc75 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1983,6 +1983,16 @@
   }
 
   if (!runtime->IsAotCompiler()) {
+    // If we are profiling the boot classpath, disable the shared memory for
+    // boot image method optimization. We need to disable it before doing
+    // ResetCounter below, as counters of shared memory method always hold the
+    // "hot" value.
+    if (runtime->GetJITOptions()->GetProfileSaverOptions().GetProfileBootClassPath()) {
+      header.VisitPackedArtMethods([&](ArtMethod& method) REQUIRES_SHARED(Locks::mutator_lock_) {
+        method.ClearMemorySharedMethod();
+      }, space->Begin(), image_pointer_size_);
+    }
+
     ScopedTrace trace("AppImage:UpdateCodeItemAndNterp");
     bool can_use_nterp = interpreter::CanRuntimeUseNterp();
     uint16_t hotness_threshold = runtime->GetJITOptions()->GetWarmupThreshold();
@@ -3762,7 +3772,8 @@
     }
   }
 
-  if (Runtime::Current()->IsZygote()) {
+  if (Runtime::Current()->IsZygote() &&
+      !Runtime::Current()->GetJITOptions()->GetProfileSaverOptions().GetProfileBootClassPath()) {
     dst->SetMemorySharedMethod();
   }
 }
diff --git a/test/595-profile-saving/src/Main.java b/test/595-profile-saving/src/Main.java
index e693006..5b1a448 100644
--- a/test/595-profile-saving/src/Main.java
+++ b/test/595-profile-saving/src/Main.java
@@ -46,6 +46,11 @@
       }
       testAddMethodToProfile(file, bootMethod);
 
+      // We never expect System.console to be executed before Main.main gets invoked, and therefore
+      // it should never be in a profile.
+      Method bootNotInProfileMethod = System.class.getDeclaredMethod("console");
+      testMethodNotInProfile(file, bootNotInProfileMethod);
+
       System.out.println("IsForBootImage: " + isForBootImage(file.getPath()));
     } finally {
       if (file != null) {
@@ -61,7 +66,16 @@
     ensureProfileProcessing();
     // Verify that the profile was saved and contains the method.
     if (!presentInProfile(file.getPath(), m)) {
-      throw new RuntimeException("Method with index " + m + " not in the profile");
+      throw new RuntimeException("Expected method " + m + " to be in the profile");
+    }
+  }
+
+  static void testMethodNotInProfile(File file, Method m) {
+    // Make sure the profile gets saved.
+    ensureProfileProcessing();
+    // Verify that the profile was saved and contains the method.
+    if (presentInProfile(file.getPath(), m)) {
+      throw new RuntimeException("Did not expect method " + m + " to be in the profile");
     }
   }