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