OSDN Git Service

ART: Don't nest indenters in oatdump.
authorVladimir Marko <vmarko@google.com>
Fri, 26 Jun 2015 11:06:30 +0000 (12:06 +0100)
committerVladimir Marko <vmarko@google.com>
Mon, 13 Jul 2015 12:30:13 +0000 (13:30 +0100)
Reduces the time taken by the oatdump_test by ~12s (15%)
on host and ~55s (9%) on N5.

Change-Id: I99bb16ff5f3640389815f1fe54379ca64eac071b

oatdump/oatdump.cc
runtime/indenter.h
runtime/indenter_test.cc
runtime/stack_map.cc
runtime/stack_map.h
runtime/verifier/method_verifier.cc
runtime/verifier/method_verifier.h

index 8dde547..82452ba 100644 (file)
@@ -599,6 +599,9 @@ class OatDumper {
       os << std::flush;
       return false;
     }
+
+    VariableIndentationOutputStream vios(&os);
+    ScopedIndentation indent1(&vios);
     for (size_t class_def_index = 0;
          class_def_index < dex_file->NumClassDefs();
          class_def_index++) {
@@ -617,10 +620,8 @@ class OatDumper {
          << " (" << oat_class.GetStatus() << ")"
          << " (" << oat_class.GetType() << ")\n";
       // TODO: include bitmap here if type is kOatClassSomeCompiled?
-      Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-      std::ostream indented_os(&indent_filter);
       if (options_.list_classes_) continue;
-      if (!DumpOatClass(indented_os, oat_class, *(dex_file.get()), class_def, &stop_analysis)) {
+      if (!DumpOatClass(&vios, oat_class, *(dex_file.get()), class_def, &stop_analysis)) {
         success = false;
       }
       if (stop_analysis) {
@@ -720,20 +721,21 @@ class OatDumper {
     }
   }
 
-  bool DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
+  bool DumpOatClass(VariableIndentationOutputStream* vios,
+                    const OatFile::OatClass& oat_class, const DexFile& dex_file,
                     const DexFile::ClassDef& class_def, bool* stop_analysis) {
     bool success = true;
     bool addr_found = false;
     const uint8_t* class_data = dex_file.GetClassData(class_def);
     if (class_data == nullptr) {  // empty class such as a marker interface?
-      os << std::flush;
+      vios->Stream() << std::flush;
       return success;
     }
     ClassDataItemIterator it(dex_file, class_data);
     SkipAllFields(it);
     uint32_t class_method_index = 0;
     while (it.HasNextDirectMethod()) {
-      if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
+      if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
                          it.GetMemberIndex(), it.GetMethodCodeItem(),
                          it.GetRawMemberAccessFlags(), &addr_found)) {
         success = false;
@@ -746,7 +748,7 @@ class OatDumper {
       it.Next();
     }
     while (it.HasNextVirtualMethod()) {
-      if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
+      if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
                          it.GetMemberIndex(), it.GetMethodCodeItem(),
                          it.GetRawMemberAccessFlags(), &addr_found)) {
         success = false;
@@ -759,7 +761,7 @@ class OatDumper {
       it.Next();
     }
     DCHECK(!it.HasNext());
-    os << std::flush;
+    vios->Stream() << std::flush;
     return success;
   }
 
@@ -768,7 +770,8 @@ class OatDumper {
   // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
   static constexpr uint32_t kMaxCodeSize = 100 * 1000;
 
-  bool DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def,
+  bool DumpOatMethod(VariableIndentationOutputStream* vios,
+                     const DexFile::ClassDef& class_def,
                      uint32_t class_method_index,
                      const OatFile::OatClass& oat_class, const DexFile& dex_file,
                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
@@ -782,16 +785,11 @@ class OatDumper {
     }
 
     std::string pretty_method = PrettyMethod(dex_method_idx, dex_file, true);
-    os << StringPrintf("%d: %s (dex_method_idx=%d)\n",
-                       class_method_index, pretty_method.c_str(),
-                       dex_method_idx);
+    vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
+                                   class_method_index, pretty_method.c_str(),
+                                   dex_method_idx);
     if (options_.list_methods_) return success;
 
-    Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-    std::unique_ptr<std::ostream> indent1_os(new std::ostream(&indent1_filter));
-    Indenter indent2_filter(indent1_os->rdbuf(), kIndentChar, kIndentBy1Count);
-    std::unique_ptr<std::ostream> indent2_os(new std::ostream(&indent2_filter));
-
     uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
     const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
     const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
@@ -805,137 +803,147 @@ class OatDumper {
       }
     }
 
+    // Everything below is indented at least once.
+    ScopedIndentation indent1(vios);
+
     {
-      *indent1_os << "DEX CODE:\n";
-      DumpDexCode(*indent2_os, dex_file, code_item);
+      vios->Stream() << "DEX CODE:\n";
+      ScopedIndentation indent2(vios);
+      DumpDexCode(vios->Stream(), dex_file, code_item);
     }
 
     std::unique_ptr<verifier::MethodVerifier> verifier;
     if (Runtime::Current() != nullptr) {
-      *indent1_os << "VERIFIER TYPE ANALYSIS:\n";
-      verifier.reset(DumpVerifier(*indent2_os, dex_method_idx, &dex_file, class_def, code_item,
+      vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
+      ScopedIndentation indent2(vios);
+      verifier.reset(DumpVerifier(vios,
+                                  dex_method_idx, &dex_file, class_def, code_item,
                                   method_access_flags));
     }
     {
-      *indent1_os << "OatMethodOffsets ";
+      vios->Stream() << "OatMethodOffsets ";
       if (options_.absolute_addresses_) {
-        *indent1_os << StringPrintf("%p ", oat_method_offsets);
+        vios->Stream() << StringPrintf("%p ", oat_method_offsets);
       }
-      *indent1_os << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
       if (oat_method_offsets_offset > oat_file_.Size()) {
-        *indent1_os << StringPrintf(
+        vios->Stream() << StringPrintf(
             "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
             oat_method_offsets_offset, oat_file_.Size());
         // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
-        os << std::flush;
+        vios->Stream() << std::flush;
         return false;
       }
 
-      *indent2_os << StringPrintf("code_offset: 0x%08x ", code_offset);
+      ScopedIndentation indent2(vios);
+      vios->Stream() << StringPrintf("code_offset: 0x%08x ", code_offset);
       uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
       if (aligned_code_begin > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "code offset 0x%08x is past end of file 0x%08zx.\n",
-                                    aligned_code_begin, oat_file_.Size());
+        vios->Stream() << StringPrintf("WARNING: "
+                                       "code offset 0x%08x is past end of file 0x%08zx.\n",
+                                       aligned_code_begin, oat_file_.Size());
         success = false;
       }
-      *indent2_os << "\n";
+      vios->Stream() << "\n";
 
-      *indent2_os << "gc_map: ";
+      vios->Stream() << "gc_map: ";
       if (options_.absolute_addresses_) {
-        *indent2_os << StringPrintf("%p ", oat_method.GetGcMap());
+        vios->Stream() << StringPrintf("%p ", oat_method.GetGcMap());
       }
       uint32_t gc_map_offset = oat_method.GetGcMapOffset();
-      *indent2_os << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
       if (gc_map_offset > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "gc map table offset 0x%08x is past end of file 0x%08zx.\n",
-                                    gc_map_offset, oat_file_.Size());
+        vios->Stream() << StringPrintf("WARNING: "
+                           "gc map table offset 0x%08x is past end of file 0x%08zx.\n",
+                           gc_map_offset, oat_file_.Size());
         success = false;
       } else if (options_.dump_raw_gc_map_) {
-        Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent3_os(&indent3_filter);
-        DumpGcMap(indent3_os, oat_method, code_item);
+        ScopedIndentation indent3(vios);
+        DumpGcMap(vios->Stream(), oat_method, code_item);
       }
     }
     {
-      *indent1_os << "OatQuickMethodHeader ";
+      vios->Stream() << "OatQuickMethodHeader ";
       uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
       const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
 
       if (options_.absolute_addresses_) {
-        *indent1_os << StringPrintf("%p ", method_header);
+        vios->Stream() << StringPrintf("%p ", method_header);
       }
-      *indent1_os << StringPrintf("(offset=0x%08x)\n", method_header_offset);
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset);
       if (method_header_offset > oat_file_.Size()) {
-        *indent1_os << StringPrintf(
+        vios->Stream() << StringPrintf(
             "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
             method_header_offset, oat_file_.Size());
         // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
-        os << std::flush;
+        vios->Stream() << std::flush;
         return false;
       }
 
-      *indent2_os << "mapping_table: ";
+      ScopedIndentation indent2(vios);
+      vios->Stream() << "mapping_table: ";
       if (options_.absolute_addresses_) {
-        *indent2_os << StringPrintf("%p ", oat_method.GetMappingTable());
+        vios->Stream() << StringPrintf("%p ", oat_method.GetMappingTable());
       }
       uint32_t mapping_table_offset = oat_method.GetMappingTableOffset();
-      *indent2_os << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset());
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset());
       if (mapping_table_offset > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "mapping table offset 0x%08x is past end of file 0x%08zx. "
-                                    "mapping table offset was loaded from offset 0x%08x.\n",
-                                    mapping_table_offset, oat_file_.Size(),
-                                    oat_method.GetMappingTableOffsetOffset());
+        vios->Stream() << StringPrintf("WARNING: "
+                                       "mapping table offset 0x%08x is past end of file 0x%08zx. "
+                                       "mapping table offset was loaded from offset 0x%08x.\n",
+                                       mapping_table_offset, oat_file_.Size(),
+                                       oat_method.GetMappingTableOffsetOffset());
         success = false;
       } else if (options_.dump_raw_mapping_table_) {
-        Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent3_os(&indent3_filter);
-        DumpMappingTable(indent3_os, oat_method);
+        ScopedIndentation indent3(vios);
+        DumpMappingTable(vios, oat_method);
       }
 
-      *indent2_os << "vmap_table: ";
+      vios->Stream() << "vmap_table: ";
       if (options_.absolute_addresses_) {
-        *indent2_os << StringPrintf("%p ", oat_method.GetVmapTable());
+        vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
       }
       uint32_t vmap_table_offset = oat_method.GetVmapTableOffset();
-      *indent2_os << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
       if (vmap_table_offset > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "vmap table offset 0x%08x is past end of file 0x%08zx. "
-                                    "vmap table offset was loaded from offset 0x%08x.\n",
-                                    vmap_table_offset, oat_file_.Size(),
-                                    oat_method.GetVmapTableOffsetOffset());
+        vios->Stream() << StringPrintf("WARNING: "
+                                       "vmap table offset 0x%08x is past end of file 0x%08zx. "
+                                       "vmap table offset was loaded from offset 0x%08x.\n",
+                                       vmap_table_offset, oat_file_.Size(),
+                                       oat_method.GetVmapTableOffsetOffset());
         success = false;
       } else if (options_.dump_vmap_) {
-        DumpVmapData(*indent2_os, oat_method, code_item);
+        DumpVmapData(vios, oat_method, code_item);
       }
     }
     {
-      *indent1_os << "QuickMethodFrameInfo\n";
-
-      *indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
-      *indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
-      DumpSpillMask(*indent2_os, oat_method.GetCoreSpillMask(), false);
-      *indent2_os << "\n";
-      *indent2_os << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
-      DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true);
-      *indent2_os << "\n";
+      vios->Stream() << "QuickMethodFrameInfo\n";
+
+      ScopedIndentation indent2(vios);
+      vios->Stream()
+          << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
+      vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
+      DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false);
+      vios->Stream() << "\n";
+      vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
+      DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true);
+      vios->Stream() << "\n";
     }
     {
-        // Based on spill masks from QuickMethodFrameInfo so placed
-        // after it is dumped, but useful for understanding quick
-        // code, so dumped here.
-        DumpVregLocations(*indent2_os, oat_method, code_item);
+      // Based on spill masks from QuickMethodFrameInfo so placed
+      // after it is dumped, but useful for understanding quick
+      // code, so dumped here.
+      ScopedIndentation indent2(vios);
+      DumpVregLocations(vios->Stream(), oat_method, code_item);
     }
     {
-      *indent1_os << "CODE: ";
+      vios->Stream() << "CODE: ";
       uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
       if (code_size_offset > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "code size offset 0x%08x is past end of file 0x%08zx.",
-                                    code_size_offset, oat_file_.Size());
+        ScopedIndentation indent2(vios);
+        vios->Stream() << StringPrintf("WARNING: "
+                                       "code size offset 0x%08x is past end of file 0x%08zx.",
+                                       code_size_offset, oat_file_.Size());
         success = false;
       } else {
         const void* code = oat_method.GetQuickCode();
@@ -943,49 +951,52 @@ class OatDumper {
         uint64_t aligned_code_end = aligned_code_begin + code_size;
 
         if (options_.absolute_addresses_) {
-          *indent1_os << StringPrintf("%p ", code);
+          vios->Stream() << StringPrintf("%p ", code);
         }
-        *indent1_os << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
-                                    code_offset,
-                                    code_size_offset,
-                                    code_size,
-                                    code != nullptr ? "..." : "");
+        vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
+                                       code_offset,
+                                       code_size_offset,
+                                       code_size,
+                                       code != nullptr ? "..." : "");
 
