Add class table field to class loader

Fixes bug with the class table where the comparator would cause read
barriers and break the map strict ordering properties.

Bug: 22957957

Change-Id: I8dbc042db6e22e2172ab4ec58ddf1db0345dcaaa
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index a306c30..7821da3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1273,23 +1273,16 @@
     // Moving concurrent:
     // Need to make sure to not copy ArtMethods without doing read barriers since the roots are
     // marked concurrently and we don't hold the classlinker_classes_lock_ when we do the copy.
-    std::vector<std::pair<GcRoot<mirror::ClassLoader>, ClassTable*>> reinsert;
-    for (auto it = classes_.begin(); it != classes_.end(); ) {
-      it->second->VisitRoots(visitor, flags);
-      const GcRoot<mirror::ClassLoader>& root = it->first;
-      mirror::ClassLoader* old_ref = root.Read<kWithoutReadBarrier>();
-      root.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
-      mirror::ClassLoader* new_ref = root.Read<kWithoutReadBarrier>();
-      if (new_ref != old_ref) {
-        reinsert.push_back(*it);
-        it = classes_.erase(it);
-      } else {
-        ++it;
+    boot_class_table_.VisitRoots(visitor, flags);
+    for (GcRoot<mirror::ClassLoader>& root : class_loaders_) {
+      // May be null for boot ClassLoader.
+      root.VisitRoot(visitor, RootInfo(kRootVMInternal));
+      ClassTable* const class_table = root.Read()->GetClassTable();
+      if (class_table != nullptr) {
+        // May be null if we have no classes.
+        class_table->VisitRoots(visitor, flags);
       }
     }
-    for (auto& pair : reinsert) {
-      classes_.Put(pair.first, pair.second);
-    }
   } else if ((flags & kVisitRootFlagNewRoots) != 0) {
     for (auto& root : new_class_roots_) {
       mirror::Class* old_ref = root.Read<kWithoutReadBarrier>();
@@ -1346,10 +1339,12 @@
 }
 
 void ClassLinker::VisitClassesInternal(ClassVisitor* visitor) {
-  for (auto& pair : classes_) {
-    ClassTable* const class_table = pair.second;
-    if (!class_table->Visit(visitor)) {
-      return;
+  if (boot_class_table_.Visit(visitor)) {
+    for (GcRoot<mirror::ClassLoader>& root : class_loaders_) {
+      ClassTable* const class_table = root.Read()->GetClassTable();
+      if (class_table != nullptr && !class_table->Visit(visitor)) {
+        return;
+      }
     }
   }
 }
@@ -1469,7 +1464,10 @@
   mirror::LongArray::ResetArrayClass();
   mirror::ShortArray::ResetArrayClass();
   STLDeleteElements(&oat_files_);
-  STLDeleteValues(&classes_);
+  for (GcRoot<mirror::ClassLoader>& root : class_loaders_) {
+    ClassTable* const class_table = root.Read()->GetClassTable();
+    delete class_table;
+  }
 }
 
 mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length) {
@@ -2907,8 +2905,12 @@
 
 void ClassLinker::MoveClassTableToPreZygote() {
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  for (auto& class_table : classes_) {
-    class_table.second->FreezeSnapshot();
+  boot_class_table_.FreezeSnapshot();
+  for (GcRoot<mirror::ClassLoader>& root : class_loaders_) {
+    ClassTable* const class_table = root.Read()->GetClassTable();
+    if (class_table != nullptr) {
+      class_table->FreezeSnapshot();
+    }
   }
 }
 
@@ -2941,10 +2943,15 @@
     MoveImageClassesToClassTable();
   }
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  for (auto& pair : classes_) {
+  const size_t hash = ComputeModifiedUtf8Hash(descriptor);
+  mirror::Class* klass = boot_class_table_.Lookup(descriptor, hash);
+  if (klass != nullptr) {
+    result.push_back(klass);
+  }
+  for (GcRoot<mirror::ClassLoader>& root : class_loaders_) {
     // There can only be one class with the same descriptor per class loader.
-    ClassTable* const class_table  = pair.second;
-    mirror::Class* klass = class_table->Lookup(descriptor, ComputeModifiedUtf8Hash(descriptor));
+    ClassTable* const class_table = root.Read()->GetClassTable();
+    klass = class_table->Lookup(descriptor, hash);
     if (klass != nullptr) {
       result.push_back(klass);
     }
@@ -3998,22 +4005,21 @@
 }
 
 ClassTable* ClassLinker::InsertClassTableForClassLoader(mirror::ClassLoader* class_loader) {
-  auto it = classes_.find(GcRoot<mirror::ClassLoader>(class_loader));
-  if (it != classes_.end()) {
-    return it->second;
+  if (class_loader == nullptr) {
+    return &boot_class_table_;
   }
-  // Class table for loader not found, add it to the table.
-  auto* const class_table = new ClassTable;
-  classes_.Put(GcRoot<mirror::ClassLoader>(class_loader), class_table);
+  ClassTable* class_table = class_loader->GetClassTable();
+  if (class_table == nullptr) {
+    class_table = new ClassTable;
+    class_loaders_.push_back(class_loader);
+    // Don't already have a class table, add it to the class loader.
+    class_loader->SetClassTable(class_table);
+  }
   return class_table;
 }
 
 ClassTable* ClassLinker::ClassTableForClassLoader(mirror::ClassLoader* class_loader) {
-  auto it = classes_.find(GcRoot<mirror::ClassLoader>(class_loader));
-  if (it != classes_.end()) {
-    return it->second;
-  }
-  return nullptr;
+  return class_loader == nullptr ? &boot_class_table_ : class_loader->GetClassTable();
 }
 
 bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass,
@@ -5649,28 +5655,33 @@
 }
 
 void ClassLinker::DumpForSigQuit(std::ostream& os) {
-  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(Thread::Current());
   if (dex_cache_image_class_lookup_required_) {
-    ScopedObjectAccess soa(self);
     MoveImageClassesToClassTable();
   }
-  ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(soa.Self(), *Locks::classlinker_classes_lock_);
   os << "Zygote loaded classes=" << NumZygoteClasses() << " post zygote classes="
      << NumNonZygoteClasses() << "\n";
 }
 
 size_t ClassLinker::NumZygoteClasses() const {
-  size_t sum = 0;
-  for (auto& pair : classes_) {
-    sum += pair.second->NumZygoteClasses();
+  size_t sum = boot_class_table_.NumZygoteClasses();
+  for (const GcRoot<mirror::ClassLoader>& root : class_loaders_) {
+    ClassTable* const class_table = root.Read()->GetClassTable();
+    if (class_table != nullptr) {
+      sum += class_table->NumZygoteClasses();
+    }
   }
   return sum;
 }
 
 size_t ClassLinker::NumNonZygoteClasses() const {
-  size_t sum = 0;
-  for (auto& pair : classes_) {
-    sum += pair.second->NumNonZygoteClasses();
+  size_t sum = boot_class_table_.NumNonZygoteClasses();
+  for (const GcRoot<mirror::ClassLoader>& root : class_loaders_) {
+    ClassTable* const class_table = root.Read()->GetClassTable();
+    if (class_table != nullptr) {
+      sum += class_table->NumNonZygoteClasses();
+    }
   }
   return sum;
 }