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