+        ScopedIndentation indent2(vios);
         if (aligned_code_begin > oat_file_.Size()) {
-          *indent2_os << StringPrintf("WARNING: "
-                                      "start of code at 0x%08x is past end of file 0x%08zx.",
-                                      aligned_code_begin, oat_file_.Size());
+          vios->Stream() << StringPrintf("WARNING: "
+                                         "start of code at 0x%08x is past end of file 0x%08zx.",
+                                         aligned_code_begin, oat_file_.Size());
           success = false;
         } else if (aligned_code_end > oat_file_.Size()) {
-          *indent2_os << StringPrintf("WARNING: "
-                                      "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
-                                      "code size is 0x%08x loaded from offset 0x%08x.\n",
-                                      aligned_code_end, oat_file_.Size(),
-                                      code_size, code_size_offset);
+          vios->Stream() << StringPrintf(
+              "WARNING: "
+              "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
+              "code size is 0x%08x loaded from offset 0x%08x.\n",
+              aligned_code_end, oat_file_.Size(),
+              code_size, code_size_offset);
           success = false;
           if (options_.disassemble_code_) {
             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
-              DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
+              DumpCode(vios, verifier.get(), oat_method, code_item, true, kPrologueBytes);
             }
           }
         } else if (code_size > kMaxCodeSize) {
-          *indent2_os << StringPrintf("WARNING: "
-                                      "code size %d is bigger than max expected threshold of %d. "
-                                      "code size is 0x%08x loaded from offset 0x%08x.\n",
-                                      code_size, kMaxCodeSize,
-                                      code_size, code_size_offset);
+          vios->Stream() << StringPrintf(
+              "WARNING: "
+              "code size %d is bigger than max expected threshold of %d. "
+              "code size is 0x%08x loaded from offset 0x%08x.\n",
+              code_size, kMaxCodeSize,
+              code_size, code_size_offset);
           success = false;
           if (options_.disassemble_code_) {
             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
-              DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
+              DumpCode(vios, verifier.get(), oat_method, code_item, true, kPrologueBytes);
             }
           }
         } else if (options_.disassemble_code_) {
-          DumpCode(*indent2_os, verifier.get(), oat_method, code_item, !success, 0);
+          DumpCode(vios, verifier.get(), oat_method, code_item, !success, 0);
         }
       }
     }
