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