|  | /* | 
|  | * Copyright (C) 2015 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_CLASS_TABLE_H_ | 
|  | #define ART_RUNTIME_CLASS_TABLE_H_ | 
|  |  | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/allocator.h" | 
|  | #include "base/hash_set.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/mutex.h" | 
|  | #include "gc_root.h" | 
|  | #include "obj_ptr.h" | 
|  |  | 
|  | namespace art { | 
|  |  | 
|  | class OatFile; | 
|  |  | 
|  | namespace linker { | 
|  | class ImageWriter; | 
|  | }  // namespace linker | 
|  |  | 
|  | namespace linker { | 
|  | class OatWriter; | 
|  | }  // namespace linker | 
|  |  | 
|  | namespace mirror { | 
|  | class Class; | 
|  | class ClassLoader; | 
|  | class Object; | 
|  | }  // namespace mirror | 
|  |  | 
|  | // Each loader has a ClassTable | 
|  | class ClassTable { | 
|  | public: | 
|  | class TableSlot { | 
|  | public: | 
|  | TableSlot() : data_(0u) {} | 
|  |  | 
|  | TableSlot(const TableSlot& copy) : data_(copy.data_.load(std::memory_order_relaxed)) {} | 
|  |  | 
|  | explicit TableSlot(ObjPtr<mirror::Class> klass); | 
|  |  | 
|  | TableSlot(ObjPtr<mirror::Class> klass, uint32_t descriptor_hash); | 
|  |  | 
|  | TableSlot& operator=(const TableSlot& copy) { | 
|  | data_.store(copy.data_.load(std::memory_order_relaxed), std::memory_order_relaxed); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | bool IsNull() const REQUIRES_SHARED(Locks::mutator_lock_) { | 
|  | return Read<kWithoutReadBarrier>() == nullptr; | 
|  | } | 
|  |  | 
|  | uint32_t Hash() const { | 
|  | return MaskHash(data_.load(std::memory_order_relaxed)); | 
|  | } | 
|  |  | 
|  | static uint32_t MaskHash(uint32_t hash) { | 
|  | return hash & kHashMask; | 
|  | } | 
|  |  | 
|  | bool MaskedHashEquals(uint32_t other) const { | 
|  | return MaskHash(other) == Hash(); | 
|  | } | 
|  |  | 
|  | static uint32_t HashDescriptor(ObjPtr<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier> | 
|  | mirror::Class* Read() const REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // NO_THREAD_SAFETY_ANALYSIS since the visitor may require heap bitmap lock. | 
|  | template<typename Visitor> | 
|  | void VisitRoot(const Visitor& visitor) const NO_THREAD_SAFETY_ANALYSIS; | 
|  |  | 
|  | private: | 
|  | // Extract a raw pointer from an address. | 
|  | static ObjPtr<mirror::Class> ExtractPtr(uint32_t data) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | static uint32_t Encode(ObjPtr<mirror::Class> klass, uint32_t hash_bits) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Data contains the class pointer GcRoot as well as the low bits of the descriptor hash. | 
|  | mutable Atomic<uint32_t> data_; | 
|  | static const uint32_t kHashMask = kObjectAlignment - 1; | 
|  | }; | 
|  |  | 
|  | using DescriptorHashPair = std::pair<const char*, uint32_t>; | 
|  |  | 
|  | class ClassDescriptorHashEquals { | 
|  | public: | 
|  | // uint32_t for cross compilation. | 
|  | uint32_t operator()(const TableSlot& slot) const NO_THREAD_SAFETY_ANALYSIS; | 
|  | // Same class loader and descriptor. | 
|  | bool operator()(const TableSlot& a, const TableSlot& b) const | 
|  | NO_THREAD_SAFETY_ANALYSIS; | 
|  | // Same descriptor. | 
|  | bool operator()(const TableSlot& a, const DescriptorHashPair& b) const | 
|  | NO_THREAD_SAFETY_ANALYSIS; | 
|  | // uint32_t for cross compilation. | 
|  | uint32_t operator()(const DescriptorHashPair& pair) const NO_THREAD_SAFETY_ANALYSIS; | 
|  | }; | 
|  |  | 
|  | class TableSlotEmptyFn { | 
|  | public: | 
|  | void MakeEmpty(TableSlot& item) const NO_THREAD_SAFETY_ANALYSIS { | 
|  | item = TableSlot(); | 
|  | DCHECK(IsEmpty(item)); | 
|  | } | 
|  | bool IsEmpty(const TableSlot& item) const NO_THREAD_SAFETY_ANALYSIS { | 
|  | return item.IsNull(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Hash set that hashes class descriptor, and compares descriptors and class loaders. Results | 
|  | // should be compared for a matching class descriptor and class loader. | 
|  | typedef HashSet<TableSlot, | 
|  | TableSlotEmptyFn, | 
|  | ClassDescriptorHashEquals, | 
|  | ClassDescriptorHashEquals, | 
|  | TrackingAllocator<TableSlot, kAllocatorTagClassTable>> ClassSet; | 
|  |  | 
|  | ClassTable(); | 
|  |  | 
|  | // Used by image writer for checking. | 
|  | bool Contains(ObjPtr<mirror::Class> klass) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Freeze the current class tables by allocating a new table and never updating or modifying the | 
|  | // existing table. This helps prevents dirty pages after caused by inserting after zygote fork. | 
|  | void FreezeSnapshot() | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Returns the number of classes in previous snapshots defined by `defining_loader`. | 
|  | size_t NumZygoteClasses(ObjPtr<mirror::ClassLoader> defining_loader) const | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Returns all off the classes in the lastest snapshot defined by `defining_loader`. | 
|  | size_t NumNonZygoteClasses(ObjPtr<mirror::ClassLoader> defining_loader) const | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Returns the number of classes in previous snapshots no matter the defining loader. | 
|  | size_t NumReferencedZygoteClasses() const | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Returns all off the classes in the lastest snapshot no matter the defining loader. | 
|  | size_t NumReferencedNonZygoteClasses() const | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Update a class in the table with the new class. Returns the existing class which was replaced. | 
|  | mirror::Class* UpdateClass(const char* descriptor, mirror::Class* new_klass, size_t hash) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // NO_THREAD_SAFETY_ANALYSIS for object marking requiring heap bitmap lock. | 
|  | template<class Visitor> | 
|  | void VisitRoots(Visitor& visitor) | 
|  | NO_THREAD_SAFETY_ANALYSIS | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | template<class Visitor> | 
|  | void VisitRoots(const Visitor& visitor) | 
|  | NO_THREAD_SAFETY_ANALYSIS | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Stops visit if the visitor returns false. | 
|  | template <typename Visitor, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> | 
|  | bool Visit(Visitor& visitor) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | template <typename Visitor, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> | 
|  | bool Visit(const Visitor& visitor) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Return the first class that matches the descriptor. Returns null if there are none. | 
|  | mirror::Class* Lookup(const char* descriptor, size_t hash) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Return the first class that matches the descriptor of klass. Returns null if there are none. | 
|  | mirror::Class* LookupByDescriptor(ObjPtr<mirror::Class> klass) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Try to insert a class and return the inserted class if successful. If another class | 
|  | // with the same descriptor is already in the table, return the existing entry. | 
|  | ObjPtr<mirror::Class> TryInsert(ObjPtr<mirror::Class> klass) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void Insert(ObjPtr<mirror::Class> klass) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void InsertWithHash(ObjPtr<mirror::Class> klass, size_t hash) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Returns true if the class was found and removed, false otherwise. | 
|  | bool Remove(const char* descriptor) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Return true if we inserted the strong root, false if it already exists. | 
|  | bool InsertStrongRoot(ObjPtr<mirror::Object> obj) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Return true if we inserted the oat file, false if it already exists. | 
|  | bool InsertOatFile(const OatFile* oat_file) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Combines all of the tables into one class set. | 
|  | size_t WriteToMemory(uint8_t* ptr) const | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Read a table from ptr and put it at the front of the class set. | 
|  | size_t ReadFromMemory(uint8_t* ptr) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Add a class set to the front of classes. | 
|  | void AddClassSet(ClassSet&& set) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Clear strong roots (other than classes themselves). | 
|  | void ClearStrongRoots() | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Filter strong roots (other than classes themselves). | 
|  | template <typename Filter> | 
|  | void RemoveStrongRoots(const Filter& filter) | 
|  | REQUIRES(!lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | ReaderWriterMutex& GetLock() { | 
|  | return lock_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Only copies classes. | 
|  | void CopyWithoutLocks(const ClassTable& source_table) NO_THREAD_SAFETY_ANALYSIS; | 
|  | void InsertWithoutLocks(ObjPtr<mirror::Class> klass) NO_THREAD_SAFETY_ANALYSIS; | 
|  |  | 
|  | size_t CountDefiningLoaderClasses(ObjPtr<mirror::ClassLoader> defining_loader, | 
|  | const ClassSet& set) const | 
|  | REQUIRES(lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Return true if we inserted the oat file, false if it already exists. | 
|  | bool InsertOatFileLocked(const OatFile* oat_file) | 
|  | REQUIRES(lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Lock to guard inserting and removing. | 
|  | mutable ReaderWriterMutex lock_; | 
|  | // We have a vector to help prevent dirty pages after the zygote forks by calling FreezeSnapshot. | 
|  | std::vector<ClassSet> classes_ GUARDED_BY(lock_); | 
|  | // Extra strong roots that can be either dex files or dex caches. Dex files used by the class | 
|  | // loader which may not be owned by the class loader must be held strongly live. Also dex caches | 
|  | // are held live to prevent them being unloading once they have classes in them. | 
|  | std::vector<GcRoot<mirror::Object>> strong_roots_ GUARDED_BY(lock_); | 
|  | // Keep track of oat files with GC roots associated with dex caches in `strong_roots_`. | 
|  | std::vector<const OatFile*> oat_files_ GUARDED_BY(lock_); | 
|  |  | 
|  | friend class linker::ImageWriter;  // for InsertWithoutLocks. | 
|  | }; | 
|  |  | 
|  | }  // namespace art | 
|  |  | 
|  | #endif  // ART_RUNTIME_CLASS_TABLE_H_ |