Merge "ART: Fix DexFileVerifier try_items OoO validation"
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index a1d8226..a122ceb 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -71,18 +71,18 @@
CompilerOptions::kDefaultSmallMethodThreshold,
CompilerOptions::kDefaultTinyMethodThreshold,
CompilerOptions::kDefaultNumDexMethodsThreshold,
- false,
+ /* include_patch_information */ false,
CompilerOptions::kDefaultTopKProfileThreshold,
- false, // TODO: Think about debuggability of JIT-compiled code.
+ Runtime::Current()->IsDebuggable(),
CompilerOptions::kDefaultGenerateDebugInfo,
- false,
- false,
- false,
- false, // pic
- nullptr,
+ /* implicit_null_checks */ true,
+ /* implicit_so_checks */ true,
+ /* implicit_suspend_checks */ false,
+ /* pic */ true, // TODO: Support non-PIC in optimizing.
+ /* verbose_methods */ nullptr,
pass_manager_options,
- nullptr,
- false));
+ /* init_failure_output */ nullptr,
+ /* abort_on_hard_verifier_failure */ false));
const InstructionSet instruction_set = kRuntimeISA;
instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
cumulative_logger_.reset(new CumulativeLogger("jit times"));
@@ -92,10 +92,23 @@
method_inliner_map_.get(),
CompilerCallbacks::CallbackMode::kCompileApp));
compiler_driver_.reset(new CompilerDriver(
- compiler_options_.get(), verification_results_.get(), method_inliner_map_.get(),
- Compiler::kQuick, instruction_set, instruction_set_features_.get(), false,
- nullptr, nullptr, nullptr, 1, false, true,
- std::string(), cumulative_logger_.get(), -1, std::string()));
+ compiler_options_.get(),
+ verification_results_.get(),
+ method_inliner_map_.get(),
+ Compiler::kOptimizing,
+ instruction_set,
+ instruction_set_features_.get(),
+ /* image */ false,
+ /* image_classes */ nullptr,
+ /* compiled_classes */ nullptr,
+ /* compiled_methods */ nullptr,
+ /* thread_count */ 1,
+ /* dump_stats */ false,
+ /* dump_passes */ false,
+ /* dump_cfg_file_name */ "",
+ cumulative_logger_.get(),
+ /* swap_fd */ -1,
+ /* profile_file */ ""));
// Disable dedupe so we can remove compiled methods.
compiler_driver_->SetDedupeEnabled(false);
compiler_driver_->SetSupportBootImageFixup(false);
@@ -195,9 +208,14 @@
std::copy(quick_code->data(), quick_code->data() + code_size, code_ptr);
// After we are done writing we need to update the method header.
// Write out the method header last.
- method_header = new(method_header)OatQuickMethodHeader(
- code_ptr - mapping_table, code_ptr - vmap_table, code_ptr - gc_map, frame_size_in_bytes,
- core_spill_mask, fp_spill_mask, code_size);
+ method_header = new(method_header) OatQuickMethodHeader(
+ (mapping_table == nullptr) ? 0 : code_ptr - mapping_table,
+ (vmap_table == nullptr) ? 0 : code_ptr - vmap_table,
+ (gc_map == nullptr) ? 0 : code_ptr - gc_map,
+ frame_size_in_bytes,
+ core_spill_mask,
+ fp_spill_mask,
+ code_size);
// Return the code ptr.
return code_ptr;
}
@@ -216,23 +234,35 @@
auto* const mapping_table = compiled_method->GetMappingTable();
auto* const vmap_table = compiled_method->GetVmapTable();
auto* const gc_map = compiled_method->GetGcMap();
- CHECK(gc_map != nullptr) << PrettyMethod(method);
- // Write out pre-header stuff.
- uint8_t* const mapping_table_ptr = code_cache->AddDataArray(
- self, mapping_table->data(), mapping_table->data() + mapping_table->size());
- if (mapping_table_ptr == nullptr) {
- return false; // Out of data cache.
+ uint8_t* mapping_table_ptr = nullptr;
+ uint8_t* vmap_table_ptr = nullptr;
+ uint8_t* gc_map_ptr = nullptr;
+
+ if (mapping_table != nullptr) {
+ // Write out pre-header stuff.
+ mapping_table_ptr = code_cache->AddDataArray(
+ self, mapping_table->data(), mapping_table->data() + mapping_table->size());
+ if (mapping_table_ptr == nullptr) {
+ return false; // Out of data cache.
+ }
}
- uint8_t* const vmap_table_ptr = code_cache->AddDataArray(
- self, vmap_table->data(), vmap_table->data() + vmap_table->size());
- if (vmap_table_ptr == nullptr) {
- return false; // Out of data cache.
+
+ if (vmap_table != nullptr) {
+ vmap_table_ptr = code_cache->AddDataArray(
+ self, vmap_table->data(), vmap_table->data() + vmap_table->size());
+ if (vmap_table_ptr == nullptr) {
+ return false; // Out of data cache.
+ }
}
- uint8_t* const gc_map_ptr = code_cache->AddDataArray(
- self, gc_map->data(), gc_map->data() + gc_map->size());
- if (gc_map_ptr == nullptr) {
- return false; // Out of data cache.
+
+ if (gc_map != nullptr) {
+ gc_map_ptr = code_cache->AddDataArray(
+ self, gc_map->data(), gc_map->data() + gc_map->size());
+ if (gc_map_ptr == nullptr) {
+ return false; // Out of data cache.
+ }
}
+
// Don't touch this until you protect / unprotect the code.
const size_t reserve_size = sizeof(OatQuickMethodHeader) + quick_code->size() + 32;
uint8_t* const code_reserve = code_cache->ReserveCode(self, reserve_size);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 997319a..1319f2c 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -756,6 +756,35 @@
current_block_ = nullptr;
}
+void HGraphBuilder::PotentiallySimplifyFakeString(uint16_t original_dex_register,
+ uint32_t dex_pc,
+ HInvoke* actual_string) {
+ if (!graph_->IsDebuggable()) {
+ // Notify that we cannot compile with baseline. The dex registers aliasing
+ // with `original_dex_register` will be handled when we optimize
+ // (see HInstructionSimplifer::VisitFakeString).
+ can_use_baseline_for_string_init_ = false;
+ return;
+ }
+ const VerifiedMethod* verified_method =
+ compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
+ if (verified_method != nullptr) {
+ UpdateLocal(original_dex_register, actual_string);
+ const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map =
+ verified_method->GetStringInitPcRegMap();
+ auto map_it = string_init_map.find(dex_pc);
+ if (map_it != string_init_map.end()) {
+ std::set<uint32_t> reg_set = map_it->second;
+ for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
+ HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot);
+ UpdateLocal(*set_it, load_local);
+ }
+ }
+ } else {
+ can_use_baseline_for_string_init_ = false;
+ }
+}
+
bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
uint32_t dex_pc,
uint32_t method_idx,
@@ -997,34 +1026,23 @@
if (clinit_check_requirement == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit) {
// Add the class initialization check as last input of `invoke`.
DCHECK(clinit_check != nullptr);
+ DCHECK(!is_string_init);
invoke->SetArgumentAt(argument_index, clinit_check);
+ argument_index++;
}
- current_block_->AddInstruction(invoke);
- latest_result_ = invoke;
-
// Add move-result for StringFactory method.
if (is_string_init) {
uint32_t orig_this_reg = is_range ? register_index : args[0];
- UpdateLocal(orig_this_reg, invoke);
- const VerifiedMethod* verified_method =
- compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
- if (verified_method == nullptr) {
- LOG(WARNING) << "No verified method for method calling String.<init>: "
- << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_);
- return false;
- }
- const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map =
- verified_method->GetStringInitPcRegMap();
- auto map_it = string_init_map.find(dex_pc);
- if (map_it != string_init_map.end()) {
- std::set<uint32_t> reg_set = map_it->second;
- for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
- HInstruction* load_local = LoadLocal(orig_this_reg, Primitive::kPrimNot);
- UpdateLocal(*set_it, load_local);
- }
- }
+ HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot);
+ invoke->SetArgumentAt(argument_index, fake_string);
+ current_block_->AddInstruction(invoke);
+ PotentiallySimplifyFakeString(orig_this_reg, dex_pc, invoke);
+ } else {
+ current_block_->AddInstruction(invoke);
}
+ latest_result_ = invoke;
+
return true;
}
@@ -2239,10 +2257,10 @@
case Instruction::NEW_INSTANCE: {
uint16_t type_index = instruction.VRegB_21c();
if (compiler_driver_->IsStringTypeIndex(type_index, dex_file_)) {
- // Turn new-instance of string into a const 0.
int32_t register_index = instruction.VRegA();
- HNullConstant* constant = graph_->GetNullConstant();
- UpdateLocal(register_index, constant);
+ HFakeString* fake_string = new (arena_) HFakeString();
+ current_block_->AddInstruction(fake_string);
+ UpdateLocal(register_index, fake_string);
} else {
QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
? kQuickAllocObjectWithAccessCheck
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 7098eb8..76610f5 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -54,6 +54,7 @@
return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])),
code_start_(nullptr),
latest_result_(nullptr),
+ can_use_baseline_for_string_init_(true),
compilation_stats_(compiler_stats) {}
// Only for unit testing.
@@ -72,10 +73,15 @@
return_type_(return_type),
code_start_(nullptr),
latest_result_(nullptr),
+ can_use_baseline_for_string_init_(true),
compilation_stats_(nullptr) {}
bool BuildGraph(const DexFile::CodeItem& code);
+ bool CanUseBaselineForStringInit() const {
+ return can_use_baseline_for_string_init_;
+ }
+
static constexpr const char* kBuilderPassName = "builder";
private:
@@ -251,6 +257,10 @@
// Returns whether `type_index` points to the outer-most compiling method's class.
bool IsOutermostCompilingClass(uint16_t type_index) const;
+ void PotentiallySimplifyFakeString(uint16_t original_dex_register,
+ uint32_t dex_pc,
+ HInvoke* invoke);
+
ArenaAllocator* const arena_;
// A list of the size of the dex code holding block information for
@@ -290,6 +300,11 @@
// used by move-result instructions.
HInstruction* latest_result_;
+ // We need to know whether we have built a graph that has calls to StringFactory
+ // and hasn't gone through the verifier. If the following flag is `false`, then
+ // we cannot compile with baseline.
+ bool can_use_baseline_for_string_init_;
+
OptimizingCompilerStats* compilation_stats_;
DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index ff12329..75b8f06 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -4552,6 +4552,18 @@
LOG(FATAL) << "Unreachable";
}
+void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
+ DCHECK(codegen_->IsBaseline());
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+ DCHECK(codegen_->IsBaseline());
+ // Will be generated at use site.
+}
+
#undef __
#undef QUICK_ENTRY_POINT
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index f64e801..069c9e1 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -657,6 +657,13 @@
Primitive::Type type = instruction->GetType();
DCHECK_NE(type, Primitive::kPrimVoid);
+ if (instruction->IsFakeString()) {
+ // The fake string is an alias for null.
+ DCHECK(IsBaseline());
+ instruction = locations->Out().GetConstant();
+ DCHECK(instruction->IsNullConstant()) << instruction->DebugName();
+ }
+
if (instruction->IsCurrentMethod()) {
MoveLocation(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
} else if (locations != nullptr && locations->Out().Equals(location)) {
@@ -905,7 +912,7 @@
(source.IsFpuRegister() == Primitive::IsFloatingPointType(type)));
__ Str(CPURegisterFrom(source, type), StackOperandFrom(destination));
} else if (source.IsConstant()) {
- DCHECK(unspecified_type || CoherentConstantAndType(source, type));
+ DCHECK(unspecified_type || CoherentConstantAndType(source, type)) << source << " " << type;
UseScratchRegisterScope temps(GetVIXLAssembler());
HConstant* src_cst = source.GetConstant();
CPURegister temp;
@@ -3039,6 +3046,18 @@
LOG(FATAL) << "Unreachable";
}
+void LocationsBuilderARM64::VisitFakeString(HFakeString* instruction) {
+ DCHECK(codegen_->IsBaseline());
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorARM64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+ DCHECK(codegen_->IsBaseline());
+ // Will be generated at use site.
+}
+
#undef __
#undef QUICK_ENTRY_POINT
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index aa4fd26..e7d2ec6 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3292,5 +3292,17 @@
VisitCondition(comp);
}
+void LocationsBuilderMIPS64::VisitFakeString(HFakeString* instruction) {
+ DCHECK(codegen_->IsBaseline());
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorMIPS64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+ DCHECK(codegen_->IsBaseline());
+ // Will be generated at use site.
+}
+
} // namespace mips64
} // namespace art
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index fd4bd18..e15eff9 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4964,6 +4964,18 @@
LOG(FATAL) << "Unreachable";
}
+void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) {
+ DCHECK(codegen_->IsBaseline());
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+ DCHECK(codegen_->IsBaseline());
+ // Will be generated at use site.
+}
+
#undef __
} // namespace x86
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index ae7bcc8..a95ce68 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -4774,6 +4774,18 @@
LOG(FATAL) << "Unreachable";
}
+void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
+ DCHECK(codegen_->IsBaseline());
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+ DCHECK(codegen_->IsBaseline());
+ // Will be generated at use site.
+}
+
void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
if (value == 0) {
__ xorl(dest, dest);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 017b678..c86d797 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -70,6 +70,7 @@
void VisitUShr(HUShr* instruction) OVERRIDE;
void VisitXor(HXor* instruction) OVERRIDE;
void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE;
+ void VisitFakeString(HFakeString* fake_string) OVERRIDE;
bool IsDominatedByInputNullCheck(HInstruction* instr);
OptimizingCompilerStats* stats_;
@@ -903,4 +904,46 @@
}
}
+void InstructionSimplifierVisitor::VisitFakeString(HFakeString* instruction) {
+ HInstruction* actual_string = nullptr;
+
+ // Find the string we need to replace this instruction with. The actual string is
+ // the return value of a StringFactory call.
+ for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
+ HInstruction* use = it.Current()->GetUser();
+ if (use->IsInvokeStaticOrDirect()
+ && use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)) {
+ use->AsInvokeStaticOrDirect()->RemoveFakeStringArgumentAsLastInput();
+ actual_string = use;
+ break;
+ }
+ }
+
+ // Check that there is no other instruction that thinks it is the factory for that string.
+ if (kIsDebugBuild) {
+ CHECK(actual_string != nullptr);
+ for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
+ HInstruction* use = it.Current()->GetUser();
+ if (use->IsInvokeStaticOrDirect()) {
+ CHECK(!use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction));
+ }
+ }
+ }
+
+ // We need to remove any environment uses of the fake string that are not dominated by
+ // `actual_string` to null.
+ for (HUseIterator<HEnvironment*> it(instruction->GetEnvUses()); !it.Done(); it.Advance()) {
+ HEnvironment* environment = it.Current()->GetUser();
+ if (!actual_string->StrictlyDominates(environment->GetHolder())) {
+ environment->RemoveAsUserOfInput(it.Current()->GetIndex());
+ environment->SetRawEnvAt(it.Current()->GetIndex(), nullptr);
+ }
+ }
+
+ // Only uses dominated by `actual_string` must remain. We can safely replace and remove
+ // `instruction`.
+ instruction->ReplaceWith(actual_string);
+ instruction->GetBlock()->RemoveInstruction(instruction);
+}
+
} // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 7d26062..8546a10 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -38,6 +38,7 @@
class HCurrentMethod;
class HDoubleConstant;
class HEnvironment;
+class HFakeString;
class HFloatConstant;
class HGraphBuilder;
class HGraphVisitor;
@@ -914,6 +915,7 @@
M(DoubleConstant, Constant) \
M(Equal, Condition) \
M(Exit, Instruction) \
+ M(FakeString, Instruction) \
M(FloatConstant, Constant) \
M(Goto, Instruction) \
M(GreaterThan, Condition) \
@@ -1339,8 +1341,7 @@
const uint32_t dex_pc_;
const InvokeType invoke_type_;
- // The instruction that holds this environment. Only used in debug mode
- // to ensure the graph is consistent.
+ // The instruction that holds this environment.
HInstruction* const holder_;
friend class HInstruction;
@@ -2742,9 +2743,11 @@
ClinitCheckRequirement clinit_check_requirement)
: HInvoke(arena,
number_of_arguments,
- // There is one extra argument for the HCurrentMethod node, and
- // potentially one other if the clinit check is explicit.
- clinit_check_requirement == ClinitCheckRequirement::kExplicit ? 2u : 1u,
+ // There is one extra argument for the HCurrentMethod node, and
+ // potentially one other if the clinit check is explicit, and one other
+ // if the method is a string factory.
+ 1u + (clinit_check_requirement == ClinitCheckRequirement::kExplicit ? 1u : 0u)
+ + (string_init_offset ? 1u : 0u),
return_type,
dex_pc,
dex_method_index,
@@ -2789,6 +2792,23 @@
DCHECK(IsStaticWithImplicitClinitCheck());
}
+ bool IsStringFactoryFor(HFakeString* str) const {
+ if (!IsStringInit()) return false;
+ // +1 for the current method.
+ if (InputCount() == (number_of_arguments_ + 1)) return false;
+ return InputAt(InputCount() - 1)->AsFakeString() == str;
+ }
+
+ void RemoveFakeStringArgumentAsLastInput() {
+ DCHECK(IsStringInit());
+ size_t last_input_index = InputCount() - 1;
+ HInstruction* last_input = InputAt(last_input_index);
+ DCHECK(last_input != nullptr);
+ DCHECK(last_input->IsFakeString()) << last_input->DebugName();
+ RemoveAsUserOfInput(last_input_index);
+ inputs_.DeleteAt(last_input_index);
+ }
+
// Is this a call to a static method whose declaring class has an
// explicit intialization check in the graph?
bool IsStaticWithExplicitClinitCheck() const {
@@ -4171,6 +4191,25 @@
DISALLOW_COPY_AND_ASSIGN(HMonitorOperation);
};
+/**
+ * A HInstruction used as a marker for the replacement of new + <init>
+ * of a String to a call to a StringFactory. Only baseline will see
+ * the node at code generation, where it will be be treated as null.
+ * When compiling non-baseline, `HFakeString` instructions are being removed
+ * in the instruction simplifier.
+ */
+class HFakeString : public HTemplateInstruction<0> {
+ public:
+ HFakeString() : HTemplateInstruction(SideEffects::None()) {}
+
+ Primitive::Type GetType() const OVERRIDE { return Primitive::kPrimNot; }
+
+ DECLARE_INSTRUCTION(FakeString);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HFakeString);
+};
+
class MoveOperands : public ArenaObject<kArenaAllocMisc> {
public:
MoveOperands(Location source,
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 1e51530..4568a46 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -627,7 +627,7 @@
// `run_optimizations_` is set explicitly (either through a compiler filter
// or the debuggable flag). If it is set, we can run baseline. Otherwise, we fall back
// to Quick.
- bool can_use_baseline = !run_optimizations_;
+ bool can_use_baseline = !run_optimizations_ && builder.CanUseBaselineForStringInit();
if (run_optimizations_ && can_optimize && can_allocate_registers) {
VLOG(compiler) << "Optimizing " << method_name;
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 8dde547..82452ba 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -599,6 +599,9 @@
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 @@
<< " (" << 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 @@
}
}
- 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 @@
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 @@
it.Next();
}
DCHECK(!it.HasNext());
- os << std::flush;
+ vios->Stream() << std::flush;
return success;
}
@@ -768,7 +770,8 @@
// 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 @@
}
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 @@
}
}
+ // 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";
+ vios->Stream() << "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";
+ 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 @@
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 @@
}
// 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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
}
}
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 @@
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 @@
}
}
{
- 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 @@
// 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 @@
// 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 @@
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 @@
} 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 @@
}
}
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 @@
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 @@
} 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 @@
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 @@
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 @@
// 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_;
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index ca3ca1d..a7826a74 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -331,9 +331,7 @@
SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3 @ save callee saves in case allocation triggers GC
mov r2, r9 @ pass Thread::Current
mov r3, sp
- .cfi_adjust_cfa_offset 16
bl \cxx_name @ (method_idx, this, caller, Thread*, SP)
- .cfi_adjust_cfa_offset -16
mov r12, r1 @ save Method*->code_
RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
cbz r0, 1f @ did we find the target? if not go to exception delivery
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/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index b28adf9..df0cf45 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -698,18 +698,13 @@
return false;
}
- ClassLinker* linker = runtime->GetClassLinker();
- CHECK(linker != nullptr) << "ClassLinker is not created yet";
- const OatFile* primary_oat_file = linker->GetPrimaryOatFile();
- const bool debuggable = primary_oat_file != nullptr && primary_oat_file->IsDebuggable();
-
std::vector<std::string> argv;
argv.push_back(runtime->GetCompilerExecutable());
argv.push_back("--runtime-arg");
argv.push_back("-classpath");
argv.push_back("--runtime-arg");
argv.push_back(runtime->GetClassPathString());
- if (debuggable) {
+ if (runtime->IsDebuggable()) {
argv.push_back("--debuggable");
}
runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5067b0d..884662d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -680,6 +680,11 @@
return IsShuttingDownLocked();
}
+bool Runtime::IsDebuggable() const {
+ const OatFile* oat_file = GetClassLinker()->GetPrimaryOatFile();
+ return oat_file != nullptr && oat_file->IsDebuggable();
+}
+
void Runtime::StartDaemonThreads() {
VLOG(startup) << "Runtime::StartDaemonThreads entering";
diff --git a/runtime/runtime.h b/runtime/runtime.h
index bcc7118..6fd1b07 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -552,6 +552,8 @@
return method_ref_string_init_reg_map_;
}
+ bool IsDebuggable() const;
+
private:
static void InitPlatformSignalHandlers();
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'.
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index c18bb5c..38973f7 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -434,20 +434,6 @@
TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS :=
-# Known broken tests for the MIPS64 optimizing compiler backend in 64-bit mode. b/21555893
-TEST_ART_BROKEN_OPTIMIZING_MIPS64_64BIT_RUN_TESTS := \
- 449-checker-bce
-
-ifeq ($(TARGET_ARCH),mips64)
- ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
- ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
- optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
- $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_MIPS64_64BIT_RUN_TESTS),64)
- endif
-endif
-
-TEST_ART_BROKEN_OPTIMIZING_MIPS64_64BIT_RUN_TESTS :=
-
# Known broken tests for the optimizing compiler.
TEST_ART_BROKEN_OPTIMIZING_RUN_TESTS :=
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 7135dba..116a611 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -33,7 +33,7 @@
# We use Quick's image on target because optimizing's image is not compiled debuggable.
image="-Ximage:/data/art-test/core.art"
args=$@
-debuggee_args="-Xcompiler-option --compiler-backend=Optimizing -Xcompiler-option --debuggable"
+debuggee_args="-Xcompiler-option --debuggable"
device_dir="--device-dir=/data/local/tmp"
# We use the art script on target to ensure the runner and the debuggee share the same
# image.
@@ -92,6 +92,5 @@
--vm-arg -Djpda.settings.transportAddress=127.0.0.1:55107 \
--vm-arg -Djpda.settings.debuggeeJavaPath="\"$art_debugee $image $debuggee_args\"" \
--classpath $test_jar \
- --vm-arg -Xcompiler-option --vm-arg --compiler-backend=Optimizing \
--vm-arg -Xcompiler-option --vm-arg --debuggable \
org.apache.harmony.jpda.tests.share.AllTests