// 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>();
}
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;
+ }
}
}
}
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) {
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();
+ }
}
}
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);
}
}
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_;
+ }
+ 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);
}
- // 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);
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,
}
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;
}
void DropFindArrayClassCache() SHARED_REQUIRES(Locks::mutator_lock_);
private:
- class CompareClassLoaderGcRoot {
- public:
- bool operator()(const GcRoot<mirror::ClassLoader>& a, const GcRoot<mirror::ClassLoader>& b)
- const SHARED_REQUIRES(Locks::mutator_lock_) {
- return a.Read() < b.Read();
- }
- };
-
- typedef SafeMap<GcRoot<mirror::ClassLoader>, ClassTable*, CompareClassLoaderGcRoot>
- ClassLoaderClassTable;
-
void VisitClassesInternal(ClassVisitor* visitor)
REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
// Returns the number of zygote and image classes.
- size_t NumZygoteClasses() const REQUIRES(Locks::classlinker_classes_lock_);
+ size_t NumZygoteClasses() const
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
// Returns the number of non zygote nor image classes.
- size_t NumNonZygoteClasses() const REQUIRES(Locks::classlinker_classes_lock_);
+ size_t NumNonZygoteClasses() const
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
OatFile& GetImageOatFile(gc::space::ImageSpace* space)
REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
std::vector<GcRoot<mirror::DexCache>> dex_caches_ GUARDED_BY(dex_lock_);
std::vector<const OatFile*> oat_files_ GUARDED_BY(dex_lock_);
- // This contains strong roots. To enable concurrent root scanning of the class table.
- ClassLoaderClassTable classes_ GUARDED_BY(Locks::classlinker_classes_lock_);
+ // This contains the class laoders which have class tables. It is populated by
+ // InsertClassTableForClassLoader.
+ std::vector<GcRoot<mirror::ClassLoader>> class_loaders_
+ GUARDED_BY(Locks::classlinker_classes_lock_);
+
+ // Boot class path table. Since the class loader for this is null.
+ ClassTable boot_class_table_ GUARDED_BY(Locks::classlinker_classes_lock_);
// New class roots, only used by CMS since the GC needs to mark these in the pause.
std::vector<GcRoot<mirror::Class>> new_class_roots_ GUARDED_BY(Locks::classlinker_classes_lock_);