diff options
Diffstat (limited to 'runtime/base/logging.h')
-rw-r--r-- | runtime/base/logging.h | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/runtime/base/logging.h b/runtime/base/logging.h new file mode 100644 index 0000000000..8d89e4d0cb --- /dev/null +++ b/runtime/base/logging.h @@ -0,0 +1,337 @@ +/* + * 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_BASE_LOGGING_H_ +#define ART_SRC_BASE_LOGGING_H_ + +#include <cerrno> +#include <cstring> +#include <iostream> // NOLINT +#include <sstream> +#include <signal.h> +#include "base/macros.h" +#include "log_severity.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<typeof(LHS), typeof(RHS)> _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 <typename LHS, typename RHS> +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<T1, T2> { \ + EagerEvaluator(T1 lhs, T2 rhs) \ + : lhs(reinterpret_cast<const void*>(lhs)), \ + rhs(reinterpret_cast<const void*>(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(const char* file, int line, LogSeverity severity, int error); + std::ostringstream buffer; + const char* const file; + const int line_number; + const LogSeverity severity; + const int error; + + private: + DISALLOW_COPY_AND_ASSIGN(LogMessageData); +}; + +class LogMessage { + public: + LogMessage(const char* file, int line, LogSeverity severity, int error) + : data_(new LogMessageData(file, line, severity, error)) { + } + + ~LogMessage() LOCKS_EXCLUDED(Locks::logging_lock_); + + std::ostream& stream() { + return data_->buffer; + } + + private: + static void LogLine(const LogMessageData& data, const char*); + + LogMessageData* const data_; + + friend void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context); + friend class Mutex; + 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<MyType>(my_type_instance); +// +template<typename T> +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<typename T> +std::ostream& operator<<(std::ostream& os, const Dumpable<T>& rhs) { + rhs.Dump(os); + return os; +} + +template<typename T> +class MutatorLockedDumpable { + public: + explicit MutatorLockedDumpable(T& value) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : value_(value) { + } + + void Dump(std::ostream& os) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + 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(MutatorLockedDumpable); +#endif +}; + +template<typename T> +std::ostream& operator<<(std::ostream& os, const MutatorLockedDumpable<T>& rhs) +// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) however annotalysis +// currently fails for this. + NO_THREAD_SAFETY_ANALYSIS { + rhs.Dump(os); + return os; +} + +// Helps you use operator<< in a const char*-like context such as our various 'F' methods with +// format strings. +template<typename T> +class ToStr { + public: + explicit ToStr(const T& value) { + std::ostringstream os; + os << value; + s_ = os.str(); + } + + const char* c_str() const { + return s_.c_str(); + } + + const std::string& str() const { + return s_; + } + + private: + std::string s_; + DISALLOW_COPY_AND_ASSIGN(ToStr); +}; + +// 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; + +// Used on fatal exit. Prevents recursive aborts. Allows us to disable +// some error checking to ensure fatal shutdown makes forward progress. +extern unsigned int gAborting; + +extern void InitLogging(char* argv[]); + +extern const char* GetCmdLine(); +extern const char* ProgramInvocationName(); +extern const char* ProgramInvocationShortName(); + +} // namespace art + +#endif // ART_SRC_BASE_LOGGING_H_ |