DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (d1ed7de67f5a)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// This header provides virtual, non-templated alternatives to MFBT's RefCounted<T>.
// It intentionally uses MFBT coding style with the intention of moving there
// should there be other use cases for it.

#ifndef MOZILLA_GENERICREFCOUNTED_H_
#define MOZILLA_GENERICREFCOUNTED_H_

#include "mozilla/RefPtr.h"

namespace mozilla {

/**
 * Common base class for GenericRefCounted and GenericAtomicRefCounted.
 *
 * Having this shared base class, common to both the atomic and non-atomic
 * cases, allows to have RefPtr's that don't care about whether the
 * objects they're managing have atomic refcounts or not.
 */
class GenericRefCountedBase
{
  protected:
    virtual ~GenericRefCountedBase() {};

  public:
    // AddRef() and Release() method names are for compatibility with nsRefPtr.
    virtual void AddRef() = 0;

    virtual void Release() = 0;

    // ref() and deref() method names are for compatibility with wtf::RefPtr.
    // No virtual keywords here: if a subclass wants to override the refcounting
    // mechanism, it is welcome to do so by overriding AddRef() and Release().
    void ref() { AddRef(); }
    void deref() { Release(); }

#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
    virtual const char* typeName() const = 0;
    virtual size_t typeSize() const = 0;
#endif
};

namespace detail {

template<RefCountAtomicity Atomicity>
class GenericRefCounted : public GenericRefCountedBase
{
  protected:
    GenericRefCounted() : refCnt(0) { }

    virtual ~GenericRefCounted() {
      MOZ_ASSERT(refCnt == detail::DEAD);
    }

  public:
    virtual void AddRef() {
      // Note: this method must be thread safe for GenericAtomicRefCounted.
      MOZ_ASSERT(int32_t(refCnt) >= 0);
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
      ++refCnt;
#else
      const char* type = typeName();
      uint32_t size = typeSize();
      const void* ptr = this;
      MozRefCountType cnt = ++refCnt;
      detail::RefCountLogger::logAddRef(ptr, cnt, type, size);
#endif
    }

    virtual void Release() {
      // Note: this method must be thread safe for GenericAtomicRefCounted.
      MOZ_ASSERT(int32_t(refCnt) > 0);
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
      MozRefCountType cnt = --refCnt;
#else
      const char* type = typeName();
      const void* ptr = this;
      MozRefCountType cnt = --refCnt;
      // Note: it's not safe to touch |this| after decrementing the refcount,
      // except for below.
      detail::RefCountLogger::logRelease(ptr, cnt, type);
#endif
      if (0 == cnt) {
        // Because we have atomically decremented the refcount above, only
        // one thread can get a 0 count here, so as long as we can assume that
        // everything else in the system is accessing this object through
        // RefPtrs, it's safe to access |this| here.
#ifdef DEBUG
        refCnt = detail::DEAD;
#endif
        delete this;
      }
    }

    MozRefCountType refCount() const { return refCnt; }
    bool hasOneRef() const {
      MOZ_ASSERT(refCnt > 0);
      return refCnt == 1;
    }

  private:
    typename Conditional<Atomicity == AtomicRefCount, Atomic<MozRefCountType>, MozRefCountType>::Type refCnt;
};

} // namespace detail

/**
 * This reference-counting base class is virtual instead of
 * being templated, which is useful in cases where one needs
 * genericity at binary code level, but comes at the cost
 * of a moderate performance and size overhead, like anything virtual.
 */
class GenericRefCounted : public detail::GenericRefCounted<detail::NonAtomicRefCount>
{
};

/**
 * GenericAtomicRefCounted is like GenericRefCounted, with an atomically updated
 * reference counter.
 */
class GenericAtomicRefCounted : public detail::GenericRefCounted<detail::AtomicRefCount>
{
};

} // namespace mozilla

#endif