Merge "ART: Update stl_util.h"
diff --git a/runtime/dex_reference_collection.h b/runtime/dex_reference_collection.h
new file mode 100644
index 0000000..76355d6
--- /dev/null
+++ b/runtime/dex_reference_collection.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 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_RUNTIME_DEX_REFERENCE_COLLECTION_H_
+#define ART_RUNTIME_DEX_REFERENCE_COLLECTION_H_
+
+#include "base/macros.h"
+
+#include <vector>
+#include <map>
+
+namespace art {
+
+class DexFile;
+
+// Collection of dex references that is more memory efficient than a vector of <dex, index> pairs.
+// Also allows quick lookups of all of the references for a single dex.
+template <class IndexType, template<typename Type> class Allocator>
+class DexReferenceCollection {
+ public:
+  using VectorAllocator = Allocator<IndexType>;
+  using IndexVector = std::vector<IndexType, VectorAllocator>;
+  using MapAllocator = Allocator<std::pair<const DexFile*, IndexVector>>;
+  using DexFileMap = std::map<
+      const DexFile*,
+      IndexVector,
+      std::less<const DexFile*>,
+      Allocator<std::pair<const DexFile* const, IndexVector>>>;
+
+  DexReferenceCollection(const MapAllocator& map_allocator = MapAllocator(),
+                         const VectorAllocator& vector_allocator = VectorAllocator())
+      : map_(map_allocator),
+        vector_allocator_(vector_allocator) {}
+
+  void AddReference(const DexFile* dex, IndexType index) {
+    GetOrInsertVector(dex)->push_back(index);
+  }
+
+  DexFileMap& GetMap() {
+    return map_;
+  }
+
+  size_t NumReferences() const {
+    size_t ret = 0;
+    for (auto&& pair : map_) {
+      ret += pair.second.size();
+    }
+    return ret;
+  }
+
+ private:
+  DexFileMap map_;
+  // Optimize for adding to same vector in succession.
+  const DexFile* current_dex_file_ = nullptr;
+  IndexVector* current_vector_ = nullptr;
+  VectorAllocator vector_allocator_;
+
+  ALWAYS_INLINE IndexVector* GetOrInsertVector(const DexFile* dex) {
+    if (UNLIKELY(current_dex_file_ != dex)) {
+      // There is an assumption that constructing an empty vector wont do any allocations. If this
+      // incorrect, this might leak for the arena case.
+      current_vector_ = &map_.emplace(dex, IndexVector(vector_allocator_)).first->second;
+      current_dex_file_ = dex;
+    }
+    return current_vector_;
+  }
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEX_REFERENCE_COLLECTION_H_
diff --git a/runtime/jit/profile_compilation_info-inl.h b/runtime/jit/profile_compilation_info-inl.h
new file mode 100644
index 0000000..8a067a5
--- /dev/null
+++ b/runtime/jit/profile_compilation_info-inl.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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_RUNTIME_JIT_PROFILE_COMPILATION_INFO_INL_H_
+#define ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_INL_H_
+
+#include "profile_compilation_info.h"
+
+namespace art {
+
+template <class Iterator>
+inline bool ProfileCompilationInfo::AddSampledMethodsForDex(bool startup,
+                                                            const DexFile* dex_file,
+                                                            Iterator index_begin,
+                                                            Iterator index_end) {
+  DexFileData* data = GetOrAddDexFileData(dex_file);
+  if (data == nullptr) {
+    return false;
+  }
+  for (auto it = index_begin; it != index_end; ++it) {
+    DCHECK_LT(*it, data->num_method_ids);
+    data->AddSampledMethod(startup, *it);
+  }
+  return true;
+}
+
+template <class Iterator>
+inline bool ProfileCompilationInfo::AddHotMethodsForDex(const DexFile* dex_file,
+                                                        Iterator index_begin,
+                                                        Iterator index_end) {
+  DexFileData* data = GetOrAddDexFileData(dex_file);
+  if (data == nullptr) {
+    return false;
+  }
+  for (auto it = index_begin; it != index_end; ++it) {
+    DCHECK_LT(*it, data->num_method_ids);
+    data->FindOrAddMethod(*it);
+  }
+  return true;
+}
+
+template <class Iterator>
+inline bool ProfileCompilationInfo::AddClassesForDex(const DexFile* dex_file,
+                                                     Iterator index_begin,
+                                                     Iterator index_end) {
+  DexFileData* data = GetOrAddDexFileData(dex_file);
+  if (data == nullptr) {
+    return false;
+  }
+  data->class_set.insert(index_begin, index_end);
+  return true;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_JIT_PROFILE_COMPILATION_INFO_INL_H_
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index 3852a5b..ea27d3b 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -147,18 +147,6 @@
   return true;
 }
 
-bool ProfileCompilationInfo::AddSampledMethods(bool startup,
-                                               std::vector<MethodReference>& methods) {
-  for (const MethodReference& ref : methods) {
-    DexFileData* data = GetOrAddDexFileData(ref.dex_file);
-    if (data == nullptr) {
-      return false;
-    }
-    data->AddSampledMethod(startup, ref.dex_method_index);
-  }
-  return true;
-}
-
 bool ProfileCompilationInfo::AddMethodsAndClasses(
     const std::vector<ProfileMethodInfo>& methods,
     const std::set<DexCacheResolvedClasses>& resolved_classes) {
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index a9f2fb6..bd1b9d6 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -197,6 +197,10 @@
   bool AddMethodsAndClasses(const std::vector<ProfileMethodInfo>& methods,
                             const std::set<DexCacheResolvedClasses>& resolved_classes);
 
+  // Iterator is type for ids not class defs.
+  template <class Iterator>
+  bool AddClassesForDex(const DexFile* dex_file, Iterator index_begin, Iterator index_end);
+
   // Add a method index to the profile (without inline caches).
   bool AddMethodIndex(const std::string& dex_location,
                       uint32_t checksum,
@@ -207,13 +211,24 @@
   bool AddMethod(const ProfileMethodInfo& pmi);
 
   // Add methods that have samples but are are not necessarily hot. These are partitioned into two
-  // possibly interesecting sets startup and post startup.
-  bool AddSampledMethods(bool startup, std::vector<MethodReference>& methods);
+  // possibly intersecting sets startup and post startup.
   bool AddSampledMethod(bool startup,
                         const std::string& dex_location,
                         uint32_t checksum,
                         uint16_t method_idx,
                         uint32_t num_method_ids);
+  // Bulk add sampled methods for a single dex, fast since it only has one GetOrAddDexFileData call.
+  template <class Iterator>
+  bool AddSampledMethodsForDex(bool startup,
+                               const DexFile* dex_file,
+                               Iterator index_begin,
+                               Iterator index_end);
+
+  // Bulk add hot methods for a single dex, fast since it only has one GetOrAddDexFileData call.
+  template <class Iterator>
+  bool AddHotMethodsForDex(const DexFile* dex_file,
+                           Iterator index_begin,
+                           Iterator index_end);
 
   // Load profile information from the given file descriptor.
   // If the current profile is non-empty the load will fail.
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 2a191f2..68f33bd 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -25,13 +25,16 @@
 
 #include "art_method-inl.h"
 #include "base/enums.h"
+#include "base/scoped_arena_containers.h"
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/time_utils.h"
 #include "compiler_filter.h"
+#include "dex_reference_collection.h"
 #include "gc/collector_type.h"
 #include "gc/gc_cause.h"
 #include "gc/scoped_gc_critical_section.h"
+#include "jit/profile_compilation_info-inl.h"
 #include "oat_file_manager.h"
 #include "scoped_thread_state_change-inl.h"
 
@@ -180,33 +183,45 @@
   }
 }
 
+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 GetMethodsVisitor : public ClassVisitor {
+class GetClassesAndMethodsVisitor : public ClassVisitor {
  public:
-  GetMethodsVisitor(std::vector<MethodReference>* hot_methods,
-                    std::vector<MethodReference>* sampled_methods,
-                    uint32_t hot_method_sample_threshold)
+  GetClassesAndMethodsVisitor(MethodReferenceCollection* hot_methods,
+                              MethodReferenceCollection* sampled_methods,
+                              TypeReferenceCollection* resolved_classes,
+                              uint32_t hot_method_sample_threshold)
     : hot_methods_(hot_methods),
       sampled_methods_(sampled_methods),
+      resolved_classes_(resolved_classes),
       hot_method_sample_threshold_(hot_method_sample_threshold) {}
 
   virtual bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
+    if (klass->IsProxyClass() ||
+        klass->IsArrayClass() ||
+        !klass->IsResolved() ||
+        klass->IsErroneousResolved() ||
+        klass->GetClassLoader() == nullptr) {
       return true;
     }
+    DCHECK(klass->GetDexCache() != nullptr) << klass->PrettyClass();
+    resolved_classes_->AddReference(&klass->GetDexFile(), klass->GetDexTypeIndex());
     for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) {
-      if (!method.IsNative() && !method.IsProxyMethod()) {
+      if (!method.IsNative()) {
+        DCHECK(!method.IsProxyMethod());
         const uint16_t counter = method.GetCounter();
-        MethodReference ref(method.GetDexFile(), method.GetDexMethodIndex());
         // 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_->push_back(ref);
+          hot_methods_->AddReference(method.GetDexFile(), method.GetDexMethodIndex());
         } else if (counter != 0) {
-          sampled_methods_->push_back(ref);
+          sampled_methods_->AddReference(method.GetDexFile(), method.GetDexMethodIndex());
         }
       } else {
         CHECK_EQ(method.GetCounter(), 0u);
@@ -216,85 +231,95 @@
   }
 
  private:
-  std::vector<MethodReference>* const hot_methods_;
-  std::vector<MethodReference>* const sampled_methods_;
+  MethodReferenceCollection* const hot_methods_;
+  MethodReferenceCollection* const sampled_methods_;
+  TypeReferenceCollection* const resolved_classes_;
   uint32_t hot_method_sample_threshold_;
 };
 
 void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
   ScopedTrace trace(__PRETTY_FUNCTION__);
+  const uint64_t start_time = NanoTime();
 
   // Resolve any new registered locations.
   ResolveTrackedLocations();
 
   Thread* const self = Thread::Current();
-  std::vector<MethodReference> hot_methods;
-  std::vector<MethodReference> startup_methods;
-  std::set<DexCacheResolvedClasses> resolved_classes;
+  Runtime* const runtime = Runtime::Current();
+  ArenaStack stack(runtime->GetArenaPool());
+  ScopedArenaAllocator allocator(&stack);
+  MethodReferenceCollection hot_methods(allocator.Adapter(), allocator.Adapter());
+  MethodReferenceCollection startup_methods(allocator.Adapter(), allocator.Adapter());
+  TypeReferenceCollection resolved_classes(allocator.Adapter(), allocator.Adapter());
+  const size_t hot_threshold = options_.GetHotStartupMethodSamples();
   {
     ScopedObjectAccess soa(self);
     gc::ScopedGCCriticalSection sgcs(self,
                                      gc::kGcCauseProfileSaver,
                                      gc::kCollectorTypeCriticalSection);
-
-    ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-    resolved_classes = class_linker->GetResolvedClasses(/*ignore boot classes*/ true);
-
     {
       ScopedTrace trace2("Get hot methods");
-      GetMethodsVisitor visitor(&hot_methods,
-                                &startup_methods,
-                                options_.GetHotStartupMethodSamples());
-      class_linker->VisitClasses(&visitor);
-      VLOG(profiler) << "Profile saver recorded " << hot_methods.size() << " hot methods and "
-                     << startup_methods.size() << " startup methods with threshold "
-                     << options_.GetHotStartupMethodSamples();
+      GetClassesAndMethodsVisitor visitor(&hot_methods,
+                                          &startup_methods,
+                                          &resolved_classes,
+                                          hot_threshold);
+      runtime->GetClassLinker()->VisitClasses(&visitor);
     }
   }
+
   MutexLock mu(self, *Locks::profiler_lock_);
   uint64_t total_number_of_profile_entries_cached = 0;
 
   for (const auto& it : tracked_dex_base_locations_) {
     std::set<DexCacheResolvedClasses> resolved_classes_for_location;
     const std::string& filename = it.first;
-    const std::set<std::string>& locations = it.second;
-    std::vector<ProfileMethodInfo> profile_methods_for_location;
-    std::vector<MethodReference> startup_methods_for_locations;
-    for (const MethodReference& ref : hot_methods) {
-      if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) {
-        profile_methods_for_location.emplace_back(ref.dex_file, ref.dex_method_index);
-        // Hot methods are also startup methods since this function is only invoked during startup.
-        startup_methods_for_locations.push_back(ref);
-      }
-    }
-    for (const MethodReference& ref : startup_methods) {
-      if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) {
-        startup_methods_for_locations.push_back(ref);
-      }
-    }
-
-    for (const DexCacheResolvedClasses& classes : resolved_classes) {
-      if (locations.find(classes.GetBaseLocation()) != locations.end()) {
-        VLOG(profiler) << "Added " << classes.GetClasses().size() << " classes for location "
-                       << classes.GetBaseLocation() << " (" << classes.GetDexLocation() << ")";
-        resolved_classes_for_location.insert(classes);
-      } else {
-        VLOG(profiler) << "Location not found " << classes.GetBaseLocation()
-                       << " (" << classes.GetDexLocation() << ")";
-      }
-    }
     auto info_it = profile_cache_.Put(
         filename,
         new ProfileCompilationInfo(Runtime::Current()->GetArenaPool()));
-
     ProfileCompilationInfo* cached_info = info_it->second;
-    cached_info->AddMethodsAndClasses(profile_methods_for_location, resolved_classes_for_location);
-    cached_info->AddSampledMethods(/*startup*/ true, startup_methods_for_locations);
+
+    const std::set<std::string>& locations = it.second;
+    for (const auto& pair : hot_methods.GetMap()) {
+      const DexFile* const dex_file = pair.first;
+      if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+        cached_info->AddSampledMethodsForDex(/*startup*/ true,
+                                             dex_file,
+                                             pair.second.begin(),
+                                             pair.second.end());
+        // Adding hot methods is a bit slow, TODO: optimize.
+        cached_info->AddHotMethodsForDex(dex_file, pair.second.begin(), pair.second.end());
+      }
+    }
+    for (const auto& pair : startup_methods.GetMap()) {
+      const DexFile* const dex_file = pair.first;
+      if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+        cached_info->AddSampledMethodsForDex(/*startup*/ true,
+                                             dex_file,
+                                             pair.second.begin(),
+                                             pair.second.end());
+      }
+    }
+    for (const auto& pair : resolved_classes.GetMap()) {
+      const DexFile* const dex_file = pair.first;
+      if (locations.find(dex_file->GetBaseLocation()) != locations.end()) {
+        const TypeReferenceCollection::IndexVector& classes = pair.second;
+        VLOG(profiler) << "Added " << classes.size() << " classes for location "
+                       << dex_file->GetBaseLocation()
+                       << " (" << dex_file->GetLocation() << ")";
+        cached_info->AddClassesForDex(dex_file, classes.begin(), classes.end());
+      } else {
+        VLOG(profiler) << "Location not found " << dex_file->GetBaseLocation()
+                       << " (" << dex_file->GetLocation() << ")";
+      }
+    }
     total_number_of_profile_entries_cached += resolved_classes_for_location.size();
   }
   max_number_of_profile_entries_cached_ = std::max(
       max_number_of_profile_entries_cached_,
       total_number_of_profile_entries_cached);
+  VLOG(profiler) << "Profile saver recorded " << hot_methods.NumReferences() << " hot methods and "
+                 << 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) {