Revert "Record post startup methods in profile"

Breaks target tests.

This reverts commit 5594f11fa8a8a1efc24d1b258592f68cf462eec8.

Change-Id: I5ff4aab14bb241e287f042a9a90458e61306985e
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 00ae758..de1fefd 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -671,10 +671,6 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_);
 
-  // Visit all of the class loaders in the class linker.
-  void VisitClassLoaders(ClassLoaderVisitor* visitor) const
-      REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
-
   struct DexCacheData {
     // Construct an invalid data object.
     DexCacheData()
@@ -724,6 +720,9 @@
   static void DeleteClassLoader(Thread* self, const ClassLoaderData& data)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  void VisitClassLoaders(ClassLoaderVisitor* visitor) const
+      REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
+
   void VisitClassesInternal(ClassVisitor* visitor)
       REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
 
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 556fe66..10dddae 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -29,7 +29,6 @@
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/time_utils.h"
-#include "class_table-inl.h"
 #include "compiler_filter.h"
 #include "dex_reference_collection.h"
 #include "gc/collector_type.h"
@@ -122,7 +121,7 @@
     }
     total_ms_of_sleep_ += options_.GetSaveResolvedClassesDelayMs();
   }
-  FetchAndCacheResolvedClassesAndMethods(/*startup*/ true);
+  FetchAndCacheResolvedClassesAndMethods();
 
   // Loop for the profiled methods.
   while (!ShuttingDown(self)) {
@@ -211,6 +210,64 @@
   }
 }
 
