| Elliott Hughes | 2faa5f1 | 2012-01-30 14:42:07 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2011 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 |  */ | 
| Brian Carlstrom | 7e93b50 | 2011-08-04 14:16:22 -0700 | [diff] [blame] | 16 |  | 
 | 17 | #include "intern_table.h" | 
 | 18 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 19 | #include "gc/space/image_space.h" | 
 | 20 | #include "mirror/dex_cache.h" | 
 | 21 | #include "mirror/object_array-inl.h" | 
 | 22 | #include "mirror/object-inl.h" | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 23 | #include "mirror/string.h" | 
 | 24 | #include "thread.h" | 
| Elliott Hughes | 90a3369 | 2011-08-30 13:27:07 -0700 | [diff] [blame] | 25 | #include "UniquePtr.h" | 
| Elliott Hughes | 814e403 | 2011-08-23 12:07:56 -0700 | [diff] [blame] | 26 | #include "utf.h" | 
| Brian Carlstrom | 7e93b50 | 2011-08-04 14:16:22 -0700 | [diff] [blame] | 27 |  | 
 | 28 | namespace art { | 
 | 29 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 30 | InternTable::InternTable() | 
| Mathieu Chartier | c11d9b8 | 2013-09-19 10:01:59 -0700 | [diff] [blame] | 31 |     : intern_table_lock_("InternTable lock"), is_dirty_(false), allow_new_interns_(true), | 
 | 32 |       new_intern_condition_("New intern condition", intern_table_lock_) { | 
 | 33 | } | 
| Elliott Hughes | de69d7f | 2011-08-18 16:49:37 -0700 | [diff] [blame] | 34 |  | 
| Brian Carlstrom | a663ea5 | 2011-08-19 23:33:41 -0700 | [diff] [blame] | 35 | size_t InternTable::Size() const { | 
| Ian Rogers | 50b35e2 | 2012-10-04 10:09:15 -0700 | [diff] [blame] | 36 |   MutexLock mu(Thread::Current(), intern_table_lock_); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 37 |   return strong_interns_.size() + weak_interns_.size(); | 
| Brian Carlstrom | a663ea5 | 2011-08-19 23:33:41 -0700 | [diff] [blame] | 38 | } | 
 | 39 |  | 
| Elliott Hughes | cac6cc7 | 2011-11-03 20:31:21 -0700 | [diff] [blame] | 40 | void InternTable::DumpForSigQuit(std::ostream& os) const { | 
| Ian Rogers | 50b35e2 | 2012-10-04 10:09:15 -0700 | [diff] [blame] | 41 |   MutexLock mu(Thread::Current(), intern_table_lock_); | 
| Elliott Hughes | cac6cc7 | 2011-11-03 20:31:21 -0700 | [diff] [blame] | 42 |   os << "Intern table: " << strong_interns_.size() << " strong; " | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 43 |      << weak_interns_.size() << " weak\n"; | 
| Elliott Hughes | cac6cc7 | 2011-11-03 20:31:21 -0700 | [diff] [blame] | 44 | } | 
 | 45 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 46 | void InternTable::VisitRoots(RootVisitor* visitor, void* arg, | 
| Mathieu Chartier | c462198 | 2013-09-16 19:43:47 -0700 | [diff] [blame] | 47 |                              bool only_dirty, bool clean_dirty) { | 
| Ian Rogers | 50b35e2 | 2012-10-04 10:09:15 -0700 | [diff] [blame] | 48 |   MutexLock mu(Thread::Current(), intern_table_lock_); | 
| Mathieu Chartier | c462198 | 2013-09-16 19:43:47 -0700 | [diff] [blame] | 49 |   if (!only_dirty || is_dirty_) { | 
| Mathieu Chartier | b307052 | 2013-09-17 14:18:21 -0700 | [diff] [blame] | 50 |     for (auto& strong_intern : strong_interns_) { | 
 | 51 |       strong_intern.second = reinterpret_cast<mirror::String*>(visitor(strong_intern.second, arg)); | 
 | 52 |       DCHECK(strong_intern.second != nullptr); | 
| Mathieu Chartier | c462198 | 2013-09-16 19:43:47 -0700 | [diff] [blame] | 53 |     } | 
| Mathieu Chartier | b307052 | 2013-09-17 14:18:21 -0700 | [diff] [blame] | 54 |  | 
| Mathieu Chartier | c462198 | 2013-09-16 19:43:47 -0700 | [diff] [blame] | 55 |     if (clean_dirty) { | 
 | 56 |       is_dirty_ = false; | 
 | 57 |     } | 
| Ian Rogers | 1d54e73 | 2013-05-02 21:10:01 -0700 | [diff] [blame] | 58 |   } | 
| Mathieu Chartier | 423d2a3 | 2013-09-12 17:33:56 -0700 | [diff] [blame] | 59 |   // Note: we deliberately don't visit the weak_interns_ table and the immutable image roots. | 
| Brian Carlstrom | 7e93b50 | 2011-08-04 14:16:22 -0700 | [diff] [blame] | 60 | } | 
 | 61 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 62 | mirror::String* InternTable::Lookup(Table& table, mirror::String* s, | 
 | 63 |                                     uint32_t hash_code) { | 
| Ian Rogers | 50b35e2 | 2012-10-04 10:09:15 -0700 | [diff] [blame] | 64 |   intern_table_lock_.AssertHeld(Thread::Current()); | 
| Mathieu Chartier | 02e2511 | 2013-08-14 16:14:24 -0700 | [diff] [blame] | 65 |   for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 66 |     mirror::String* existing_string = it->second; | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 67 |     if (existing_string->Equals(s)) { | 
 | 68 |       return existing_string; | 
| Brian Carlstrom | 7e93b50 | 2011-08-04 14:16:22 -0700 | [diff] [blame] | 69 |     } | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 70 |   } | 
 | 71 |   return NULL; | 
 | 72 | } | 
 | 73 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 74 | mirror::String* InternTable::Insert(Table& table, mirror::String* s, | 
 | 75 |                                     uint32_t hash_code) { | 
| Ian Rogers | 50b35e2 | 2012-10-04 10:09:15 -0700 | [diff] [blame] | 76 |   intern_table_lock_.AssertHeld(Thread::Current()); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 77 |   table.insert(std::make_pair(hash_code, s)); | 
 | 78 |   return s; | 
 | 79 | } | 
 | 80 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 81 | void InternTable::Remove(Table& table, const mirror::String* s, | 
 | 82 |                          uint32_t hash_code) { | 
| Ian Rogers | 50b35e2 | 2012-10-04 10:09:15 -0700 | [diff] [blame] | 83 |   intern_table_lock_.AssertHeld(Thread::Current()); | 
| Mathieu Chartier | 02e2511 | 2013-08-14 16:14:24 -0700 | [diff] [blame] | 84 |   for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 85 |     if (it->second == s) { | 
 | 86 |       table.erase(it); | 
 | 87 |       return; | 
 | 88 |     } | 
| Brian Carlstrom | 7e93b50 | 2011-08-04 14:16:22 -0700 | [diff] [blame] | 89 |   } | 
 | 90 | } | 
 | 91 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 92 | static mirror::String* LookupStringFromImage(mirror::String* s) | 
 | 93 |     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { | 
 | 94 |   gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace(); | 
 | 95 |   if (image == NULL) { | 
 | 96 |     return NULL;  // No image present. | 
 | 97 |   } | 
 | 98 |   mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); | 
 | 99 |   mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>(); | 
 | 100 |   const std::string utf8 = s->ToModifiedUtf8(); | 
 | 101 |   for (int32_t i = 0; i < dex_caches->GetLength(); ++i) { | 
 | 102 |     mirror::DexCache* dex_cache = dex_caches->Get(i); | 
 | 103 |     const DexFile* dex_file = dex_cache->GetDexFile(); | 
 | 104 |     // Binary search the dex file for the string index. | 
 | 105 |     const DexFile::StringId* string_id = dex_file->FindStringId(utf8.c_str()); | 
 | 106 |     if (string_id != NULL) { | 
 | 107 |       uint32_t string_idx = dex_file->GetIndexForStringId(*string_id); | 
 | 108 |       mirror::String* image = dex_cache->GetResolvedString(string_idx); | 
 | 109 |       if (image != NULL) { | 
 | 110 |         return image; | 
 | 111 |       } | 
 | 112 |     } | 
 | 113 |   } | 
 | 114 |   return NULL; | 
 | 115 | } | 
 | 116 |  | 
