summaryrefslogtreecommitdiff
path: root/libartbase/base/debug_stack.h
diff options
context:
space:
mode:
author David Sehr <sehr@google.com> 2018-03-02 12:01:51 -0800
committer David Sehr <sehr@google.com> 2018-03-05 13:58:20 -0800
commitc431b9dc4b23cc950eb313695258df5d89f53b22 (patch)
tree422273559c3ae52caff0c6b1cf1a62a8312f0e26 /libartbase/base/debug_stack.h
parentf46f46cf5bd32788d5252b7107628a66594a5e98 (diff)
Move most of runtime/base to libartbase/base
Enforce the layering that code in runtime/base should not depend on runtime by separating it into libartbase. Some of the code in runtime/base depends on the Runtime class, so it cannot be moved yet. Also, some of the tests depend on CommonRuntimeTest, which itself needs to be factored (in a subsequent CL). Bug: 22322814 Test: make -j 50 checkbuild make -j 50 test-art-host Change-Id: I8b096c1e2542f829eb456b4b057c71421b77d7e2
Diffstat (limited to 'libartbase/base/debug_stack.h')
-rw-r--r--libartbase/base/debug_stack.h147
1 files changed, 147 insertions, 0 deletions
diff --git a/libartbase/base/debug_stack.h b/libartbase/base/debug_stack.h
new file mode 100644
index 0000000000..f2d93d462a
--- /dev/null
+++ b/libartbase/base/debug_stack.h
@@ -0,0 +1,147 @@
+/*
+ * 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_