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 "dex/utf.h"
24 #include "gc_root-inl.h"
25 #include "mirror/class.h"
26 #include "oat/oat_file.h"
27 #include "obj_ptr-inl.h"
28 
29 namespace art HIDDEN {
30 
TableSlot(ObjPtr<mirror::Class> klass)31 inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass)
32     : TableSlot(klass, klass->DescriptorHash()) {}
33 
operator()34 inline uint32_t ClassTable::ClassDescriptorHash::operator()(const TableSlot& slot) const {
35   // No read barriers needed, we're reading a chain of constant references
36   // for comparison with null and retrieval of constant primitive data.
37   // See `ReadBarrierOption` and `Class::DescriptorHash()`.
38   return slot.Read<kWithoutReadBarrier>()->DescriptorHash();
39 }
40 
operator()41 inline uint32_t ClassTable::ClassDescriptorHash::operator()(const DescriptorHashPair& pair) const {
42   DCHECK_EQ(ComputeModifiedUtf8Hash(pair.first), pair.second);
43   return pair.second;
44 }
45 
operator()46 inline bool ClassTable::ClassDescriptorEquals::operator()(const TableSlot& a,
47                                                           const TableSlot& b) const {
48   // No read barrier needed, we're reading a chain of constant references
49   // for comparison with null and retrieval of constant primitive data.
50   // See ReadBarrierOption and `Class::DescriptorEquals()`.
51   if (a.Hash() != b.Hash()) {
52     DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.Read<kWithoutReadBarrier>()));
53     return false;
54   }
55   return a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.Read<kWithoutReadBarrier>());
56 }
57 
operator()58 inline bool ClassTable::ClassDescriptorEquals::operator()(const TableSlot& a,
59                                                           const DescriptorHashPair& b) const {
60   // No read barrier needed, we're reading a chain of constant references for comparison
61   // with null and retrieval of constant primitive data. See ReadBarrierOption.
62   if (!a.MaskedHashEquals(b.second)) {
63     DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.first));
64     return false;
65   }
66   return a.Read<kWithoutReadBarrier>()->DescriptorEquals(b.first);
67 }
68 
69 template <class Visitor>
VisitRoots(Visitor & visitor,bool skip_classes)70 void ClassTable::VisitRoots(Visitor& visitor, bool skip_classes) {
71   ReaderMutexLock mu(Thread::Current(), lock_);
72   if (!skip_classes) {
73     for (ClassSet& class_set : classes_) {
74       for (TableSlot& table_slot : class_set) {
75         table_slot.VisitRoot(visitor);
76       }
77     }
78   }
79   for (GcRoot<mirror::Object>& root : strong_roots_) {
80     visitor.VisitRoot(root.AddressWithoutBarrier());
81   }
82   for (const OatFile* oat_file : oat_files_) {
83     for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
84       visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
85     }
86   }
87 }
88 
89 template <class Visitor>
VisitRoots(const Visitor & visitor,bool skip_classes)90 void ClassTable::VisitRoots(const Visitor& visitor, bool skip_classes) {
91   ReaderMutexLock mu(Thread::Current(), lock_);
92   if (!skip_classes) {
93     for (ClassSet& class_set : classes_) {
94       for (TableSlot& table_slot : class_set) {
95         table_slot.VisitRoot(visitor);
96       }
97     }
98   }
99   for (GcRoot<mirror::Object>& root : strong_roots_) {
100     visitor.VisitRoot(root.AddressWithoutBarrier());
101   }
102   for (const OatFile* oat_file : oat_files_) {
103     for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
104       visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
105     }
106   }
107 }
108 
109 template <class Condition, class Visitor>
VisitClassesIfConditionMet(Condition & cond,Visitor & visitor)110 void ClassTable::VisitClassesIfConditionMet(Condition& cond, Visitor& visitor) {
111   ReaderMutexLock mu(Thread::Current(), lock_);
112   for (ClassSet& class_set : classes_) {
113     if (cond(class_set)) {
114       for (TableSlot& table_slot : class_set) {
115         table_slot.VisitRoot(visitor);
116       }
117     }
118   }
119 }
120 
121 template <typename Visitor>
122 class ClassTable::TableSlot::ClassAndRootVisitor {
123  public:
ClassAndRootVisitor(Visitor & visitor)124   explicit ClassAndRootVisitor(Visitor& visitor) : visitor_(visitor) {}
125 
VisitRoot(mirror::CompressedReference<mirror::Object> * klass)126   void VisitRoot(mirror::CompressedReference<mirror::Object>* klass) const
127       REQUIRES_SHARED(Locks::mutator_lock_) {
128     DCHECK(!klass->IsNull());
129     // Visit roots in the klass object
130     visitor_(klass->AsMirrorPtr());
131     // Visit the GC-root holding klass' reference
132     visitor_.VisitRoot(klass);
133   }
134 
135  private:
136   Visitor& visitor_;
137 };
138 
139 template <typename Visitor>
VisitClassesAndRoots(Visitor & visitor)140 void ClassTable::VisitClassesAndRoots(Visitor& visitor) {
141   TableSlot::ClassAndRootVisitor class_visitor(visitor);
142   ReaderMutexLock mu(Thread::Current(), lock_);
143   for (ClassSet& class_set : classes_) {
144     for (TableSlot& table_slot : class_set) {
145       table_slot.VisitRoot(class_visitor);
146     }
147   }
148   for (GcRoot<mirror::Object>& root : strong_roots_) {
149     visitor.VisitRoot(root.AddressWithoutBarrier());
150   }
151   for (const OatFile* oat_file : oat_files_) {
152     for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
153       visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
154     }
155   }
156 }
157 
158 template <ReadBarrierOption kReadBarrierOption, typename Visitor>
Visit(Visitor & visitor)159 bool ClassTable::Visit(Visitor& visitor) {
160   ReaderMutexLock mu(Thread::Current(), lock_);
161   for (ClassSet& class_set : classes_) {
162     for (TableSlot& table_slot : class_set) {
163       if (!visitor(table_slot.Read<kReadBarrierOption>())) {
164         return false;
165       }
166     }
167   }
168   return true;
169 }
170 
171 template <ReadBarrierOption kReadBarrierOption, typename Visitor>
Visit(const Visitor & visitor)172 bool ClassTable::Visit(const Visitor& visitor) {
173   ReaderMutexLock mu(Thread::Current(), lock_);
174   for (ClassSet& class_set : classes_) {
175     for (TableSlot& table_slot : class_set) {
176       if (!visitor(table_slot.Read<kReadBarrierOption>())) {
177         return false;
178       }
179     }
180   }
181   return true;
182 }
183 
IsNull()184 inline bool ClassTable::TableSlot::IsNull() const {
185   return Read<kWithoutReadBarrier>() == nullptr;
186 }
187 
188 template<ReadBarrierOption kReadBarrierOption>
Read()189 inline ObjPtr<mirror::Class> ClassTable::TableSlot::Read() const {
190   const uint32_t before = data_.load(std::memory_order_relaxed);
191   const ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
192   const ObjPtr<mirror::Class> after_ptr(
193       GcRoot<mirror::Class>(before_ptr).Read<kReadBarrierOption>());
194   if (kReadBarrierOption != kWithoutReadBarrier && before_ptr != after_ptr) {
195     // If another thread raced and updated the reference, do not store the read barrier updated
196     // one.
197     data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
198   }
199   return after_ptr;
200 }
201 
202 template<typename Visitor>
VisitRoot(const Visitor & visitor)203 inline void ClassTable::TableSlot::VisitRoot(const Visitor& visitor) const {
204   const uint32_t before = data_.load(std::memory_order_relaxed);
205   ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
206   GcRoot<mirror::Class> root(before_ptr);
207   visitor.VisitRoot(root.AddressWithoutBarrier());
208   ObjPtr<mirror::Class> after_ptr(root.Read<kWithoutReadBarrier>());
209   if (before_ptr != after_ptr) {
210     // If another thread raced and updated the reference, do not store the read barrier updated
211     // one.
212     data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
213   }
214 }
215 
ExtractPtr(uint32_t data)216 inline ObjPtr<mirror::Class> ClassTable::TableSlot::ExtractPtr(uint32_t data) {
217   return reinterpret_cast<mirror::Class*>(data & ~kHashMask);
218 }
219 
Encode(ObjPtr<mirror::Class> klass,uint32_t hash_bits)220 inline uint32_t ClassTable::TableSlot::Encode(ObjPtr<mirror::Class> klass, uint32_t hash_bits) {
221   DCHECK_LE(hash_bits, kHashMask);
222   return reinterpret_cast<uintptr_t>(klass.Ptr()) | hash_bits;
223 }
224 
TableSlot(ObjPtr<mirror::Class> klass,uint32_t descriptor_hash)225 inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass, uint32_t descriptor_hash)
226     : data_(Encode(klass, MaskHash(descriptor_hash))) {
227   DCHECK_EQ(descriptor_hash, klass->DescriptorHash());
228 }
229 
TableSlot(uint32_t ptr,uint32_t descriptor_hash)230 inline ClassTable::TableSlot::TableSlot(uint32_t ptr, uint32_t descriptor_hash)
231     : data_(ptr | MaskHash(descriptor_hash)) {
232   DCHECK_ALIGNED(ptr, kObjectAlignment);
233 }
234 
235 template <typename Filter>
RemoveStrongRoots(const Filter & filter)236 inline void ClassTable::RemoveStrongRoots(const Filter& filter) {
237   WriterMutexLock mu(Thread::Current(), lock_);
238   strong_roots_.erase(std::remove_if(strong_roots_.begin(), strong_roots_.end(), filter),
239                       strong_roots_.end());
240 }
241 
LookupByDescriptor(ObjPtr<mirror::Class> klass)242 inline ObjPtr<mirror::Class> ClassTable::LookupByDescriptor(ObjPtr<mirror::Class> klass) {
243   uint32_t hash = klass->DescriptorHash();
244   std::string temp;
245   const char* descriptor = klass->GetDescriptor(&temp);
246   return Lookup(descriptor, hash);
247 }
248 
Size()249 inline size_t ClassTable::Size() const {
250   ReaderMutexLock mu(Thread::Current(), lock_);
251   return classes_.size();
252 }
253 
254 }  // namespace art
255 
256 #endif  // ART_RUNTIME_CLASS_TABLE_INL_H_
257