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"
17 * On architectures that are little endian and that support unaligned reads,
18 * we can use direct type, but on others, we want to have a special class
19 * to handle conversion and alignment issues.
21 #if !defined(DEBUG) && (defined(__i386__) || defined(__x86_64__))
22 typedef uint16_t le_uint16
;
23 typedef uint32_t le_uint32
;
27 * Template that allows to find an unsigned int type from a (computed) bit size
33 typedef uint16_t Type
;
37 typedef uint32_t Type
;
41 * Template to access 2 n-bit sized words as a 2*n-bit sized word, doing
42 * conversion from little endian and avoiding alignment issues.
47 typedef typename UInt
<16 * sizeof(T
)>::Type Type
;
49 operator Type() const { return (b
<< (sizeof(T
) * 8)) | a
; }
51 const le_to_cpu
& operator=(const Type
& v
) {
52 a
= v
& ((1 << (sizeof(T
) * 8)) - 1);
53 b
= v
>> (sizeof(T
) * 8);
58 explicit le_to_cpu(const Type
& v
) { operator=(v
); }
60 const le_to_cpu
& operator+=(const Type
& v
) {
61 return operator=(operator Type() + v
);
64 const le_to_cpu
& operator++(int) { return operator=(operator Type() + 1); }
73 typedef le_to_cpu
<unsigned char> le_uint16
;
74 typedef le_to_cpu
<le_uint16
> le_uint32
;
80 MOZ_IMPLICIT
AutoCloseFD(int fd
) : fd(fd
) {}
82 if (fd
!= -1) close(fd
);
84 operator int() const { return fd
; }
87 extern mozilla::Atomic
<size_t, mozilla::ReleaseAcquire
> gPageSize
;
90 * Page alignment helpers
92 static size_t PageSize() {
94 gPageSize
= sysconf(_SC_PAGESIZE
);
100 static inline uintptr_t AlignedPtr(uintptr_t ptr
, size_t alignment
) {
101 return ptr
& ~(alignment
- 1);
104 template <typename T
>
105 static inline T
* AlignedPtr(T
* ptr
, size_t alignment
) {
106 return reinterpret_cast<T
*>(
107 AlignedPtr(reinterpret_cast<uintptr_t>(ptr
), alignment
));
110 template <typename T
>
111 static inline T
PageAlignedPtr(T ptr
) {
112 return AlignedPtr(ptr
, PageSize());
115 static inline uintptr_t AlignedEndPtr(uintptr_t ptr
, size_t alignment
) {
116 return AlignedPtr(ptr
+ alignment
- 1, alignment
);
119 template <typename T
>
120 static inline T
* AlignedEndPtr(T
* ptr
, size_t alignment
) {
121 return reinterpret_cast<T
*>(
122 AlignedEndPtr(reinterpret_cast<uintptr_t>(ptr
), alignment
));
125 template <typename T
>
126 static inline T
PageAlignedEndPtr(T ptr
) {
127 return AlignedEndPtr(ptr
, PageSize());
130 static inline size_t AlignedSize(size_t size
, size_t alignment
) {
131 return (size
+ alignment
- 1) & ~(alignment
- 1);
134 static inline size_t PageAlignedSize(size_t size
) {
135 return AlignedSize(size
, PageSize());
138 static inline bool IsAlignedPtr(uintptr_t ptr
, size_t alignment
) {
139 return ptr
% alignment
== 0;
142 template <typename T
>
143 static inline bool IsAlignedPtr(T
* ptr
, size_t alignment
) {
144 return IsAlignedPtr(reinterpret_cast<uintptr_t>(ptr
), alignment
);
147 template <typename T
>
148 static inline bool IsPageAlignedPtr(T ptr
) {
149 return IsAlignedPtr(ptr
, PageSize());
152 static inline bool IsAlignedSize(size_t size
, size_t alignment
) {
153 return size
% alignment
== 0;
156 static inline bool IsPageAlignedSize(size_t size
) {
157 return IsAlignedSize(size
, PageSize());
160 static inline size_t PageNumber(size_t size
) {
161 return (size
+ PageSize() - 1) / PageSize();
165 * MemoryRange stores a pointer, size pair.
169 MemoryRange(void* buf
, size_t length
) : buf(buf
), length(length
) {}
171 void Assign(void* b
, size_t len
) {
176 void Assign(const MemoryRange
& other
) {
178 length
= other
.length
;
181 void* get() const { return buf
; }
183 operator void*() const { return buf
; }
185 operator unsigned char*() const {
186 return reinterpret_cast<unsigned char*>(buf
);
189 bool operator==(void* ptr
) const { return buf
== ptr
; }
191 bool operator==(unsigned char* ptr
) const { return buf
== ptr
; }
193 void* operator+(off_t offset
) const {
194 return reinterpret_cast<char*>(buf
) + offset
;
198 * Returns whether the given address is within the mapped range
200 bool Contains(void* ptr
) const {
201 return (ptr
>= buf
) && (ptr
< reinterpret_cast<char*>(buf
) + length
);
205 * Returns the length of the mapped range
207 size_t GetLength() const { return length
; }
209 static MemoryRange
mmap(void* addr
, size_t length
, int prot
, int flags
,
210 int fd
, off_t offset
) {
211 return MemoryRange(::mmap(addr
, length
, prot
, flags
, fd
, offset
), length
);
220 * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as
221 * a simple void * or unsigned char *.
223 * It is defined as a derivative of a template that allows to use a
224 * different unmapping strategy.
226 template <typename T
>
227 class GenericMappedPtr
: public MemoryRange
{
229 GenericMappedPtr(void* buf
, size_t length
) : MemoryRange(buf
, length
) {}
230 explicit GenericMappedPtr(const MemoryRange
& other
) : MemoryRange(other
) {}
231 GenericMappedPtr() : MemoryRange(MAP_FAILED
, 0) {}
233 void Assign(void* b
, size_t len
) {
234 if (get() != MAP_FAILED
) static_cast<T
*>(this)->munmap(get(), GetLength());
235 MemoryRange::Assign(b
, len
);
238 void Assign(const MemoryRange
& other
) {
239 Assign(other
.get(), other
.GetLength());
242 ~GenericMappedPtr() {
243 if (get() != MAP_FAILED
) static_cast<T
*>(this)->munmap(get(), GetLength());
246 void release() { MemoryRange::Assign(MAP_FAILED
, 0); }
249 struct MappedPtr
: public GenericMappedPtr
<MappedPtr
> {
250 MappedPtr(void* buf
, size_t length
)
251 : GenericMappedPtr
<MappedPtr
>(buf
, length
) {}
252 MOZ_IMPLICIT
MappedPtr(const MemoryRange
& other
)
253 : GenericMappedPtr
<MappedPtr
>(other
) {}
254 MappedPtr() : GenericMappedPtr
<MappedPtr
>() {}
257 friend class GenericMappedPtr
<MappedPtr
>;
258 void munmap(void* buf
, size_t length
) { ::munmap(buf
, length
); }
262 * UnsizedArray is a way to access raw arrays of data in memory.
265 * UnsizedArray<S> a(buf);
266 * UnsizedArray<S> b; b.Init(buf);
268 * This is roughly equivalent to
269 * const S *a = reinterpret_cast<const S *>(buf);
270 * const S *b = nullptr; b = reinterpret_cast<const S *>(buf);
272 * An UnsizedArray has no known length, and it's up to the caller to make
273 * sure the accessed memory is mapped and makes sense.
275 template <typename T
>
278 typedef size_t idx_t
;
281 * Constructors and Initializers
283 UnsizedArray() : contents(nullptr) {}
284 explicit UnsizedArray(const void* buf
)
285 : contents(reinterpret_cast<const T
*>(buf
)) {}
287 void Init(const void* buf
) {
288 MOZ_ASSERT(contents
== nullptr);
289 contents
= reinterpret_cast<const T
*>(buf
);
293 * Returns the nth element of the array
295 const T
& operator[](const idx_t index
) const {
296 MOZ_ASSERT(contents
);
297 return contents
[index
];
300 operator const T
*() const { return contents
; }
302 * Returns whether the array points somewhere
304 explicit operator bool() const { return contents
!= nullptr; }
311 * Array, like UnsizedArray, is a way to access raw arrays of data in memory.
312 * Unlike UnsizedArray, it has a known length, and is enumerable with an
316 * Array<S> a(buf, len);
317 * UnsizedArray<S> b; b.Init(buf, len);
319 * In the above examples, len is the number of elements in the array. It is
320 * also possible to initialize an Array with the buffer size:
322 * Array<S> c; c.InitSize(buf, size);
324 * It is also possible to initialize an Array in two steps, only providing
325 * one data at a time:
329 * d.Init(len); // or d.InitSize(size);
332 template <typename T
>
333 class Array
: public UnsizedArray
<T
> {
335 typedef typename UnsizedArray
<T
>::idx_t idx_t
;
338 * Constructors and Initializers
340 Array() : UnsizedArray
<T
>(), length(0) {}
341 Array(const void* buf
, const idx_t length
)
342 : UnsizedArray
<T
>(buf
), length(length
) {}
344 void Init(const void* buf
) { UnsizedArray
<T
>::Init(buf
); }
346 void Init(const idx_t len
) {
347 MOZ_ASSERT(length
== 0);
351 void InitSize(const idx_t size
) { Init(size
/ sizeof(T
)); }
353 void Init(const void* buf
, const idx_t len
) {
354 UnsizedArray
<T
>::Init(buf
);
358 void InitSize(const void* buf
, const idx_t size
) {
359 UnsizedArray
<T
>::Init(buf
);
364 * Returns the nth element of the array
366 const T
& operator[](const idx_t index
) const {
367 MOZ_ASSERT(index
< length
);
368 MOZ_ASSERT(operator bool());
369 return UnsizedArray
<T
>::operator[](index
);
373 * Returns the number of elements in the array
375 idx_t
numElements() const { return length
; }
378 * Returns whether the array points somewhere and has at least one element.
380 explicit operator bool() const {
381 return (length
> 0) && UnsizedArray
<T
>::operator bool();
385 * Iterator for an Array. Use is similar to that of STL const_iterators:
388 * Array<S> a(buf, len);
389 * for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) {
390 * // Do something with *it.
395 iterator() : item(nullptr) {}
397 const T
& operator*() const { return *item
; }
399 const T
* operator->() const { return item
; }
401 iterator
& operator++() {
406 bool operator<(const iterator
& other
) const { return item
< other
.item
; }
409 friend class Array
<T
>;
410 explicit iterator(const T
& item
) : item(&item
) {}
417 * Returns an iterator pointing at the beginning of the Array
419 iterator
begin() const {
420 if (length
) return iterator(UnsizedArray
<T
>::operator[](0));
425 * Returns an iterator pointing past the end of the Array
427 iterator
end() const {
428 if (length
) return iterator(UnsizedArray
<T
>::operator[](length
));
433 * Reverse iterator for an Array. Use is similar to that of STL
434 * const_reverse_iterators:
437 * Array<S> a(buf, len);
438 * for (Array<S>::reverse_iterator it = a.rbegin(); it < a.rend(); ++it) {
439 * // Do something with *it.
442 class reverse_iterator
{
444 reverse_iterator() : item(nullptr) {}
446 const T
& operator*() const {
451 const T
* operator->() const { return &operator*(); }
453 reverse_iterator
& operator++() {
458 bool operator<(const reverse_iterator
& other
) const {
459 return item
> other
.item
;
463 friend class Array
<T
>;
464 explicit reverse_iterator(const T
& item
) : item(&item
) {}
471 * Returns a reverse iterator pointing at the end of the Array
473 reverse_iterator
rbegin() const {
474 if (length
) return reverse_iterator(UnsizedArray
<T
>::operator[](length
));
475 return reverse_iterator();
479 * Returns a reverse iterator pointing past the beginning of the Array
481 reverse_iterator
rend() const {
482 if (length
) return reverse_iterator(UnsizedArray
<T
>::operator[](0));
483 return reverse_iterator();
491 * Transforms a pointer-to-function to a pointer-to-object pointing at the
494 template <typename T
>
495 void* FunctionPtr(T func
) {
506 explicit AutoLock(pthread_mutex_t
* mutex
) : mutex(mutex
) {
507 if (pthread_mutex_lock(mutex
)) MOZ_CRASH("pthread_mutex_lock failed");
510 if (pthread_mutex_unlock(mutex
)) MOZ_CRASH("pthread_mutex_unlock failed");
514 pthread_mutex_t
* mutex
;