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