michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * PR assertion checker. michael@0: */ michael@0: michael@0: #ifndef jsutil_h michael@0: #define jsutil_h michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Compiler.h" michael@0: #include "mozilla/GuardObjects.h" michael@0: michael@0: #include michael@0: michael@0: #include "js/Utility.h" michael@0: michael@0: #define JS_ALWAYS_TRUE(expr) MOZ_ALWAYS_TRUE(expr) michael@0: #define JS_ALWAYS_FALSE(expr) MOZ_ALWAYS_FALSE(expr) michael@0: michael@0: #if defined(JS_DEBUG) michael@0: # define JS_DIAGNOSTICS_ASSERT(expr) MOZ_ASSERT(expr) michael@0: #elif defined(JS_CRASH_DIAGNOSTICS) michael@0: # define JS_DIAGNOSTICS_ASSERT(expr) do { if (MOZ_UNLIKELY(!(expr))) MOZ_CRASH(); } while(0) michael@0: #else michael@0: # define JS_DIAGNOSTICS_ASSERT(expr) ((void) 0) michael@0: #endif michael@0: michael@0: static MOZ_ALWAYS_INLINE void * michael@0: js_memcpy(void *dst_, const void *src_, size_t len) michael@0: { michael@0: char *dst = (char *) dst_; michael@0: const char *src = (const char *) src_; michael@0: JS_ASSERT_IF(dst >= src, (size_t) (dst - src) >= len); michael@0: JS_ASSERT_IF(src >= dst, (size_t) (src - dst) >= len); michael@0: michael@0: return memcpy(dst, src, len); michael@0: } michael@0: michael@0: namespace js { michael@0: michael@0: template michael@0: struct AlignmentTestStruct michael@0: { michael@0: char c; michael@0: T t; michael@0: }; michael@0: michael@0: /* This macro determines the alignment requirements of a type. */ michael@0: #define JS_ALIGNMENT_OF(t_) \ michael@0: (sizeof(js::AlignmentTestStruct) - sizeof(t_)) michael@0: michael@0: template michael@0: class AlignedPtrAndFlag michael@0: { michael@0: uintptr_t bits; michael@0: michael@0: public: michael@0: AlignedPtrAndFlag(T *t, bool aFlag) { michael@0: JS_ASSERT((uintptr_t(t) & 1) == 0); michael@0: bits = uintptr_t(t) | uintptr_t(aFlag); michael@0: } michael@0: michael@0: T *ptr() const { michael@0: return (T *)(bits & ~uintptr_t(1)); michael@0: } michael@0: michael@0: bool flag() const { michael@0: return (bits & 1) != 0; michael@0: } michael@0: michael@0: void setPtr(T *t) { michael@0: JS_ASSERT((uintptr_t(t) & 1) == 0); michael@0: bits = uintptr_t(t) | uintptr_t(flag()); michael@0: } michael@0: michael@0: void setFlag() { michael@0: bits |= 1; michael@0: } michael@0: michael@0: void unsetFlag() { michael@0: bits &= ~uintptr_t(1); michael@0: } michael@0: michael@0: void set(T *t, bool aFlag) { michael@0: JS_ASSERT((uintptr_t(t) & 1) == 0); michael@0: bits = uintptr_t(t) | aFlag; michael@0: } michael@0: }; michael@0: michael@0: template michael@0: static inline void michael@0: Reverse(T *beg, T *end) michael@0: { michael@0: while (beg != end) { michael@0: if (--end == beg) michael@0: return; michael@0: T tmp = *beg; michael@0: *beg = *end; michael@0: *end = tmp; michael@0: ++beg; michael@0: } michael@0: } michael@0: michael@0: template michael@0: static inline T * michael@0: Find(T *beg, T *end, const T &v) michael@0: { michael@0: for (T *p = beg; p != end; ++p) { michael@0: if (*p == v) michael@0: return p; michael@0: } michael@0: return end; michael@0: } michael@0: michael@0: template michael@0: static inline typename Container::ElementType * michael@0: Find(Container &c, const typename Container::ElementType &v) michael@0: { michael@0: return Find(c.begin(), c.end(), v); michael@0: } michael@0: michael@0: template michael@0: void michael@0: ForEach(InputIterT begin, InputIterT end, CallableT f) michael@0: { michael@0: for (; begin != end; ++begin) michael@0: f(*begin); michael@0: } michael@0: michael@0: template michael@0: static inline T michael@0: Min(T t1, T t2) michael@0: { michael@0: return t1 < t2 ? t1 : t2; michael@0: } michael@0: michael@0: template michael@0: static inline T michael@0: Max(T t1, T t2) michael@0: { michael@0: return t1 > t2 ? t1 : t2; michael@0: } michael@0: michael@0: /* Allows a const variable to be initialized after its declaration. */ michael@0: template michael@0: static T& michael@0: InitConst(const T &t) michael@0: { michael@0: return const_cast(t); michael@0: } michael@0: michael@0: template michael@0: MOZ_ALWAYS_INLINE T & michael@0: ImplicitCast(U &u) michael@0: { michael@0: T &t = u; michael@0: return t; michael@0: } michael@0: michael@0: template michael@0: class AutoScopedAssign michael@0: { michael@0: public: michael@0: AutoScopedAssign(T *addr, const T &value michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : addr_(addr), old(*addr_) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: *addr_ = value; michael@0: } michael@0: michael@0: ~AutoScopedAssign() { *addr_ = old; } michael@0: michael@0: private: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: T *addr_; michael@0: T old; michael@0: }; michael@0: michael@0: template michael@0: static inline bool michael@0: IsPowerOfTwo(T t) michael@0: { michael@0: return t && !(t & (t - 1)); michael@0: } michael@0: michael@0: template michael@0: static inline U michael@0: ComputeByteAlignment(T bytes, U alignment) michael@0: { michael@0: JS_ASSERT(IsPowerOfTwo(alignment)); michael@0: return (alignment - (bytes % alignment)) % alignment; michael@0: } michael@0: michael@0: template michael@0: static inline T michael@0: AlignBytes(T bytes, U alignment) michael@0: { michael@0: return bytes + ComputeByteAlignment(bytes, alignment); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE size_t michael@0: UnsignedPtrDiff(const void *bigger, const void *smaller) michael@0: { michael@0: return size_t(bigger) - size_t(smaller); michael@0: } michael@0: michael@0: /*****************************************************************************/ michael@0: michael@0: /* A bit array is an array of bits represented by an array of words (size_t). */ michael@0: michael@0: static const size_t BitArrayElementBits = sizeof(size_t) * CHAR_BIT; michael@0: michael@0: static inline unsigned michael@0: NumWordsForBitArrayOfLength(size_t length) michael@0: { michael@0: return (length + (BitArrayElementBits - 1)) / BitArrayElementBits; michael@0: } michael@0: michael@0: static inline unsigned michael@0: BitArrayIndexToWordIndex(size_t length, size_t bitIndex) michael@0: { michael@0: unsigned wordIndex = bitIndex / BitArrayElementBits; michael@0: JS_ASSERT(wordIndex < length); michael@0: return wordIndex; michael@0: } michael@0: michael@0: static inline size_t michael@0: BitArrayIndexToWordMask(size_t i) michael@0: { michael@0: return size_t(1) << (i % BitArrayElementBits); michael@0: } michael@0: michael@0: static inline bool michael@0: IsBitArrayElementSet(size_t *array, size_t length, size_t i) michael@0: { michael@0: return array[BitArrayIndexToWordIndex(length, i)] & BitArrayIndexToWordMask(i); michael@0: } michael@0: michael@0: static inline bool michael@0: IsAnyBitArrayElementSet(size_t *array, size_t length) michael@0: { michael@0: unsigned numWords = NumWordsForBitArrayOfLength(length); michael@0: for (unsigned i = 0; i < numWords; ++i) { michael@0: if (array[i]) michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: static inline void michael@0: SetBitArrayElement(size_t *array, size_t length, size_t i) michael@0: { michael@0: array[BitArrayIndexToWordIndex(length, i)] |= BitArrayIndexToWordMask(i); michael@0: } michael@0: michael@0: static inline void michael@0: ClearBitArrayElement(size_t *array, size_t length, size_t i) michael@0: { michael@0: array[BitArrayIndexToWordIndex(length, i)] &= ~BitArrayIndexToWordMask(i); michael@0: } michael@0: michael@0: static inline void michael@0: ClearAllBitArrayElements(size_t *array, size_t length) michael@0: { michael@0: for (unsigned i = 0; i < length; ++i) michael@0: array[i] = 0; michael@0: } michael@0: michael@0: } /* namespace js */ michael@0: michael@0: /* Crash diagnostics */ michael@0: #ifdef DEBUG michael@0: # define JS_CRASH_DIAGNOSTICS 1 michael@0: #endif michael@0: #if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL) michael@0: # define JS_POISON(p, val, size) memset((p), (val), (size)) michael@0: #else michael@0: # define JS_POISON(p, val, size) ((void) 0) michael@0: #endif michael@0: michael@0: /* Bug 984101: Disable labeled poisoning until we have poison checking. */ michael@0: #define JS_EXTRA_POISON(p, val, size) ((void) 0) michael@0: michael@0: /* Basic stats */ michael@0: #ifdef DEBUG michael@0: # define JS_BASIC_STATS 1 michael@0: #endif michael@0: #ifdef JS_BASIC_STATS michael@0: # include michael@0: typedef struct JSBasicStats { michael@0: uint32_t num; michael@0: uint32_t max; michael@0: double sum; michael@0: double sqsum; michael@0: uint32_t logscale; /* logarithmic scale: 0 (linear), 2, 10 */ michael@0: uint32_t hist[11]; michael@0: } JSBasicStats; michael@0: # define JS_INIT_STATIC_BASIC_STATS {0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0}} michael@0: # define JS_BASIC_STATS_INIT(bs) memset((bs), 0, sizeof(JSBasicStats)) michael@0: # define JS_BASIC_STATS_ACCUM(bs,val) \ michael@0: JS_BasicStatsAccum(bs, val) michael@0: # define JS_MeanAndStdDevBS(bs,sigma) \ michael@0: JS_MeanAndStdDev((bs)->num, (bs)->sum, (bs)->sqsum, sigma) michael@0: extern void michael@0: JS_BasicStatsAccum(JSBasicStats *bs, uint32_t val); michael@0: extern double michael@0: JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double *sigma); michael@0: extern void michael@0: JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp); michael@0: extern void michael@0: JS_DumpHistogram(JSBasicStats *bs, FILE *fp); michael@0: #else michael@0: # define JS_BASIC_STATS_ACCUM(bs,val) michael@0: #endif michael@0: michael@0: /* A jsbitmap_t is a long integer that can be used for bitmaps. */ michael@0: typedef size_t jsbitmap; michael@0: #define JS_BITMAP_NBITS (sizeof(jsbitmap) * CHAR_BIT) michael@0: #define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] & \ michael@0: (jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) michael@0: #define JS_SET_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] |= \ michael@0: (jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) michael@0: #define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] &= \ michael@0: ~(jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) michael@0: michael@0: /* Wrapper for various macros to stop warnings coming from their expansions. */ michael@0: #if defined(__clang__) michael@0: # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ michael@0: JS_BEGIN_MACRO \ michael@0: _Pragma("clang diagnostic push") \ michael@0: /* If these _Pragmas cause warnings for you, try disabling ccache. */ \ michael@0: _Pragma("clang diagnostic ignored \"-Wunused-value\"") \ michael@0: { expr; } \ michael@0: _Pragma("clang diagnostic pop") \ michael@0: JS_END_MACRO michael@0: #elif MOZ_IS_GCC michael@0: michael@0: #if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) michael@0: # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ michael@0: JS_BEGIN_MACRO \ michael@0: _Pragma("GCC diagnostic push") \ michael@0: _Pragma("GCC diagnostic ignored \"-Wunused-but-set-variable\"") \ michael@0: expr; \ michael@0: _Pragma("GCC diagnostic pop") \ michael@0: JS_END_MACRO michael@0: #endif michael@0: #endif michael@0: michael@0: #if !defined(JS_SILENCE_UNUSED_VALUE_IN_EXPR) michael@0: # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ michael@0: JS_BEGIN_MACRO \ michael@0: expr; \ michael@0: JS_END_MACRO michael@0: #endif michael@0: michael@0: #endif /* jsutil_h */