Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef nsVoidArray_h___
6 #define nsVoidArray_h___
8 //#define DEBUG_VOIDARRAY 1
10 #include "nsDebug.h"
12 #include "mozilla/MemoryReporting.h"
13 #include <stdint.h>
15 // Comparator callback function for sorting array values.
16 typedef int (* nsVoidArrayComparatorFunc)
17 (const void* aElement1, const void* aElement2, void* aData);
19 // Enumerator callback function. Return false to stop
20 typedef bool (* nsVoidArrayEnumFunc)(void* aElement, void *aData);
21 typedef bool (* nsVoidArrayEnumFuncConst)(const void* aElement, void *aData);
23 // SizeOfExcludingThis callback function.
24 typedef size_t (* nsVoidArraySizeOfElementIncludingThisFunc)(const void* aElement,
25 mozilla::MallocSizeOf aMallocSizeOf,
26 void *aData);
28 /// A basic zero-based array of void*'s that manages its own memory
29 class NS_COM_GLUE nsVoidArray {
30 public:
31 nsVoidArray();
32 nsVoidArray(int32_t aCount); // initial count of aCount elements set to nullptr
33 ~nsVoidArray();
35 nsVoidArray& operator=(const nsVoidArray& other);
37 inline int32_t Count() const {
38 return mImpl ? mImpl->mCount : 0;
39 }
40 // If the array grows, the newly created entries will all be null
41 bool SetCount(int32_t aNewCount);
42 // returns the max number that can be held without allocating
43 inline int32_t GetArraySize() const {
44 return mImpl ? mImpl->mSize : 0;
45 }
47 void* FastElementAt(int32_t aIndex) const
48 {
49 NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsVoidArray::FastElementAt: index out of range");
50 return mImpl->mArray[aIndex];
51 }
53 // This both asserts and bounds-checks, because (1) we don't want
54 // people to write bad code, but (2) we don't want to change it to
55 // crashing for backwards compatibility. See bug 96108.
56 void* ElementAt(int32_t aIndex) const
57 {
58 NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsVoidArray::ElementAt: index out of range");
59 return SafeElementAt(aIndex);
60 }
62 // bounds-checked version
63 void* SafeElementAt(int32_t aIndex) const
64 {
65 if (uint32_t(aIndex) >= uint32_t(Count())) // handles aIndex < 0 too
66 {
67 return nullptr;
68 }
69 // The bounds check ensures mImpl is non-null.
70 return mImpl->mArray[aIndex];
71 }
73 void* operator[](int32_t aIndex) const { return ElementAt(aIndex); }
75 int32_t IndexOf(void* aPossibleElement) const;
77 bool InsertElementAt(void* aElement, int32_t aIndex);
78 bool InsertElementsAt(const nsVoidArray &other, int32_t aIndex);
80 bool ReplaceElementAt(void* aElement, int32_t aIndex);
82 // useful for doing LRU arrays, sorting, etc
83 bool MoveElement(int32_t aFrom, int32_t aTo);
85 bool AppendElement(void* aElement) {
86 return InsertElementAt(aElement, Count());
87 }
89 bool AppendElements(nsVoidArray& aElements) {
90 return InsertElementsAt(aElements, Count());
91 }
93 bool RemoveElement(void* aElement);
94 void RemoveElementsAt(int32_t aIndex, int32_t aCount);
95 void RemoveElementAt(int32_t aIndex) { return RemoveElementsAt(aIndex,1); }
97 void Clear();
99 bool SizeTo(int32_t aMin);
100 // Subtly different - Compact() tries to be smart about whether we
101 // should reallocate the array; SizeTo() always reallocates.
102 void Compact();
104 void Sort(nsVoidArrayComparatorFunc aFunc, void* aData);
106 bool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData);
107 bool EnumerateForwards(nsVoidArrayEnumFuncConst aFunc, void* aData) const;
108 bool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData);
110 // Measures the size of the array's element storage, and if
111 // |aSizeOfElementIncludingThis| is non-nullptr, measures the size of things
112 // pointed to by elements.
113 size_t SizeOfExcludingThis(
114 nsVoidArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis,
115 mozilla::MallocSizeOf aMallocSizeOf, void* aData = nullptr) const;
117 protected:
118 bool GrowArrayBy(int32_t aGrowBy);
120 struct Impl {
121 /**
122 * The actual array size.
123 */
124 int32_t mSize;
126 /**
127 * The number of elements in the array
128 */
129 int32_t mCount;
131 /**
132 * Array data, padded out to the actual size of the array.
133 */
134 void* mArray[1];
135 };
137 Impl* mImpl;
138 #if DEBUG_VOIDARRAY
139 int32_t mMaxCount;
140 int32_t mMaxSize;
141 bool mIsAuto;
142 #endif
144 // bit twiddlers
145 void SetArray(Impl *newImpl, int32_t aSize, int32_t aCount);
147 private:
148 /// Copy constructors are not allowed
149 nsVoidArray(const nsVoidArray& other);
150 };
152 //===================================================================
153 // nsSmallVoidArray is not a general-purpose replacement for
154 // ns(Auto)VoidArray because there is (some) extra CPU overhead for arrays
155 // larger than 1 element, though not a lot. It is appropriate for
156 // space-sensitive uses where sizes of 0 or 1 are moderately common or
157 // more, and where we're NOT storing arbitrary integers or arbitrary
158 // pointers.
160 // NOTE: nsSmallVoidArray can ONLY be used for holding items that always
161 // have the low bit as a 0 - i.e. element & 1 == 0. This happens to be
162 // true for allocated and object pointers for all the architectures we run
163 // on, but conceivably there might be some architectures/compilers for
164 // which it is NOT true. We know this works for all existing architectures
165 // because if it didn't then nsCheapVoidArray would have failed. Also note
166 // that we will ASSERT if this assumption is violated in DEBUG builds.
168 // XXX we're really re-implementing the whole nsVoidArray interface here -
169 // some form of abstract class would be useful
171 // I disagree on the abstraction here. If the point of this class is to be
172 // as small as possible, and no one will ever derive from it, as I found
173 // today, there should not be any virtualness to it to avoid the vtable
174 // ptr overhead.
176 class NS_COM_GLUE nsSmallVoidArray : private nsVoidArray
177 {
178 public:
179 ~nsSmallVoidArray();
181 nsSmallVoidArray& operator=(nsSmallVoidArray& other);
182 void* operator[](int32_t aIndex) const { return ElementAt(aIndex); }
184 int32_t GetArraySize() const;
186 int32_t Count() const;
187 void* FastElementAt(int32_t aIndex) const;
188 // This both asserts and bounds-checks, because (1) we don't want
189 // people to write bad code, but (2) we don't want to change it to
190 // crashing for backwards compatibility. See bug 96108.
191 void* ElementAt(int32_t aIndex) const
192 {
193 NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsSmallVoidArray::ElementAt: index out of range");
194 return SafeElementAt(aIndex);
195 }
196 void* SafeElementAt(int32_t aIndex) const {
197 // let compiler inline; it may be able to remove these checks
198 if (uint32_t(aIndex) >= uint32_t(Count())) // handles aIndex < 0 too
199 {
200 return nullptr;
201 }
202 return FastElementAt(aIndex);
203 }
204 int32_t IndexOf(void* aPossibleElement) const;
205 bool InsertElementAt(void* aElement, int32_t aIndex);
206 bool InsertElementsAt(const nsVoidArray &other, int32_t aIndex);
207 bool ReplaceElementAt(void* aElement, int32_t aIndex);
208 bool MoveElement(int32_t aFrom, int32_t aTo);
209 bool AppendElement(void* aElement);
210 bool AppendElements(nsVoidArray& aElements) {
211 return InsertElementsAt(aElements, Count());
212 }
213 bool RemoveElement(void* aElement);
214 void RemoveElementsAt(int32_t aIndex, int32_t aCount);
215 void RemoveElementAt(int32_t aIndex);
217 void Clear();
218 bool SizeTo(int32_t aMin);
219 void Compact();
220 void Sort(nsVoidArrayComparatorFunc aFunc, void* aData);
222 bool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData);
223 bool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData);
225 private:
227 bool HasSingle() const
228 {
229 return !!(reinterpret_cast<intptr_t>(mImpl) & 0x1);
230 }
231 void* GetSingle() const
232 {
233 NS_ASSERTION(HasSingle(), "wrong type");
234 return reinterpret_cast<void*>
235 (reinterpret_cast<intptr_t>(mImpl) & ~0x1);
236 }
237 void SetSingle(void *aChild)
238 {
239 NS_ASSERTION(HasSingle() || !mImpl, "overwriting array");
240 mImpl = reinterpret_cast<Impl*>
241 (reinterpret_cast<intptr_t>(aChild) | 0x1);
242 }
243 bool IsEmpty() const
244 {
245 // Note that this isn't the same as Count()==0
246 return !mImpl;
247 }
248 const nsVoidArray* AsArray() const
249 {
250 NS_ASSERTION(!HasSingle(), "This is a single");
251 return this;
252 }
253 nsVoidArray* AsArray()
254 {
255 NS_ASSERTION(!HasSingle(), "This is a single");
256 return this;
257 }
258 bool EnsureArray();
259 };
261 #endif /* nsVoidArray_h___ */