/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_RUNTIME_INTERN_TABLE_INL_H_ #define ART_RUNTIME_INTERN_TABLE_INL_H_ #include "intern_table.h" #include "gc/space/image_space.h" #include "image.h" #include "mirror/string-inl.h" // Required for ToModifiedUtf8 below. namespace art { template inline void InternTable::AddImageStringsToTable(gc::space::ImageSpace* image_space, const Visitor& visitor) { DCHECK(image_space != nullptr); // Only add if we have the interned strings section. const ImageHeader& header = image_space->GetImageHeader(); const ImageSection& section = header.GetInternedStringsSection(); if (section.Size() > 0) { AddTableFromMemory(image_space->Begin() + section.Offset(), visitor, !header.IsAppImage()); } } template inline size_t InternTable::AddTableFromMemory(const uint8_t* ptr, const Visitor& visitor, bool is_boot_image) { size_t read_count = 0; UnorderedSet set(ptr, /*make copy*/false, &read_count); { // Hold the lock while calling the visitor to prevent possible race // conditions with another thread adding intern strings. MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); // Visit the unordered set, may remove elements. visitor(set); if (!set.empty()) { strong_interns_.AddInternStrings(std::move(set), is_boot_image); } } return read_count; } inline void InternTable::Table::AddInternStrings(UnorderedSet&& intern_strings, bool is_boot_image) { static constexpr bool kCheckDuplicates = kIsDebugBuild; if (kCheckDuplicates) { // Avoid doing read barriers since the space might not yet be added to the heap. // See b/117803941 for (GcRoot& string : intern_strings) { CHECK(Find(string.Read()) == nullptr) << "Already found " << string.Read()->ToModifiedUtf8() << " in the intern table"; } } // Insert at the front since we add new interns into the back. tables_.insert(tables_.begin(), InternalTable(std::move(intern_strings), is_boot_image)); } template inline void InternTable::VisitInterns(const Visitor& visitor, bool visit_boot_images, bool visit_non_boot_images) { auto visit_tables = [&](std::vector& tables) NO_THREAD_SAFETY_ANALYSIS { for (Table::InternalTable& table : tables) { // Determine if we want to visit the table based on the flags.. const bool visit = (visit_boot_images && table.IsBootImage()) || (visit_non_boot_images && !table.IsBootImage()); if (visit) { for (auto& intern : table.set_) { visitor(intern); } } } }; visit_tables(strong_interns_.tables_); visit_tables(weak_interns_.tables_); } inline size_t InternTable::CountInterns(bool visit_boot_images, bool visit_non_boot_images) const { size_t ret = 0u; auto visit_tables = [&](const std::vector& tables) NO_THREAD_SAFETY_ANALYSIS { for (const Table::InternalTable& table : tables) { // Determine if we want to visit the table based on the flags.. const bool visit = (visit_boot_images && table.IsBootImage()) || (visit_non_boot_images && !table.IsBootImage()); if (visit) { ret += table.set_.size(); } } }; visit_tables(strong_interns_.tables_); visit_tables(weak_interns_.tables_); return ret; } } // namespace art #endif // ART_RUNTIME_INTERN_TABLE_INL_H_