| /* |
| * 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; |
| |
| using DebugStackRefCounter = DebugStackRefCounterImpl<kIsDebugBuild>; |
| using DebugStackReference = DebugStackReferenceImpl<kIsDebugBuild>; |
| using DebugStackIndirectTopRef = DebugStackIndirectTopRefImpl<kIsDebugBuild>; |
| |
| // 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([[maybe_unused]] DebugStackRefCounterImpl<false>* counter) {} |
| DebugStackReferenceImpl(const DebugStackReferenceImpl& other) = default; |
| DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) = default; |
| void CheckTop() { } |
| }; |
| |
| template <> |
| class DebugStackIndirectTopRefImpl<false> { |
| public: |
| explicit DebugStackIndirectTopRefImpl([[maybe_unused]] DebugStackReferenceImpl<false>* ref) {} |
| 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) noexcept |
| : 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_ |