Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: src/base/logging.h

Issue 891693002: [base] Further improve the logging facility. Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Android GCC Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/base/logging.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef V8_BASE_LOGGING_H_ 5 #ifndef V8_BASE_LOGGING_H_
6 #define V8_BASE_LOGGING_H_ 6 #define V8_BASE_LOGGING_H_
7 7
8 #include <cstring> 8 #include <cstring>
9 #include <sstream> 9 #include <sstream>
10 #include <string> 10 #include <string>
11 11
12 #include "src/base/build_config.h" 12 #include "src/base/build_config.h"
13 #include "src/base/compiler-specific.h"
13 14
14 extern "C" void V8_Fatal(const char* file, int line, const char* format, ...); 15 extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
15 16
16 17
17 // The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during 18 // The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during
18 // development, but they should not be relied on in the final product. 19 // development, but they should not be relied on in the final product.
19 #ifdef DEBUG 20 #ifdef DEBUG
20 #define FATAL(msg) \ 21 #define FATAL(msg) \
21 V8_Fatal(__FILE__, __LINE__, "%s", (msg)) 22 V8_Fatal(__FILE__, __LINE__, "%s", (msg))
22 #define UNIMPLEMENTED() \ 23 #define UNIMPLEMENTED() \
23 V8_Fatal(__FILE__, __LINE__, "unimplemented code") 24 V8_Fatal(__FILE__, __LINE__, "unimplemented code")
24 #define UNREACHABLE() \ 25 #define UNREACHABLE() \
25 V8_Fatal(__FILE__, __LINE__, "unreachable code") 26 V8_Fatal(__FILE__, __LINE__, "unreachable code")
26 #else 27 #else
27 #define FATAL(msg) \ 28 #define FATAL(msg) \
28 V8_Fatal("", 0, "%s", (msg)) 29 V8_Fatal("", 0, "%s", (msg))
29 #define UNIMPLEMENTED() \ 30 #define UNIMPLEMENTED() \
30 V8_Fatal("", 0, "unimplemented code") 31 V8_Fatal("", 0, "unimplemented code")
31 #define UNREACHABLE() ((void) 0) 32 #define UNREACHABLE() ((void) 0)
32 #endif 33 #endif
33 34
34 35
35 namespace v8 { 36 namespace v8 {
36 namespace base { 37 namespace base {
38 namespace logging {
39
40 typedef int LogSeverity;
41 const LogSeverity LOG_INFO = 0;
42 const LogSeverity LOG_FATAL = 1;
43
44
45 // A few definitions of macros that don't generate much code. These are used
46 // by LOG() and LOG_IF, etc. Since these are used all over our code, it's
47 // better to have compact code for these operations.
48 #define COMPACT_GOOGLE_LOG_INFO \
49 ::v8::base::logging::LogMessage(__FILE__, __LINE__, \
50 ::v8::base::logging::LOG_INFO)
51 #define COMPACT_GOOGLE_LOG_FATAL \
52 ::v8::base::logging::LogMessage(__FILE__, __LINE__, \
53 ::v8::base::logging::LOG_FATAL)
54
55
56 // Helper macro which avoids evaluating the arguments to a stream if
57 // the condition doesn't hold.
58 #define LAZY_STREAM(stream, condition) \
59 V8_LIKELY(!(condition)) \
60 ? (void)0 : ::v8::base::logging::LogMessageVoidify() & (stream)
61
62
63 // We use the preprocessor's merging operator, "##", so that, e.g.,
64 // LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny
65 // subtle difference between ostream member streaming functions (e.g.,
66 // ostream::operator<<(int) and ostream non-member streaming functions
67 // (e.g., ::operator<<(ostream&, string&): it turns out that it's
68 // impossible to stream something like a string directly to an unnamed
69 // ostream. We employ a neat hack by calling the stream() member
70 // function of LogMessage which seems to avoid the problem.
71 #define LOG_STREAM(SEVERITY) COMPACT_GOOGLE_LOG_##SEVERITY.stream()
72
73
74 // The actual stream used isn't important.
75 #define EAT_STREAM_PARAMETERS \
76 true ? (void)0 : ::v8::base::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
77
37 78
38 // CHECK dies with a fatal error if condition is not true. It is *not* 79 // CHECK dies with a fatal error if condition is not true. It is *not*
39 // controlled by DEBUG, so the check will be executed regardless of 80 // controlled by DEBUG, so the check will be executed regardless of
40 // compilation mode. 81 // compilation mode.
41 // 82 //
42 // We make sure CHECK et al. always evaluates their arguments, as 83 // We make sure CHECK et al. always evaluates their arguments, as
43 // doing CHECK(FunctionWithSideEffect()) is a common idiom. 84 // doing CHECK(FunctionWithSideEffect()) is a common idiom.
44 #define CHECK(condition) \ 85 #ifdef DEBUG
45 do { \
46 if (V8_UNLIKELY(!(condition))) { \
47 V8_Fatal(__FILE__, __LINE__, "Check failed: %s.", #condition); \
48 } \
49 } while (0)
50 86
87 #ifdef _PREFAST_
88 // Use __analysis_assume to tell the VC++ static analysis engine that
89 // assert conditions are true, to suppress warnings. The LAZY_STREAM
90 // parameter doesn't reference 'condition' in /analyze builds because
91 // this evaluation confuses /analyze. The !! before condition is because
92 // __analysis_assume gets confused on some conditions:
93 // http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugl y-part-5/
51 94
52 #ifdef DEBUG 95 #define CHECK(condition) \
96 __analysis_assume(!!(condition)), LAZY_STREAM(LOG_STREAM(FATAL), false) \
97 << "Check failed: " #condition ". "
98
99 #else // _PREFAST_
100
101 #define CHECK(condition) \
102 LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
103 << "Check failed: " << #condition ". "
104
105 #endif // _PREFAST_
53 106
54 // Helper macro for binary operators. 107 // Helper macro for binary operators.
55 // Don't use this macro directly in your code, use CHECK_EQ et al below. 108 // Don't use this macro directly in your code, use CHECK_EQ et al below.
56 #define CHECK_OP(name, op, lhs, rhs) \ 109 #define CHECK_OP(name, op, lhs, rhs) \
57 do { \ 110 if (std::string* _result = ::v8::base::logging::Check##name##Impl( \
58 if (std::string* _msg = ::v8::base::Check##name##Impl( \ 111 (lhs), (rhs), #lhs " " #op " " #rhs)) \
59 (lhs), (rhs), #lhs " " #op " " #rhs)) { \ 112 ::v8::base::logging::LogMessage(__FILE__, __LINE__, _result).stream()
60 V8_Fatal(__FILE__, __LINE__, "Check failed: %s.", _msg->c_str()); \
61 delete _msg; \
62 } \
63 } while (0)
64 113
65 #else 114 #else // DEBUG
115
116 #define CHECK(condition) \
117 V8_UNLIKELY(!(condition)) \
118 ? V8_Fatal(__FILE__, __LINE__, "Check failed: %s.", #condition) \
119 : EAT_STREAM_PARAMETERS
66 120
67 // Make all CHECK functions discard their log strings to reduce code 121 // Make all CHECK functions discard their log strings to reduce code
68 // bloat for official release builds. 122 // bloat for official release builds.
69 123
70 #define CHECK_OP(name, op, lhs, rhs) CHECK((lhs)op(rhs)) 124 #define CHECK_OP(name, op, lhs, rhs) CHECK((lhs)op(rhs))
71 125
72 #endif 126 #endif // DEBUG
73 127
74 128
75 // Build the error message string. This is separate from the "Impl" 129 // Build the error message string. This is separate from the "Impl"
76 // function template because it is not performance critical and so can 130 // function template because it is not performance critical and so can
77 // be out of line, while the "Impl" code should be inline. Caller 131 // be out of line, while the "Impl" code should be inline. Caller
78 // takes ownership of the returned string. 132 // takes ownership of the returned string.
79 template <typename Lhs, typename Rhs> 133 template <typename Lhs, typename Rhs>
80 std::string* MakeCheckOpString(Lhs const& lhs, Rhs const& rhs, 134 std::string* MakeCheckOpString(Lhs const& lhs, Rhs const& rhs,
81 char const* msg) { 135 char const* result) {
82 std::ostringstream ss; 136 std::ostringstream ss;
83 ss << msg << " (" << lhs << " vs. " << rhs << ")"; 137 ss << result << " (" << lhs << " vs. " << rhs << ")";
84 return new std::string(ss.str()); 138 return new std::string(ss.str());
85 } 139 }
86 140
87 // Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated 141 // Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
88 // in logging.cc. 142 // in logging.cc.
89 #define DEFINE_MAKE_CHECK_OP_STRING(type) \ 143 #define DEFINE_MAKE_CHECK_OP_STRING(type) \
90 extern template std::string* MakeCheckOpString<type, type>( \ 144 extern template std::string* MakeCheckOpString<type, type>( \
91 type const&, type const&, char const*); 145 type const&, type const&, char const*);
92 DEFINE_MAKE_CHECK_OP_STRING(int) 146 DEFINE_MAKE_CHECK_OP_STRING(int)
93 DEFINE_MAKE_CHECK_OP_STRING(long) // NOLINT(runtime/int) 147 DEFINE_MAKE_CHECK_OP_STRING(long) // NOLINT(runtime/int)
94 DEFINE_MAKE_CHECK_OP_STRING(long long) // NOLINT(runtime/int) 148 DEFINE_MAKE_CHECK_OP_STRING(long long) // NOLINT(runtime/int)
95 DEFINE_MAKE_CHECK_OP_STRING(unsigned int) 149 DEFINE_MAKE_CHECK_OP_STRING(unsigned int)
96 DEFINE_MAKE_CHECK_OP_STRING(unsigned long) // NOLINT(runtime/int) 150 DEFINE_MAKE_CHECK_OP_STRING(unsigned long) // NOLINT(runtime/int)
97 DEFINE_MAKE_CHECK_OP_STRING(unsigned long long) // NOLINT(runtime/int) 151 DEFINE_MAKE_CHECK_OP_STRING(unsigned long long) // NOLINT(runtime/int)
98 DEFINE_MAKE_CHECK_OP_STRING(char const*) 152 DEFINE_MAKE_CHECK_OP_STRING(char const*)
99 DEFINE_MAKE_CHECK_OP_STRING(void const*) 153 DEFINE_MAKE_CHECK_OP_STRING(void const*)
100 #undef DEFINE_MAKE_CHECK_OP_STRING 154 #undef DEFINE_MAKE_CHECK_OP_STRING
101 155
102 156
103 // Helper functions for CHECK_OP macro. 157 // Helper functions for CHECK_OP macro.
104 // The (int, int) specialization works around the issue that the compiler 158 // The (int, int) specialization works around the issue that the compiler
105 // will not instantiate the template version of the function on values of 159 // will not instantiate the template version of the function on values of
106 // unnamed enum type - see comment below. 160 // unnamed enum type - see comment below.
107 // The (float, float) and (double, double) instantiations are explicitly 161 // The (float, float) and (double, double) instantiations are explicitly
108 // externialized to ensure proper 32/64-bit comparisons on x86. 162 // externialized to ensure proper 32/64-bit comparisons on x86.
109 #define DEFINE_CHECK_OP_IMPL(NAME, op) \ 163 #define DEFINE_CHECK_OP_IMPL(NAME, op) \
110 template <typename Lhs, typename Rhs> \ 164 template <typename Lhs, typename Rhs> \
111 V8_INLINE std::string* Check##NAME##Impl(Lhs const& lhs, Rhs const& rhs, \ 165 V8_INLINE std::string* Check##NAME##Impl(Lhs const& lhs, Rhs const& rhs, \
112 char const* msg) { \ 166 char const* result) { \
113 return V8_LIKELY(lhs op rhs) ? nullptr : MakeCheckOpString(lhs, rhs, msg); \ 167 return V8_LIKELY(lhs op rhs) ? nullptr \
114 } \ 168 : MakeCheckOpString(lhs, rhs, result); \
115 V8_INLINE std::string* Check##NAME##Impl(int lhs, int rhs, \ 169 } \
116 char const* msg) { \ 170 V8_INLINE std::string* Check##NAME##Impl(int lhs, int rhs, \
117 return V8_LIKELY(lhs op rhs) ? nullptr : MakeCheckOpString(lhs, rhs, msg); \ 171 char const* result) { \
118 } \ 172 return V8_LIKELY(lhs op rhs) ? nullptr \
119 extern template std::string* Check##NAME##Impl<float, float>( \ 173 : MakeCheckOpString(lhs, rhs, result); \
120 float const& lhs, float const& rhs, char const* msg); \ 174 } \
121 extern template std::string* Check##NAME##Impl<double, double>( \ 175 extern template std::string* Check##NAME##Impl<float, float>( \
122 double const& lhs, double const& rhs, char const* msg); 176 float const& lhs, float const& rhs, char const* result); \
123 DEFINE_CHECK_OP_IMPL(EQ, ==) 177 extern template std::string* Check##NAME##Impl<double, double>( \
178 double const& lhs, double const& rhs, char const* result);
179 DEFINE_CHECK_OP_IMPL(EQ, == )
124 DEFINE_CHECK_OP_IMPL(NE, !=) 180 DEFINE_CHECK_OP_IMPL(NE, !=)
125 DEFINE_CHECK_OP_IMPL(LE, <=) 181 DEFINE_CHECK_OP_IMPL(LE, <=)
126 DEFINE_CHECK_OP_IMPL(LT, < ) 182 DEFINE_CHECK_OP_IMPL(LT, < )
127 DEFINE_CHECK_OP_IMPL(GE, >=) 183 DEFINE_CHECK_OP_IMPL(GE, >=)
128 DEFINE_CHECK_OP_IMPL(GT, > ) 184 DEFINE_CHECK_OP_IMPL(GT, > )
129 #undef DEFINE_CHECK_OP_IMPL 185 #undef DEFINE_CHECK_OP_IMPL
130 186
131 #define CHECK_EQ(lhs, rhs) CHECK_OP(EQ, ==, lhs, rhs) 187 #define CHECK_EQ(lhs, rhs) CHECK_OP(EQ, ==, lhs, rhs)
132 #define CHECK_NE(lhs, rhs) CHECK_OP(NE, !=, lhs, rhs) 188 #define CHECK_NE(lhs, rhs) CHECK_OP(NE, !=, lhs, rhs)
133 #define CHECK_LE(lhs, rhs) CHECK_OP(LE, <=, lhs, rhs) 189 #define CHECK_LE(lhs, rhs) CHECK_OP(LE, <=, lhs, rhs)
134 #define CHECK_LT(lhs, rhs) CHECK_OP(LT, <, lhs, rhs) 190 #define CHECK_LT(lhs, rhs) CHECK_OP(LT, <, lhs, rhs)
135 #define CHECK_GE(lhs, rhs) CHECK_OP(GE, >=, lhs, rhs) 191 #define CHECK_GE(lhs, rhs) CHECK_OP(GE, >=, lhs, rhs)
136 #define CHECK_GT(lhs, rhs) CHECK_OP(GT, >, lhs, rhs) 192 #define CHECK_GT(lhs, rhs) CHECK_OP(GT, >, lhs, rhs)
137 #define CHECK_NULL(val) CHECK((val) == nullptr) 193 #define CHECK_NULL(val) CHECK((val) == nullptr)
138 #define CHECK_NOT_NULL(val) CHECK((val) != nullptr) 194 #define CHECK_NOT_NULL(val) CHECK((val) != nullptr)
139 #define CHECK_IMPLIES(lhs, rhs) CHECK(!(lhs) || (rhs)) 195 #define CHECK_IMPLIES(lhs, rhs) CHECK(!(lhs) || (rhs))
140 196
141 197
142 // Exposed for making debugging easier (to see where your function is being 198 // This class more or less represents a particular log message. You create an
143 // called, just add a call to DumpBacktrace). 199 // instance of LogMessage and then stream stuff to it. When you finish streaming
144 void DumpBacktrace(); 200 // to it, the destructor is called and the full message gets streamed to the
201 // appropriate destination.
202 //
203 // You shouldn't actually use LogMessage's constructor to log things, through.
204 // You should use the macros above.
205 class LogMessage FINAL {
206 public:
207 // Used for LOG(severity), CHECK() and friends.
208 LogMessage(char const* file, int line, LogSeverity severity);
145 209
210 // Used for CHECK_EQ() and friends. Takes ownership of the given string.
211 // Implied severity = LOG_FATAL.
212 LogMessage(char const* file, int line, std::string* result);
213
214 // Used for DCHECK_EQ() and friends. Takes ownership of the given string.
215 LogMessage(char const* file, int line, LogSeverity severity,
216 std::string* result);
217
218 ~LogMessage();
219
220 std::ostream& stream() { return stream_; }
221
222 private:
223 std::ostringstream stream_;
224 char const* const file_; // The file information passed into the constructor.
225 int const line_; // The line information passed into the constructor.
226 LogSeverity const severity_;
227
228 // TODO(bmeurer): Use DISALLOW_IMPLICIT_CONSTRUCTORS once macros.h no longer
229 // depends on logging.h.
230 LogMessage() V8_DELETE;
231 LogMessage(LogMessage const&) V8_DELETE;
232 void operator=(LogMessage const&) V8_DELETE;
233 };
234
235
236 // This class is used to explicitly ignore values in the conditional
237 // logging macros. This avoids compiler warnings like "value computed
238 // is not used" and "statement has no effect".
239 class LogMessageVoidify FINAL {
240 public:
241 LogMessageVoidify() {}
242
243 // This has to be an operator with a precedence lower than << but
244 // higher than ?:
245 void operator&(std::ostream&) {}
246 };
247
248 } // namespace logging
146 } // namespace base 249 } // namespace base
147 } // namespace v8 250 } // namespace v8
148 251
149 252
150 // The DCHECK macro is equivalent to CHECK except that it only 253 // The DCHECK macro is equivalent to CHECK except that it only
151 // generates code in debug builds. 254 // generates code in debug builds.
152 // TODO(bmeurer): DCHECK_RESULT(expr) must die!
153 #ifdef DEBUG 255 #ifdef DEBUG
154 #define DCHECK_RESULT(expr) CHECK(expr)
155 #define DCHECK(condition) CHECK(condition) 256 #define DCHECK(condition) CHECK(condition)
156 #define DCHECK_EQ(v1, v2) CHECK_EQ(v1, v2) 257 #define DCHECK_EQ(v1, v2) CHECK_EQ(v1, v2)
157 #define DCHECK_NE(v1, v2) CHECK_NE(v1, v2) 258 #define DCHECK_NE(v1, v2) CHECK_NE(v1, v2)
158 #define DCHECK_GE(v1, v2) CHECK_GE(v1, v2) 259 #define DCHECK_GE(v1, v2) CHECK_GE(v1, v2)
159 #define DCHECK_LT(v1, v2) CHECK_LT(v1, v2) 260 #define DCHECK_LT(v1, v2) CHECK_LT(v1, v2)
160 #define DCHECK_LE(v1, v2) CHECK_LE(v1, v2) 261 #define DCHECK_LE(v1, v2) CHECK_LE(v1, v2)
161 #define DCHECK_NULL(val) CHECK_NULL(val) 262 #define DCHECK_NULL(val) CHECK_NULL(val)
162 #define DCHECK_NOT_NULL(val) CHECK_NOT_NULL(val) 263 #define DCHECK_NOT_NULL(val) CHECK_NOT_NULL(val)
163 #define DCHECK_IMPLIES(v1, v2) CHECK_IMPLIES(v1, v2) 264 #define DCHECK_IMPLIES(v1, v2) CHECK_IMPLIES(v1, v2)
164 #else 265 #else
165 #define DCHECK_RESULT(expr) (expr)
166 #define DCHECK(condition) ((void) 0) 266 #define DCHECK(condition) ((void) 0)
167 #define DCHECK_EQ(v1, v2) ((void) 0) 267 #define DCHECK_EQ(v1, v2) ((void) 0)
168 #define DCHECK_NE(v1, v2) ((void) 0) 268 #define DCHECK_NE(v1, v2) ((void) 0)
169 #define DCHECK_GE(v1, v2) ((void) 0) 269 #define DCHECK_GE(v1, v2) ((void) 0)
170 #define DCHECK_LT(v1, v2) ((void) 0) 270 #define DCHECK_LT(v1, v2) ((void) 0)
171 #define DCHECK_LE(v1, v2) ((void) 0) 271 #define DCHECK_LE(v1, v2) ((void) 0)
172 #define DCHECK_NULL(val) ((void) 0) 272 #define DCHECK_NULL(val) ((void) 0)
173 #define DCHECK_NOT_NULL(val) ((void) 0) 273 #define DCHECK_NOT_NULL(val) ((void) 0)
174 #define DCHECK_IMPLIES(v1, v2) ((void) 0) 274 #define DCHECK_IMPLIES(v1, v2) ((void) 0)
175 #endif 275 #endif
176 276
177 #endif // V8_BASE_LOGGING_H_ 277 #endif // V8_BASE_LOGGING_H_
OLDNEW
« no previous file with comments | « no previous file | src/base/logging.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698