| /* | |
| * 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_ |