Provide a convenience for logging types that don't have an operator<<.

Change-Id: I650b852ded67576dc5ec7c8e57732cfb49f1ecd6
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index d521e91..79a455e 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -890,12 +890,9 @@
   DexVerifier verifier(method);
   verifier.Verify();
 
-  LogMessage log(__FILE__, __LINE__, INFO, -1);
-  log.stream() << "Dump of method " << PrettyMethod(method) << " "
-               << verifier.fail_messages_.str();
-  log.stream() << std::endl << verifier.info_messages_.str();
-
-  verifier.Dump(log.stream());
+  LOG(INFO) << "Dump of method " << PrettyMethod(method) << " "
+            << verifier.fail_messages_.str() << std::endl
+            << verifier.info_messages_.str() << Dumpable<DexVerifier>(verifier);
 }
 
 DexVerifier::DexVerifier(Method* method) : java_lang_throwable_(NULL), work_insn_idx_(-1),
diff --git a/src/logging.h b/src/logging.h
index 2e7856e..b653931 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -171,6 +171,32 @@
 
 void HexDump(const void* address, size_t byte_count, bool show_actual_address = false);
 
+// 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;
+}
+
 }  // namespace art
 
 #endif  // ART_SRC_LOGGING_H_
diff --git a/src/object.cc b/src/object.cc
index 343f643..e59e79a 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -782,7 +782,7 @@
     if ((flags & kDumpClassInitialized) != 0) {
       os << ' ' << GetStatus();
     }
-    os << std::endl;
+    os << "\n";
     return;
   }
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 9c923fb..54d7ec6 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -76,27 +76,26 @@
   instance_ = NULL;
 }
 
+struct AbortState {
+  void Dump(std::ostream& os) {
+    os << "Runtime aborting...\n";
+    Thread* self = Thread::Current();
+    if (self == NULL) {
+      os << "(Aborting thread was not attached to runtime!)\n";
+    } else {
+      self->Dump(os, true);
+    }
+  }
+};
+
 void Runtime::Abort(const char* file, int line) {
   // Get any pending output out of the way.
   fflush(NULL);
 
   // Many people have difficulty distinguish aborts from crashes,
   // so be explicit.
-  {
-    LogMessage log(file, line, ERROR, -1);
-    log.stream() << "Runtime aborting..." << std::endl;
-    // Add Java stack trace if possible
-    Thread* thread = Thread::Current();
-    if (thread != NULL) {
-      log.stream() << "Java stack trace of aborting thread:" << std::endl;
-      thread->DumpStack(log.stream());
-      if (thread->IsExceptionPending()) {
-        Throwable* e = thread->GetException();
-        log.stream() << "Pending exception on thread: " << PrettyTypeOf(e) << std::endl;
-        log.stream() << e->Dump();
-      }
-    }
-  }
+  AbortState state;
+  LOG(ERROR) << Dumpable<AbortState>(state);
 
   // Perform any platform-specific pre-abort actions.
   PlatformAbort(file, line);
diff --git a/src/thread.cc b/src/thread.cc
index 54d2e6c..841ea9b 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -344,9 +344,13 @@
   CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), __FUNCTION__);
 }
 
-void Thread::Dump(std::ostream& os) const {
+void Thread::Dump(std::ostream& os, bool dump_pending_exception) const {
   DumpState(os);
   DumpStack(os);
+  if (dump_pending_exception && IsExceptionPending()) {
+    os << "Pending " << PrettyTypeOf(GetException()) << " on thread:\n";
+    os << GetException()->Dump();
+  }
 }
 
 std::string GetSchedulerGroup(pid_t tid) {
diff --git a/src/thread.h b/src/thread.h
index 975edfc..ac97ebe 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -180,7 +180,7 @@
   static Thread* FromManagedThread(JNIEnv* env, jobject thread);
   static uint32_t LockOwnerFromThreadLock(Object* thread_lock);
 
-  void Dump(std::ostream& os) const;
+  void Dump(std::ostream& os, bool dump_pending_exception = false) const;
 
   State GetState() const {
     return state_;
diff --git a/src/thread_list.cc b/src/thread_list.cc
index a77b8f6..6da5e68 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -371,9 +371,7 @@
   Thread* self = Thread::Current();
 
   if (verbose_) {
-    LogMessage log(__FILE__, __LINE__, INFO, -1);
-    log.stream() << "ThreadList::Register() " << *self << "\n";
-    self->Dump(log.stream());
+    LOG(INFO) << "ThreadList::Register() " << *self << "\n" << Dumpable<Thread>(*self);
   }
 
   ThreadListLocker locker(this);