Differential D3143 Diff 14286 ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Utility.h
Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/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: 2 -*- | ||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | * vim: set ts=8 sts=2 et sw=2 tw=80: | ||||
* 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/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/TemplateLib.h" | #include "mozilla/TemplateLib.h" | ||||
#include "mozilla/UniquePtr.h" | #include "mozilla/UniquePtr.h" | ||||
#include "mozilla/WrappingOperations.h" | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#ifdef JS_OOM_DO_BACKTRACES | #ifdef JS_OOM_DO_BACKTRACES | ||||
#include <execinfo.h> | # include <execinfo.h> | ||||
#include <stdio.h> | # include <stdio.h> | ||||
#endif | #endif | ||||
#include "jstypes.h" | #include "jstypes.h" | ||||
#include "mozmemory.h" | #include "mozmemory.h" | ||||
/* The public JS engine namespace. */ | /* The public JS engine namespace. */ | ||||
namespace JS {} | namespace JS {} | ||||
Show All 11 Lines | |||||
extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API void JS_Assert(const char* s, | extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API void JS_Assert(const char* s, | ||||
const char* file, | const char* file, | ||||
int ln); | int ln); | ||||
/* | /* | ||||
* Custom allocator support for SpiderMonkey | * Custom allocator support for SpiderMonkey | ||||
*/ | */ | ||||
#if defined JS_USE_CUSTOM_ALLOCATOR | #if defined JS_USE_CUSTOM_ALLOCATOR | ||||
#include "jscustomallocator.h" | # include "jscustomallocator.h" | ||||
#else | #else | ||||
namespace js { | namespace js { | ||||
/* | /* | ||||
* Thread types are used to tag threads for certain kinds of testing (see | * Thread types are used to tag threads for certain kinds of testing (see | ||||
* below), and also used to characterize threads in the thread scheduler (see | * below), and also used to characterize threads in the thread scheduler (see | ||||
* js/src/vm/HelperThreads.cpp). | * js/src/vm/HelperThreads.cpp). | ||||
* | * | ||||
* Please update oom::FirstThreadTypeToTest and oom::LastThreadTypeToTest when | * Please update oom::FirstThreadTypeToTest and oom::LastThreadTypeToTest when | ||||
* adding new thread types. | * adding new thread types. | ||||
*/ | */ | ||||
enum ThreadType { | enum ThreadType { | ||||
THREAD_TYPE_NONE = 0, // 0 | THREAD_TYPE_NONE = 0, // 0 | ||||
THREAD_TYPE_COOPERATING, // 1 | THREAD_TYPE_MAIN, // 1 | ||||
THREAD_TYPE_WASM, // 2 | THREAD_TYPE_WASM, // 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_PROMISE_TASK, // 8 | ||||
THREAD_TYPE_ION_FREE, // 9 | THREAD_TYPE_ION_FREE, // 9 | ||||
THREAD_TYPE_WASM_TIER2, // 10 | THREAD_TYPE_WASM_TIER2, // 10 | ||||
THREAD_TYPE_WORKER, // 11 | THREAD_TYPE_WORKER, // 11 | ||||
THREAD_TYPE_MAX // Used to check shell function arguments | THREAD_TYPE_MAX // Used to check shell function arguments | ||||
}; | }; | ||||
/* | |||||
* Threads need a universal way to dispatch from xpcom thread pools, | |||||
* so having objects inherit from this struct enables | |||||
* mozilla::HelperThreadPool's runnable handler to call runTask() on each type. | |||||
*/ | |||||
struct RunnableTask { | |||||
virtual void runTask() = 0; | |||||
}; | |||||
namespace oom { | namespace oom { | ||||
/* | /* | ||||
* Theads are tagged only in certain debug contexts. Notably, to make testing | * Theads are tagged only in certain debug contexts. Notably, to make testing | ||||
* OOM in certain helper threads more effective, we allow restricting the OOM | * OOM in certain helper threads more effective, we allow restricting the OOM | ||||
* testing to a certain helper thread type. This allows us to fail e.g. in | * 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 active thread first. | * off-thread script parsing without causing an OOM in the active thread first. | ||||
* | * | ||||
* Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation | * Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation | ||||
* is in jsutil.cpp. | * is in jsutil.cpp. | ||||
*/ | */ | ||||
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | ||||
// Define the range of threads tested by simulated OOM testing and the | // Define the range of threads tested by simulated OOM testing and the | ||||
// like. Testing worker threads is not supported. | // like. Testing worker threads is not supported. | ||||
const ThreadType FirstThreadTypeToTest = THREAD_TYPE_COOPERATING; | const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN; | ||||
const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_TIER2; | const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_TIER2; | ||||
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; } | ||||
inline uint32_t GetAllocationThreadType(void) { return 0; } | |||||
inline uint32_t GetStackCheckThreadType(void) { return 0; } | |||||
inline uint32_t GetInterruptCheckThreadType(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) | ||||
#ifdef JS_OOM_BREAKPOINT | # ifdef JS_OOM_BREAKPOINT | ||||
#if defined(_MSC_VER) | # if defined(_MSC_VER) | ||||
static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { | static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { | ||||
__asm {} | __asm {} | ||||
; | ; | ||||
} | } | ||||
#else | # else | ||||
static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } | static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } | ||||
#endif | # endif | ||||
#define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() | # define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() | ||||
#else | # else | ||||
#define JS_OOM_CALL_BP_FUNC() \ | # define JS_OOM_CALL_BP_FUNC() \ | ||||
do { \ | do { \ | ||||
} while (0) | } while (0) | ||||
#endif | # endif | ||||
namespace js { | namespace js { | ||||
namespace oom { | namespace oom { | ||||
/* | /* | ||||
* Out of memory testing support. We provide various testing functions to | * Out of memory testing support. We provide various testing functions to | ||||
* simulate OOM conditions and so we can test that they are handled correctly. | * simulate OOM conditions and so we can test that they are handled correctly. | ||||
*/ | */ | ||||
class FailureSimulator { | |||||
public: | |||||
enum class Kind : uint8_t { Nothing, OOM, StackOOM, Interrupt }; | |||||
extern JS_PUBLIC_DATA uint32_t targetThread; | private: | ||||
extern JS_PUBLIC_DATA uint64_t maxAllocations; | Kind kind_ = Kind::Nothing; | ||||
extern JS_PUBLIC_DATA uint64_t counter; | uint32_t targetThread_ = 0; | ||||
extern JS_PUBLIC_DATA bool failAlways; | uint64_t maxChecks_ = UINT64_MAX; | ||||
uint64_t counter_ = 0; | |||||
bool failAlways_ = true; | |||||
bool inUnsafeRegion_ = false; | |||||
public: | |||||
uint64_t maxChecks() const { return maxChecks_; } | |||||
uint64_t counter() const { return counter_; } | |||||
void setInUnsafeRegion(bool b) { | |||||
MOZ_ASSERT(inUnsafeRegion_ != b); | |||||
inUnsafeRegion_ = b; | |||||
} | |||||
uint32_t targetThread() const { return targetThread_; } | |||||
bool isThreadSimulatingAny() const { | |||||
return targetThread_ && targetThread_ == js::oom::GetThreadType() && | |||||
!inUnsafeRegion_; | |||||
} | |||||
bool isThreadSimulating(Kind kind) const { | |||||
return kind_ == kind && isThreadSimulatingAny(); | |||||
} | |||||
bool isSimulatedFailure(Kind kind) const { | |||||
if (!isThreadSimulating(kind)) { | |||||
return false; | |||||
} | |||||
return counter_ == maxChecks_ || (counter_ > maxChecks_ && failAlways_); | |||||
} | |||||
bool hadFailure(Kind kind) const { | |||||
return kind_ == kind && counter_ >= maxChecks_; | |||||
} | |||||
bool shouldFail(Kind kind) { | |||||
if (!isThreadSimulating(kind)) { | |||||
return false; | |||||
} | |||||
counter_++; | |||||
if (isSimulatedFailure(kind)) { | |||||
JS_OOM_CALL_BP_FUNC(); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
extern void SimulateOOMAfter(uint64_t allocations, uint32_t thread, | void simulateFailureAfter(Kind kind, uint64_t checks, uint32_t thread, | ||||
bool always); | bool always); | ||||
void reset(); | |||||
extern void ResetSimulatedOOM(); | }; | ||||
extern JS_PUBLIC_DATA FailureSimulator simulator; | |||||
inline bool IsThreadSimulatingOOM() { | |||||
return js::oom::targetThread && | |||||
js::oom::targetThread == js::oom::GetThreadType(); | |||||
} | |||||
inline bool IsSimulatedOOMAllocation() { | inline bool IsSimulatedOOMAllocation() { | ||||
return IsThreadSimulatingOOM() && (counter == maxAllocations || | return simulator.isSimulatedFailure(FailureSimulator::Kind::OOM); | ||||
(counter > maxAllocations && failAlways)); | |||||
} | } | ||||
inline bool ShouldFailWithOOM() { | inline bool ShouldFailWithOOM() { | ||||
if (!IsThreadSimulatingOOM()) return false; | return simulator.shouldFail(FailureSimulator::Kind::OOM); | ||||
counter++; | |||||
if (IsSimulatedOOMAllocation()) { | |||||
JS_OOM_CALL_BP_FUNC(); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | } | ||||
inline bool HadSimulatedOOM() { return counter >= maxAllocations; } | inline bool HadSimulatedOOM() { | ||||
return simulator.hadFailure(FailureSimulator::Kind::OOM); | |||||
} | |||||
/* | /* | ||||
* Out of stack space testing support, similar to OOM testing functions. | * Out of stack space testing support, similar to OOM testing functions. | ||||
*/ | */ | ||||
extern JS_PUBLIC_DATA uint32_t stackTargetThread; | |||||
extern JS_PUBLIC_DATA uint64_t maxStackChecks; | |||||
extern JS_PUBLIC_DATA uint64_t stackCheckCounter; | |||||
extern JS_PUBLIC_DATA bool stackCheckFailAlways; | |||||
extern void SimulateStackOOMAfter(uint64_t checks, uint32_t thread, | |||||
bool always); | |||||
extern void ResetSimulatedStackOOM(); | |||||
inline bool IsThreadSimulatingStackOOM() { | |||||
return js::oom::stackTargetThread && | |||||
js::oom::stackTargetThread == js::oom::GetThreadType(); | |||||
} | |||||
inline bool IsSimulatedStackOOMCheck() { | inline bool IsSimulatedStackOOMCheck() { | ||||
return IsThreadSimulatingStackOOM() && | return simulator.isSimulatedFailure(FailureSimulator::Kind::StackOOM); | ||||
(stackCheckCounter == maxStackChecks || | |||||
(stackCheckCounter > maxStackChecks && stackCheckFailAlways)); | |||||
} | } | ||||
inline bool ShouldFailWithStackOOM() { | inline bool ShouldFailWithStackOOM() { | ||||
if (!IsThreadSimulatingStackOOM()) return false; | return simulator.shouldFail(FailureSimulator::Kind::StackOOM); | ||||
stackCheckCounter++; | |||||
if (IsSimulatedStackOOMCheck()) { | |||||
JS_OOM_CALL_BP_FUNC(); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | } | ||||
inline bool HadSimulatedStackOOM() { | inline bool HadSimulatedStackOOM() { | ||||
return stackCheckCounter >= maxStackChecks; | return simulator.hadFailure(FailureSimulator::Kind::StackOOM); | ||||
} | } | ||||
/* | /* | ||||
* Interrupt testing support, similar to OOM testing functions. | * Interrupt testing support, similar to OOM testing functions. | ||||
*/ | */ | ||||
extern JS_PUBLIC_DATA uint32_t interruptTargetThread; | |||||
extern JS_PUBLIC_DATA uint64_t maxInterruptChecks; | |||||
extern JS_PUBLIC_DATA uint64_t interruptCheckCounter; | |||||
extern JS_PUBLIC_DATA bool interruptCheckFailAlways; | |||||
extern void SimulateInterruptAfter(uint64_t checks, uint32_t thread, | |||||
bool always); | |||||
extern void ResetSimulatedInterrupt(); | |||||
inline bool IsThreadSimulatingInterrupt() { | |||||
return js::oom::interruptTargetThread && | |||||
js::oom::interruptTargetThread == js::oom::GetThreadType(); | |||||
} | |||||
inline bool IsSimulatedInterruptCheck() { | inline bool IsSimulatedInterruptCheck() { | ||||
return IsThreadSimulatingInterrupt() && | return simulator.isSimulatedFailure(FailureSimulator::Kind::Interrupt); | ||||
(interruptCheckCounter == maxInterruptChecks || | |||||
(interruptCheckCounter > maxInterruptChecks && | |||||
interruptCheckFailAlways)); | |||||
} | } | ||||
inline bool ShouldFailWithInterrupt() { | inline bool ShouldFailWithInterrupt() { | ||||
if (!IsThreadSimulatingInterrupt()) return false; | return simulator.shouldFail(FailureSimulator::Kind::Interrupt); | ||||
interruptCheckCounter++; | |||||
if (IsSimulatedInterruptCheck()) { | |||||
JS_OOM_CALL_BP_FUNC(); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | } | ||||
inline bool HadSimulatedInterrupt() { | inline bool HadSimulatedInterrupt() { | ||||
return interruptCheckCounter >= maxInterruptChecks; | return simulator.hadFailure(FailureSimulator::Kind::Interrupt); | ||||
} | } | ||||
} /* namespace oom */ | } /* namespace oom */ | ||||
} /* namespace js */ | } /* namespace js */ | ||||
#define JS_OOM_POSSIBLY_FAIL() \ | # define JS_OOM_POSSIBLY_FAIL() \ | ||||
do { \ | do { \ | ||||
if (js::oom::ShouldFailWithOOM()) return nullptr; \ | if (js::oom::ShouldFailWithOOM()) return nullptr; \ | ||||
} while (0) | } while (0) | ||||
#define JS_OOM_POSSIBLY_FAIL_BOOL() \ | # define JS_OOM_POSSIBLY_FAIL_BOOL() \ | ||||
do { \ | do { \ | ||||
if (js::oom::ShouldFailWithOOM()) return false; \ | if (js::oom::ShouldFailWithOOM()) return false; \ | ||||
} while (0) | } while (0) | ||||
#define JS_STACK_OOM_POSSIBLY_FAIL() \ | # define JS_STACK_OOM_POSSIBLY_FAIL() \ | ||||
do { \ | do { \ | ||||
if (js::oom::ShouldFailWithStackOOM()) return false; \ | if (js::oom::ShouldFailWithStackOOM()) return false; \ | ||||
} while (0) | } while (0) | ||||
#define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \ | # define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \ | ||||
do { \ | do { \ | ||||
if (js::oom::ShouldFailWithStackOOM()) { \ | if (js::oom::ShouldFailWithStackOOM()) { \ | ||||
ReportOverRecursed(cx); \ | ReportOverRecursed(cx); \ | ||||
return false; \ | return false; \ | ||||
} \ | } \ | ||||
} while (0) | } while (0) | ||||
#define JS_INTERRUPT_POSSIBLY_FAIL() \ | # define JS_INTERRUPT_POSSIBLY_FAIL() \ | ||||
do { \ | do { \ | ||||
if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) { \ | if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) { \ | ||||
cx->interrupt_ = true; \ | cx->requestInterrupt(js::InterruptReason::CallbackUrgent); \ | ||||
return cx->handleInterrupt(); \ | return cx->handleInterrupt(); \ | ||||
} \ | } \ | ||||
} while (0) | } while (0) | ||||
#else | # else | ||||
#define JS_OOM_POSSIBLY_FAIL() \ | # define JS_OOM_POSSIBLY_FAIL() \ | ||||
do { \ | do { \ | ||||
} while (0) | } while (0) | ||||
#define JS_OOM_POSSIBLY_FAIL_BOOL() \ | # define JS_OOM_POSSIBLY_FAIL_BOOL() \ | ||||
do { \ | do { \ | ||||
} while (0) | } while (0) | ||||
#define JS_STACK_OOM_POSSIBLY_FAIL() \ | # define JS_STACK_OOM_POSSIBLY_FAIL() \ | ||||
do { \ | do { \ | ||||
} while (0) | } while (0) | ||||
#define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \ | # define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \ | ||||
do { \ | do { \ | ||||
} while (0) | } while (0) | ||||
#define JS_INTERRUPT_POSSIBLY_FAIL() \ | # define JS_INTERRUPT_POSSIBLY_FAIL() \ | ||||
do { \ | do { \ | ||||
} while (0) | } while (0) | ||||
namespace js { | namespace js { | ||||
namespace oom { | namespace oom { | ||||
static inline bool IsSimulatedOOMAllocation() { return false; } | static inline bool IsSimulatedOOMAllocation() { return false; } | ||||
static inline bool ShouldFailWithOOM() { return false; } | static inline bool ShouldFailWithOOM() { return false; } | ||||
} /* 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 JS_PUBLIC_DATA 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); | MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason); | ||||
using AnnotateOOMAllocationSizeCallback = void (*)(size_t); | using AnnotateOOMAllocationSizeCallback = void (*)(size_t); | ||||
static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback; | static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback; | ||||
static void setAnnotateOOMAllocationSizeCallback( | static void setAnnotateOOMAllocationSizeCallback( | ||||
AnnotateOOMAllocationSizeCallback callback) { | AnnotateOOMAllocationSizeCallback callback) { | ||||
annotateOOMSizeCallback = callback; | annotateOOMSizeCallback = callback; | ||||
} | } | ||||
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) | ||||
AutoEnterOOMUnsafeRegion() | AutoEnterOOMUnsafeRegion() | ||||
: oomEnabled_(oom::IsThreadSimulatingOOM() && | : oomEnabled_(oom::simulator.isThreadSimulatingAny()) { | ||||
oom::maxAllocations != UINT64_MAX), | |||||
oomAfter_(0) { | |||||
if (oomEnabled_) { | if (oomEnabled_) { | ||||
MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this)); | MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this)); | ||||
oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter); | oom::simulator.setInUnsafeRegion(true); | ||||
oom::maxAllocations = UINT64_MAX; | |||||
} | } | ||||
} | } | ||||
~AutoEnterOOMUnsafeRegion() { | ~AutoEnterOOMUnsafeRegion() { | ||||
if (oomEnabled_) { | if (oomEnabled_) { | ||||
MOZ_ASSERT(oom::maxAllocations == UINT64_MAX); | oom::simulator.setInUnsafeRegion(false); | ||||
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)); | MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); | ||||
} | } | ||||
} | } | ||||
private: | private: | ||||
// Used to catch concurrent use from other threads. | // Used to catch concurrent use from other threads. | ||||
static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_; | static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_; | ||||
bool oomEnabled_; | bool oomEnabled_; | ||||
int64_t oomAfter_; | |||||
#endif | # endif | ||||
}; | }; | ||||
} /* namespace js */ | } /* namespace js */ | ||||
// Malloc allocation. | // Malloc allocation. | ||||
namespace js { | namespace js { | ||||
extern JS_PUBLIC_DATA arena_id_t MallocArena; | extern JS_PUBLIC_DATA arena_id_t MallocArena; | ||||
extern JS_PUBLIC_DATA arena_id_t ArrayBufferContentsArena; | |||||
extern JS_PUBLIC_DATA arena_id_t StringBufferArena; | |||||
extern void InitMallocAllocator(); | extern void InitMallocAllocator(); | ||||
extern void ShutDownMallocAllocator(); | extern void ShutDownMallocAllocator(); | ||||
# ifdef MOZ_DEBUG | |||||
extern void AssertJSStringBufferInCorrectArena(const void* ptr); | |||||
# endif | |||||
} /* namespace js */ | } /* namespace js */ | ||||
static inline void* js_arena_malloc(arena_id_t arena, size_t bytes) { | |||||
JS_OOM_POSSIBLY_FAIL(); | |||||
return moz_arena_malloc(arena, bytes); | |||||
} | |||||
static inline void* js_malloc(size_t bytes) { | static inline void* js_malloc(size_t bytes) { | ||||
return js_arena_malloc(js::MallocArena, bytes); | |||||
} | |||||
static inline void* js_arena_calloc(arena_id_t arena, size_t bytes) { | |||||
JS_OOM_POSSIBLY_FAIL(); | JS_OOM_POSSIBLY_FAIL(); | ||||
return moz_arena_malloc(js::MallocArena, bytes); | return moz_arena_calloc(arena, bytes, 1); | ||||
} | } | ||||
static inline void* js_calloc(size_t bytes) { | static inline void* js_arena_calloc(arena_id_t arena, size_t nmemb, | ||||
size_t size) { | |||||
JS_OOM_POSSIBLY_FAIL(); | JS_OOM_POSSIBLY_FAIL(); | ||||
return moz_arena_calloc(js::MallocArena, bytes, 1); | return moz_arena_calloc(arena, nmemb, size); | ||||
} | |||||
static inline void* js_calloc(size_t bytes) { | |||||
return js_arena_calloc(js::MallocArena, bytes); | |||||
} | } | ||||
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(); | return js_arena_calloc(js::MallocArena, nmemb, size); | ||||
return moz_arena_calloc(js::MallocArena, nmemb, size); | |||||
} | } | ||||
static inline void* js_realloc(void* p, size_t bytes) { | static inline void* js_arena_realloc(arena_id_t arena, void* p, size_t bytes) { | ||||
// realloc() with zero size is not portable, as some implementations may | // realloc() with zero size is not portable, as some implementations may | ||||
// return nullptr on success and free |p| for this. We assume nullptr | // return nullptr on success and free |p| for this. We assume nullptr | ||||
// indicates failure and that |p| is still valid. | // indicates failure and that |p| is still valid. | ||||
MOZ_ASSERT(bytes != 0); | MOZ_ASSERT(bytes != 0); | ||||
JS_OOM_POSSIBLY_FAIL(); | JS_OOM_POSSIBLY_FAIL(); | ||||
return moz_arena_realloc(js::MallocArena, p, bytes); | return moz_arena_realloc(arena, p, bytes); | ||||
} | |||||
static inline void* js_realloc(void* p, size_t bytes) { | |||||
return js_arena_realloc(js::MallocArena, p, bytes); | |||||
} | } | ||||
static inline void js_free(void* p) { | static inline void js_free(void* p) { | ||||
// TODO: This should call |moz_arena_free(js::MallocArena, p)| but we | // TODO: This should call |moz_arena_free(js::MallocArena, p)| but we | ||||
// currently can't enforce that all memory freed here was allocated by | // currently can't enforce that all memory freed here was allocated by | ||||
// js_malloc(). | // js_malloc(). | ||||
free(p); | free(p); | ||||
} | } | ||||
JS_PUBLIC_API char* js_strdup(const char* s); | |||||
#endif /* JS_USE_CUSTOM_ALLOCATOR */ | #endif /* JS_USE_CUSTOM_ALLOCATOR */ | ||||
#include <new> | #include <new> | ||||
/* | /* | ||||
* Low-level memory management in SpiderMonkey: | * [SMDOC] Low-level memory management in SpiderMonkey | ||||
* | * | ||||
* ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these | * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these | ||||
* to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's | * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's | ||||
* these symbols. | * these symbols. | ||||
* | * | ||||
* ** Do not use the builtin C++ operator new and delete: these throw on | * ** Do not use the builtin C++ operator new and delete: these throw on | ||||
* error and we cannot override them not to. | * error and we cannot override them not to. | ||||
* | * | ||||
* Allocation: | * Allocation: | ||||
* | * | ||||
* - If the lifetime of the allocation is tied to the lifetime of a GC-thing | * - 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 | * (that is, finalizing the GC-thing will free the allocation), call one of | ||||
* the following functions: | * the following functions: | ||||
* | * | ||||
* JSContext::{malloc_,realloc_,calloc_,new_} | * JSContext::{pod_malloc,pod_calloc,pod_realloc} | ||||
* JSRuntime::{malloc_,realloc_,calloc_,new_} | * Zone::{pod_malloc,pod_calloc,pod_realloc} | ||||
* | * | ||||
* These functions accumulate the number of bytes allocated which is used as | * These functions accumulate the number of bytes allocated which is used as | ||||
* part of the GC-triggering heuristic. | * part of the GC-triggering heuristics. | ||||
* | * | ||||
* The difference between the JSContext and JSRuntime versions is that the | * The difference between the JSContext and Zone versions is that the | ||||
* cx version reports an out-of-memory error on OOM. (This follows from the | * cx version report an out-of-memory error on OOM. (This follows from the | ||||
* general SpiderMonkey idiom that a JSContext-taking function reports its | * general SpiderMonkey idiom that a JSContext-taking function reports its | ||||
* own errors.) | * own errors.) | ||||
* | * | ||||
* If you don't want to report an error on failure, there are maybe_ versions | |||||
* of these methods available too, e.g. maybe_pod_malloc. | |||||
* | |||||
* The methods above use templates to allow allocating memory suitable for an | |||||
* array of a given type and number of elements. There are _with_extra | |||||
* versions to allow allocating an area of memory which is larger by a | |||||
* specified number of bytes, e.g. pod_malloc_with_extra. | |||||
* | |||||
* These methods are available on a JSRuntime, but calling them is | |||||
* discouraged. Memory attributed to a runtime can only be reclaimed by full | |||||
* GCs, and we try to avoid those where possible. | |||||
* | |||||
* - Otherwise, use js_malloc/js_realloc/js_calloc/js_new | * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new | ||||
* | * | ||||
* Deallocation: | * Deallocation: | ||||
* | * | ||||
* - Ordinarily, use js_free/js_delete. | * - Ordinarily, use js_free/js_delete. | ||||
* | * | ||||
* - For deallocations during GC finalization, use one of the following | * - For deallocations during GC finalization, use one of the following | ||||
* operations on the FreeOp provided to the finalizer: | * operations on the FreeOp provided to the finalizer: | ||||
* | * | ||||
* FreeOp::{free_,delete_} | * 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 | * 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* NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ | QUALIFIERS T* MOZ_HEAP_ALLOCATOR NEWNAME(Args&&... args) { \ | ||||
void* memory = ALLOCATOR(sizeof(T)); \ | void* memory = ALLOCATOR(sizeof(T)); \ | ||||
return MOZ_LIKELY(memory) ? new (memory) \ | return MOZ_LIKELY(memory) ? new (memory) T(std::forward<Args>(args)...) \ | ||||
T(mozilla::Forward<Args>(args)...) \ | : nullptr; \ | ||||
} | |||||
/* | |||||
* Given a class which should provide a 'new' method that takes an arena as | |||||
* its first argument, add JS_DECLARE_NEW_ARENA_METHODS | |||||
* (see js::MallocProvider for an example). | |||||
* | |||||
* Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_ARENA_METHODS, | |||||
* or the build will break. | |||||
*/ | |||||
#define JS_DECLARE_NEW_ARENA_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \ | |||||
template <class T, typename... Args> \ | |||||
QUALIFIERS T* MOZ_HEAP_ALLOCATOR NEWNAME(arena_id_t arena, Args&&... args) { \ | |||||
void* memory = ALLOCATOR(arena, sizeof(T)); \ | |||||
return MOZ_LIKELY(memory) ? new (memory) T(std::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. | ||||
* | * | ||||
* Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS, | * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS, | ||||
* or the build will break. | * or the build will break. | ||||
*/ | */ | ||||
#define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS) \ | #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS) \ | ||||
template <class T, typename... Args> \ | template <class T, typename... Args> \ | ||||
QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> MAKENAME( \ | QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> MOZ_HEAP_ALLOCATOR \ | ||||
Args&&... args) MOZ_HEAP_ALLOCATOR { \ | MAKENAME(Args&&... args) { \ | ||||
T* ptr = NEWNAME<T>(mozilla::Forward<Args>(args)...); \ | T* ptr = NEWNAME<T>(std::forward<Args>(args)...); \ | ||||
return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \ | return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \ | ||||
} | } | ||||
JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) | JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) | ||||
JS_DECLARE_NEW_ARENA_METHODS(js_arena_new, js_arena_malloc, | |||||
static MOZ_ALWAYS_INLINE) | |||||
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> | ||||
Show All 24 Lines | if (p) { | ||||
js_free(const_cast<T*>(p)); | js_free(const_cast<T*>(p)); | ||||
} | } | ||||
} | } | ||||
template <class T> | template <class T> | ||||
static MOZ_ALWAYS_INLINE void js_delete_poison(const T* p) { | static MOZ_ALWAYS_INLINE void js_delete_poison(const T* p) { | ||||
if (p) { | if (p) { | ||||
p->~T(); | p->~T(); | ||||
memset(const_cast<T*>(p), 0x3B, sizeof(T)); | memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T)); | ||||
js_free(const_cast<T*>(p)); | js_free(const_cast<T*>(p)); | ||||
} | } | ||||
} | } | ||||
template <class T> | template <class T> | ||||
static MOZ_ALWAYS_INLINE T* js_pod_malloc() { | static MOZ_ALWAYS_INLINE T* js_pod_arena_malloc(arena_id_t arena, | ||||
return static_cast<T*>(js_malloc(sizeof(T))); | size_t numElems) { | ||||
size_t bytes; | |||||
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) { | |||||
return nullptr; | |||||
} | |||||
return static_cast<T*>(js_arena_malloc(arena, bytes)); | |||||
} | } | ||||
template <class T> | template <class T> | ||||
static MOZ_ALWAYS_INLINE T* js_pod_calloc() { | static MOZ_ALWAYS_INLINE T* js_pod_malloc(size_t numElems) { | ||||
return static_cast<T*>(js_calloc(sizeof(T))); | return js_pod_arena_malloc<T>(js::MallocArena, numElems); | ||||
} | } | ||||
template <class T> | template <class T> | ||||
static MOZ_ALWAYS_INLINE T* js_pod_malloc(size_t numElems) { | static MOZ_ALWAYS_INLINE T* js_pod_arena_calloc(arena_id_t arena, | ||||
size_t numElems) { | |||||
size_t bytes; | size_t bytes; | ||||
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) | if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) { | ||||
return nullptr; | return nullptr; | ||||
return static_cast<T*>(js_malloc(bytes)); | } | ||||
return static_cast<T*>(js_arena_calloc(arena, bytes, 1)); | |||||
} | } | ||||
template <class T> | template <class T> | ||||
static MOZ_ALWAYS_INLINE T* js_pod_calloc(size_t numElems) { | static MOZ_ALWAYS_INLINE T* js_pod_calloc(size_t numElems) { | ||||
size_t bytes; | return js_pod_arena_calloc<T>(js::MallocArena, numElems); | ||||
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) | |||||
return nullptr; | |||||
return static_cast<T*>(js_calloc(bytes)); | |||||
} | } | ||||
template <class T> | template <class T> | ||||
static MOZ_ALWAYS_INLINE T* js_pod_realloc(T* prior, size_t oldSize, | static MOZ_ALWAYS_INLINE T* js_pod_arena_realloc(arena_id_t arena, T* prior, | ||||
size_t oldSize, | |||||
size_t newSize) { | size_t newSize) { | ||||
MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value)); | MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value)); | ||||
size_t bytes; | size_t bytes; | ||||
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) return nullptr; | if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) { | ||||
return static_cast<T*>(js_realloc(prior, bytes)); | return nullptr; | ||||
} | } | ||||
return static_cast<T*>(js_arena_realloc(arena, 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 */ | template <class T> | ||||
static MOZ_ALWAYS_INLINE T* js_pod_realloc(T* prior, size_t oldSize, | |||||
size_t newSize) { | |||||
return js_pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize); | |||||
} | |||||
namespace JS { | namespace JS { | ||||
template <typename T> | template <typename T> | ||||
struct DeletePolicy { | struct DeletePolicy { | ||||
constexpr DeletePolicy() {} | constexpr DeletePolicy() {} | ||||
template <typename U> | template <typename U> | ||||
Show All 9 Lines | struct FreePolicy { | ||||
void operator()(const void* ptr) { js_free(const_cast<void*>(ptr)); } | void operator()(const void* ptr) { js_free(const_cast<void*>(ptr)); } | ||||
}; | }; | ||||
typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars; | typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars; | ||||
typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars; | typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars; | ||||
} // namespace JS | } // 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 mozilla::WrappingMultiply(h, goldenRatio); | |||||
} | |||||
} /* namespace detail */ | |||||
} /* namespace js */ | |||||
/* sixgill annotation defines */ | /* sixgill annotation defines */ | ||||
#ifndef HAVE_STATIC_ANNOTATIONS | #ifndef HAVE_STATIC_ANNOTATIONS | ||||
#define HAVE_STATIC_ANNOTATIONS | # define HAVE_STATIC_ANNOTATIONS | ||||
#ifdef XGILL_PLUGIN | # ifdef XGILL_PLUGIN | ||||
#define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) | # define STATIC_PRECONDITION(COND) __attribute__((precondition(# COND))) | ||||
#define STATIC_PRECONDITION_ASSUME(COND) \ | # define STATIC_PRECONDITION_ASSUME(COND) \ | ||||
__attribute__((precondition_assume(#COND))) | __attribute__((precondition_assume(#COND))) | ||||
#define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) | # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(# COND))) | ||||
#define STATIC_POSTCONDITION_ASSUME(COND) \ | # define STATIC_POSTCONDITION_ASSUME(COND) \ | ||||
__attribute__((postcondition_assume(#COND))) | __attribute__((postcondition_assume(#COND))) | ||||
#define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) | # define STATIC_INVARIANT(COND) __attribute__((invariant(# COND))) | ||||
#define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) | # define STATIC_INVARIANT_ASSUME(COND) \ | ||||
__attribute__((invariant_assume(#COND))) | |||||
#define STATIC_ASSUME(COND) \ | # define STATIC_ASSUME(COND) \ | ||||
JS_BEGIN_MACRO \ | JS_BEGIN_MACRO \ | ||||
__attribute__((assume_static(#COND), unused)) int STATIC_PASTE1( \ | __attribute__((assume_static(#COND), unused)) int STATIC_PASTE1( \ | ||||
assume_static_, __COUNTER__); \ | assume_static_, __COUNTER__); \ | ||||
JS_END_MACRO | JS_END_MACRO | ||||
#else /* XGILL_PLUGIN */ | # else /* XGILL_PLUGIN */ | ||||
#define STATIC_PRECONDITION(COND) /* nothing */ | # define STATIC_PRECONDITION(COND) /* nothing */ | ||||
#define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ | # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ | ||||
#define STATIC_POSTCONDITION(COND) /* nothing */ | # define STATIC_POSTCONDITION(COND) /* nothing */ | ||||
#define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ | # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ | ||||
#define STATIC_INVARIANT(COND) /* nothing */ | # define STATIC_INVARIANT(COND) /* nothing */ | ||||
#define STATIC_INVARIANT_ASSUME(COND) /* nothing */ | # define STATIC_INVARIANT_ASSUME(COND) /* nothing */ | ||||
#define STATIC_ASSUME(COND) \ | # define STATIC_ASSUME(COND) \ | ||||
JS_BEGIN_MACRO /* nothing */ \ | JS_BEGIN_MACRO /* nothing */ \ | ||||
JS_END_MACRO | JS_END_MACRO | ||||
#endif /* XGILL_PLUGIN */ | # endif /* XGILL_PLUGIN */ | ||||
#define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) | # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) | ||||
#endif /* HAVE_STATIC_ANNOTATIONS */ | #endif /* HAVE_STATIC_ANNOTATIONS */ | ||||
#endif /* js_Utility_h */ | #endif /* js_Utility_h */ |
Wildfire Games · Phabricator