diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /js/src/jsutil.h | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/jsutil.h')
-rw-r--r-- | js/src/jsutil.h | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/js/src/jsutil.h b/js/src/jsutil.h new file mode 100644 index 000000000..790b97ddc --- /dev/null +++ b/js/src/jsutil.h @@ -0,0 +1,454 @@ +/* -*- 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/Assertions.h" +#include "mozilla/Compiler.h" +#include "mozilla/GuardObjects.h" +#include "mozilla/HashFunctions.h" +#include "mozilla/MathAlgorithms.h" +#include "mozilla/PodOperations.h" + +#include <limits.h> + +#include "js/Utility.h" +#include "js/Value.h" + +#define JS_ALWAYS_TRUE(expr) MOZ_ALWAYS_TRUE(expr) +#define JS_ALWAYS_FALSE(expr) MOZ_ALWAYS_FALSE(expr) + +#if defined(JS_DEBUG) +# define JS_DIAGNOSTICS_ASSERT(expr) MOZ_ASSERT(expr) +#elif defined(JS_CRASH_DIAGNOSTICS) +# define JS_DIAGNOSTICS_ASSERT(expr) do { if (MOZ_UNLIKELY(!(expr))) MOZ_CRASH(); } while(0) +#else +# define JS_DIAGNOSTICS_ASSERT(expr) ((void) 0) +#endif + +static MOZ_ALWAYS_INLINE void* +js_memcpy(void* dst_, const void* src_, size_t len) +{ + char* dst = (char*) dst_; + const char* src = (const char*) src_; + MOZ_ASSERT_IF(dst >= src, (size_t) (dst - src) >= len); + MOZ_ASSERT_IF(src >= dst, (size_t) (src - dst) >= len); + + return memcpy(dst, src, len); +} + +namespace js { + +template <class T> +class AlignedPtrAndFlag +{ + uintptr_t bits; + + public: + AlignedPtrAndFlag(T* t, bool aFlag) { + MOZ_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) { + MOZ_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) { + MOZ_ASSERT((uintptr_t(t) & 1) == 0); + bits = uintptr_t(t) | aFlag; + } +}; + +template <class T> +static inline void +Reverse(T* beg, T* end) +{ + while (beg != end) { + if (--end == beg) + return; + T tmp = *beg; + *beg = *end; + *end = tmp; + ++beg; + } +} + +template <class T> +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 <class Container> +static inline typename Container::ElementType* +Find(Container& c, const typename Container::ElementType& v) +{ + return Find(c.begin(), c.end(), v); +} + +template <typename InputIterT, typename CallableT> +void +ForEach(InputIterT begin, InputIterT end, CallableT f) +{ + for (; begin != end; ++begin) + f(*begin); +} + +template <class Container1, class Container2> +static inline bool +EqualContainers(const Container1& lhs, const Container2& rhs) +{ + if (lhs.length() != rhs.length()) + return false; + for (size_t i = 0, n = lhs.length(); i < n; i++) { + if (lhs[i] != rhs[i]) + return false; + } + return true; +} + +template <class Container> +static inline HashNumber +AddContainerToHash(const Container& c, HashNumber hn = 0) +{ + for (size_t i = 0; i < c.length(); i++) + hn = mozilla::AddToHash(hn, HashNumber(c[i])); + return hn; +} + +template <class T> +static inline T +Min(T t1, T t2) +{ + return t1 < t2 ? t1 : t2; +} + +template <class T> +static inline T +Max(T t1, T t2) +{ + return t1 > t2 ? t1 : t2; +} + +/* Allows a const variable to be initialized after its declaration. */ +template <class T> +static T& +InitConst(const T& t) +{ + return const_cast<T&>(t); +} + +template <class T, class U> +MOZ_ALWAYS_INLINE T& +ImplicitCast(U& u) +{ + T& t = u; + return t; +} + +template<typename T> +class MOZ_RAII 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 <typename T, typename U> +static inline U +ComputeByteAlignment(T bytes, U alignment) +{ + static_assert(mozilla::IsUnsigned<U>::value, + "alignment amount must be unsigned"); + + MOZ_ASSERT(mozilla::IsPowerOfTwo(alignment)); + return (alignment - (bytes % alignment)) % alignment; +} + +template <typename T, typename U> +static inline T +AlignBytes(T bytes, U alignment) +{ + static_assert(mozilla::IsUnsigned<U>::value, + "alignment amount must be unsigned"); + + return bytes + ComputeByteAlignment(bytes, alignment); +} + +/*****************************************************************************/ + +/* A bit array is an array of bits represented by an array of words (size_t). */ + +static const size_t BitArrayElementBits = sizeof(size_t) * CHAR_BIT; + +static inline unsigned +NumWordsForBitArrayOfLength(size_t length) +{ + return (length + (BitArrayElementBits - 1)) / BitArrayElementBits; +} + +static inline unsigned +BitArrayIndexToWordIndex(size_t length, size_t bitIndex) +{ + unsigned wordIndex = bitIndex / BitArrayElementBits; + MOZ_ASSERT(wordIndex < length); + return wordIndex; +} + +static inline size_t +BitArrayIndexToWordMask(size_t i) +{ + return size_t(1) << (i % BitArrayElementBits); +} + +static inline bool +IsBitArrayElementSet(const size_t* array, size_t length, size_t i) +{ + return array[BitArrayIndexToWordIndex(length, i)] & BitArrayIndexToWordMask(i); +} + +static inline bool +IsAnyBitArrayElementSet(const 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; +} + +} /* namespace js */ + +namespace mozilla { + +/** + * Set the first |aNElem| T elements in |aDst| to |aSrc|. + */ +template<typename T> +static MOZ_ALWAYS_INLINE void +PodSet(T* aDst, const T& aSrc, size_t aNElem) +{ + for (const T* dstend = aDst + aNElem; aDst < dstend; ++aDst) + *aDst = aSrc; +} + +} /* namespace mozilla */ + +/* + * Patterns used by SpiderMonkey to overwrite unused memory. If you are + * accessing an object with one of these pattern, you probably have a dangling + * pointer. These values should be odd, see the comment in IsThingPoisoned. + * + * Note: new patterns should also be added to the array in IsThingPoisoned! + */ +#define JS_FRESH_NURSERY_PATTERN 0x2F +#define JS_SWEPT_NURSERY_PATTERN 0x2B +#define JS_ALLOCATED_NURSERY_PATTERN 0x2D +#define JS_FRESH_TENURED_PATTERN 0x4F +#define JS_MOVED_TENURED_PATTERN 0x49 +#define JS_SWEPT_TENURED_PATTERN 0x4B +#define JS_ALLOCATED_TENURED_PATTERN 0x4D +#define JS_FREED_HEAP_PTR_PATTERN 0x6B + +/* + * Ensure JS_SWEPT_CODE_PATTERN is a byte pattern that will crash immediately + * when executed, so either an undefined instruction or an instruction that's + * illegal in user mode. + */ +#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_NONE) +# define JS_SWEPT_CODE_PATTERN 0xED // IN instruction, crashes in user mode. +#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) +# define JS_SWEPT_CODE_PATTERN 0xA3 // undefined instruction +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +# define JS_SWEPT_CODE_PATTERN 0x01 // undefined instruction +#else +# error "JS_SWEPT_CODE_PATTERN not defined for this platform" +#endif + +static inline void* +Poison(void* ptr, uint8_t value, size_t num) +{ + static bool disablePoison = bool(getenv("JSGC_DISABLE_POISONING")); + if (disablePoison) + return ptr; + + // Without a valid Value tag, a poisoned Value may look like a valid + // floating point number. To ensure that we crash more readily when + // observing a poisoned Value, we make the poison an invalid ObjectValue. + // Unfortunately, this adds about 2% more overhead, so we can only enable + // it in debug. +#if defined(DEBUG) + uintptr_t obj; + memset(&obj, value, sizeof(obj)); +# if defined(JS_PUNBOX64) + obj = obj & ((uintptr_t(1) << JSVAL_TAG_SHIFT) - 1); +# endif + JS::Value v = JS::PoisonedObjectValue(reinterpret_cast<JSObject*>(obj)); + + size_t value_count = num / sizeof(v); + size_t byte_count = num % sizeof(v); + mozilla::PodSet(reinterpret_cast<JS::Value*>(ptr), v, value_count); + if (byte_count) { + uint8_t* bytes = static_cast<uint8_t*>(ptr); + uint8_t* end = bytes + num; + mozilla::PodSet(end - byte_count, value, byte_count); + } +#else // !DEBUG + memset(ptr, value, num); +#endif // !DEBUG + return ptr; +} + +/* Crash diagnostics by default in debug and on nightly channel. */ +#if (defined(DEBUG) || defined(NIGHTLY_BUILD)) && !defined(MOZ_ASAN) +# define JS_CRASH_DIAGNOSTICS 1 +#endif + +/* Enable poisoning in crash-diagnostics and zeal builds. */ +#if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL) +# define JS_POISON(p, val, size) Poison(p, val, size) +#else +# define JS_POISON(p, val, size) ((void) 0) +#endif + +/* Enable even more poisoning in purely debug builds. */ +#if defined(DEBUG) +# define JS_EXTRA_POISON(p, val, size) Poison(p, val, size) +#else +# define JS_EXTRA_POISON(p, val, size) ((void) 0) +#endif + +/* Basic stats */ +#ifdef DEBUG +# define JS_BASIC_STATS 1 +#endif +#ifdef JS_BASIC_STATS +# include <stdio.h> +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_BITMAP_NBITS (sizeof(jsbitmap) * CHAR_BIT) +#define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] & \ + (jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) +#define JS_SET_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] |= \ + (jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) +#define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)/JS_BITMAP_NBITS] &= \ + ~(jsbitmap(1)<<((_bit)%JS_BITMAP_NBITS))) + +/* 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 + +# 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 + +#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 */ |