/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_SRC_LOGGING_H_ #define ART_SRC_LOGGING_H_ #include #include #include // NOLINT #include #include "log_severity.h" #include "macros.h" #define CHECK(x) \ if (UNLIKELY(!(x))) \ ::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \ << "Check failed: " #x << " " #define CHECK_OP(LHS, RHS, OP) \ for (::art::EagerEvaluator _values(LHS, RHS); \ UNLIKELY(!(_values.lhs OP _values.rhs)); /* empty */) \ ::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \ << "Check failed: " << #LHS << " " << #OP << " " << #RHS \ << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") " #define CHECK_EQ(x, y) CHECK_OP(x, y, ==) #define CHECK_NE(x, y) CHECK_OP(x, y, !=) #define CHECK_LE(x, y) CHECK_OP(x, y, <=) #define CHECK_LT(x, y) CHECK_OP(x, y, <) #define CHECK_GE(x, y) CHECK_OP(x, y, >=) #define CHECK_GT(x, y) CHECK_OP(x, y, >) #define CHECK_STROP(s1, s2, sense) \ if (UNLIKELY((strcmp(s1, s2) == 0) != sense)) \ LOG(FATAL) << "Check failed: " \ << "\"" << s1 << "\"" \ << (sense ? " == " : " != ") \ << "\"" << s2 << "\"" #define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true) #define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false) #define CHECK_PTHREAD_CALL(call, args, what) \ do { \ int rc = call args; \ if (rc != 0) { \ errno = rc; \ PLOG(FATAL) << # call << " failed for " << what; \ } \ } while (false) #ifndef NDEBUG #define DCHECK(x) CHECK(x) #define DCHECK_EQ(x, y) CHECK_EQ(x, y) #define DCHECK_NE(x, y) CHECK_NE(x, y) #define DCHECK_LE(x, y) CHECK_LE(x, y) #define DCHECK_LT(x, y) CHECK_LT(x, y) #define DCHECK_GE(x, y) CHECK_GE(x, y) #define DCHECK_GT(x, y) CHECK_GT(x, y) #define DCHECK_STREQ(s1, s2) CHECK_STREQ(s1, s2) #define DCHECK_STRNE(s1, s2) CHECK_STRNE(s1, s2) #else // NDEBUG #define DCHECK(condition) \ while (false) \ CHECK(condition) #define DCHECK_EQ(val1, val2) \ while (false) \ CHECK_EQ(val1, val2) #define DCHECK_NE(val1, val2) \ while (false) \ CHECK_NE(val1, val2) #define DCHECK_LE(val1, val2) \ while (false) \ CHECK_LE(val1, val2) #define DCHECK_LT(val1, val2) \ while (false) \ CHECK_LT(val1, val2) #define DCHECK_GE(val1, val2) \ while (false) \ CHECK_GE(val1, val2) #define DCHECK_GT(val1, val2) \ while (false) \ CHECK_GT(val1, val2) #define DCHECK_STREQ(str1, str2) \ while (false) \ CHECK_STREQ(str1, str2) #define DCHECK_STRNE(str1, str2) \ while (false) \ CHECK_STRNE(str1, str2) #endif #define LOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, -1).stream() #define PLOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, errno).stream() #define LG LOG(INFO) #define UNIMPLEMENTED(level) LOG(level) << __PRETTY_FUNCTION__ << " unimplemented " #define VLOG_IS_ON(module) UNLIKELY(::art::gLogVerbosity.module) #define VLOG(module) if (VLOG_IS_ON(module)) ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream() // // Implementation details beyond this point. // namespace art { template struct EagerEvaluator { EagerEvaluator(LHS lhs, RHS rhs) : lhs(lhs), rhs(rhs) { } LHS lhs; RHS rhs; }; // We want char*s to be treated as pointers, not strings. If you want them treated like strings, // you'd need to use CHECK_STREQ and CHECK_STRNE anyway to compare the characters rather than their // addresses. We could express this more succinctly with std::remove_const, but this is quick and // easy to understand, and works before we have C++0x. We rely on signed/unsigned warnings to // protect you against combinations not explicitly listed below. #define EAGER_PTR_EVALUATOR(T1, T2) \ template <> struct EagerEvaluator { \ EagerEvaluator(T1 lhs, T2 rhs) \ : lhs(reinterpret_cast(lhs)), \ rhs(reinterpret_cast(rhs)) { } \ const void* lhs; \ const void* rhs; \ } EAGER_PTR_EVALUATOR(const char*, const char*); EAGER_PTR_EVALUATOR(const char*, char*); EAGER_PTR_EVALUATOR(char*, const char*); EAGER_PTR_EVALUATOR(char*, char*); EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*); EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*); EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*); EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*); EAGER_PTR_EVALUATOR(const signed char*, const signed char*); EAGER_PTR_EVALUATOR(const signed char*, signed char*); EAGER_PTR_EVALUATOR(signed char*, const signed char*); EAGER_PTR_EVALUATOR(signed char*, signed char*); // This indirection greatly reduces the stack impact of having // lots of checks/logging in a function. struct LogMessageData { public: LogMessageData(int line, LogSeverity severity, int error) : file(NULL), line_number(line), severity(severity), error(error) { } std::ostringstream buffer; const char* file; int line_number; LogSeverity severity; int error; private: DISALLOW_COPY_AND_ASSIGN(LogMessageData); }; class LogMessage { public: LogMessage(const char* file, int line, LogSeverity severity, int error); ~LogMessage(); std::ostream& stream(); private: void LogLine(const char*); LogMessageData* data_; DISALLOW_COPY_AND_ASSIGN(LogMessage); }; // Prints a hex dump in this format: // // 01234560: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef // 01234568: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0123456789abcdef class HexDump { public: HexDump(const void* address, size_t byte_count, bool show_actual_addresses = false); void Dump(std::ostream& os) const; private: const void* address_; size_t byte_count_; bool show_actual_addresses_; // TODO: Remove the #if when Mac OS build server no longer uses GCC 4.2.*. #if GCC_VERSION >= 40300 DISALLOW_COPY_AND_ASSIGN(HexDump); #endif }; std::ostream& operator<<(std::ostream& os, const HexDump& rhs); // A convenience to allow any class with a "Dump(std::ostream& os)" member function // but without an operator<< to be used as if it had an operator<<. Use like this: // // os << Dumpable(my_type_instance); // template class Dumpable { public: explicit Dumpable(T& value) : value_(value) { } void Dump(std::ostream& os) const { value_.Dump(os); } private: T& value_; // TODO: Remove the #if when Mac OS build server no longer uses GCC 4.2.*. #if GCC_VERSION >= 40300 DISALLOW_COPY_AND_ASSIGN(Dumpable); #endif }; template std::ostream& operator<<(std::ostream& os, const Dumpable& rhs) { rhs.Dump(os); return os; } // The members of this struct are the valid arguments to VLOG and VLOG_IS_ON in code, // and the "-verbose:" command line argument. struct LogVerbosity { bool class_linker; // Enabled with "-verbose:class". bool compiler; bool heap; bool gc; bool jdwp; bool jni; bool monitor; bool startup; bool third_party_jni; // Enabled with "-verbose:third-party-jni". bool threads; }; extern LogVerbosity gLogVerbosity; extern void InitLogging(char* argv[]); extern const char* GetCmdLine(); extern const char* ProgramInvocationName(); extern const char* ProgramInvocationShortName(); } // namespace art #endif // ART_SRC_LOGGING_H_