Utils.h (7038B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef Utils_h 8 #define Utils_h 9 10 #include <cstring> 11 #include <type_traits> 12 13 #ifdef XP_WIN 14 # include <io.h> // for _write() 15 #endif 16 17 #include "mozilla/CheckedInt.h" 18 19 // Helper for log2 of powers of 2 at compile time. 20 constexpr size_t LOG2(size_t N) { return mozilla::CeilingLog2(N); } 21 22 enum class Order { 23 eLess = -1, 24 eEqual = 0, 25 eGreater = 1, 26 }; 27 28 // Compare two integers. Returns whether the first integer is Less, 29 // Equal or Greater than the second integer. 30 template <typename T> 31 Order CompareInt(T aValue1, T aValue2) { 32 static_assert(std::is_integral_v<T>, "Type must be integral"); 33 if (aValue1 < aValue2) { 34 return Order::eLess; 35 } 36 if (aValue1 > aValue2) { 37 return Order::eGreater; 38 } 39 return Order::eEqual; 40 } 41 42 // Compare two addresses. Returns whether the first address is Less, 43 // Equal or Greater than the second address. 44 template <typename T> 45 Order CompareAddr(T* aAddr1, T* aAddr2) { 46 return CompareInt(uintptr_t(aAddr1), uintptr_t(aAddr2)); 47 } 48 49 // Helper for (fast) comparison of fractions without involving divisions or 50 // floats. 51 class Fraction { 52 public: 53 explicit constexpr Fraction(size_t aNumerator, size_t aDenominator) 54 : mNumerator(aNumerator), mDenominator(aDenominator) {} 55 56 MOZ_IMPLICIT constexpr Fraction(long double aValue) 57 // We use an arbitrary power of two as denominator that provides enough 58 // precision for our use case. 59 : mNumerator(aValue * 4096), mDenominator(4096) {} 60 61 inline bool operator<(const Fraction& aOther) const { 62 #ifndef MOZ_DEBUG 63 // We are comparing A / B < C / D, with all A, B, C and D being positive 64 // numbers. Multiplying both sides with B * D, we have: 65 // (A * B * D) / B < (C * B * D) / D, which can then be simplified as 66 // A * D < C * B. When can thus compare our fractions without actually 67 // doing any division. 68 // This however assumes the multiplied quantities are small enough not 69 // to overflow the multiplication. We use CheckedInt on debug builds 70 // to enforce the assumption. 71 return mNumerator * aOther.mDenominator < aOther.mNumerator * mDenominator; 72 #else 73 mozilla::CheckedInt<size_t> numerator(mNumerator); 74 mozilla::CheckedInt<size_t> denominator(mDenominator); 75 // value() asserts when the multiplication overflowed. 76 size_t lhs = (numerator * aOther.mDenominator).value(); 77 size_t rhs = (aOther.mNumerator * denominator).value(); 78 return lhs < rhs; 79 #endif 80 } 81 82 inline bool operator>(const Fraction& aOther) const { return aOther < *this; } 83 84 inline bool operator>=(const Fraction& aOther) const { 85 return !(*this < aOther); 86 } 87 88 inline bool operator<=(const Fraction& aOther) const { 89 return !(*this > aOther); 90 } 91 92 inline bool operator==(const Fraction& aOther) const { 93 #ifndef MOZ_DEBUG 94 // Same logic as operator< 95 return mNumerator * aOther.mDenominator == aOther.mNumerator * mDenominator; 96 #else 97 mozilla::CheckedInt<size_t> numerator(mNumerator); 98 mozilla::CheckedInt<size_t> denominator(mDenominator); 99 size_t lhs = (numerator * aOther.mDenominator).value(); 100 size_t rhs = (aOther.mNumerator * denominator).value(); 101 return lhs == rhs; 102 #endif 103 } 104 105 inline bool operator!=(const Fraction& aOther) const { 106 return !(*this == aOther); 107 } 108 109 private: 110 size_t mNumerator; 111 size_t mDenominator; 112 }; 113 114 // Fast division 115 // 116 // During deallocation we want to divide by the size class. This class 117 // provides a routine and sets up a constant as follows. 118 // 119 // To divide by a number D that is not a power of two we multiply by (2^17 / 120 // D) and then right shift by 17 positions. 121 // 122 // X / D 123 // 124 // becomes 125 // 126 // (X * m) >> p 127 // 128 // Where m is calculated during the FastDivisor constructor similarly to: 129 // 130 // m = 2^p / D 131 // 132 template <typename T> 133 class FastDivisor { 134 private: 135 // The shift amount (p) is chosen to minimise the size of m while 136 // working for divisors up to 65536 in steps of 16. I arrived at 17 137 // experimentally. I wanted a low number to minimise the range of m 138 // so it can fit in a uint16_t, 16 didn't work but 17 worked perfectly. 139 // 140 // We'd need to increase this if we allocated memory on smaller boundaries 141 // than 16. 142 static const unsigned p = 17; 143 144 // We can fit the inverted divisor in 16 bits, but we template it here for 145 // convenience. 146 T m; 147 148 public: 149 // Needed so mBins can be constructed. 150 FastDivisor() : m(0) {} 151 152 FastDivisor(unsigned div, unsigned max) { 153 MOZ_ASSERT(div <= max); 154 155 // divide_inv_shift is large enough. 156 MOZ_ASSERT((1U << p) >= div); 157 158 // The calculation here for m is formula 26 from Section 159 // 10-9 "Unsigned Division by Divisors >= 1" in 160 // Henry S. Warren, Jr.'s Hacker's Delight, 2nd Ed. 161 unsigned m_ = ((1U << p) + div - 1 - (((1U << p) - 1) % div)) / div; 162 163 // Make sure that max * m does not overflow. 164 MOZ_DIAGNOSTIC_ASSERT(max < UINT_MAX / m_); 165 166 MOZ_ASSERT(m_ <= std::numeric_limits<T>::max()); 167 m = static_cast<T>(m_); 168 169 // Initialisation made m non-zero. 170 MOZ_ASSERT(m); 171 172 // Test that all the divisions in the range we expected would work. 173 #ifdef MOZ_DEBUG 174 for (unsigned num = 0; num < max; num += div) { 175 MOZ_ASSERT(num / div == divide(num)); 176 } 177 #endif 178 } 179 180 // Note that this always occurs in uint32_t regardless of m's type. If m is 181 // a uint16_t it will be zero-extended before the multiplication. We also use 182 // uint32_t rather than something that could possibly be larger because it is 183 // most-likely the cheapest multiplication. 184 inline uint32_t divide(uint32_t num) const { 185 // Check that m was initialised. 186 MOZ_ASSERT(m); 187 return (num * m) >> p; 188 } 189 }; 190 191 template <typename T> 192 unsigned inline operator/(unsigned num, FastDivisor<T> divisor) { 193 return divisor.divide(num); 194 } 195 196 // Return the offset between a and the nearest aligned address at or below a. 197 #define ALIGNMENT_ADDR2OFFSET(a, alignment) \ 198 ((size_t)((uintptr_t)(a) & ((alignment) - 1))) 199 200 // Return the smallest alignment multiple that is >= s. 201 #define ALIGNMENT_CEILING(s, alignment) \ 202 (((s) + ((alignment) - 1)) & (~((alignment) - 1))) 203 204 #define ALIGNMENT_FLOOR(s, alignment) ((s) & (~((alignment) - 1))) 205 206 static inline const char* _getprogname(void) { return "<jemalloc>"; } 207 208 #ifdef XP_WIN 209 # define STDERR_FILENO 2 210 #else 211 # define _write write 212 #endif 213 inline void _malloc_message(const char* p) { 214 // Pretend to check _write() errors to suppress gcc warnings about 215 // warn_unused_result annotations in some versions of glibc headers. 216 if (_write(STDERR_FILENO, p, (unsigned int)strlen(p)) < 0) { 217 return; 218 } 219 } 220 221 template <typename... Args> 222 static void _malloc_message(const char* p, Args... args) { 223 _malloc_message(p); 224 _malloc_message(args...); 225 } 226 227 #endif