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