123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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/. */
- #ifndef js_Utility_h
- #define js_Utility_h
- #include "mozilla/Assertions.h"
- #include "mozilla/Atomics.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/Compiler.h"
- #include "mozilla/Move.h"
- #include "mozilla/Scoped.h"
- #include "mozilla/TemplateLib.h"
- #include "mozilla/UniquePtr.h"
- #include <stdlib.h>
- #include <string.h>
- #ifdef JS_OOM_DO_BACKTRACES
- #include <execinfo.h>
- #include <stdio.h>
- #endif
- #include "jstypes.h"
- /* The public JS engine namespace. */
- namespace JS {}
- /* The mozilla-shared reusable template/utility namespace. */
- namespace mozilla {}
- /* The private JS engine namespace. */
- namespace js {}
- #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT")
- #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF")
- extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API(void)
- JS_Assert(const char* s, const char* file, int ln);
- /*
- * Custom allocator support for SpiderMonkey
- */
- #if defined JS_USE_CUSTOM_ALLOCATOR
- # include "jscustomallocator.h"
- #else
- namespace js {
- namespace oom {
- /*
- * To make testing OOM in certain helper threads more effective,
- * allow restricting the OOM testing to a certain helper thread
- * type. This allows us to fail e.g. in off-thread script parsing
- * without causing an OOM in the main thread first.
- */
- enum ThreadType {
- THREAD_TYPE_NONE = 0, // 0
- THREAD_TYPE_MAIN, // 1
- THREAD_TYPE_ASMJS, // 2
- THREAD_TYPE_ION, // 3
- THREAD_TYPE_PARSE, // 4
- THREAD_TYPE_COMPRESS, // 5
- THREAD_TYPE_GCHELPER, // 6
- THREAD_TYPE_GCPARALLEL, // 7
- THREAD_TYPE_PROMISE_TASK, // 8
- THREAD_TYPE_MAX // Used to check shell function arguments
- };
- /*
- * Getter/Setter functions to encapsulate mozilla::ThreadLocal,
- * implementation is in jsutil.cpp.
- */
- # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
- extern bool InitThreadType(void);
- extern void SetThreadType(ThreadType);
- extern JS_FRIEND_API(uint32_t) GetThreadType(void);
- # else
- inline bool InitThreadType(void) { return true; }
- inline void SetThreadType(ThreadType t) {};
- inline uint32_t GetThreadType(void) { return 0; }
- # endif
- } /* namespace oom */
- } /* namespace js */
- # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
- #ifdef JS_OOM_BREAKPOINT
- static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
- #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint()
- #else
- #define JS_OOM_CALL_BP_FUNC() do {} while(0)
- #endif
- namespace js {
- namespace oom {
- /*
- * Out of memory testing support. We provide various testing functions to
- * simulate OOM conditions and so we can test that they are handled correctly.
- */
- extern JS_PUBLIC_DATA(uint32_t) targetThread;
- extern JS_PUBLIC_DATA(uint64_t) maxAllocations;
- extern JS_PUBLIC_DATA(uint64_t) counter;
- extern JS_PUBLIC_DATA(bool) failAlways;
- extern void
- SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always);
- extern void
- ResetSimulatedOOM();
- inline bool
- IsThreadSimulatingOOM()
- {
- return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType();
- }
- inline bool
- IsSimulatedOOMAllocation()
- {
- return IsThreadSimulatingOOM() &&
- (counter == maxAllocations || (counter > maxAllocations && failAlways));
- }
- inline bool
- ShouldFailWithOOM()
- {
- if (!IsThreadSimulatingOOM())
- return false;
- counter++;
- if (IsSimulatedOOMAllocation()) {
- JS_OOM_CALL_BP_FUNC();
- return true;
- }
- return false;
- }
- inline bool
- HadSimulatedOOM() {
- return counter >= maxAllocations;
- }
- } /* namespace oom */
- } /* namespace js */
- # define JS_OOM_POSSIBLY_FAIL() \
- do { \
- if (js::oom::ShouldFailWithOOM()) \
- return nullptr; \
- } while (0)
- # define JS_OOM_POSSIBLY_FAIL_BOOL() \
- do { \
- if (js::oom::ShouldFailWithOOM()) \
- return false; \
- } while (0)
- # else
- # define JS_OOM_POSSIBLY_FAIL() do {} while(0)
- # define JS_OOM_POSSIBLY_FAIL_BOOL() do {} while(0)
- namespace js {
- namespace oom {
- static inline bool IsSimulatedOOMAllocation() { return false; }
- static inline bool ShouldFailWithOOM() { return false; }
- } /* namespace oom */
- } /* namespace js */
- # endif /* DEBUG || JS_OOM_BREAKPOINT */
- namespace js {
- /* Disable OOM testing in sections which are not OOM safe. */
- struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion)
- {
- MOZ_NORETURN MOZ_COLD void crash(const char* reason);
- MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason);
- using AnnotateOOMAllocationSizeCallback = void(*)(size_t);
- static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback;
- static void setAnnotateOOMAllocationSizeCallback(AnnotateOOMAllocationSizeCallback callback) {
- annotateOOMSizeCallback = callback;
- }
- #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
- AutoEnterOOMUnsafeRegion()
- : oomEnabled_(oom::IsThreadSimulatingOOM() && oom::maxAllocations != UINT64_MAX),
- oomAfter_(0)
- {
- if (oomEnabled_) {
- MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this));
- oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter);
- oom::maxAllocations = UINT64_MAX;
- }
- }
- ~AutoEnterOOMUnsafeRegion() {
- if (oomEnabled_) {
- MOZ_ASSERT(oom::maxAllocations == UINT64_MAX);
- int64_t maxAllocations = int64_t(oom::counter) + oomAfter_;
- MOZ_ASSERT(maxAllocations >= 0,
- "alloc count + oom limit exceeds range, your oom limit is probably too large");
- oom::maxAllocations = uint64_t(maxAllocations);
- MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr));
- }
- }
- private:
- // Used to catch concurrent use from other threads.
- static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_;
- bool oomEnabled_;
- int64_t oomAfter_;
- #endif
- };
- } /* namespace js */
- static inline void* js_malloc(size_t bytes)
- {
- JS_OOM_POSSIBLY_FAIL();
- return malloc(bytes);
- }
- static inline void* js_calloc(size_t bytes)
- {
- JS_OOM_POSSIBLY_FAIL();
- return calloc(bytes, 1);
- }
- static inline void* js_calloc(size_t nmemb, size_t size)
- {
- JS_OOM_POSSIBLY_FAIL();
- return calloc(nmemb, size);
- }
- static inline void* js_realloc(void* p, size_t bytes)
- {
- // realloc() with zero size is not portable, as some implementations may
- // return nullptr on success and free |p| for this. We assume nullptr
- // indicates failure and that |p| is still valid.
- MOZ_ASSERT(bytes != 0);
- JS_OOM_POSSIBLY_FAIL();
- return realloc(p, bytes);
- }
- static inline void js_free(void* p)
- {
- free(p);
- }
- static inline char* js_strdup(const char* s)
- {
- JS_OOM_POSSIBLY_FAIL();
- return strdup(s);
- }
- #endif/* JS_USE_CUSTOM_ALLOCATOR */
- #include <new>
- /*
- * Low-level memory management in SpiderMonkey:
- *
- * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these
- * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's
- * these symbols.
- *
- * ** Do not use the builtin C++ operator new and delete: these throw on
- * error and we cannot override them not to.
- *
- * Allocation:
- *
- * - If the lifetime of the allocation is tied to the lifetime of a GC-thing
- * (that is, finalizing the GC-thing will free the allocation), call one of
- * the following functions:
- *
- * JSContext::{malloc_,realloc_,calloc_,new_}
- * JSRuntime::{malloc_,realloc_,calloc_,new_}
- *
- * These functions accumulate the number of bytes allocated which is used as
- * part of the GC-triggering heuristic.
- *
- * The difference between the JSContext and JSRuntime versions is that the
- * cx version reports an out-of-memory error on OOM. (This follows from the
- * general SpiderMonkey idiom that a JSContext-taking function reports its
- * own errors.)
- *
- * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new
- *
- * Deallocation:
- *
- * - Ordinarily, use js_free/js_delete.
- *
- * - For deallocations during GC finalization, use one of the following
- * operations on the FreeOp provided to the finalizer:
- *
- * FreeOp::{free_,delete_}
- *
- * The advantage of these operations is that the memory is batched and freed
- * on another thread.
- */
- /*
- * Given a class which should provide a 'new' method, add
- * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
- *
- * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
- * or the build will break.
- */
- #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
- template <class T, typename... Args> \
- QUALIFIERS T * \
- NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
- void* memory = ALLOCATOR(sizeof(T)); \
- return MOZ_LIKELY(memory) \
- ? new(memory) T(mozilla::Forward<Args>(args)...) \
- : nullptr; \
- }
- /*
- * Given a class which should provide 'make' methods, add
- * JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This
- * method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares
- * methods that return mozilla::UniquePtr instances that will singly-manage
- * ownership of the created object.
- *
- * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS,
- * or the build will break.
- */
- #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS)\
- template <class T, typename... Args> \
- QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
- MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
- T* ptr = NEWNAME<T>(mozilla::Forward<Args>(args)...); \
- return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
- }
- JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
- namespace js {
- /*
- * Calculate the number of bytes needed to allocate |numElems| contiguous
- * instances of type |T|. Return false if the calculation overflowed.
- */
- template <typename T>
- MOZ_MUST_USE inline bool
- CalculateAllocSize(size_t numElems, size_t* bytesOut)
- {
- *bytesOut = numElems * sizeof(T);
- return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0;
- }
- /*
- * Calculate the number of bytes needed to allocate a single instance of type
- * |T| followed by |numExtra| contiguous instances of type |Extra|. Return
- * false if the calculation overflowed.
- */
- template <typename T, typename Extra>
- MOZ_MUST_USE inline bool
- CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut)
- {
- *bytesOut = sizeof(T) + numExtra * sizeof(Extra);
- return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 &&
- *bytesOut >= sizeof(T);
- }
- } /* namespace js */
- template <class T>
- static MOZ_ALWAYS_INLINE void
- js_delete(const T* p)
- {
- if (p) {
- p->~T();
- js_free(const_cast<T*>(p));
- }
- }
- template<class T>
- static MOZ_ALWAYS_INLINE void
- js_delete_poison(const T* p)
- {
- if (p) {
- p->~T();
- memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T));
- js_free(const_cast<T*>(p));
- }
- }
- template <class T>
- static MOZ_ALWAYS_INLINE T*
- js_pod_malloc()
- {
- return static_cast<T*>(js_malloc(sizeof(T)));
- }
- template <class T>
- static MOZ_ALWAYS_INLINE T*
- js_pod_calloc()
- {
- return static_cast<T*>(js_calloc(sizeof(T)));
- }
- template <class T>
- static MOZ_ALWAYS_INLINE T*
- js_pod_malloc(size_t numElems)
- {
- size_t bytes;
- if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
- return nullptr;
- return static_cast<T*>(js_malloc(bytes));
- }
- template <class T>
- static MOZ_ALWAYS_INLINE T*
- js_pod_calloc(size_t numElems)
- {
- size_t bytes;
- if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
- return nullptr;
- return static_cast<T*>(js_calloc(bytes));
- }
- template <class T>
- static MOZ_ALWAYS_INLINE T*
- js_pod_realloc(T* prior, size_t oldSize, size_t newSize)
- {
- MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
- size_t bytes;
- if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes)))
- return nullptr;
- return static_cast<T*>(js_realloc(prior, bytes));
- }
- namespace js {
- template<typename T>
- struct ScopedFreePtrTraits
- {
- typedef T* type;
- static T* empty() { return nullptr; }
- static void release(T* ptr) { js_free(ptr); }
- };
- SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
- template <typename T>
- struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
- {
- static void release(T* ptr) { js_delete(ptr); }
- };
- SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits)
- template <typename T>
- struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T>
- {
- static void release(T* ptr) { if (ptr) ptr->release(); }
- };
- SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
- } /* namespace js */
- namespace JS {
- template<typename T>
- struct DeletePolicy
- {
- constexpr DeletePolicy() {}
- template<typename U>
- MOZ_IMPLICIT DeletePolicy(DeletePolicy<U> other,
- typename mozilla::EnableIf<mozilla::IsConvertible<U*, T*>::value,
- int>::Type dummy = 0)
- {}
- void operator()(const T* ptr) {
- js_delete(const_cast<T*>(ptr));
- }
- };
- struct FreePolicy
- {
- void operator()(const void* ptr) {
- js_free(const_cast<void*>(ptr));
- }
- };
- typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
- typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
- } // namespace JS
- namespace js {
- /* Integral types for all hash functions. */
- typedef uint32_t HashNumber;
- const unsigned HashNumberSizeBits = 32;
- namespace detail {
- /*
- * Given a raw hash code, h, return a number that can be used to select a hash
- * bucket.
- *
- * This function aims to produce as uniform an output distribution as possible,
- * especially in the most significant (leftmost) bits, even though the input
- * distribution may be highly nonrandom, given the constraints that this must
- * be deterministic and quick to compute.
- *
- * Since the leftmost bits of the result are best, the hash bucket index is
- * computed by doing ScrambleHashCode(h) / (2^32/N) or the equivalent
- * right-shift, not ScrambleHashCode(h) % N or the equivalent bit-mask.
- *
- * FIXME: OrderedHashTable uses a bit-mask; see bug 775896.
- */
- inline HashNumber
- ScrambleHashCode(HashNumber h)
- {
- /*
- * Simply returning h would not cause any hash tables to produce wrong
- * answers. But it can produce pathologically bad performance: The caller
- * right-shifts the result, keeping only the highest bits. The high bits of
- * hash codes are very often completely entropy-free. (So are the lowest
- * bits.)
- *
- * So we use Fibonacci hashing, as described in Knuth, The Art of Computer
- * Programming, 6.4. This mixes all the bits of the input hash code h.
- *
- * The value of goldenRatio is taken from the hex
- * expansion of the golden ratio, which starts 1.9E3779B9....
- * This value is especially good if values with consecutive hash codes
- * are stored in a hash table; see Knuth for details.
- */
- static const HashNumber goldenRatio = 0x9E3779B9U;
- return h * goldenRatio;
- }
- } /* namespace detail */
- } /* namespace js */
- /* sixgill annotation defines */
- #ifndef HAVE_STATIC_ANNOTATIONS
- # define HAVE_STATIC_ANNOTATIONS
- # ifdef XGILL_PLUGIN
- # define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND)))
- # define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND)))
- # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND)))
- # define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
- # define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
- # define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND)))
- # define STATIC_ASSUME(COND) \
- JS_BEGIN_MACRO \
- __attribute__((assume_static(#COND), unused)) \
- int STATIC_PASTE1(assume_static_, __COUNTER__); \
- JS_END_MACRO
- # else /* XGILL_PLUGIN */
- # define STATIC_PRECONDITION(COND) /* nothing */
- # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
- # define STATIC_POSTCONDITION(COND) /* nothing */
- # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
- # define STATIC_INVARIANT(COND) /* nothing */
- # define STATIC_INVARIANT_ASSUME(COND) /* nothing */
- # define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
- # endif /* XGILL_PLUGIN */
- # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
- #endif /* HAVE_STATIC_ANNOTATIONS */
- #endif /* js_Utility_h */
|