1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef BERBERIS_BASE_CHECKS_H_
18 #define BERBERIS_BASE_CHECKS_H_
19
20 #include <array>
21 #include <cinttypes>
22
23 #include "berberis/base/config.h"
24 #include "berberis/base/logging.h"
25
26 // Helpers for building message format, without incurring any function calls when the condition
27 // does not fail.
28
29 namespace berberis {
30
31 class FmtSpec {
32 private:
Get(int32_t)33 constexpr static const char (&Get(int32_t))[sizeof "%" PRId32] { return "%" PRId32; }
Get(uint32_t)34 constexpr static const char (&Get(uint32_t))[sizeof "%" PRIu32] { return "%" PRIu32; }
Get(int64_t)35 constexpr static const char (&Get(int64_t))[sizeof "%" PRId64] { return "%" PRId64; }
Get(uint64_t)36 constexpr static const char (&Get(uint64_t))[sizeof "%" PRIu64] { return "%" PRIu64; }
Get(double)37 constexpr static const char (&Get(double))[sizeof "%f"] { return "%f"; }
Get(const void *)38 constexpr static const char (&Get(const void*))[sizeof "%p"] { return "%p"; }
39
40 public:
41 template <typename Type>
42 constexpr static auto& kValue = FmtSpec::Get(static_cast<std::decay_t<Type>>(0));
43
44 template <size_t prefix_len, size_t op_len, size_t spec1_len, size_t spec2_len>
Fmt(const char (& prefix)[prefix_len],const char (& op)[op_len],const char (& spec1)[spec1_len],const char (& spec2)[spec2_len])45 constexpr static std::array<char, prefix_len + op_len + spec1_len + spec2_len - 3> Fmt(
46 const char (&prefix)[prefix_len], const char (&op)[op_len], const char (&spec1)[spec1_len],
47 const char (&spec2)[spec2_len]) {
48 std::array<char, prefix_len + op_len + spec1_len + spec2_len - 3> fmt{};
49 auto pos = begin(fmt);
50 Append(&pos, prefix, prefix_len);
51 Append(&pos, spec1, spec1_len);
52 Append(&pos, op, op_len);
53 Append(&pos, spec2, spec2_len);
54 return fmt;
55 }
56
57 private:
58 template <typename Iterator>
Append(Iterator * pos,const char * text,size_t len)59 constexpr static void Append(Iterator* pos, const char* text, size_t len) {
60 while (--len > 0) *(*pos)++ = *text++;
61 }
62 };
63
ValueForFmtSpec(auto && value)64 constexpr auto&& ValueForFmtSpec(auto&& value) {
65 return std::forward<decltype(value)>(value);
66 }
67
68 } // namespace berberis
69
70 #define BERBERIS_VALUE_STR_IMPL(v) #v
71 #define BERBERIS_VALUE_STR(v) BERBERIS_VALUE_STR_IMPL(v)
72 #define BERBERIS_CHECK_PREFIX __FILE__ ":" BERBERIS_VALUE_STR(__LINE__) ": CHECK failed: "
73
74 // Log fatal error.
75 // NEVER stripped - side effects always apply.
76
77 #define FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
78
79 #define UNREACHABLE() FATAL("This code is (supposed to be) unreachable.")
80
81 #define FATAL_UNIMPL_INSN_IF_NOT_BRINGUP() \
82 if (!berberis::config::kInstructionsBringupMode) { \
83 FATAL("Unimplemented instruction: %s", __func__); \
84 }
85
86 #ifdef CHECK
87 #undef CHECK
88 #endif
89 #define CHECK(cond) LOG_ALWAYS_FATAL_IF(!(cond), "%s", BERBERIS_CHECK_PREFIX #cond)
90
91 // TODO(b/232598137): fix multiple evaluation of v1 and v2!
92 // TODO(b/232598137): change message from '1 == 0' to 'x == y (1 == 0)'!
93 #define BERBERIS_CHECK_OP(op, v1, v2) \
94 LOG_ALWAYS_FATAL_IF( \
95 !((v1)op(v2)), /* // NOLINT */ \
96 []() { \
97 using ::berberis::ValueForFmtSpec; \
98 constexpr static auto __fmt = \
99 berberis::FmtSpec::Fmt(BERBERIS_CHECK_PREFIX, \
100 " " #op " ", \
101 berberis::FmtSpec::kValue<decltype(ValueForFmtSpec(v1))>, \
102 berberis::FmtSpec::kValue<decltype(ValueForFmtSpec(v2))>); \
103 return __fmt.data(); \
104 }(), \
105 ({ \
106 using ::berberis::ValueForFmtSpec; \
107 ValueForFmtSpec(v1); \
108 }), \
109 ({ \
110 using ::berberis::ValueForFmtSpec; \
111 ValueForFmtSpec(v2); \
112 }))
113
114 #ifdef CHECK_EQ
115 #undef CHECK_EQ
116 #endif
117 #define CHECK_EQ(v1, v2) BERBERIS_CHECK_OP(==, v1, v2)
118
119 #ifdef CHECK_NE
120 #undef CHECK_NE
121 #endif
122 #define CHECK_NE(v1, v2) BERBERIS_CHECK_OP(!=, v1, v2)
123
124 #ifdef CHECK_LT
125 #undef CHECK_LT
126 #endif
127 #define CHECK_LT(v1, v2) BERBERIS_CHECK_OP(<, v1, v2)
128
129 #ifdef CHECK_LE
130 #undef CHECK_LE
131 #endif
132 #define CHECK_LE(v1, v2) BERBERIS_CHECK_OP(<=, v1, v2)
133
134 #ifdef CHECK_GT
135 #undef CHECK_GT
136 #endif
137 #define CHECK_GT(v1, v2) BERBERIS_CHECK_OP(>, v1, v2)
138
139 #ifdef CHECK_GE
140 #undef CHECK_GE
141 #endif
142 #define CHECK_GE(v1, v2) BERBERIS_CHECK_OP(>=, v1, v2)
143
144 // Log fatal error.
145 // ATTENTION - stripped from release builds, be careful with side effects!
146
147 #ifdef DCHECK
148 #undef DCHECK
149 #endif
150 #if LOG_NDEBUG
151 #define DCHECK(cond)
152 #else
153 #define DCHECK(cond) CHECK(cond)
154 #endif
155
156 #if LOG_NDEBUG
157 #define BERBERIS_DCHECK_OP(op, v1, v2)
158 #else
159 #define BERBERIS_DCHECK_OP(op, v1, v2) BERBERIS_CHECK_OP(op, v1, v2)
160 #endif
161
162 #ifdef DCHECK_EQ
163 #undef DCHECK_EQ
164 #endif
165 #define DCHECK_EQ(v1, v2) BERBERIS_DCHECK_OP(==, v1, v2)
166
167 #ifdef DCHECK_NE
168 #undef DCHECK_NE
169 #endif
170 #define DCHECK_NE(v1, v2) BERBERIS_DCHECK_OP(!=, v1, v2)
171
172 #ifdef DCHECK_LT
173 #undef DCHECK_LT
174 #endif
175 #define DCHECK_LT(v1, v2) BERBERIS_DCHECK_OP(<, v1, v2)
176
177 #ifdef DCHECK_LE
178 #undef DCHECK_LE
179 #endif
180 #define DCHECK_LE(v1, v2) BERBERIS_DCHECK_OP(<=, v1, v2)
181
182 #ifdef DCHECK_GT
183 #undef DCHECK_GT
184 #endif
185 #define DCHECK_GT(v1, v2) BERBERIS_DCHECK_OP(>, v1, v2)
186
187 #ifdef DCHECK_GE
188 #undef DCHECK_GE
189 #endif
190 #define DCHECK_GE(v1, v2) BERBERIS_DCHECK_OP(>=, v1, v2)
191
192 #endif // BERBERIS_BASE_CHECKS_H_
193