michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef js_Utility_h michael@0: #define js_Utility_h michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/Compiler.h" michael@0: #include "mozilla/Move.h" michael@0: #include "mozilla/NullPtr.h" michael@0: #include "mozilla/Scoped.h" michael@0: #include "mozilla/TemplateLib.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #ifdef JS_OOM_DO_BACKTRACES michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: #include "jstypes.h" michael@0: michael@0: /* The public JS engine namespace. */ michael@0: namespace JS {} michael@0: michael@0: /* The mozilla-shared reusable template/utility namespace. */ michael@0: namespace mozilla {} michael@0: michael@0: /* The private JS engine namespace. */ michael@0: namespace js {} michael@0: michael@0: /* michael@0: * Patterns used by SpiderMonkey to overwrite unused memory. If you are michael@0: * accessing an object with one of these pattern, you probably have a dangling michael@0: * pointer. michael@0: */ michael@0: #define JS_FRESH_NURSERY_PATTERN 0x2F michael@0: #define JS_SWEPT_NURSERY_PATTERN 0x2B michael@0: #define JS_ALLOCATED_NURSERY_PATTERN 0x2D michael@0: #define JS_FRESH_TENURED_PATTERN 0x4F michael@0: #define JS_SWEPT_TENURED_PATTERN 0x4B michael@0: #define JS_ALLOCATED_TENURED_PATTERN 0x4D michael@0: #define JS_SWEPT_CODE_PATTERN 0x3b michael@0: #define JS_SWEPT_FRAME_PATTERN 0x5b michael@0: michael@0: #define JS_ASSERT(expr) MOZ_ASSERT(expr) michael@0: #define JS_ASSERT_IF(cond, expr) MOZ_ASSERT_IF(cond, expr) michael@0: michael@0: #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT") michael@0: #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF") michael@0: michael@0: extern MOZ_NORETURN JS_PUBLIC_API(void) michael@0: JS_Assert(const char *s, const char *file, int ln); michael@0: michael@0: /* michael@0: * Abort the process in a non-graceful manner. This will cause a core file, michael@0: * call to the debugger or other moral equivalent as well as causing the michael@0: * entire process to stop. michael@0: */ michael@0: extern JS_PUBLIC_API(void) JS_Abort(void); michael@0: michael@0: /* michael@0: * Custom allocator support for SpiderMonkey michael@0: */ michael@0: #if defined JS_USE_CUSTOM_ALLOCATOR michael@0: # include "jscustomallocator.h" michael@0: #else michael@0: # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) michael@0: /* michael@0: * In order to test OOM conditions, when the testing function michael@0: * oomAfterAllocations COUNT is passed, we fail continuously after the NUM'th michael@0: * allocation from now. michael@0: */ michael@0: extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set in builtin/TestingFunctions.cpp */ michael@0: extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */ michael@0: michael@0: #ifdef JS_OOM_BREAKPOINT michael@0: static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } michael@0: #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() michael@0: #else michael@0: #define JS_OOM_CALL_BP_FUNC() do {} while(0) michael@0: #endif michael@0: michael@0: # define JS_OOM_POSSIBLY_FAIL() \ michael@0: do \ michael@0: { \ michael@0: if (++OOM_counter > OOM_maxAllocations) { \ michael@0: JS_OOM_CALL_BP_FUNC();\ michael@0: return nullptr; \ michael@0: } \ michael@0: } while (0) michael@0: michael@0: # else michael@0: # define JS_OOM_POSSIBLY_FAIL() do {} while(0) michael@0: # endif /* DEBUG || JS_OOM_BREAKPOINT */ michael@0: michael@0: static inline void* js_malloc(size_t bytes) michael@0: { michael@0: JS_OOM_POSSIBLY_FAIL(); michael@0: return malloc(bytes); michael@0: } michael@0: michael@0: static inline void* js_calloc(size_t bytes) michael@0: { michael@0: JS_OOM_POSSIBLY_FAIL(); michael@0: return calloc(bytes, 1); michael@0: } michael@0: michael@0: static inline void* js_calloc(size_t nmemb, size_t size) michael@0: { michael@0: JS_OOM_POSSIBLY_FAIL(); michael@0: return calloc(nmemb, size); michael@0: } michael@0: michael@0: static inline void* js_realloc(void* p, size_t bytes) michael@0: { michael@0: JS_OOM_POSSIBLY_FAIL(); michael@0: return realloc(p, bytes); michael@0: } michael@0: michael@0: static inline void js_free(void* p) michael@0: { michael@0: free(p); michael@0: } michael@0: #endif/* JS_USE_CUSTOM_ALLOCATOR */ michael@0: michael@0: #include michael@0: michael@0: /* michael@0: * Low-level memory management in SpiderMonkey: michael@0: * michael@0: * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these michael@0: * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's michael@0: * these symbols. michael@0: * michael@0: * ** Do not use the builtin C++ operator new and delete: these throw on michael@0: * error and we cannot override them not to. michael@0: * michael@0: * Allocation: michael@0: * michael@0: * - If the lifetime of the allocation is tied to the lifetime of a GC-thing michael@0: * (that is, finalizing the GC-thing will free the allocation), call one of michael@0: * the following functions: michael@0: * michael@0: * JSContext::{malloc_,realloc_,calloc_,new_} michael@0: * JSRuntime::{malloc_,realloc_,calloc_,new_} michael@0: * michael@0: * These functions accumulate the number of bytes allocated which is used as michael@0: * part of the GC-triggering heuristic. michael@0: * michael@0: * The difference between the JSContext and JSRuntime versions is that the michael@0: * cx version reports an out-of-memory error on OOM. (This follows from the michael@0: * general SpiderMonkey idiom that a JSContext-taking function reports its michael@0: * own errors.) michael@0: * michael@0: * - Otherwise, use js_malloc/js_realloc/js_calloc/js_free/js_new michael@0: * michael@0: * Deallocation: michael@0: * michael@0: * - Ordinarily, use js_free/js_delete. michael@0: * michael@0: * - For deallocations during GC finalization, use one of the following michael@0: * operations on the FreeOp provided to the finalizer: michael@0: * michael@0: * FreeOp::{free_,delete_} michael@0: * michael@0: * The advantage of these operations is that the memory is batched and freed michael@0: * on another thread. michael@0: */ michael@0: michael@0: #define JS_NEW_BODY(allocator, t, parms) \ michael@0: void *memory = allocator(sizeof(t)); \ michael@0: return memory ? new(memory) t parms : nullptr; michael@0: michael@0: /* michael@0: * Given a class which should provide 'new' methods, add michael@0: * JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This michael@0: * adds news with up to 12 parameters. Add more versions of new below if michael@0: * you need more than 12 parameters. michael@0: * michael@0: * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS, michael@0: * or the build will break. michael@0: */ michael@0: #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS)\ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME() MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T, ())\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4),\ michael@0: mozilla::Forward(p5)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4),\ michael@0: mozilla::Forward(p5),\ michael@0: mozilla::Forward(p6)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4),\ michael@0: mozilla::Forward(p5),\ michael@0: mozilla::Forward(p6),\ michael@0: mozilla::Forward(p7)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4),\ michael@0: mozilla::Forward(p5),\ michael@0: mozilla::Forward(p6),\ michael@0: mozilla::Forward(p7),\ michael@0: mozilla::Forward(p8)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4),\ michael@0: mozilla::Forward(p5),\ michael@0: mozilla::Forward(p6),\ michael@0: mozilla::Forward(p7),\ michael@0: mozilla::Forward(p8),\ michael@0: mozilla::Forward(p9)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4),\ michael@0: mozilla::Forward(p5),\ michael@0: mozilla::Forward(p6),\ michael@0: mozilla::Forward(p7),\ michael@0: mozilla::Forward(p8),\ michael@0: mozilla::Forward(p9),\ michael@0: mozilla::Forward(p10)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4),\ michael@0: mozilla::Forward(p5),\ michael@0: mozilla::Forward(p6),\ michael@0: mozilla::Forward(p7),\ michael@0: mozilla::Forward(p8),\ michael@0: mozilla::Forward(p9),\ michael@0: mozilla::Forward(p10),\ michael@0: mozilla::Forward(p11)))\ michael@0: }\ michael@0: \ michael@0: template \ michael@0: QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11, P12 &&p12) MOZ_HEAP_ALLOCATOR {\ michael@0: JS_NEW_BODY(ALLOCATOR, T,\ michael@0: (mozilla::Forward(p1),\ michael@0: mozilla::Forward(p2),\ michael@0: mozilla::Forward(p3),\ michael@0: mozilla::Forward(p4),\ michael@0: mozilla::Forward(p5),\ michael@0: mozilla::Forward(p6),\ michael@0: mozilla::Forward(p7),\ michael@0: mozilla::Forward(p8),\ michael@0: mozilla::Forward(p9),\ michael@0: mozilla::Forward(p10),\ michael@0: mozilla::Forward(p11),\ michael@0: mozilla::Forward(p12)))\ michael@0: }\ michael@0: michael@0: JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) michael@0: michael@0: template michael@0: static MOZ_ALWAYS_INLINE void michael@0: js_delete(T *p) michael@0: { michael@0: if (p) { michael@0: p->~T(); michael@0: js_free(p); michael@0: } michael@0: } michael@0: michael@0: template michael@0: static MOZ_ALWAYS_INLINE void michael@0: js_delete_poison(T *p) michael@0: { michael@0: if (p) { michael@0: p->~T(); michael@0: memset(p, 0x3B, sizeof(T)); michael@0: js_free(p); michael@0: } michael@0: } michael@0: michael@0: template michael@0: static MOZ_ALWAYS_INLINE T * michael@0: js_pod_malloc() michael@0: { michael@0: return (T *)js_malloc(sizeof(T)); michael@0: } michael@0: michael@0: template michael@0: static MOZ_ALWAYS_INLINE T * michael@0: js_pod_calloc() michael@0: { michael@0: return (T *)js_calloc(sizeof(T)); michael@0: } michael@0: michael@0: template michael@0: static MOZ_ALWAYS_INLINE T * michael@0: js_pod_malloc(size_t numElems) michael@0: { michael@0: if (numElems & mozilla::tl::MulOverflowMask::value) michael@0: return nullptr; michael@0: return (T *)js_malloc(numElems * sizeof(T)); michael@0: } michael@0: michael@0: template michael@0: static MOZ_ALWAYS_INLINE T * michael@0: js_pod_calloc(size_t numElems) michael@0: { michael@0: if (numElems & mozilla::tl::MulOverflowMask::value) michael@0: return nullptr; michael@0: return (T *)js_calloc(numElems * sizeof(T)); michael@0: } michael@0: michael@0: namespace js { michael@0: michael@0: template michael@0: struct ScopedFreePtrTraits michael@0: { michael@0: typedef T* type; michael@0: static T* empty() { return nullptr; } michael@0: static void release(T* ptr) { js_free(ptr); } michael@0: }; michael@0: SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits) michael@0: michael@0: template michael@0: struct ScopedDeletePtrTraits : public ScopedFreePtrTraits michael@0: { michael@0: static void release(T *ptr) { js_delete(ptr); } michael@0: }; michael@0: SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits) michael@0: michael@0: template michael@0: struct ScopedReleasePtrTraits : public ScopedFreePtrTraits michael@0: { michael@0: static void release(T *ptr) { if (ptr) ptr->release(); } michael@0: }; michael@0: SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits) michael@0: michael@0: } /* namespace js */ michael@0: michael@0: namespace js { michael@0: michael@0: /* Integral types for all hash functions. */ michael@0: typedef uint32_t HashNumber; michael@0: const unsigned HashNumberSizeBits = 32; michael@0: michael@0: namespace detail { michael@0: michael@0: /* michael@0: * Given a raw hash code, h, return a number that can be used to select a hash michael@0: * bucket. michael@0: * michael@0: * This function aims to produce as uniform an output distribution as possible, michael@0: * especially in the most significant (leftmost) bits, even though the input michael@0: * distribution may be highly nonrandom, given the constraints that this must michael@0: * be deterministic and quick to compute. michael@0: * michael@0: * Since the leftmost bits of the result are best, the hash bucket index is michael@0: * computed by doing ScrambleHashCode(h) / (2^32/N) or the equivalent michael@0: * right-shift, not ScrambleHashCode(h) % N or the equivalent bit-mask. michael@0: * michael@0: * FIXME: OrderedHashTable uses a bit-mask; see bug 775896. michael@0: */ michael@0: inline HashNumber michael@0: ScrambleHashCode(HashNumber h) michael@0: { michael@0: /* michael@0: * Simply returning h would not cause any hash tables to produce wrong michael@0: * answers. But it can produce pathologically bad performance: The caller michael@0: * right-shifts the result, keeping only the highest bits. The high bits of michael@0: * hash codes are very often completely entropy-free. (So are the lowest michael@0: * bits.) michael@0: * michael@0: * So we use Fibonacci hashing, as described in Knuth, The Art of Computer michael@0: * Programming, 6.4. This mixes all the bits of the input hash code h. michael@0: * michael@0: * The value of goldenRatio is taken from the hex michael@0: * expansion of the golden ratio, which starts 1.9E3779B9.... michael@0: * This value is especially good if values with consecutive hash codes michael@0: * are stored in a hash table; see Knuth for details. michael@0: */ michael@0: static const HashNumber goldenRatio = 0x9E3779B9U; michael@0: return h * goldenRatio; michael@0: } michael@0: michael@0: } /* namespace detail */ michael@0: michael@0: } /* namespace js */ michael@0: michael@0: namespace JS { michael@0: michael@0: /* michael@0: * Methods for poisoning GC heap pointer words and checking for poisoned words. michael@0: * These are in this file for use in Value methods and so forth. michael@0: * michael@0: * If the moving GC hazard analysis is in use and detects a non-rooted stack michael@0: * pointer to a GC thing, one byte of that pointer is poisoned to refer to an michael@0: * invalid location. For both 32 bit and 64 bit systems, the fourth byte of the michael@0: * pointer is overwritten, to reduce the likelihood of accidentally changing michael@0: * a live integer value. michael@0: */ michael@0: michael@0: inline void PoisonPtr(void *v) michael@0: { michael@0: #if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG) michael@0: uint8_t *ptr = (uint8_t *) v + 3; michael@0: *ptr = JS_FREE_PATTERN; michael@0: #endif michael@0: } michael@0: michael@0: template michael@0: inline bool IsPoisonedPtr(T *v) michael@0: { michael@0: #if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG) michael@0: uint32_t mask = uintptr_t(v) & 0xff000000; michael@0: return mask == uint32_t(JS_FREE_PATTERN << 24); michael@0: #else michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: } michael@0: michael@0: /* sixgill annotation defines */ michael@0: #ifndef HAVE_STATIC_ANNOTATIONS michael@0: # define HAVE_STATIC_ANNOTATIONS michael@0: # ifdef XGILL_PLUGIN michael@0: # define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) michael@0: # define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) michael@0: # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) michael@0: # define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) michael@0: # define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) michael@0: # define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) michael@0: # define STATIC_PASTE2(X,Y) X ## Y michael@0: # define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y) michael@0: # define STATIC_ASSERT(COND) \ michael@0: JS_BEGIN_MACRO \ michael@0: __attribute__((assert_static(#COND), unused)) \ michael@0: int STATIC_PASTE1(assert_static_, __COUNTER__); \ michael@0: JS_END_MACRO michael@0: # define STATIC_ASSUME(COND) \ michael@0: JS_BEGIN_MACRO \ michael@0: __attribute__((assume_static(#COND), unused)) \ michael@0: int STATIC_PASTE1(assume_static_, __COUNTER__); \ michael@0: JS_END_MACRO michael@0: # define STATIC_ASSERT_RUNTIME(COND) \ michael@0: JS_BEGIN_MACRO \ michael@0: __attribute__((assert_static_runtime(#COND), unused)) \ michael@0: int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \ michael@0: JS_END_MACRO michael@0: # else /* XGILL_PLUGIN */ michael@0: # define STATIC_PRECONDITION(COND) /* nothing */ michael@0: # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ michael@0: # define STATIC_POSTCONDITION(COND) /* nothing */ michael@0: # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ michael@0: # define STATIC_INVARIANT(COND) /* nothing */ michael@0: # define STATIC_INVARIANT_ASSUME(COND) /* nothing */ michael@0: # define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO michael@0: # define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO michael@0: # define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO michael@0: # endif /* XGILL_PLUGIN */ michael@0: # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) michael@0: #endif /* HAVE_STATIC_ANNOTATIONS */ michael@0: michael@0: #endif /* js_Utility_h */