1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "class_table.h" 18 19 #include "mirror/class-inl.h" 20 #include "oat_file.h" 21 22 namespace art { 23 24 ClassTable::ClassTable() : lock_("Class loader classes", kClassLoaderClassesLock) { 25 Runtime* const runtime = Runtime::Current(); 26 classes_.push_back(ClassSet(runtime->GetHashTableMinLoadFactor(), 27 runtime->GetHashTableMaxLoadFactor())); 28 } 29 30 void ClassTable::FreezeSnapshot() { 31 WriterMutexLock mu(Thread::Current(), lock_); 32 classes_.push_back(ClassSet()); 33 } 34 35 bool ClassTable::Contains(ObjPtr<mirror::Class> klass) { 36 ReaderMutexLock mu(Thread::Current(), lock_); 37 TableSlot slot(klass); 38 for (ClassSet& class_set : classes_) { 39 auto it = class_set.Find(slot); 40 if (it != class_set.end()) { 41 return it->Read() == klass; 42 } 43 } 44 return false; 45 } 46 47 mirror::Class* ClassTable::LookupByDescriptor(ObjPtr<mirror::Class> klass) { 48 ReaderMutexLock mu(Thread::Current(), lock_); 49 TableSlot slot(klass); 50 for (ClassSet& class_set : classes_) { 51 auto it = class_set.Find(slot); 52 if (it != class_set.end()) { 53 return it->Read(); 54 } 55 } 56 return nullptr; 57 } 58 59 // To take into account http://b/35845221 60 #pragma clang diagnostic push 61 #if __clang_major__ < 4 62 #pragma clang diagnostic ignored "-Wunreachable-code" 63 #endif 64 65 mirror::Class* ClassTable::UpdateClass(const char* descriptor, mirror::Class* klass, size_t hash) { 66 WriterMutexLock mu(Thread::Current(), lock_); 67 // Should only be updating latest table. 68 DescriptorHashPair pair(descriptor, hash); 69 auto existing_it = classes_.back().FindWithHash(pair, hash); 70 if (kIsDebugBuild && existing_it == classes_.back().end()) { 71 for (const ClassSet& class_set : classes_) { 72 if (class_set.FindWithHash(pair, hash) != class_set.end()) { 73 LOG(FATAL) << "Updating class found in frozen table " << descriptor; 74 } 75 } 76 LOG(FATAL) << "Updating class not found " << descriptor; 77 } 78 mirror::Class* const existing = existing_it->Read(); 79 CHECK_NE(existing, klass) << descriptor; 80 CHECK(!existing->IsResolved()) << descriptor; 81 CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor; 82 CHECK(!klass->IsTemp()) << descriptor; 83 VerifyObject(klass); 84 // Update the element in the hash set with the new class. This is safe to do since the descriptor 85 // doesn't change. 86 *existing_it = TableSlot(klass, hash); 87 return existing; 88 } 89 90 #pragma clang diagnostic pop 91 92 size_t ClassTable::CountDefiningLoaderClasses(ObjPtr<mirror::ClassLoader> defining_loader, 93 const ClassSet& set) const { 94 size_t count = 0; 95 for (const TableSlot& root : set) { 96 if (root.Read()->GetClassLoader() == defining_loader) { 97 ++count; 98 } 99 } 100 return count; 101 } 102 103 size_t ClassTable::NumZygoteClasses(ObjPtr<mirror::ClassLoader> defining_loader) const { 104 ReaderMutexLock mu(Thread::Current(), lock_); 105 size_t sum = 0; 106 for (size_t i = 0; i < classes_.size() - 1; ++i) { 107 sum += CountDefiningLoaderClasses(defining_loader, classes_[i]); 108 } 109 return sum; 110 } 111 112 size_t ClassTable::NumNonZygoteClasses(ObjPtr<mirror::ClassLoader> defining_loader) const { 113 ReaderMutexLock mu(Thread::Current(), lock_); 114 return CountDefiningLoaderClasses(defining_loader, classes_.back()); 115 } 116 117 size_t ClassTable::NumReferencedZygoteClasses() const { 118 ReaderMutexLock mu(Thread::Current(), lock_); 119 size_t sum = 0; 120 for (size_t i = 0; i < classes_.size() - 1; ++i) { 121 sum += classes_[i].Size(); 122 } 123 return sum; 124 } 125 126 size_t ClassTable::NumReferencedNonZygoteClasses() const { 127 ReaderMutexLock mu(Thread::Current(), lock_); 128 return classes_.back().Size(); 129 } 130 131 mirror::Class* ClassTable::Lookup(const char* descriptor, size_t hash) { 132 DescriptorHashPair pair(descriptor, hash); 133 ReaderMutexLock mu(Thread::Current(), lock_); 134 for (ClassSet& class_set : classes_) { 135 auto it = class_set.FindWithHash(pair, hash); 136 if (it != class_set.end()) { 137 return it->Read(); 138 } 139 } 140 return nullptr; 141 } 142 143 ObjPtr<mirror::Class> ClassTable::TryInsert(ObjPtr<mirror::Class> klass) { 144 TableSlot slot(klass); 145 WriterMutexLock mu(Thread::Current(), lock_); 146 for (ClassSet& class_set : classes_) { 147 auto it = class_set.Find(slot); 148 if (it != class_set.end()) { 149 return it->Read(); 150 } 151 } 152 classes_.back().Insert(slot); 153 return klass; 154 } 155 156 void ClassTable::Insert(ObjPtr<mirror::Class> klass) { 157 const uint32_t hash = TableSlot::HashDescriptor(klass); 158 WriterMutexLock mu(Thread::Current(), lock_); 159 classes_.back().InsertWithHash(TableSlot(klass, hash), hash); 160 } 161 162 void ClassTable::CopyWithoutLocks(const ClassTable& source_table) { 163 if (kIsDebugBuild) { 164 for (ClassSet& class_set : classes_) { 165 CHECK(class_set.Empty()); 166 } 167 } 168 for (const ClassSet& class_set : source_table.classes_) { 169 for (const TableSlot& slot : class_set) { 170 classes_.back().Insert(slot); 171 } 172 } 173 } 174 175 void ClassTable::InsertWithoutLocks(ObjPtr<mirror::Class> klass) { 176 const uint32_t hash = TableSlot::HashDescriptor(klass); 177 classes_.back().InsertWithHash(TableSlot(klass, hash), hash); 178 } 179 180 void ClassTable::InsertWithHash(ObjPtr<mirror::Class> klass, size_t hash) { 181 WriterMutexLock mu(Thread::Current(), lock_); 182 classes_.back().InsertWithHash(TableSlot(klass, hash), hash); 183 } 184 185 bool ClassTable::Remove(const char* descriptor) { 186 DescriptorHashPair pair(descriptor, ComputeModifiedUtf8Hash(descriptor)); 187 WriterMutexLock mu(Thread::Current(), lock_); 188 for (ClassSet& class_set : classes_) { 189 auto it = class_set.Find(pair); 190 if (it != class_set.end()) { 191 class_set.Erase(it); 192 return true; 193 } 194 } 195 return false; 196 } 197 198 uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const TableSlot& slot) 199 const { 200 std::string temp; 201 return ComputeModifiedUtf8Hash(slot.Read()->GetDescriptor(&temp)); 202 } 203 204 bool ClassTable::ClassDescriptorHashEquals::operator()(const TableSlot& a, 205 const TableSlot& b) const { 206 if (a.Hash() != b.Hash()) { 207 std::string temp; 208 DCHECK(!a.Read()->DescriptorEquals(b.Read()->GetDescriptor(&temp))); 209 return false; 210 } 211 std::string temp; 212 return a.Read()->DescriptorEquals(b.Read()->GetDescriptor(&temp)); 213 } 214 215 bool ClassTable::ClassDescriptorHashEquals::operator()(const TableSlot& a, 216 const DescriptorHashPair& b) const { 217 if (!a.MaskedHashEquals(b.second)) { 218 DCHECK(!a.Read()->DescriptorEquals(b.first)); 219 return false; 220 } 221 return a.Read()->DescriptorEquals(b.first); 222 } 223 224 uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const DescriptorHashPair& pair) const { 225 return ComputeModifiedUtf8Hash(pair.first); 226 } 227 228 bool ClassTable::InsertStrongRoot(ObjPtr<mirror::Object> obj) { 229 WriterMutexLock mu(Thread::Current(), lock_); 230 DCHECK(obj != nullptr); 231 for (GcRoot<mirror::Object>& root : strong_roots_) { 232 if (root.Read() == obj) { 233 return false; 234 } 235 } 236 strong_roots_.push_back(GcRoot<mirror::Object>(obj)); 237 // If `obj` is a dex cache associated with a new oat file with GC roots, add it to oat_files_. 238 if (obj->IsDexCache()) { 239 const DexFile* dex_file = ObjPtr<mirror::DexCache>::DownCast(obj)->GetDexFile(); 240 if (dex_file != nullptr && dex_file->GetOatDexFile() != nullptr) { 241 const OatFile* oat_file = dex_file->GetOatDexFile()->GetOatFile(); 242 if (oat_file != nullptr && !oat_file->GetBssGcRoots().empty()) { 243 InsertOatFileLocked(oat_file); // Ignore return value. 244 } 245 } 246 } 247 return true; 248 } 249 250 bool ClassTable::InsertOatFile(const OatFile* oat_file) { 251 WriterMutexLock mu(Thread::Current(), lock_); 252 return InsertOatFileLocked(oat_file); 253 } 254 255 bool ClassTable::InsertOatFileLocked(const OatFile* oat_file) { 256 if (ContainsElement(oat_files_, oat_file)) { 257 return false; 258 } 259 oat_files_.push_back(oat_file); 260 return true; 261 } 262 263 size_t ClassTable::WriteToMemory(uint8_t* ptr) const { 264 ReaderMutexLock mu(Thread::Current(), lock_); 265 ClassSet combined; 266 // Combine all the class sets in case there are multiple, also adjusts load factor back to 267 // default in case classes were pruned. 268 for (const ClassSet& class_set : classes_) { 269 for (const TableSlot& root : class_set) { 270 combined.Insert(root); 271 } 272 } 273 const size_t ret = combined.WriteToMemory(ptr); 274 // Sanity check. 275 if (kIsDebugBuild && ptr != nullptr) { 276 size_t read_count; 277 ClassSet class_set(ptr, /*make copy*/false, &read_count); 278 class_set.Verify(); 279 } 280 return ret; 281 } 282 283 size_t ClassTable::ReadFromMemory(uint8_t* ptr) { 284 size_t read_count = 0; 285 AddClassSet(ClassSet(ptr, /*make copy*/false, &read_count)); 286 return read_count; 287 } 288 289 void ClassTable::AddClassSet(ClassSet&& set) { 290 WriterMutexLock mu(Thread::Current(), lock_); 291 classes_.insert(classes_.begin(), std::move(set)); 292 } 293 294 void ClassTable::ClearStrongRoots() { 295 WriterMutexLock mu(Thread::Current(), lock_); 296 oat_files_.clear(); 297 strong_roots_.clear(); 298 } 299 300 ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass) 301 : TableSlot(klass, HashDescriptor(klass)) {} 302 303 uint32_t ClassTable::TableSlot::HashDescriptor(ObjPtr<mirror::Class> klass) { 304 std::string temp; 305 return ComputeModifiedUtf8Hash(klass->GetDescriptor(&temp)); 306 } 307 308 } // namespace art 309