• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
operator <<(std::ostream & os,const ObjectRegistryEntry & rhs)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 
ObjectRegistry()34 ObjectRegistry::ObjectRegistry()
35     : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), next_id_(1) {
36 }
37 
AddRefType(mirror::Class * c)38 JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) {
39   return InternalAdd(c);
40 }
41 
Add(mirror::Object * o)42 JDWP::ObjectId ObjectRegistry::Add(mirror::Object* o) {
43   return InternalAdd(o);
44 }
45 
InternalAdd(mirror::Object * o)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 
Contains(mirror::Object * o,ObjectRegistryEntry ** out_entry)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 
ContainsLocked(Thread * self,mirror::Object * o,int32_t identity_hash_code,ObjectRegistryEntry ** out_entry)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 
Clear()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 
InternalGet(JDWP::ObjectId id)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 
GetJObject(JDWP::ObjectId id)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 
DisableCollection(JDWP::ObjectId id)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 
EnableCollection(JDWP::ObjectId id)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 
Demote(ObjectRegistryEntry & entry)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 
Promote(ObjectRegistryEntry & entry)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 
IsCollected(JDWP::ObjectId id)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 
DisposeObject(JDWP::ObjectId id,uint32_t reference_count)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