• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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