Bug 1568157 - Part 4: Replace `toolbox.walker` with the contextual WalkerFront. r...
[gecko.git] / mozglue / linker / Utils.h
blobd3827f1f41456660c1de0d9f4000f2b1822f39cf
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/. */
5 #ifndef Utils_h
6 #define Utils_h
8 #include <pthread.h>
9 #include <stdint.h>
10 #include <stddef.h>
11 #include <sys/mman.h>
12 #include <unistd.h>
13 #include "mozilla/Assertions.h"
14 #include "mozilla/Atomics.h"
15 #include "mozilla/Scoped.h"
17 /**
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;
25 #else
27 /**
28 * Template that allows to find an unsigned int type from a (computed) bit size
30 template <int s>
31 struct UInt {};
32 template <>
33 struct UInt<16> {
34 typedef uint16_t Type;
36 template <>
37 struct UInt<32> {
38 typedef uint32_t Type;
41 /**
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.
45 template <typename T>
46 class le_to_cpu {
47 public:
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);
55 return *this;
58 le_to_cpu() {}
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); }
67 private:
68 T a, b;
71 /**
72 * Type definitions
74 typedef le_to_cpu<unsigned char> le_uint16;
75 typedef le_to_cpu<le_uint16> le_uint32;
76 #endif
78 /**
79 * AutoCloseFD is a RAII wrapper for POSIX file descriptors
81 struct AutoCloseFDTraits {
82 typedef int type;
83 static int empty() { return -1; }
84 static void release(int fd) {
85 if (fd != -1) close(fd);
88 typedef mozilla::Scoped<AutoCloseFDTraits> AutoCloseFD;
90 /**
91 * AutoCloseFILE is a RAII wrapper for POSIX streams
93 struct AutoCloseFILETraits {
94 typedef FILE* type;
95 static FILE* empty() { return nullptr; }
96 static void release(FILE* f) {
97 if (f) fclose(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() {
108 if (!gPageSize) {
109 gPageSize = sysconf(_SC_PAGESIZE);
112 return gPageSize;
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.
182 class MemoryRange {
183 public:
184 MemoryRange(void* buf, size_t length) : buf(buf), length(length) {}
186 void Assign(void* b, size_t len) {
187 buf = b;
188 length = len;
191 void Assign(const MemoryRange& other) {
192 buf = other.buf;
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);
229 private:
230 void* buf;
231 size_t 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 {
243 public:
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>() {}
271 private:
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.
279 * struct S { ... };
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>
291 class UnsizedArray {
292 public:
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; }
321 private:
322 const T* contents;
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
328 * iterator.
330 * struct S { ... };
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:
342 * Array<S> d;
343 * d.Init(buf);
344 * d.Init(len); // or d.InitSize(size);
347 template <typename T>
348 class Array : public UnsizedArray<T> {
349 public:
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);
363 length = len;
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);
370 Init(len);
373 void InitSize(const void* buf, const idx_t size) {
374 UnsizedArray<T>::Init(buf);
375 InitSize(size);
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:
402 * struct S { ... };
403 * Array<S> a(buf, len);
404 * for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) {
405 * // Do something with *it.
408 class iterator {
409 public:
410 iterator() : item(nullptr) {}
412 const T& operator*() const { return *item; }
414 const T* operator->() const { return item; }
416 iterator& operator++() {
417 ++item;
418 return *this;
421 bool operator<(const iterator& other) const { return item < other.item; }
423 protected:
424 friend class Array<T>;
425 explicit iterator(const T& item) : item(&item) {}
427 private:
428 const T* 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));
436 return iterator();
440 * Returns an iterator pointing past the end of the Array
442 iterator end() const {
443 if (length) return iterator(UnsizedArray<T>::operator[](length));
444 return iterator();
448 * Reverse iterator for an Array. Use is similar to that of STL
449 * const_reverse_iterators:
451 * struct S { ... };
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 {
458 public:
459 reverse_iterator() : item(nullptr) {}
461 const T& operator*() const {
462 const T* tmp = item;
463 return *--tmp;
466 const T* operator->() const { return &operator*(); }
468 reverse_iterator& operator++() {
469 --item;
470 return *this;
473 bool operator<(const reverse_iterator& other) const {
474 return item > other.item;
477 protected:
478 friend class Array<T>;
479 explicit reverse_iterator(const T& item) : item(&item) {}
481 private:
482 const T* 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();
501 private:
502 idx_t length;
506 * Transforms a pointer-to-function to a pointer-to-object pointing at the
507 * same address.
509 template <typename T>
510 void* FunctionPtr(T func) {
511 union {
512 void* ptr;
513 T func;
514 } f;
515 f.func = func;
516 return f.ptr;
519 class AutoLock {
520 public:
521 explicit AutoLock(pthread_mutex_t* mutex) : mutex(mutex) {
522 if (pthread_mutex_lock(mutex)) MOZ_CRASH("pthread_mutex_lock failed");
524 ~AutoLock() {
525 if (pthread_mutex_unlock(mutex)) MOZ_CRASH("pthread_mutex_unlock failed");
528 private:
529 pthread_mutex_t* mutex;
532 #endif /* Utils_h */