Home | History | Annotate | Download | only in jdwp
      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 
     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 
     34 ObjectRegistry::ObjectRegistry()
     35     : lock_("ObjectRegistry lock", kJdwpObjectRegistryLock), next_id_(1) {
     36 }
     37 
     38 JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) {
     39   return InternalAdd(c);
     40 }
     41 
     42 JDWP::ObjectId ObjectRegistry::Add(mirror::Object* o) {
     43   return InternalAdd(o);
     44 }
     45 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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