/*
* 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_RUNTIME_BASE_LOGGING_H_
#define ART_RUNTIME_BASE_LOGGING_H_
#include <cerrno>
#include <cstring>
#include <iostream> // NOLINT
#include <sstream>
#include <signal.h>
#include "base/macros.h"
#include "log_severity.h"
#include "UniquePtr.h"
#define CHECK(x) \
if (UNLIKELY(!(x))) \
::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \
<< "Check failed: " #x << " "
#define CHECK_OP(LHS, RHS, OP) \
for (auto _values = ::art::MakeEagerEvaluator(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()
#define VLOG_STREAM(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*);
template <typename LHS, typename RHS>
EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
return EagerEvaluator<LHS, RHS>(lhs, rhs);
}
// 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*);
const UniquePtr<LogMessageData> 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_;
DISALLOW_COPY_AND_ASSIGN(HexDump);
};
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_;
DISALLOW_COPY_AND_ASSIGN(Dumpable);
};
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_;
DISALLOW_COPY_AND_ASSIGN(MutatorLockedDumpable);
};
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 verifier;
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_RUNTIME_BASE_LOGGING_H_