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