DWARF: Allow compilation units to contain methods out of order.

Test: m test-art-host

Change-Id: I463a413fea3a740d4a8912f138bdccdc09a3d1e4
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index de32351..6c6bd63 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -122,17 +122,39 @@
     const Elf_Addr base_address = compilation_unit.is_code_address_text_relative
         ? owner_->builder_->GetText()->GetAddress()
         : 0;
-    const uint64_t cu_size = compilation_unit.code_end - compilation_unit.code_address;
+    const bool is64bit = Is64BitInstructionSet(owner_->builder_->GetIsa());
     using namespace dwarf;  // NOLINT. For easy access to DWARF constants.
 
     info_.StartTag(DW_TAG_compile_unit);
     info_.WriteString(DW_AT_producer, "Android dex2oat");
     info_.WriteData1(DW_AT_language, DW_LANG_Java);
     info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT");
+    // The low_pc acts as base address for several other addresses/ranges.
     info_.WriteAddr(DW_AT_low_pc, base_address + compilation_unit.code_address);
-    info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size));
     info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset);
 
+    // Write .debug_ranges entries covering code ranges of the whole compilation unit.
+    dwarf::Writer<> debug_ranges(&owner_->debug_ranges_);
+    info_.WriteSecOffset(DW_AT_ranges, owner_->debug_ranges_.size());
+    for (auto mi : compilation_unit.methods) {
+      uint64_t low_pc = mi->code_address - compilation_unit.code_address;
+      uint64_t high_pc = low_pc + mi->code_size;
+      if (is64bit) {
+        debug_ranges.PushUint64(low_pc);
+        debug_ranges.PushUint64(high_pc);
+      } else {
+        debug_ranges.PushUint32(low_pc);
+        debug_ranges.PushUint32(high_pc);
+      }
+    }
+    if (is64bit) {
+      debug_ranges.PushUint64(0);  // End of list.
+      debug_ranges.PushUint64(0);
+    } else {
+      debug_ranges.PushUint32(0);  // End of list.
+      debug_ranges.PushUint32(0);
+    }
+
     const char* last_dex_class_desc = nullptr;
     for (auto mi : compilation_unit.methods) {
       DCHECK(mi->dex_file != nullptr);
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 7fa6e14..e962d56 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -17,6 +17,7 @@
 #include "elf_debug_writer.h"
 
 #include <vector>
+#include <unordered_map>
 
 #include "base/array_ref.h"
 #include "debug/dwarf/dwarf_constants.h"
@@ -46,27 +47,42 @@
   // Write .debug_frame.
   WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
 
-  // Group the methods into compilation units based on source file.
-  std::vector<ElfCompilationUnit> compilation_units;
-  const char* last_source_file = nullptr;
+  // Group the methods into compilation units based on class.
+  std::unordered_map<const DexFile::ClassDef*, ElfCompilationUnit> class_to_compilation_unit;
   for (const MethodDebugInfo& mi : method_infos) {
     if (mi.dex_file != nullptr) {
       auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
-      const char* source_file = mi.dex_file->GetSourceFile(dex_class_def);
-      if (compilation_units.empty() || source_file != last_source_file) {
-        compilation_units.push_back(ElfCompilationUnit());
-      }
-      ElfCompilationUnit& cu = compilation_units.back();
+      ElfCompilationUnit& cu = class_to_compilation_unit[&dex_class_def];
       cu.methods.push_back(&mi);
       // All methods must have the same addressing mode otherwise the min/max below does not work.
       DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
       cu.is_code_address_text_relative = mi.is_code_address_text_relative;
       cu.code_address = std::min(cu.code_address, mi.code_address);
       cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
-      last_source_file = source_file;
     }
   }
 
+  // Sort compilation units to make the compiler output deterministic.
+  std::vector<ElfCompilationUnit> compilation_units;
+  compilation_units.reserve(class_to_compilation_unit.size());
+  for (auto& it : class_to_compilation_unit) {
+    // The .debug_line section requires the methods to be sorted by code address.
+    std::stable_sort(it.second.methods.begin(),
+                     it.second.methods.end(),
+                     [](const MethodDebugInfo* a, const MethodDebugInfo* b) {
+                         return a->code_address < b->code_address;
+                     });
+    compilation_units.push_back(std::move(it.second));
+  }
+  std::sort(compilation_units.begin(),
+            compilation_units.end(),
+            [](ElfCompilationUnit& a, ElfCompilationUnit& b) {
+                // Sort by index of the first method within the method_infos array.
+                // This assumes that the order of method_infos is deterministic.
+                // Code address is not good for sorting due to possible duplicates.
+                return a.methods.front() < b.methods.front();
+            });
+
   // Write .debug_line section.
   if (!compilation_units.empty()) {
     ElfDebugLineWriter<ElfTypes> line_writer(builder);