-
Notifications
You must be signed in to change notification settings - Fork 139
/
Copy pathAssert.hpp
253 lines (211 loc) · 9.25 KB
/
Assert.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*******************************************************************************
* Copyright IBM Corp. and others 2000
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution
* and is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception [1] and GNU General Public
* License, version 2 with the OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] https://openjdk.org/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
*******************************************************************************/
/**
* \file Assert.hpp
*
* Defines a number of assert functions and macros.
*
* \def TR::trap a convenience function for taking down the VM and
* generating a core dump.
*
* \def TR_ASSERT_FATAL an assertion that will always take down the VM.
* Intended for the most egregious of errors.
*
* \def TR_ASSERT_SAFE_FATAL an assertion that will take down the VM, unless
* the non-fatal assert option is set (intended for
* service purposes). The presumption is that the
* user of this assert has ensured that the code
* subsequent to the assert is safe to continue
* executing.
*
* In production builds, only the line number and
* file name are available to conserve DLL size.
*
* \def TR_ASSERT a macro that defines an assertion which is compiled out
* (including format strings) during production builds
*
* \def TR_UNIMPLEMENTED a macro that expands into an unconditional assertion
* failure. Used to indicate that a function has not been
* implemented and may not be called.
*
* A number of helper macros are also provided for printing more detailed contextual
* information on fatal assertion failures to assist with debugging.
*
* \def TR_ASSERT_FATAL_WITH_DETAIL
* a fatal assertion which will print the provided contextual information upon failure
* in addition to the provided message.
*
* \def TR_ASSERT_FATAL_WITH_NODE
* a fatal assertion which will print NodeAssertionContext for the provided node upon
* failure in addition to the provided message.
*
* \def TR_ASSERT_FATAL_WITH_INSTRUCTION
* a fatal assertion which will print InstructionAssertionContext for the provided
* instruction upon failure in addition to the provided message.
*
* We also provide Expect and Ensure, based on the developing C++ Core guidelines [1].
*
* \def Expect Precondition macro, only defined for DEBUG and
* EXPECT_BUILDs.
*
* \def Ensure Postcondition macro, only defined for DEBUG and
* EXPECT_BUILDs.
*
*
* \note While not standardized, this header relies on compiler behaviour that
* will trim the trailing comma from a variadic macro when provided no
* variadic arguments, to avoid TR_ASSERT(cond, "message") from
* complaining about a trailing comma.
*
* [1]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Ri-expects
*/
#ifndef TR_ASSERT_HPP
#define TR_ASSERT_HPP
#include "infra/Annotations.hpp" // OMR_NORETURN
#include "compile/CompilationException.hpp"
#include <cstddef>
namespace TR
{
class Node;
class Instruction;
void OMR_NORETURN trap();
/**
* Represents context to be printed alongside an assertion failure message.
*
* After printing the message and stack trace associated with an assertion failure, the relevant context will be
* printed to stderr by calling its printContext function. Contextual information generally includes relevant details
* about the state of the compiler at the time of the failure, such as the tree containing a node which resulted in
* an assertion failure.
*/
class AssertionContext
{
public:
/**
* Prints contextual information about the assertion for debugging purposes.
*
* It is valid for this function to itself result in an assertion failure (potentially with its own context)
* during the process of printing. To prevent boundless recursion, the context of such an assertion failure will
* not be printed.
*/
virtual void printContext() const = 0;
};
/**
* An assertion context which does not print any information.
*/
class NullAssertionContext : public AssertionContext
{
public:
virtual void printContext() const {}
};
/**
* An assertion context which prints the treetop containing a particular node.
*/
class NodeAssertionContext : public AssertionContext
{
TR::Node *_node;
public:
NodeAssertionContext(TR::Node *node) : _node(node) {}
virtual void printContext() const;
};
/**
* An assertion context which prints instructions surrounding a particular instructions.
*/
class InstructionAssertionContext : public AssertionContext
{
TR::Instruction *_instruction;
public:
InstructionAssertionContext(TR::Instruction *instruction) : _instruction(instruction) {}
virtual void printContext() const;
};
// Don't use these directly.
//
// Use the TR_ASSERT* macros instead as they control the string
// contents in production builds.
void OMR_NORETURN fatal_assertion(const char *file, int line, const char *condition, const char *format, ...);
void OMR_NORETURN fatal_assertion_with_detail(const AssertionContext& ctx, const char *file, int line, const char *condition, const char *format, ...);
// Non fatal assertions may in some circumstances return, so do not mark them as
// no-return.
void assertion(const char *file, int line, const char *condition, const char *format, ...);
/**
* Assertion failure exception type.
*
* Thrown only by TR_ASSERT_SAFE_FATAL, when softFailOnAssumes is set.
*/
struct AssertionFailure : public virtual CompilationException
{
virtual const char* what() const throw() { return "Assertion Failure"; }
};
}
// Macro Definitions
#define TR_ASSERT_FATAL(condition, format, ...) \
do { (condition) ? (void)0 : TR::fatal_assertion(__FILE__, __LINE__, #condition, format, ##__VA_ARGS__); } while(0)
#define TR_ASSERT_FATAL_WITH_DETAIL(ctx, condition, format, ...) \
do { \
if (!(condition)) \
TR::fatal_assertion_with_detail(ctx, __FILE__, __LINE__, #condition, format, ##__VA_ARGS__); \
} while (0)
#define TR_ASSERT_FATAL_WITH_NODE(node, condition, format, ...) \
do { \
TR::Node *nodeVal = (node); \
TR_ASSERT_FATAL_WITH_DETAIL( \
TR::NodeAssertionContext(nodeVal), \
condition, \
"Node %p [%s]: " format, \
nodeVal, \
nodeVal ? nodeVal->getOpCode().getName() : "null", \
##__VA_ARGS__ \
); \
} while (0)
#define TR_ASSERT_FATAL_WITH_INSTRUCTION(instr, condition, format, ...) \
do { \
TR::Instruction *instrVal = (instr); \
TR::Node *instrNode = instrVal ? instrVal->getNode() : NULL; \
TR_ASSERT_FATAL_WITH_DETAIL( \
TR::InstructionAssertionContext(instrVal), \
condition, \
"Instruction %p [%s] (generated from node %p [%s]): " format, \
instrVal, \
instrVal ? instrVal->getOpCode().getMnemonicName() : "null", \
instrNode, \
instrNode ? instrNode->getOpCode().getName() : "null", \
##__VA_ARGS__ \
); \
} while (0)
#define TR_UNIMPLEMENTED() \
::TR::fatal_assertion(__FILE__, __LINE__, NULL, "Unimplemented function: %s", __FUNCTION__)
#if defined(DEBUG) || defined(PROD_WITH_ASSUMES)
#define TR_ASSERT(condition, format, ...) \
do { (condition) ? (void)0 : TR::assertion(__FILE__, __LINE__, #condition, format, ##__VA_ARGS__); } while(0)
#define TR_ASSERT_SAFE_FATAL(condition, format, ...) \
do { (condition) ? (void)0 : TR::assertion(__FILE__, __LINE__, #condition, format, ##__VA_ARGS__); } while(0)
#else
#define TR_ASSERT(condition, format, ...) (void)0
#define TR_ASSERT_SAFE_FATAL(condition, format, ...) \
do { (condition) ? (void)0 : TR::assertion(__FILE__, __LINE__, NULL, NULL); } while(0)
#endif
#if defined(DEBUG) || defined(EXPECT_BUILD)
#define Expect(x) TR_ASSERT((x), "Expectation Failure:")
#define Ensure(x) TR_ASSERT((x), "Ensure Failure:")
#else
#define Expect(x) (void)0
#define Ensure(x) (void)0
#endif
#endif