|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
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 /* |
|
8 * PR assertion checker. |
|
9 */ |
|
10 |
|
11 #ifndef jsutil_h |
|
12 #define jsutil_h |
|
13 |
|
14 #include "mozilla/Assertions.h" |
|
15 #include "mozilla/Compiler.h" |
|
16 #include "mozilla/GuardObjects.h" |
|
17 |
|
18 #include <limits.h> |
|
19 |
|
20 #include "js/Utility.h" |
|
21 |
|
22 #define JS_ALWAYS_TRUE(expr) MOZ_ALWAYS_TRUE(expr) |
|
23 #define JS_ALWAYS_FALSE(expr) MOZ_ALWAYS_FALSE(expr) |
|
24 |
|
25 #if defined(JS_DEBUG) |
|
26 # define JS_DIAGNOSTICS_ASSERT(expr) MOZ_ASSERT(expr) |
|
27 #elif defined(JS_CRASH_DIAGNOSTICS) |
|
28 # define JS_DIAGNOSTICS_ASSERT(expr) do { if (MOZ_UNLIKELY(!(expr))) MOZ_CRASH(); } while(0) |
|
29 #else |
|
30 # define JS_DIAGNOSTICS_ASSERT(expr) ((void) 0) |
|
31 #endif |
|
32 |
|
33 static MOZ_ALWAYS_INLINE void * |
|
34 js_memcpy(void *dst_, const void *src_, size_t len) |
|
35 { |
|
36 char *dst = (char *) dst_; |
|
37 const char *src = (const char *) src_; |
|
38 JS_ASSERT_IF(dst >= src, (size_t) (dst - src) >= len); |
|
39 JS_ASSERT_IF(src >= dst, (size_t) (src - dst) >= len); |
|
40 |
|
41 return memcpy(dst, src, len); |
|
42 } |
|
43 |
|
44 namespace js { |
|
45 |
|
46 template <class T> |
|
47 struct AlignmentTestStruct |
|
48 { |
|
49 char c; |
|
50 T t; |
|
51 }; |
|
52 |
|
53 /* This macro determines the alignment requirements of a type. */ |
|
54 #define JS_ALIGNMENT_OF(t_) \ |
|
55 (sizeof(js::AlignmentTestStruct<t_>) - sizeof(t_)) |
|
56 |
|
57 template <class T> |
|
58 class AlignedPtrAndFlag |
|
59 { |
|
60 uintptr_t bits; |
|
61 |
|
62 public: |
|
63 AlignedPtrAndFlag(T *t, bool aFlag) { |
|
64 JS_ASSERT((uintptr_t(t) & 1) == 0); |
|
65 bits = uintptr_t(t) | uintptr_t(aFlag); |
|
66 } |
|
67 |
|
68 T *ptr() const { |
|
69 return (T *)(bits & ~uintptr_t(1)); |
|
70 } |
|
71 |
|
72 bool flag() const { |
|
73 return (bits & 1) != 0; |
|
74 } |
|
75 |
|
76 void setPtr(T *t) { |
|
77 JS_ASSERT((uintptr_t(t) & 1) == 0); |
|
78 bits = uintptr_t(t) | uintptr_t(flag()); |
|
79 } |
|
80 |
|
81 void setFlag() { |
|
82 bits |= 1; |
|
83 } |
|
84 |
|
85 void unsetFlag() { |
|
86 bits &= ~uintptr_t(1); |
|
87 } |
|
88 |
|
89 void set(T *t, bool aFlag) { |
|
90 JS_ASSERT((uintptr_t(t) & 1) == 0); |
|
91 bits = uintptr_t(t) | aFlag; |
|
92 } |
|
93 }; |
|
94 |
|
95 template <class T> |
|
96 static inline void |
|
97 Reverse(T *beg, T *end) |
|
98 { |
|
99 while (beg != end) { |
|
100 if (--end == beg) |
|
101 return; |
|
102 T tmp = *beg; |
|
103 *beg = *end; |
|
104 *end = tmp; |
|
105 ++beg; |
|
106 } |
|
107 } |
|
108 |
|
109 template <class T> |
|
110 static inline T * |
|
111 Find(T *beg, T *end, const T &v) |
|
112 { |
|
113 for (T *p = beg; p != end; ++p) { |
|
114 if (*p == v) |
|
115 return p; |
|
116 } |
|
117 return end; |
|
118 } |
|
119 |
|
120 template <class Container> |
|
121 static inline typename Container::ElementType * |
|
122 Find(Container &c, const typename Container::ElementType &v) |
|
123 { |
|
124 return Find(c.begin(), c.end(), v); |
|
125 } |
|
126 |
|
127 template <typename InputIterT, typename CallableT> |
|
128 void |
|
129 ForEach(InputIterT begin, InputIterT end, CallableT f) |
|
130 { |
|
131 for (; begin != end; ++begin) |
|
132 f(*begin); |
|
133 } |
|
134 |
|
135 template <class T> |
|
136 static inline T |
|
137 Min(T t1, T t2) |
|
138 { |
|
139 return t1 < t2 ? t1 : t2; |
|
140 } |
|
141 |
|
142 template <class T> |
|
143 static inline T |
|
144 Max(T t1, T t2) |
|
145 { |
|
146 return t1 > t2 ? t1 : t2; |
|
147 } |
|
148 |
|
149 /* Allows a const variable to be initialized after its declaration. */ |
|
150 template <class T> |
|
151 static T& |
|
152 InitConst(const T &t) |
|
153 { |
|
154 return const_cast<T &>(t); |
|
155 } |
|
156 |
|
157 template <class T, class U> |
|
158 MOZ_ALWAYS_INLINE T & |
|
159 ImplicitCast(U &u) |
|
160 { |
|
161 T &t = u; |
|
162 return t; |
|
163 } |
|
164 |
|
165 template<typename T> |
|
166 class AutoScopedAssign |
|
167 { |
|
168 public: |
|
169 AutoScopedAssign(T *addr, const T &value |
|
170 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
171 : addr_(addr), old(*addr_) |
|
172 { |
|
173 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
174 *addr_ = value; |
|
175 } |
|
176 |
|
177 ~AutoScopedAssign() { *addr_ = old; } |
|
178 |
|
179 private: |
|
180 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
181 T *addr_; |
|
182 T old; |
|
183 }; |
|
184 |
|
185 template <typename T> |
|
186 static inline bool |
|
187 IsPowerOfTwo(T t) |
|
188 { |
|
189 return t && !(t & (t - 1)); |
|
190 } |
|
191 |
|
192 template <typename T, typename U> |
|
193 static inline U |
|
194 ComputeByteAlignment(T bytes, U alignment) |
|
195 { |
|
196 JS_ASSERT(IsPowerOfTwo(alignment)); |
|
197 return (alignment - (bytes % alignment)) % alignment; |
|
198 } |
|
199 |
|
200 template <typename T, typename U> |
|
201 static inline T |
|
202 AlignBytes(T bytes, U alignment) |
|
203 { |
|
204 return bytes + ComputeByteAlignment(bytes, alignment); |
|
205 } |
|
206 |
|
207 static MOZ_ALWAYS_INLINE size_t |
|
208 UnsignedPtrDiff(const void *bigger, const void *smaller) |
|
209 { |
|
210 return size_t(bigger) - size_t(smaller); |
|
211 } |
|
212 |
|
213 /*****************************************************************************/ |
|
214 |
|
215 /* A bit array is an array of bits represented by an array of words (size_t). */ |
|
216 |
|
217 static const size_t BitArrayElementBits = sizeof(size_t) * CHAR_BIT; |
|
218 |
|
219 static inline unsigned |
|
220 NumWordsForBitArrayOfLength(size_t length) |
|
221 { |
|
222 return (length + (BitArrayElementBits - 1)) / BitArrayElementBits; |
|
223 } |
|
224 |
|
225 static inline unsigned |
|
226 BitArrayIndexToWordIndex(size_t length, size_t bitIndex) |
|
227 { |
|
228 unsigned wordIndex = bitIndex / BitArrayElementBits; |
|
229 JS_ASSERT(wordIndex < length); |
|
230 return wordIndex; |
|
231 } |
|
232 |
|
233 static inline size_t |
|
234 BitArrayIndexToWordMask(size_t i) |
|
235 { |
|
236 return size_t(1) << (i % BitArrayElementBits); |
|
237 } |
|
238 |
|
239 static inline bool |
|
240 IsBitArrayElementSet(size_t *array, size_t length, size_t i) |
|
241 { |
|
242 return array[BitArrayIndexToWordIndex(length, i)] & BitArrayIndexToWordMask(i); |
|
243 } |
|
244 |
|
245 static inline bool |
|
246 IsAnyBitArrayElementSet(size_t *array, size_t length) |
|
247 { |
|
248 unsigned numWords = NumWordsForBitArrayOfLength(length); |
|
249 for (unsigned i = 0; i < numWords; ++i) { |
|
250 if (array[i]) |
|
251 return true; |
|
252 } |
|
253 return false; |
|
254 } |
|
255 |
|
256 static inline void |
|
257 SetBitArrayElement(size_t *array, size_t length, size_t i) |
|
258 { |
|
259 array[BitArrayIndexToWordIndex(length, i)] |= BitArrayIndexToWordMask(i); |
|
260 } |
|
261 |
|
262 static inline void |
|
263 ClearBitArrayElement(size_t *array, size_t length, size_t i) |
|
264 { |
|
265 array[BitArrayIndexToWordIndex(length, i)] &= ~BitArrayIndexToWordMask(i); |
|
266 } |
|
267 |
|
268 static inline void |
|
269 ClearAllBitArrayElements(size_t *array, size_t length) |
|
270 { |
|
271 for (unsigned i = 0; i < length; ++i) |
|
272 array[i] = 0; |
|
273 } |
|
274 |
|
275 } /* namespace js */ |
|
276 |
|
277 /* Crash diagnostics */ |
|
278 #ifdef DEBUG |
|
279 # define JS_CRASH_DIAGNOSTICS 1 |
|
280 #endif |
|
281 #if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL) |
|
282 # define JS_POISON(p, val, size) memset((p), (val), (size)) |
|
283 #else |
|
284 # define JS_POISON(p, val, size) ((void) 0) |
|
285 #endif |
|
286 |
|
287 /* Bug 984101: Disable labeled poisoning until we have poison checking. */ |
|
288 #define JS_EXTRA_POISON(p, val, size) ((void) 0) |
|
289 |
|
290 /* Basic stats */ |
|
291 #ifdef DEBUG |
|
292 # define JS_BASIC_STATS 1 |
|
293 #endif |
|
294 #ifdef JS_BASIC_STATS |
|
295 # include <stdio.h> |
|
296 typedef struct JSBasicStats { |
|
297 uint32_t num; |
|
298 uint32_t max; |
|
299 double sum; |
|
300 double sqsum; |
|
301 uint32_t logscale; /* logarithmic scale: 0 (linear), 2, 10 */ |
|
302 uint32_t hist[11]; |
|
303 } JSBasicStats; |
|
304 # define JS_INIT_STATIC_BASIC_STATS {0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0}} |
|
305 # define JS_BASIC_STATS_INIT(bs) memset((bs), 0, sizeof(JSBasicStats)) |
|
306 # define JS_BASIC_STATS_ACCUM(bs,val) \ |
|
307 JS_BasicStatsAccum(bs, val) |
|
308 # define JS_MeanAndStdDevBS(bs,sigma) \ |
|
309 JS_MeanAndStdDev((bs)->num, (bs)->sum, (bs)->sqsum, sigma) |
|
310 extern void |
|
311 JS_BasicStatsAccum(JSBasicStats *bs, uint32_t val); |
|
312 extern double |
|
313 JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double *sigma); |
|
314 extern void |
|
315 JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp); |
|
316 extern void |
|
317 JS_DumpHistogram(JSBasicStats *bs, FILE *fp); |
|
318 #else |
|
319 # define JS_BASIC_STATS_ACCUM(bs,val) |
|
320 #endif |
|
321 |
|
322 /* A jsbitmap_t is a long integer that can be used for bitmaps. */ |
|
323 typedef size_t jsbitmap; |
|
324 #define JS_BITMAP_NBITS (sizeof(jsbitmap) * CHAR_BIT) |
|
325 #define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] & \ |
|
326 (jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) |
|
327 #define JS_SET_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] |= \ |
|
328 (jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) |
|
329 #define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] &= \ |
|
330 ~(jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) |
|
331 |
|
332 /* Wrapper for various macros to stop warnings coming from their expansions. */ |
|
333 #if defined(__clang__) |
|
334 # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ |
|
335 JS_BEGIN_MACRO \ |
|
336 _Pragma("clang diagnostic push") \ |
|
337 /* If these _Pragmas cause warnings for you, try disabling ccache. */ \ |
|
338 _Pragma("clang diagnostic ignored \"-Wunused-value\"") \ |
|
339 { expr; } \ |
|
340 _Pragma("clang diagnostic pop") \ |
|
341 JS_END_MACRO |
|
342 #elif MOZ_IS_GCC |
|
343 |
|
344 #if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) |
|
345 # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ |
|
346 JS_BEGIN_MACRO \ |
|
347 _Pragma("GCC diagnostic push") \ |
|
348 _Pragma("GCC diagnostic ignored \"-Wunused-but-set-variable\"") \ |
|
349 expr; \ |
|
350 _Pragma("GCC diagnostic pop") \ |
|
351 JS_END_MACRO |
|
352 #endif |
|
353 #endif |
|
354 |
|
355 #if !defined(JS_SILENCE_UNUSED_VALUE_IN_EXPR) |
|
356 # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ |
|
357 JS_BEGIN_MACRO \ |
|
358 expr; \ |
|
359 JS_END_MACRO |
|
360 #endif |
|
361 |
|
362 #endif /* jsutil_h */ |