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