Mark DWARF lines in non-debuggable methods as "not a statement".

This is a hint to the debugger that breakpoints and stepping
might not function as intended (since we have limited information).

Change-Id: I23c4a816182cc7548fcd69fbd00112225e7b1710
diff --git a/compiler/debug/dwarf/debug_line_opcode_writer.h b/compiler/debug/dwarf/debug_line_opcode_writer.h
index 58502a3..b4a4d63 100644
--- a/compiler/debug/dwarf/debug_line_opcode_writer.h
+++ b/compiler/debug/dwarf/debug_line_opcode_writer.h
@@ -36,7 +36,7 @@
 
  public:
   static constexpr int kOpcodeBase = 13;
-  static constexpr bool kDefaultIsStmt = true;
+  static constexpr bool kDefaultIsStmt = false;
   static constexpr int kLineBase = -5;
   static constexpr int kLineRange = 14;
 
@@ -81,8 +81,11 @@
     this->PushUleb128(column);
   }
 
-  void NegateStmt() {
-    this->PushUint8(DW_LNS_negate_stmt);
+  void SetIsStmt(bool is_stmt) {
+    if (is_stmt_ != is_stmt) {
+      this->PushUint8(DW_LNS_negate_stmt);
+      is_stmt_ = is_stmt;
+    }
   }
 
   void SetBasicBlock() {
@@ -112,6 +115,7 @@
     current_address_ = 0;
     current_file_ = 1;
     current_line_ = 1;
+    is_stmt_ = kDefaultIsStmt;
   }
 
   // Uncoditionally set address using the long encoding.
@@ -227,7 +231,8 @@
         code_factor_bits_(codeFactorBits),
         current_address_(0),
         current_file_(1),
-        current_line_(1) {
+        current_line_(1),
+        is_stmt_(kDefaultIsStmt) {
   }
 
  private:
@@ -244,6 +249,7 @@
   uint64_t current_address_;
   int current_file_;
   int current_line_;
+  bool is_stmt_;
   std::vector<uintptr_t> patch_locations_;
 
   DISALLOW_COPY_AND_ASSIGN(DebugLineOpCodeWriter);
diff --git a/compiler/debug/dwarf/dwarf_test.cc b/compiler/debug/dwarf/dwarf_test.cc
index e455d0d..2ba3af5 100644
--- a/compiler/debug/dwarf/dwarf_test.cc
+++ b/compiler/debug/dwarf/dwarf_test.cc
@@ -217,7 +217,9 @@
   DW_CHECK_NEXT("Advance Line by 2 to 3");
   opcodes.SetColumn(4);
   DW_CHECK_NEXT("Set column to 4");
-  opcodes.NegateStmt();
+  opcodes.SetIsStmt(true);
+  DW_CHECK_NEXT("Set is_stmt to 1");
+  opcodes.SetIsStmt(false);
   DW_CHECK_NEXT("Set is_stmt to 0");
   opcodes.SetBasicBlock();
   DW_CHECK_NEXT("Set basic block");
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index d3859ca..11be4e9 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -184,6 +184,10 @@
 
       // Generate mapping opcodes from PC to Java lines.
       if (file_index != 0) {
+        // If the method was not compiled as native-debuggable, we still generate all available
+        // lines, but we try to prevent the debugger from stepping and setting breakpoints since
+        // the information is too inaccurate for that (breakpoints would be set after the calls).
+        const bool default_is_stmt = mi->is_native_debuggable;
         bool first = true;
         for (SrcMapElem pc2dex : pc2dex_map) {
           uint32_t pc = pc2dex.from_;
@@ -205,13 +209,14 @@
                 // Assume that any preceding code is prologue.
                 int first_line = dex2line_map.front().line_;
                 // Prologue is not a sensible place for a breakpoint.
-                opcodes.NegateStmt();
+                opcodes.SetIsStmt(false);
                 opcodes.AddRow(method_address, first_line);
-                opcodes.NegateStmt();
                 opcodes.SetPrologueEnd();
               }
+              opcodes.SetIsStmt(default_is_stmt);
               opcodes.AddRow(method_address + pc, line);
             } else if (line != opcodes.CurrentLine()) {
+              opcodes.SetIsStmt(default_is_stmt);
               opcodes.AddRow(method_address + pc, line);
             }
           }
diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h
index 6b3dd8c..bb09f7e 100644
--- a/compiler/debug/method_debug_info.h
+++ b/compiler/debug/method_debug_info.h
@@ -30,6 +30,7 @@
   uint32_t access_flags;
   const DexFile::CodeItem* code_item;
   bool deduped;
+  bool is_native_debuggable;
   uintptr_t low_pc;
   uintptr_t high_pc;
   CompiledMethod* compiled_method;
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c60b02a..50f5aba 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -806,7 +806,8 @@
         }
       }
 
-      if (writer_->compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo()) {
+      const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
+      if (compiler_options.GenerateAnyDebugInfo()) {
         // Record debug information for this function if we are doing that.
         const uint32_t quick_code_start = quick_code_offset -
             writer_->oat_header_->GetExecutableOffset() - thumb_offset;
@@ -817,6 +818,7 @@
             it.GetMethodAccessFlags(),
             it.GetMethodCodeItem(),
             deduped,
+            compiler_options.GetNativeDebuggable(),
             quick_code_start,
             quick_code_start + code_size,
             compiled_method});
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index b49b91d..42f22af 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -913,7 +913,8 @@
     return false;
   }
 
-  if (GetCompilerDriver()->GetCompilerOptions().GetGenerateDebugInfo()) {
+  const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions();
+  if (compiler_options.GetGenerateDebugInfo()) {
     const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code);
     const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode());
     CompiledMethod compiled_method(
@@ -936,6 +937,7 @@
         access_flags,
         code_item,
         false,  // deduped.
+        compiler_options.GetNativeDebuggable(),
         code_address,
         code_address + code_allocator.GetSize(),
         &compiled_method