1 /*
2  * Copyright (C) 2015 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_CLASS_TABLE_INL_H_
18 #define ART_RUNTIME_CLASS_TABLE_INL_H_
19 
20 #include "class_table.h"
21 
22 #include "base/mutex-inl.h"
23 #include "gc_root-inl.h"
24 #include "mirror/class.h"
25 #include "oat_file.h"
26 #include "obj_ptr-inl.h"
27 
28 namespace art {
29 
30 template<class Visitor>
VisitRoots(Visitor & visitor)31 void ClassTable::VisitRoots(Visitor& visitor) {
32   ReaderMutexLock mu(Thread::Current(), lock_);
33   for (ClassSet& class_set : classes_) {
34     for (TableSlot& table_slot : class_set) {
35       table_slot.VisitRoot(visitor);
36     }
37   }
38   for (GcRoot<mirror::Object>& root : strong_roots_) {
39     visitor.VisitRoot(root.AddressWithoutBarrier());
40   }
41   for (const OatFile* oat_file : oat_files_) {
42     for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
43       visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
44     }
45   }
46 }
47 
48 template<class Visitor>
VisitRoots(const Visitor & visitor)49 void ClassTable::VisitRoots(const Visitor& visitor) {
50   ReaderMutexLock mu(Thread::Current(), lock_);
51   for (ClassSet& class_set : classes_) {
52     for (TableSlot& table_slot : class_set) {
53       table_slot.VisitRoot(visitor);
54     }
55   }
56   for (GcRoot<mirror::Object>& root : strong_roots_) {
57     visitor.VisitRoot(root.AddressWithoutBarrier());
58   }
59   for (const OatFile* oat_file : oat_files_) {
60     for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
61       visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
62     }
63   }
64 }
65 
66 template <typename Visitor, ReadBarrierOption kReadBarrierOption>
Visit(Visitor & visitor)67 bool ClassTable::Visit(Visitor& visitor) {
68   ReaderMutexLock mu(Thread::Current(), lock_);
69   for (ClassSet& class_set : classes_) {
70     for (TableSlot& table_slot : class_set) {
71       if (!visitor(table_slot.Read<kReadBarrierOption>())) {
72         return false;
73       }
74     }
75   }
76   return true;
77 }
78 
79 template <typename Visitor, ReadBarrierOption kReadBarrierOption>
Visit(const Visitor & visitor)80 bool ClassTable::Visit(const Visitor& visitor) {
81   ReaderMutexLock mu(Thread::Current(), lock_);
82   for (ClassSet& class_set : classes_) {
83     for (TableSlot& table_slot : class_set) {
84       if (!visitor(table_slot.Read<kReadBarrierOption>())) {
85         return false;
86       }
87     }
88   }
89   return true;
90 }
91 
IsNull()92 inline bool ClassTable::TableSlot::IsNull() const {
93   return Read<kWithoutReadBarrier>() == nullptr;
94 }
95 
96 template<ReadBarrierOption kReadBarrierOption>
Read()97 inline ObjPtr<mirror::Class> ClassTable::TableSlot::Read() const {
98   const uint32_t before = data_.load(std::memory_order_relaxed);
99   const ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
100   const ObjPtr<mirror::Class> after_ptr(
101       GcRoot<mirror::Class>(before_ptr).Read<kReadBarrierOption>());
102   if (kReadBarrierOption != kWithoutReadBarrier && before_ptr != after_ptr) {
103     // If another thread raced and updated the reference, do not store the read barrier updated
104     // one.
105     data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
106   }
107   return after_ptr;
108 }
109 
110 template<typename Visitor>
VisitRoot(const Visitor & visitor)111 inline void ClassTable::TableSlot::VisitRoot(const Visitor& visitor) const {
112   const uint32_t before = data_.load(std::memory_order_relaxed);
113   ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
114   GcRoot<mirror::Class> root(before_ptr);
115   visitor.VisitRoot(root.AddressWithoutBarrier());
116   ObjPtr<mirror::Class> after_ptr(root.Read<kWithoutReadBarrier>());
117   if (before_ptr != after_ptr) {
118     // If another thread raced and updated the reference, do not store the read barrier updated
119     // one.
120     data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
121   }
122 }
123 
ExtractPtr(uint32_t data)124 inline ObjPtr<mirror::Class> ClassTable::TableSlot::ExtractPtr(uint32_t data) {
125   return reinterpret_cast<mirror::Class*>(data & ~kHashMask);
126 }
127 
Encode(ObjPtr<mirror::Class> klass,uint32_t hash_bits)128 inline uint32_t ClassTable::TableSlot::Encode(ObjPtr<mirror::Class> klass, uint32_t hash_bits) {
129   DCHECK_LE(hash_bits, kHashMask);
130   return reinterpret_cast<uintptr_t>(klass.Ptr()) | hash_bits;
131 }
132 
TableSlot(ObjPtr<mirror::Class> klass,uint32_t descriptor_hash)133 inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass, uint32_t descriptor_hash)
134     : data_(Encode(klass, MaskHash(descriptor_hash))) {
135   DCHECK_EQ(descriptor_hash, HashDescriptor(klass));
136 }
137 
138 template <typename Filter>
RemoveStrongRoots(const Filter & filter)139 inline void ClassTable::RemoveStrongRoots(const Filter& filter) {
140   WriterMutexLock mu(Thread::Current(), lock_);
141   strong_roots_.erase(std::remove_if(strong_roots_.begin(), strong_roots_.end(), filter),
142                       strong_roots_.end());
143 }
144 
145 }  // namespace art
146 
147 #endif  // ART_RUNTIME_CLASS_TABLE_INL_H_
148