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