/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * PR assertion checker. */ #ifndef jsutil_h #define jsutil_h #include "mozilla/Attributes.h" #include "mozilla/Compiler.h" #include "mozilla/GuardObjects.h" #ifdef USE_ZLIB #include #endif #include "js/Utility.h" /* Forward declarations. */ struct JSContext; static JS_ALWAYS_INLINE void * js_memcpy(void *dst_, const void *src_, size_t len) { char *dst = (char *) dst_; const char *src = (const char *) src_; JS_ASSERT_IF(dst >= src, (size_t) (dst - src) >= len); JS_ASSERT_IF(src >= dst, (size_t) (src - dst) >= len); return memcpy(dst, src, len); } namespace js { template struct AlignmentTestStruct { char c; T t; }; /* This macro determines the alignment requirements of a type. */ #define JS_ALIGNMENT_OF(t_) \ (sizeof(js::AlignmentTestStruct) - sizeof(t_)) template class AlignedPtrAndFlag { uintptr_t bits; public: AlignedPtrAndFlag(T *t, bool aFlag) { JS_ASSERT((uintptr_t(t) & 1) == 0); bits = uintptr_t(t) | uintptr_t(aFlag); } T *ptr() const { return (T *)(bits & ~uintptr_t(1)); } bool flag() const { return (bits & 1) != 0; } void setPtr(T *t) { JS_ASSERT((uintptr_t(t) & 1) == 0); bits = uintptr_t(t) | uintptr_t(flag()); } void setFlag() { bits |= 1; } void unsetFlag() { bits &= ~uintptr_t(1); } void set(T *t, bool aFlag) { JS_ASSERT((uintptr_t(t) & 1) == 0); bits = uintptr_t(t) | aFlag; } }; template static inline void Reverse(T *beg, T *end) { while (beg != end) { if (--end == beg) return; T tmp = *beg; *beg = *end; *end = tmp; ++beg; } } template static inline T * Find(T *beg, T *end, const T &v) { for (T *p = beg; p != end; ++p) { if (*p == v) return p; } return end; } template static inline typename Container::ElementType * Find(Container &c, const typename Container::ElementType &v) { return Find(c.begin(), c.end(), v); } template void ForEach(InputIterT begin, InputIterT end, CallableT f) { for (; begin != end; ++begin) f(*begin); } template static inline T Min(T t1, T t2) { return t1 < t2 ? t1 : t2; } template static inline T Max(T t1, T t2) { return t1 > t2 ? t1 : t2; } /* Allows a const variable to be initialized after its declaration. */ template static T& InitConst(const T &t) { return const_cast(t); } template JS_ALWAYS_INLINE T & ImplicitCast(U &u) { T &t = u; return t; } template class AutoScopedAssign { public: AutoScopedAssign(T *addr, const T &value MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : addr_(addr), old(*addr_) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; *addr_ = value; } ~AutoScopedAssign() { *addr_ = old; } private: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER T *addr_; T old; }; template static inline bool IsPowerOfTwo(T t) { return t && !(t & (t - 1)); } template static inline U ComputeByteAlignment(T bytes, U alignment) { JS_ASSERT(IsPowerOfTwo(alignment)); return (alignment - (bytes % alignment)) % alignment; } template static inline T AlignBytes(T bytes, U alignment) { return bytes + ComputeByteAlignment(bytes, alignment); } JS_ALWAYS_INLINE static size_t UnsignedPtrDiff(const void *bigger, const void *smaller) { return size_t(bigger) - size_t(smaller); } /*****************************************************************************/ /* A bit array is an array of bits represented by an array of words (size_t). */ static inline unsigned NumWordsForBitArrayOfLength(size_t length) { return (length + (JS_BITS_PER_WORD - 1)) / JS_BITS_PER_WORD; } static inline unsigned BitArrayIndexToWordIndex(size_t length, size_t bitIndex) { unsigned wordIndex = bitIndex / JS_BITS_PER_WORD; JS_ASSERT(wordIndex < length); return wordIndex; } static inline size_t BitArrayIndexToWordMask(size_t i) { return size_t(1) << (i % JS_BITS_PER_WORD); } static inline bool IsBitArrayElementSet(size_t *array, size_t length, size_t i) { return array[BitArrayIndexToWordIndex(length, i)] & BitArrayIndexToWordMask(i); } static inline bool IsAnyBitArrayElementSet(size_t *array, size_t length) { unsigned numWords = NumWordsForBitArrayOfLength(length); for (unsigned i = 0; i < numWords; ++i) { if (array[i]) return true; } return false; } static inline void SetBitArrayElement(size_t *array, size_t length, size_t i) { array[BitArrayIndexToWordIndex(length, i)] |= BitArrayIndexToWordMask(i); } static inline void ClearBitArrayElement(size_t *array, size_t length, size_t i) { array[BitArrayIndexToWordIndex(length, i)] &= ~BitArrayIndexToWordMask(i); } static inline void ClearAllBitArrayElements(size_t *array, size_t length) { for (unsigned i = 0; i < length; ++i) array[i] = 0; } #ifdef USE_ZLIB class Compressor { /* Number of bytes we should hand to zlib each compressMore() call. */ static const size_t CHUNKSIZE = 2048; z_stream zs; const unsigned char *inp; size_t inplen; size_t outbytes; public: enum Status { MOREOUTPUT, DONE, CONTINUE, OOM }; Compressor(const unsigned char *inp, size_t inplen); ~Compressor(); bool init(); void setOutput(unsigned char *out, size_t outlen); size_t outWritten() const { return outbytes; } /* Compress some of the input. Return true if it should be called again. */ Status compressMore(); }; /* * Decompress a string. The caller must know the length of the output and * allocate |out| to a string of that length. */ bool DecompressString(const unsigned char *inp, size_t inplen, unsigned char *out, size_t outlen); #endif } /* namespace js */ /* Crash diagnostics */ #ifdef DEBUG # define JS_CRASH_DIAGNOSTICS 1 #endif #ifdef JS_CRASH_DIAGNOSTICS # define JS_POISON(p, val, size) memset((p), (val), (size)) #else # define JS_POISON(p, val, size) ((void) 0) #endif /* Basic stats */ #ifdef DEBUG # define JS_BASIC_STATS 1 #endif #ifdef JS_BASIC_STATS # include typedef struct JSBasicStats { uint32_t num; uint32_t max; double sum; double sqsum; uint32_t logscale; /* logarithmic scale: 0 (linear), 2, 10 */ uint32_t hist[11]; } JSBasicStats; # define JS_INIT_STATIC_BASIC_STATS {0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0}} # define JS_BASIC_STATS_INIT(bs) memset((bs), 0, sizeof(JSBasicStats)) # define JS_BASIC_STATS_ACCUM(bs,val) \ JS_BasicStatsAccum(bs, val) # define JS_MeanAndStdDevBS(bs,sigma) \ JS_MeanAndStdDev((bs)->num, (bs)->sum, (bs)->sqsum, sigma) extern void JS_BasicStatsAccum(JSBasicStats *bs, uint32_t val); extern double JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double *sigma); extern void JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp); extern void JS_DumpHistogram(JSBasicStats *bs, FILE *fp); #else # define JS_BASIC_STATS_ACCUM(bs,val) #endif /* A jsbitmap_t is a long integer that can be used for bitmaps. */ typedef size_t jsbitmap; #define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & \ ((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) #define JS_SET_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= \ ((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) #define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= \ ~((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) /* Wrapper for various macros to stop warnings coming from their expansions. */ #if defined(__clang__) # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ JS_BEGIN_MACRO \ _Pragma("clang diagnostic push") \ /* If these _Pragmas cause warnings for you, try disabling ccache. */ \ _Pragma("clang diagnostic ignored \"-Wunused-value\"") \ { expr; } \ _Pragma("clang diagnostic pop") \ JS_END_MACRO #elif MOZ_IS_GCC #if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ JS_BEGIN_MACRO \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wunused-but-set-variable\"") \ expr; \ _Pragma("GCC diagnostic pop") \ JS_END_MACRO #endif #endif #if !defined(JS_SILENCE_UNUSED_VALUE_IN_EXPR) # define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \ JS_BEGIN_MACRO \ expr; \ JS_END_MACRO #endif #endif /* jsutil_h */