ART: Improve Indenter performance.

This reduces the time taken by oatdump_test by ~15s (16%)
on host and ~30s (5%) on N5. The Indenter.overflow() was
previously the hottest function according to perf.

Change-Id: I96eb69ce3f5420cd09dba23b29f8025cedc3d80a
diff --git a/runtime/indenter.h b/runtime/indenter.h
index d055d4e..38b398d 100644
--- a/runtime/indenter.h
+++ b/runtime/indenter.h
@@ -27,45 +27,76 @@
 class Indenter : public std::streambuf {
  public:
   Indenter(std::streambuf* out, char text, size_t count)
-      : indent_next_(true), out_sbuf_(out), text_(text), count_(count) {}
+      : indent_next_(true), out_sbuf_(out),
+        text_{text, text, text, text, text, text, text, text},  // NOLINT(whitespace/braces)
+        count_(count) {}
 
  private:
-  int_type overflow(int_type c) {
+  std::streamsize xsputn(const char* s, std::streamsize n) OVERRIDE {
+    std::streamsize result = n;  // Aborts on failure.
+    const char* eol = static_cast<const char*>(memchr(s, '\n', n));
+    while (eol != nullptr) {
+      size_t to_write = eol + 1 - s;
+      Write(s, to_write);
+      s += to_write;
+      n -= to_write;
+      indent_next_ = true;
+      eol = static_cast<const char*>(memchr(s, '\n', n));
+    }
+    if (n != 0u) {
+      Write(s, n);
+    }
+    return result;
+  }
+
+  int_type overflow(int_type c) OVERRIDE {
     if (UNLIKELY(c == std::char_traits<char>::eof())) {
       out_sbuf_->pubsync();
       return c;
     }
-    if (indent_next_) {
-      for (size_t i = 0; i < count_; ++i) {
-        int_type r = out_sbuf_->sputc(text_);
-        if (UNLIKELY(r != text_)) {
-          out_sbuf_->pubsync();
-          r = out_sbuf_->sputc(text_);
-          CHECK_EQ(r, text_) << "Error writing to buffer. Disk full?";
-        }
-      }
-    }
+    char data[1] = { static_cast<char>(c) };
+    Write(data, 1u);
     indent_next_ = (c == '\n');
-    int_type r = out_sbuf_->sputc(c);
-    if (UNLIKELY(r != c)) {
-      out_sbuf_->pubsync();
-      r = out_sbuf_->sputc(c);
-      CHECK_EQ(r, c) << "Error writing to buffer. Disk full?";
-    }
-    return r;
+    return c;
   }
 
   int sync() {
     return out_sbuf_->pubsync();
   }
 
+  void Write(const char* s, std::streamsize n) {
+    if (indent_next_) {
+      size_t remaining = count_;
+      while (remaining != 0u) {
+        size_t to_write = std::min(remaining, sizeof(text_));
+        RawWrite(text_, to_write);
+        remaining -= to_write;
+      }
+      indent_next_ = false;
+    }
+    RawWrite(s, n);
+  }
+
+  void RawWrite(const char* s, std::streamsize n) {
+    size_t written = out_sbuf_->sputn(s, n);
+    s += written;
+    n -= written;
+    while (n != 0u) {
+      out_sbuf_->pubsync();
+      written = out_sbuf_->sputn(s, n);
+      CHECK_NE(written, 0u) << "Error writing to buffer. Disk full?";
+      s += written;
+      n -= written;
+    }
+  }
+
   bool indent_next_;
 
   // Buffer to write output to.
   std::streambuf* const out_sbuf_;
 
   // Text output as indent.
-  const char text_;
+  const char text_[8];
 
   // Number of times text is output.
   const size_t count_;