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