-    os << std::flush;
+    vios->Stream() << std::flush;
     return success;
   }
 
@@ -1013,7 +1024,7 @@ class OatDumper {
   }
 
   // Display data stored at the the vmap offset of an oat method.
-  void DumpVmapData(std::ostream& os,
+  void DumpVmapData(VariableIndentationOutputStream* vios,
                     const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem* code_item) {
     if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
@@ -1022,24 +1033,25 @@ class OatDumper {
       if (raw_code_info != nullptr) {
         CodeInfo code_info(raw_code_info);
         DCHECK(code_item != nullptr);
-        DumpCodeInfo(os, code_info, oat_method, *code_item);
+        ScopedIndentation indent1(vios);
+        DumpCodeInfo(vios, code_info, oat_method, *code_item);
       }
     } else {
       // Otherwise, display the vmap table.
       const uint8_t* raw_table = oat_method.GetVmapTable();
       if (raw_table != nullptr) {
         VmapTable vmap_table(raw_table);
-        DumpVmapTable(os, oat_method, vmap_table);
+        DumpVmapTable(vios->Stream(), oat_method, vmap_table);
       }
     }
   }
 
   // Display a CodeInfo object emitted by the optimizing compiler.
-  void DumpCodeInfo(std::ostream& os,
+  void DumpCodeInfo(VariableIndentationOutputStream* vios,
                     const CodeInfo& code_info,
                     const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem& code_item) {
-    code_info.Dump(os,
+    code_info.Dump(vios,
                    oat_method.GetCodeOffset(),
                    code_item.registers_size_,
                    options_.dump_code_info_stack_maps_);
@@ -1177,48 +1189,50 @@ class OatDumper {
     }
   }
 
-  void DumpMappingTable(std::ostream& os, const OatFile::OatMethod& oat_method) {
+  void DumpMappingTable(VariableIndentationOutputStream* vios,
+                        const OatFile::OatMethod& oat_method) {
     const void* quick_code = oat_method.GetQuickCode();
     if (quick_code == nullptr) {
       return;
     }
     MappingTable table(oat_method.GetMappingTable());
     if (table.TotalSize() != 0) {
-      Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-      std::ostream indent_os(&indent_filter);
       if (table.PcToDexSize() != 0) {
         typedef MappingTable::PcToDexIterator It;
-        os << "suspend point mappings {\n";
+        vios->Stream() << "suspend point mappings {\n";
         for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
-          indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
+          ScopedIndentation indent1(vios);
+          vios->Stream() << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
         }
-        os << "}\n";
+        vios->Stream() << "}\n";
       }
       if (table.DexToPcSize() != 0) {
         typedef MappingTable::DexToPcIterator It;
-        os << "catch entry mappings {\n";
+        vios->Stream() << "catch entry mappings {\n";
         for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
-          indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
+          ScopedIndentation indent1(vios);
+          vios->Stream() << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
         }
-        os << "}\n";
+        vios->Stream() << "}\n";
       }
     }
   }
 
-  uint32_t DumpInformationAtOffset(std::ostream& os,
+  uint32_t DumpInformationAtOffset(VariableIndentationOutputStream* vios,
                                    const OatFile::OatMethod& oat_method,
                                    const DexFile::CodeItem* code_item,
                                    size_t offset,
                                    bool suspend_point_mapping) {
     if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
       if (suspend_point_mapping) {
-        DumpDexRegisterMapAtOffset(os, oat_method, code_item, offset);
+        ScopedIndentation indent1(vios);
+        DumpDexRegisterMapAtOffset(vios, oat_method, code_item, offset);
       }
       // The return value is not used in the case of a method compiled
       // with the optimizing compiler.
       return DexFile::kDexNoIndex;
     } else {
-      return DumpMappingAtOffset(os, oat_method, offset, suspend_point_mapping);
+      return DumpMappingAtOffset(vios->Stream(), oat_method, offset, suspend_point_mapping);
     }
   }
 
@@ -1334,7 +1348,7 @@ class OatDumper {
     return oat_method.GetGcMap() == nullptr && code_item != nullptr;
   }
 
-  void DumpDexRegisterMapAtOffset(std::ostream& os,
+  void DumpDexRegisterMapAtOffset(VariableIndentationOutputStream* vios,
                                   const OatFile::OatMethod& oat_method,
                                   const DexFile::CodeItem* code_item,
                                   size_t offset) {
@@ -1349,13 +1363,14 @@ class OatDumper {
       StackMapEncoding encoding = code_info.ExtractEncoding();
       StackMap stack_map = code_info.GetStackMapForNativePcOffset(offset, encoding);
       if (stack_map.IsValid()) {
-        stack_map.Dump(
-            os, code_info, encoding, oat_method.GetCodeOffset(), code_item->registers_size_);
+        stack_map.Dump(vios, code_info, encoding, oat_method.GetCodeOffset(),
+                       code_item->registers_size_);
       }
     }
   }
 
-  verifier::MethodVerifier* DumpVerifier(std::ostream& os, uint32_t dex_method_idx,
+  verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
+                                         uint32_t dex_method_idx,
                                          const DexFile* dex_file,
                                          const DexFile::ClassDef& class_def,
                                          const DexFile::CodeItem* code_item,
@@ -1367,14 +1382,15 @@ class OatDumper {
           hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file)));
       DCHECK(options_.class_loader_ != nullptr);
       return verifier::MethodVerifier::VerifyMethodAndDump(
-          soa.Self(), os, dex_method_idx, dex_file, dex_cache, *options_.class_loader_, &class_def,
-          code_item, nullptr, method_access_flags);
+          soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
+          &class_def, code_item, nullptr, method_access_flags);
     }
 
     return nullptr;
   }
 
