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