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