+using MethodReferenceCollection = DexReferenceCollection<uint16_t, ScopedArenaAllocatorAdapter>;
+using TypeReferenceCollection = DexReferenceCollection<dex::TypeIndex,
+                                                       ScopedArenaAllocatorAdapter>;
+
+// Get resolved methods that have a profile info or more than kStartupMethodSamples samples.
+// Excludes native methods and classes in the boot image.
+class GetClassesAndMethodsVisitor : public ClassVisitor {
+ public:
+  GetClassesAndMethodsVisitor(MethodReferenceCollection* hot_methods,
+                              MethodReferenceCollection* sampled_methods,
+                              TypeReferenceCollection* resolved_classes,
+                              uint32_t hot_method_sample_threshold,
+                              bool profile_boot_class_path)
+    : hot_methods_(hot_methods),
+      sampled_methods_(sampled_methods),
+      resolved_classes_(resolved_classes),
+      hot_method_sample_threshold_(hot_method_sample_threshold),
+      profile_boot_class_path_(profile_boot_class_path) {}
+
+  virtual bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (klass->IsProxyClass() ||
+        klass->IsArrayClass() ||
+        klass->IsPrimitive() ||
+        !klass->IsResolved() ||
+        klass->IsErroneousResolved() ||
+        (!profile_boot_class_path_ && klass->GetClassLoader() == nullptr)) {
+      return true;
+    }
+    CHECK(klass->GetDexCache() != nullptr) << klass->PrettyClass();
+    resolved_classes_->AddReference(&klass->GetDexFile(), klass->GetDexTypeIndex());
+    for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
+      if (!method.IsNative()) {
+        DCHECK(!method.IsProxyMethod());
+        const uint16_t counter = method.GetCounter();
+        // Mark startup methods as hot if they have more than hot_method_sample_threshold_ samples.
+        // This means they will get compiled by the compiler driver.
+        if (method.GetProfilingInfo(kRuntimePointerSize) != nullptr ||
+            (method.GetAccessFlags() & kAccPreviouslyWarm) != 0 ||
+            counter >= hot_method_sample_threshold_) {
+          hot_methods_->AddReference(method.GetDexFile(), method.GetDexMethodIndex());
+        } else if (counter != 0) {
+          sampled_methods_->AddReference(method.GetDexFile(), method.GetDexMethodIndex());
+        }
+      } else {
+        CHECK_EQ(method.GetCounter(), 0u);
+      }
+    }
+    return true;
+  }
+
+ private:
+  MethodReferenceCollection* const hot_methods_;
+  MethodReferenceCollection* const sampled_methods_;
+  TypeReferenceCollection* const resolved_classes_;
+  uint32_t hot_method_sample_threshold_;
+  const bool profile_boot_class_path_;
+};
+
 class ScopedDefaultPriority {
  public:
   explicit ScopedDefaultPriority(pthread_t thread) : thread_(thread) {
@@ -225,140 +282,7 @@
   const pthread_t thread_;
 };
 
-// GetClassLoadersVisitor takes a snapshot of the class loaders and stores them in the out
-// class_loaders argument. Not affected by class unloading since there are no suspend points in
-// the caller.
-class GetClassLoadersVisitor : public ClassLoaderVisitor {
- public:
-  explicit GetClassLoadersVisitor(VariableSizedHandleScope* hs,
-                                  std::vector<Handle<mirror::ClassLoader>>* class_loaders)
-      : hs_(hs),
-        class_loaders_(class_loaders) {}
-
-  void Visit(ObjPtr<mirror::ClassLoader> class_loader)
-      REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE {
-    class_loaders_->push_back(hs_->NewHandle(class_loader));
-  }
-
- private:
-  VariableSizedHandleScope* const hs_;
-  std::vector<Handle<mirror::ClassLoader>>* const class_loaders_;
-};
-
-// GetClassesVisitor takes a snapshot of the loaded classes that we may want to visit and stores
-// them in the out argument. Not affected by class unloading since there are no suspend points in
-// the caller.
-class GetClassesVisitor : public ClassVisitor {
- public:
-  explicit GetClassesVisitor(bool profile_boot_class_path,
-                             ScopedArenaVector<ObjPtr<mirror::Class>>* out)
-      : profile_boot_class_path_(profile_boot_class_path),
-        out_(out) {}
-
-  virtual bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (klass->IsProxyClass() ||
-        klass->IsArrayClass() ||
-        klass->IsPrimitive() ||
-        !klass->IsResolved() ||
-        klass->IsErroneousResolved() ||
-        (!profile_boot_class_path_ && klass->GetClassLoader() == nullptr)) {
-      return true;
-    }
-    out_->push_back(klass);
-    return true;
-  }
-
- private:
-  const bool profile_boot_class_path_;
-  ScopedArenaVector<ObjPtr<mirror::Class>>* const out_;
-};
-
-using MethodReferenceCollection = DexReferenceCollection<uint16_t, ScopedArenaAllocatorAdapter>;
-using TypeReferenceCollection = DexReferenceCollection<dex::TypeIndex,
-                                                       ScopedArenaAllocatorAdapter>;
-
-// Iterate over all of the loaded classes and visit each one. For each class, add it to the
-// resolved_classes out argument if startup is true.
-// Add methods to the hot_methods out argument if the number of samples is greater or equal to
-// hot_method_sample_threshold, add it to sampled_methods if it has at least one sample.
-static void SampleClassesAndExecutedMethods(pthread_t profiler_pthread,
-                                            bool profile_boot_class_path,
-                                            ScopedArenaAllocator* allocator,
-                                            uint32_t hot_method_sample_threshold,
-                                            bool startup,
-                                            TypeReferenceCollection* resolved_classes,
-                                            MethodReferenceCollection* hot_methods,
-                                            MethodReferenceCollection* sampled_methods) {
-  Thread* const self = Thread::Current();
-  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  // Restore profile saver thread priority during the GC critical section. This helps prevent
-  // priority inversions blocking the GC for long periods of time.
-  ScopedDefaultPriority sdp(profiler_pthread);
-  // Do ScopedGCCriticalSection before acquiring mutator lock to prevent the GC running and
-  // blocking threads during thread root flipping. Since the GC is a background thread, blocking it
-  // is not a problem.
-  ScopedObjectAccess soa(self);
-  gc::ScopedGCCriticalSection sgcs(self,
-                                   gc::kGcCauseProfileSaver,
-                                   gc::kCollectorTypeCriticalSection);
-  VariableSizedHandleScope hs(soa.Self());
-  std::vector<Handle<mirror::ClassLoader>> class_loaders;
-  if (profile_boot_class_path) {
-    // First add the boot class loader since visit classloaders doesn't visit it.
-    class_loaders.push_back(hs.NewHandle<mirror::ClassLoader>(nullptr));
-  }
-  GetClassLoadersVisitor class_loader_visitor(&hs, &class_loaders);
-  {
-    // Read the class loaders into a temporary array to prevent contention problems on the
-    // class_linker_classes_lock.
-    ScopedTrace trace2("Get class loaders");
-    ReaderMutexLock mu(soa.Self(), *Locks::classlinker_classes_lock_);
-    class_linker->VisitClassLoaders(&class_loader_visitor);
-  }
-  ScopedArenaVector<ObjPtr<mirror::Class>> classes(allocator->Adapter());
-  for (Handle<mirror::ClassLoader> class_loader : class_loaders) {
-    ClassTable* table = class_linker->ClassTableForClassLoader(class_loader.Get());
-    if (table == nullptr) {
-      // If the class loader has not loaded any classes, it may have a null table.
-      continue;
-    }
-    GetClassesVisitor get_classes_visitor(profile_boot_class_path, &classes);
-    {
-      // Collect the classes into a temporary array to prevent lock contention on the class
-      // table lock. We want to avoid blocking class loading in other threads as much as
-      // possible.
-      ScopedTrace trace3("Visiting class table");
-      table->Visit(get_classes_visitor);
-    }
-    for (ObjPtr<mirror::Class> klass : classes) {
-      if (startup) {
-        // We only record classes for the startup case. This may change in the future.
-        resolved_classes->AddReference(&klass->GetDexFile(), klass->GetDexTypeIndex());
-      }
-      // Visit all of the methods in the class to see which ones were executed.
-      for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
-        if (!method.IsNative()) {
-          DCHECK(!method.IsProxyMethod());
-          const uint16_t counter = method.GetCounter();
-          // Mark startup methods as hot if they have more than hot_method_sample_threshold
-          // samples. This means they will get compiled by the compiler driver.
-          if (method.GetProfilingInfo(kRuntimePointerSize) != nullptr ||
-              (method.GetAccessFlags() & kAccPreviouslyWarm) != 0 ||
-              counter >= hot_method_sample_threshold) {
-            hot_methods->AddReference(method.GetDexFile(), method.GetDexMethodIndex());
-          } else if (counter != 0) {
-            sampled_methods->AddReference(method.GetDexFile(), method.GetDexMethodIndex());
-          }
-        } else {
-          CHECK_EQ(method.GetCounter(), 0u);
-        }
-      }
-    }
-    classes.clear();
-  }
-}
-
-void ProfileSaver::FetchAndCacheResolvedClassesAndMethods(bool startup) {
+void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
   ScopedTrace trace(__PRETTY_FUNCTION__);
   const uint64_t start_time = NanoTime();
 
@@ -370,25 +294,34 @@
   ArenaStack stack(runtime->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   MethodReferenceCollection hot_methods(allocator.Adapter(), allocator.Adapter());
-  MethodReferenceCollection sampled_methods(allocator.Adapter(), allocator.Adapter());
+  MethodReferenceCollection startup_methods(allocator.Adapter(), allocator.Adapter());
   TypeReferenceCollection resolved_classes(allocator.Adapter(), allocator.Adapter());
   const bool is_low_ram = Runtime::Current()->GetHeap()->IsLowMemoryMode();
+  const size_t hot_threshold = options_.GetHotStartupMethodSamples(is_low_ram);
   pthread_t profiler_pthread;
   {
     MutexLock mu(self, *Locks::profiler_lock_);
     profiler_pthread = profiler_pthread_;
   }
-  const uint32_t hot_method_sample_threshold = startup ?
-      options_.GetHotStartupMethodSamples(is_low_ram) :
-      std::numeric_limits<uint32_t>::max();
-  SampleClassesAndExecutedMethods(profiler_pthread,
-                                  options_.GetProfileBootClassPath(),
-                                  &allocator,
-                                  hot_method_sample_threshold,
-                                  startup,
-                                  &resolved_classes,
-                                  &hot_methods,
-                                  &sampled_methods);
+  {
+    // Restore profile saver thread priority during the GC critical section. This helps prevent
+    // priority inversions blocking the GC for long periods of time.
+    ScopedDefaultPriority sdp(profiler_pthread);
+    ScopedObjectAccess soa(self);
+    gc::ScopedGCCriticalSection sgcs(self,
+                                     gc::kGcCauseProfileSaver,
+                                     gc::kCollectorTypeCriticalSection);
+    {
+      ScopedTrace trace2("Get hot methods");
+      GetClassesAndMethodsVisitor visitor(&hot_methods,
+                                          &startup_methods,
+                                          &resolved_classes,
+                                          hot_threshold,
+                                          options_.GetProfileBootClassPath());
+      runtime->GetClassLinker()->VisitClasses(&visitor);
+    }
+  }
+
   MutexLock mu(self, *Locks::profiler_lock_);
   uint64_t total_number_of_profile_entries_cached = 0;
   using Hotness = ProfileCompilationInfo::MethodHotness;
@@ -396,12 +329,9 @@
   for (const auto& it : tracked_dex_base_locations_) {
     std::set<DexCacheResolvedClasses> resolved_classes_for_location;
     const std::string& filename = it.first;
-    auto info_it = profile_cache_.find(filename);
-    if (info_it == profile_cache_.end()) {
-      info_it = profile_cache_.Put(
-          filename,
-          new ProfileCompilationInfo(Runtime::Current()->GetArenaPool()));
-    }
+    auto info_it = profile_cache_.Put(
+        filename,
+        new ProfileCompilationInfo(Runtime::Current()->GetArenaPool()));
     ProfileCompilationInfo* cached_info = info_it->second;
 
     const std::set<std::string>& locations = it.second;
@@ -409,20 +339,18 @@
       const DexFile* const dex_file = pair.first;
       if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
         const MethodReferenceCollection::IndexVector& indices = pair.second;
-        uint8_t flags = Hotness::kFlagHot;
-        flags |= startup ? Hotness::kFlagStartup : Hotness::kFlagPostStartup;
         cached_info->AddMethodsForDex(
-            static_cast<Hotness::Flag>(flags),
+            static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup),
             dex_file,
             indices.begin(),
             indices.end());
       }
     }
