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