object_registry.cc revision b5a9e3d1cc1fd66683e43e365afc8c900e2800c4
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 "scoped_thread_state_change.h" 20 21namespace art { 22 23mirror::Object* const ObjectRegistry::kInvalidObject = reinterpret_cast<mirror::Object*>(1); 24 25std::ostream& operator<<(std::ostream& os, const ObjectRegistryEntry& rhs) { 26 os << "ObjectRegistryEntry[" << rhs.jni_reference_type 27 << ",reference=" << rhs.jni_reference 28 << ",count=" << rhs.reference_count 29 << ",id=" << rhs.id << "]"; 30 return os; 31} 32 33ObjectRegistry::ObjectRegistry() 34 : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), next_id_(1) { 35} 36 37JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) { 38 return InternalAdd(c); 39} 40 41JDWP::ObjectId ObjectRegistry::Add(mirror::Object* o) { 42 return InternalAdd(o); 43} 44 45JDWP::ObjectId ObjectRegistry::InternalAdd(mirror::Object* o) { 46 if (o == nullptr) { 47 return 0; 48 } 49 50 // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock. 51 int32_t identity_hash_code = o->IdentityHashCode(); 52 ScopedObjectAccessUnchecked soa(Thread::Current()); 53 MutexLock mu(soa.Self(), lock_); 54 ObjectRegistryEntry* entry = nullptr; 55 if (ContainsLocked(soa.Self(), o, identity_hash_code, &entry)) { 56 // This object was already in our map. 57 ++entry->reference_count; 58 } else { 59 entry = new ObjectRegistryEntry; 60 entry->jni_reference_type = JNIWeakGlobalRefType; 61 entry->jni_reference = nullptr; 62 entry->reference_count = 0; 63 entry->id = 0; 64 entry->identity_hash_code = identity_hash_code; 65 object_to_entry_.insert(std::make_pair(identity_hash_code, entry)); 66 67 // This object isn't in the registry yet, so add it. 68 JNIEnv* env = soa.Env(); 69 70 jobject local_reference = soa.AddLocalReference<jobject>(o); 71 72 entry->jni_reference_type = JNIWeakGlobalRefType; 73 entry->jni_reference = env->NewWeakGlobalRef(local_reference); 74 entry->reference_count = 1; 75 entry->id = next_id_++; 76 77 id_to_entry_.Put(entry->id, entry); 78 79 env->DeleteLocalRef(local_reference); 80 } 81 return entry->id; 82} 83 84bool ObjectRegistry::Contains(mirror::Object* o, ObjectRegistryEntry** out_entry) { 85 if (o == nullptr) { 86 return false; 87 } 88 // Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock. 89 int32_t identity_hash_code = o->IdentityHashCode(); 90 Thread* self = Thread::Current(); 91 MutexLock mu(self, lock_); 92 return ContainsLocked(self, o, identity_hash_code, out_entry); 93} 94 95bool ObjectRegistry::ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code, 96 ObjectRegistryEntry** out_entry) { 97 DCHECK(o != nullptr); 98 for (auto it = object_to_entry_.lower_bound(identity_hash_code), end = object_to_entry_.end(); 99 it != end && it->first == identity_hash_code; ++it) { 100 ObjectRegistryEntry* entry = it->second; 101 if (o == self->DecodeJObject(entry->jni_reference)) { 102 if (out_entry != nullptr) { 103 *out_entry = entry; 104 } 105 return true; 106 } 107 } 108 return false; 109} 110 111void ObjectRegistry::Clear() { 112 Thread* self = Thread::Current(); 113 MutexLock mu(self, lock_); 114 VLOG(jdwp) << "Object registry contained " << object_to_entry_.size() << " entries"; 115 // Delete all the JNI references. 116 JNIEnv* env = self->GetJniEnv(); 117 for (const auto& pair : object_to_entry_) { 118 const ObjectRegistryEntry& entry = *pair.second; 119 if (entry.jni_reference_type == JNIWeakGlobalRefType) { 120 env->DeleteWeakGlobalRef(entry.jni_reference); 121 } else { 122 env->DeleteGlobalRef(entry.jni_reference); 123 } 124 } 125 // Clear the maps. 126 object_to_entry_.clear(); 127 id_to_entry_.clear(); 128} 129 130mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id) { 131 Thread* self = Thread::Current(); 132 MutexLock mu(self, lock_); 133 auto it = id_to_entry_.find(id); 134 if (it == id_to_entry_.end()) { 135 return kInvalidObject; 136 } 137 ObjectRegistryEntry& entry = *it->second; 138 return self->DecodeJObject(entry.jni_reference); 139} 140 141jobject ObjectRegistry::GetJObject(JDWP::ObjectId id) { 142 if (id == 0) { 143 return NULL; 144 } 145 Thread* self = Thread::Current(); 146 MutexLock mu(self, lock_); 147 auto it = id_to_entry_.find(id); 148 CHECK(it != id_to_entry_.end()) << id; 149 ObjectRegistryEntry& entry = *it->second; 150 return entry.jni_reference; 151} 152 153void ObjectRegistry::DisableCollection(JDWP::ObjectId id) { 154 Thread* self = Thread::Current(); 155 MutexLock mu(self, lock_); 156 auto it = id_to_entry_.find(id); 157 CHECK(it != id_to_entry_.end()); 158 Promote(*it->second); 159} 160 161void ObjectRegistry::EnableCollection(JDWP::ObjectId id) { 162 Thread* self = Thread::Current(); 163 MutexLock mu(self, lock_); 164 auto it = id_to_entry_.find(id); 165 CHECK(it != id_to_entry_.end()); 166 Demote(*it->second); 167} 168 169void ObjectRegistry::Demote(ObjectRegistryEntry& entry) { 170 if (entry.jni_reference_type == JNIGlobalRefType) { 171 Thread* self = Thread::Current(); 172 JNIEnv* env = self->GetJniEnv(); 173 jobject global = entry.jni_reference; 174 entry.jni_reference = env->NewWeakGlobalRef(entry.jni_reference); 175 entry.jni_reference_type = JNIWeakGlobalRefType; 176 env->DeleteGlobalRef(global); 177 } 178} 179 180void ObjectRegistry::Promote(ObjectRegistryEntry& entry) { 181 if (entry.jni_reference_type == JNIWeakGlobalRefType) { 182 Thread* self = Thread::Current(); 183 JNIEnv* env = self->GetJniEnv(); 184 jobject weak = entry.jni_reference; 185 entry.jni_reference = env->NewGlobalRef(entry.jni_reference); 186 entry.jni_reference_type = JNIGlobalRefType; 187 env->DeleteWeakGlobalRef(weak); 188 } 189} 190 191bool ObjectRegistry::IsCollected(JDWP::ObjectId id) { 192 Thread* self = Thread::Current(); 193 MutexLock mu(self, lock_); 194 auto it = id_to_entry_.find(id); 195 CHECK(it != id_to_entry_.end()); 196 ObjectRegistryEntry& entry = *it->second; 197 if (entry.jni_reference_type == JNIWeakGlobalRefType) { 198 JNIEnv* env = self->GetJniEnv(); 199 return env->IsSameObject(entry.jni_reference, NULL); // Has the jweak been collected? 200 } else { 201 return false; // We hold a strong reference, so we know this is live. 202 } 203} 204 205void ObjectRegistry::DisposeObject(JDWP::ObjectId id, uint32_t reference_count) { 206 Thread* self = Thread::Current(); 207 MutexLock mu(self, lock_); 208 auto it = id_to_entry_.find(id); 209 if (it == id_to_entry_.end()) { 210 return; 211 } 212 ObjectRegistryEntry* entry = it->second; 213 entry->reference_count -= reference_count; 214 if (entry->reference_count <= 0) { 215 JNIEnv* env = self->GetJniEnv(); 216 // Erase the object from the maps. Note object may be null if it's 217 // a weak ref and the GC has cleared it. 218 int32_t hash_code = entry->identity_hash_code; 219 for (auto it = object_to_entry_.lower_bound(hash_code), end = object_to_entry_.end(); 220 it != end && it->first == hash_code; ++it) { 221 if (entry == it->second) { 222 object_to_entry_.erase(it); 223 break; 224 } 225 } 226 if (entry->jni_reference_type == JNIWeakGlobalRefType) { 227 env->DeleteWeakGlobalRef(entry->jni_reference); 228 } else { 229 env->DeleteGlobalRef(entry->jni_reference); 230 } 231 id_to_entry_.erase(id); 232 delete entry; 233 } 234} 235 236} // namespace art 237