-    for (const auto& pair : sampled_methods.GetMap()) {
+    for (const auto& pair : startup_methods.GetMap()) {
       const DexFile* const dex_file = pair.first;
       if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
         const MethodReferenceCollection::IndexVector& indices = pair.second;
-        cached_info->AddMethodsForDex(startup ? Hotness::kFlagStartup : Hotness::kFlagPostStartup,
+        cached_info->AddMethodsForDex(Hotness::kFlagStartup,
                                       dex_file,
                                       indices.begin(),
                                       indices.end());
@@ -447,9 +375,8 @@
       max_number_of_profile_entries_cached_,
       total_number_of_profile_entries_cached);
   VLOG(profiler) << "Profile saver recorded " << hot_methods.NumReferences() << " hot methods and "
-                 << sampled_methods.NumReferences() << " sampled methods with threshold "
-                 << hot_method_sample_threshold << " in "
-                 << PrettyDuration(NanoTime() - start_time);
+                 << startup_methods.NumReferences() << " startup methods with threshold "
+                 << hot_threshold << " in " << PrettyDuration(NanoTime() - start_time);
 }
 
 bool ProfileSaver::ProcessProfilingInfo(bool force_save, /*out*/uint16_t* number_of_new_methods) {
@@ -470,10 +397,6 @@
     *number_of_new_methods = 0;
   }
 
-  // We only need to do this once, not once per dex location.
-  // TODO: Figure out a way to only do it when stuff has changed? It takes 30-50ms.
-  FetchAndCacheResolvedClassesAndMethods(/*startup*/ false);
-
   for (const auto& it : tracked_locations) {
     if (!force_save && ShuttingDown(Thread::Current())) {
       // The ProfileSaver is in shutdown mode, meaning a stop request was made and
@@ -519,7 +442,6 @@
         total_number_of_skipped_writes_++;
         continue;
       }
-
       if (number_of_new_methods != nullptr) {
         *number_of_new_methods =
             std::max(static_cast<uint16_t>(delta_number_of_methods),
@@ -551,12 +473,11 @@
         total_number_of_failed_writes_++;
       }
     }
+    // Trim the maps to madvise the pages used for profile info.
+    // It is unlikely we will need them again in the near feature.
+    Runtime::Current()->GetArenaPool()->TrimMaps();
   }
 
-  // Trim the maps to madvise the pages used for profile info.
-  // It is unlikely we will need them again in the near feature.
-  Runtime::Current()->GetArenaPool()->TrimMaps();
-
   return profile_file_saved;
 }
 