| Mathieu Chartier | c11d9b8 | 2013-09-19 10:01:59 -0700 | [diff] [blame] | 117 | void InternTable::AllowNewInterns() { | 
 | 118 |   Thread* self = Thread::Current(); | 
 | 119 |   MutexLock mu(self, intern_table_lock_); | 
 | 120 |   allow_new_interns_ = true; | 
 | 121 |   new_intern_condition_.Broadcast(self); | 
 | 122 | } | 
 | 123 |  | 
 | 124 | void InternTable::DisallowNewInterns() { | 
 | 125 |   Thread* self = Thread::Current(); | 
 | 126 |   MutexLock mu(self, intern_table_lock_); | 
 | 127 |   allow_new_interns_ = false; | 
 | 128 | } | 
 | 129 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 130 | mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { | 
| Mathieu Chartier | c11d9b8 | 2013-09-19 10:01:59 -0700 | [diff] [blame] | 131 |   Thread* self = Thread::Current(); | 
 | 132 |   MutexLock mu(self, intern_table_lock_); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 133 |  | 
 | 134 |   DCHECK(s != NULL); | 
 | 135 |   uint32_t hash_code = s->GetHashCode(); | 
 | 136 |  | 
| Mathieu Chartier | c11d9b8 | 2013-09-19 10:01:59 -0700 | [diff] [blame] | 137 |   while (UNLIKELY(!allow_new_interns_)) { | 
 | 138 |     new_intern_condition_.WaitHoldingLocks(self); | 
 | 139 |   } | 
 | 140 |  | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 141 |   if (is_strong) { | 
| jeffhao | b1c6f34 | 2012-03-20 17:57:26 -0700 | [diff] [blame] | 142 |     // Check the strong table for a match. | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 143 |     mirror::String* strong = Lookup(strong_interns_, s, hash_code); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 144 |     if (strong != NULL) { | 
 | 145 |       return strong; | 
 | 146 |     } | 
 | 147 |  | 
| Mathieu Chartier | 9ebae1f | 2012-10-15 17:38:16 -0700 | [diff] [blame] | 148 |     // Mark as dirty so that we rescan the roots. | 
| Mathieu Chartier | c462198 | 2013-09-16 19:43:47 -0700 | [diff] [blame] | 149 |     is_dirty_ = true; | 
| Mathieu Chartier | 9ebae1f | 2012-10-15 17:38:16 -0700 | [diff] [blame] | 150 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 151 |     // Check the image for a match. | 
 | 152 |     mirror::String* image = LookupStringFromImage(s); | 
 | 153 |     if (image != NULL) { | 
 | 154 |       return Insert(strong_interns_, image, hash_code); | 
 | 155 |     } | 
 | 156 |  | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 157 |     // There is no match in the strong table, check the weak table. | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 158 |     mirror::String* weak = Lookup(weak_interns_, s, hash_code); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 159 |     if (weak != NULL) { | 
 | 160 |       // A match was found in the weak table. Promote to the strong table. | 
 | 161 |       Remove(weak_interns_, weak, hash_code); | 
 | 162 |       return Insert(strong_interns_, weak, hash_code); | 
 | 163 |     } | 
 | 164 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 165 |     // No match in the strong table or the weak table. Insert into the strong | 
 | 166 |     // table. | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 167 |     return Insert(strong_interns_, s, hash_code); | 
 | 168 |   } | 
 | 169 |  | 
 | 170 |   // Check the strong table for a match. | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 171 |   mirror::String* strong = Lookup(strong_interns_, s, hash_code); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 172 |   if (strong != NULL) { | 
 | 173 |     return strong; | 
 | 174 |   } | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 175 |   // Check the image for a match. | 
 | 176 |   mirror::String* image = LookupStringFromImage(s); | 
