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