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 21 namespace art { 22 23 ClassTable::ClassTable() : lock_("Class loader classes", kClassLoaderClassesLock) { 24 Runtime* const runtime = Runtime::Current(); 25 classes_.push_back(ClassSet(runtime->GetHashTableMinLoadFactor(), 26 runtime->GetHashTableMaxLoadFactor())); 27 } 28 29 void ClassTable::FreezeSnapshot() { 30 WriterMutexLock mu(Thread::Current(), lock_); 31 classes_.push_back(ClassSet()); 32 } 33 34 bool ClassTable::Contains(mirror::Class* klass) { 35 ReaderMutexLock mu(Thread::Current(), lock_); 36 for (ClassSet& class_set : classes_) { 37 auto it = class_set.Find(GcRoot<mirror::Class>(klass)); 38 if (it != class_set.end()) { 39 return it->Read() == klass; 40 } 41 } 42 return false; 43 } 44 45 mirror::Class* ClassTable::LookupByDescriptor(mirror::Class* klass) { 46 ReaderMutexLock mu(Thread::Current(), lock_); 47 for (ClassSet& class_set : classes_) { 48 auto it = class_set.Find(GcRoot<mirror::Class>(klass)); 49 if (it != class_set.end()) { 50 return it->Read(); 51 } 52 } 53 return nullptr; 54 } 55 56 mirror::Class* ClassTable::UpdateClass(const char* descriptor, mirror::Class* klass, size_t hash) { 57 WriterMutexLock mu(Thread::Current(), lock_); 58 // Should only be updating latest table. 59 auto existing_it = classes_.back().FindWithHash(descriptor, hash); 60 if (kIsDebugBuild && existing_it == classes_.back().end()) { 61 for (const ClassSet& class_set : classes_) { 62 if (class_set.FindWithHash(descriptor, hash) != class_set.end()) { 63 LOG(FATAL) << "Updating class found in frozen table " << descriptor; 64 } 65 } 66 LOG(FATAL) << "Updating class not found " << descriptor; 67 } 68 mirror::Class* const existing = existing_it->Read(); 69 CHECK_NE(existing, klass) << descriptor; 70 CHECK(!existing->IsResolved()) << descriptor; 71 CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor; 72 CHECK(!klass->IsTemp()) << descriptor; 73 VerifyObject(klass); 74 // Update the element in the hash set with the new class. This is safe to do since the descriptor 75 // doesn't change. 76 *existing_it = GcRoot<mirror::Class>(klass); 77 return existing; 78 } 79 80 size_t ClassTable::NumZygoteClasses() const { 81 ReaderMutexLock mu(Thread::Current(), lock_); 82 size_t sum = 0; 83 for (size_t i = 0; i < classes_.size() - 1; ++i) { 84 sum += classes_[i].Size(); 85 } 86 return sum; 87 } 88 89 size_t ClassTable::NumNonZygoteClasses() const { 90 ReaderMutexLock mu(Thread::Current(), lock_); 91 return classes_.back().Size(); 92 } 93 94 mirror::Class* ClassTable::Lookup(const char* descriptor, size_t hash) { 95 ReaderMutexLock mu(Thread::Current(), lock_); 96 for (ClassSet& class_set : classes_) { 97 auto it = class_set.FindWithHash(descriptor, hash); 98 if (it != class_set.end()) { 99 return it->Read(); 100 } 101 } 102 return nullptr; 103 } 104 105 void ClassTable::Insert(mirror::Class* klass) { 106 WriterMutexLock mu(Thread::Current(), lock_); 107 classes_.back().Insert(GcRoot<mirror::Class>(klass)); 108 } 109 110 void ClassTable::InsertWithoutLocks(mirror::Class* klass) { 111 classes_.back().Insert(GcRoot<mirror::Class>(klass)); 112 } 113 114 void ClassTable::InsertWithHash(mirror::Class* klass, size_t hash) { 115 WriterMutexLock mu(Thread::Current(), lock_); 116 classes_.back().InsertWithHash(GcRoot<mirror::Class>(klass), hash); 117 } 118 119 bool ClassTable::Remove(const char* descriptor) { 120 WriterMutexLock mu(Thread::Current(), lock_); 121 for (ClassSet& class_set : classes_) { 122 auto it = class_set.Find(descriptor); 123 if (it != class_set.end()) { 124 class_set.Erase(it); 125 return true; 126 } 127 } 128 return false; 129 } 130 131 uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& root) 132 const { 133 std::string temp; 134 return ComputeModifiedUtf8Hash(root.Read()->GetDescriptor(&temp)); 135 } 136 137 bool ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& a, 138 const GcRoot<mirror::Class>& b) const { 139 DCHECK_EQ(a.Read()->GetClassLoader(), b.Read()->GetClassLoader()); 140 std::string temp; 141 return a.Read()->DescriptorEquals(b.Read()->GetDescriptor(&temp)); 142 } 143 144 bool ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& a, 145 const char* descriptor) const { 146 return a.Read()->DescriptorEquals(descriptor); 147 } 148 149 uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const char* descriptor) const { 150 return ComputeModifiedUtf8Hash(descriptor); 151 } 152 153 bool ClassTable::InsertStrongRoot(mirror::Object* obj) { 154 WriterMutexLock mu(Thread::Current(), lock_); 155 DCHECK(obj != nullptr); 156 for (GcRoot<mirror::Object>& root : strong_roots_) { 157 if (root.Read() == obj) { 158 return false; 159 } 160 } 161 strong_roots_.push_back(GcRoot<mirror::Object>(obj)); 162 return true; 163 } 164 165 size_t ClassTable::WriteToMemory(uint8_t* ptr) const { 166 ReaderMutexLock mu(Thread::Current(), lock_); 167 ClassSet combined; 168 // Combine all the class sets in case there are multiple, also adjusts load factor back to 169 // default in case classes were pruned. 170 for (const ClassSet& class_set : classes_) { 171 for (const GcRoot<mirror::Class>& root : class_set) { 172 combined.Insert(root); 173 } 174 } 175 const size_t ret = combined.WriteToMemory(ptr); 176 // Sanity check. 177 if (kIsDebugBuild && ptr != nullptr) { 178 size_t read_count; 179 ClassSet class_set(ptr, /*make copy*/false, &read_count); 180 class_set.Verify(); 181 } 182 return ret; 183 } 184 185 size_t ClassTable::ReadFromMemory(uint8_t* ptr) { 186 size_t read_count = 0; 187 AddClassSet(ClassSet(ptr, /*make copy*/false, &read_count)); 188 return read_count; 189 } 190 191 void ClassTable::AddClassSet(ClassSet&& set) { 192 WriterMutexLock mu(Thread::Current(), lock_); 193 classes_.insert(classes_.begin(), std::move(set)); 194 } 195 196 void ClassTable::ClearStrongRoots() { 197 WriterMutexLock mu(Thread::Current(), lock_); 198 strong_roots_.clear(); 199 } 200 } // namespace art 201