diff options
-rw-r--r-- | compiler/driver/compiler_options.cc | 6 | ||||
-rw-r--r-- | compiler/driver/compiler_options.h | 6 | ||||
-rw-r--r-- | compiler/optimizing/builder.cc | 61 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 1 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/dead_code_elimination.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 18 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 7 |
13 files changed, 146 insertions, 2 deletions
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index 4d2d9246df..8c38cf263e 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -34,6 +34,7 @@ CompilerOptions::CompilerOptions() include_patch_information_(kDefaultIncludePatchInformation), top_k_profile_threshold_(kDefaultTopKProfileThreshold), debuggable_(false), + native_debuggable_(kDefaultNativeDebuggable), generate_debug_info_(kDefaultGenerateDebugInfo), implicit_null_checks_(true), implicit_so_checks_(true), @@ -81,6 +82,7 @@ CompilerOptions::CompilerOptions(CompilerFilter compiler_filter, include_patch_information_(include_patch_information), top_k_profile_threshold_(top_k_profile_threshold), debuggable_(debuggable), + native_debuggable_(kDefaultNativeDebuggable), generate_debug_info_(generate_debug_info), implicit_null_checks_(implicit_null_checks), implicit_so_checks_(implicit_so_checks), @@ -207,6 +209,10 @@ bool CompilerOptions::ParseCompilerOption(const StringPiece& option, UsageFn Usa } else if (option == "--debuggable") { debuggable_ = true; generate_debug_info_ = true; + } else if (option == "--native-debuggable") { + native_debuggable_ = true; + debuggable_ = true; + generate_debug_info_ = true; } else if (option.starts_with("--top-k-profile-threshold=")) { ParseDouble(option.data(), '=', 0.0, 100.0, &top_k_profile_threshold_, Usage); } else if (option == "--include-patch-information") { diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index e6acab42f2..2b047a203c 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -49,6 +49,7 @@ class CompilerOptions FINAL { static const size_t kDefaultTinyMethodThreshold = 20; static const size_t kDefaultNumDexMethodsThreshold = 900; static constexpr double kDefaultTopKProfileThreshold = 90.0; + static const bool kDefaultNativeDebuggable = false; static const bool kDefaultGenerateDebugInfo = kIsDebugBuild; static const bool kDefaultIncludePatchInformation = false; static const size_t kDefaultInlineDepthLimit = 3; @@ -162,6 +163,10 @@ class CompilerOptions FINAL { return debuggable_; } + bool GetNativeDebuggable() const { + return native_debuggable_; + } + bool GetGenerateDebugInfo() const { return generate_debug_info_; } @@ -240,6 +245,7 @@ class CompilerOptions FINAL { // When using a profile file only the top K% of the profiled samples will be compiled. double top_k_profile_threshold_; bool debuggable_; + bool native_debuggable_; bool generate_debug_info_; bool implicit_null_checks_; bool implicit_so_checks_; diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 1178d0fb25..4dd0d26b89 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -17,6 +17,8 @@ #include "builder.h" #include "art_field-inl.h" +#include "base/arena_bit_vector.h" +#include "base/bit_vector-inl.h" #include "base/logging.h" #include "class_linker.h" #include "dex/verified_method.h" @@ -458,6 +460,19 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { return false; } + // Find locations where we want to generate extra stackmaps for native debugging. + // This allows us to generate the info only at interesting points (for example, + // at start of java statement) rather than before every dex instruction. + const bool native_debuggable = compiler_driver_ != nullptr && + compiler_driver_->GetCompilerOptions().GetNativeDebuggable(); + ArenaBitVector* native_debug_info_locations; + if (native_debuggable) { + const uint32_t num_instructions = code_item.insns_size_in_code_units_; + native_debug_info_locations = new (arena_) ArenaBitVector (arena_, num_instructions, false); + native_debug_info_locations->ClearAllBits(); + FindNativeDebugInfoLocations(code_item, native_debug_info_locations); + } + CreateBlocksForTryCatch(code_item); InitializeParameters(code_item.ins_size_); @@ -467,6 +482,11 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { // Update the current block if dex_pc starts a new block. MaybeUpdateCurrentBlock(dex_pc); const Instruction& instruction = *Instruction::At(code_ptr); + if (native_debuggable && native_debug_info_locations->IsBitSet(dex_pc)) { + if (current_block_ != nullptr) { + current_block_->AddInstruction(new (arena_) HNativeDebugInfo(dex_pc)); + } + } if (!AnalyzeDexInstruction(instruction, dex_pc)) { return false; } @@ -507,6 +527,47 @@ void HGraphBuilder::MaybeUpdateCurrentBlock(size_t dex_pc) { current_block_ = block; } +void HGraphBuilder::FindNativeDebugInfoLocations(const DexFile::CodeItem& code_item, + ArenaBitVector* locations) { + // The callback gets called when the line number changes. + // In other words, it marks the start of new java statement. + struct Callback { + static bool Position(void* ctx, const DexFile::PositionInfo& entry) { + static_cast<ArenaBitVector*>(ctx)->SetBit(entry.address_); + return false; + } + }; + dex_file_->DecodeDebugPositionInfo(&code_item, Callback::Position, locations); + // Add native debug info at the start of every basic block. + for (uint32_t pc = 0; pc < code_item.insns_size_in_code_units_; pc++) { + if (FindBlockStartingAt(pc) != nullptr) { + locations->SetBit(pc); + } + } + // Instruction-specific tweaks. + const Instruction* const begin = Instruction::At(code_item.insns_); + const Instruction* const end = begin->RelativeAt(code_item.insns_size_in_code_units_); + for (const Instruction* inst = begin; inst < end; inst = inst->Next()) { + switch (inst->Opcode()) { + case Instruction::MOVE_EXCEPTION: + case Instruction::MOVE_RESULT: + case Instruction::MOVE_RESULT_WIDE: + case Instruction::MOVE_RESULT_OBJECT: { + // The compiler checks that there are no instructions before those. + // So generate HNativeDebugInfo after them instead. + locations->ClearBit(inst->GetDexPc(code_item.insns_)); + const Instruction* next = inst->Next(); + if (next < end) { + locations->SetBit(next->GetDexPc(code_item.insns_)); + } + break; + } + default: + break; + } + } +} + bool HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end, size_t* number_of_branches) { diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 73e85bb5e3..26bf1cbc75 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -112,6 +112,7 @@ class HGraphBuilder : public ValueObject { const uint16_t* end, size_t* number_of_branches); void MaybeUpdateCurrentBlock(size_t dex_pc); + void FindNativeDebugInfoLocations(const DexFile::CodeItem& code_item, ArenaBitVector* locations); HBasicBlock* FindBlockStartingAt(int32_t dex_pc) const; HBasicBlock* FindOrCreateBlockStartingAt(int32_t dex_pc); diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 07cc059983..58feb67a58 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1618,6 +1618,14 @@ void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) { /* false_target */ nullptr); } +void LocationsBuilderARM::VisitNativeDebugInfo(HNativeDebugInfo* info) { + new (GetGraph()->GetArena()) LocationSummary(info); +} + +void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo* info) { + codegen_->RecordPcInfo(info, info->GetDexPc()); +} + void LocationsBuilderARM::HandleCondition(HCondition* cond) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 068676da0e..b49f42b6c8 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2949,6 +2949,14 @@ void InstructionCodeGeneratorARM64::VisitDeoptimize(HDeoptimize* deoptimize) { /* false_target */ nullptr); } +void LocationsBuilderARM64::VisitNativeDebugInfo(HNativeDebugInfo* info) { + new (GetGraph()->GetArena()) LocationSummary(info); +} + +void InstructionCodeGeneratorARM64::VisitNativeDebugInfo(HNativeDebugInfo* info) { + codegen_->RecordPcInfo(info, info->GetDexPc()); +} + void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { HandleFieldGet(instruction); } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index ef6b403eea..07efdee22d 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -3244,6 +3244,14 @@ void InstructionCodeGeneratorMIPS::VisitDeoptimize(HDeoptimize* deoptimize) { /* false_target */ nullptr); } +void LocationsBuilderMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) { + new (GetGraph()->GetArena()) LocationSummary(info); +} + +void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) { + codegen_->RecordPcInfo(info, info->GetDexPc()); +} + void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) { Primitive::Type field_type = field_info.GetFieldType(); bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble); diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 0f340a9a15..05834ff063 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -2745,6 +2745,14 @@ void InstructionCodeGeneratorMIPS64::VisitDeoptimize(HDeoptimize* deoptimize) { /* false_target */ nullptr); } +void LocationsBuilderMIPS64::VisitNativeDebugInfo(HNativeDebugInfo* info) { + new (GetGraph()->GetArena()) LocationSummary(info); +} + +void InstructionCodeGeneratorMIPS64::VisitNativeDebugInfo(HNativeDebugInfo* info) { + codegen_->RecordPcInfo(info, info->GetDexPc()); +} + void LocationsBuilderMIPS64::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info ATTRIBUTE_UNUSED) { LocationSummary* locations = diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 313610975b..fd18917842 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1616,6 +1616,14 @@ void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) { /* false_target */ nullptr); } +void LocationsBuilderX86::VisitNativeDebugInfo(HNativeDebugInfo* info) { + new (GetGraph()->GetArena()) LocationSummary(info); +} + +void InstructionCodeGeneratorX86::VisitNativeDebugInfo(HNativeDebugInfo* info) { + codegen_->RecordPcInfo(info, info->GetDexPc()); +} + void LocationsBuilderX86::VisitLocal(HLocal* local) { local->SetLocations(nullptr); } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 0de616cbd2..ffd8c42e20 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1600,6 +1600,14 @@ void InstructionCodeGeneratorX86_64::VisitDeoptimize(HDeoptimize* deoptimize) { /* false_target */ nullptr); } +void LocationsBuilderX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) { + new (GetGraph()->GetArena()) LocationSummary(info); +} + +void InstructionCodeGeneratorX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) { + codegen_->RecordPcInfo(info, info->GetDexPc()); +} + void LocationsBuilderX86_64::VisitLocal(HLocal* local) { local->SetLocations(nullptr); } diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc index 02e5dab3d4..67ff87a759 100644 --- a/compiler/optimizing/dead_code_elimination.cc +++ b/compiler/optimizing/dead_code_elimination.cc @@ -165,6 +165,7 @@ void HDeadCodeElimination::RemoveDeadInstructions() { if (!inst->HasSideEffects() && !inst->CanThrow() && !inst->IsSuspendCheck() + && !inst->IsNativeDebugInfo() // If we added an explicit barrier then we should keep it. && !inst->IsMemoryBarrier() && !inst->IsParameterValue() diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 00820a66e7..db3e969afc 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1066,6 +1066,7 @@ class HLoopInformationOutwardIterator : public ValueObject { M(MemoryBarrier, Instruction) \ M(MonitorOperation, Instruction) \ M(Mul, BinaryOperation) \ + M(NativeDebugInfo, Instruction) \ M(Neg, UnaryOperation) \ M(NewArray, Instruction) \ M(NewInstance, Instruction) \ @@ -4872,6 +4873,23 @@ class HSuspendCheck : public HTemplateInstruction<0> { DISALLOW_COPY_AND_ASSIGN(HSuspendCheck); }; +// Pseudo-instruction which provides the native debugger with mapping information. +// It ensures that we can generate line number and local variables at this point. +class HNativeDebugInfo : public HTemplateInstruction<0> { + public: + explicit HNativeDebugInfo(uint32_t dex_pc) + : HTemplateInstruction<0>(SideEffects::None(), dex_pc) {} + + bool NeedsEnvironment() const OVERRIDE { + return true; + } + + DECLARE_INSTRUCTION(NativeDebugInfo); + + private: + DISALLOW_COPY_AND_ASSIGN(HNativeDebugInfo); +}; + /** * Instruction to load a Class object. */ diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 6fae8e4109..21ce73c7d4 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -315,10 +315,13 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" stripped using standard command line tools such as strip or objcopy."); UsageError(" (enabled by default in debug builds, disabled by default otherwise)"); UsageError(""); - UsageError(" --debuggable: Produce debuggable code. Implies --generate-debug-info."); - UsageError(""); UsageError(" --no-generate-debug-info: Do not generate debug information for native debugging."); UsageError(""); + UsageError(" --debuggable: Produce code debuggable with Java debugger. Implies -g."); + UsageError(""); + UsageError(" --native-debuggable: Produce code debuggable with native debugger (like LLDB)."); + UsageError(" Implies --debuggable."); + UsageError(""); UsageError(" --runtime-arg <argument>: used to specify various arguments for the runtime,"); UsageError(" such as initial heap size, maximum heap size, and verbose output."); UsageError(" Use a separate --runtime-arg switch for each argument."); |