ART: Don't nest indenters in oatdump.
Reduces the time taken by the oatdump_test by ~12s (15%)
on host and ~55s (9%) on N5.
Change-Id: I99bb16ff5f3640389815f1fe54379ca64eac071b
diff --git a/runtime/indenter.h b/runtime/indenter.h
index 38b398d..78b18f6 100644
--- a/runtime/indenter.h
+++ b/runtime/indenter.h
@@ -19,10 +19,13 @@
#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 @@
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_
diff --git a/runtime/indenter_test.cc b/runtime/indenter_test.cc
index 1919e3d..1a26d7b 100644
--- a/runtime/indenter_test.cc
+++ b/runtime/indenter_test.cc
@@ -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 @@
input << "\n";
EXPECT_EQ(output.str(), "\t\thello\n\t\thello again\n");
}
+
+} // namespace art
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 741cd90..962132b 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -95,40 +95,37 @@
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 @@
// 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 @@
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]);
}
}
}
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 4e42008..e8769f9 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -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 @@
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 @@
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 @@
&& 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 @@
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 @@
// 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;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 09db7cd..11c3e65 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -349,27 +349,29 @@
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 @@
}
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);
+ vios->Stream() << "Register Types:\n";
+ ScopedIndentation indent1(vios);
+ reg_types_.Dump(vios->Stream());
}
- os << "Dumping instructions and register lines:\n";
- Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
- std::ostream indent_os(&indent_filter);
+ 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();
}
}
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 2550694..d933448 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -32,6 +32,7 @@
class Instruction;
struct ReferenceMap2Visitor;
class Thread;
+class VariableIndentationOutputStream;
namespace verifier {
@@ -157,7 +158,9 @@
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 @@
// 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'.