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_BASE_DEBUG_STACK_H_ 18 #define ART_RUNTIME_BASE_DEBUG_STACK_H_ 19 20 #include "base/logging.h" 21 #include "base/macros.h" 22 #include "globals.h" 23 24 namespace art { 25 26 // Helper classes for reference counting to enforce construction/destruction order and 27 // usage of the top element of a stack in debug mode with no overhead in release mode. 28 29 // Reference counter. No references allowed in destructor or in explicitly called CheckNoRefs(). 30 template <bool kIsDebug> 31 class DebugStackRefCounterImpl; 32 // Reference. Allows an explicit check that it's the top reference. 33 template <bool kIsDebug> 34 class DebugStackReferenceImpl; 35 // Indirect top reference. Checks that the reference is the top reference when used. 36 template <bool kIsDebug> 37 class DebugStackIndirectTopRefImpl; 38 39 typedef DebugStackRefCounterImpl<kIsDebugBuild> DebugStackRefCounter; 40 typedef DebugStackReferenceImpl<kIsDebugBuild> DebugStackReference; 41 typedef DebugStackIndirectTopRefImpl<kIsDebugBuild> DebugStackIndirectTopRef; 42 43 // Non-debug mode specializations. This should be optimized away. 44 45 template <> 46 class DebugStackRefCounterImpl<false> { 47 public: 48 size_t IncrementRefCount() { return 0u; } 49 void DecrementRefCount() { } 50 size_t GetRefCount() const { return 0u; } 51 void CheckNoRefs() const { } 52 }; 53 54 template <> 55 class DebugStackReferenceImpl<false> { 56 public: 57 explicit DebugStackReferenceImpl(DebugStackRefCounterImpl<false>* counter ATTRIBUTE_UNUSED) {} 58 DebugStackReferenceImpl(const DebugStackReferenceImpl& other) = default; 59 DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) = default; 60 void CheckTop() { } 61 }; 62 63 template <> 64 class DebugStackIndirectTopRefImpl<false> { 65 public: 66 explicit DebugStackIndirectTopRefImpl(DebugStackReferenceImpl<false>* ref ATTRIBUTE_UNUSED) {} 67 DebugStackIndirectTopRefImpl(const DebugStackIndirectTopRefImpl& other) = default; 68 DebugStackIndirectTopRefImpl& operator=(const DebugStackIndirectTopRefImpl& other) = default; 69 void CheckTop() { } 70 }; 71 72 // Debug mode versions. 73 74 template <bool kIsDebug> 75 class DebugStackRefCounterImpl { 76 public: 77 DebugStackRefCounterImpl() : ref_count_(0u) { } 78 ~DebugStackRefCounterImpl() { CheckNoRefs(); } 79 size_t IncrementRefCount() { return ++ref_count_; } 80 void DecrementRefCount() { --ref_count_; } 81 size_t GetRefCount() const { return ref_count_; } 82 void CheckNoRefs() const { CHECK_EQ(ref_count_, 0u); } 83 84 private: 85 size_t ref_count_; 86 }; 87 88 template <bool kIsDebug> 89 class DebugStackReferenceImpl { 90 public: 91 explicit DebugStackReferenceImpl(DebugStackRefCounterImpl<kIsDebug>* counter) 92 : counter_(counter), ref_count_(counter->IncrementRefCount()) { 93 } 94 DebugStackReferenceImpl(const DebugStackReferenceImpl& other) 95 : counter_(other.counter_), ref_count_(counter_->IncrementRefCount()) { 96 } 97 DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) { 98 CHECK(counter_ == other.counter_); 99 return *this; 100 } 101 ~DebugStackReferenceImpl() { counter_->DecrementRefCount(); } 102 void CheckTop() { CHECK_EQ(counter_->GetRefCount(), ref_count_); } 103 104 private: 105 DebugStackRefCounterImpl<true>* counter_; 106 size_t ref_count_; 107 }; 108 109 template <bool kIsDebug> 110 class DebugStackIndirectTopRefImpl { 111 public: 112 explicit DebugStackIndirectTopRefImpl(DebugStackReferenceImpl<kIsDebug>* ref) 113 : ref_(ref) { 114 CheckTop(); 115 } 116 DebugStackIndirectTopRefImpl(const DebugStackIndirectTopRefImpl& other) 117 : ref_(other.ref_) { 118 CheckTop(); 119 } 120 DebugStackIndirectTopRefImpl& operator=(const DebugStackIndirectTopRefImpl& other) { 121 CHECK(ref_ == other.ref_); 122 CheckTop(); 123 return *this; 124 } 125 ~DebugStackIndirectTopRefImpl() { 126 CheckTop(); 127 } 128 void CheckTop() { 129 ref_->CheckTop(); 130 } 131 132 private: 133 DebugStackReferenceImpl<kIsDebug>* ref_; 134 }; 135 136 } // namespace art 137 138 #endif // ART_RUNTIME_BASE_DEBUG_STACK_H_ 139