-  void DumpCode(std::ostream& os, verifier::MethodVerifier* verifier,
+  void DumpCode(VariableIndentationOutputStream* vios,
+                verifier::MethodVerifier* verifier,
                 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
                 bool bad_input, size_t code_size) {
     const void* quick_code = oat_method.GetQuickCode();
@@ -1383,22 +1399,23 @@ class OatDumper {
       code_size = oat_method.GetQuickCodeSize();
     }
     if (code_size == 0 || quick_code == nullptr) {
-      os << "NO CODE!\n";
+      vios->Stream() << "NO CODE!\n";
       return;
     } else {
       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
       size_t offset = 0;
       while (offset < code_size) {
         if (!bad_input) {
-          DumpInformationAtOffset(os, oat_method, code_item, offset, false);
+          DumpInformationAtOffset(vios, oat_method, code_item, offset, false);
         }
-        offset += disassembler_->Dump(os, quick_native_pc + offset);
+        offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
         if (!bad_input) {
-          uint32_t dex_pc = DumpInformationAtOffset(os, oat_method, code_item, offset, true);
+          uint32_t dex_pc =
+              DumpInformationAtOffset(vios, oat_method, code_item, offset, true);
           if (dex_pc != DexFile::kDexNoIndex) {
-            DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
+            DumpGcMapAtNativePcOffset(vios->Stream(), oat_method, code_item, offset);
             if (verifier != nullptr) {
-              DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc);
+              DumpVRegsAtDexPc(vios->Stream(), verifier, oat_method, code_item, dex_pc);
             }
           }
         }
@@ -1420,12 +1437,16 @@ class ImageDumper {
   explicit ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space,
                        const ImageHeader& image_header, OatDumperOptions* oat_dumper_options)
       : os_(os),
+        vios_(os),
+        indent1_(&vios_),
         image_space_(image_space),
         image_header_(image_header),
         oat_dumper_options_(oat_dumper_options) {}
 
   bool Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     std::ostream& os = *os_;
+    std::ostream& indent_os = vios_.Stream();
+
     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
 
     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
@@ -1453,20 +1474,17 @@ class ImageDumper {
 
     {
       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
-      Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-      std::ostream indent1_os(&indent1_filter);
       static_assert(arraysize(image_roots_descriptions_) ==
           static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
       for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
         const char* image_root_description = image_roots_descriptions_[i];
         mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
-        indent1_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
+        indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
         if (image_root_object->IsObjectArray()) {
-          Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
-          std::ostream indent2_os(&indent2_filter);
           mirror::ObjectArray<mirror::Object>* image_root_object_array
               = image_root_object->AsObjectArray<mirror::Object>();
+          ScopedIndentation indent2(&vios_);
           for (int j = 0; j < image_root_object_array->GetLength(); j++) {
             mirror::Object* value = image_root_object_array->Get(j);
             size_t run = 0;
@@ -1478,20 +1496,22 @@ class ImageDumper {
               }
             }
             if (run == 0) {
-              indent2_os << StringPrintf("%d: ", j);
+              indent_os << StringPrintf("%d: ", j);
             } else {
-              indent2_os << StringPrintf("%d to %zd: ", j, j + run);
+              indent_os << StringPrintf("%d to %zd: ", j, j + run);
               j = j + run;
             }
             if (value != nullptr) {
-              PrettyObjectValue(indent2_os, value->GetClass(), value);
+              PrettyObjectValue(indent_os, value->GetClass(), value);
             } else {
-              indent2_os << j << ": null\n";
+              indent_os << j << ": null\n";
             }
           }
         }
       }
+    }
 
+    {
       os << "METHOD ROOTS\n";
       static_assert(arraysize(image_methods_descriptions_) ==
           static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
@@ -1499,7 +1519,7 @@ class ImageDumper {
         auto image_root = static_cast<ImageHeader::ImageMethod>(i);
         const char* description = image_methods_descriptions_[i];
         auto* image_method = image_header_.GetImageMethod(image_root);
-        indent1_os << StringPrintf("%s: %p\n", description, image_method);
+        indent_os << StringPrintf("%s: %p\n", description, image_method);
       }
     }
     os << "\n";
@@ -1556,11 +1576,6 @@ class ImageDumper {
       }
     }
     {
-      std::ostream* saved_os = os_;
-      Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-      std::ostream indent_os(&indent_filter);
-      os_ = &indent_os;
-
       // Mark dex caches.
       dex_cache_arrays_.clear();
       {
@@ -1596,7 +1611,6 @@ class ImageDumper {
       // Dump the large objects separately.
       heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
       indent_os << "\n";
-      os_ = saved_os;
     }
     os << "STATS:\n" << std::flush;
     std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
@@ -1621,7 +1635,7 @@ class ImageDumper {
     // RoundUp to 8 bytes to match the intern table alignment expectation.
     stats_.art_method_bytes += RoundUp(method_section.Size(), sizeof(uint64_t));
     stats_.interned_strings_bytes += intern_section.Size();
-    stats_.Dump(os);
+    stats_.Dump(os, indent_os);
     os << "\n";
 
     os << std::flush;
@@ -1760,7 +1774,8 @@ class ImageDumper {
     state->stats_.object_bytes += object_bytes;
     state->stats_.alignment_bytes += alignment_bytes;
 
-    std::ostream& os = *state->os_;
+    std::ostream& os = state->vios_.Stream();
+
     mirror::Class* obj_class = obj->GetClass();
     if (obj_class->IsArrayClass()) {
       os << StringPrintf("%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
@@ -1775,9 +1790,8 @@ class ImageDumper {
     } else {
       os << StringPrintf("%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
     }
-    Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-    std::ostream indent_os(&indent_filter);
-    DumpFields(indent_os, obj, obj_class);
+    ScopedIndentation indent1(&state->vios_);
+    DumpFields(os, obj, obj_class);
     const auto image_pointer_size =
         InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet());
     if (obj->IsObjectArray()) {
@@ -1793,25 +1807,24 @@ class ImageDumper {
           }
         }
         if (run == 0) {
-          indent_os << StringPrintf("%d: ", i);
+          os << StringPrintf("%d: ", i);
         } else {
-          indent_os << StringPrintf("%d to %zd: ", i, i + run);
+          os << StringPrintf("%d to %zd: ", i, i + run);
           i = i + run;
         }
         mirror::Class* value_class =
             (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
-        PrettyObjectValue(indent_os, value_class, value);
+        PrettyObjectValue(os, value_class, value);
       }
     } else if (obj->IsClass()) {
       mirror::Class* klass = obj->AsClass();
       ArtField* sfields = klass->GetSFields();
       const size_t num_fields = klass->NumStaticFields();
       if (num_fields != 0) {
-        indent_os << "STATICS:\n";
-        Indenter indent2_filter(indent_os.rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent2_os(&indent2_filter);
+        os << "STATICS:\n";
+        ScopedIndentation indent2(&state->vios_);
         for (size_t i = 0; i < num_fields; i++) {
-          PrintField(indent2_os, &sfields[i], sfields[i].GetDeclaringClass());
+          PrintField(os, &sfields[i], sfields[i].GetDeclaringClass());
         }
       }
     } else {
@@ -1827,9 +1840,9 @@ class ImageDumper {
           for (int32_t j = i + 1; j < length &&
               elem == arr->GetElementPtrSize<void*>(j, image_pointer_size); j++, run++) { }
           if (run == 0) {
-            indent_os << StringPrintf("%d: ", i);
+            os << StringPrintf("%d: ", i);
           } else {
-            indent_os << StringPrintf("%d to %zd: ", i, i + run);
+            os << StringPrintf("%d to %zd: ", i, i + run);
             i = i + run;
           }
           auto offset = reinterpret_cast<uint8_t*>(elem) - state->image_space_.Begin();
@@ -1841,7 +1854,7 @@ class ImageDumper {
           } else {
             msg = "Unknown type";
           }
-          indent_os << StringPrintf("%p   %s\n", elem, msg.c_str());
+          os << StringPrintf("%p   %s\n", elem, msg.c_str());
         }
       }
     }
@@ -1920,7 +1933,7 @@ class ImageDumper {
 
       indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
       indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
-      dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
+                                dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
 
       size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
           vmap_table_bytes + quick_oat_code_size + ArtMethod::ObjectSize(image_pointer_size);
@@ -2135,12 +2148,11 @@ class ImageDumper {
       os << "\n" << std::flush;
     }
 
-    void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    void Dump(std::ostream& os, std::ostream& indent_os)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
       {
         os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
            << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
-        Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent_os(&indent_filter);
         indent_os << StringPrintf("header_bytes          =  %8zd (%2.0f%% of art file bytes)\n"
                                   "object_bytes          =  %8zd (%2.0f%% of art file bytes)\n"
                                   "art_field_bytes       =  %8zd (%2.0f%% of art file bytes)\n"
@@ -2233,7 +2245,13 @@ class ImageDumper {
     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
     kLargeMethodDexBytes = 16000
   };
+
+  // For performance, use the *os_ directly for anything that doesn't need indentation
+  // and prepare an indentation stream with default indentation 1.
   std::ostream* os_;
+  VariableIndentationOutputStream vios_;
+  ScopedIndentation indent1_;
+
   gc::space::ImageSpace& image_space_;
   const ImageHeader& image_header_;
   std::unique_ptr<OatDumper> oat_dumper_;
index 38b398d..78b18f6 100644 (file)
 
 #include "base/logging.h"
 #include "base/macros.h"
+#include <ostream>
 #include <streambuf>
 
-const char kIndentChar =' ';
-const size_t kIndentBy1Count = 2;
+namespace art {
+
+constexpr char kIndentChar =' ';
+constexpr size_t kIndentBy1Count = 2;
 
 class Indenter : public std::streambuf {
  public:
@@ -99,9 +102,60 @@ class Indenter : public std::streambuf {
   const char text_[8];
 
   // Number of times text is output.
-  const size_t count_;
+  size_t count_;
+
+  friend class VariableIndentationOutputStream;
 
   DISALLOW_COPY_AND_ASSIGN(Indenter);
 };
 
+class VariableIndentationOutputStream {
+ public:
+  explicit VariableIndentationOutputStream(std::ostream* os, char text = kIndentChar)
+      : indenter_(os->rdbuf(), text, 0u),
+        indented_os_(&indenter_) {
+  }
+
+  std::ostream& Stream() {
+    return indented_os_;
+  }
+
+  void IncreaseIndentation(size_t adjustment) {
+    indenter_.count_ += adjustment;
+  }
+
+  void DecreaseIndentation(size_t adjustment) {
+    DCHECK_GE(indenter_.count_, adjustment);
+    indenter_.count_ -= adjustment;
+  }
+
+ private:
+  Indenter indenter_;
+  std::ostream indented_os_;
+
+  DISALLOW_COPY_AND_ASSIGN(VariableIndentationOutputStream);
+};
+
+class ScopedIndentation {
+ public:
+  explicit ScopedIndentation(VariableIndentationOutputStream* vios,
+                             size_t adjustment = kIndentBy1Count)
+      : vios_(vios),
+        adjustment_(adjustment) {
+    vios_->IncreaseIndentation(adjustment_);
+  }
+
+  ~ScopedIndentation() {
+    vios_->DecreaseIndentation(adjustment_);
+  }
+
+ private:
+  VariableIndentationOutputStream* const vios_;
+  const size_t adjustment_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedIndentation);
+};
+
+}  // namespace art
+
 #endif  // ART_RUNTIME_INDENTER_H_
index 1919e3d..1a26d7b 100644 (file)
@@ -17,6 +17,8 @@
 #include "gtest/gtest.h"
 #include "indenter.h"
 
+namespace art {
+
 TEST(IndenterTest, MultiLineTest) {
   std::ostringstream output;
   Indenter indent_filter(output.rdbuf(), '\t', 2);
@@ -33,3 +35,5 @@ TEST(IndenterTest, MultiLineTest) {
   input << "\n";
   EXPECT_EQ(output.str(), "\t\thello\n\t\thello again\n");
 }
+
+}  // namespace art
index 741cd90..962132b 100644 (file)
@@ -95,40 +95,37 @@ static void DumpRegisterMapping(std::ostream& os,
                                 DexRegisterLocation location,
                                 const std::string& prefix = "v",
                                 const std::string& suffix = "") {
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << prefix << dex_register_num << ": "
-              << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
-              << " (" << location.GetValue() << ")" << suffix << '\n';
+  os << prefix << dex_register_num << ": "
+     << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
+     << " (" << location.GetValue() << ")" << suffix << '\n';
 }
 
-void CodeInfo::Dump(std::ostream& os,
+void CodeInfo::Dump(VariableIndentationOutputStream* vios,
                     uint32_t code_offset,
                     uint16_t number_of_dex_registers,
                     bool dump_stack_maps) const {
   StackMapEncoding encoding = ExtractEncoding();
   uint32_t code_info_size = GetOverallSize();
   size_t number_of_stack_maps = GetNumberOfStackMaps();
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << "Optimized CodeInfo (size=" << code_info_size
-              << ", number_of_dex_registers=" << number_of_dex_registers
-              << ", number_of_stack_maps=" << number_of_stack_maps
-              << ", has_inline_info=" << encoding.HasInlineInfo()
-              << ", number_of_bytes_for_inline_info=" << encoding.NumberOfBytesForInlineInfo()
-              << ", number_of_bytes_for_dex_register_map="
-                  << encoding.NumberOfBytesForDexRegisterMap()
-              << ", number_of_bytes_for_dex_pc=" << encoding.NumberOfBytesForDexPc()
-              << ", number_of_bytes_for_native_pc=" << encoding.NumberOfBytesForNativePc()
-              << ", number_of_bytes_for_register_mask=" << encoding.NumberOfBytesForRegisterMask()
-              << ")\n";
+  vios->Stream()
+      << "Optimized CodeInfo (size=" << code_info_size
+      << ", number_of_dex_registers=" << number_of_dex_registers
+      << ", number_of_stack_maps=" << number_of_stack_maps
+      << ", has_inline_info=" << encoding.HasInlineInfo()
+      << ", number_of_bytes_for_inline_info=" << encoding.NumberOfBytesForInlineInfo()
+      << ", number_of_bytes_for_dex_register_map=" << encoding.NumberOfBytesForDexRegisterMap()
+      << ", number_of_bytes_for_dex_pc=" << encoding.NumberOfBytesForDexPc()
+      << ", number_of_bytes_for_native_pc=" << encoding.NumberOfBytesForNativePc()
+      << ", number_of_bytes_for_register_mask=" << encoding.NumberOfBytesForRegisterMask()
+      << ")\n";
+  ScopedIndentation indent1(vios);
   // Display the Dex register location catalog.
-  GetDexRegisterLocationCatalog(encoding).Dump(indented_os, *this);
+  GetDexRegisterLocationCatalog(encoding).Dump(vios, *this);
   // Display stack maps along with (live) Dex register maps.
   if (dump_stack_maps) {
     for (size_t i = 0; i < number_of_stack_maps; ++i) {
       StackMap stack_map = GetStackMapAt(i, encoding);
-      stack_map.Dump(indented_os,
+      stack_map.Dump(vios,
                      *this,
                      encoding,
                      code_offset,
@@ -140,30 +137,28 @@ void CodeInfo::Dump(std::ostream& os,
   //       we need to know the number of dex registers for each inlined method.
 }
 
-void DexRegisterLocationCatalog::Dump(std::ostream& os, const CodeInfo& code_info) {
+void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios,
+                                      const CodeInfo& code_info) {
   StackMapEncoding encoding = code_info.ExtractEncoding();
   size_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
   size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding);
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os
+  vios->Stream()
       << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
       << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
   for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
     DexRegisterLocation location = GetDexRegisterLocation(i);
-    DumpRegisterMapping(indented_os, i, location, "entry ");
+    ScopedIndentation indent1(vios);
+    DumpRegisterMapping(vios->Stream(), i, location, "entry ");
   }
 }
 
-void DexRegisterMap::Dump(std::ostream& os,
+void DexRegisterMap::Dump(VariableIndentationOutputStream* vios,
                           const CodeInfo& code_info,
                           uint16_t number_of_dex_registers) const {
   StackMapEncoding encoding = code_info.ExtractEncoding();
   size_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
   // TODO: Display the bit mask of live Dex registers.
   for (size_t j = 0; j < number_of_dex_registers; ++j) {
     if (IsDexRegisterLive(j)) {
@@ -173,70 +168,70 @@ void DexRegisterMap::Dump(std::ostream& os,
                                                             number_of_dex_registers,
                                                             code_info,
                                                             encoding);
+      ScopedIndentation indent1(vios);
       DumpRegisterMapping(
-          indented_os, j, location, "v",
+          vios->Stream(), j, location, "v",
           "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
     }
   }
 }
 
-void StackMap::Dump(std::ostream& os,
+void StackMap::Dump(VariableIndentationOutputStream* vios,
                     const CodeInfo& code_info,
                     const StackMapEncoding& encoding,
                     uint32_t code_offset,
                     uint16_t number_of_dex_registers,
                     const std::string& header_suffix) const {
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << "StackMap" << header_suffix
-              << std::hex
-              << " [native_pc=0x" << code_offset + GetNativePcOffset(encoding) << "]"
-              << " (dex_pc=0x" << GetDexPc(encoding)
-              << ", native_pc_offset=0x" << GetNativePcOffset(encoding)
-              << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(encoding)
-              << ", inline_info_offset=0x" << GetInlineDescriptorOffset(encoding)
-              << ", register_mask=0x" << GetRegisterMask(encoding)
-              << std::dec
-              << ", stack_mask=0b";
+  vios->Stream()
+      << "StackMap" << header_suffix
+      << std::hex
+      << " [native_pc=0x" << code_offset + GetNativePcOffset(encoding) << "]"
+      << " (dex_pc=0x" << GetDexPc(encoding)
+      << ", native_pc_offset=0x" << GetNativePcOffset(encoding)
+      << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(encoding)
+      << ", inline_info_offset=0x" << GetInlineDescriptorOffset(encoding)
+      << ", register_mask=0x" << GetRegisterMask(encoding)
+      << std::dec
+      << ", stack_mask=0b";
   MemoryRegion stack_mask = GetStackMask(encoding);
   for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
-    indented_os << stack_mask.LoadBit(e - i - 1);
+    vios->Stream() << stack_mask.LoadBit(e - i - 1);
   }
-  indented_os << ")\n";
+  vios->Stream() << ")\n";
   if (HasDexRegisterMap(encoding)) {
     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
         *this, encoding, number_of_dex_registers);
-    dex_register_map.Dump(os, code_info, number_of_dex_registers);
+    dex_register_map.Dump(vios, code_info, number_of_dex_registers);
   }
   if (HasInlineInfo(encoding)) {
     InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding);
     // We do not know the length of the dex register maps of inlined frames
     // at this level, so we just pass null to `InlineInfo::Dump` to tell
     // it not to look at these maps.
-    inline_info.Dump(os, code_info, nullptr);
+    inline_info.Dump(vios, code_info, nullptr);
   }
 }
 
-void InlineInfo::Dump(std::ostream& os,
+void InlineInfo::Dump(VariableIndentationOutputStream* vios,
                       const CodeInfo& code_info,
                       uint16_t number_of_dex_registers[]) const {
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
+  vios->Stream() << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
 
   for (size_t i = 0; i < GetDepth(); ++i) {
-    indented_os << " At depth " << i
-                << std::hex
-                << " (dex_pc=0x" << GetDexPcAtDepth(i)
-                << std::dec
-                << ", method_index=" << GetMethodIndexAtDepth(i)
-                << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(i))
-                << ")\n";
+    vios->Stream()
+        << " At depth " << i
+        << std::hex
+        << " (dex_pc=0x" << GetDexPcAtDepth(i)
+        << std::dec
+        << ", method_index=" << GetMethodIndexAtDepth(i)
+        << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(i))
+        << ")\n";
     if (HasDexRegisterMapAtDepth(i) && (number_of_dex_registers != nullptr)) {
       StackMapEncoding encoding = code_info.ExtractEncoding();
       DexRegisterMap dex_register_map =
           code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
-      dex_register_map.Dump(indented_os, code_info, number_of_dex_registers[i]);
+      ScopedIndentation indent1(vios);
+      dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]);
     }
   }
 }
index 4e42008..e8769f9 100644 (file)
@@ -23,6 +23,8 @@
 
 namespace art {
 
+class VariableIndentationOutputStream;
+
 // Size of a frame slot, in bytes.  This constant is a signed value,
 // to please the compiler in arithmetic operations involving int32_t
 // (signed) values.
@@ -357,7 +359,7 @@ class DexRegisterLocationCatalog {
     return region_.size();
   }
 
-  void Dump(std::ostream& os, const CodeInfo& code_info);
+  void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
 
   // Special (invalid) Dex register location catalog entry index meaning
   // that there is no location for a given Dex register (i.e., it is
@@ -610,7 +612,8 @@ class DexRegisterMap {
     return region_.size();
   }
 
-  void Dump(std::ostream& o, const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
+  void Dump(VariableIndentationOutputStream* vios,
+            const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
 
  private:
   // Return the index in the Dex register map corresponding to the Dex
@@ -837,7 +840,7 @@ class StackMap {
        && region_.size() == other.region_.size();
   }
 
-  void Dump(std::ostream& os,
+  void Dump(VariableIndentationOutputStream* vios,
             const CodeInfo& code_info,
             const StackMapEncoding& encoding,
             uint32_t code_offset,
@@ -931,7 +934,8 @@ class InlineInfo {
     return kFixedEntrySize;
   }
 
-  void Dump(std::ostream& os, const CodeInfo& info, uint16_t* number_of_dex_registers) const;
+  void Dump(VariableIndentationOutputStream* vios,
+            const CodeInfo& info, uint16_t* number_of_dex_registers) const;
 
  private:
   // TODO: Instead of plain types such as "uint8_t", introduce
@@ -1120,7 +1124,7 @@ class CodeInfo {
   // number of Dex virtual registers used in this method.  If
   // `dump_stack_maps` is true, also dump the stack maps and the
   // associated Dex register maps.
-  void Dump(std::ostream& os,
+  void Dump(VariableIndentationOutputStream* vios,
             uint32_t code_offset,
             uint16_t number_of_dex_registers,
             bool dump_stack_maps) const;
index 09db7cd..11c3e65 100644 (file)
@@ -349,27 +349,29 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, uint32_t
   return result;
 }
 
-MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t dex_method_idx,
-                                         const DexFile* dex_file,
-                                         Handle<mirror::DexCache> dex_cache,
-                                         Handle<mirror::ClassLoader> class_loader,
-                                         const DexFile::ClassDef* class_def,
-                                         const DexFile::CodeItem* code_item,
-                                         ArtMethod* method,
-                                         uint32_t method_access_flags) {
+MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self,
+                                                    VariableIndentationOutputStream* vios,
+                                                    uint32_t dex_method_idx,
+                                                    const DexFile* dex_file,
+                                                    Handle<mirror::DexCache> dex_cache,
+                                                    Handle<mirror::ClassLoader> class_loader,
+                                                    const DexFile::ClassDef* class_def,
+                                                    const DexFile::CodeItem* code_item,
+                                                    ArtMethod* method,
+                                                    uint32_t method_access_flags) {
   MethodVerifier* verifier = new MethodVerifier(self, dex_file, dex_cache, class_loader,
                                                 class_def, code_item, dex_method_idx, method,
                                                 method_access_flags, true, true, true, true);
   verifier->Verify();
-  verifier->DumpFailures(os);
-  os << verifier->info_messages_.str();
+  verifier->DumpFailures(vios->Stream());
+  vios->Stream() << verifier->info_messages_.str();
   // Only dump and return if no hard failures. Otherwise the verifier may be not fully initialized
   // and querying any info is dangerous/can abort.
   if (verifier->have_pending_hard_failure_) {
     delete verifier;
     return nullptr;
   } else {
-    verifier->Dump(os);
+    verifier->Dump(vios);
     return verifier;
   }
 }
@@ -1280,32 +1282,36 @@ std::ostream& MethodVerifier::DumpFailures(std::ostream& os) {
 }
 
 void MethodVerifier::Dump(std::ostream& os) {
+  VariableIndentationOutputStream vios(&os);
+  Dump(&vios);
+}
+
+void MethodVerifier::Dump(VariableIndentationOutputStream* vios) {
   if (code_item_ == nullptr) {
-    os << "Native method\n";
+    vios->Stream() << "Native method\n";
     return;
   }
   {
-    os << "Register Types:\n";
-    Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-    std::ostream indent_os(&indent_filter);
-    reg_types_.Dump(indent_os);
-  }
-  os << "Dumping instructions and register lines:\n";
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indent_os(&indent_filter);
+    vios->Stream() << "Register Types:\n";
+    ScopedIndentation indent1(vios);
+    reg_types_.Dump(vios->Stream());
+  }
+  vios->Stream() << "Dumping instructions and register lines:\n";
+  ScopedIndentation indent1(vios);
   const Instruction* inst = Instruction::At(code_item_->insns_);
   for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
       dex_pc += inst->SizeInCodeUnits()) {
     RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
     if (reg_line != nullptr) {
-      indent_os << reg_line->Dump(this) << "\n";
+      vios->Stream() << reg_line->Dump(this) << "\n";
     }
-    indent_os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].ToString() << " ";
+    vios->Stream()
+        << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].ToString() << " ";
     const bool kDumpHexOfInstruction = false;
     if (kDumpHexOfInstruction) {
-      indent_os << inst->DumpHex(5) << " ";
+      vios->Stream() << inst->DumpHex(5) << " ";
     }
-    indent_os << inst->DumpString(dex_file_) << "\n";
+    vios->Stream() << inst->DumpString(dex_file_) << "\n";
     inst = inst->Next();
   }
 }
index 2550694..d933448 100644 (file)
@@ -32,6 +32,7 @@ namespace art {
 class Instruction;
 struct ReferenceMap2Visitor;
 class Thread;
+class VariableIndentationOutputStream;
 
 namespace verifier {
 
@@ -157,7 +158,9 @@ class MethodVerifier {
                                  bool allow_soft_failures, std::string* error)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static MethodVerifier* VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t method_idx,
+  static MethodVerifier* VerifyMethodAndDump(Thread* self,
+                                             VariableIndentationOutputStream* vios,
+                                             uint32_t method_idx,
                                              const DexFile* dex_file,
                                              Handle<mirror::DexCache> dex_cache,
                                              Handle<mirror::ClassLoader> class_loader,
@@ -191,6 +194,7 @@ class MethodVerifier {
   // Dump the state of the verifier, namely each instruction, what flags are set on it, register
   // information
   void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void Dump(VariableIndentationOutputStream* vios) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
   // to the locks held at 'dex_pc' in method 'm'.