Tidy up logging.

Move gVerboseMethods to CompilerOptions. Now "--verbose-methods=" option to
dex2oat rather than runtime argument "-verbose-methods:".
Move ToStr and Dumpable out of logging.h, move LogMessageData into logging.cc
except for a forward declaration.
Remove ConstDumpable as Dump methods are all const (and make this so if not
currently true).
Make LogSeverity an enum and improve compile time assertions and type checking.
Remove log_severity.h that's only used in logging.h.
With system headers gone from logging.h, go add to .cc files missing system
header includes.
Also, make operator new in ValueObject private for compile time instantiation
checking.

Change-Id: I3228f614500ccc9b14b49c72b9821c8b0db3d641
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 5af597b..46c3538 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -16,17 +16,25 @@
 
 #include "logging.h"
 
+#include <sstream>
+
 #include "base/mutex.h"
 #include "runtime.h"
 #include "thread-inl.h"
 #include "utils.h"
 
+// Headers for LogMessage::LogLine.
+#ifdef HAVE_ANDROID_OS
+#include "cutils/log.h"
+#else
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
 namespace art {
 
 LogVerbosity gLogVerbosity;
 
-std::vector<std::string> gVerboseMethods;
-
 unsigned int gAborting = 0;
 
 static LogSeverity gMinimumLogSeverity = INFO;
@@ -47,14 +55,6 @@
                                                         : "art";
 }
 
-// Configure logging based on ANDROID_LOG_TAGS environment variable.
-// We need to parse a string that looks like
-//
-//      *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
-//
-// The tag (or '*' for the global level) comes first, followed by a colon
-// and a letter indicating the minimum priority level we're expected to log.
-// This can be used to reveal or conceal logs with specific tags.
 void InitLogging(char* argv[]) {
   if (gCmdLine.get() != nullptr) {
     return;
@@ -65,22 +65,22 @@
   // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this,
   // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are
   // commonly used.
-  if (argv != NULL) {
+  if (argv != nullptr) {
     gCmdLine.reset(new std::string(argv[0]));
-    for (size_t i = 1; argv[i] != NULL; ++i) {
+    for (size_t i = 1; argv[i] != nullptr; ++i) {
       gCmdLine->append(" ");
       gCmdLine->append(argv[i]);
     }
     gProgramInvocationName.reset(new std::string(argv[0]));
     const char* last_slash = strrchr(argv[0], '/');
-    gProgramInvocationShortName.reset(new std::string((last_slash != NULL) ? last_slash + 1
+    gProgramInvocationShortName.reset(new std::string((last_slash != nullptr) ? last_slash + 1
                                                                            : argv[0]));
   } else {
-    // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux
+    // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux.
     gCmdLine.reset(new std::string("<unset>"));
   }
   const char* tags = getenv("ANDROID_LOG_TAGS");
-  if (tags == NULL) {
+  if (tags == nullptr) {
     return;
   }
 
@@ -119,47 +119,121 @@
   }
 }
 
-LogMessageData::LogMessageData(const char* file, int line, LogSeverity severity, int error)
-    : file(file),
-      line_number(line),
-      severity(severity),
-      error(error) {
-  const char* last_slash = strrchr(file, '/');
-  file = (last_slash == NULL) ? file : last_slash + 1;
-}
+// This indirection greatly reduces the stack impact of having
+// lots of checks/logging in a function.
+class LogMessageData {
+ public:
+  LogMessageData(const char* file, unsigned int line, LogSeverity severity, int error)
+      : file_(file),
+        line_number_(line),
+        severity_(severity),
+        error_(error) {
+    const char* last_slash = strrchr(file, '/');
+    file = (last_slash == nullptr) ? file : last_slash + 1;
+  }
 
+  const char * GetFile() const {
+    return file_;
+  }
+
+  unsigned int GetLineNumber() const {
+    return line_number_;
+  }
+
+  LogSeverity GetSeverity() const {
+    return severity_;
+  }
+
+  int GetError() const {
+    return error_;
+  }
+
+  std::ostream& GetBuffer() {
+    return buffer_;
+  }
+
+  std::string ToString() const {
+    return buffer_.str();
+  }
+
+ private:
+  std::ostringstream buffer_;
+  const char* const file_;
+  const unsigned int line_number_;
+  const LogSeverity severity_;
+  const int error_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, int error)
+  : data_(new LogMessageData(file, line, severity, error)) {
+}
 LogMessage::~LogMessage() {
-  if (data_->severity < gMinimumLogSeverity) {
+  if (data_->GetSeverity() < gMinimumLogSeverity) {
     return;  // No need to format something we're not going to output.
   }
 
   // Finish constructing the message.
-  if (data_->error != -1) {
-    data_->buffer << ": " << strerror(data_->error);
+  if (data_->GetError() != -1) {
+    data_->GetBuffer() << ": " << strerror(data_->GetError());
   }
-  std::string msg(data_->buffer.str());
+  std::string msg(data_->ToString());
 
   // Do the actual logging with the lock held.
   {
     MutexLock mu(Thread::Current(), *Locks::logging_lock_);
     if (msg.find('\n') == std::string::npos) {
-      LogLine(*data_, msg.c_str());
+      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), msg.c_str());
     } else {
       msg += '\n';
       size_t i = 0;
       while (i < msg.size()) {
         size_t nl = msg.find('\n', i);
         msg[nl] = '\0';
-        LogLine(*data_, &msg[i]);
+        LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), &msg[i]);
         i = nl + 1;
       }
     }
   }
 
   // Abort if necessary.
-  if (data_->severity == FATAL) {
+  if (data_->GetSeverity() == FATAL) {
     Runtime::Abort();
   }
 }
 
+std::ostream& LogMessage::stream() {
+  return data_->GetBuffer();
+}
+
+#ifdef HAVE_ANDROID_OS
+static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
+  ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
+  ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL
+};
+COMPILE_ASSERT(arraysize(kLogSeverityToAndroidLogPriority) == INTERNAL_FATAL + 1,
+               mismatch_in_size_of_kLogSeverityToAndroidLogPriority_and_values_in_LogSeverity);
+#endif
+
+void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity log_severity,
+                         const char* message) {
+#ifdef HAVE_ANDROID_OS
+  const char* tag = ProgramInvocationShortName();
+  int priority = kLogSeverityToAndroidLogPriority[log_severity];
+  if (priority == ANDROID_LOG_FATAL) {
+    LOG_PRI(priority, tag, "%s:%u] %s", file, line, message);
+  } else {
+    LOG_PRI(priority, tag, "%s", message);
+  }
+#else
+  static const char* log_characters = "VDIWEFF";
+  CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
+  char severity = log_characters[log_severity];
+  fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n",
+          ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(), file, line, message);
+#endif
+}
+
 }  // namespace art