intern_table.cc revision c4621985bdfc2b27494087e5dee65a6d0cc5a632
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 */ 16 17#include "intern_table.h" 18 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" 23#include "mirror/string.h" 24#include "thread.h" 25#include "UniquePtr.h" 26#include "utf.h" 27 28namespace art { 29 30InternTable::InternTable() 31 : intern_table_lock_("InternTable lock"), is_dirty_(false) {} 32 33size_t InternTable::Size() const { 34 MutexLock mu(Thread::Current(), intern_table_lock_); 35 return strong_interns_.size() + weak_interns_.size(); 36} 37 38void InternTable::DumpForSigQuit(std::ostream& os) const { 39 MutexLock mu(Thread::Current(), intern_table_lock_); 40 os << "Intern table: " << strong_interns_.size() << " strong; " 41 << weak_interns_.size() << " weak\n"; 42} 43 44void InternTable::VisitRoots(RootVisitor* visitor, void* arg, 45 bool only_dirty, bool clean_dirty) { 46 MutexLock mu(Thread::Current(), intern_table_lock_); 47 if (!only_dirty || is_dirty_) { 48 for (const auto& strong_intern : strong_interns_) { 49 visitor(strong_intern.second, arg); 50 } 51 if (clean_dirty) { 52 is_dirty_ = false; 53 } 54 } 55 // Note: we deliberately don't visit the weak_interns_ table and the immutable 56 // image roots. 57} 58 59mirror::String* InternTable::Lookup(Table& table, mirror::String* s, 60 uint32_t hash_code) { 61 intern_table_lock_.AssertHeld(Thread::Current()); 62 for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { 63 mirror::String* existing_string = it->second; 64 if (existing_string->Equals(s)) { 65 return existing_string; 66 } 67 } 68 return NULL; 69} 70 71mirror::String* InternTable::Insert(Table& table, mirror::String* s, 72 uint32_t hash_code) { 73 intern_table_lock_.AssertHeld(Thread::Current()); 74 table.insert(std::make_pair(hash_code, s)); 75 return s; 76} 77 78void InternTable::Remove(Table& table, const mirror::String* s, 79 uint32_t hash_code) { 80 intern_table_lock_.AssertHeld(Thread::Current()); 81 for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { 82 if (it->second == s) { 83 table.erase(it); 84 return; 85 } 86 } 87} 88 89static mirror::String* LookupStringFromImage(mirror::String* s) 90 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 91 gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace(); 92 if (image == NULL) { 93 return NULL; // No image present. 94 } 95 mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); 96 mirror::ObjectArray<mirror::DexCache>* dex_caches = root->AsObjectArray<mirror::DexCache>(); 97 const std::string utf8 = s->ToModifiedUtf8(); 98 for (int32_t i = 0; i < dex_caches->GetLength(); ++i) { 99 mirror::DexCache* dex_cache = dex_caches->Get(i); 100 const DexFile* dex_file = dex_cache->GetDexFile(); 101 // Binary search the dex file for the string index. 102 const DexFile::StringId* string_id = dex_file->FindStringId(utf8.c_str()); 103 if (string_id != NULL) { 104 uint32_t string_idx = dex_file->GetIndexForStringId(*string_id); 105 mirror::String* image = dex_cache->GetResolvedString(string_idx); 106 if (image != NULL) { 107 return image; 108 } 109 } 110 } 111 return NULL; 112} 113 114mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) { 115 MutexLock mu(Thread::Current(), intern_table_lock_); 116 117 DCHECK(s != NULL); 118 uint32_t hash_code = s->GetHashCode(); 119 120 if (is_strong) { 121 // Check the strong table for a match. 122 mirror::String* strong = Lookup(strong_interns_, s, hash_code); 123 if (strong != NULL) { 124 return strong; 125 } 126 127 // Mark as dirty so that we rescan the roots. 128 is_dirty_ = true; 129 130 // Check the image for a match. 131 mirror::String* image = LookupStringFromImage(s); 132 if (image != NULL) { 133 return Insert(strong_interns_, image, hash_code); 134 } 135 136 // There is no match in the strong table, check the weak table. 137 mirror::String* weak = Lookup(weak_interns_, s, hash_code); 138 if (weak != NULL) { 139 // A match was found in the weak table. Promote to the strong table. 140 Remove(weak_interns_, weak, hash_code); 141 return Insert(strong_interns_, weak, hash_code); 142 } 143 144 // No match in the strong table or the weak table. Insert into the strong 145 // table. 146 return Insert(strong_interns_, s, hash_code); 147 } 148 149 // Check the strong table for a match. 150 mirror::String* strong = Lookup(strong_interns_, s, hash_code); 151 if (strong != NULL) { 152 return strong; 153 } 154 // Check the image for a match. 155 mirror::String* image = LookupStringFromImage(s); 156 if (image != NULL) { 157 return Insert(weak_interns_, image, hash_code); 158 } 159 // Check the weak table for a match. 160 mirror::String* weak = Lookup(weak_interns_, s, hash_code); 161 if (weak != NULL) { 162 return weak; 163 } 164 // Insert into the weak table. 165 return Insert(weak_interns_, s, hash_code); 166} 167 168mirror::String* InternTable::InternStrong(int32_t utf16_length, 169 const char* utf8_data) { 170 return InternStrong(mirror::String::AllocFromModifiedUtf8( 171 Thread::Current(), utf16_length, utf8_data)); 172} 173 174mirror::String* InternTable::InternStrong(const char* utf8_data) { 175 return InternStrong( 176 mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data)); 177} 178 179mirror::String* InternTable::InternStrong(mirror::String* s) { 180 if (s == NULL) { 181 return NULL; 182 } 183 return Insert(s, true); 184} 185 186mirror::String* InternTable::InternWeak(mirror::String* s) { 187 if (s == NULL) { 188 return NULL; 189 } 190 return Insert(s, false); 191} 192 193bool InternTable::ContainsWeak(mirror::String* s) { 194 MutexLock mu(Thread::Current(), intern_table_lock_); 195 const mirror::String* found = Lookup(weak_interns_, s, s->GetHashCode()); 196 return found == s; 197} 198 199void InternTable::SweepInternTableWeaks(IsMarkedTester is_marked, void* arg) { 200 MutexLock mu(Thread::Current(), intern_table_lock_); 201 // TODO: std::remove_if + lambda. 202 for (auto it = weak_interns_.begin(), end = weak_interns_.end(); it != end;) { 203 mirror::Object* object = it->second; 204 if (!is_marked(object, arg)) { 205 weak_interns_.erase(it++); 206 } else { 207 ++it; 208 } 209 } 210} 211 212} // namespace art 213