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 <ReadBarrierOption kReadBarrierOption, typename Visitor>
Visit(Visitor & visitor)108 bool ClassTable::Visit(Visitor& visitor) {
109 ReaderMutexLock mu(Thread::Current(), lock_);
110 for (ClassSet& class_set : classes_) {
111 for (TableSlot& table_slot : class_set) {
112 if (!visitor(table_slot.Read<kReadBarrierOption>())) {
113 return false;
114 }
115 }
116 }
117 return true;
118 }
119
120 template <ReadBarrierOption kReadBarrierOption, typename Visitor>
Visit(const Visitor & visitor)121 bool ClassTable::Visit(const Visitor& visitor) {
122 ReaderMutexLock mu(Thread::Current(), lock_);
123 for (ClassSet& class_set : classes_) {
124 for (TableSlot& table_slot : class_set) {
125 if (!visitor(table_slot.Read<kReadBarrierOption>())) {
126 return false;
127 }
128 }
129 }
130 return true;
131 }
132
IsNull()133 inline bool ClassTable::TableSlot::IsNull() const {
134 return Read<kWithoutReadBarrier>() == nullptr;
135 }
136
137 template<ReadBarrierOption kReadBarrierOption>
Read()138 inline ObjPtr<mirror::Class> ClassTable::TableSlot::Read() const {
139 const uint32_t before = data_.load(std::memory_order_relaxed);
140 const ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
141 const ObjPtr<mirror::Class> after_ptr(
142 GcRoot<mirror::Class>(before_ptr).Read<kReadBarrierOption>());
143 if (kReadBarrierOption != kWithoutReadBarrier && before_ptr != after_ptr) {
144 // If another thread raced and updated the reference, do not store the read barrier updated
145 // one.
146 data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
147 }
148 return after_ptr;
149 }
150
151 template<typename Visitor>
VisitRoot(const Visitor & visitor)152 inline void ClassTable::TableSlot::VisitRoot(const Visitor& visitor) const {
153 const uint32_t before = data_.load(std::memory_order_relaxed);
154 ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
155 GcRoot<mirror::Class> root(before_ptr);
156 visitor.VisitRoot(root.AddressWithoutBarrier());
157 ObjPtr<mirror::Class> after_ptr(root.Read<kWithoutReadBarrier>());
158 if (before_ptr != after_ptr) {
159 // If another thread raced and updated the reference, do not store the read barrier updated
160 // one.
161 data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
162 }
163 }
164
ExtractPtr(uint32_t data)165 inline ObjPtr<mirror::Class> ClassTable::TableSlot::ExtractPtr(uint32_t data) {
166 return reinterpret_cast<mirror::Class*>(data & ~kHashMask);
167 }
168
Encode(ObjPtr<mirror::Class> klass,uint32_t hash_bits)169 inline uint32_t ClassTable::TableSlot::Encode(ObjPtr<mirror::Class> klass, uint32_t hash_bits) {
170 DCHECK_LE(hash_bits, kHashMask);
171 return reinterpret_cast<uintptr_t>(klass.Ptr()) | hash_bits;
172 }
173
TableSlot(ObjPtr<mirror::Class> klass,uint32_t descriptor_hash)174 inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass, uint32_t descriptor_hash)
175 : data_(Encode(klass, MaskHash(descriptor_hash))) {
176 DCHECK_EQ(descriptor_hash, klass->DescriptorHash());
177 }
178
179 template <typename Filter>
RemoveStrongRoots(const Filter & filter)180 inline void ClassTable::RemoveStrongRoots(const Filter& filter) {
181 WriterMutexLock mu(Thread::Current(), lock_);
182 strong_roots_.erase(std::remove_if(strong_roots_.begin(), strong_roots_.end(), filter),
183 strong_roots_.end());
184 }
185
LookupByDescriptor(ObjPtr<mirror::Class> klass)186 inline ObjPtr<mirror::Class> ClassTable::LookupByDescriptor(ObjPtr<mirror::Class> klass) {
187 uint32_t hash = klass->DescriptorHash();
188 std::string temp;
189 const char* descriptor = klass->GetDescriptor(&temp);
190 return Lookup(descriptor, hash);
191 }
192
193 } // namespace art
194
195 #endif // ART_RUNTIME_CLASS_TABLE_INL_H_
196