Changeset View
Changeset View
Standalone View
Standalone View
libraries/source/spidermonkey/include-win32-debug/js/Utility.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | * vim: set ts=8 sts=4 et sw=4 tw=99: | ||||
* This Source Code Form is subject to the terms of the Mozilla Public | * 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 | * 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/. */ | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
#ifndef js_Utility_h | #ifndef js_Utility_h | ||||
#define js_Utility_h | #define js_Utility_h | ||||
#include "mozilla/Assertions.h" | #include "mozilla/Assertions.h" | ||||
#include "mozilla/Atomics.h" | |||||
#include "mozilla/Attributes.h" | #include "mozilla/Attributes.h" | ||||
#include "mozilla/Compiler.h" | #include "mozilla/Compiler.h" | ||||
#include "mozilla/Move.h" | #include "mozilla/Move.h" | ||||
#include "mozilla/Scoped.h" | #include "mozilla/Scoped.h" | ||||
#include "mozilla/TemplateLib.h" | #include "mozilla/TemplateLib.h" | ||||
#include "mozilla/UniquePtr.h" | #include "mozilla/UniquePtr.h" | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
Show All 10 Lines | |||||
namespace JS {} | namespace JS {} | ||||
/* The mozilla-shared reusable template/utility namespace. */ | /* The mozilla-shared reusable template/utility namespace. */ | ||||
namespace mozilla {} | namespace mozilla {} | ||||
/* The private JS engine namespace. */ | /* The private JS engine namespace. */ | ||||
namespace js {} | namespace js {} | ||||
/* | |||||
* 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. | |||||
*/ | |||||
#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_EMPTY_STOREBUFFER_PATTERN 0x1B | |||||
#define JS_SWEPT_CODE_PATTERN 0x3B | |||||
#define JS_SWEPT_FRAME_PATTERN 0x5B | |||||
#define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT") | #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") | #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) | extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API(void) | ||||
JS_Assert(const char* s, const char* file, int ln); | JS_Assert(const char* s, const char* file, int ln); | ||||
/* | /* | ||||
* Custom allocator support for SpiderMonkey | * Custom allocator support for SpiderMonkey | ||||
Show All 15 Lines | enum ThreadType { | ||||
THREAD_TYPE_NONE = 0, // 0 | THREAD_TYPE_NONE = 0, // 0 | ||||
THREAD_TYPE_MAIN, // 1 | THREAD_TYPE_MAIN, // 1 | ||||
THREAD_TYPE_ASMJS, // 2 | THREAD_TYPE_ASMJS, // 2 | ||||
THREAD_TYPE_ION, // 3 | THREAD_TYPE_ION, // 3 | ||||
THREAD_TYPE_PARSE, // 4 | THREAD_TYPE_PARSE, // 4 | ||||
THREAD_TYPE_COMPRESS, // 5 | THREAD_TYPE_COMPRESS, // 5 | ||||
THREAD_TYPE_GCHELPER, // 6 | THREAD_TYPE_GCHELPER, // 6 | ||||
THREAD_TYPE_GCPARALLEL, // 7 | THREAD_TYPE_GCPARALLEL, // 7 | ||||
THREAD_TYPE_PROMISE_TASK, // 8 | |||||
THREAD_TYPE_MAX // Used to check shell function arguments | THREAD_TYPE_MAX // Used to check shell function arguments | ||||
}; | }; | ||||
/* | /* | ||||
* Getter/Setter functions to encapsulate mozilla::ThreadLocal, | * Getter/Setter functions to encapsulate mozilla::ThreadLocal, | ||||
* implementation is in jsutil.cpp. | * implementation is in jsutil.cpp. | ||||
*/ | */ | ||||
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | ||||
extern bool InitThreadType(void); | extern bool InitThreadType(void); | ||||
extern void SetThreadType(ThreadType); | extern void SetThreadType(ThreadType); | ||||
extern JS_FRIEND_API(uint32_t) GetThreadType(void); | extern JS_FRIEND_API(uint32_t) GetThreadType(void); | ||||
# else | # else | ||||
inline bool InitThreadType(void) { return true; } | inline bool InitThreadType(void) { return true; } | ||||
inline void SetThreadType(ThreadType t) {}; | inline void SetThreadType(ThreadType t) {}; | ||||
inline uint32_t GetThreadType(void) { return 0; } | inline uint32_t GetThreadType(void) { return 0; } | ||||
# endif | # endif | ||||
} /* namespace oom */ | } /* namespace oom */ | ||||
} /* namespace js */ | } /* namespace js */ | ||||
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | ||||
/* | |||||
* In order to test OOM conditions, when the testing function | |||||
* oomAfterAllocations COUNT is passed, we fail continuously after the NUM'th | |||||
* allocation from now. | |||||
*/ | |||||
extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set in builtin/TestingFunctions.cpp */ | |||||
extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */ | |||||
extern JS_PUBLIC_DATA(bool) OOM_failAlways; | |||||
#ifdef JS_OOM_BREAKPOINT | #ifdef JS_OOM_BREAKPOINT | ||||
static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } | static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } | ||||
#define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() | #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() | ||||
#else | #else | ||||
#define JS_OOM_CALL_BP_FUNC() do {} while(0) | #define JS_OOM_CALL_BP_FUNC() do {} while(0) | ||||
#endif | #endif | ||||
namespace js { | namespace js { | ||||
namespace oom { | 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(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(); | |||||
static inline bool | inline bool | ||||
IsThreadSimulatingOOM() | IsThreadSimulatingOOM() | ||||
{ | { | ||||
return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType(); | return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType(); | ||||
} | } | ||||
static inline bool | inline bool | ||||
IsSimulatedOOMAllocation() | IsSimulatedOOMAllocation() | ||||
{ | { | ||||
return IsThreadSimulatingOOM() && (OOM_counter == OOM_maxAllocations || | return IsThreadSimulatingOOM() && | ||||
(OOM_counter > OOM_maxAllocations && OOM_failAlways)); | (counter == maxAllocations || (counter > maxAllocations && failAlways)); | ||||
} | } | ||||
static inline bool | inline bool | ||||
ShouldFailWithOOM() | ShouldFailWithOOM() | ||||
{ | { | ||||
if (!IsThreadSimulatingOOM()) | if (!IsThreadSimulatingOOM()) | ||||
return false; | return false; | ||||
OOM_counter++; | counter++; | ||||
if (IsSimulatedOOMAllocation()) { | if (IsSimulatedOOMAllocation()) { | ||||
JS_OOM_CALL_BP_FUNC(); | JS_OOM_CALL_BP_FUNC(); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
inline bool | |||||
HadSimulatedOOM() { | |||||
return counter >= maxAllocations; | |||||
} | |||||
} /* namespace oom */ | } /* namespace oom */ | ||||
} /* namespace js */ | } /* namespace js */ | ||||
# define JS_OOM_POSSIBLY_FAIL() \ | # define JS_OOM_POSSIBLY_FAIL() \ | ||||
do { \ | do { \ | ||||
if (js::oom::ShouldFailWithOOM()) \ | if (js::oom::ShouldFailWithOOM()) \ | ||||
return nullptr; \ | return nullptr; \ | ||||
} while (0) | } while (0) | ||||
Show All 15 Lines | |||||
} /* namespace oom */ | } /* namespace oom */ | ||||
} /* namespace js */ | } /* namespace js */ | ||||
# endif /* DEBUG || JS_OOM_BREAKPOINT */ | # endif /* DEBUG || JS_OOM_BREAKPOINT */ | ||||
namespace js { | namespace js { | ||||
/* Disable OOM testing in sections which are not OOM safe. */ | /* Disable OOM testing in sections which are not OOM safe. */ | ||||
struct MOZ_RAII AutoEnterOOMUnsafeRegion | struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion) | ||||
{ | { | ||||
MOZ_NORETURN MOZ_COLD void crash(const char* reason); | 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) | #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | ||||
AutoEnterOOMUnsafeRegion() | AutoEnterOOMUnsafeRegion() | ||||
: oomEnabled_(oom::IsThreadSimulatingOOM() && OOM_maxAllocations != UINT32_MAX), | : oomEnabled_(oom::IsThreadSimulatingOOM() && oom::maxAllocations != UINT64_MAX), | ||||
oomAfter_(0) | oomAfter_(0) | ||||
{ | { | ||||
if (oomEnabled_) { | if (oomEnabled_) { | ||||
oomAfter_ = int64_t(OOM_maxAllocations) - OOM_counter; | MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this)); | ||||
OOM_maxAllocations = UINT32_MAX; | oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter); | ||||
oom::maxAllocations = UINT64_MAX; | |||||
} | } | ||||
} | } | ||||
~AutoEnterOOMUnsafeRegion() { | ~AutoEnterOOMUnsafeRegion() { | ||||
if (oomEnabled_) { | if (oomEnabled_) { | ||||
MOZ_ASSERT(OOM_maxAllocations == UINT32_MAX); | MOZ_ASSERT(oom::maxAllocations == UINT64_MAX); | ||||
int64_t maxAllocations = OOM_counter + oomAfter_; | int64_t maxAllocations = int64_t(oom::counter) + oomAfter_; | ||||
MOZ_ASSERT(maxAllocations >= 0 && maxAllocations < UINT32_MAX, | MOZ_ASSERT(maxAllocations >= 0, | ||||
"alloc count + oom limit exceeds range, your oom limit is probably too large"); | "alloc count + oom limit exceeds range, your oom limit is probably too large"); | ||||
OOM_maxAllocations = uint32_t(maxAllocations); | oom::maxAllocations = uint64_t(maxAllocations); | ||||
MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); | |||||
} | } | ||||
} | } | ||||
private: | private: | ||||
// Used to catch concurrent use from other threads. | |||||
static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_; | |||||
bool oomEnabled_; | bool oomEnabled_; | ||||
int64_t oomAfter_; | int64_t oomAfter_; | ||||
#endif | #endif | ||||
}; | }; | ||||
} /* namespace js */ | } /* namespace js */ | ||||
static inline void* js_malloc(size_t bytes) | static inline void* js_malloc(size_t bytes) | ||||
Show All 11 Lines | |||||
static inline void* js_calloc(size_t nmemb, size_t size) | static inline void* js_calloc(size_t nmemb, size_t size) | ||||
{ | { | ||||
JS_OOM_POSSIBLY_FAIL(); | JS_OOM_POSSIBLY_FAIL(); | ||||
return calloc(nmemb, size); | return calloc(nmemb, size); | ||||
} | } | ||||
static inline void* js_realloc(void* p, size_t bytes) | 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(); | JS_OOM_POSSIBLY_FAIL(); | ||||
return realloc(p, bytes); | return realloc(p, bytes); | ||||
} | } | ||||
static inline void js_free(void* p) | static inline void js_free(void* p) | ||||
{ | { | ||||
free(p); | free(p); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Given a class which should provide a 'new' method, add | * Given a class which should provide a 'new' method, add | ||||
* JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example). | * 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, | * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS, | ||||
* or the build will break. | * or the build will break. | ||||
*/ | */ | ||||
#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS)\ | #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \ | ||||
template <class T, typename... Args> \ | template <class T, typename... Args> \ | ||||
QUALIFIERS T * \ | QUALIFIERS T * \ | ||||
NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ | NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ | ||||
void* memory = ALLOCATOR(sizeof(T)); \ | void* memory = ALLOCATOR(sizeof(T)); \ | ||||
return memory \ | return MOZ_LIKELY(memory) \ | ||||
? new(memory) T(mozilla::Forward<Args>(args)...) \ | ? new(memory) T(mozilla::Forward<Args>(args)...) \ | ||||
: nullptr; \ | : nullptr; \ | ||||
} | } | ||||
/* | /* | ||||
* Given a class which should provide 'make' methods, add | * Given a class which should provide 'make' methods, add | ||||
* JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This | * JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This | ||||
* method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares | * method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares | ||||
* methods that return mozilla::UniquePtr instances that will singly-manage | * methods that return mozilla::UniquePtr instances that will singly-manage | ||||
* ownership of the created object. | * ownership of the created object. | ||||
Show All 13 Lines | |||||
namespace js { | namespace js { | ||||
/* | /* | ||||
* Calculate the number of bytes needed to allocate |numElems| contiguous | * Calculate the number of bytes needed to allocate |numElems| contiguous | ||||
* instances of type |T|. Return false if the calculation overflowed. | * instances of type |T|. Return false if the calculation overflowed. | ||||
*/ | */ | ||||
template <typename T> | template <typename T> | ||||
MOZ_WARN_UNUSED_RESULT inline bool | MOZ_MUST_USE inline bool | ||||
CalculateAllocSize(size_t numElems, size_t* bytesOut) | CalculateAllocSize(size_t numElems, size_t* bytesOut) | ||||
{ | { | ||||
*bytesOut = numElems * sizeof(T); | *bytesOut = numElems * sizeof(T); | ||||
return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0; | return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0; | ||||
} | } | ||||
/* | /* | ||||
* Calculate the number of bytes needed to allocate a single instance of type | * Calculate the number of bytes needed to allocate a single instance of type | ||||
* |T| followed by |numExtra| contiguous instances of type |Extra|. Return | * |T| followed by |numExtra| contiguous instances of type |Extra|. Return | ||||
* false if the calculation overflowed. | * false if the calculation overflowed. | ||||
*/ | */ | ||||
template <typename T, typename Extra> | template <typename T, typename Extra> | ||||
MOZ_WARN_UNUSED_RESULT inline bool | MOZ_MUST_USE inline bool | ||||
CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut) | CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut) | ||||
{ | { | ||||
*bytesOut = sizeof(T) + numExtra * sizeof(Extra); | *bytesOut = sizeof(T) + numExtra * sizeof(Extra); | ||||
return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 && | return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 && | ||||
*bytesOut >= sizeof(T); | *bytesOut >= sizeof(T); | ||||
} | } | ||||
} /* namespace js */ | } /* namespace js */ | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
} /* namespace js */ | } /* namespace js */ | ||||
namespace JS { | namespace JS { | ||||
template<typename T> | template<typename T> | ||||
struct DeletePolicy | 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) { | void operator()(const T* ptr) { | ||||
js_delete(const_cast<T*>(ptr)); | js_delete(const_cast<T*>(ptr)); | ||||
} | } | ||||
}; | }; | ||||
struct FreePolicy | struct FreePolicy | ||||
{ | { | ||||
void operator()(const void* ptr) { | void operator()(const void* ptr) { | ||||
js_free(const_cast<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 | ||||
namespace js { | namespace js { | ||||
/* Integral types for all hash functions. */ | /* Integral types for all hash functions. */ | ||||
typedef uint32_t HashNumber; | typedef uint32_t HashNumber; | ||||
const unsigned HashNumberSizeBits = 32; | const unsigned HashNumberSizeBits = 32; | ||||
typedef mozilla::UniquePtr<char, JS::FreePolicy> UniqueChars; | |||||
static inline UniqueChars make_string_copy(const char* str) | |||||
{ | |||||
return UniqueChars(js_strdup(str)); | |||||
} | |||||
namespace detail { | namespace detail { | ||||
/* | /* | ||||
* Given a raw hash code, h, return a number that can be used to select a hash | * Given a raw hash code, h, return a number that can be used to select a hash | ||||
* bucket. | * bucket. | ||||
* | * | ||||
* This function aims to produce as uniform an output distribution as possible, | * This function aims to produce as uniform an output distribution as possible, | ||||
* especially in the most significant (leftmost) bits, even though the input | * especially in the most significant (leftmost) bits, even though the input | ||||
▲ Show 20 Lines • Show All 63 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator