LCOV - code coverage report
Current view: top level - js/public - Utility.h (source / functions) Hit Total Coverage
Test: output.info Lines: 19 97 19.6 %
Date: 2018-08-07 16:35:00 Functions: 0 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             : #ifndef js_Utility_h
       8             : #define js_Utility_h
       9             : 
      10             : #include "mozilla/Assertions.h"
      11             : #include "mozilla/Atomics.h"
      12             : #include "mozilla/Attributes.h"
      13             : #include "mozilla/Compiler.h"
      14             : #include "mozilla/Move.h"
      15             : #include "mozilla/Scoped.h"
      16             : #include "mozilla/TemplateLib.h"
      17             : #include "mozilla/UniquePtr.h"
      18             : #include "mozilla/WrappingOperations.h"
      19             : 
      20             : #include <stdlib.h>
      21             : #include <string.h>
      22             : 
      23             : #ifdef JS_OOM_DO_BACKTRACES
      24             : #include <execinfo.h>
      25             : #include <stdio.h>
      26             : #endif
      27             : 
      28             : #include "jstypes.h"
      29             : 
      30             : #include "mozmemory.h"
      31             : 
      32             : /* The public JS engine namespace. */
      33             : namespace JS {}
      34             : 
      35             : /* The mozilla-shared reusable template/utility namespace. */
      36             : namespace mozilla {}
      37             : 
      38             : /* The private JS engine namespace. */
      39             : namespace js {}
      40             : 
      41             : #define JS_STATIC_ASSERT(cond)           static_assert(cond, "JS_STATIC_ASSERT")
      42             : #define JS_STATIC_ASSERT_IF(cond, expr)  MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF")
      43             : 
      44             : extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API(void)
      45             : JS_Assert(const char* s, const char* file, int ln);
      46             : 
      47             : /*
      48             :  * Custom allocator support for SpiderMonkey
      49             :  */
      50             : #if defined JS_USE_CUSTOM_ALLOCATOR
      51             : # include "jscustomallocator.h"
      52             : #else
      53             : 
      54             : namespace js {
      55             : 
      56             : /*
      57             :  * Thread types are used to tag threads for certain kinds of testing (see
      58             :  * below), and also used to characterize threads in the thread scheduler (see
      59             :  * js/src/vm/HelperThreads.cpp).
      60             :  *
      61             :  * Please update oom::FirstThreadTypeToTest and oom::LastThreadTypeToTest when
      62             :  * adding new thread types.
      63             :  */
      64             : enum ThreadType {
      65             :     THREAD_TYPE_NONE = 0,       // 0
      66             :     THREAD_TYPE_MAIN,           // 1
      67             :     THREAD_TYPE_WASM,           // 2
      68             :     THREAD_TYPE_ION,            // 3
      69             :     THREAD_TYPE_PARSE,          // 4
      70             :     THREAD_TYPE_COMPRESS,       // 5
      71             :     THREAD_TYPE_GCHELPER,       // 6
      72             :     THREAD_TYPE_GCPARALLEL,     // 7
      73             :     THREAD_TYPE_PROMISE_TASK,   // 8
      74             :     THREAD_TYPE_ION_FREE,       // 9
      75             :     THREAD_TYPE_WASM_TIER2,     // 10
      76             :     THREAD_TYPE_WORKER,         // 11
      77             :     THREAD_TYPE_MAX             // Used to check shell function arguments
      78             : };
      79             : 
      80             : namespace oom {
      81             : 
      82             : /*
      83             :  * Theads are tagged only in certain debug contexts.  Notably, to make testing
      84             :  * OOM in certain helper threads more effective, we allow restricting the OOM
      85             :  * testing to a certain helper thread type. This allows us to fail e.g. in
      86             :  * off-thread script parsing without causing an OOM in the active thread first.
      87             :  *
      88             :  * Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation
      89             :  * is in jsutil.cpp.
      90             :  */
      91             : # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
      92             : 
      93             : // Define the range of threads tested by simulated OOM testing and the
      94             : // like. Testing worker threads is not supported.
      95             : const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN;
      96             : const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_TIER2;
      97             : 
      98             : extern bool InitThreadType(void);
      99             : extern void SetThreadType(ThreadType);
     100             : extern JS_FRIEND_API(uint32_t) GetThreadType(void);
     101             : 
     102             : # else
     103             : 
     104             : inline bool InitThreadType(void) { return true; }
     105             : inline void SetThreadType(ThreadType t) {};
     106             : inline uint32_t GetThreadType(void) { return 0; }
     107             : 
     108             : # endif
     109             : 
     110             : } /* namespace oom */
     111             : } /* namespace js */
     112             : 
     113             : # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
     114             : 
     115             : #ifdef JS_OOM_BREAKPOINT
     116             : #  if defined(_MSC_VER)
     117             : static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { __asm { }; }
     118             : #  else
     119             : static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
     120             : #  endif
     121             : #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint()
     122             : #else
     123             : #define JS_OOM_CALL_BP_FUNC() do {} while(0)
     124             : #endif
     125             : 
     126             : namespace js {
     127             : namespace oom {
     128             : 
     129             : /*
     130             :  * Out of memory testing support.  We provide various testing functions to
     131             :  * simulate OOM conditions and so we can test that they are handled correctly.
     132             :  */
     133             : 
     134             : extern JS_PUBLIC_DATA(uint32_t) targetThread;
     135             : extern JS_PUBLIC_DATA(uint64_t) maxAllocations;
     136             : extern JS_PUBLIC_DATA(uint64_t) counter;
     137             : extern JS_PUBLIC_DATA(bool) failAlways;
     138             : 
     139             : extern void
     140             : SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always);
     141             : 
     142             : extern void
     143             : ResetSimulatedOOM();
     144             : 
     145             : inline bool
     146           0 : IsThreadSimulatingOOM()
     147             : {
     148           0 :     return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType();
     149             : }
     150             : 
     151             : inline bool
     152           0 : IsSimulatedOOMAllocation()
     153             : {
     154           0 :     return IsThreadSimulatingOOM() &&
     155           0 :            (counter == maxAllocations || (counter > maxAllocations && failAlways));
     156             : }
     157             : 
     158             : inline bool
     159           0 : ShouldFailWithOOM()
     160             : {
     161           0 :     if (!IsThreadSimulatingOOM())
     162             :         return false;
     163             : 
     164           0 :     counter++;
     165           0 :     if (IsSimulatedOOMAllocation()) {
     166             :         JS_OOM_CALL_BP_FUNC();
     167             :         return true;
     168             :     }
     169           0 :     return false;
     170             : }
     171             : 
     172             : inline bool
     173             : HadSimulatedOOM() {
     174           0 :     return counter >= maxAllocations;
     175             : }
     176             : 
     177             : /*
     178             :  * Out of stack space testing support, similar to OOM testing functions.
     179             :  */
     180             : 
     181             : extern JS_PUBLIC_DATA(uint32_t) stackTargetThread;
     182             : extern JS_PUBLIC_DATA(uint64_t) maxStackChecks;
     183             : extern JS_PUBLIC_DATA(uint64_t) stackCheckCounter;
     184             : extern JS_PUBLIC_DATA(bool) stackCheckFailAlways;
     185             : 
     186             : extern void
     187             : SimulateStackOOMAfter(uint64_t checks, uint32_t thread, bool always);
     188             : 
     189             : extern void
     190             : ResetSimulatedStackOOM();
     191             : 
     192             : inline bool
     193           0 : IsThreadSimulatingStackOOM()
     194             : {
     195           0 :     return js::oom::stackTargetThread && js::oom::stackTargetThread == js::oom::GetThreadType();
     196             : }
     197             : 
     198             : inline bool
     199           0 : IsSimulatedStackOOMCheck()
     200             : {
     201           0 :     return IsThreadSimulatingStackOOM() &&
     202           0 :            (stackCheckCounter == maxStackChecks || (stackCheckCounter > maxStackChecks && stackCheckFailAlways));
     203             : }
     204             : 
     205             : inline bool
     206           0 : ShouldFailWithStackOOM()
     207             : {
     208           0 :     if (!IsThreadSimulatingStackOOM())
     209             :         return false;
     210             : 
     211           0 :     stackCheckCounter++;
     212           0 :     if (IsSimulatedStackOOMCheck()) {
     213             :         JS_OOM_CALL_BP_FUNC();
     214             :         return true;
     215             :     }
     216           0 :     return false;
     217             : }
     218             : 
     219             : inline bool
     220             : HadSimulatedStackOOM()
     221             : {
     222           0 :     return stackCheckCounter >= maxStackChecks;
     223             : }
     224             : 
     225             : /*
     226             :  * Interrupt testing support, similar to OOM testing functions.
     227             :  */
     228             : 
     229             : extern JS_PUBLIC_DATA(uint32_t) interruptTargetThread;
     230             : extern JS_PUBLIC_DATA(uint64_t) maxInterruptChecks;
     231             : extern JS_PUBLIC_DATA(uint64_t) interruptCheckCounter;
     232             : extern JS_PUBLIC_DATA(bool) interruptCheckFailAlways;
     233             : 
     234             : extern void
     235             : SimulateInterruptAfter(uint64_t checks, uint32_t thread, bool always);
     236             : 
     237             : extern void
     238             : ResetSimulatedInterrupt();
     239             : 
     240             : inline bool
     241             : IsThreadSimulatingInterrupt()
     242             : {
     243           0 :     return js::oom::interruptTargetThread && js::oom::interruptTargetThread == js::oom::GetThreadType();
     244             : }
     245             : 
     246             : inline bool
     247           0 : IsSimulatedInterruptCheck()
     248             : {
     249           0 :     return IsThreadSimulatingInterrupt() &&
     250           0 :            (interruptCheckCounter == maxInterruptChecks || (interruptCheckCounter > maxInterruptChecks && interruptCheckFailAlways));
     251             : }
     252             : 
     253             : inline bool
     254           0 : ShouldFailWithInterrupt()
     255             : {
     256           0 :     if (!IsThreadSimulatingInterrupt())
     257             :         return false;
     258             : 
     259           0 :     interruptCheckCounter++;
     260           0 :     if (IsSimulatedInterruptCheck()) {
     261             :         JS_OOM_CALL_BP_FUNC();
     262             :         return true;
     263             :     }
     264           0 :     return false;
     265             : }
     266             : 
     267             : inline bool
     268             : HadSimulatedInterrupt()
     269             : {
     270           0 :     return interruptCheckCounter >= maxInterruptChecks;
     271             : }
     272             : 
     273             : } /* namespace oom */
     274             : } /* namespace js */
     275             : 
     276             : #  define JS_OOM_POSSIBLY_FAIL()                                              \
     277             :     do {                                                                      \
     278             :         if (js::oom::ShouldFailWithOOM())                                     \
     279             :             return nullptr;                                                   \
     280             :     } while (0)
     281             : 
     282             : #  define JS_OOM_POSSIBLY_FAIL_BOOL()                                         \
     283             :     do {                                                                      \
     284             :         if (js::oom::ShouldFailWithOOM())                                     \
     285             :             return false;                                                     \
     286             :     } while (0)
     287             : 
     288             : #  define JS_STACK_OOM_POSSIBLY_FAIL()                                        \
     289             :     do {                                                                      \
     290             :         if (js::oom::ShouldFailWithStackOOM())                                \
     291             :             return false;                                                     \
     292             :     } while (0)
     293             : 
     294             : #  define JS_STACK_OOM_POSSIBLY_FAIL_REPORT()                                 \
     295             :     do {                                                                      \
     296             :         if (js::oom::ShouldFailWithStackOOM()) {                              \
     297             :             ReportOverRecursed(cx);                                           \
     298             :             return false;                                                     \
     299             :         }                                                                     \
     300             :     } while (0)
     301             : 
     302             : #  define JS_INTERRUPT_POSSIBLY_FAIL()                                        \
     303             :     do {                                                                      \
     304             :         if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) {               \
     305             :             cx->requestInterrupt(js::InterruptReason::CallbackUrgent);        \
     306             :             return cx->handleInterrupt();                                     \
     307             :         }                                                                     \
     308             :     } while (0)
     309             : 
     310             : # else
     311             : 
     312             : #  define JS_OOM_POSSIBLY_FAIL() do {} while(0)
     313             : #  define JS_OOM_POSSIBLY_FAIL_BOOL() do {} while(0)
     314             : #  define JS_STACK_OOM_POSSIBLY_FAIL() do {} while(0)
     315             : #  define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() do {} while(0)
     316             : #  define JS_INTERRUPT_POSSIBLY_FAIL() do {} while(0)
     317             : namespace js {
     318             : namespace oom {
     319             : static inline bool IsSimulatedOOMAllocation() { return false; }
     320             : static inline bool ShouldFailWithOOM() { return false; }
     321             : } /* namespace oom */
     322             : } /* namespace js */
     323             : 
     324             : # endif /* DEBUG || JS_OOM_BREAKPOINT */
     325             : 
     326             : namespace js {
     327             : 
     328             : /* Disable OOM testing in sections which are not OOM safe. */
     329             : struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion)
     330             : {
     331             :     MOZ_NORETURN MOZ_COLD void crash(const char* reason);
     332             :     MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason);
     333             : 
     334             :     using AnnotateOOMAllocationSizeCallback = void(*)(size_t);
     335             :     static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback;
     336             :     static void setAnnotateOOMAllocationSizeCallback(AnnotateOOMAllocationSizeCallback callback) {
     337           0 :         annotateOOMSizeCallback = callback;
     338             :     }
     339             : 
     340             : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
     341           0 :     AutoEnterOOMUnsafeRegion()
     342           0 :       : oomEnabled_(oom::IsThreadSimulatingOOM() && oom::maxAllocations != UINT64_MAX),
     343           0 :         oomAfter_(0)
     344             :     {
     345           0 :         if (oomEnabled_) {
     346           0 :             MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this));
     347           0 :             oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter);
     348           0 :             oom::maxAllocations = UINT64_MAX;
     349             :         }
     350           0 :     }
     351             : 
     352           0 :     ~AutoEnterOOMUnsafeRegion() {
     353           0 :         if (oomEnabled_) {
     354           0 :             MOZ_ASSERT(oom::maxAllocations == UINT64_MAX);
     355           0 :             int64_t maxAllocations = int64_t(oom::counter) + oomAfter_;
     356           0 :             MOZ_ASSERT(maxAllocations >= 0,
     357             :                        "alloc count + oom limit exceeds range, your oom limit is probably too large");
     358           0 :             oom::maxAllocations = uint64_t(maxAllocations);
     359           0 :             MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr));
     360             :         }
     361           0 :     }
     362             : 
     363             :   private:
     364             :     // Used to catch concurrent use from other threads.
     365             :     static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_;
     366             : 
     367             :     bool oomEnabled_;
     368             :     int64_t oomAfter_;
     369             : #endif
     370             : };
     371             : 
     372             : } /* namespace js */
     373             : 
     374             : // Malloc allocation.
     375             : 
     376             : namespace js {
     377             : 
     378             : extern JS_PUBLIC_DATA(arena_id_t) MallocArena;
     379             : 
     380             : extern void InitMallocAllocator();
     381             : extern void ShutDownMallocAllocator();
     382             : 
     383             : } /* namespace js */
     384             : 
     385           0 : static inline void* js_malloc(size_t bytes)
     386             : {
     387           0 :     JS_OOM_POSSIBLY_FAIL();
     388           0 :     return moz_arena_malloc(js::MallocArena, bytes);
     389             : }
     390             : 
     391           0 : static inline void* js_calloc(size_t bytes)
     392             : {
     393           0 :     JS_OOM_POSSIBLY_FAIL();
     394           0 :     return moz_arena_calloc(js::MallocArena, bytes, 1);
     395             : }
     396             : 
     397           0 : static inline void* js_calloc(size_t nmemb, size_t size)
     398             : {
     399           0 :     JS_OOM_POSSIBLY_FAIL();
     400           0 :     return moz_arena_calloc(js::MallocArena, nmemb, size);
     401             : }
     402             : 
     403           0 : static inline void* js_realloc(void* p, size_t bytes)
     404             : {
     405             :     // realloc() with zero size is not portable, as some implementations may
     406             :     // return nullptr on success and free |p| for this.  We assume nullptr
     407             :     // indicates failure and that |p| is still valid.
     408           0 :     MOZ_ASSERT(bytes != 0);
     409             : 
     410           0 :     JS_OOM_POSSIBLY_FAIL();
     411           0 :     return moz_arena_realloc(js::MallocArena, p, bytes);
     412             : }
     413             : 
     414           0 : static inline void js_free(void* p)
     415             : {
     416             :     // TODO: This should call |moz_arena_free(js::MallocArena, p)| but we
     417             :     // currently can't enforce that all memory freed here was allocated by
     418             :     // js_malloc().
     419           0 :     free(p);
     420           0 : }
     421             : #endif/* JS_USE_CUSTOM_ALLOCATOR */
     422             : 
     423             : #include <new>
     424             : 
     425             : /*
     426             :  * Low-level memory management in SpiderMonkey:
     427             :  *
     428             :  *  ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these
     429             :  *     to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's
     430             :  *     these symbols.
     431             :  *
     432             :  *  ** Do not use the builtin C++ operator new and delete: these throw on
     433             :  *     error and we cannot override them not to.
     434             :  *
     435             :  * Allocation:
     436             :  *
     437             :  * - If the lifetime of the allocation is tied to the lifetime of a GC-thing
     438             :  *   (that is, finalizing the GC-thing will free the allocation), call one of
     439             :  *   the following functions:
     440             :  *
     441             :  *     JSContext::{pod_malloc,pod_calloc,pod_realloc}
     442             :  *     Zone::{pod_malloc,pod_calloc,pod_realloc}
     443             :  *
     444             :  *   These functions accumulate the number of bytes allocated which is used as
     445             :  *   part of the GC-triggering heuristics.
     446             :  *
     447             :  *   The difference between the JSContext and Zone versions is that the
     448             :  *   cx version report an out-of-memory error on OOM. (This follows from the
     449             :  *   general SpiderMonkey idiom that a JSContext-taking function reports its
     450             :  *   own errors.)
     451             :  *
     452             :  *   If you don't want to report an error on failure, there are maybe_ versions
     453             :  *   of these methods available too, e.g. maybe_pod_malloc.
     454             :  *
     455             :  *   The methods above use templates to allow allocating memory suitable for an
     456             :  *   array of a given type and number of elements. There are _with_extra
     457             :  *   versions to allow allocating an area of memory which is larger by a
     458             :  *   specified number of bytes, e.g. pod_malloc_with_extra.
     459             :  *
     460             :  *   These methods are available on a JSRuntime, but calling them is
     461             :  *   discouraged. Memory attributed to a runtime can only be reclaimed by full
     462             :  *   GCs, and we try to avoid those where possible.
     463             :  *
     464             :  * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new
     465             :  *
     466             :  * Deallocation:
     467             :  *
     468             :  * - Ordinarily, use js_free/js_delete.
     469             :  *
     470             :  * - For deallocations during GC finalization, use one of the following
     471             :  *   operations on the FreeOp provided to the finalizer:
     472             :  *
     473             :  *     FreeOp::{free_,delete_}
     474             :  */
     475             : 
     476             : /*
     477             :  * Given a class which should provide a 'new' method, add
     478             :  * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
     479             :  *
     480             :  * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
     481             :  * or the build will break.
     482             :  */
     483             : #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
     484             :     template <class T, typename... Args> \
     485             :     QUALIFIERS T * \
     486             :     NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
     487             :         void* memory = ALLOCATOR(sizeof(T)); \
     488             :         return MOZ_LIKELY(memory) \
     489             :             ? new(memory) T(std::forward<Args>(args)...) \
     490             :             : nullptr; \
     491             :     }
     492             : 
     493             : /*
     494             :  * Given a class which should provide 'make' methods, add
     495             :  * JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example).  This
     496             :  * method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares
     497             :  * methods that return mozilla::UniquePtr instances that will singly-manage
     498             :  * ownership of the created object.
     499             :  *
     500             :  * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS,
     501             :  * or the build will break.
     502             :  */
     503             : #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS)\
     504             :     template <class T, typename... Args> \
     505             :     QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
     506             :     MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
     507             :         T* ptr = NEWNAME<T>(std::forward<Args>(args)...); \
     508             :         return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
     509             :     }
     510             : 
     511       12812 : JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
     512             : 
     513             : namespace js {
     514             : 
     515             : /*
     516             :  * Calculate the number of bytes needed to allocate |numElems| contiguous
     517             :  * instances of type |T|.  Return false if the calculation overflowed.
     518             :  */
     519             : template <typename T>
     520             : MOZ_MUST_USE inline bool
     521             : CalculateAllocSize(size_t numElems, size_t* bytesOut)
     522             : {
     523      408931 :     *bytesOut = numElems * sizeof(T);
     524      204458 :     return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0;
     525             : }
     526             : 
     527             : /*
     528             :  * Calculate the number of bytes needed to allocate a single instance of type
     529             :  * |T| followed by |numExtra| contiguous instances of type |Extra|.  Return
     530             :  * false if the calculation overflowed.
     531             :  */
     532             : template <typename T, typename Extra>
     533             : MOZ_MUST_USE inline bool
     534             : CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut)
     535             : {
     536         976 :     *bytesOut = sizeof(T) + numExtra * sizeof(Extra);
     537         124 :     return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 &&
     538             :            *bytesOut >= sizeof(T);
     539             : }
     540             : 
     541             : } /* namespace js */
     542             : 
     543             : template <class T>
     544             : static MOZ_ALWAYS_INLINE void
     545        1519 : js_delete(const T* p)
     546             : {
     547       18437 :     if (p) {
     548           0 :         p->~T();
     549             :         js_free(const_cast<T*>(p));
     550             :     }
     551           0 : }
     552             : 
     553             : template<class T>
     554             : static MOZ_ALWAYS_INLINE void
     555           0 : js_delete_poison(const T* p)
     556             : {
     557           0 :     if (p) {
     558           0 :         p->~T();
     559           0 :         memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T));
     560             :         js_free(const_cast<T*>(p));
     561             :     }
     562           0 : }
     563             : 
     564             : template <class T>
     565             : static MOZ_ALWAYS_INLINE T*
     566             : js_pod_malloc()
     567             : {
     568             :     return static_cast<T*>(js_malloc(sizeof(T)));
     569             : }
     570             : 
     571             : template <class T>
     572             : static MOZ_ALWAYS_INLINE T*
     573             : js_pod_calloc()
     574             : {
     575             :     return static_cast<T*>(js_calloc(sizeof(T)));
     576             : }
     577             : 
     578             : template <class T>
     579             : static MOZ_ALWAYS_INLINE T*
     580        2050 : js_pod_malloc(size_t numElems)
     581             : {
     582             :     size_t bytes;
     583      262165 :     if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
     584             :         return nullptr;
     585      262165 :     return static_cast<T*>(js_malloc(bytes));
     586             : }
     587             : 
     588             : template <class T>
     589             : static MOZ_ALWAYS_INLINE T*
     590             : js_pod_calloc(size_t numElems)
     591             : {
     592             :     size_t bytes;
     593           0 :     if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
     594             :         return nullptr;
     595           0 :     return static_cast<T*>(js_calloc(bytes));
     596             : }
     597             : 
     598             : template <class T>
     599             : static MOZ_ALWAYS_INLINE T*
     600       13449 : js_pod_realloc(T* prior, size_t oldSize, size_t newSize)
     601             : {
     602       13449 :     MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
     603             :     size_t bytes;
     604       56869 :     if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes)))
     605             :         return nullptr;
     606       56869 :     return static_cast<T*>(js_realloc(prior, bytes));
     607             : }
     608             : 
     609             : namespace js {
     610             : 
     611             : template<typename T>
     612             : struct ScopedFreePtrTraits
     613             : {
     614             :     typedef T* type;
     615             :     static T* empty() { return nullptr; }
     616           0 :     static void release(T* ptr) { js_free(ptr); }
     617             : };
     618           0 : SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
     619             : 
     620             : template <typename T>
     621             : struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
     622             : {
     623         378 :     static void release(T* ptr) { js_delete(ptr); }
     624             : };
     625        1230 : SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits)
     626             : 
     627             : template <typename T>
     628             : struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T>
     629             : {
     630             :     static void release(T* ptr) { if (ptr) ptr->release(); }
     631             : };
     632             : SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
     633             : 
     634             : } /* namespace js */
     635             : 
     636             : namespace JS {
     637             : 
     638             : template<typename T>
     639             : struct DeletePolicy
     640             : {
     641           0 :     constexpr DeletePolicy() {}
     642             : 
     643             :     template<typename U>
     644             :     MOZ_IMPLICIT DeletePolicy(DeletePolicy<U> other,
     645             :                               typename mozilla::EnableIf<mozilla::IsConvertible<U*, T*>::value,
     646             :                                                          int>::Type dummy = 0)
     647             :     {}
     648             : 
     649        1195 :     void operator()(const T* ptr) {
     650           0 :         js_delete(const_cast<T*>(ptr));
     651        1195 :     }
     652             : };
     653             : 
     654             : struct FreePolicy
     655             : {
     656             :     void operator()(const void* ptr) {
     657       26285 :         js_free(const_cast<void*>(ptr));
     658             :     }
     659             : };
     660             : 
     661             : typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
     662             : typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
     663             : 
     664             : } // namespace JS
     665             : 
     666             : namespace js {
     667             : 
     668             : /* Integral types for all hash functions. */
     669             : typedef uint32_t HashNumber;
     670             : const unsigned HashNumberSizeBits = 32;
     671             : 
     672             : namespace detail {
     673             : 
     674             : /*
     675             :  * Given a raw hash code, h, return a number that can be used to select a hash
     676             :  * bucket.
     677             :  *
     678             :  * This function aims to produce as uniform an output distribution as possible,
     679             :  * especially in the most significant (leftmost) bits, even though the input
     680             :  * distribution may be highly nonrandom, given the constraints that this must
     681             :  * be deterministic and quick to compute.
     682             :  *
     683             :  * Since the leftmost bits of the result are best, the hash bucket index is
     684             :  * computed by doing ScrambleHashCode(h) / (2^32/N) or the equivalent
     685             :  * right-shift, not ScrambleHashCode(h) % N or the equivalent bit-mask.
     686             :  *
     687             :  * FIXME: OrderedHashTable uses a bit-mask; see bug 775896.
     688             :  */
     689             : inline HashNumber
     690             : ScrambleHashCode(HashNumber h)
     691             : {
     692             :     /*
     693             :      * Simply returning h would not cause any hash tables to produce wrong
     694             :      * answers. But it can produce pathologically bad performance: The caller
     695             :      * right-shifts the result, keeping only the highest bits. The high bits of
     696             :      * hash codes are very often completely entropy-free. (So are the lowest
     697             :      * bits.)
     698             :      *
     699             :      * So we use Fibonacci hashing, as described in Knuth, The Art of Computer
     700             :      * Programming, 6.4. This mixes all the bits of the input hash code h.
     701             :      *
     702             :      * The value of goldenRatio is taken from the hex
     703             :      * expansion of the golden ratio, which starts 1.9E3779B9....
     704             :      * This value is especially good if values with consecutive hash codes
     705             :      * are stored in a hash table; see Knuth for details.
     706             :      */
     707             :     static const HashNumber goldenRatio = 0x9E3779B9U;
     708             :     return mozilla::WrappingMultiply(h, goldenRatio);
     709             : }
     710             : 
     711             : } /* namespace detail */
     712             : 
     713             : } /* namespace js */
     714             : 
     715             : /* sixgill annotation defines */
     716             : #ifndef HAVE_STATIC_ANNOTATIONS
     717             : # define HAVE_STATIC_ANNOTATIONS
     718             : # ifdef XGILL_PLUGIN
     719             : #  define STATIC_PRECONDITION(COND)         __attribute__((precondition(#COND)))
     720             : #  define STATIC_PRECONDITION_ASSUME(COND)  __attribute__((precondition_assume(#COND)))
     721             : #  define STATIC_POSTCONDITION(COND)        __attribute__((postcondition(#COND)))
     722             : #  define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
     723             : #  define STATIC_INVARIANT(COND)            __attribute__((invariant(#COND)))
     724             : #  define STATIC_INVARIANT_ASSUME(COND)     __attribute__((invariant_assume(#COND)))
     725             : #  define STATIC_ASSUME(COND)                        \
     726             :   JS_BEGIN_MACRO                                     \
     727             :     __attribute__((assume_static(#COND), unused))    \
     728             :     int STATIC_PASTE1(assume_static_, __COUNTER__);  \
     729             :   JS_END_MACRO
     730             : # else /* XGILL_PLUGIN */
     731             : #  define STATIC_PRECONDITION(COND)          /* nothing */
     732             : #  define STATIC_PRECONDITION_ASSUME(COND)   /* nothing */
     733             : #  define STATIC_POSTCONDITION(COND)         /* nothing */
     734             : #  define STATIC_POSTCONDITION_ASSUME(COND)  /* nothing */
     735             : #  define STATIC_INVARIANT(COND)             /* nothing */
     736             : #  define STATIC_INVARIANT_ASSUME(COND)      /* nothing */
     737             : #  define STATIC_ASSUME(COND)          JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
     738             : # endif /* XGILL_PLUGIN */
     739             : # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
     740             : #endif /* HAVE_STATIC_ANNOTATIONS */
     741             : 
     742             : #endif /* js_Utility_h */

Generated by: LCOV version 1.13-14-ga5dd952