1 /* 2 * Copyright (C) 2014 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_READ_BARRIER_INL_H_ 18 #define ART_RUNTIME_READ_BARRIER_INL_H_ 19 20 #include "read_barrier.h" 21 22 #include "gc/collector/concurrent_copying-inl.h" 23 #include "gc/heap.h" 24 #include "mirror/object_reference.h" 25 #include "mirror/reference.h" 26 #include "runtime.h" 27 #include "utils.h" 28 29 namespace art { 30 31 template <typename MirrorType, ReadBarrierOption kReadBarrierOption, bool kAlwaysUpdateField> 32 inline MirrorType* ReadBarrier::Barrier( 33 mirror::Object* obj, MemberOffset offset, mirror::HeapReference<MirrorType>* ref_addr) { 34 constexpr bool with_read_barrier = kReadBarrierOption == kWithReadBarrier; 35 if (kUseReadBarrier && with_read_barrier) { 36 if (kIsDebugBuild) { 37 Thread* const self = Thread::Current(); 38 if (self != nullptr) { 39 CHECK_EQ(self->GetDebugDisallowReadBarrierCount(), 0u); 40 } 41 } 42 if (kUseBakerReadBarrier) { 43 // The higher bits of the rb_ptr, rb_ptr_high_bits (must be zero) 44 // is used to create artificial data dependency from the is_gray 45 // load to the ref field (ptr) load to avoid needing a load-load 46 // barrier between the two. 47 uintptr_t rb_ptr_high_bits; 48 bool is_gray = HasGrayReadBarrierPointer(obj, &rb_ptr_high_bits); 49 ref_addr = reinterpret_cast<mirror::HeapReference<MirrorType>*>( 50 rb_ptr_high_bits | reinterpret_cast<uintptr_t>(ref_addr)); 51 MirrorType* ref = ref_addr->AsMirrorPtr(); 52 MirrorType* old_ref = ref; 53 if (is_gray) { 54 // Slow-path. 55 ref = reinterpret_cast<MirrorType*>(Mark(ref)); 56 // If kAlwaysUpdateField is true, update the field atomically. This may fail if mutator 57 // updates before us, but it's ok. 58 if (kAlwaysUpdateField && ref != old_ref) { 59 obj->CasFieldStrongRelaxedObjectWithoutWriteBarrier<false, false>( 60 offset, old_ref, ref); 61 } 62 } 63 if (kEnableReadBarrierInvariantChecks) { 64 CHECK_EQ(rb_ptr_high_bits, 0U) << obj << " rb_ptr=" << obj->GetReadBarrierPointer(); 65 } 66 AssertToSpaceInvariant(obj, offset, ref); 67 return ref; 68 } else if (kUseBrooksReadBarrier) { 69 // To be implemented. 70 return ref_addr->AsMirrorPtr(); 71 } else if (kUseTableLookupReadBarrier) { 72 MirrorType* ref = ref_addr->AsMirrorPtr(); 73 MirrorType* old_ref = ref; 74 // The heap or the collector can be null at startup. TODO: avoid the need for this null check. 75 gc::Heap* heap = Runtime::Current()->GetHeap(); 76 if (heap != nullptr && heap->GetReadBarrierTable()->IsSet(old_ref)) { 77 ref = reinterpret_cast<MirrorType*>(Mark(old_ref)); 78 // Update the field atomically. This may fail if mutator updates before us, but it's ok. 79 if (ref != old_ref) { 80 obj->CasFieldStrongRelaxedObjectWithoutWriteBarrier<false, false>( 81 offset, old_ref, ref); 82 } 83 } 84 AssertToSpaceInvariant(obj, offset, ref); 85 return ref; 86 } else { 87 LOG(FATAL) << "Unexpected read barrier type"; 88 UNREACHABLE(); 89 } 90 } else { 91 // No read barrier. 92 return ref_addr->AsMirrorPtr(); 93 } 94 } 95 96 template <typename MirrorType, ReadBarrierOption kReadBarrierOption> 97 inline MirrorType* ReadBarrier::BarrierForRoot(MirrorType** root, 98 GcRootSource* gc_root_source) { 99 MirrorType* ref = *root; 100 const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier; 101 if (kUseReadBarrier && with_read_barrier) { 102 if (kIsDebugBuild) { 103 Thread* const self = Thread::Current(); 104 if (self != nullptr) { 105 CHECK_EQ(self->GetDebugDisallowReadBarrierCount(), 0u); 106 } 107 } 108 if (kUseBakerReadBarrier) { 109 // TODO: separate the read barrier code from the collector code more. 110 Thread* self = Thread::Current(); 111 if (self != nullptr && self->GetIsGcMarking()) { 112 ref = reinterpret_cast<MirrorType*>(Mark(ref)); 113 } 114 AssertToSpaceInvariant(gc_root_source, ref); 115 return ref; 116 } else if (kUseBrooksReadBarrier) { 117 // To be implemented. 118 return ref; 119 } else if (kUseTableLookupReadBarrier) { 120 Thread* self = Thread::Current(); 121 if (self != nullptr && 122 self->GetIsGcMarking() && 123 Runtime::Current()->GetHeap()->GetReadBarrierTable()->IsSet(ref)) { 124 MirrorType* old_ref = ref; 125 ref = reinterpret_cast<MirrorType*>(Mark(old_ref)); 126 // Update the field atomically. This may fail if mutator updates before us, but it's ok. 127 if (ref != old_ref) { 128 Atomic<mirror::Object*>* atomic_root = reinterpret_cast<Atomic<mirror::Object*>*>(root); 129 atomic_root->CompareExchangeStrongRelaxed(old_ref, ref); 130 } 131 } 132 AssertToSpaceInvariant(gc_root_source, ref); 133 return ref; 134 } else { 135 LOG(FATAL) << "Unexpected read barrier type"; 136 UNREACHABLE(); 137 } 138 } else { 139 return ref; 140 } 141 } 142 143 // TODO: Reduce copy paste 144 template <typename MirrorType, ReadBarrierOption kReadBarrierOption> 145 inline MirrorType* ReadBarrier::BarrierForRoot(mirror::CompressedReference<MirrorType>* root, 146 GcRootSource* gc_root_source) { 147 MirrorType* ref = root->AsMirrorPtr(); 148 const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier; 149 if (with_read_barrier && kUseBakerReadBarrier) { 150 // TODO: separate the read barrier code from the collector code more. 151 Thread* self = Thread::Current(); 152 if (self != nullptr && self->GetIsGcMarking()) { 153 ref = reinterpret_cast<MirrorType*>(Mark(ref)); 154 } 155 AssertToSpaceInvariant(gc_root_source, ref); 156 return ref; 157 } else if (with_read_barrier && kUseBrooksReadBarrier) { 158 // To be implemented. 159 return ref; 160 } else if (with_read_barrier && kUseTableLookupReadBarrier) { 161 Thread* self = Thread::Current(); 162 if (self != nullptr && 163 self->GetIsGcMarking() && 164 Runtime::Current()->GetHeap()->GetReadBarrierTable()->IsSet(ref)) { 165 auto old_ref = mirror::CompressedReference<MirrorType>::FromMirrorPtr(ref); 166 ref = reinterpret_cast<MirrorType*>(Mark(ref)); 167 auto new_ref = mirror::CompressedReference<MirrorType>::FromMirrorPtr(ref); 168 // Update the field atomically. This may fail if mutator updates before us, but it's ok. 169 if (new_ref.AsMirrorPtr() != old_ref.AsMirrorPtr()) { 170 auto* atomic_root = 171 reinterpret_cast<Atomic<mirror::CompressedReference<MirrorType>>*>(root); 172 atomic_root->CompareExchangeStrongRelaxed(old_ref, new_ref); 173 } 174 } 175 AssertToSpaceInvariant(gc_root_source, ref); 176 return ref; 177 } else { 178 return ref; 179 } 180 } 181 182 inline bool ReadBarrier::IsDuringStartup() { 183 gc::Heap* heap = Runtime::Current()->GetHeap(); 184 if (heap == nullptr) { 185 // During startup, the heap can be null. 186 return true; 187 } 188 if (heap->CurrentCollectorType() != gc::kCollectorTypeCC) { 189 // CC isn't running. 190 return true; 191 } 192 gc::collector::ConcurrentCopying* collector = heap->ConcurrentCopyingCollector(); 193 if (collector == nullptr) { 194 // During startup, the collector can be null. 195 return true; 196 } 197 return false; 198 } 199 200 inline void ReadBarrier::AssertToSpaceInvariant(mirror::Object* obj, MemberOffset offset, 201 mirror::Object* ref) { 202 if (kEnableToSpaceInvariantChecks || kIsDebugBuild) { 203 if (ref == nullptr || IsDuringStartup()) { 204 return; 205 } 206 Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()-> 207 AssertToSpaceInvariant(obj, offset, ref); 208 } 209 } 210 211 inline void ReadBarrier::AssertToSpaceInvariant(GcRootSource* gc_root_source, 212 mirror::Object* ref) { 213 if (kEnableToSpaceInvariantChecks || kIsDebugBuild) { 214 if (ref == nullptr || IsDuringStartup()) { 215 return; 216 } 217 Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()-> 218 AssertToSpaceInvariant(gc_root_source, ref); 219 } 220 } 221 222 inline mirror::Object* ReadBarrier::Mark(mirror::Object* obj) { 223 return Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->Mark(obj); 224 } 225 226 inline bool ReadBarrier::HasGrayReadBarrierPointer(mirror::Object* obj, 227 uintptr_t* out_rb_ptr_high_bits) { 228 mirror::Object* rb_ptr = obj->GetReadBarrierPointer(); 229 uintptr_t rb_ptr_bits = reinterpret_cast<uintptr_t>(rb_ptr); 230 uintptr_t rb_ptr_low_bits = rb_ptr_bits & rb_ptr_mask_; 231 if (kEnableReadBarrierInvariantChecks) { 232 CHECK(rb_ptr_low_bits == white_ptr_ || rb_ptr_low_bits == gray_ptr_ || 233 rb_ptr_low_bits == black_ptr_) 234 << "obj=" << obj << " rb_ptr=" << rb_ptr << " " << PrettyTypeOf(obj); 235 } 236 bool is_gray = rb_ptr_low_bits == gray_ptr_; 237 // The high bits are supposed to be zero. We check this on the caller side. 238 *out_rb_ptr_high_bits = rb_ptr_bits & ~rb_ptr_mask_; 239 return is_gray; 240 } 241 242 } // namespace art 243 244 #endif // ART_RUNTIME_READ_BARRIER_INL_H_ 245