RefCounted.h (2279B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef js_RefCounted_h 8 #define js_RefCounted_h 9 10 #include "mozilla/Atomics.h" 11 #include "mozilla/RefCountType.h" 12 13 #include "js/Utility.h" 14 15 // These types implement the same interface as mozilla::(Atomic)RefCounted and 16 // must be used instead of mozilla::(Atomic)RefCounted for everything in 17 // SpiderMonkey. This is because Release() needs to call js_delete, not delete. 18 19 namespace js { 20 21 template <typename T> 22 class RefCounted { 23 static const MozRefCountType DEAD = 0xffffdead; 24 25 protected: 26 RefCounted() : mRefCnt(0) {} 27 ~RefCounted() { MOZ_ASSERT(mRefCnt == DEAD); } 28 29 public: 30 void AddRef() const { 31 MOZ_ASSERT(int32_t(mRefCnt) >= 0); 32 ++mRefCnt; 33 } 34 35 void Release() const { 36 MOZ_ASSERT(int32_t(mRefCnt) > 0); 37 MozRefCountType cnt = --mRefCnt; 38 if (0 == cnt) { 39 #ifdef DEBUG 40 mRefCnt = DEAD; 41 #endif 42 js_delete(const_cast<T*>(static_cast<const T*>(this))); 43 } 44 } 45 46 private: 47 mutable MozRefCountType mRefCnt; 48 }; 49 50 template <typename T> 51 class AtomicRefCounted { 52 // On 64-bit systems, if the refcount type is small (say, 32 bits), there's 53 // a risk that it could overflow. So require it to be large enough. 54 55 static_assert(sizeof(MozRefCountType) == sizeof(uintptr_t), 56 "You're at risk for ref count overflow."); 57 58 static const MozRefCountType DEAD = ~MozRefCountType(0xffff) | 0xdead; 59 60 protected: 61 AtomicRefCounted() = default; 62 ~AtomicRefCounted() { MOZ_ASSERT(mRefCnt == DEAD); } 63 64 public: 65 void AddRef() const { 66 ++mRefCnt; 67 MOZ_ASSERT(mRefCnt != DEAD); 68 } 69 70 void Release() const { 71 MOZ_ASSERT(mRefCnt != 0); 72 MozRefCountType cnt = --mRefCnt; 73 if (0 == cnt) { 74 #ifdef DEBUG 75 mRefCnt = DEAD; 76 #endif 77 js_delete(const_cast<T*>(static_cast<const T*>(this))); 78 } 79 } 80 81 bool hasOneRef() const { 82 MOZ_ASSERT(mRefCnt > 0); 83 return mRefCnt == 1; 84 } 85 86 private: 87 mutable mozilla::Atomic<MozRefCountType> mRefCnt{0}; 88 }; 89 90 } // namespace js 91 92 #endif /* js_RefCounted_h */