Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/Queue.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
#ifndef mozilla_Queue_h
8
#define mozilla_Queue_h
9
10
#include "mozilla/MemoryReporting.h"
11
12
namespace mozilla {
13
14
// A queue implements a singly linked list of pages, each of which contains some
15
// number of elements. Since the queue needs to store a "next" pointer, the
16
// actual number of elements per page won't be quite as many as were requested.
17
//
18
// This class should only be used if it's valid to construct T elements from all
19
// zeroes. The class also fails to call the destructor on items. However, it
20
// will only destroy items after it has moved out their contents. The queue is
21
// required to be empty when it is destroyed.
22
template<class T, size_t RequestedItemsPerPage = 256>
23
class Queue
24
{
25
public:
26
74
  Queue() {}
mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::Queue()
Line
Count
Source
26
62
  Queue() {}
mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::Queue()
Line
Count
Source
26
12
  Queue() {}
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::Queue()
27
28
  ~Queue()
29
0
  {
30
0
    MOZ_ASSERT(IsEmpty());
31
0
32
0
    if (mHead) {
33
0
      free(mHead);
34
0
    }
35
0
  }
Unexecuted instantiation: mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::~Queue()
Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::~Queue()
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::~Queue()
36
37
  T& Push(T&& aElement)
38
194
  {
39
194
    if (!mHead) {
40
19
      mHead = NewPage();
41
19
      MOZ_ASSERT(mHead);
42
19
43
19
      mTail = mHead;
44
19
      mOffsetHead = 0;
45
19
      mOffsetTail = 0;
46
175
    } else if (mOffsetTail == ItemsPerPage) {
47
0
      Page* page = NewPage();
48
0
      MOZ_ASSERT(page);
49
0
50
0
      mTail->mNext = page;
51
0
      mTail = page;
52
0
      mOffsetTail = 0;
53
0
    }
54
194
55
194
    T& eltLocation = mTail->mEvents[mOffsetTail];
56
194
    eltLocation = std::move(aElement);
57
194
    ++mOffsetTail;
58
194
59
194
    return eltLocation;
60
194
  }
mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::Push(nsCOMPtr<nsIRunnable>&&)
Line
Count
Source
38
194
  {
39
194
    if (!mHead) {
40
19
      mHead = NewPage();
41
19
      MOZ_ASSERT(mHead);
42
19
43
19
      mTail = mHead;
44
19
      mOffsetHead = 0;
45
19
      mOffsetTail = 0;
46
175
    } else if (mOffsetTail == ItemsPerPage) {
47
0
      Page* page = NewPage();
48
0
      MOZ_ASSERT(page);
49
0
50
0
      mTail->mNext = page;
51
0
      mTail = page;
52
0
      mOffsetTail = 0;
53
0
    }
54
194
55
194
    T& eltLocation = mTail->mEvents[mOffsetTail];
56
194
    eltLocation = std::move(aElement);
57
194
    ++mOffsetTail;
58
194
59
194
    return eltLocation;
60
194
  }
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::Push(mozilla::LabeledEventQueue::Epoch&&)
Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::Push(mozilla::SchedulerGroup::EpochQueueEntry&&)
61
62
  bool IsEmpty() const
63
82
  {
64
82
    return !mHead || (mHead == mTail && mOffsetHead == mOffsetTail);
65
82
  }
mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::IsEmpty() const
Line
Count
Source
63
82
  {
64
82
    return !mHead || (mHead == mTail && mOffsetHead == mOffsetTail);
65
82
  }
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::IsEmpty() const
Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::IsEmpty() const
66
67
  T Pop()
68
31
  {
69
31
    MOZ_ASSERT(!IsEmpty());
70
31
71
31
    MOZ_ASSERT(mOffsetHead < ItemsPerPage);
72
31
    MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail);
73
31
    T result = std::move(mHead->mEvents[mOffsetHead++]);
74
31
75
31
    MOZ_ASSERT(mOffsetHead <= ItemsPerPage);
76
31
77
31
    // Check if mHead points to empty Page
78
31
    if (mOffsetHead == ItemsPerPage) {
79
0
      Page* dead = mHead;
80
0
      mHead = mHead->mNext;
81
0
      free(dead);
82
0
      mOffsetHead = 0;
83
0
    }
84
31
85
31
    return result;
86
31
  }
mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::Pop()
Line
Count
Source
68
31
  {
69
31
    MOZ_ASSERT(!IsEmpty());
70
31
71
31
    MOZ_ASSERT(mOffsetHead < ItemsPerPage);
72
31
    MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail);
73
31
    T result = std::move(mHead->mEvents[mOffsetHead++]);
74
31
75
31
    MOZ_ASSERT(mOffsetHead <= ItemsPerPage);
76
31
77
31
    // Check if mHead points to empty Page
78
31
    if (mOffsetHead == ItemsPerPage) {
79
0
      Page* dead = mHead;
80
0
      mHead = mHead->mNext;
81
0
      free(dead);
82
0
      mOffsetHead = 0;
83
0
    }
84
31
85
31
    return result;
86
31
  }
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::Pop()
Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::Pop()
87
88
  void FirstElementAssertions() const
89
0
  {
90
0
    MOZ_ASSERT(!IsEmpty());
91
0
    MOZ_ASSERT(mOffsetHead < ItemsPerPage);
92
0
    MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail);
