Merge mozilla-central to autoland. a=merge CLOSED TREE
[gecko.git] / js / public / Utility.h
blob25e351d740fef9886e570f1d74e587c054db718a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef js_Utility_h
8 #define js_Utility_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Atomics.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/Compiler.h"
14 #include "mozilla/TemplateLib.h"
15 #include "mozilla/UniquePtr.h"
17 #include <stdlib.h>
18 #include <string.h>
19 #include <type_traits>
20 #include <utility>
22 #include "jstypes.h"
23 #include "mozmemory.h"
24 #include "js/TypeDecls.h"
26 /* The public JS engine namespace. */
27 namespace JS {}
29 /* The mozilla-shared reusable template/utility namespace. */
30 namespace mozilla {}
32 /* The private JS engine namespace. */
33 namespace js {}
35 extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API void JS_Assert(const char* s,
36 const char* file,
37 int ln);
40 * Custom allocator support for SpiderMonkey
42 #if defined JS_USE_CUSTOM_ALLOCATOR
43 # include "jscustomallocator.h"
44 #else
46 namespace js {
49 * Thread types are used to tag threads for certain kinds of testing (see
50 * below), and also used to characterize threads in the thread scheduler (see
51 * js/src/vm/HelperThreads.cpp).
53 * Please update oom::FirstThreadTypeToTest and oom::LastThreadTypeToTest when
54 * adding new thread types.
56 enum ThreadType {
57 THREAD_TYPE_NONE = 0, // 0
58 THREAD_TYPE_MAIN, // 1
59 THREAD_TYPE_WASM_COMPILE_TIER1, // 2
60 THREAD_TYPE_WASM_COMPILE_TIER2, // 3
61 THREAD_TYPE_ION, // 4
62 THREAD_TYPE_COMPRESS, // 5
63 THREAD_TYPE_GCPARALLEL, // 6
64 THREAD_TYPE_PROMISE_TASK, // 7
65 THREAD_TYPE_ION_FREE, // 8
66 THREAD_TYPE_WASM_GENERATOR_TIER2, // 9
67 THREAD_TYPE_WORKER, // 10
68 THREAD_TYPE_DELAZIFY, // 11
69 THREAD_TYPE_DELAZIFY_FREE, // 12
70 THREAD_TYPE_MAX // Used to check shell function arguments
73 namespace oom {
76 * Theads are tagged only in certain debug contexts. Notably, to make testing
77 * OOM in certain helper threads more effective, we allow restricting the OOM
78 * testing to a certain helper thread type. This allows us to fail e.g. in
79 * off-thread script parsing without causing an OOM in the active thread first.
81 * Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation
82 * is in util/Utility.cpp.
84 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
86 // Define the range of threads tested by simulated OOM testing and the
87 // like. Testing worker threads is not supported.
88 const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN;
89 const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_GENERATOR_TIER2;
91 extern bool InitThreadType(void);
92 extern void SetThreadType(ThreadType);
93 extern JS_PUBLIC_API uint32_t GetThreadType(void);
95 # else
97 inline bool InitThreadType(void) { return true; }
98 inline void SetThreadType(ThreadType t){};
99 inline uint32_t GetThreadType(void) { return 0; }
100 inline uint32_t GetAllocationThreadType(void) { return 0; }
101 inline uint32_t GetStackCheckThreadType(void) { return 0; }
102 inline uint32_t GetInterruptCheckThreadType(void) { return 0; }
104 # endif
106 } /* namespace oom */
107 } /* namespace js */
109 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
111 # ifdef JS_OOM_BREAKPOINT
112 # if defined(_MSC_VER)
113 static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() {
114 __asm {}
117 # else
118 static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
119 # endif
120 # define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint()
121 # else
122 # define JS_OOM_CALL_BP_FUNC() \
123 do { \
124 } while (0)
125 # endif
127 namespace js {
128 namespace oom {
131 * Out of memory testing support. We provide various testing functions to
132 * simulate OOM conditions and so we can test that they are handled correctly.
134 class FailureSimulator {
135 public:
136 enum class Kind : uint8_t { Nothing, OOM, StackOOM, Interrupt };
138 private:
139 Kind kind_ = Kind::Nothing;
140 uint32_t targetThread_ = 0;
141 uint64_t maxChecks_ = UINT64_MAX;
142 uint64_t counter_ = 0;
143 bool failAlways_ = true;
144 bool inUnsafeRegion_ = false;
146 public:
147 uint64_t maxChecks() const { return maxChecks_; }
148 uint64_t counter() const { return counter_; }
149 void setInUnsafeRegion(bool b) {
150 MOZ_ASSERT(inUnsafeRegion_ != b);
151 inUnsafeRegion_ = b;
153 uint32_t targetThread() const { return targetThread_; }
154 bool isThreadSimulatingAny() const {
155 return targetThread_ && targetThread_ == js::oom::GetThreadType() &&
156 !inUnsafeRegion_;
158 bool isThreadSimulating(Kind kind) const {
159 return kind_ == kind && isThreadSimulatingAny();
161 bool isSimulatedFailure(Kind kind) const {
162 if (!isThreadSimulating(kind)) {
163 return false;
165 return counter_ == maxChecks_ || (counter_ > maxChecks_ && failAlways_);
167 bool hadFailure(Kind kind) const {
168 return kind_ == kind && counter_ >= maxChecks_;
170 bool shouldFail(Kind kind) {
171 if (!isThreadSimulating(kind)) {
172 return false;
174 counter_++;
175 if (isSimulatedFailure(kind)) {
176 JS_OOM_CALL_BP_FUNC();
177 return true;
179 return false;
182 void simulateFailureAfter(Kind kind, uint64_t checks, uint32_t thread,
183 bool always);
184 void reset();
186 extern JS_PUBLIC_DATA FailureSimulator simulator;
188 inline bool IsSimulatedOOMAllocation() {
189 return simulator.isSimulatedFailure(FailureSimulator::Kind::OOM);
192 inline bool ShouldFailWithOOM() {
193 return simulator.shouldFail(FailureSimulator::Kind::OOM);
196 inline bool HadSimulatedOOM() {
197 return simulator.hadFailure(FailureSimulator::Kind::OOM);
201 * Out of stack space testing support, similar to OOM testing functions.
204 inline bool IsSimulatedStackOOMCheck() {
205 return simulator.isSimulatedFailure(FailureSimulator::Kind::StackOOM);
208 inline bool ShouldFailWithStackOOM() {
209 return simulator.shouldFail(FailureSimulator::Kind::StackOOM);
212 inline bool HadSimulatedStackOOM() {
213 return simulator.hadFailure(FailureSimulator::Kind::StackOOM);
217 * Interrupt testing support, similar to OOM testing functions.
220 inline bool IsSimulatedInterruptCheck() {
221 return simulator.isSimulatedFailure(FailureSimulator::Kind::Interrupt);
224 inline bool ShouldFailWithInterrupt() {
225 return simulator.shouldFail(FailureSimulator::Kind::Interrupt);
228 inline bool HadSimulatedInterrupt() {
229 return simulator.hadFailure(FailureSimulator::Kind::Interrupt);
232 } /* namespace oom */
233 } /* namespace js */
235 # define JS_OOM_POSSIBLY_FAIL() \
236 do { \
237 if (js::oom::ShouldFailWithOOM()) return nullptr; \
238 } while (0)
240 # define JS_OOM_POSSIBLY_FAIL_BOOL() \
241 do { \
242 if (js::oom::ShouldFailWithOOM()) return false; \
243 } while (0)
245 # define JS_STACK_OOM_POSSIBLY_FAIL() \
246 do { \
247 if (js::oom::ShouldFailWithStackOOM()) return false; \
248 } while (0)
250 # define JS_INTERRUPT_POSSIBLY_FAIL() \
251 do { \
252 if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) { \
253 cx->requestInterrupt(js::InterruptReason::CallbackUrgent); \
254 return cx->handleInterrupt(); \
256 } while (0)
258 # else
260 # define JS_OOM_POSSIBLY_FAIL() \
261 do { \
262 } while (0)
263 # define JS_OOM_POSSIBLY_FAIL_BOOL() \
264 do { \
265 } while (0)
266 # define JS_STACK_OOM_POSSIBLY_FAIL() \
267 do { \
268 } while (0)
269 # define JS_INTERRUPT_POSSIBLY_FAIL() \
270 do { \
271 } while (0)
272 namespace js {
273 namespace oom {
274 static inline bool IsSimulatedOOMAllocation() { return false; }
275 static inline bool ShouldFailWithOOM() { return false; }
276 } /* namespace oom */
277 } /* namespace js */
279 # endif /* DEBUG || JS_OOM_BREAKPOINT */
281 # ifdef FUZZING
282 namespace js {
283 namespace oom {
284 extern JS_PUBLIC_DATA size_t largeAllocLimit;
285 extern void InitLargeAllocLimit();
286 } /* namespace oom */
287 } /* namespace js */
289 # define JS_CHECK_LARGE_ALLOC(x) \
290 do { \
291 if (js::oom::largeAllocLimit && x > js::oom::largeAllocLimit) { \
292 if (getenv("MOZ_FUZZ_CRASH_ON_LARGE_ALLOC")) { \
293 MOZ_CRASH("Large allocation"); \
294 } else { \
295 return nullptr; \
298 } while (0)
299 # else
300 # define JS_CHECK_LARGE_ALLOC(x) \
301 do { \
302 } while (0)
303 # endif
305 namespace js {
307 /* Disable OOM testing in sections which are not OOM safe. */
308 struct MOZ_RAII JS_PUBLIC_DATA AutoEnterOOMUnsafeRegion {
309 MOZ_NORETURN MOZ_COLD void crash(const char* reason) { crash_impl(reason); }
310 MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason) {
311 crash_impl(reason);
314 using AnnotateOOMAllocationSizeCallback = void (*)(size_t);
315 static mozilla::Atomic<AnnotateOOMAllocationSizeCallback, mozilla::Relaxed>
316 annotateOOMSizeCallback;
317 static void setAnnotateOOMAllocationSizeCallback(
318 AnnotateOOMAllocationSizeCallback callback) {
319 annotateOOMSizeCallback = callback;
322 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
323 AutoEnterOOMUnsafeRegion()
324 : oomEnabled_(oom::simulator.isThreadSimulatingAny()) {
325 if (oomEnabled_) {
326 MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this));
327 oom::simulator.setInUnsafeRegion(true);
331 ~AutoEnterOOMUnsafeRegion() {
332 if (oomEnabled_) {
333 oom::simulator.setInUnsafeRegion(false);
334 MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr));
338 private:
339 // Used to catch concurrent use from other threads.
340 static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_;
342 bool oomEnabled_;
343 # endif
344 private:
345 static MOZ_NORETURN MOZ_COLD void crash_impl(const char* reason);
346 static MOZ_NORETURN MOZ_COLD void crash_impl(size_t size, const char* reason);
349 } /* namespace js */
351 // Malloc allocation.
353 namespace js {
355 extern JS_PUBLIC_DATA arena_id_t MallocArena;
356 extern JS_PUBLIC_DATA arena_id_t ArrayBufferContentsArena;
357 extern JS_PUBLIC_DATA arena_id_t StringBufferArena;
359 extern void InitMallocAllocator();
360 extern void ShutDownMallocAllocator();
362 // This is a no-op if built without MOZ_MEMORY and MOZ_DEBUG.
363 extern void AssertJSStringBufferInCorrectArena(const void* ptr);
365 } /* namespace js */
367 static inline void* js_arena_malloc(arena_id_t arena, size_t bytes) {
368 JS_OOM_POSSIBLY_FAIL();
369 JS_CHECK_LARGE_ALLOC(bytes);
370 return moz_arena_malloc(arena, bytes);
373 static inline void* js_malloc(size_t bytes) {
374 return js_arena_malloc(js::MallocArena, bytes);
377 static inline void* js_arena_calloc(arena_id_t arena, size_t bytes) {
378 JS_OOM_POSSIBLY_FAIL();
379 JS_CHECK_LARGE_ALLOC(bytes);
380 return moz_arena_calloc(arena, bytes, 1);
383 static inline void* js_arena_calloc(arena_id_t arena, size_t nmemb,
384 size_t size) {
385 JS_OOM_POSSIBLY_FAIL();
386 JS_CHECK_LARGE_ALLOC(nmemb * size);
387 return moz_arena_calloc(arena, nmemb, size);
390 static inline void* js_calloc(size_t bytes) {
391 return js_arena_calloc(js::MallocArena, bytes);
394 static inline void* js_calloc(size_t nmemb, size_t size) {
395 return js_arena_calloc(js::MallocArena, nmemb, size);
398 static inline void* js_arena_realloc(arena_id_t arena, void* p, size_t bytes) {
399 // realloc() with zero size is not portable, as some implementations may
400 // return nullptr on success and free |p| for this. We assume nullptr
401 // indicates failure and that |p| is still valid.
402 MOZ_ASSERT(bytes != 0);
404 JS_OOM_POSSIBLY_FAIL();
405 JS_CHECK_LARGE_ALLOC(bytes);
406 return moz_arena_realloc(arena, p, bytes);
409 static inline void* js_realloc(void* p, size_t bytes) {
410 return js_arena_realloc(js::MallocArena, p, bytes);
413 static inline void js_free(void* p) {
414 // Bug 1784164: This should call |moz_arena_free(js::MallocArena, p)| but we
415 // currently can't enforce that all memory freed here was allocated by
416 // js_malloc(). All other memory should go through a different allocator and
417 // deallocator.
418 free(p);
420 #endif /* JS_USE_CUSTOM_ALLOCATOR */
422 #include <new>
425 * [SMDOC] Low-level memory management in SpiderMonkey
427 * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these
428 * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's
429 * these symbols.
431 * ** Do not use the builtin C++ operator new and delete: these throw on
432 * error and we cannot override them not to.
434 * Allocation:
436 * - If the lifetime of the allocation is tied to the lifetime of a GC-thing
437 * (that is, finalizing the GC-thing will free the allocation), call one of
438 * the following functions:
440 * JSContext::{pod_malloc,pod_calloc,pod_realloc}
441 * Zone::{pod_malloc,pod_calloc,pod_realloc}
443 * These functions accumulate the number of bytes allocated which is used as
444 * part of the GC-triggering heuristics.
446 * The difference between the JSContext and Zone versions is that the
447 * cx version report an out-of-memory error on OOM. (This follows from the
448 * general SpiderMonkey idiom that a JSContext-taking function reports its
449 * own errors.)
451 * If you don't want to report an error on failure, there are maybe_ versions
452 * of these methods available too, e.g. maybe_pod_malloc.
454 * The methods above use templates to allow allocating memory suitable for an
455 * array of a given type and number of elements. There are _with_extra
456 * versions to allow allocating an area of memory which is larger by a
457 * specified number of bytes, e.g. pod_malloc_with_extra.
459 * These methods are available on a JSRuntime, but calling them is
460 * discouraged. Memory attributed to a runtime can only be reclaimed by full
461 * GCs, and we try to avoid those where possible.
463 * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new
465 * Deallocation:
467 * - Ordinarily, use js_free/js_delete.
469 * - For deallocations during GC finalization, use one of the following
470 * operations on the JS::GCContext provided to the finalizer:
472 * JS::GCContext::{free_,delete_}
476 * Given a class which should provide a 'new' method, add
477 * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
479 * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
480 * or the build will break.
482 #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
483 template <class T, typename... Args> \
484 QUALIFIERS T* MOZ_HEAP_ALLOCATOR NEWNAME(Args&&... args) { \
485 static_assert( \
486 alignof(T) <= alignof(max_align_t), \
487 "over-aligned type is not supported by JS_DECLARE_NEW_METHODS"); \
488 void* memory = ALLOCATOR(sizeof(T)); \
489 return MOZ_LIKELY(memory) ? new (memory) T(std::forward<Args>(args)...) \
490 : nullptr; \
494 * Given a class which should provide a 'new' method that takes an arena as
495 * its first argument, add JS_DECLARE_NEW_ARENA_METHODS
496 * (see js::MallocProvider for an example).
498 * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_ARENA_METHODS,
499 * or the build will break.
501 #define JS_DECLARE_NEW_ARENA_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
502 template <class T, typename... Args> \
503 QUALIFIERS T* MOZ_HEAP_ALLOCATOR NEWNAME(arena_id_t arena, Args&&... args) { \
504 static_assert( \
505 alignof(T) <= alignof(max_align_t), \
506 "over-aligned type is not supported by JS_DECLARE_NEW_ARENA_METHODS"); \
507 void* memory = ALLOCATOR(arena, sizeof(T)); \
508 return MOZ_LIKELY(memory) ? new (memory) T(std::forward<Args>(args)...) \
509 : nullptr; \
513 * Given a class which should provide 'make' methods, add
514 * JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This
515 * method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares
516 * methods that return mozilla::UniquePtr instances that will singly-manage
517 * ownership of the created object.
519 * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS,
520 * or the build will break.
522 #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS) \
523 template <class T, typename... Args> \
524 QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> MOZ_HEAP_ALLOCATOR \
525 MAKENAME(Args&&... args) { \
526 T* ptr = NEWNAME<T>(std::forward<Args>(args)...); \
527 return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
530 JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
531 JS_DECLARE_NEW_ARENA_METHODS(js_arena_new, js_arena_malloc,
532 static MOZ_ALWAYS_INLINE)
534 namespace js {
537 * Calculate the number of bytes needed to allocate |numElems| contiguous
538 * instances of type |T|. Return false if the calculation overflowed.
540 template <typename T>
541 [[nodiscard]] inline bool CalculateAllocSize(size_t numElems,
542 size_t* bytesOut) {
543 *bytesOut = numElems * sizeof(T);
544 return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0;
548 * Calculate the number of bytes needed to allocate a single instance of type
549 * |T| followed by |numExtra| contiguous instances of type |Extra|. Return
550 * false if the calculation overflowed.
552 template <typename T, typename Extra>
553 [[nodiscard]] inline bool CalculateAllocSizeWithExtra(size_t numExtra,
554 size_t* bytesOut) {
555 *bytesOut = sizeof(T) + numExtra * sizeof(Extra);
556 return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 &&
557 *bytesOut >= sizeof(T);
560 } /* namespace js */
562 template <class T>
563 static MOZ_ALWAYS_INLINE void js_delete(const T* p) {
564 if (p) {
565 p->~T();
566 js_free(const_cast<T*>(p));
570 template <class T>
571 static MOZ_ALWAYS_INLINE void js_delete_poison(const T* p) {
572 if (p) {
573 p->~T();
574 memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T));
575 js_free(const_cast<T*>(p));
579 template <class T>
580 static MOZ_ALWAYS_INLINE T* js_pod_arena_malloc(arena_id_t arena,
581 size_t numElems) {
582 size_t bytes;
583 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
584 return nullptr;
586 return static_cast<T*>(js_arena_malloc(arena, bytes));
589 template <class T>
590 static MOZ_ALWAYS_INLINE T* js_pod_malloc(size_t numElems) {
591 return js_pod_arena_malloc<T>(js::MallocArena, numElems);
594 template <class T>
595 static MOZ_ALWAYS_INLINE T* js_pod_arena_calloc(arena_id_t arena,
596 size_t numElems) {
597 size_t bytes;
598 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
599 return nullptr;
601 return static_cast<T*>(js_arena_calloc(arena, bytes, 1));
604 template <class T>
605 static MOZ_ALWAYS_INLINE T* js_pod_calloc(size_t numElems) {
606 return js_pod_arena_calloc<T>(js::MallocArena, numElems);
609 template <class T>
610 static MOZ_ALWAYS_INLINE T* js_pod_arena_realloc(arena_id_t arena, T* prior,
611 size_t oldSize,
612 size_t newSize) {
613 MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
614 size_t bytes;
615 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) {
616 return nullptr;
618 return static_cast<T*>(js_arena_realloc(arena, prior, bytes));
621 template <class T>
622 static MOZ_ALWAYS_INLINE T* js_pod_realloc(T* prior, size_t oldSize,
623 size_t newSize) {
624 return js_pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize);
627 namespace JS {
629 template <typename T>
630 struct DeletePolicy {
631 constexpr DeletePolicy() = default;
633 template <typename U>
634 MOZ_IMPLICIT DeletePolicy(
635 DeletePolicy<U> other,
636 std::enable_if_t<std::is_convertible_v<U*, T*>, int> dummy = 0) {}
638 void operator()(const T* ptr) { js_delete(const_cast<T*>(ptr)); }
641 struct FreePolicy {
642 void operator()(const void* ptr) { js_free(const_cast<void*>(ptr)); }
645 using UniqueChars = mozilla::UniquePtr<char[], JS::FreePolicy>;
646 using UniqueTwoByteChars = mozilla::UniquePtr<char16_t[], JS::FreePolicy>;
647 using UniqueLatin1Chars = mozilla::UniquePtr<JS::Latin1Char[], JS::FreePolicy>;
648 using UniqueWideChars = mozilla::UniquePtr<wchar_t[], JS::FreePolicy>;
650 } // namespace JS
652 /* sixgill annotation defines */
653 #ifndef HAVE_STATIC_ANNOTATIONS
654 # define HAVE_STATIC_ANNOTATIONS
655 # ifdef XGILL_PLUGIN
656 # define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND)))
657 # define STATIC_PRECONDITION_ASSUME(COND) \
658 __attribute__((precondition_assume(#COND)))
659 # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND)))
660 # define STATIC_POSTCONDITION_ASSUME(COND) \
661 __attribute__((postcondition_assume(#COND)))
662 # define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
663 # define STATIC_INVARIANT_ASSUME(COND) \
664 __attribute__((invariant_assume(#COND)))
665 # define STATIC_ASSUME(COND) \
666 JS_BEGIN_MACRO \
667 __attribute__((assume_static(#COND), unused)) int STATIC_PASTE1( \
668 assume_static_, __COUNTER__); \
669 JS_END_MACRO
670 # else /* XGILL_PLUGIN */
671 # define STATIC_PRECONDITION(COND) /* nothing */
672 # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
673 # define STATIC_POSTCONDITION(COND) /* nothing */
674 # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
675 # define STATIC_INVARIANT(COND) /* nothing */
676 # define STATIC_INVARIANT_ASSUME(COND) /* nothing */
677 # define STATIC_ASSUME(COND) \
678 JS_BEGIN_MACRO /* nothing */ \
679 JS_END_MACRO
680 # endif /* XGILL_PLUGIN */
681 # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
682 #endif /* HAVE_STATIC_ANNOTATIONS */
684 #endif /* js_Utility_h */