@@ -792,15 +713,16 @@
   }
 }
 
-bool ProfileSaver::HasSeenMethod(const std::string& profile, bool hot, MethodReference ref) {
+bool ProfileSaver::HasSeenMethod(const std::string& profile,
+                                 const DexFile* dex_file,
+                                 uint16_t method_idx) {
   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
   if (instance_ != nullptr) {
     ProfileCompilationInfo info(Runtime::Current()->GetArenaPool());
     if (!info.Load(profile, /*clear_if_invalid*/false)) {
       return false;
     }
-    ProfileCompilationInfo::MethodHotness hotness = info.GetMethodHotness(ref);
-    return hot ? hotness.IsHot() : hotness.IsInProfile();
+    return info.GetMethodHotness(MethodReference(dex_file, method_idx)).IsInProfile();
   }
   return false;
 }
diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h
index ce8233b..01d72fe 100644
--- a/runtime/jit/profile_saver.h
+++ b/runtime/jit/profile_saver.h
@@ -19,7 +19,6 @@
 
 #include "base/mutex.h"
 #include "jit_code_cache.h"
-#include "method_reference.h"
 #include "profile_compilation_info.h"
 #include "profile_saver_options.h"
 #include "safe_map.h"
@@ -56,8 +55,10 @@
   // For testing or manual purposes (SIGUSR1).
   static void ForceProcessProfiles();
 
-  // Just for testing purposes.
-  static bool HasSeenMethod(const std::string& profile, bool hot, MethodReference ref);
+  // Just for testing purpose.
+  static bool HasSeenMethod(const std::string& profile,
+                            const DexFile* dex_file,
+                            uint16_t method_idx);
 
  private:
   ProfileSaver(const ProfileSaverOptions& options,
@@ -96,7 +97,7 @@
 
   // Fetches the current resolved classes and methods from the ClassLinker and stores them in the
   // profile_cache_ for later save.
-  void FetchAndCacheResolvedClassesAndMethods(bool startup);
+  void FetchAndCacheResolvedClassesAndMethods();
 
   void DumpInfo(std::ostream& os);
 
diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc
index b2b7ef2..0bdbade 100644
--- a/test/595-profile-saving/profile-saving.cc
+++ b/test/595-profile-saving/profile-saving.cc
@@ -45,9 +45,8 @@
   ProfileSaver::ForceProcessProfiles();
 }
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_profileHasMethod(JNIEnv* env,
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_presentInProfile(JNIEnv* env,
                                                                  jclass,
-                                                                 jboolean hot,
                                                                  jstring filename,
                                                                  jobject method) {
   ScopedUtfChars filename_chars(env, filename);
@@ -56,9 +55,8 @@
   ObjPtr<mirror::Executable> exec = soa.Decode<mirror::Executable>(method);
   ArtMethod* art_method = exec->GetArtMethod();
   return ProfileSaver::HasSeenMethod(std::string(filename_chars.c_str()),
-                                     hot != JNI_FALSE,
-                                     MethodReference(art_method->GetDexFile(),
-                                                     art_method->GetDexMethodIndex()));
+                                     art_method->GetDexFile(),
+                                     art_method->GetDexMethodIndex());
 }
 
 }  // namespace
