1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/RefPtr.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,521 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Helpers for defining and using refcounted objects. */ 1.11 + 1.12 +#ifndef mozilla_RefPtr_h 1.13 +#define mozilla_RefPtr_h 1.14 + 1.15 +#include "mozilla/Assertions.h" 1.16 +#include "mozilla/Atomics.h" 1.17 +#include "mozilla/Attributes.h" 1.18 +#include "mozilla/RefCountType.h" 1.19 +#include "mozilla/TypeTraits.h" 1.20 +#if defined(MOZILLA_INTERNAL_API) 1.21 +#include "nsXPCOM.h" 1.22 +#endif 1.23 + 1.24 +#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) 1.25 +#define MOZ_REFCOUNTED_LEAK_CHECKING 1.26 +#endif 1.27 + 1.28 +namespace mozilla { 1.29 + 1.30 +template<typename T> class RefCounted; 1.31 +template<typename T> class RefPtr; 1.32 +template<typename T> class TemporaryRef; 1.33 +template<typename T> class OutParamRef; 1.34 +template<typename T> OutParamRef<T> byRef(RefPtr<T>&); 1.35 + 1.36 +/** 1.37 + * RefCounted<T> is a sort of a "mixin" for a class T. RefCounted 1.38 + * manages, well, refcounting for T, and because RefCounted is 1.39 + * parameterized on T, RefCounted<T> can call T's destructor directly. 1.40 + * This means T doesn't need to have a virtual dtor and so doesn't 1.41 + * need a vtable. 1.42 + * 1.43 + * RefCounted<T> is created with refcount == 0. Newly-allocated 1.44 + * RefCounted<T> must immediately be assigned to a RefPtr to make the 1.45 + * refcount > 0. It's an error to allocate and free a bare 1.46 + * RefCounted<T>, i.e. outside of the RefPtr machinery. Attempts to 1.47 + * do so will abort DEBUG builds. 1.48 + * 1.49 + * Live RefCounted<T> have refcount > 0. The lifetime (refcounts) of 1.50 + * live RefCounted<T> are controlled by RefPtr<T> and 1.51 + * RefPtr<super/subclass of T>. Upon a transition from refcounted==1 1.52 + * to 0, the RefCounted<T> "dies" and is destroyed. The "destroyed" 1.53 + * state is represented in DEBUG builds by refcount==0xffffdead. This 1.54 + * state distinguishes use-before-ref (refcount==0) from 1.55 + * use-after-destroy (refcount==0xffffdead). 1.56 + * 1.57 + * Note that when deriving from RefCounted or AtomicRefCounted, you 1.58 + * should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public 1.59 + * section of your class, where ClassName is the name of your class. 1.60 + */ 1.61 +namespace detail { 1.62 +#ifdef DEBUG 1.63 +const MozRefCountType DEAD = 0xffffdead; 1.64 +#endif 1.65 + 1.66 +// When building code that gets compiled into Gecko, try to use the 1.67 +// trace-refcount leak logging facilities. 1.68 +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING 1.69 +class RefCountLogger 1.70 +{ 1.71 + public: 1.72 + static void logAddRef(const void* aPointer, MozRefCountType aRefCount, 1.73 + const char* aTypeName, uint32_t aInstanceSize) 1.74 + { 1.75 + MOZ_ASSERT(aRefCount != DEAD); 1.76 + NS_LogAddRef(const_cast<void*>(aPointer), aRefCount, aTypeName, aInstanceSize); 1.77 + } 1.78 + 1.79 + static void logRelease(const void* aPointer, MozRefCountType aRefCount, 1.80 + const char* aTypeName) 1.81 + { 1.82 + MOZ_ASSERT(aRefCount != DEAD); 1.83 + NS_LogRelease(const_cast<void*>(aPointer), aRefCount, aTypeName); 1.84 + } 1.85 +}; 1.86 +#endif 1.87 + 1.88 +// This is used WeakPtr.h as well as this file. 1.89 +enum RefCountAtomicity 1.90 +{ 1.91 + AtomicRefCount, 1.92 + NonAtomicRefCount 1.93 +}; 1.94 + 1.95 +template<typename T, RefCountAtomicity Atomicity> 1.96 +class RefCounted 1.97 +{ 1.98 + friend class RefPtr<T>; 1.99 + 1.100 + protected: 1.101 + RefCounted() : refCnt(0) { } 1.102 + ~RefCounted() { 1.103 + MOZ_ASSERT(refCnt == detail::DEAD); 1.104 + } 1.105 + 1.106 + public: 1.107 + // Compatibility with nsRefPtr. 1.108 + void AddRef() const { 1.109 + // Note: this method must be thread safe for AtomicRefCounted. 1.110 + MOZ_ASSERT(int32_t(refCnt) >= 0); 1.111 +#ifndef MOZ_REFCOUNTED_LEAK_CHECKING 1.112 + ++refCnt; 1.113 +#else 1.114 + const char* type = static_cast<const T*>(this)->typeName(); 1.115 + uint32_t size = static_cast<const T*>(this)->typeSize(); 1.116 + const void* ptr = static_cast<const T*>(this); 1.117 + MozRefCountType cnt = ++refCnt; 1.118 + detail::RefCountLogger::logAddRef(ptr, cnt, type, size); 1.119 +#endif 1.120 + } 1.121 + 1.122 + void Release() const { 1.123 + // Note: this method must be thread safe for AtomicRefCounted. 1.124 + MOZ_ASSERT(int32_t(refCnt) > 0); 1.125 +#ifndef MOZ_REFCOUNTED_LEAK_CHECKING 1.126 + MozRefCountType cnt = --refCnt; 1.127 +#else 1.128 + const char* type = static_cast<const T*>(this)->typeName(); 1.129 + const void* ptr = static_cast<const T*>(this); 1.130 + MozRefCountType cnt = --refCnt; 1.131 + // Note: it's not safe to touch |this| after decrementing the refcount, 1.132 + // except for below. 1.133 + detail::RefCountLogger::logRelease(ptr, cnt, type); 1.134 +#endif 1.135 + if (0 == cnt) { 1.136 + // Because we have atomically decremented the refcount above, only 1.137 + // one thread can get a 0 count here, so as long as we can assume that 1.138 + // everything else in the system is accessing this object through 1.139 + // RefPtrs, it's safe to access |this| here. 1.140 +#ifdef DEBUG 1.141 + refCnt = detail::DEAD; 1.142 +#endif 1.143 + delete static_cast<const T*>(this); 1.144 + } 1.145 + } 1.146 + 1.147 + // Compatibility with wtf::RefPtr. 1.148 + void ref() { AddRef(); } 1.149 + void deref() { Release(); } 1.150 + MozRefCountType refCount() const { return refCnt; } 1.151 + bool hasOneRef() const { 1.152 + MOZ_ASSERT(refCnt > 0); 1.153 + return refCnt == 1; 1.154 + } 1.155 + 1.156 + private: 1.157 + mutable typename Conditional<Atomicity == AtomicRefCount, Atomic<MozRefCountType>, MozRefCountType>::Type refCnt; 1.158 +}; 1.159 + 1.160 +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING 1.161 +#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \ 1.162 + const char* typeName() const { return #T; } \ 1.163 + size_t typeSize() const { return sizeof(*this); } 1.164 + 1.165 +#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T) \ 1.166 + virtual const char* typeName() const { return #T; } \ 1.167 + virtual size_t typeSize() const { return sizeof(*this); } 1.168 +#else 1.169 +#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) 1.170 +#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T) 1.171 +#endif 1.172 + 1.173 +} 1.174 + 1.175 +template<typename T> 1.176 +class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount> 1.177 +{ 1.178 + public: 1.179 + ~RefCounted() { 1.180 + static_assert(IsBaseOf<RefCounted, T>::value, 1.181 + "T must derive from RefCounted<T>"); 1.182 + } 1.183 +}; 1.184 + 1.185 +/** 1.186 + * AtomicRefCounted<T> is like RefCounted<T>, with an atomically updated 1.187 + * reference counter. 1.188 + */ 1.189 +template<typename T> 1.190 +class AtomicRefCounted : public detail::RefCounted<T, detail::AtomicRefCount> 1.191 +{ 1.192 + public: 1.193 + ~AtomicRefCounted() { 1.194 + static_assert(IsBaseOf<AtomicRefCounted, T>::value, 1.195 + "T must derive from AtomicRefCounted<T>"); 1.196 + } 1.197 +}; 1.198 + 1.199 +/** 1.200 + * RefPtr points to a refcounted thing that has AddRef and Release 1.201 + * methods to increase/decrease the refcount, respectively. After a 1.202 + * RefPtr<T> is assigned a T*, the T* can be used through the RefPtr 1.203 + * as if it were a T*. 1.204 + * 1.205 + * A RefPtr can forget its underlying T*, which results in the T* 1.206 + * being wrapped in a temporary object until the T* is either 1.207 + * re-adopted from or released by the temporary. 1.208 + */ 1.209 +template<typename T> 1.210 +class RefPtr 1.211 +{ 1.212 + // To allow them to use unref() 1.213 + friend class TemporaryRef<T>; 1.214 + friend class OutParamRef<T>; 1.215 + 1.216 + struct DontRef {}; 1.217 + 1.218 + public: 1.219 + RefPtr() : ptr(0) { } 1.220 + RefPtr(const RefPtr& o) : ptr(ref(o.ptr)) {} 1.221 + RefPtr(const TemporaryRef<T>& o) : ptr(o.drop()) {} 1.222 + RefPtr(T* t) : ptr(ref(t)) {} 1.223 + 1.224 + template<typename U> 1.225 + RefPtr(const RefPtr<U>& o) : ptr(ref(o.get())) {} 1.226 + 1.227 + ~RefPtr() { unref(ptr); } 1.228 + 1.229 + RefPtr& operator=(const RefPtr& o) { 1.230 + assign(ref(o.ptr)); 1.231 + return *this; 1.232 + } 1.233 + RefPtr& operator=(const TemporaryRef<T>& o) { 1.234 + assign(o.drop()); 1.235 + return *this; 1.236 + } 1.237 + RefPtr& operator=(T* t) { 1.238 + assign(ref(t)); 1.239 + return *this; 1.240 + } 1.241 + 1.242 + template<typename U> 1.243 + RefPtr& operator=(const RefPtr<U>& o) { 1.244 + assign(ref(o.get())); 1.245 + return *this; 1.246 + } 1.247 + 1.248 + TemporaryRef<T> forget() { 1.249 + T* tmp = ptr; 1.250 + ptr = 0; 1.251 + return TemporaryRef<T>(tmp, DontRef()); 1.252 + } 1.253 + 1.254 + T* get() const { return ptr; } 1.255 + operator T*() const { return ptr; } 1.256 + T* operator->() const { return ptr; } 1.257 + T& operator*() const { return *ptr; } 1.258 + template<typename U> 1.259 + operator TemporaryRef<U>() { return TemporaryRef<U>(ptr); } 1.260 + 1.261 + private: 1.262 + void assign(T* t) { 1.263 + unref(ptr); 1.264 + ptr = t; 1.265 + } 1.266 + 1.267 + T* ptr; 1.268 + 1.269 + static MOZ_ALWAYS_INLINE T* ref(T* t) { 1.270 + if (t) 1.271 + t->AddRef(); 1.272 + return t; 1.273 + } 1.274 + 1.275 + static MOZ_ALWAYS_INLINE void unref(T* t) { 1.276 + if (t) 1.277 + t->Release(); 1.278 + } 1.279 +}; 1.280 + 1.281 +/** 1.282 + * TemporaryRef<T> represents an object that holds a temporary 1.283 + * reference to a T. TemporaryRef objects can't be manually ref'd or 1.284 + * unref'd (being temporaries, not lvalues), so can only relinquish 1.285 + * references to other objects, or unref on destruction. 1.286 + */ 1.287 +template<typename T> 1.288 +class TemporaryRef 1.289 +{ 1.290 + // To allow it to construct TemporaryRef from a bare T* 1.291 + friend class RefPtr<T>; 1.292 + 1.293 + typedef typename RefPtr<T>::DontRef DontRef; 1.294 + 1.295 + public: 1.296 + TemporaryRef(T* t) : ptr(RefPtr<T>::ref(t)) {} 1.297 + TemporaryRef(const TemporaryRef& o) : ptr(o.drop()) {} 1.298 + 1.299 + template<typename U> 1.300 + TemporaryRef(const TemporaryRef<U>& o) : ptr(o.drop()) {} 1.301 + 1.302 + ~TemporaryRef() { RefPtr<T>::unref(ptr); } 1.303 + 1.304 + T* drop() const { 1.305 + T* tmp = ptr; 1.306 + ptr = 0; 1.307 + return tmp; 1.308 + } 1.309 + 1.310 + private: 1.311 + TemporaryRef(T* t, const DontRef&) : ptr(t) {} 1.312 + 1.313 + mutable T* ptr; 1.314 + 1.315 + TemporaryRef() MOZ_DELETE; 1.316 + void operator=(const TemporaryRef&) MOZ_DELETE; 1.317 +}; 1.318 + 1.319 +/** 1.320 + * OutParamRef is a wrapper that tracks a refcounted pointer passed as 1.321 + * an outparam argument to a function. OutParamRef implements COM T** 1.322 + * outparam semantics: this requires the callee to AddRef() the T* 1.323 + * returned through the T** outparam on behalf of the caller. This 1.324 + * means the caller (through OutParamRef) must Release() the old 1.325 + * object contained in the tracked RefPtr. It's OK if the callee 1.326 + * returns the same T* passed to it through the T** outparam, as long 1.327 + * as the callee obeys the COM discipline. 1.328 + * 1.329 + * Prefer returning TemporaryRef<T> from functions over creating T** 1.330 + * outparams and passing OutParamRef<T> to T**. Prefer RefPtr<T>* 1.331 + * outparams over T** outparams. 1.332 + */ 1.333 +template<typename T> 1.334 +class OutParamRef 1.335 +{ 1.336 + friend OutParamRef byRef<T>(RefPtr<T>&); 1.337 + 1.338 + public: 1.339 + ~OutParamRef() { 1.340 + RefPtr<T>::unref(refPtr.ptr); 1.341 + refPtr.ptr = tmp; 1.342 + } 1.343 + 1.344 + operator T**() { return &tmp; } 1.345 + 1.346 + private: 1.347 + OutParamRef(RefPtr<T>& p) : refPtr(p), tmp(p.get()) {} 1.348 + 1.349 + RefPtr<T>& refPtr; 1.350 + T* tmp; 1.351 + 1.352 + OutParamRef() MOZ_DELETE; 1.353 + OutParamRef& operator=(const OutParamRef&) MOZ_DELETE; 1.354 +}; 1.355 + 1.356 +/** 1.357 + * byRef cooperates with OutParamRef to implement COM outparam semantics. 1.358 + */ 1.359 +template<typename T> 1.360 +OutParamRef<T> 1.361 +byRef(RefPtr<T>& ptr) 1.362 +{ 1.363 + return OutParamRef<T>(ptr); 1.364 +} 1.365 + 1.366 +} // namespace mozilla 1.367 + 1.368 +#if 0 1.369 + 1.370 +// Command line that builds these tests 1.371 +// 1.372 +// cp RefPtr.h test.cc && g++ -g -Wall -pedantic -DDEBUG -o test test.cc && ./test 1.373 + 1.374 +using namespace mozilla; 1.375 + 1.376 +struct Foo : public RefCounted<Foo> 1.377 +{ 1.378 + MOZ_DECLARE_REFCOUNTED_TYPENAME(Foo) 1.379 + Foo() : dead(false) { } 1.380 + ~Foo() { 1.381 + MOZ_ASSERT(!dead); 1.382 + dead = true; 1.383 + numDestroyed++; 1.384 + } 1.385 + 1.386 + bool dead; 1.387 + static int numDestroyed; 1.388 +}; 1.389 +int Foo::numDestroyed; 1.390 + 1.391 +struct Bar : public Foo { }; 1.392 + 1.393 +TemporaryRef<Foo> 1.394 +NewFoo() 1.395 +{ 1.396 + return RefPtr<Foo>(new Foo()); 1.397 +} 1.398 + 1.399 +TemporaryRef<Foo> 1.400 +NewBar() 1.401 +{ 1.402 + return new Bar(); 1.403 +} 1.404 + 1.405 +void 1.406 +GetNewFoo(Foo** f) 1.407 +{ 1.408 + *f = new Bar(); 1.409 + // Kids, don't try this at home 1.410 + (*f)->AddRef(); 1.411 +} 1.412 + 1.413 +void 1.414 +GetPassedFoo(Foo** f) 1.415 +{ 1.416 + // Kids, don't try this at home 1.417 + (*f)->AddRef(); 1.418 +} 1.419 + 1.420 +void 1.421 +GetNewFoo(RefPtr<Foo>* f) 1.422 +{ 1.423 + *f = new Bar(); 1.424 +} 1.425 + 1.426 +void 1.427 +GetPassedFoo(RefPtr<Foo>* f) 1.428 +{} 1.429 + 1.430 +TemporaryRef<Foo> 1.431 +GetNullFoo() 1.432 +{ 1.433 + return 0; 1.434 +} 1.435 + 1.436 +int 1.437 +main(int argc, char** argv) 1.438 +{ 1.439 + // This should blow up 1.440 +// Foo* f = new Foo(); delete f; 1.441 + 1.442 + MOZ_ASSERT(0 == Foo::numDestroyed); 1.443 + { 1.444 + RefPtr<Foo> f = new Foo(); 1.445 + MOZ_ASSERT(f->refCount() == 1); 1.446 + } 1.447 + MOZ_ASSERT(1 == Foo::numDestroyed); 1.448 + 1.449 + { 1.450 + RefPtr<Foo> f1 = NewFoo(); 1.451 + RefPtr<Foo> f2(NewFoo()); 1.452 + MOZ_ASSERT(1 == Foo::numDestroyed); 1.453 + } 1.454 + MOZ_ASSERT(3 == Foo::numDestroyed); 1.455 + 1.456 + { 1.457 + RefPtr<Foo> b = NewBar(); 1.458 + MOZ_ASSERT(3 == Foo::numDestroyed); 1.459 + } 1.460 + MOZ_ASSERT(4 == Foo::numDestroyed); 1.461 + 1.462 + { 1.463 + RefPtr<Foo> f1; 1.464 + { 1.465 + f1 = new Foo(); 1.466 + RefPtr<Foo> f2(f1); 1.467 + RefPtr<Foo> f3 = f2; 1.468 + MOZ_ASSERT(4 == Foo::numDestroyed); 1.469 + } 1.470 + MOZ_ASSERT(4 == Foo::numDestroyed); 1.471 + } 1.472 + MOZ_ASSERT(5 == Foo::numDestroyed); 1.473 + 1.474 + { 1.475 + RefPtr<Foo> f = new Foo(); 1.476 + f.forget(); 1.477 + MOZ_ASSERT(6 == Foo::numDestroyed); 1.478 + } 1.479 + 1.480 + { 1.481 + RefPtr<Foo> f = new Foo(); 1.482 + GetNewFoo(byRef(f)); 1.483 + MOZ_ASSERT(7 == Foo::numDestroyed); 1.484 + } 1.485 + MOZ_ASSERT(8 == Foo::numDestroyed); 1.486 + 1.487 + { 1.488 + RefPtr<Foo> f = new Foo(); 1.489 + GetPassedFoo(byRef(f)); 1.490 + MOZ_ASSERT(8 == Foo::numDestroyed); 1.491 + } 1.492 + MOZ_ASSERT(9 == Foo::numDestroyed); 1.493 + 1.494 + { 1.495 + RefPtr<Foo> f = new Foo(); 1.496 + GetNewFoo(&f); 1.497 + MOZ_ASSERT(10 == Foo::numDestroyed); 1.498 + } 1.499 + MOZ_ASSERT(11 == Foo::numDestroyed); 1.500 + 1.501 + { 1.502 + RefPtr<Foo> f = new Foo(); 1.503 + GetPassedFoo(&f); 1.504 + MOZ_ASSERT(11 == Foo::numDestroyed); 1.505 + } 1.506 + MOZ_ASSERT(12 == Foo::numDestroyed); 1.507 + 1.508 + { 1.509 + RefPtr<Foo> f1 = new Bar(); 1.510 + } 1.511 + MOZ_ASSERT(13 == Foo::numDestroyed); 1.512 + 1.513 + { 1.514 + RefPtr<Foo> f = GetNullFoo(); 1.515 + MOZ_ASSERT(13 == Foo::numDestroyed); 1.516 + } 1.517 + MOZ_ASSERT(13 == Foo::numDestroyed); 1.518 + 1.519 + return 0; 1.520 +} 1.521 + 1.522 +#endif 1.523 + 1.524 +#endif /* mozilla_RefPtr_h */