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