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 
operator()31 inline uint32_t ClassTable::ClassDescriptorHash::operator()(const TableSlot& slot) const {
32   std::string temp;
33   // No read barrier needed, we're reading a chain of constant references for comparison
34   // with null and retrieval of constant primitive data. See ReadBarrierOption.
35   return ComputeModifiedUtf8Hash(slot.Read<kWithoutReadBarrier>()->GetDescriptor(&temp));
36 }
37 
operator()38 inline uint32_t ClassTable::ClassDescriptorHash::operator()(const DescriptorHashPair& pair) const {
39   DCHECK_EQ(ComputeModifiedUtf8Hash(pair.first), pair.second);
40   return pair.second;
41 }
42 
operator()43 inline bool ClassTable::ClassDescriptorEquals::operator()(const TableSlot& a,
44                                                           const TableSlot& b) const {
45   // No read barrier needed, we're reading a chain of constant references for comparison
46   // with null and retrieval of constant primitive data. See ReadBarrierOption.
47   if (a.Hash() != b.Hash()) {
48     std::string temp;
49     DCHECK(!a.Read<kWithoutReadBarrier>()->DescriptorEquals(
50         b.Read<kWithoutReadBarrier>()->GetDescriptor(&temp)));
51     return false;
52   }
53   std::string temp;
54   return a.Read<kWithoutReadBarrier>()->DescriptorEquals(
55       b.Read<kWithoutReadBarrier>()->GetDescriptor(&temp));
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)70 void ClassTable::VisitRoots(Visitor& visitor) {
71   ReaderMutexLock mu(Thread::Current(), lock_);
72   for (ClassSet& class_set : classes_) {
73     for (TableSlot& table_slot : class_set) {
74       table_slot.VisitRoot(visitor);
75     }
76   }
77   for (GcRoot<mirror::Object>& root : strong_roots_) {
78     visitor.VisitRoot(root.AddressWithoutBarrier());
79   }
80   for (const OatFile* oat_file : oat_files_) {
81     for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
82       visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
83     }
84   }
85 }
86 
87 template<class Visitor>
VisitRoots(const Visitor & visitor)88 void ClassTable::VisitRoots(const Visitor& visitor) {
89   ReaderMutexLock mu(Thread::Current(), lock_);
90   for (ClassSet& class_set : classes_) {
91     for (TableSlot& table_slot : class_set) {
92       table_slot.VisitRoot(visitor);
93     }
94   }
95   for (GcRoot<mirror::Object>& root : strong_roots_) {
96     visitor.VisitRoot(root.AddressWithoutBarrier());
97   }
98   for (const OatFile* oat_file : oat_files_) {
99     for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
100       visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
101     }
102   }
103 }
104 
105 template <typename Visitor, ReadBarrierOption kReadBarrierOption>
Visit(Visitor & visitor)106 bool ClassTable::Visit(Visitor& visitor) {
107   ReaderMutexLock mu(Thread::Current(), lock_);
108   for (ClassSet& class_set : classes_) {
109     for (TableSlot& table_slot : class_set) {
110       if (!visitor(table_slot.Read<kReadBarrierOption>())) {
111         return false;
112       }
113     }
114   }
115   return true;
116 }
117 
118 template <typename Visitor, ReadBarrierOption kReadBarrierOption>
Visit(const Visitor & visitor)119 bool ClassTable::Visit(const Visitor& visitor) {
120   ReaderMutexLock mu(Thread::Current(), lock_);
121   for (ClassSet& class_set : classes_) {
122     for (TableSlot& table_slot : class_set) {
123       if (!visitor(table_slot.Read<kReadBarrierOption>())) {
124         return false;
125       }
126     }
127   }
128   return true;
129 }
130 
IsNull()131 inline bool ClassTable::TableSlot::IsNull() const {
132   return Read<kWithoutReadBarrier>() == nullptr;
133 }
134 
135 template<ReadBarrierOption kReadBarrierOption>
Read()136 inline ObjPtr<mirror::Class> ClassTable::TableSlot::Read() const {
137   const uint32_t before = data_.load(std::memory_order_relaxed);
138   const ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
139   const ObjPtr<mirror::Class> after_ptr(
140       GcRoot<mirror::Class>(before_ptr).Read<kReadBarrierOption>());
141   if (kReadBarrierOption != kWithoutReadBarrier && before_ptr != after_ptr) {
142     // If another thread raced and updated the reference, do not store the read barrier updated
143     // one.
144     data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
145   }
146   return after_ptr;
147 }
148 
149 template<typename Visitor>
VisitRoot(const Visitor & visitor)150 inline void ClassTable::TableSlot::VisitRoot(const Visitor& visitor) const {
151   const uint32_t before = data_.load(std::memory_order_relaxed);
152   ObjPtr<mirror::Class> before_ptr(ExtractPtr(before));
153   GcRoot<mirror::Class> root(before_ptr);
154   visitor.VisitRoot(root.AddressWithoutBarrier());
155   ObjPtr<mirror::Class> after_ptr(root.Read<kWithoutReadBarrier>());
156   if (before_ptr != after_ptr) {
157     // If another thread raced and updated the reference, do not store the read barrier updated
158     // one.
159     data_.CompareAndSetStrongRelease(before, Encode(after_ptr, MaskHash(before)));
160   }
161 }
162 
ExtractPtr(uint32_t data)163 inline ObjPtr<mirror::Class> ClassTable::TableSlot::ExtractPtr(uint32_t data) {
164   return reinterpret_cast<mirror::Class*>(data & ~kHashMask);
165 }
166 
Encode(ObjPtr<mirror::Class> klass,uint32_t hash_bits)167 inline uint32_t ClassTable::TableSlot::Encode(ObjPtr<mirror::Class> klass, uint32_t hash_bits) {
168   DCHECK_LE(hash_bits, kHashMask);
169   return reinterpret_cast<uintptr_t>(klass.Ptr()) | hash_bits;
170 }
171 
TableSlot(ObjPtr<mirror::Class> klass,uint32_t descriptor_hash)172 inline ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass, uint32_t descriptor_hash)
173     : data_(Encode(klass, MaskHash(descriptor_hash))) {
174   DCHECK_EQ(descriptor_hash, HashDescriptor(klass));
175 }
176 
177 template <typename Filter>
RemoveStrongRoots(const Filter & filter)178 inline void ClassTable::RemoveStrongRoots(const Filter& filter) {
179   WriterMutexLock mu(Thread::Current(), lock_);
180   strong_roots_.erase(std::remove_if(strong_roots_.begin(), strong_roots_.end(), filter),
181                       strong_roots_.end());
182 }
183 
LookupByDescriptor(ObjPtr<mirror::Class> klass)184 inline ObjPtr<mirror::Class> ClassTable::LookupByDescriptor(ObjPtr<mirror::Class> klass) {
185   std::string temp;
186   const char* descriptor = klass->GetDescriptor(&temp);
187   uint32_t hash = TableSlot::HashDescriptor(klass);
188   return Lookup(descriptor, hash);
189 }
190 
191 }  // namespace art
192 
193 #endif  // ART_RUNTIME_CLASS_TABLE_INL_H_
194