Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | /* Implementations of runtime and static assertion macros for C and C++. */ |
michael@0 | 8 | |
michael@0 | 9 | #ifndef mozilla_Assertions_h |
michael@0 | 10 | #define mozilla_Assertions_h |
michael@0 | 11 | |
michael@0 | 12 | #include "mozilla/Attributes.h" |
michael@0 | 13 | #include "mozilla/Compiler.h" |
michael@0 | 14 | #include "mozilla/Likely.h" |
michael@0 | 15 | #include "mozilla/MacroArgs.h" |
michael@0 | 16 | |
michael@0 | 17 | #include <stddef.h> |
michael@0 | 18 | #include <stdio.h> |
michael@0 | 19 | #include <stdlib.h> |
michael@0 | 20 | #ifdef WIN32 |
michael@0 | 21 | /* |
michael@0 | 22 | * TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which |
michael@0 | 23 | * further depends on <windef.h>. We hardcode these few definitions manually |
michael@0 | 24 | * because those headers clutter the global namespace with a significant |
michael@0 | 25 | * number of undesired macros and symbols. |
michael@0 | 26 | */ |
michael@0 | 27 | # ifdef __cplusplus |
michael@0 | 28 | extern "C" { |
michael@0 | 29 | # endif |
michael@0 | 30 | __declspec(dllimport) int __stdcall |
michael@0 | 31 | TerminateProcess(void* hProcess, unsigned int uExitCode); |
michael@0 | 32 | __declspec(dllimport) void* __stdcall GetCurrentProcess(void); |
michael@0 | 33 | # ifdef __cplusplus |
michael@0 | 34 | } |
michael@0 | 35 | # endif |
michael@0 | 36 | #else |
michael@0 | 37 | # include <signal.h> |
michael@0 | 38 | #endif |
michael@0 | 39 | #ifdef ANDROID |
michael@0 | 40 | # include <android/log.h> |
michael@0 | 41 | #endif |
michael@0 | 42 | |
michael@0 | 43 | /* |
michael@0 | 44 | * MOZ_STATIC_ASSERT may be used to assert a condition *at compile time* in C. |
michael@0 | 45 | * In C++11, static_assert is provided by the compiler to the same effect. |
michael@0 | 46 | * This can be useful when you make certain assumptions about what must hold for |
michael@0 | 47 | * optimal, or even correct, behavior. For example, you might assert that the |
michael@0 | 48 | * size of a struct is a multiple of the target architecture's word size: |
michael@0 | 49 | * |
michael@0 | 50 | * struct S { ... }; |
michael@0 | 51 | * // C |
michael@0 | 52 | * MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0, |
michael@0 | 53 | * "S should be a multiple of word size for efficiency"); |
michael@0 | 54 | * // C++11 |
michael@0 | 55 | * static_assert(sizeof(S) % sizeof(size_t) == 0, |
michael@0 | 56 | * "S should be a multiple of word size for efficiency"); |
michael@0 | 57 | * |
michael@0 | 58 | * This macro can be used in any location where both an extern declaration and a |
michael@0 | 59 | * typedef could be used. |
michael@0 | 60 | */ |
michael@0 | 61 | #ifndef __cplusplus |
michael@0 | 62 | /* |
michael@0 | 63 | * Some of the definitions below create an otherwise-unused typedef. This |
michael@0 | 64 | * triggers compiler warnings with some versions of gcc, so mark the typedefs |
michael@0 | 65 | * as permissibly-unused to disable the warnings. |
michael@0 | 66 | */ |
michael@0 | 67 | # if defined(__GNUC__) |
michael@0 | 68 | # define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) |
michael@0 | 69 | # else |
michael@0 | 70 | # define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */ |
michael@0 | 71 | # endif |
michael@0 | 72 | # define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y |
michael@0 | 73 | # define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y) |
michael@0 | 74 | # if defined(__SUNPRO_CC) |
michael@0 | 75 | /* |
michael@0 | 76 | * The Sun Studio C++ compiler is buggy when declaring, inside a function, |
michael@0 | 77 | * another extern'd function with an array argument whose length contains a |
michael@0 | 78 | * sizeof, triggering the error message "sizeof expression not accepted as |
michael@0 | 79 | * size of array parameter". This bug (6688515, not public yet) would hit |
michael@0 | 80 | * defining moz_static_assert as a function, so we always define an extern |
michael@0 | 81 | * array for Sun Studio. |
michael@0 | 82 | * |
michael@0 | 83 | * We include the line number in the symbol name in a best-effort attempt |
michael@0 | 84 | * to avoid conflicts (see below). |
michael@0 | 85 | */ |
michael@0 | 86 | # define MOZ_STATIC_ASSERT(cond, reason) \ |
michael@0 | 87 | extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1] |
michael@0 | 88 | # elif defined(__COUNTER__) |
michael@0 | 89 | /* |
michael@0 | 90 | * If there was no preferred alternative, use a compiler-agnostic version. |
michael@0 | 91 | * |
michael@0 | 92 | * Note that the non-__COUNTER__ version has a bug in C++: it can't be used |
michael@0 | 93 | * in both |extern "C"| and normal C++ in the same translation unit. (Alas |
michael@0 | 94 | * |extern "C"| isn't allowed in a function.) The only affected compiler |
michael@0 | 95 | * we really care about is gcc 4.2. For that compiler and others like it, |
michael@0 | 96 | * we include the line number in the function name to do the best we can to |
michael@0 | 97 | * avoid conflicts. These should be rare: a conflict would require use of |
michael@0 | 98 | * MOZ_STATIC_ASSERT on the same line in separate files in the same |
michael@0 | 99 | * translation unit, *and* the uses would have to be in code with |
michael@0 | 100 | * different linkage, *and* the first observed use must be in C++-linkage |
michael@0 | 101 | * code. |
michael@0 | 102 | */ |
michael@0 | 103 | # define MOZ_STATIC_ASSERT(cond, reason) \ |
michael@0 | 104 | typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE |
michael@0 | 105 | # else |
michael@0 | 106 | # define MOZ_STATIC_ASSERT(cond, reason) \ |
michael@0 | 107 | extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE |
michael@0 | 108 | # endif |
michael@0 | 109 | |
michael@0 | 110 | #define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason) |
michael@0 | 111 | #else |
michael@0 | 112 | #define MOZ_STATIC_ASSERT_IF(cond, expr, reason) static_assert(!(cond) || (expr), reason) |
michael@0 | 113 | #endif |
michael@0 | 114 | |
michael@0 | 115 | #ifdef __cplusplus |
michael@0 | 116 | extern "C" { |
michael@0 | 117 | #endif |
michael@0 | 118 | |
michael@0 | 119 | /* |
michael@0 | 120 | * Prints |s| as an assertion failure (using file and ln as the location of the |
michael@0 | 121 | * assertion) to the standard debug-output channel. |
michael@0 | 122 | * |
michael@0 | 123 | * Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This |
michael@0 | 124 | * method is primarily for internal use in this header, and only secondarily |
michael@0 | 125 | * for use in implementing release-build assertions. |
michael@0 | 126 | */ |
michael@0 | 127 | static MOZ_ALWAYS_INLINE void |
michael@0 | 128 | MOZ_ReportAssertionFailure(const char* s, const char* file, int ln) |
michael@0 | 129 | { |
michael@0 | 130 | #ifdef ANDROID |
michael@0 | 131 | __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", |
michael@0 | 132 | "Assertion failure: %s, at %s:%d\n", s, file, ln); |
michael@0 | 133 | #else |
michael@0 | 134 | fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); |
michael@0 | 135 | fflush(stderr); |
michael@0 | 136 | #endif |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | static MOZ_ALWAYS_INLINE void |
michael@0 | 140 | MOZ_ReportCrash(const char* s, const char* file, int ln) |
michael@0 | 141 | { |
michael@0 | 142 | #ifdef ANDROID |
michael@0 | 143 | __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH", |
michael@0 | 144 | "Hit MOZ_CRASH(%s) at %s:%d\n", s, file, ln); |
michael@0 | 145 | #else |
michael@0 | 146 | fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", s, file, ln); |
michael@0 | 147 | fflush(stderr); |
michael@0 | 148 | #endif |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | /** |
michael@0 | 152 | * MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should |
michael@0 | 153 | * call MOZ_CRASH instead. |
michael@0 | 154 | */ |
michael@0 | 155 | #if defined(_MSC_VER) |
michael@0 | 156 | /* |
michael@0 | 157 | * On MSVC use the __debugbreak compiler intrinsic, which produces an inline |
michael@0 | 158 | * (not nested in a system function) breakpoint. This distinctively invokes |
michael@0 | 159 | * Breakpad without requiring system library symbols on all stack-processing |
michael@0 | 160 | * machines, as a nested breakpoint would require. |
michael@0 | 161 | * |
michael@0 | 162 | * We use TerminateProcess with the exit code aborting would generate |
michael@0 | 163 | * because we don't want to invoke atexit handlers, destructors, library |
michael@0 | 164 | * unload handlers, and so on when our process might be in a compromised |
michael@0 | 165 | * state. |
michael@0 | 166 | * |
michael@0 | 167 | * We don't use abort() because it'd cause Windows to annoyingly pop up the |
michael@0 | 168 | * process error dialog multiple times. See bug 345118 and bug 426163. |
michael@0 | 169 | * |
michael@0 | 170 | * We follow TerminateProcess() with a call to MOZ_NoReturn() so that the |
michael@0 | 171 | * compiler doesn't hassle us to provide a return statement after a |
michael@0 | 172 | * MOZ_REALLY_CRASH() call. |
michael@0 | 173 | * |
michael@0 | 174 | * (Technically these are Windows requirements, not MSVC requirements. But |
michael@0 | 175 | * practically you need MSVC for debugging, and we only ship builds created |
michael@0 | 176 | * by MSVC, so doing it this way reduces complexity.) |
michael@0 | 177 | */ |
michael@0 | 178 | |
michael@0 | 179 | __declspec(noreturn) __inline void MOZ_NoReturn() {} |
michael@0 | 180 | |
michael@0 | 181 | # ifdef __cplusplus |
michael@0 | 182 | # define MOZ_REALLY_CRASH() \ |
michael@0 | 183 | do { \ |
michael@0 | 184 | ::__debugbreak(); \ |
michael@0 | 185 | *((volatile int*) NULL) = 123; \ |
michael@0 | 186 | ::TerminateProcess(::GetCurrentProcess(), 3); \ |
michael@0 | 187 | ::MOZ_NoReturn(); \ |
michael@0 | 188 | } while (0) |
michael@0 | 189 | # else |
michael@0 | 190 | # define MOZ_REALLY_CRASH() \ |
michael@0 | 191 | do { \ |
michael@0 | 192 | __debugbreak(); \ |
michael@0 | 193 | *((volatile int*) NULL) = 123; \ |
michael@0 | 194 | TerminateProcess(GetCurrentProcess(), 3); \ |
michael@0 | 195 | MOZ_NoReturn(); \ |
michael@0 | 196 | } while (0) |
michael@0 | 197 | # endif |
michael@0 | 198 | #else |
michael@0 | 199 | # ifdef __cplusplus |
michael@0 | 200 | # define MOZ_REALLY_CRASH() \ |
michael@0 | 201 | do { \ |
michael@0 | 202 | *((volatile int*) NULL) = 123; \ |
michael@0 | 203 | ::abort(); \ |
michael@0 | 204 | } while (0) |
michael@0 | 205 | # else |
michael@0 | 206 | # define MOZ_REALLY_CRASH() \ |
michael@0 | 207 | do { \ |
michael@0 | 208 | *((volatile int*) NULL) = 123; \ |
michael@0 | 209 | abort(); \ |
michael@0 | 210 | } while (0) |
michael@0 | 211 | # endif |
michael@0 | 212 | #endif |
michael@0 | 213 | |
michael@0 | 214 | /* |
michael@0 | 215 | * MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a |
michael@0 | 216 | * Breakpad-compatible way, in both debug and release builds. |
michael@0 | 217 | * |
michael@0 | 218 | * MOZ_CRASH is a good solution for "handling" failure cases when you're |
michael@0 | 219 | * unwilling or unable to handle them more cleanly -- for OOM, for likely memory |
michael@0 | 220 | * corruption, and so on. It's also a good solution if you need safe behavior |
michael@0 | 221 | * in release builds as well as debug builds. But if the failure is one that |
michael@0 | 222 | * should be debugged and fixed, MOZ_ASSERT is generally preferable. |
michael@0 | 223 | * |
michael@0 | 224 | * The optional explanation-string, if provided, must be a string literal |
michael@0 | 225 | * explaining why we're crashing. This argument is intended for use with |
michael@0 | 226 | * MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's |
michael@0 | 227 | * obvious why we're crashing. |
michael@0 | 228 | * |
michael@0 | 229 | * If we're a DEBUG build and we crash at a MOZ_CRASH which provides an |
michael@0 | 230 | * explanation-string, we print the string to stderr. Otherwise, we don't |
michael@0 | 231 | * print anything; this is because we want MOZ_CRASH to be 100% safe in release |
michael@0 | 232 | * builds, and it's hard to print to stderr safely when memory might have been |
michael@0 | 233 | * corrupted. |
michael@0 | 234 | */ |
michael@0 | 235 | #ifndef DEBUG |
michael@0 | 236 | # define MOZ_CRASH(...) MOZ_REALLY_CRASH() |
michael@0 | 237 | #else |
michael@0 | 238 | # define MOZ_CRASH(...) \ |
michael@0 | 239 | do { \ |
michael@0 | 240 | MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ |
michael@0 | 241 | MOZ_REALLY_CRASH(); \ |
michael@0 | 242 | } while(0) |
michael@0 | 243 | #endif |
michael@0 | 244 | |
michael@0 | 245 | #ifdef __cplusplus |
michael@0 | 246 | } /* extern "C" */ |
michael@0 | 247 | #endif |
michael@0 | 248 | |
michael@0 | 249 | /* |
michael@0 | 250 | * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in |
michael@0 | 251 | * debug builds. If it is, execution continues. Otherwise, an error message |
michael@0 | 252 | * including the expression and the explanation-string (if provided) is printed, |
michael@0 | 253 | * an attempt is made to invoke any existing debugger, and execution halts. |
michael@0 | 254 | * MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition |
michael@0 | 255 | * which can correctly be falsy. |
michael@0 | 256 | * |
michael@0 | 257 | * The optional explanation-string, if provided, must be a string literal |
michael@0 | 258 | * explaining the assertion. It is intended for use with assertions whose |
michael@0 | 259 | * correctness or rationale is non-obvious, and for assertions where the "real" |
michael@0 | 260 | * condition being tested is best described prosaically. Don't provide an |
michael@0 | 261 | * explanation if it's not actually helpful. |
michael@0 | 262 | * |
michael@0 | 263 | * // No explanation needed: pointer arguments often must not be NULL. |
michael@0 | 264 | * MOZ_ASSERT(arg); |
michael@0 | 265 | * |
michael@0 | 266 | * // An explanation can be helpful to explain exactly how we know an |
michael@0 | 267 | * // assertion is valid. |
michael@0 | 268 | * MOZ_ASSERT(state == WAITING_FOR_RESPONSE, |
michael@0 | 269 | * "given that <thingA> and <thingB>, we must have..."); |
michael@0 | 270 | * |
michael@0 | 271 | * // Or it might disambiguate multiple identical (save for their location) |
michael@0 | 272 | * // assertions of the same expression. |
michael@0 | 273 | * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), |
michael@0 | 274 | * "we already set [[PrimitiveThis]] for this Boolean object"); |
michael@0 | 275 | * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), |
michael@0 | 276 | * "we already set [[PrimitiveThis]] for this String object"); |
michael@0 | 277 | * |
michael@0 | 278 | * MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs |
michael@0 | 279 | * *only* during debugging, not "in the field". If you want the latter, use |
michael@0 | 280 | * MOZ_RELEASE_ASSERT, which applies to non-debug builds as well. |
michael@0 | 281 | */ |
michael@0 | 282 | |
michael@0 | 283 | /* First the single-argument form. */ |
michael@0 | 284 | #define MOZ_ASSERT_HELPER1(expr) \ |
michael@0 | 285 | do { \ |
michael@0 | 286 | if (MOZ_UNLIKELY(!(expr))) { \ |
michael@0 | 287 | MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ |
michael@0 | 288 | MOZ_REALLY_CRASH(); \ |
michael@0 | 289 | } \ |
michael@0 | 290 | } while (0) |
michael@0 | 291 | /* Now the two-argument form. */ |
michael@0 | 292 | #define MOZ_ASSERT_HELPER2(expr, explain) \ |
michael@0 | 293 | do { \ |
michael@0 | 294 | if (MOZ_UNLIKELY(!(expr))) { \ |
michael@0 | 295 | MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ |
michael@0 | 296 | MOZ_REALLY_CRASH(); \ |
michael@0 | 297 | } \ |
michael@0 | 298 | } while (0) |
michael@0 | 299 | |
michael@0 | 300 | #define MOZ_RELEASE_ASSERT_GLUE(a, b) a b |
michael@0 | 301 | #define MOZ_RELEASE_ASSERT(...) \ |
michael@0 | 302 | MOZ_RELEASE_ASSERT_GLUE( \ |
michael@0 | 303 | MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ |
michael@0 | 304 | (__VA_ARGS__)) |
michael@0 | 305 | |
michael@0 | 306 | #ifdef DEBUG |
michael@0 | 307 | # define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) |
michael@0 | 308 | #else |
michael@0 | 309 | # define MOZ_ASSERT(...) do { } while(0) |
michael@0 | 310 | #endif /* DEBUG */ |
michael@0 | 311 | |
michael@0 | 312 | /* |
michael@0 | 313 | * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is |
michael@0 | 314 | * true. |
michael@0 | 315 | * |
michael@0 | 316 | * MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num)); |
michael@0 | 317 | * |
michael@0 | 318 | * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is |
michael@0 | 319 | * designed to catch bugs during debugging, not "in the field". |
michael@0 | 320 | */ |
michael@0 | 321 | #ifdef DEBUG |
michael@0 | 322 | # define MOZ_ASSERT_IF(cond, expr) \ |
michael@0 | 323 | do { \ |
michael@0 | 324 | if (cond) \ |
michael@0 | 325 | MOZ_ASSERT(expr); \ |
michael@0 | 326 | } while (0) |
michael@0 | 327 | #else |
michael@0 | 328 | # define MOZ_ASSERT_IF(cond, expr) do { } while (0) |
michael@0 | 329 | #endif |
michael@0 | 330 | |
michael@0 | 331 | /* |
michael@0 | 332 | * MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that it is |
michael@0 | 333 | * undefined behavior for execution to reach this point. No guarantees are made |
michael@0 | 334 | * about what will happen if this is reached at runtime. Most code should |
michael@0 | 335 | * probably use the higher level MOZ_ASSUME_UNREACHABLE, which uses this when |
michael@0 | 336 | * appropriate. |
michael@0 | 337 | */ |
michael@0 | 338 | #if defined(__clang__) |
michael@0 | 339 | # define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() |
michael@0 | 340 | #elif defined(__GNUC__) |
michael@0 | 341 | /* |
michael@0 | 342 | * __builtin_unreachable() was implemented in gcc 4.5. If we don't have |
michael@0 | 343 | * that, call a noreturn function; abort() will do nicely. Qualify the call |
michael@0 | 344 | * in C++ in case there's another abort() visible in local scope. |
michael@0 | 345 | */ |
michael@0 | 346 | # if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0) |
michael@0 | 347 | # define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() |
michael@0 | 348 | # else |
michael@0 | 349 | # ifdef __cplusplus |
michael@0 | 350 | # define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() |
michael@0 | 351 | # else |
michael@0 | 352 | # define MOZ_ASSUME_UNREACHABLE_MARKER() abort() |
michael@0 | 353 | # endif |
michael@0 | 354 | # endif |
michael@0 | 355 | #elif defined(_MSC_VER) |
michael@0 | 356 | # define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0) |
michael@0 | 357 | #else |
michael@0 | 358 | # ifdef __cplusplus |
michael@0 | 359 | # define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() |
michael@0 | 360 | # else |
michael@0 | 361 | # define MOZ_ASSUME_UNREACHABLE_MARKER() abort() |
michael@0 | 362 | # endif |
michael@0 | 363 | #endif |
michael@0 | 364 | |
michael@0 | 365 | /* |
michael@0 | 366 | * MOZ_ASSUME_UNREACHABLE([reason]) tells the compiler that it can assume that |
michael@0 | 367 | * the macro call cannot be reached during execution. This lets the compiler |
michael@0 | 368 | * generate better-optimized code under some circumstances, at the expense of |
michael@0 | 369 | * the program's behavior being undefined if control reaches the |
michael@0 | 370 | * MOZ_ASSUME_UNREACHABLE. |
michael@0 | 371 | * |
michael@0 | 372 | * In Gecko, you probably should not use this macro outside of performance- or |
michael@0 | 373 | * size-critical code, because it's unsafe. If you don't care about code size |
michael@0 | 374 | * or performance, you should probably use MOZ_ASSERT or MOZ_CRASH. |
michael@0 | 375 | * |
michael@0 | 376 | * SpiderMonkey is a different beast, and there it's acceptable to use |
michael@0 | 377 | * MOZ_ASSUME_UNREACHABLE more widely. |
michael@0 | 378 | * |
michael@0 | 379 | * Note that MOZ_ASSUME_UNREACHABLE is noreturn, so it's valid not to return a |
michael@0 | 380 | * value following a MOZ_ASSUME_UNREACHABLE call. |
michael@0 | 381 | * |
michael@0 | 382 | * Example usage: |
michael@0 | 383 | * |
michael@0 | 384 | * enum ValueType { |
michael@0 | 385 | * VALUE_STRING, |
michael@0 | 386 | * VALUE_INT, |
michael@0 | 387 | * VALUE_FLOAT |
michael@0 | 388 | * }; |
michael@0 | 389 | * |
michael@0 | 390 | * int ptrToInt(ValueType type, void* value) { |
michael@0 | 391 | * { |
michael@0 | 392 | * // We know for sure that type is either INT or FLOAT, and we want this |
michael@0 | 393 | * // code to run as quickly as possible. |
michael@0 | 394 | * switch (type) { |
michael@0 | 395 | * case VALUE_INT: |
michael@0 | 396 | * return *(int*) value; |
michael@0 | 397 | * case VALUE_FLOAT: |
michael@0 | 398 | * return (int) *(float*) value; |
michael@0 | 399 | * default: |
michael@0 | 400 | * MOZ_ASSUME_UNREACHABLE("can only handle VALUE_INT and VALUE_FLOAT"); |
michael@0 | 401 | * } |
michael@0 | 402 | * } |
michael@0 | 403 | */ |
michael@0 | 404 | #if defined(DEBUG) |
michael@0 | 405 | # define MOZ_ASSUME_UNREACHABLE(...) \ |
michael@0 | 406 | do { \ |
michael@0 | 407 | MOZ_ASSERT(false, "MOZ_ASSUME_UNREACHABLE(" __VA_ARGS__ ")"); \ |
michael@0 | 408 | MOZ_ASSUME_UNREACHABLE_MARKER(); \ |
michael@0 | 409 | } while (0) |
michael@0 | 410 | #else |
michael@0 | 411 | # define MOZ_ASSUME_UNREACHABLE(reason) MOZ_ASSUME_UNREACHABLE_MARKER() |
michael@0 | 412 | #endif |
michael@0 | 413 | |
michael@0 | 414 | /* |
michael@0 | 415 | * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided |
michael@0 | 416 | * expression, in debug builds and in release builds both. Then, in debug |
michael@0 | 417 | * builds only, the value of the expression is asserted either true or false |
michael@0 | 418 | * using MOZ_ASSERT. |
michael@0 | 419 | */ |
michael@0 | 420 | #ifdef DEBUG |
michael@0 | 421 | # define MOZ_ALWAYS_TRUE(expr) MOZ_ASSERT((expr)) |
michael@0 | 422 | # define MOZ_ALWAYS_FALSE(expr) MOZ_ASSERT(!(expr)) |
michael@0 | 423 | #else |
michael@0 | 424 | # define MOZ_ALWAYS_TRUE(expr) ((void)(expr)) |
michael@0 | 425 | # define MOZ_ALWAYS_FALSE(expr) ((void)(expr)) |
michael@0 | 426 | #endif |
michael@0 | 427 | |
michael@0 | 428 | #endif /* mozilla_Assertions_h */ |