1 /* 2 * Copyright (C) 2013 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 "object_registry.h" 18 19 #include "handle_scope-inl.h" 20 #include "jni_internal.h" 21 #include "mirror/class.h" 22 #include "mirror/throwable.h" 23 #include "obj_ptr-inl.h" 24 #include "scoped_thread_state_change-inl.h" 25 26 namespace art { 27 28 std::ostream& operator<<(std::ostream& os, const ObjectRegistryEntry& rhs) { 29 os << "ObjectRegistryEntry[" << rhs.jni_reference_type 30 << ",reference=" << rhs.jni_reference 31 << ",count=" << rhs.reference_count 32 << ",id=" << rhs.id << "]"; 33 return os; 34 } 35 36 ObjectRegistry::ObjectRegistry() 37 : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), next_id_(1) { 38 Locks::AddToExpectedMutexesOnWeakRefAccess(&lock_); 39 } 40 41 ObjectRegistry::~ObjectRegistry() { 42 Locks::RemoveFromExpectedMutexesOnWeakRefAccess(&lock_); 43 } 44 45 JDWP::RefTypeId ObjectRegistry::AddRefType(ObjPtr<mirror::Class> c) { 46 return Add(c); 47 } 48 49 JDWP::RefTypeId ObjectRegistry::AddRefType(Handle<mirror::Class> c_h) { 50 return Add(c_h); 51 } 52 53 JDWP::ObjectId ObjectRegistry::Add(ObjPtr<mirror::Object> o) { 54 if (o == nullptr) { 55 return 0; 56 } 57 Thread* const self = Thread::Current(); 58 StackHandleScope<1> hs(self); 59 return InternalAdd(hs.NewHandle(o)); 60 } 61 62 // Template instantiations must be declared below. 63 template<class T> 64 JDWP::ObjectId ObjectRegistry::Add(Handle<T> obj_h) { 65 if (obj_h == nullptr) { 66 return 0; 67 } 68 return InternalAdd(obj_h); 69 } 70 71 // Explicit template instantiation. 72 template 73 REQUIRES_SHARED(Locks::mutator_lock_) 74 REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_) 75 JDWP::ObjectId ObjectRegistry::Add(Handle<mirror::Object> obj_h); 76 77 template 78 REQUIRES_SHARED(Locks::mutator_lock_) 79 REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_) 80 JDWP::ObjectId ObjectRegistry::Add(Handle<mirror::Throwable> obj_h); 81 82 template<class T> 83 JDWP::ObjectId ObjectRegistry::InternalAdd(Handle<T> obj_h) { 84 CHECK(obj_h != nullptr); 85 86 Thread* const self = Thread::Current(); 87 self->AssertNoPendingException(); 88 // Object::IdentityHashCode may cause these locks to be held so check we do not already 89 // hold them. 90 Locks::thread_list_lock_->AssertNotHeld(self); 91 Locks::thread_suspend_count_lock_->AssertNotHeld(self); 92 93 // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock. 94 int32_t identity_hash_code = obj_h->IdentityHashCode(); 95 96 ScopedObjectAccessUnchecked soa(self); 97 MutexLock mu(soa.Self(), lock_); 98 ObjectRegistryEntry* entry = nullptr; 99 if (ContainsLocked(soa.Self(), obj_h.Get(), identity_hash_code, &entry)) { 100 // This object was already in our map. 101 ++entry->reference_count; 102 } else { 103 entry = new ObjectRegistryEntry; 104 entry->jni_reference_type = JNIWeakGlobalRefType; 105 entry->jni_reference = nullptr; 106 entry->reference_count = 0; 107 entry->id = 0; 108 entry->identity_hash_code = identity_hash_code; 109 object_to_entry_.insert(std::make_pair(identity_hash_code, entry)); 110 111 // This object isn't in the registry yet, so add it. 112 JNIEnv* env = soa.Env(); 113 114 jobject local_reference = soa.AddLocalReference<jobject>(obj_h.Get()); 115 116 entry->jni_reference_type = JNIWeakGlobalRefType; 117 entry->jni_reference = env->NewWeakGlobalRef(local_reference); 118 entry->reference_count = 1; 119 entry->id = next_id_++; 120 121 id_to_entry_.Put(entry->id, entry); 122 123 env->DeleteLocalRef(local_reference); 124 } 125 return entry->id; 126 } 127 128 bool ObjectRegistry::ContainsLocked(Thread* self, 129 ObjPtr<mirror::Object> o, 130 int32_t identity_hash_code, 131 ObjectRegistryEntry** out_entry) { 132 DCHECK(o != nullptr); 133 for (auto it = object_to_entry_.lower_bound(identity_hash_code), end = object_to_entry_.end(); 134 it != end && it->first == identity_hash_code; ++it) { 135 ObjectRegistryEntry* entry = it->second; 136 if (o == self->DecodeJObject(entry->jni_reference)) { 137 if (out_entry != nullptr) { 138 *out_entry = entry; 139 } 140 return true; 141 } 142 } 143 return false; 144 } 145 146 void ObjectRegistry::Clear() { 147 Thread* const self = Thread::Current(); 148 149 // We must not hold the mutator lock exclusively if we want to delete weak global 150 // references. Otherwise this can lead to a deadlock with a running GC: 151 // 1. GC thread disables access to weak global references, then releases 152 // mutator lock. 153 // 2. JDWP thread takes mutator lock exclusively after suspending all 154 // threads. 155 // 3. GC thread waits for shared mutator lock which is held by JDWP 156 // thread. 157 // 4. JDWP thread clears weak global references but need to wait for GC 158 // thread to re-enable access to them. 159 Locks::mutator_lock_->AssertNotExclusiveHeld(self); 160 161 MutexLock mu(self, lock_); 162 VLOG(jdwp) << "Object registry contained " << object_to_entry_.size() << " entries"; 163 // Delete all the JNI references. 164 JNIEnv* env = self->GetJniEnv(); 165 for (const auto& pair : object_to_entry_) { 166 const ObjectRegistryEntry* entry = pair.second; 167 if (entry->jni_reference_type == JNIWeakGlobalRefType) { 168 env->DeleteWeakGlobalRef(entry->jni_reference); 169 } else { 170 env->DeleteGlobalRef(entry->jni_reference); 171 } 172 delete entry; 173 } 174 // Clear the maps. 175 object_to_entry_.clear(); 176 id_to_entry_.clear(); 177 } 178 179 mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id, JDWP::JdwpError* error) { 180 Thread* self = Thread::Current(); 181 MutexLock mu(self, lock_); 182 auto it = id_to_entry_.find(id); 183 if (it == id_to_entry_.end()) { 184 *error = JDWP::ERR_INVALID_OBJECT; 185 return nullptr; 186 } 187 ObjectRegistryEntry& entry = *it->second; 188 *error = JDWP::ERR_NONE; 189 return self->DecodeJObject(entry.jni_reference).Ptr(); 190 } 191 192 jobject ObjectRegistry::GetJObject(JDWP::ObjectId id) { 193 if (id == 0) { 194 return nullptr; 195 } 196 Thread* self = Thread::Current(); 197 MutexLock mu(self, lock_); 198 auto it = id_to_entry_.find(id); 199 CHECK(it != id_to_entry_.end()) << id; 200 ObjectRegistryEntry& entry = *it->second; 201 return entry.jni_reference; 202 } 203 204 void ObjectRegistry::DisableCollection(JDWP::ObjectId id) { 205 Thread* self = Thread::Current(); 206 MutexLock mu(self, lock_); 207 auto it = id_to_entry_.find(id); 208 CHECK(it != id_to_entry_.end()); 209 Promote(*it->second); 210 } 211 212 void ObjectRegistry::EnableCollection(JDWP::ObjectId id) { 213 Thread* self = Thread::Current(); 214 MutexLock mu(self, lock_); 215 auto it = id_to_entry_.find(id); 216 CHECK(it != id_to_entry_.end()); 217 Demote(*it->second); 218 } 219 220 void ObjectRegistry::Demote(ObjectRegistryEntry& entry) { 221 if (entry.jni_reference_type == JNIGlobalRefType) { 222 Thread* self = Thread::Current(); 223 JNIEnv* env = self->GetJniEnv(); 224 jobject global = entry.jni_reference; 225 entry.jni_reference = env->NewWeakGlobalRef(entry.jni_reference); 226 entry.jni_reference_type = JNIWeakGlobalRefType; 227 env->DeleteGlobalRef(global); 228 } 229 } 230 231 void ObjectRegistry::Promote(ObjectRegistryEntry& entry) { 232 if (entry.jni_reference_type == JNIWeakGlobalRefType) { 233 Thread* self = Thread::Current(); 234 JNIEnv* env = self->GetJniEnv(); 235 jobject weak = entry.jni_reference; 236 entry.jni_reference = env->NewGlobalRef(entry.jni_reference); 237 entry.jni_reference_type = JNIGlobalRefType; 238 env->DeleteWeakGlobalRef(weak); 239 } 240 } 241 242 bool ObjectRegistry::IsCollected(JDWP::ObjectId id) { 243 Thread* self = Thread::Current(); 244 MutexLock mu(self, lock_); 245 auto it = id_to_entry_.find(id); 246 CHECK(it != id_to_entry_.end()); 247 ObjectRegistryEntry& entry = *it->second; 248 if (entry.jni_reference_type == JNIWeakGlobalRefType) { 249 JNIEnv* env = self->GetJniEnv(); 250 return env->IsSameObject(entry.jni_reference, nullptr); // Has the jweak been collected? 251 } else { 252 return false; // We hold a strong reference, so we know this is live. 253 } 254 } 255 256 void ObjectRegistry::DisposeObject(JDWP::ObjectId id, uint32_t reference_count) { 257 Thread* self = Thread::Current(); 258 MutexLock mu(self, lock_); 259 auto it = id_to_entry_.find(id); 260 if (it == id_to_entry_.end()) { 261 return; 262 } 263 ObjectRegistryEntry* entry = it->second; 264 entry->reference_count -= reference_count; 265 if (entry->reference_count <= 0) { 266 JNIEnv* env = self->GetJniEnv(); 267 // Erase the object from the maps. Note object may be null if it's 268 // a weak ref and the GC has cleared it. 269 int32_t hash_code = entry->identity_hash_code; 270 for (auto inner_it = object_to_entry_.lower_bound(hash_code), end = object_to_entry_.end(); 271 inner_it != end && inner_it->first == hash_code; ++inner_it) { 272 if (entry == inner_it->second) { 273 object_to_entry_.erase(inner_it); 274 break; 275 } 276 } 277 if (entry->jni_reference_type == JNIWeakGlobalRefType) { 278 env->DeleteWeakGlobalRef(entry->jni_reference); 279 } else { 280 env->DeleteGlobalRef(entry->jni_reference); 281 } 282 id_to_entry_.erase(id); 283 delete entry; 284 } 285 } 286 287 } // namespace art 288