93
0
  }
Unexecuted instantiation: mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::FirstElementAssertions() const
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::FirstElementAssertions() const
Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::FirstElementAssertions() const
94
95
  T& FirstElement()
96
0
  {
97
0
    FirstElementAssertions();
98
0
    return mHead->mEvents[mOffsetHead];
99
0
  }
Unexecuted instantiation: mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::FirstElement()
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::FirstElement()
Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::FirstElement()
100
101
  const T& FirstElement() const
102
  {
103
    FirstElementAssertions();
104
    return mHead->mEvents[mOffsetHead];
105
  }
106
107
  void LastElementAssertions() const
108
0
  {
109
0
    MOZ_ASSERT(!IsEmpty());
110
0
    MOZ_ASSERT(mOffsetTail > 0);
111
0
    MOZ_ASSERT(mOffsetTail <= ItemsPerPage);
112
0
    MOZ_ASSERT_IF(mHead == mTail, mOffsetHead <= mOffsetTail);
113
0
  }
114
115
  T& LastElement()
116
0
  {
117
0
    LastElementAssertions();
118
0
    return mTail->mEvents[mOffsetTail - 1];
119
0
  }
120
121
  const T& LastElement() const
122
  {
123
    LastElementAssertions();
124
    return mTail->mEvents[mOffsetTail - 1];
125
  }
126
127
  size_t Count() const
128
0
  {
129
0
    // It is obvious count is 0 when the queue is empty.
130
0
    if (!mHead) {
131
0
      return 0;
132
0
    }
133
0
134
0
    /* How we count the number of events in the queue:
135
0
     * 1. Let pageCount(x, y) denote the number of pages excluding the tail page
136
0
     *    where x is the index of head page and y is the index of the tail page.
137
0
     * 2. Then we have pageCount(x, y) = y - x.
138
0
     *
139
0
     * Ex: pageCount(0, 0) = 0 where both head and tail pages point to page 0.
140
0
     *     pageCount(0, 1) = 1 where head points to page 0 and tail points page 1.
141
0
     *
142
0
     * 3. number of events = (ItemsPerPage * pageCount(x, y))
143
0
     *      - (empty slots in head page) + (non-empty slots in tail page)
144
0
     *      = (ItemsPerPage * pageCount(x, y)) - mOffsetHead + mOffsetTail
145
0
     */
146
0
147
0
    int count = -mOffsetHead;
148
0
149
0
    // Compute (ItemsPerPage * pageCount(x, y))
150
0
    for (Page* page = mHead; page != mTail; page = page->mNext) {
151
0
      count += ItemsPerPage;
152
0
    }
153
0
154
0
    count += mOffsetTail;
155
0
    MOZ_ASSERT(count >= 0);
156
0
157
0
    return count;
158
0
  }
159
160
  size_t ShallowSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
161
0
  {
162
0
    size_t n = 0;
163
0
    if (mHead) {
164
0
      for (Page* page = mHead; page != mTail; page = page->mNext) {
165
0
        n += aMallocSizeOf(page);
166
0
      }
167
0
    }
168
0
    return n;
169
0
  }
Unexecuted instantiation: mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::ShallowSizeOfExcludingThis(unsigned long (*)(void const*)) const
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::ShallowSizeOfExcludingThis(unsigned long (*)(void const*)) const
Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::ShallowSizeOfExcludingThis(unsigned long (*)(void const*)) const
170
171
  size_t ShallowSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
172
  {
173
    return aMallocSizeOf(this) + ShallowSizeOfExcludingThis(aMallocSizeOf);
174
  }
175
176
private:
177
  static_assert((RequestedItemsPerPage & (RequestedItemsPerPage - 1)) == 0,
178
                "RequestedItemsPerPage should be a power of two to avoid heap slop.");
179
180
  // Since a Page must also contain a "next" pointer, we use one of the items to
181
  // store this pointer. If sizeof(T) > sizeof(Page*), then some space will be
182
  // wasted. So be it.
183
  static const size_t ItemsPerPage = RequestedItemsPerPage - 1;
184
185
  // Page objects are linked together to form a simple deque.
186
  struct Page
187
  {
188
    struct Page* mNext;
189
    T mEvents[ItemsPerPage];
190
  };
191
192
  static Page* NewPage()
193
19
  {
194
19
    return static_cast<Page*>(moz_xcalloc(1, sizeof(Page)));
195
19
  }
mozilla::Queue<nsCOMPtr<nsIRunnable>, 256ul>::NewPage()
Line
Count
Source
193
19
  {
194
19
    return static_cast<Page*>(moz_xcalloc(1, sizeof(Page)));
195
19
  }
Unexecuted instantiation: mozilla::Queue<mozilla::LabeledEventQueue::Epoch, 8ul>::NewPage()
Unexecuted instantiation: mozilla::Queue<mozilla::SchedulerGroup::EpochQueueEntry, 32ul>::NewPage()
196
197
  Page* mHead = nullptr;
198
  Page* mTail = nullptr;
199
200
  uint16_t mOffsetHead = 0;  // offset into mHead where next item is removed
201
  uint16_t mOffsetTail = 0;  // offset into mTail where next item is added
202
};
203
204
} // namespace mozilla
205
206
#endif // mozilla_Queue_h