Avoid re-declarations of base classes in DWARF.

Declare each base class only once for sanity and to save space.
If the class also has definition, use it instead.

Change-Id: I07cca012d0db75980b1239f44c6cb4069c3f353e
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index b93c9df..5dbbbc7 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -621,6 +621,12 @@
       info_.WriteStrp(DW_AT_producer, owner_->WriteString("Android dex2oat"));
       info_.WriteData1(DW_AT_language, DW_LANG_Java);
 
+      // Base class references to be patched at the end.
+      std::map<size_t, mirror::Class*> base_class_references;
+
+      // Already written declarations or definitions.
+      std::map<mirror::Class*, size_t> class_declarations;
+
       std::vector<uint8_t> expr_buffer;
       for (mirror::Class* type : types) {
         if (type->IsPrimitive()) {
@@ -652,22 +658,10 @@
           // Skip.  Variables cannot have an interface as a dynamic type.
           // We do not expose the interface information to the debugger in any way.
         } else {
-          // Declare base class.  We can not use the standard WriteLazyType
-          // since we want to avoid the DW_TAG_reference_tag wrapping.
-          mirror::Class* base_class = type->GetSuperClass();
-          size_t base_class_declaration_offset = 0;
-          if (base_class != nullptr) {
-            std::string tmp_storage;
-            const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
-            base_class_declaration_offset = StartClassTag(base_class_desc);
-            info_.WriteFlagPresent(DW_AT_declaration);
-            WriteLinkageName(base_class);
-            EndClassTag();
-          }
-
           std::string descriptor_string;
           const char* desc = type->GetDescriptor(&descriptor_string);
-          StartClassTag(desc);
+          size_t class_offset = StartClassTag(desc);
+          class_declarations.emplace(type, class_offset);
 
           if (!type->IsVariableSize()) {
             info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize());
@@ -704,9 +698,11 @@
           }
 
           // Base class.
+          mirror::Class* base_class = type->GetSuperClass();
           if (base_class != nullptr) {
             info_.StartTag(DW_TAG_inheritance);
-            info_.WriteRef4(DW_AT_type, base_class_declaration_offset);
+            base_class_references.emplace(info_.size(), base_class);
+            info_.WriteRef4(DW_AT_type, 0);
             info_.WriteUdata(DW_AT_data_member_location, 0);
             info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
             info_.EndTag();  // DW_TAG_inheritance.
@@ -749,6 +745,27 @@
         }
       }
 
+      // Write base class declarations.
+      for (const auto& base_class_reference : base_class_references) {
+        size_t reference_offset = base_class_reference.first;
+        mirror::Class* base_class = base_class_reference.second;
+        const auto& it = class_declarations.find(base_class);
+        if (it != class_declarations.end()) {
+          info_.UpdateUint32(reference_offset, it->second);
+        } else {
+          // Declare base class.  We can not use the standard WriteLazyType
+          // since we want to avoid the DW_TAG_reference_tag wrapping.
+          std::string tmp_storage;
+          const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
+          size_t base_class_declaration_offset = StartClassTag(base_class_desc);
+          info_.WriteFlagPresent(DW_AT_declaration);
+          WriteLinkageName(base_class);
+          EndClassTag();
+          class_declarations.emplace(base_class, base_class_declaration_offset);
+          info_.UpdateUint32(reference_offset, base_class_declaration_offset);
+        }
+      }
+
       FinishLazyTypes();
       CloseNamespacesAboveDepth(0);
       info_.EndTag();  // DW_TAG_compile_unit.