Bug 1692971 [wpt PR 27638] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / js / public / Utility.h
blobb4700672ad59417ec1ddc5df3064f4ea05faa99a
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, // 2
60 THREAD_TYPE_ION, // 3
61 THREAD_TYPE_PARSE, // 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_TIER2, // 9
67 THREAD_TYPE_WORKER, // 10
68 THREAD_TYPE_MAX // Used to check shell function arguments
72 * Threads need a universal way to dispatch from xpcom thread pools,
73 * so having objects inherit from this struct enables
74 * mozilla::HelperThreadPool's runnable handler to call runTask() on each type.
76 struct RunnableTask {
77 virtual ThreadType threadType() = 0;
78 virtual void runTask() = 0;
79 virtual ~RunnableTask() = default;
82 namespace oom {
85 * Theads are tagged only in certain debug contexts. Notably, to make testing
86 * OOM in certain helper threads more effective, we allow restricting the OOM
87 * testing to a certain helper thread type. This allows us to fail e.g. in
88 * off-thread script parsing without causing an OOM in the active thread first.
90 * Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation
91 * is in util/Utility.cpp.
93 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
95 // Define the range of threads tested by simulated OOM testing and the
96 // like. Testing worker threads is not supported.
97 const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN;
98 const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_TIER2;
100 extern bool InitThreadType(void);
101 extern void SetThreadType(ThreadType);
102 extern JS_FRIEND_API uint32_t GetThreadType(void);
104 # else
106 inline bool InitThreadType(void) { return true; }
107 inline void SetThreadType(ThreadType t){};
108 inline uint32_t GetThreadType(void) { return 0; }
109 inline uint32_t GetAllocationThreadType(void) { return 0; }
110 inline uint32_t GetStackCheckThreadType(void) { return 0; }
111 inline uint32_t GetInterruptCheckThreadType(void) { return 0; }
113 # endif
115 } /* namespace oom */
116 } /* namespace js */
118 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
120 # ifdef JS_OOM_BREAKPOINT
121 # if defined(_MSC_VER)
122 static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() {
123 __asm {}
126 # else
127 static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
128 # endif
129 # define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint()
130 # else
131 # define JS_OOM_CALL_BP_FUNC() \
132 do { \
133 } while (0)
134 # endif
136 namespace js {
137 namespace oom {
140 * Out of memory testing support. We provide various testing functions to
141 * simulate OOM conditions and so we can test that they are handled correctly.
143 class FailureSimulator {
144 public:
145 enum class Kind : uint8_t { Nothing, OOM, StackOOM, Interrupt };
147 private:
148 Kind kind_ = Kind::Nothing;
149 uint32_t targetThread_ = 0;
150 uint64_t maxChecks_ = UINT64_MAX;
151 uint64_t counter_ = 0;
152 bool failAlways_ = true;
153 bool inUnsafeRegion_ = false;
155 public:
156 uint64_t maxChecks() const { return maxChecks_; }
157 uint64_t counter() const { return counter_; }
158 void setInUnsafeRegion(bool b) {
159 MOZ_ASSERT(inUnsafeRegion_ != b);
160 inUnsafeRegion_ = b;
162 uint32_t targetThread() const { return targetThread_; }
163 bool isThreadSimulatingAny() const {
164 return targetThread_ && targetThread_ == js::oom::GetThreadType() &&
165 !inUnsafeRegion_;
167 bool isThreadSimulating(Kind kind) const {
168 return kind_ == kind && isThreadSimulatingAny();
170 bool isSimulatedFailure(Kind kind) const {
171 if (!isThreadSimulating(kind)) {
172 return false;
174 return counter_ == maxChecks_ || (counter_ > maxChecks_ && failAlways_);
176 bool hadFailure(Kind kind) const {
177 return kind_ == kind && counter_ >= maxChecks_;
179 bool shouldFail(Kind kind) {
180 if (!isThreadSimulating(kind)) {
181 return false;
183 counter_++;
184 if (isSimulatedFailure(kind)) {
185 JS_OOM_CALL_BP_FUNC();
186 return true;
188 return false;
191 void simulateFailureAfter(Kind kind, uint64_t checks, uint32_t thread,
192 bool always);
193 void reset();
195 extern JS_PUBLIC_DATA FailureSimulator simulator;
197 inline bool IsSimulatedOOMAllocation() {
198 return simulator.isSimulatedFailure(FailureSimulator::Kind::OOM);
201 inline bool ShouldFailWithOOM() {
202 return simulator.shouldFail(FailureSimulator::Kind::OOM);
205 inline bool HadSimulatedOOM() {
206 return simulator.hadFailure(FailureSimulator::Kind::OOM);
210 * Out of stack space testing support, similar to OOM testing functions.
213 inline bool IsSimulatedStackOOMCheck() {
214 return simulator.isSimulatedFailure(FailureSimulator::Kind::StackOOM);
217 inline bool ShouldFailWithStackOOM() {
218 return simulator.shouldFail(FailureSimulator::Kind::StackOOM);
221 inline bool HadSimulatedStackOOM() {
222 return simulator.hadFailure(FailureSimulator::Kind::StackOOM);
226 * Interrupt testing support, similar to OOM testing functions.
229 inline bool IsSimulatedInterruptCheck() {
230 return simulator.isSimulatedFailure(FailureSimulator::Kind::Interrupt);
233 inline bool ShouldFailWithInterrupt() {
234 return simulator.shouldFail(FailureSimulator::Kind::Interrupt);
237 inline bool HadSimulatedInterrupt() {
238 return simulator.hadFailure(FailureSimulator::Kind::Interrupt);
241 } /* namespace oom */
242 } /* namespace js */
244 # define JS_OOM_POSSIBLY_FAIL() \
245 do { \
246 if (js::oom::ShouldFailWithOOM()) return nullptr; \
247 } while (0)
249 # define JS_OOM_POSSIBLY_FAIL_BOOL() \
250 do { \
251 if (js::oom::ShouldFailWithOOM()) return false; \
252 } while (0)
254 # define JS_STACK_OOM_POSSIBLY_FAIL() \
255 do { \
256 if (js::oom::ShouldFailWithStackOOM()) return false; \
257 } while (0)
259 # define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \
260 do { \
261 if (js::oom::ShouldFailWithStackOOM()) { \
262 ReportOverRecursed(cx); \
263 return false; \
265 } while (0)
267 # define JS_INTERRUPT_POSSIBLY_FAIL() \
268 do { \
269 if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) { \
270 cx->requestInterrupt(js::InterruptReason::CallbackUrgent); \
271 return cx->handleInterrupt(); \
273 } while (0)
275 # else
277 # define JS_OOM_POSSIBLY_FAIL() \
278 do { \
279 } while (0)
280 # define JS_OOM_POSSIBLY_FAIL_BOOL() \
281 do { \
282 } while (0)
283 # define JS_STACK_OOM_POSSIBLY_FAIL() \
284 do { \
285 } while (0)
286 # define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \
287 do { \
288 } while (0)
289 # define JS_INTERRUPT_POSSIBLY_FAIL() \
290 do { \
291 } while (0)
292 namespace js {
293 namespace oom {
294 static inline bool IsSimulatedOOMAllocation() { return false; }
295 static inline bool ShouldFailWithOOM() { return false; }
296 } /* namespace oom */
297 } /* namespace js */
299 # endif /* DEBUG || JS_OOM_BREAKPOINT */
301 # ifdef FUZZING
302 namespace js {
303 namespace oom {
304 extern JS_PUBLIC_DATA size_t largeAllocLimit;
305 extern void InitLargeAllocLimit();
306 } /* namespace oom */
307 } /* namespace js */
309 # define JS_CHECK_LARGE_ALLOC(x) \
310 do { \
311 if (js::oom::largeAllocLimit && x > js::oom::largeAllocLimit) { \
312 if (getenv("MOZ_FUZZ_CRASH_ON_LARGE_ALLOC")) { \
313 MOZ_CRASH("Large allocation"); \
314 } else { \
315 return nullptr; \
318 } while (0)
319 # else
320 # define JS_CHECK_LARGE_ALLOC(x) \
321 do { \
322 } while (0)
323 # endif
325 namespace js {
327 /* Disable OOM testing in sections which are not OOM safe. */
328 struct MOZ_RAII JS_PUBLIC_DATA AutoEnterOOMUnsafeRegion {
329 MOZ_NORETURN MOZ_COLD void crash(const char* reason);
330 MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason);
332 using AnnotateOOMAllocationSizeCallback = void (*)(size_t);
333 static mozilla::Atomic<AnnotateOOMAllocationSizeCallback, mozilla::Relaxed>
334 annotateOOMSizeCallback;
335 static void setAnnotateOOMAllocationSizeCallback(
336 AnnotateOOMAllocationSizeCallback callback) {
337 annotateOOMSizeCallback = callback;
340 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
341 AutoEnterOOMUnsafeRegion()
342 : oomEnabled_(oom::simulator.isThreadSimulatingAny()) {
343 if (oomEnabled_) {
344 MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this));
345 oom::simulator.setInUnsafeRegion(true);
349 ~AutoEnterOOMUnsafeRegion() {
350 if (oomEnabled_) {
351 oom::simulator.setInUnsafeRegion(false);
352 MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr));
356 private:
357 // Used to catch concurrent use from other threads.
358 static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_;
360 bool oomEnabled_;
361 # endif
364 } /* namespace js */
366 // Malloc allocation.
368 namespace js {
370 extern JS_PUBLIC_DATA arena_id_t MallocArena;
371 extern JS_PUBLIC_DATA arena_id_t ArrayBufferContentsArena;
372 extern JS_PUBLIC_DATA arena_id_t StringBufferArena;
374 extern void InitMallocAllocator();
375 extern void ShutDownMallocAllocator();
377 // This is a no-op if built without MOZ_MEMORY and MOZ_DEBUG.
378 extern void AssertJSStringBufferInCorrectArena(const void* ptr);
380 } /* namespace js */
382 static inline void* js_arena_malloc(arena_id_t arena, size_t bytes) {
383 JS_OOM_POSSIBLY_FAIL();
384 JS_CHECK_LARGE_ALLOC(bytes);
385 return moz_arena_malloc(arena, bytes);
388 static inline void* js_malloc(size_t bytes) {
389 return js_arena_malloc(js::MallocArena, bytes);
392 static inline void* js_arena_calloc(arena_id_t arena, size_t bytes) {
393 JS_OOM_POSSIBLY_FAIL();
394 JS_CHECK_LARGE_ALLOC(bytes);
395 return moz_arena_calloc(arena, bytes, 1);
398 static inline void* js_arena_calloc(arena_id_t arena, size_t nmemb,
399 size_t size) {
400 JS_OOM_POSSIBLY_FAIL();
401 JS_CHECK_LARGE_ALLOC(nmemb * size);
402 return moz_arena_calloc(arena, nmemb, size);
405 static inline void* js_calloc(size_t bytes) {
406 return js_arena_calloc(js::MallocArena, bytes);
409 static inline void* js_calloc(size_t nmemb, size_t size) {
410 return js_arena_calloc(js::MallocArena, nmemb, size);
413 static inline void* js_arena_realloc(arena_id_t arena, void* p, size_t bytes) {
414 // realloc() with zero size is not portable, as some implementations may
415 // return nullptr on success and free |p| for this. We assume nullptr
416 // indicates failure and that |p| is still valid.
417 MOZ_ASSERT(bytes != 0);
419 JS_OOM_POSSIBLY_FAIL();
420 JS_CHECK_LARGE_ALLOC(bytes);
421 return moz_arena_realloc(arena, p, bytes);
424 static inline void* js_realloc(void* p, size_t bytes) {
425 return js_arena_realloc(js::MallocArena, p, bytes);
428 static inline void js_free(void* p) {
429 // TODO: This should call |moz_arena_free(js::MallocArena, p)| but we
430 // currently can't enforce that all memory freed here was allocated by
431 // js_malloc().
432 free(p);
434 #endif /* JS_USE_CUSTOM_ALLOCATOR */
436 #include <new>
439 * [SMDOC] Low-level memory management in SpiderMonkey
441 * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these
442 * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's
443 * these symbols.
445 * ** Do not use the builtin C++ operator new and delete: these throw on
446 * error and we cannot override them not to.
448 * Allocation:
450 * - If the lifetime of the allocation is tied to the lifetime of a GC-thing
451 * (that is, finalizing the GC-thing will free the allocation), call one of
452 * the following functions:
454 * JSContext::{pod_malloc,pod_calloc,pod_realloc}
455 * Zone::{pod_malloc,pod_calloc,pod_realloc}
457 * These functions accumulate the number of bytes allocated which is used as
458 * part of the GC-triggering heuristics.
460 * The difference between the JSContext and Zone versions is that the
461 * cx version report an out-of-memory error on OOM. (This follows from the
462 * general SpiderMonkey idiom that a JSContext-taking function reports its
463 * own errors.)
465 * If you don't want to report an error on failure, there are maybe_ versions
466 * of these methods available too, e.g. maybe_pod_malloc.
468 * The methods above use templates to allow allocating memory suitable for an
469 * array of a given type and number of elements. There are _with_extra
470 * versions to allow allocating an area of memory which is larger by a
471 * specified number of bytes, e.g. pod_malloc_with_extra.
473 * These methods are available on a JSRuntime, but calling them is
474 * discouraged. Memory attributed to a runtime can only be reclaimed by full
475 * GCs, and we try to avoid those where possible.
477 * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new
479 * Deallocation:
481 * - Ordinarily, use js_free/js_delete.
483 * - For deallocations during GC finalization, use one of the following
484 * operations on the JSFreeOp provided to the finalizer:
486 * JSFreeOp::{free_,delete_}
490 * Given a class which should provide a 'new' method, add
491 * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
493 * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
494 * or the build will break.
496 #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
497 template <class T, typename... Args> \
498 QUALIFIERS T* MOZ_HEAP_ALLOCATOR NEWNAME(Args&&... args) { \
499 void* memory = ALLOCATOR(sizeof(T)); \
500 return MOZ_LIKELY(memory) ? new (memory) T(std::forward<Args>(args)...) \
501 : nullptr; \
505 * Given a class which should provide a 'new' method that takes an arena as
506 * its first argument, add JS_DECLARE_NEW_ARENA_METHODS
507 * (see js::MallocProvider for an example).
509 * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_ARENA_METHODS,
510 * or the build will break.
512 #define JS_DECLARE_NEW_ARENA_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
513 template <class T, typename... Args> \
514 QUALIFIERS T* MOZ_HEAP_ALLOCATOR NEWNAME(arena_id_t arena, Args&&... args) { \
515 void* memory = ALLOCATOR(arena, sizeof(T)); \
516 return MOZ_LIKELY(memory) ? new (memory) T(std::forward<Args>(args)...) \
517 : nullptr; \
521 * Given a class which should provide 'make' methods, add
522 * JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This
523 * method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares
524 * methods that return mozilla::UniquePtr instances that will singly-manage
525 * ownership of the created object.
527 * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS,
528 * or the build will break.
530 #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS) \
531 template <class T, typename... Args> \
532 QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> MOZ_HEAP_ALLOCATOR \
533 MAKENAME(Args&&... args) { \
534 T* ptr = NEWNAME<T>(std::forward<Args>(args)...); \
535 return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
538 JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
539 JS_DECLARE_NEW_ARENA_METHODS(js_arena_new, js_arena_malloc,
540 static MOZ_ALWAYS_INLINE)
542 namespace js {
545 * Calculate the number of bytes needed to allocate |numElems| contiguous
546 * instances of type |T|. Return false if the calculation overflowed.
548 template <typename T>
549 [[nodiscard]] inline bool CalculateAllocSize(size_t numElems,
550 size_t* bytesOut) {
551 *bytesOut = numElems * sizeof(T);
552 return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0;
556 * Calculate the number of bytes needed to allocate a single instance of type
557 * |T| followed by |numExtra| contiguous instances of type |Extra|. Return
558 * false if the calculation overflowed.
560 template <typename T, typename Extra>
561 [[nodiscard]] inline bool CalculateAllocSizeWithExtra(size_t numExtra,
562 size_t* bytesOut) {
563 *bytesOut = sizeof(T) + numExtra * sizeof(Extra);
564 return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 &&
565 *bytesOut >= sizeof(T);
568 } /* namespace js */
570 template <class T>
571 static MOZ_ALWAYS_INLINE void js_delete(const T* p) {
572 if (p) {
573 p->~T();
574 js_free(const_cast<T*>(p));
578 template <class T>
579 static MOZ_ALWAYS_INLINE void js_delete_poison(const T* p) {
580 if (p) {
581 p->~T();
582 memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T));
583 js_free(const_cast<T*>(p));
587 template <class T>
588 static MOZ_ALWAYS_INLINE T* js_pod_arena_malloc(arena_id_t arena,
589 size_t numElems) {
590 size_t bytes;
591 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
592 return nullptr;
594 return static_cast<T*>(js_arena_malloc(arena, bytes));
597 template <class T>
598 static MOZ_ALWAYS_INLINE T* js_pod_malloc(size_t numElems) {
599 return js_pod_arena_malloc<T>(js::MallocArena, numElems);
602 template <class T>
603 static MOZ_ALWAYS_INLINE T* js_pod_arena_calloc(arena_id_t arena,
604 size_t numElems) {
605 size_t bytes;
606 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
607 return nullptr;
609 return static_cast<T*>(js_arena_calloc(arena, bytes, 1));
612 template <class T>
613 static MOZ_ALWAYS_INLINE T* js_pod_calloc(size_t numElems) {
614 return js_pod_arena_calloc<T>(js::MallocArena, numElems);
617 template <class T>
618 static MOZ_ALWAYS_INLINE T* js_pod_arena_realloc(arena_id_t arena, T* prior,
619 size_t oldSize,
620 size_t newSize) {
621 MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
622 size_t bytes;
623 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) {
624 return nullptr;
626 return static_cast<T*>(js_arena_realloc(arena, prior, bytes));
629 template <class T>
630 static MOZ_ALWAYS_INLINE T* js_pod_realloc(T* prior, size_t oldSize,
631 size_t newSize) {
632 return js_pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize);
635 namespace JS {
637 template <typename T>
638 struct DeletePolicy {
639 constexpr DeletePolicy() = default;
641 template <typename U>
642 MOZ_IMPLICIT DeletePolicy(
643 DeletePolicy<U> other,
644 std::enable_if_t<std::is_convertible_v<U*, T*>, int> dummy = 0) {}
646 void operator()(const T* ptr) { js_delete(const_cast<T*>(ptr)); }
649 struct FreePolicy {
650 void operator()(const void* ptr) { js_free(const_cast<void*>(ptr)); }
653 typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
654 typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
655 typedef mozilla::UniquePtr<JS::Latin1Char[], JS::FreePolicy> UniqueLatin1Chars;
657 } // namespace JS
659 /* sixgill annotation defines */
660 #ifndef HAVE_STATIC_ANNOTATIONS
661 # define HAVE_STATIC_ANNOTATIONS
662 # ifdef XGILL_PLUGIN
663 # define STATIC_PRECONDITION(COND) __attribute__((precondition(# COND)))
664 # define STATIC_PRECONDITION_ASSUME(COND) \
665 __attribute__((precondition_assume(#COND)))
666 # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(# COND)))
667 # define STATIC_POSTCONDITION_ASSUME(COND) \
668 __attribute__((postcondition_assume(#COND)))
669 # define STATIC_INVARIANT(COND) __attribute__((invariant(# COND)))
670 # define STATIC_INVARIANT_ASSUME(COND) \
671 __attribute__((invariant_assume(#COND)))
672 # define STATIC_ASSUME(COND) \
673 JS_BEGIN_MACRO \
674 __attribute__((assume_static(#COND), unused)) int STATIC_PASTE1( \
675 assume_static_, __COUNTER__); \
676 JS_END_MACRO
677 # else /* XGILL_PLUGIN */
678 # define STATIC_PRECONDITION(COND) /* nothing */
679 # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
680 # define STATIC_POSTCONDITION(COND) /* nothing */
681 # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
682 # define STATIC_INVARIANT(COND) /* nothing */
683 # define STATIC_INVARIANT_ASSUME(COND) /* nothing */
684 # define STATIC_ASSUME(COND) \
685 JS_BEGIN_MACRO /* nothing */ \
686 JS_END_MACRO
687 # endif /* XGILL_PLUGIN */
688 # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
689 #endif /* HAVE_STATIC_ANNOTATIONS */
691 #endif /* js_Utility_h */