summaryrefslogtreecommitdiffstats
path: root/js/src/jsutil.h
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/jsutil.h
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-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.h454
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 */