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