/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_LIBARTBASE_BASE_DEBUG_STACK_H_ #define ART_LIBARTBASE_BASE_DEBUG_STACK_H_ #include <android-base/logging.h> #include <android-base/macros.h> #include "globals.h" namespace art { // Helper classes for reference counting to enforce construction/destruction order and // usage of the top element of a stack in debug mode with no overhead in release mode. // Reference counter. No references allowed in destructor or in explicitly called CheckNoRefs(). template <bool kIsDebug> class DebugStackRefCounterImpl; // Reference. Allows an explicit check that it's the top reference. template <bool kIsDebug> class DebugStackReferenceImpl; // Indirect top reference. Checks that the reference is the top reference when used. template <bool kIsDebug> class DebugStackIndirectTopRefImpl; typedef DebugStackRefCounterImpl<kIsDebugBuild> DebugStackRefCounter; typedef DebugStackReferenceImpl<kIsDebugBuild> DebugStackReference; typedef DebugStackIndirectTopRefImpl<kIsDebugBuild> DebugStackIndirectTopRef; // Non-debug mode specializations. This should be optimized away. template <> class DebugStackRefCounterImpl<false> { public: size_t IncrementRefCount() { return 0u; } void DecrementRefCount() { } size_t GetRefCount() const { return 0u; } void CheckNoRefs() const { } }; template <> class DebugStackReferenceImpl<false> { public: explicit DebugStackReferenceImpl(DebugStackRefCounterImpl<false>* counter ATTRIBUTE_UNUSED) {} DebugStackReferenceImpl(const DebugStackReferenceImpl& other) = default; DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) = default; void CheckTop() { } }; template <> class DebugStackIndirectTopRefImpl<false> { public: explicit DebugStackIndirectTopRefImpl(DebugStackReferenceImpl<false>* ref ATTRIBUTE_UNUSED) {} DebugStackIndirectTopRefImpl(const DebugStackIndirectTopRefImpl& other) = default; DebugStackIndirectTopRefImpl& operator=(const DebugStackIndirectTopRefImpl& other) = default; void CheckTop() { } }; // Debug mode versions. template <bool kIsDebug> class DebugStackRefCounterImpl { public: DebugStackRefCounterImpl() : ref_count_(0u) { } ~DebugStackRefCounterImpl() { CheckNoRefs(); } size_t IncrementRefCount() { return ++ref_count_; } void DecrementRefCount() { --ref_count_; } size_t GetRefCount() const { return ref_count_; } void CheckNoRefs() const { CHECK_EQ(ref_count_, 0u); } private: size_t ref_count_; }; template <bool kIsDebug> class DebugStackReferenceImpl { public: explicit DebugStackReferenceImpl(DebugStackRefCounterImpl<kIsDebug>* counter) : counter_(counter), ref_count_(counter->IncrementRefCount()) { } DebugStackReferenceImpl(const DebugStackReferenceImpl& other) : counter_(other.counter_), ref_count_(counter_->IncrementRefCount()) { } DebugStackReferenceImpl(DebugStackReferenceImpl&& other) : counter_(other.counter_), ref_count_(other.ref_count_) { other.counter_ = nullptr; } DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) { CHECK(counter_ == other.counter_); return *this; } ~DebugStackReferenceImpl() { if (counter_ != nullptr) { counter_->DecrementRefCount(); } } void CheckTop() { CHECK_EQ(counter_->GetRefCount(), ref_count_); } private: DebugStackRefCounterImpl<true>* counter_; size_t ref_count_; }; template <bool kIsDebug> class DebugStackIndirectTopRefImpl { public: explicit DebugStackIndirectTopRefImpl(DebugStackReferenceImpl<kIsDebug>* ref) : ref_(ref) { CheckTop(); } DebugStackIndirectTopRefImpl(const DebugStackIndirectTopRefImpl& other) : ref_(other.ref_) { CheckTop(); } DebugStackIndirectTopRefImpl& operator=(const DebugStackIndirectTopRefImpl& other) { CHECK(ref_ == other.ref_); CheckTop(); return *this; } ~DebugStackIndirectTopRefImpl() { CheckTop(); } void CheckTop() { ref_->CheckTop(); } private: DebugStackReferenceImpl<kIsDebug>* ref_; }; } // namespace art #endif // ART_LIBARTBASE_BASE_DEBUG_STACK_H_