1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
13 #include "mozilla/Assertions.h"
14 #include "mozilla/Atomics.h"
15 #include "mozilla/Scoped.h"
18 * On architectures that are little endian and that support unaligned reads,
19 * we can use direct type, but on others, we want to have a special class
20 * to handle conversion and alignment issues.
22 #if !defined(DEBUG) && (defined(__i386__) || defined(__x86_64__))
23 typedef uint16_t le_uint16
;
24 typedef uint32_t le_uint32
;
28 * Template that allows to find an unsigned int type from a (computed) bit size
34 typedef uint16_t Type
;
38 typedef uint32_t Type
;
42 * Template to access 2 n-bit sized words as a 2*n-bit sized word, doing
43 * conversion from little endian and avoiding alignment issues.
48 typedef typename UInt
<16 * sizeof(T
)>::Type Type
;
50 operator Type() const { return (b
<< (sizeof(T
) * 8)) | a
; }
52 const le_to_cpu
& operator=(const Type
& v
) {
53 a
= v
& ((1 << (sizeof(T
) * 8)) - 1);
54 b
= v
>> (sizeof(T
) * 8);
59 explicit le_to_cpu(const Type
& v
) { operator=(v
); }
61 const le_to_cpu
& operator+=(const Type
& v
) {
62 return operator=(operator Type() + v
);
65 const le_to_cpu
& operator++(int) { return operator=(operator Type() + 1); }
74 typedef le_to_cpu
<unsigned char> le_uint16
;
75 typedef le_to_cpu
<le_uint16
> le_uint32
;
79 * AutoCloseFD is a RAII wrapper for POSIX file descriptors
81 struct AutoCloseFDTraits
{
83 static int empty() { return -1; }
84 static void release(int fd
) {
85 if (fd
!= -1) close(fd
);
88 typedef mozilla::Scoped
<AutoCloseFDTraits
> AutoCloseFD
;
91 * AutoCloseFILE is a RAII wrapper for POSIX streams
93 struct AutoCloseFILETraits
{
95 static FILE* empty() { return nullptr; }
96 static void release(FILE* f
) {
100 typedef mozilla::Scoped
<AutoCloseFILETraits
> AutoCloseFILE
;
102 extern mozilla::Atomic
<size_t, mozilla::ReleaseAcquire
> gPageSize
;
105 * Page alignment helpers
107 static size_t PageSize() {
109 gPageSize
= sysconf(_SC_PAGESIZE
);
115 static inline uintptr_t AlignedPtr(uintptr_t ptr
, size_t alignment
) {
116 return ptr
& ~(alignment
- 1);
119 template <typename T
>
120 static inline T
* AlignedPtr(T
* ptr
, size_t alignment
) {
121 return reinterpret_cast<T
*>(
122 AlignedPtr(reinterpret_cast<uintptr_t>(ptr
), alignment
));
125 template <typename T
>
126 static inline T
PageAlignedPtr(T ptr
) {
127 return AlignedPtr(ptr
, PageSize());
130 static inline uintptr_t AlignedEndPtr(uintptr_t ptr
, size_t alignment
) {
131 return AlignedPtr(ptr
+ alignment
- 1, alignment
);
134 template <typename T
>
135 static inline T
* AlignedEndPtr(T
* ptr
, size_t alignment
) {
136 return reinterpret_cast<T
*>(
137 AlignedEndPtr(reinterpret_cast<uintptr_t>(ptr
), alignment
));
140 template <typename T
>
141 static inline T
PageAlignedEndPtr(T ptr
) {
142 return AlignedEndPtr(ptr
, PageSize());
145 static inline size_t AlignedSize(size_t size
, size_t alignment
) {
146 return (size
+ alignment
- 1) & ~(alignment
- 1);
149 static inline size_t PageAlignedSize(size_t size
) {
150 return AlignedSize(size
, PageSize());
153 static inline bool IsAlignedPtr(uintptr_t ptr
, size_t alignment
) {
154 return ptr
% alignment
== 0;
157 template <typename T
>
158 static inline bool IsAlignedPtr(T
* ptr
, size_t alignment
) {
159 return IsAlignedPtr(reinterpret_cast<uintptr_t>(ptr
), alignment
);
162 template <typename T
>
163 static inline bool IsPageAlignedPtr(T ptr
) {
164 return IsAlignedPtr(ptr
, PageSize());
167 static inline bool IsAlignedSize(size_t size
, size_t alignment
) {
168 return size
% alignment
== 0;
171 static inline bool IsPageAlignedSize(size_t size
) {
172 return IsAlignedSize(size
, PageSize());
175 static inline size_t PageNumber(size_t size
) {
176 return (size
+ PageSize() - 1) / PageSize();
180 * MemoryRange stores a pointer, size pair.
184 MemoryRange(void* buf
, size_t length
) : buf(buf
), length(length
) {}
186 void Assign(void* b
, size_t len
) {
191 void Assign(const MemoryRange
& other
) {
193 length
= other
.length
;
196 void* get() const { return buf
; }
198 operator void*() const { return buf
; }
200 operator unsigned char*() const {
201 return reinterpret_cast<unsigned char*>(buf
);
204 bool operator==(void* ptr
) const { return buf
== ptr
; }
206 bool operator==(unsigned char* ptr
) const { return buf
== ptr
; }
208 void* operator+(off_t offset
) const {
209 return reinterpret_cast<char*>(buf
) + offset
;
213 * Returns whether the given address is within the mapped range
215 bool Contains(void* ptr
) const {
216 return (ptr
>= buf
) && (ptr
< reinterpret_cast<char*>(buf
) + length
);
220 * Returns the length of the mapped range
222 size_t GetLength() const { return length
; }
224 static MemoryRange
mmap(void* addr
, size_t length
, int prot
, int flags
,
225 int fd
, off_t offset
) {
226 return MemoryRange(::mmap(addr
, length
, prot
, flags
, fd
, offset
), length
);
235 * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as
236 * a simple void * or unsigned char *.
238 * It is defined as a derivative of a template that allows to use a
239 * different unmapping strategy.
241 template <typename T
>
242 class GenericMappedPtr
: public MemoryRange
{
244 GenericMappedPtr(void* buf
, size_t length
) : MemoryRange(buf
, length
) {}
245 explicit GenericMappedPtr(const MemoryRange
& other
) : MemoryRange(other
) {}
246 GenericMappedPtr() : MemoryRange(MAP_FAILED
, 0) {}
248 void Assign(void* b
, size_t len
) {
249 if (get() != MAP_FAILED
) static_cast<T
*>(this)->munmap(get(), GetLength());
250 MemoryRange::Assign(b
, len
);
253 void Assign(const MemoryRange
& other
) {
254 Assign(other
.get(), other
.GetLength());
257 ~GenericMappedPtr() {
258 if (get() != MAP_FAILED
) static_cast<T
*>(this)->munmap(get(), GetLength());
261 void release() { MemoryRange::Assign(MAP_FAILED
, 0); }
264 struct MappedPtr
: public GenericMappedPtr
<MappedPtr
> {
265 MappedPtr(void* buf
, size_t length
)
266 : GenericMappedPtr
<MappedPtr
>(buf
, length
) {}
267 MOZ_IMPLICIT
MappedPtr(const MemoryRange
& other
)
268 : GenericMappedPtr
<MappedPtr
>(other
) {}
269 MappedPtr() : GenericMappedPtr
<MappedPtr
>() {}
272 friend class GenericMappedPtr
<MappedPtr
>;
273 void munmap(void* buf
, size_t length
) { ::munmap(buf
, length
); }
277 * UnsizedArray is a way to access raw arrays of data in memory.
280 * UnsizedArray<S> a(buf);
281 * UnsizedArray<S> b; b.Init(buf);
283 * This is roughly equivalent to
284 * const S *a = reinterpret_cast<const S *>(buf);
285 * const S *b = nullptr; b = reinterpret_cast<const S *>(buf);
287 * An UnsizedArray has no known length, and it's up to the caller to make
288 * sure the accessed memory is mapped and makes sense.
290 template <typename T
>
293 typedef size_t idx_t
;
296 * Constructors and Initializers
298 UnsizedArray() : contents(nullptr) {}
299 explicit UnsizedArray(const void* buf
)
300 : contents(reinterpret_cast<const T
*>(buf
)) {}
302 void Init(const void* buf
) {
303 MOZ_ASSERT(contents
== nullptr);
304 contents
= reinterpret_cast<const T
*>(buf
);
308 * Returns the nth element of the array
310 const T
& operator[](const idx_t index
) const {
311 MOZ_ASSERT(contents
);
312 return contents
[index
];
315 operator const T
*() const { return contents
; }
317 * Returns whether the array points somewhere
319 explicit operator bool() const { return contents
!= nullptr; }
326 * Array, like UnsizedArray, is a way to access raw arrays of data in memory.
327 * Unlike UnsizedArray, it has a known length, and is enumerable with an
331 * Array<S> a(buf, len);
332 * UnsizedArray<S> b; b.Init(buf, len);
334 * In the above examples, len is the number of elements in the array. It is
335 * also possible to initialize an Array with the buffer size:
337 * Array<S> c; c.InitSize(buf, size);
339 * It is also possible to initialize an Array in two steps, only providing
340 * one data at a time:
344 * d.Init(len); // or d.InitSize(size);
347 template <typename T
>
348 class Array
: public UnsizedArray
<T
> {
350 typedef typename UnsizedArray
<T
>::idx_t idx_t
;
353 * Constructors and Initializers
355 Array() : UnsizedArray
<T
>(), length(0) {}
356 Array(const void* buf
, const idx_t length
)
357 : UnsizedArray
<T
>(buf
), length(length
) {}
359 void Init(const void* buf
) { UnsizedArray
<T
>::Init(buf
); }
361 void Init(const idx_t len
) {
362 MOZ_ASSERT(length
== 0);
366 void InitSize(const idx_t size
) { Init(size
/ sizeof(T
)); }
368 void Init(const void* buf
, const idx_t len
) {
369 UnsizedArray
<T
>::Init(buf
);
373 void InitSize(const void* buf
, const idx_t size
) {
374 UnsizedArray
<T
>::Init(buf
);
379 * Returns the nth element of the array
381 const T
& operator[](const idx_t index
) const {
382 MOZ_ASSERT(index
< length
);
383 MOZ_ASSERT(operator bool());
384 return UnsizedArray
<T
>::operator[](index
);
388 * Returns the number of elements in the array
390 idx_t
numElements() const { return length
; }
393 * Returns whether the array points somewhere and has at least one element.
395 explicit operator bool() const {
396 return (length
> 0) && UnsizedArray
<T
>::operator bool();
400 * Iterator for an Array. Use is similar to that of STL const_iterators:
403 * Array<S> a(buf, len);
404 * for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) {
405 * // Do something with *it.
410 iterator() : item(nullptr) {}
412 const T
& operator*() const { return *item
; }
414 const T
* operator->() const { return item
; }
416 iterator
& operator++() {
421 bool operator<(const iterator
& other
) const { return item
< other
.item
; }
424 friend class Array
<T
>;
425 explicit iterator(const T
& item
) : item(&item
) {}
432 * Returns an iterator pointing at the beginning of the Array
434 iterator
begin() const {
435 if (length
) return iterator(UnsizedArray
<T
>::operator[](0));
440 * Returns an iterator pointing past the end of the Array
442 iterator
end() const {
443 if (length
) return iterator(UnsizedArray
<T
>::operator[](length
));
448 * Reverse iterator for an Array. Use is similar to that of STL
449 * const_reverse_iterators:
452 * Array<S> a(buf, len);
453 * for (Array<S>::reverse_iterator it = a.rbegin(); it < a.rend(); ++it) {
454 * // Do something with *it.
457 class reverse_iterator
{
459 reverse_iterator() : item(nullptr) {}
461 const T
& operator*() const {
466 const T
* operator->() const { return &operator*(); }
468 reverse_iterator
& operator++() {
473 bool operator<(const reverse_iterator
& other
) const {
474 return item
> other
.item
;
478 friend class Array
<T
>;
479 explicit reverse_iterator(const T
& item
) : item(&item
) {}
486 * Returns a reverse iterator pointing at the end of the Array
488 reverse_iterator
rbegin() const {
489 if (length
) return reverse_iterator(UnsizedArray
<T
>::operator[](length
));
490 return reverse_iterator();
494 * Returns a reverse iterator pointing past the beginning of the Array
496 reverse_iterator
rend() const {
497 if (length
) return reverse_iterator(UnsizedArray
<T
>::operator[](0));
498 return reverse_iterator();
506 * Transforms a pointer-to-function to a pointer-to-object pointing at the
509 template <typename T
>
510 void* FunctionPtr(T func
) {
521 explicit AutoLock(pthread_mutex_t
* mutex
) : mutex(mutex
) {
522 if (pthread_mutex_lock(mutex
)) MOZ_CRASH("pthread_mutex_lock failed");
525 if (pthread_mutex_unlock(mutex
)) MOZ_CRASH("pthread_mutex_unlock failed");
529 pthread_mutex_t
* mutex
;