Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2018 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 #ifndef ART_RUNTIME_INTERN_TABLE_INL_H_
     18 #define ART_RUNTIME_INTERN_TABLE_INL_H_
     19 
     20 #include "intern_table.h"
     21 
     22 // Required for ToModifiedUtf8 below.
     23 #include "mirror/string-inl.h"
     24 
     25 namespace art {
     26 
     27 template <typename Visitor>
     28 inline void InternTable::AddImageStringsToTable(gc::space::ImageSpace* image_space,
     29                                                 const Visitor& visitor) {
     30   DCHECK(image_space != nullptr);
     31   // Only add if we have the interned strings section.
     32   const ImageHeader& header = image_space->GetImageHeader();
     33   const ImageSection& section = header.GetInternedStringsSection();
     34   if (section.Size() > 0) {
     35     AddTableFromMemory(image_space->Begin() + section.Offset(), visitor, !header.IsAppImage());
     36   }
     37 }
     38 
     39 template <typename Visitor>
     40 inline size_t InternTable::AddTableFromMemory(const uint8_t* ptr,
     41                                               const Visitor& visitor,
     42                                               bool is_boot_image) {
     43   size_t read_count = 0;
     44   UnorderedSet set(ptr, /*make copy*/false, &read_count);
     45   {
     46     // Hold the lock while calling the visitor to prevent possible race
     47     // conditions with another thread adding intern strings.
     48     MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
     49     // Visit the unordered set, may remove elements.
     50     visitor(set);
     51     if (!set.empty()) {
     52       strong_interns_.AddInternStrings(std::move(set), is_boot_image);
     53     }
     54   }
     55   return read_count;
     56 }
     57 
     58 inline void InternTable::Table::AddInternStrings(UnorderedSet&& intern_strings,
     59                                                  bool is_boot_image) {
     60   static constexpr bool kCheckDuplicates = kIsDebugBuild;
     61   if (kCheckDuplicates) {
     62     // Avoid doing read barriers since the space might not yet be added to the heap.
     63     // See b/117803941
     64     for (GcRoot<mirror::String>& string : intern_strings) {
     65       CHECK(Find(string.Read<kWithoutReadBarrier>()) == nullptr)
     66           << "Already found " << string.Read<kWithoutReadBarrier>()->ToModifiedUtf8()
     67           << " in the intern table";
     68     }
     69   }
     70   // Insert at the front since we add new interns into the back.
     71   tables_.insert(tables_.begin(),
     72                  InternalTable(std::move(intern_strings), is_boot_image));
     73 }
     74 
     75 template <typename Visitor>
     76 inline void InternTable::VisitInterns(const Visitor& visitor,
     77                                       bool visit_boot_images,
     78                                       bool visit_non_boot_images) {
     79   auto visit_tables = [&](std::vector<Table::InternalTable>& tables)
     80       NO_THREAD_SAFETY_ANALYSIS {
     81     for (Table::InternalTable& table : tables) {
     82       // Determine if we want to visit the table based on the flags..
     83       const bool visit =
     84           (visit_boot_images && table.IsBootImage()) ||
     85           (visit_non_boot_images && !table.IsBootImage());
     86       if (visit) {
     87         for (auto& intern : table.set_) {
     88           visitor(intern);
     89         }
     90       }
     91     }
     92   };
     93   visit_tables(strong_interns_.tables_);
     94   visit_tables(weak_interns_.tables_);
     95 }
     96 
     97 inline size_t InternTable::CountInterns(bool visit_boot_images,
     98                                         bool visit_non_boot_images) const {
     99   size_t ret = 0u;
    100   auto visit_tables = [&](const std::vector<Table::InternalTable>& tables)
    101       NO_THREAD_SAFETY_ANALYSIS {
    102     for (const Table::InternalTable& table : tables) {
    103       // Determine if we want to visit the table based on the flags..
    104       const bool visit =
    105           (visit_boot_images && table.IsBootImage()) ||
    106           (visit_non_boot_images && !table.IsBootImage());
    107       if (visit) {
    108         ret += table.set_.size();
    109       }
    110     }
    111   };
    112   visit_tables(strong_interns_.tables_);
    113   visit_tables(weak_interns_.tables_);
    114   return ret;
    115 }
    116 
    117 }  // namespace art
    118 
    119 #endif  // ART_RUNTIME_INTERN_TABLE_INL_H_
    120