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 #include "mozilla/PodOperations.h"
18
19 #include <limits.h>
20
21 #include "js/Utility.h"
22 #include "js/Value.h"
23
24 #define JS_ALWAYS_TRUE(expr) MOZ_ALWAYS_TRUE(expr)
25 #define JS_ALWAYS_FALSE(expr) MOZ_ALWAYS_FALSE(expr)
26
27 #if defined(JS_DEBUG)
28 # define JS_DIAGNOSTICS_ASSERT(expr) MOZ_ASSERT(expr)
29 #elif defined(JS_CRASH_DIAGNOSTICS)
30 # define JS_DIAGNOSTICS_ASSERT(expr) do { if (MOZ_UNLIKELY(!(expr))) MOZ_CRASH(); } while(0)
31 #else
32 # define JS_DIAGNOSTICS_ASSERT(expr) ((void) 0)
33 #endif
34
35 static MOZ_ALWAYS_INLINE void*
js_memcpy(void * dst_,const void * src_,size_t len)36 js_memcpy(void* dst_, const void* src_, size_t len)
37 {
38 char* dst = (char*) dst_;
39 const char* src = (const char*) src_;
40 MOZ_ASSERT_IF(dst >= src, (size_t) (dst - src) >= len);
41 MOZ_ASSERT_IF(src >= dst, (size_t) (src - dst) >= len);
42
43 return memcpy(dst, src, len);
44 }
45
46 namespace js {
47
48 template <class T>
49 struct AlignmentTestStruct
50 {
51 char c;
52 T t;
53 };
54
55 /* This macro determines the alignment requirements of a type. */
56 #define JS_ALIGNMENT_OF(t_) \
57 (sizeof(js::AlignmentTestStruct<t_>) - sizeof(t_))
58
59 template <class T>
60 class AlignedPtrAndFlag
61 {
62 uintptr_t bits;
63
64 public:
AlignedPtrAndFlag(T * t,bool aFlag)65 AlignedPtrAndFlag(T* t, bool aFlag) {
66 MOZ_ASSERT((uintptr_t(t) & 1) == 0);
67 bits = uintptr_t(t) | uintptr_t(aFlag);
68 }
69
ptr()70 T* ptr() const {
71 return (T*)(bits & ~uintptr_t(1));
72 }
73
flag()74 bool flag() const {
75 return (bits & 1) != 0;
76 }
77
setPtr(T * t)78 void setPtr(T* t) {
79 MOZ_ASSERT((uintptr_t(t) & 1) == 0);
80 bits = uintptr_t(t) | uintptr_t(flag());
81 }
82
setFlag()83 void setFlag() {
84 bits |= 1;
85 }
86
unsetFlag()87 void unsetFlag() {
88 bits &= ~uintptr_t(1);
89 }
90
set(T * t,bool aFlag)91 void set(T* t, bool aFlag) {
92 MOZ_ASSERT((uintptr_t(t) & 1) == 0);
93 bits = uintptr_t(t) | aFlag;
94 }
95 };
96
97 template <class T>
98 static inline void
Reverse(T * beg,T * end)99 Reverse(T* beg, T* end)
100 {
101 while (beg != end) {
102 if (--end == beg)
103 return;
104 T tmp = *beg;
105 *beg = *end;
106 *end = tmp;
107 ++beg;
108 }
109 }
110
111 template <class T>
112 static inline T*
Find(T * beg,T * end,const T & v)113 Find(T* beg, T* end, const T& v)
114 {
115 for (T* p = beg; p != end; ++p) {
116 if (*p == v)
117 return p;
118 }
119 return end;
120 }
121
122 template <class Container>
123 static inline typename Container::ElementType*
Find(Container & c,const typename Container::ElementType & v)124 Find(Container& c, const typename Container::ElementType& v)
125 {
126 return Find(c.begin(), c.end(), v);
127 }
128
129 template <typename InputIterT, typename CallableT>
130 void
ForEach(InputIterT begin,InputIterT end,CallableT f)131 ForEach(InputIterT begin, InputIterT end, CallableT f)
132 {
133 for (; begin != end; ++begin)
134 f(*begin);
135 }
136
137 template <class T>
138 static inline T
Min(T t1,T t2)139 Min(T t1, T t2)
140 {
141 return t1 < t2 ? t1 : t2;
142 }
143
144 template <class T>
145 static inline T
Max(T t1,T t2)146 Max(T t1, T t2)
147 {
148 return t1 > t2 ? t1 : t2;
149 }
150
151 /* Allows a const variable to be initialized after its declaration. */
152 template <class T>
153 static T&
InitConst(const T & t)154 InitConst(const T& t)
155 {
156 return const_cast<T&>(t);
157 }
158
159 template <class T, class U>
160 MOZ_ALWAYS_INLINE T&
ImplicitCast(U & u)161 ImplicitCast(U& u)
162 {
163 T& t = u;
164 return t;
165 }
166
167 template<typename T>
168 class MOZ_RAII AutoScopedAssign
169 {
170 public:
AutoScopedAssign(T * addr,const T & value MOZ_GUARD_OBJECT_NOTIFIER_PARAM)171 AutoScopedAssign(T* addr, const T& value
172 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
173 : addr_(addr), old(*addr_)
174 {
175 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
176 *addr_ = value;
177 }
178
~AutoScopedAssign()179 ~AutoScopedAssign() { *addr_ = old; }
180
181 private:
182 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
183 T* addr_;
184 T old;
185 };
186
187 template <typename T>
188 static inline bool
IsPowerOfTwo(T t)189 IsPowerOfTwo(T t)
190 {
191 return t && !(t & (t - 1));
192 }
193
194 template <typename T, typename U>
195 static inline U
ComputeByteAlignment(T bytes,U alignment)196 ComputeByteAlignment(T bytes, U alignment)
197 {
198 MOZ_ASSERT(IsPowerOfTwo(alignment));
199 return (alignment - (bytes % alignment)) % alignment;
200 }
201
202 template <typename T, typename U>
203 static inline T
AlignBytes(T bytes,U alignment)204 AlignBytes(T bytes, U alignment)
205 {
206 return bytes + ComputeByteAlignment(bytes, alignment);
207 }
208
209 static MOZ_ALWAYS_INLINE size_t
UnsignedPtrDiff(const void * bigger,const void * smaller)210 UnsignedPtrDiff(const void* bigger, const void* smaller)
211 {
212 return size_t(bigger) - size_t(smaller);
213 }
214
215 /*****************************************************************************/
216
217 /* A bit array is an array of bits represented by an array of words (size_t). */
218
219 static const size_t BitArrayElementBits = sizeof(size_t) * CHAR_BIT;
220
221 static inline unsigned
NumWordsForBitArrayOfLength(size_t length)222 NumWordsForBitArrayOfLength(size_t length)
223 {
224 return (length + (BitArrayElementBits - 1)) / BitArrayElementBits;
225 }
226
227 static inline unsigned
BitArrayIndexToWordIndex(size_t length,size_t bitIndex)228 BitArrayIndexToWordIndex(size_t length, size_t bitIndex)
229 {
230 unsigned wordIndex = bitIndex / BitArrayElementBits;
231 MOZ_ASSERT(wordIndex < length);
232 return wordIndex;
233 }
234
235 static inline size_t
BitArrayIndexToWordMask(size_t i)236 BitArrayIndexToWordMask(size_t i)
237 {
238 return size_t(1) << (i % BitArrayElementBits);
239 }
240
241 static inline bool
IsBitArrayElementSet(size_t * array,size_t length,size_t i)242 IsBitArrayElementSet(size_t* array, size_t length, size_t i)
243 {
244 return array[BitArrayIndexToWordIndex(length, i)] & BitArrayIndexToWordMask(i);
245 }
246
247 static inline bool
IsAnyBitArrayElementSet(size_t * array,size_t length)248 IsAnyBitArrayElementSet(size_t* array, size_t length)
249 {
250 unsigned numWords = NumWordsForBitArrayOfLength(length);
251 for (unsigned i = 0; i < numWords; ++i) {
252 if (array[i])
253 return true;
254 }
255 return false;
256 }
257
258 static inline void
SetBitArrayElement(size_t * array,size_t length,size_t i)259 SetBitArrayElement(size_t* array, size_t length, size_t i)
260 {
261 array[BitArrayIndexToWordIndex(length, i)] |= BitArrayIndexToWordMask(i);
262 }
263
264 static inline void
ClearBitArrayElement(size_t * array,size_t length,size_t i)265 ClearBitArrayElement(size_t* array, size_t length, size_t i)
266 {
267 array[BitArrayIndexToWordIndex(length, i)] &= ~BitArrayIndexToWordMask(i);
268 }
269
270 static inline void
ClearAllBitArrayElements(size_t * array,size_t length)271 ClearAllBitArrayElements(size_t* array, size_t length)
272 {
273 for (unsigned i = 0; i < length; ++i)
274 array[i] = 0;
275 }
276
277 } /* namespace js */
278
279 namespace mozilla {
280
281 /**
282 * Set the first |aNElem| T elements in |aDst| to |aSrc|.
283 */
284 template<typename T>
285 static MOZ_ALWAYS_INLINE void
PodSet(T * aDst,T aSrc,size_t aNElem)286 PodSet(T* aDst, T aSrc, size_t aNElem)
287 {
288 for (const T* dstend = aDst + aNElem; aDst < dstend; ++aDst)
289 *aDst = aSrc;
290 }
291
292 } /* namespace mozilla */
293
294 /*
295 * Patterns used by SpiderMonkey to overwrite unused memory. If you are
296 * accessing an object with one of these pattern, you probably have a dangling
297 * pointer. These values should be odd, see the comment in IsThingPoisoned.
298 *
299 * Note: new patterns should also be added to the array in IsThingPoisoned!
300 */
301 #define JS_FRESH_NURSERY_PATTERN 0x2F
302 #define JS_SWEPT_NURSERY_PATTERN 0x2B
303 #define JS_ALLOCATED_NURSERY_PATTERN 0x2D
304 #define JS_FRESH_TENURED_PATTERN 0x4F
305 #define JS_MOVED_TENURED_PATTERN 0x49
306 #define JS_SWEPT_TENURED_PATTERN 0x4B
307 #define JS_ALLOCATED_TENURED_PATTERN 0x4D
308 #define JS_FREED_HEAP_PTR_PATTERN 0x6B
309
310 /*
311 * Ensure JS_SWEPT_CODE_PATTERN is a byte pattern that will crash immediately
312 * when executed, so either an undefined instruction or an instruction that's
313 * illegal in user mode.
314 */
315 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_NONE)
316 # define JS_SWEPT_CODE_PATTERN 0xED // IN instruction, crashes in user mode.
317 #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
318 # define JS_SWEPT_CODE_PATTERN 0xA3 // undefined instruction
319 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
320 # define JS_SWEPT_CODE_PATTERN 0x01 // undefined instruction
321 #else
322 # error "JS_SWEPT_CODE_PATTERN not defined for this platform"
323 #endif
324
325 static inline void*
Poison(void * ptr,uint8_t value,size_t num)326 Poison(void* ptr, uint8_t value, size_t num)
327 {
328 static bool disablePoison = bool(getenv("JSGC_DISABLE_POISONING"));
329 if (disablePoison)
330 return ptr;
331
332 // Without a valid Value tag, a poisoned Value may look like a valid
333 // floating point number. To ensure that we crash more readily when
334 // observing a poisoned Value, we make the poison an invalid ObjectValue.
335 // Unfortunately, this adds about 2% more overhead, so we can only enable
336 // it in debug.
337 #if defined(DEBUG)
338 uintptr_t obj;
339 memset(&obj, value, sizeof(obj));
340 # if defined(JS_PUNBOX64)
341 obj = obj & ((uintptr_t(1) << JSVAL_TAG_SHIFT) - 1);
342 # endif
343 const jsval_layout layout = OBJECT_TO_JSVAL_IMPL((JSObject*)obj);
344
345 size_t value_count = num / sizeof(jsval_layout);
346 size_t byte_count = num % sizeof(jsval_layout);
347 mozilla::PodSet((jsval_layout*)ptr, layout, value_count);
348 if (byte_count) {
349 uint8_t* bytes = static_cast<uint8_t*>(ptr);
350 uint8_t* end = bytes + num;
351 mozilla::PodSet(end - byte_count, value, byte_count);
352 }
353 #else // !DEBUG
354 memset(ptr, value, num);
355 #endif // !DEBUG
356 return ptr;
357 }
358
359 /* Crash diagnostics by default in debug and on nightly channel. */
360 #if (defined(DEBUG) || defined(NIGHTLY_BUILD)) && !defined(MOZ_ASAN)
361 # define JS_CRASH_DIAGNOSTICS 1
362 #endif
363
364 /* Enable poisoning in crash-diagnostics and zeal builds. */
365 #if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL)
366 # define JS_POISON(p, val, size) Poison(p, val, size)
367 #else
368 # define JS_POISON(p, val, size) ((void) 0)
369 #endif
370
371 /* Enable even more poisoning in purely debug builds. */
372 #if defined(DEBUG)
373 # define JS_EXTRA_POISON(p, val, size) Poison(p, val, size)
374 #else
375 # define JS_EXTRA_POISON(p, val, size) ((void) 0)
376 #endif
377
378 /* Basic stats */
379 #ifdef DEBUG
380 # define JS_BASIC_STATS 1
381 #endif
382 #ifdef JS_BASIC_STATS
383 # include <stdio.h>
384 typedef struct JSBasicStats {
385 uint32_t num;
386 uint32_t max;
387 double sum;
388 double sqsum;
389 uint32_t logscale; /* logarithmic scale: 0 (linear), 2, 10 */
390 uint32_t hist[11];
391 } JSBasicStats;
392 # define JS_INIT_STATIC_BASIC_STATS {0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0}}
393 # define JS_BASIC_STATS_INIT(bs) memset((bs), 0, sizeof(JSBasicStats))
394 # define JS_BASIC_STATS_ACCUM(bs,val) \
395 JS_BasicStatsAccum(bs, val)
396 # define JS_MeanAndStdDevBS(bs,sigma) \
397 JS_MeanAndStdDev((bs)->num, (bs)->sum, (bs)->sqsum, sigma)
398 extern void
399 JS_BasicStatsAccum(JSBasicStats* bs, uint32_t val);
400 extern double
401 JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double* sigma);
402 extern void
403 JS_DumpBasicStats(JSBasicStats* bs, const char* title, FILE* fp);
404 extern void
405 JS_DumpHistogram(JSBasicStats* bs, FILE* fp);
406 #else
407 # define JS_BASIC_STATS_ACCUM(bs,val)
408 #endif
409
410 /* A jsbitmap_t is a long integer that can be used for bitmaps. */
411 typedef size_t jsbitmap;
412 #define JS_BITMAP_NBITS (sizeof(jsbitmap) * CHAR_BIT)
413 #define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] & \
414 (jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS)))
415 #define JS_SET_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] |= \
416 (jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS)))
417 #define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] &= \
418 ~(jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS)))
419
420 /* Wrapper for various macros to stop warnings coming from their expansions. */
421 #if defined(__clang__)
422 # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
423 JS_BEGIN_MACRO \
424 _Pragma("clang diagnostic push") \
425 /* If these _Pragmas cause warnings for you, try disabling ccache. */ \
426 _Pragma("clang diagnostic ignored \"-Wunused-value\"") \
427 { expr; } \
428 _Pragma("clang diagnostic pop") \
429 JS_END_MACRO
430 #elif MOZ_IS_GCC
431
432 # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
433 JS_BEGIN_MACRO \
434 _Pragma("GCC diagnostic push") \
435 _Pragma("GCC diagnostic ignored \"-Wunused-but-set-variable\"") \
436 expr; \
437 _Pragma("GCC diagnostic pop") \
438 JS_END_MACRO
439 #endif
440
441 #if !defined(JS_SILENCE_UNUSED_VALUE_IN_EXPR)
442 # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
443 JS_BEGIN_MACRO \
444 expr; \
445 JS_END_MACRO
446 #endif
447
448 #endif /* jsutil_h */
449