We do not require full environment at the start of basic block.
The dex pc contained in basic block is sufficient for line mapping.
Change-Id: I5ba9e5f5acbc4a783ad544769f9a73bb33e2bafa
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);
}
}
};
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.
+ case Instruction::MOVE_EXCEPTION: {
+ // Stop in native debugger after the exception has been moved.
+ // The compiler also expects the move at the start of basic block so
+ // we do not want to interfere by inserting native-debug-info before it.
locations->ClearBit(inst->GetDexPc(code_item.insns_));
const Instruction* next = inst->Next();
if (next < end) {
// errors where we reference that label.
if (block->IsSingleJump()) continue;
Bind(block);
+ // This ensures that we have correct native line mapping for all native instructions.
+ // It is necessary to make stepping over a statement work. Otherwise, any initial
+ // instructions (e.g. moves) would be assumed to be the start of next statement.
+ MaybeRecordNativeDebugInfo(nullptr /* instruction */, block->GetDexPc());
for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* current = it.Current();
DisassemblyScope disassembly_scope(current, *this);
uint32_t native_pc = GetAssembler()->CodeSize();
if (instruction == nullptr) {
- // For stack overflow checks.
+ // For stack overflow checks and native-debug-info entries without dex register
+ // mapping (i.e. start of basic block or start of slow path).
stack_map_stream_.BeginStackMapEntry(outer_dex_pc, native_pc, 0, 0, 0, 0);
stack_map_stream_.EndStackMapEntry();
return;
return count > 0 && stack_map_stream_.GetStackMap(count - 1).native_pc_offset == pc;
}
+void CodeGenerator::MaybeRecordNativeDebugInfo(HInstruction* instruction, uint32_t dex_pc) {
+ if (GetCompilerOptions().GetNativeDebuggable() && dex_pc != kNoDexPc) {
+ if (HasStackMapAtCurrentPc()) {
+ // Ensure that we do not collide with the stack map of the previous instruction.
+ GenerateNop();
+ }
+ RecordPcInfo(instruction, dex_pc);
+ }
+}
+
void CodeGenerator::RecordCatchBlockInfo() {
ArenaAllocator* arena = graph_->GetArena();
void RecordPcInfo(HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path = nullptr);
// Check whether we have already recorded mapping at this PC.
bool HasStackMapAtCurrentPc();
+ // Record extra stack maps if we support native debugging.
+ void MaybeRecordNativeDebugInfo(HInstruction* instruction, uint32_t dex_pc);
bool CanMoveNullCheckToUser(HNullCheck* null_check);
void MaybeRecordImplicitNullCheck(HInstruction* instruction);
// Copy the result of a call into the given target.
virtual void MoveFromReturnRegister(Location trg, Primitive::Type type) = 0;
+ virtual void GenerateNop() = 0;
+
protected:
// Method patch info used for recording locations of required linker patches and
// target methods. The target method can be used for various purposes, whether for
}
void InstructionCodeGeneratorARM::VisitNativeDebugInfo(HNativeDebugInfo* info) {
- if (codegen_->HasStackMapAtCurrentPc()) {
- // Ensure that we do not collide with the stack map of the previous instruction.
- __ nop();
- }
- codegen_->RecordPcInfo(info, info->GetDexPc());
+ codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+}
+
+void CodeGeneratorARM::GenerateNop() {
+ __ nop();
}
void LocationsBuilderARM::HandleCondition(HCondition* cond) {
// artReadBarrierForRootSlow.
void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
+ void GenerateNop();
+
private:
// Factored implementation of GenerateFieldLoadWithBakerReadBarrier
// and GenerateArrayLoadWithBakerReadBarrier.
}
void InstructionCodeGeneratorARM64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
- if (codegen_->HasStackMapAtCurrentPc()) {
- // Ensure that we do not collide with the stack map of the previous instruction.
- __ Nop();
- }
- codegen_->RecordPcInfo(info, info->GetDexPc());
+ codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+}
+
+void CodeGeneratorARM64::GenerateNop() {
+ __ Nop();
}
void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
// artReadBarrierForRootSlow.
void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
+ void GenerateNop();
+
private:
// Factored implementation of GenerateFieldLoadWithBakerReadBarrier
// and GenerateArrayLoadWithBakerReadBarrier.
}
void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) {
- if (codegen_->HasStackMapAtCurrentPc()) {
- // Ensure that we do not collide with the stack map of the previous instruction.
- __ Nop();
- }
- codegen_->RecordPcInfo(info, info->GetDexPc());
+ codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+}
+
+void CodeGeneratorMIPS::GenerateNop() {
+ __ Nop();
}
void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
UNIMPLEMENTED(FATAL) << "Not implemented on MIPS";
}
+ void GenerateNop();
+
private:
// Labels for each block that will be compiled.
MipsLabel* block_labels_;
}
void InstructionCodeGeneratorMIPS64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
- if (codegen_->HasStackMapAtCurrentPc()) {
- // Ensure that we do not collide with the stack map of the previous instruction.
- __ Nop();
- }
- codegen_->RecordPcInfo(info, info->GetDexPc());
+ codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+}
+
+void CodeGeneratorMIPS64::GenerateNop() {
+ __ Nop();
}
void LocationsBuilderMIPS64::HandleFieldGet(HInstruction* instruction,
UNIMPLEMENTED(FATAL);
}
+ void GenerateNop();
+
private:
// Labels for each block that will be compiled.
Mips64Label* block_labels_; // Indexed by block id.
}
void InstructionCodeGeneratorX86::VisitNativeDebugInfo(HNativeDebugInfo* info) {
- if (codegen_->HasStackMapAtCurrentPc()) {
- // Ensure that we do not collide with the stack map of the previous instruction.
- __ nop();
- }
- codegen_->RecordPcInfo(info, info->GetDexPc());
+ codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+}
+
+void CodeGeneratorX86::GenerateNop() {
+ __ nop();
}
void LocationsBuilderX86::VisitLocal(HLocal* local) {
}
}
+ void GenerateNop();
private:
// Factored implementation of GenerateFieldLoadWithBakerReadBarrier
}
void InstructionCodeGeneratorX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
- if (codegen_->HasStackMapAtCurrentPc()) {
- // Ensure that we do not collide with the stack map of the previous instruction.
- __ nop();
- }
- codegen_->RecordPcInfo(info, info->GetDexPc());
+ codegen_->MaybeRecordNativeDebugInfo(info, info->GetDexPc());
+}
+
+void CodeGeneratorX86_64::GenerateNop() {
+ __ nop();
}
void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
}
}
+ void GenerateNop();
+
private:
// Factored implementation of GenerateFieldLoadWithBakerReadBarrier
// and GenerateArrayLoadWithBakerReadBarrier.