diff options
| author | 2015-03-08 22:25:04 -0400 | |
|---|---|---|
| committer | 2015-03-08 22:25:04 -0400 | |
| commit | ba8ce6c8f59f012cd22dbc76d26ba290d9174d60 (patch) | |
| tree | 07bdfa055455654f2d1d74998137ea3b285a96a8 /src | |
| parent | Merge pull request #639 from archshift/appbundle (diff) | |
| parent | Asserts: Use lambdas to keep assertion code away from the main code path (diff) | |
| download | yuzu-ba8ce6c8f59f012cd22dbc76d26ba290d9174d60.tar.gz yuzu-ba8ce6c8f59f012cd22dbc76d26ba290d9174d60.tar.xz yuzu-ba8ce6c8f59f012cd22dbc76d26ba290d9174d60.zip | |
Merge pull request #584 from yuriks/outline-asserts
Asserts: Use lambdas to keep assertion code away from the main code path
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/assert.h | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/src/common/assert.h b/src/common/assert.h index 3b2232a7e..9ca7adb15 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -4,24 +4,43 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstdlib> | ||
| 8 | |||
| 7 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 8 | 10 | ||
| 11 | // For asserts we'd like to keep all the junk executed when an assert happens away from the | ||
| 12 | // important code in the function. One way of doing this is to put all the relevant code inside a | ||
| 13 | // lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to | ||
| 14 | // specify __declspec on lambda functions, so what we do instead is define a noinline wrapper | ||
| 15 | // template that calls the lambda. This seems to generate an extra instruction at the call-site | ||
| 16 | // compared to the ideal implementation (which wouldn't support ASSERT_MSG parameters), but is good | ||
| 17 | // enough for our purposes. | ||
| 18 | template <typename Fn> | ||
| 19 | #if defined(_MSC_VER) | ||
| 20 | __declspec(noinline, noreturn) | ||
| 21 | #elif defined(__GNUC__) | ||
| 22 | __attribute__((noinline, noreturn, cold)) | ||
| 23 | #endif | ||
| 24 | static void assert_noinline_call(const Fn& fn) { | ||
| 25 | fn(); | ||
| 26 | Crash(); | ||
| 27 | exit(1); // Keeps GCC's mouth shut about this actually returning | ||
| 28 | } | ||
| 29 | |||
| 9 | // TODO (yuriks) allow synchronous logging so we don't need printf | 30 | // TODO (yuriks) allow synchronous logging so we don't need printf |
| 10 | #define ASSERT(_a_) \ | 31 | #define ASSERT(_a_) \ |
| 11 | do if (!(_a_)) {\ | 32 | do if (!(_a_)) { assert_noinline_call([] { \ |
| 12 | fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \ | 33 | fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \ |
| 13 | __LINE__, __FILE__, __TIME__); \ | 34 | __LINE__, __FILE__, __TIME__); \ |
| 14 | Crash(); \ | 35 | }); } while (0) |
| 15 | } while (0) | ||
| 16 | 36 | ||
| 17 | #define ASSERT_MSG(_a_, ...) \ | 37 | #define ASSERT_MSG(_a_, ...) \ |
| 18 | do if (!(_a_)) {\ | 38 | do if (!(_a_)) { assert_noinline_call([&] { \ |
| 19 | fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \ | 39 | fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \ |
| 20 | __LINE__, __FILE__, __TIME__); \ | 40 | __LINE__, __FILE__, __TIME__); \ |
| 21 | fprintf(stderr, __VA_ARGS__); \ | 41 | fprintf(stderr, __VA_ARGS__); \ |
| 22 | fprintf(stderr, "\n"); \ | 42 | fprintf(stderr, "\n"); \ |
| 23 | Crash(); \ | 43 | }); } while (0) |
| 24 | } while (0) | ||
| 25 | 44 | ||
| 26 | #define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") | 45 | #define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") |
| 27 | 46 | ||