Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/GenericRefCounted.h
Line
Count
Source (jump to first uncovered line)
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
// This header provides virtual, non-templated alternatives to MFBT's RefCounted<T>.
8
// It intentionally uses MFBT coding style with the intention of moving there
9
// should there be other use cases for it.
10
11
#ifndef MOZILLA_GENERICREFCOUNTED_H_
12
#define MOZILLA_GENERICREFCOUNTED_H_
13
14
#include "mozilla/RefPtr.h"
15
#include "mozilla/RefCounted.h"
16
17
namespace mozilla {
18
19
/**
20
 * Common base class for GenericRefCounted and GenericAtomicRefCounted.
21
 *
22
 * Having this shared base class, common to both the atomic and non-atomic
23
 * cases, allows to have RefPtr's that don't care about whether the
24
 * objects they're managing have atomic refcounts or not.
25
 */
26
class GenericRefCountedBase
27
{
28
  protected:
29
0
    virtual ~GenericRefCountedBase() {};
30
31
  public:
32
    // AddRef() and Release() method names are for compatibility with nsRefPtr.
33
    virtual void AddRef() = 0;
34
35
    virtual void Release() = 0;
36
37
    // ref() and deref() method names are for compatibility with wtf::RefPtr.
38
    // No virtual keywords here: if a subclass wants to override the refcounting
39
    // mechanism, it is welcome to do so by overriding AddRef() and Release().
40
0
    void ref() { AddRef(); }
41
0
    void deref() { Release(); }
42
43
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
44
    virtual const char* typeName() const = 0;
45
    virtual size_t typeSize() const = 0;
46
#endif
47
};
48
49
namespace detail {
50
51
template<RefCountAtomicity Atomicity>
52
class GenericRefCounted : public GenericRefCountedBase
53
{
54
  protected:
55
0
    GenericRefCounted() : refCnt(0) { }
56
57
0
    virtual ~GenericRefCounted() {
58
0
      MOZ_ASSERT(refCnt == detail::DEAD);
59
0
    }
60
61
  public:
62
0
    virtual void AddRef() override {
63
0
      // Note: this method must be thread safe for GenericAtomicRefCounted.
64
0
      MOZ_ASSERT(int32_t(refCnt) >= 0);
65
0
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
66
0
      ++refCnt;
67
#else
68
      const char* type = typeName();
69
      uint32_t size = typeSize();
70
      const void* ptr = this;
71
      MozRefCountType cnt = ++refCnt;
72
      detail::RefCountLogger::logAddRef(ptr, cnt, type, size);
73
#endif
74
    }
75
76
0
    virtual void Release() override {
77
0
      // Note: this method must be thread safe for GenericAtomicRefCounted.
78
0
      MOZ_ASSERT(int32_t(refCnt) > 0);
79
0
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
80
0
      MozRefCountType cnt = --refCnt;
81
#else
82
      const char* type = typeName();
83
      const void* ptr = this;
84
      MozRefCountType cnt = --refCnt;
85
      // Note: it's not safe to touch |this| after decrementing the refcount,
86
      // except for below.
87
      detail::RefCountLogger::logRelease(ptr, cnt, type);
88
#endif
89
0
      if (0 == cnt) {
90
0
        // Because we have atomically decremented the refcount above, only
91
0
        // one thread can get a 0 count here, so as long as we can assume that
92
0
        // everything else in the system is accessing this object through
93
0
        // RefPtrs, it's safe to access |this| here.
94
#ifdef DEBUG
95
        refCnt = detail::DEAD;
96
#endif
97
        delete this;
98
0
      }
99
0
    }
100
101
    MozRefCountType refCount() const { return refCnt; }
102
    bool hasOneRef() const {
103
      MOZ_ASSERT(refCnt > 0);
104
      return refCnt == 1;
105
    }
106
107
  private:
108
    typename Conditional<Atomicity == AtomicRefCount, Atomic<MozRefCountType>, MozRefCountType>::Type refCnt;
109
};
110
111
} // namespace detail
112
113
/**
114
 * This reference-counting base class is virtual instead of
115
 * being templated, which is useful in cases where one needs
116
 * genericity at binary code level, but comes at the cost
117
 * of a moderate performance and size overhead, like anything virtual.
118
 */
119
class GenericRefCounted : public detail::GenericRefCounted<detail::NonAtomicRefCount>
120
{
121
};
122
123
/**
124
 * GenericAtomicRefCounted is like GenericRefCounted, with an atomically updated
125
 * reference counter.
126
 */
127
class GenericAtomicRefCounted : public detail::GenericRefCounted<detail::AtomicRefCount>
128
{
129
};
130
131
} // namespace mozilla
132
133
#endif