LCOV - code coverage report
Current view: top level - js/src - jsutil.h (source / functions) Hit Total Coverage
Test: output.info Lines: 33 85 38.8 %
Date: 2017-07-14 16:53:18 Functions: 28 50 56.0 %
Legend: Lines: hit not hit

          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 */

Generated by: LCOV version 1.13