| jeffhao | b1c6f34 | 2012-03-20 17:57:26 -0700 | [diff] [blame] | 177 |   if (image != NULL) { | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 178 |     return Insert(weak_interns_, image, hash_code); | 
| jeffhao | b1c6f34 | 2012-03-20 17:57:26 -0700 | [diff] [blame] | 179 |   } | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 180 |   // Check the weak table for a match. | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 181 |   mirror::String* weak = Lookup(weak_interns_, s, hash_code); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 182 |   if (weak != NULL) { | 
 | 183 |     return weak; | 
 | 184 |   } | 
 | 185 |   // Insert into the weak table. | 
 | 186 |   return Insert(weak_interns_, s, hash_code); | 
 | 187 | } | 
 | 188 |  | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 189 | mirror::String* InternTable::InternStrong(int32_t utf16_length, | 
 | 190 |                                           const char* utf8_data) { | 
 | 191 |   return InternStrong(mirror::String::AllocFromModifiedUtf8( | 
 | 192 |       Thread::Current(), utf16_length, utf8_data)); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 193 | } | 
 | 194 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 195 | mirror::String* InternTable::InternStrong(const char* utf8_data) { | 
| Ian Rogers | 7dfb28c | 2013-08-22 08:18:36 -0700 | [diff] [blame] | 196 |   return InternStrong( | 
 | 197 |       mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data)); | 
