From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- mozglue/linker/Utils.h | 532 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 532 insertions(+) create mode 100644 mozglue/linker/Utils.h (limited to 'mozglue/linker/Utils.h') diff --git a/mozglue/linker/Utils.h b/mozglue/linker/Utils.h new file mode 100644 index 0000000000..d3827f1f41 --- /dev/null +++ b/mozglue/linker/Utils.h @@ -0,0 +1,532 @@ +/* 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 +#include +#include +#include +#include +#include "mozilla/Assertions.h" +#include "mozilla/Atomics.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 +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 +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() {} + explicit 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 le_uint16; +typedef le_to_cpu 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 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 AutoCloseFILE; + +extern mozilla::Atomic gPageSize; + +/** + * Page alignment helpers + */ +static size_t PageSize() { + if (!gPageSize) { + gPageSize = sysconf(_SC_PAGESIZE); + } + + return gPageSize; +} + +static inline uintptr_t AlignedPtr(uintptr_t ptr, size_t alignment) { + return ptr & ~(alignment - 1); +} + +template +static inline T* AlignedPtr(T* ptr, size_t alignment) { + return reinterpret_cast( + AlignedPtr(reinterpret_cast(ptr), alignment)); +} + +template +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 +static inline T* AlignedEndPtr(T* ptr, size_t alignment) { + return reinterpret_cast( + AlignedEndPtr(reinterpret_cast(ptr), alignment)); +} + +template +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 +static inline bool IsAlignedPtr(T* ptr, size_t alignment) { + return IsAlignedPtr(reinterpret_cast(ptr), alignment); +} + +template +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(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(buf) + offset; + } + + /** + * Returns whether the given address is within the mapped range + */ + bool Contains(void* ptr) const { + return (ptr >= buf) && (ptr < reinterpret_cast(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 +class GenericMappedPtr : public MemoryRange { + public: + GenericMappedPtr(void* buf, size_t length) : MemoryRange(buf, length) {} + explicit GenericMappedPtr(const MemoryRange& other) : MemoryRange(other) {} + GenericMappedPtr() : MemoryRange(MAP_FAILED, 0) {} + + void Assign(void* b, size_t len) { + if (get() != MAP_FAILED) static_cast(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(this)->munmap(get(), GetLength()); + } + + void release() { MemoryRange::Assign(MAP_FAILED, 0); } +}; + +struct MappedPtr : public GenericMappedPtr { + MappedPtr(void* buf, size_t length) + : GenericMappedPtr(buf, length) {} + MOZ_IMPLICIT MappedPtr(const MemoryRange& other) + : GenericMappedPtr(other) {} + MappedPtr() : GenericMappedPtr() {} + + private: + friend class GenericMappedPtr; + 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 a(buf); + * UnsizedArray b; b.Init(buf); + * + * This is roughly equivalent to + * const S *a = reinterpret_cast(buf); + * const S *b = nullptr; b = reinterpret_cast(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 +class UnsizedArray { + public: + typedef size_t idx_t; + + /** + * Constructors and Initializers + */ + UnsizedArray() : contents(nullptr) {} + explicit UnsizedArray(const void* buf) + : contents(reinterpret_cast(buf)) {} + + void Init(const void* buf) { + MOZ_ASSERT(contents == nullptr); + contents = reinterpret_cast(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 + */ + explicit 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 a(buf, len); + * UnsizedArray 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 c; c.InitSize(buf, size); + * + * It is also possible to initialize an Array in two steps, only providing + * one data at a time: + * + * Array d; + * d.Init(buf); + * d.Init(len); // or d.InitSize(size); + * + */ +template +class Array : public UnsizedArray { + public: + typedef typename UnsizedArray::idx_t idx_t; + + /** + * Constructors and Initializers + */ + Array() : UnsizedArray(), length(0) {} + Array(const void* buf, const idx_t length) + : UnsizedArray(buf), length(length) {} + + void Init(const void* buf) { UnsizedArray::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::Init(buf); + Init(len); + } + + void InitSize(const void* buf, const idx_t size) { + UnsizedArray::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::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. + */ + explicit operator bool() const { + return (length > 0) && UnsizedArray::operator bool(); + } + + /** + * Iterator for an Array. Use is similar to that of STL const_iterators: + * + * struct S { ... }; + * Array a(buf, len); + * for (Array::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; + explicit 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::operator[](0)); + return iterator(); + } + + /** + * Returns an iterator pointing past the end of the Array + */ + iterator end() const { + if (length) return iterator(UnsizedArray::operator[](length)); + return iterator(); + } + + /** + * Reverse iterator for an Array. Use is similar to that of STL + * const_reverse_iterators: + * + * struct S { ... }; + * Array a(buf, len); + * for (Array::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; + explicit 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::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::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 +void* FunctionPtr(T func) { + union { + void* ptr; + T func; + } f; + f.func = func; + return f.ptr; +} + +class AutoLock { + public: + explicit 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 */ -- cgit v1.2.3