summaryrefslogtreecommitdiffstats
path: root/mozglue/linker/Utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'mozglue/linker/Utils.h')
-rw-r--r--mozglue/linker/Utils.h618
1 files changed, 618 insertions, 0 deletions
diff --git a/mozglue/linker/Utils.h b/mozglue/linker/Utils.h
new file mode 100644
index 000000000..c5314ef60
--- /dev/null
+++ b/mozglue/linker/Utils.h
@@ -0,0 +1,618 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef Utils_h
+#define Utils_h
+
+#include <pthread.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include "mozilla/Assertions.h"
+#include "mozilla/Scoped.h"
+
+/**
+ * On architectures that are little endian and that support unaligned reads,
+ * we can use direct type, but on others, we want to have a special class
+ * to handle conversion and alignment issues.
+ */
+#if !defined(DEBUG) && (defined(__i386__) || defined(__x86_64__))
+typedef uint16_t le_uint16;
+typedef uint32_t le_uint32;
+#else
+
+/**
+ * Template that allows to find an unsigned int type from a (computed) bit size
+ */
+template <int s> struct UInt { };
+template <> struct UInt<16> { typedef uint16_t Type; };
+template <> struct UInt<32> { typedef uint32_t Type; };
+
+/**
+ * Template to access 2 n-bit sized words as a 2*n-bit sized word, doing
+ * conversion from little endian and avoiding alignment issues.
+ */
+template <typename T>
+class le_to_cpu
+{
+public:
+ typedef typename UInt<16 * sizeof(T)>::Type Type;
+
+ operator Type() const
+ {
+ return (b << (sizeof(T) * 8)) | a;
+ }
+
+ const le_to_cpu& operator =(const Type &v)
+ {
+ a = v & ((1 << (sizeof(T) * 8)) - 1);
+ b = v >> (sizeof(T) * 8);
+ return *this;
+ }
+
+ le_to_cpu() { }
+ le_to_cpu(const Type &v)
+ {
+ operator =(v);
+ }
+
+ const le_to_cpu& operator +=(const Type &v)
+ {
+ return operator =(operator Type() + v);
+ }
+
+ const le_to_cpu& operator ++(int)
+ {
+ return operator =(operator Type() + 1);
+ }
+
+private:
+ T a, b;
+};
+
+/**
+ * Type definitions
+ */
+typedef le_to_cpu<unsigned char> le_uint16;
+typedef le_to_cpu<le_uint16> le_uint32;
+#endif
+
+
+/**
+ * AutoCloseFD is a RAII wrapper for POSIX file descriptors
+ */
+struct AutoCloseFDTraits
+{
+ typedef int type;
+ static int empty() { return -1; }
+ static void release(int fd) { if (fd != -1) close(fd); }
+};
+typedef mozilla::Scoped<AutoCloseFDTraits> AutoCloseFD;
+
+/**
+ * AutoCloseFILE is a RAII wrapper for POSIX streams
+ */
+struct AutoCloseFILETraits
+{
+ typedef FILE *type;
+ static FILE *empty() { return nullptr; }
+ static void release(FILE *f) { if (f) fclose(f); }
+};
+typedef mozilla::Scoped<AutoCloseFILETraits> AutoCloseFILE;
+
+/**
+ * Page alignment helpers
+ */
+static inline size_t PageSize()
+{
+ return 4096;
+}
+
+static inline uintptr_t AlignedPtr(uintptr_t ptr, size_t alignment)
+{
+ return ptr & ~(alignment - 1);
+}
+
+template <typename T>
+static inline T *AlignedPtr(T *ptr, size_t alignment)
+{
+ return reinterpret_cast<T *>(
+ AlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment));
+}
+
+template <typename T>
+static inline T PageAlignedPtr(T ptr)
+{
+ return AlignedPtr(ptr, PageSize());
+}
+
+static inline uintptr_t AlignedEndPtr(uintptr_t ptr, size_t alignment)
+{
+ return AlignedPtr(ptr + alignment - 1, alignment);
+}
+
+template <typename T>
+static inline T *AlignedEndPtr(T *ptr, size_t alignment)
+{
+ return reinterpret_cast<T *>(
+ AlignedEndPtr(reinterpret_cast<uintptr_t>(ptr), alignment));
+}
+
+template <typename T>
+static inline T PageAlignedEndPtr(T ptr)
+{
+ return AlignedEndPtr(ptr, PageSize());
+}
+
+static inline size_t AlignedSize(size_t size, size_t alignment)
+{
+ return (size + alignment - 1) & ~(alignment - 1);
+}
+
+static inline size_t PageAlignedSize(size_t size)
+{
+ return AlignedSize(size, PageSize());
+}
+
+static inline bool IsAlignedPtr(uintptr_t ptr, size_t alignment)
+{
+ return ptr % alignment == 0;
+}
+
+template <typename T>
+static inline bool IsAlignedPtr(T *ptr, size_t alignment)
+{
+ return IsAlignedPtr(reinterpret_cast<uintptr_t>(ptr), alignment);
+}
+
+template <typename T>
+static inline bool IsPageAlignedPtr(T ptr)
+{
+ return IsAlignedPtr(ptr, PageSize());
+}
+
+static inline bool IsAlignedSize(size_t size, size_t alignment)
+{
+ return size % alignment == 0;
+}
+
+static inline bool IsPageAlignedSize(size_t size)
+{
+ return IsAlignedSize(size, PageSize());
+}
+
+static inline size_t PageNumber(size_t size)
+{
+ return (size + PageSize() - 1) / PageSize();
+}
+
+/**
+ * MemoryRange stores a pointer, size pair.
+ */
+class MemoryRange
+{
+public:
+ MemoryRange(void *buf, size_t length): buf(buf), length(length) { }
+
+ void Assign(void *b, size_t len) {
+ buf = b;
+ length = len;
+ }
+
+ void Assign(const MemoryRange& other) {
+ buf = other.buf;
+ length = other.length;
+ }
+
+ void *get() const
+ {
+ return buf;
+ }
+
+ operator void *() const
+ {
+ return buf;
+ }
+
+ operator unsigned char *() const
+ {
+ return reinterpret_cast<unsigned char *>(buf);
+ }
+
+ bool operator ==(void *ptr) const {
+ return buf == ptr;
+ }
+
+ bool operator ==(unsigned char *ptr) const {
+ return buf == ptr;
+ }
+
+ void *operator +(off_t offset) const
+ {
+ return reinterpret_cast<char *>(buf) + offset;
+ }
+
+ /**
+ * Returns whether the given address is within the mapped range
+ */
+ bool Contains(void *ptr) const
+ {
+ return (ptr >= buf) && (ptr < reinterpret_cast<char *>(buf) + length);
+ }
+
+ /**
+ * Returns the length of the mapped range
+ */
+ size_t GetLength() const
+ {
+ return length;
+ }
+
+ static MemoryRange mmap(void *addr, size_t length, int prot, int flags,
+ int fd, off_t offset) {
+ return MemoryRange(::mmap(addr, length, prot, flags, fd, offset), length);
+ }
+
+private:
+ void *buf;
+ size_t length;
+};
+
+/**
+ * MappedPtr is a RAII wrapper for mmap()ed memory. It can be used as
+ * a simple void * or unsigned char *.
+ *
+ * It is defined as a derivative of a template that allows to use a
+ * different unmapping strategy.
+ */
+template <typename T>
+class GenericMappedPtr: public MemoryRange
+{
+public:
+ GenericMappedPtr(void *buf, size_t length): MemoryRange(buf, length) { }
+ GenericMappedPtr(const MemoryRange& other): MemoryRange(other) { }
+ GenericMappedPtr(): MemoryRange(MAP_FAILED, 0) { }
+
+ void Assign(void *b, size_t len) {
+ if (get() != MAP_FAILED)
+ static_cast<T *>(this)->munmap(get(), GetLength());
+ MemoryRange::Assign(b, len);
+ }
+
+ void Assign(const MemoryRange& other) {
+ Assign(other.get(), other.GetLength());
+ }
+
+ ~GenericMappedPtr()
+ {
+ if (get() != MAP_FAILED)
+ static_cast<T *>(this)->munmap(get(), GetLength());
+ }
+
+ void release()
+ {
+ MemoryRange::Assign(MAP_FAILED, 0);
+ }
+};
+
+struct MappedPtr: public GenericMappedPtr<MappedPtr>
+{
+ MappedPtr(void *buf, size_t length)
+ : GenericMappedPtr<MappedPtr>(buf, length) { }
+ MappedPtr(const MemoryRange& other)
+ : GenericMappedPtr<MappedPtr>(other) { }
+ MappedPtr(): GenericMappedPtr<MappedPtr>() { }
+
+private:
+ friend class GenericMappedPtr<MappedPtr>;
+ void munmap(void *buf, size_t length)
+ {
+ ::munmap(buf, length);
+ }
+};
+
+/**
+ * UnsizedArray is a way to access raw arrays of data in memory.
+ *
+ * struct S { ... };
+ * UnsizedArray<S> a(buf);
+ * UnsizedArray<S> b; b.Init(buf);
+ *
+ * This is roughly equivalent to
+ * const S *a = reinterpret_cast<const S *>(buf);
+ * const S *b = nullptr; b = reinterpret_cast<const S *>(buf);
+ *
+ * An UnsizedArray has no known length, and it's up to the caller to make
+ * sure the accessed memory is mapped and makes sense.
+ */
+template <typename T>
+class UnsizedArray
+{
+public:
+ typedef size_t idx_t;
+
+ /**
+ * Constructors and Initializers
+ */
+ UnsizedArray(): contents(nullptr) { }
+ UnsizedArray(const void *buf): contents(reinterpret_cast<const T *>(buf)) { }
+
+ void Init(const void *buf)
+ {
+ MOZ_ASSERT(contents == nullptr);
+ contents = reinterpret_cast<const T *>(buf);
+ }
+
+ /**
+ * Returns the nth element of the array
+ */
+ const T &operator[](const idx_t index) const
+ {
+ MOZ_ASSERT(contents);
+ return contents[index];
+ }
+
+ operator const T *() const
+ {
+ return contents;
+ }
+ /**
+ * Returns whether the array points somewhere
+ */
+ operator bool() const
+ {
+ return contents != nullptr;
+ }
+private:
+ const T *contents;
+};
+
+/**
+ * Array, like UnsizedArray, is a way to access raw arrays of data in memory.
+ * Unlike UnsizedArray, it has a known length, and is enumerable with an
+ * iterator.
+ *
+ * struct S { ... };
+ * Array<S> a(buf, len);
+ * UnsizedArray<S> b; b.Init(buf, len);
+ *
+ * In the above examples, len is the number of elements in the array. It is
+ * also possible to initialize an Array with the buffer size:
+ *
+ * Array<S> c; c.InitSize(buf, size);
+ *
+ * It is also possible to initialize an Array in two steps, only providing
+ * one data at a time:
+ *
+ * Array<S> d;
+ * d.Init(buf);
+ * d.Init(len); // or d.InitSize(size);
+ *
+ */
+template <typename T>
+class Array: public UnsizedArray<T>
+{
+public:
+ typedef typename UnsizedArray<T>::idx_t idx_t;
+
+ /**
+ * Constructors and Initializers
+ */
+ Array(): UnsizedArray<T>(), length(0) { }
+ Array(const void *buf, const idx_t length)
+ : UnsizedArray<T>(buf), length(length) { }
+
+ void Init(const void *buf)
+ {
+ UnsizedArray<T>::Init(buf);
+ }
+
+ void Init(const idx_t len)
+ {
+ MOZ_ASSERT(length == 0);
+ length = len;
+ }
+
+ void InitSize(const idx_t size)
+ {
+ Init(size / sizeof(T));
+ }
+
+ void Init(const void *buf, const idx_t len)
+ {
+ UnsizedArray<T>::Init(buf);
+ Init(len);
+ }
+
+ void InitSize(const void *buf, const idx_t size)
+ {
+ UnsizedArray<T>::Init(buf);
+ InitSize(size);
+ }
+
+ /**
+ * Returns the nth element of the array
+ */
+ const T &operator[](const idx_t index) const
+ {
+ MOZ_ASSERT(index < length);
+ MOZ_ASSERT(operator bool());
+ return UnsizedArray<T>::operator[](index);
+ }
+
+ /**
+ * Returns the number of elements in the array
+ */
+ idx_t numElements() const
+ {
+ return length;
+ }
+
+ /**
+ * Returns whether the array points somewhere and has at least one element.
+ */
+ operator bool() const
+ {
+ return (length > 0) && UnsizedArray<T>::operator bool();
+ }
+
+ /**
+ * Iterator for an Array. Use is similar to that of STL const_iterators:
+ *
+ * struct S { ... };
+ * Array<S> a(buf, len);
+ * for (Array<S>::iterator it = a.begin(); it < a.end(); ++it) {
+ * // Do something with *it.
+ * }
+ */
+ class iterator
+ {
+ public:
+ iterator(): item(nullptr) { }
+
+ const T &operator *() const
+ {
+ return *item;
+ }
+
+ const T *operator ->() const
+ {
+ return item;
+ }
+
+ iterator &operator ++()
+ {
+ ++item;
+ return *this;
+ }
+
+ bool operator<(const iterator &other) const
+ {
+ return item < other.item;
+ }
+ protected:
+ friend class Array<T>;
+ iterator(const T &item): item(&item) { }
+
+ private:
+ const T *item;
+ };
+
+ /**
+ * Returns an iterator pointing at the beginning of the Array
+ */
+ iterator begin() const {
+ if (length)
+ return iterator(UnsizedArray<T>::operator[](0));
+ return iterator();
+ }
+
+ /**
+ * Returns an iterator pointing past the end of the Array
+ */
+ iterator end() const {
+ if (length)
+ return iterator(UnsizedArray<T>::operator[](length));
+ return iterator();
+ }
+
+ /**
+ * Reverse iterator for an Array. Use is similar to that of STL
+ * const_reverse_iterators:
+ *
+ * struct S { ... };
+ * Array<S> a(buf, len);
+ * for (Array<S>::reverse_iterator it = a.rbegin(); it < a.rend(); ++it) {
+ * // Do something with *it.
+ * }
+ */
+ class reverse_iterator
+ {
+ public:
+ reverse_iterator(): item(nullptr) { }
+
+ const T &operator *() const
+ {
+ const T *tmp = item;
+ return *--tmp;
+ }
+
+ const T *operator ->() const
+ {
+ return &operator*();
+ }
+
+ reverse_iterator &operator ++()
+ {
+ --item;
+ return *this;
+ }
+
+ bool operator<(const reverse_iterator &other) const
+ {
+ return item > other.item;
+ }
+ protected:
+ friend class Array<T>;
+ reverse_iterator(const T &item): item(&item) { }
+
+ private:
+ const T *item;
+ };
+
+ /**
+ * Returns a reverse iterator pointing at the end of the Array
+ */
+ reverse_iterator rbegin() const {
+ if (length)
+ return reverse_iterator(UnsizedArray<T>::operator[](length));
+ return reverse_iterator();
+ }
+
+ /**
+ * Returns a reverse iterator pointing past the beginning of the Array
+ */
+ reverse_iterator rend() const {
+ if (length)
+ return reverse_iterator(UnsizedArray<T>::operator[](0));
+ return reverse_iterator();
+ }
+private:
+ idx_t length;
+};
+
+/**
+ * Transforms a pointer-to-function to a pointer-to-object pointing at the
+ * same address.
+ */
+template <typename T>
+void *FunctionPtr(T func)
+{
+ union {
+ void *ptr;
+ T func;
+ } f;
+ f.func = func;
+ return f.ptr;
+}
+
+class AutoLock {
+public:
+ AutoLock(pthread_mutex_t *mutex): mutex(mutex)
+ {
+ if (pthread_mutex_lock(mutex))
+ MOZ_CRASH("pthread_mutex_lock failed");
+ }
+ ~AutoLock()
+ {
+ if (pthread_mutex_unlock(mutex))
+ MOZ_CRASH("pthread_mutex_unlock failed");
+ }
+private:
+ pthread_mutex_t *mutex;
+};
+
+#endif /* Utils_h */
+