diff --git a/test/595-profile-saving/src/Main.java b/test/595-profile-saving/src/Main.java
index 197c4e7..18c0598 100644
--- a/test/595-profile-saving/src/Main.java
+++ b/test/595-profile-saving/src/Main.java
@@ -42,14 +42,6 @@
         System.out.println("Class loader does not match boot class");
       }
       testAddMethodToProfile(file, bootMethod);
-
-      // Test a sampled method that is only warm and not hot.
-      Method reflectMethod = Main.class.getDeclaredMethod("testReflectionInvoke");
-      reflectMethod.invoke(null);
-      testSampledMethodInProfile(file, reflectMethod);
-      if (staticObj == null) {
-        throw new AssertionError("Object was not set");
-      }
     } finally {
       if (file != null) {
         file.delete();
@@ -57,38 +49,23 @@
     }
   }
 
-  static Object staticObj = null;
-
-  static void testReflectionInvoke() {
-    staticObj = new Object();
-  }
-
   static void testAddMethodToProfile(File file, Method m) {
     // Make sure we have a profile info for this method without the need to loop.
     ensureProfilingInfo(m);
-    // Make sure the profile gets processed.
+    // Make sure the profile gets saved.
     ensureProfileProcessing();
     // Verify that the profile was saved and contains the method.
-    if (!profileHasMethod(true, file.getPath(), m)) {
+    if (!presentInProfile(file.getPath(), m)) {
       throw new RuntimeException("Method with index " + m + " not in the profile");
     }
   }
 
-  static void testSampledMethodInProfile(File file, Method m) {
-    // Make sure the profile gets processed.
-    ensureProfileProcessing();
-    // Verify that the profile was saved and contains the method.
-    if (!profileHasMethod(false, file.getPath(), m)) {
-      throw new RuntimeException("Method with index " + m + " not sampled in the profile");
-    }
-  }
-
   // Ensure a method has a profiling info.
   public static native void ensureProfilingInfo(Method method);
   // Ensures the profile saver does its usual processing.
   public static native void ensureProfileProcessing();
-  // Checks if the profile saver has the method as a warm/sampled method.
-  public static native boolean profileHasMethod(boolean hot, String profile, Method method);
+  // Checks if the profiles saver knows about the method.
+  public static native boolean presentInProfile(String profile, Method method);
 
   private static final String TEMP_FILE_NAME_PREFIX = "dummy";
   private static final String TEMP_FILE_NAME_SUFFIX = "-file";