| Brian Carlstrom | c74255f | 2011-09-11 22:47:39 -0700 | [diff] [blame] | 198 | } | 
 | 199 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 200 | mirror::String* InternTable::InternStrong(mirror::String* s) { | 
| Elliott Hughes | 37d4e6b | 2011-10-13 12:05:20 -0700 | [diff] [blame] | 201 |   if (s == NULL) { | 
 | 202 |     return NULL; | 
 | 203 |   } | 
| Brian Carlstrom | c74255f | 2011-09-11 22:47:39 -0700 | [diff] [blame] | 204 |   return Insert(s, true); | 
 | 205 | } | 
 | 206 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 207 | mirror::String* InternTable::InternWeak(mirror::String* s) { | 
| Elliott Hughes | 37d4e6b | 2011-10-13 12:05:20 -0700 | [diff] [blame] | 208 |   if (s == NULL) { | 
 | 209 |     return NULL; | 
 | 210 |   } | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 211 |   return Insert(s, false); | 
 | 212 | } | 
 | 213 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 214 | bool InternTable::ContainsWeak(mirror::String* s) { | 
| Ian Rogers | 50b35e2 | 2012-10-04 10:09:15 -0700 | [diff] [blame] | 215 |   MutexLock mu(Thread::Current(), intern_table_lock_); | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 216 |   const mirror::String* found = Lookup(weak_interns_, s, s->GetHashCode()); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 217 |   return found == s; | 
 | 218 | } | 
 | 219 |  | 
| Mathieu Chartier | 6aa3df9 | 2013-09-17 15:17:28 -0700 | [diff] [blame] | 220 | void InternTable::SweepInternTableWeaks(RootVisitor visitor, void* arg) { | 
| Ian Rogers | 50b35e2 | 2012-10-04 10:09:15 -0700 | [diff] [blame] | 221 |   MutexLock mu(Thread::Current(), intern_table_lock_); | 
| Mathieu Chartier | 02e2511 | 2013-08-14 16:14:24 -0700 | [diff] [blame] | 222 |   for (auto it = weak_interns_.begin(), end = weak_interns_.end(); it != end;) { | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 223 |     mirror::Object* object = it->second; | 
| Mathieu Chartier | 6aa3df9 | 2013-09-17 15:17:28 -0700 | [diff] [blame] | 224 |     mirror::Object* new_object = visitor(object, arg); | 
 | 225 |     if (new_object == nullptr) { | 
 | 226 |       // TODO: use it = weak_interns_.erase(it) when we get a c++11 stl. | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 227 |       weak_interns_.erase(it++); | 
 | 228 |     } else { | 
| Mathieu Chartier | 6aa3df9 | 2013-09-17 15:17:28 -0700 | [diff] [blame] | 229 |       it->second = down_cast<mirror::String*>(new_object); | 
| Elliott Hughes | cf4c6c4 | 2011-09-01 15:16:42 -0700 | [diff] [blame] | 230 |       ++it; | 
 | 231 |     } | 
 | 232 |   } | 
| Brian Carlstrom | a663ea5 | 2011-08-19 23:33:41 -0700 | [diff] [blame] | 233 | } | 
 | 234 |  | 
| Brian Carlstrom | 7e93b50 | 2011-08-04 14:16:22 -0700 | [diff] [blame] | 235 | }  // namespace art |