Do not write full method signature in mini-debug-info.

Write only fully qualified method name to reduce the size.
This approximately halves the amount of string data which
in turn reduces the overhead of mini-debug-info from 3.5% to 3%.

Change-Id: Iba9b1d5af77bd90a6c93912ff10bded243d716ce
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 94e5d76..012a71f 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -1339,8 +1339,9 @@
 }
 
 template <typename ElfTypes>
-void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
-                       const ArrayRef<const MethodDebugInfo>& method_infos) {
+static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
+                              const ArrayRef<const MethodDebugInfo>& method_infos,
+                              bool with_signature) {
   bool generated_mapping_symbol = false;
   auto* strtab = builder->GetStrTab();
   auto* symtab = builder->GetSymTab();
@@ -1360,22 +1361,31 @@
 
   strtab->Start();
   strtab->Write("");  // strtab should start with empty string.
+  std::string last_name;
+  size_t last_name_offset = 0;
   for (const MethodDebugInfo& info : method_infos) {
     if (info.deduped_) {
       continue;  // Add symbol only for the first instance.
     }
-    std::string name = PrettyMethod(info.dex_method_index_, *info.dex_file_, true);
+    std::string name = PrettyMethod(info.dex_method_index_, *info.dex_file_, with_signature);
     if (deduped_addresses.find(info.low_pc_) != deduped_addresses.end()) {
       name += " [DEDUPED]";
     }
+    // If we write method names without signature, we might see the same name multiple times.
+    size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
 
     const auto* text = builder->GetText()->Exists() ? builder->GetText() : nullptr;
     const bool is_relative = (text != nullptr);
     uint32_t low_pc = info.low_pc_;
     // Add in code delta, e.g., thumb bit 0 for Thumb2 code.
     low_pc += info.compiled_method_->CodeDelta();
-    symtab->Add(strtab->Write(name), text, low_pc,
-                is_relative, info.high_pc_ - info.low_pc_, STB_GLOBAL, STT_FUNC);
+    symtab->Add(name_offset,
+                text,
+                low_pc,
+                is_relative,
+                info.high_pc_ - info.low_pc_,
+                STB_GLOBAL,
+                STT_FUNC);
 
     // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
     // instructions, so that disassembler tools can correctly disassemble.
@@ -1388,6 +1398,9 @@
         generated_mapping_symbol = true;
       }
     }
+
+    last_name = std::move(name);
+    last_name_offset = name_offset;
   }
   strtab->End();
 
@@ -1403,7 +1416,7 @@
                     const ArrayRef<const MethodDebugInfo>& method_infos,
                     CFIFormat cfi_format) {
   // Add methods to .symtab.
-  WriteDebugSymbols(builder, method_infos);
+  WriteDebugSymbols(builder, method_infos, true /* with_signature */);
   // Generate CFI (stack unwinding information).
   WriteCFISection(builder, method_infos, cfi_format);
   // Write DWARF .debug_* sections.
@@ -1470,7 +1483,7 @@
   builder->GetRoData()->WriteNoBitsSection(parent_builder->GetRoData()->GetSize());
   builder->SetVirtualAddress(parent_builder->GetText()->GetAddress());
   builder->GetText()->WriteNoBitsSection(parent_builder->GetText()->GetSize());
-  WriteDebugSymbols(builder.get(), method_infos);
+  WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
   WriteCFISection(builder.get(), method_infos, DW_DEBUG_FRAME_FORMAT);
   builder->End();
   CHECK(builder->Good());
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 77301d2..87656bc 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -101,7 +101,12 @@
 }
 #endif
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(JNIEnv*, jobject, jint, jboolean) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(
+    JNIEnv*,
+    jobject,
+    jboolean full_signatrues,
+    jint,
+    jboolean) {
 #if __linux__
   if (IsPicImage()) {
     LOG(INFO) << "Image is pic, in-process unwinding check bypassed.";
@@ -122,14 +127,21 @@
   // We cannot really parse an exact stack, as the optimizing compiler may inline some functions.
   // This is also risky, as deduping might play a trick on us, so the test needs to make sure that
   // only unique functions are being expected.
+  // "mini-debug-info" does not include parameters to save space.
   std::vector<std::string> seq = {
       "Java_Main_unwindInProcess",                   // This function.
-      "boolean Main.unwindInProcess(int, boolean)",  // The corresponding Java native method frame.
+      "Main.unwindInProcess",                        // The corresponding Java native method frame.
+      "int java.util.Arrays.binarySearch(java.lang.Object[], int, int, java.lang.Object, java.util.Comparator)",  // Framework method.
+      "Main.main"                                    // The Java entry method.
+  };
+  std::vector<std::string> full_seq = {
+      "Java_Main_unwindInProcess",                   // This function.
+      "boolean Main.unwindInProcess(boolean, int, boolean)",  // The corresponding Java native method frame.
       "int java.util.Arrays.binarySearch(java.lang.Object[], int, int, java.lang.Object, java.util.Comparator)",  // Framework method.
       "void Main.main(java.lang.String[])"           // The Java entry method.
   };
 
-  bool result = CheckStack(bt.get(), seq);
+  bool result = CheckStack(bt.get(), full_signatrues ? full_seq : seq);
   if (!kCauseSegfault) {
     return result ? JNI_TRUE : JNI_FALSE;
   } else {
@@ -178,7 +190,11 @@
 }
 #endif
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(JNIEnv*, jobject, jint pid_int) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(
+    JNIEnv*,
+    jobject,
+    jboolean full_signatrues,
+    jint pid_int) {
 #if __linux__
   // TODO: What to do on Valgrind?
   pid_t pid = static_cast<pid_t>(pid_int);
@@ -214,17 +230,27 @@
 
   if (result) {
     // See comment in unwindInProcess for non-exact stack matching.
+    // "mini-debug-info" does not include parameters to save space.
     std::vector<std::string> seq = {
         // "Java_Main_sleep",                        // The sleep function being executed in the
                                                      // other runtime.
                                                      // Note: For some reason, the name isn't
                                                      // resolved, so don't look for it right now.
+        "Main.sleep",                                // The corresponding Java native method frame.
+        "int java.util.Arrays.binarySearch(java.lang.Object[], int, int, java.lang.Object, java.util.Comparator)",  // Framework method.
+        "Main.main"                                  // The Java entry method.
+    };
+    std::vector<std::string> full_seq = {
+        // "Java_Main_sleep",                        // The sleep function being executed in the
+                                                     // other runtime.
+                                                     // Note: For some reason, the name isn't
+                                                     // resolved, so don't look for it right now.
         "boolean Main.sleep(int, boolean, double)",  // The corresponding Java native method frame.
         "int java.util.Arrays.binarySearch(java.lang.Object[], int, int, java.lang.Object, java.util.Comparator)",  // Framework method.
         "void Main.main(java.lang.String[])"         // The Java entry method.
     };
 
-    result = CheckStack(bt.get(), seq);
+    result = CheckStack(bt.get(), full_signatrues ? full_seq : seq);
   }
 
   if (ptrace(PTRACE_DETACH, pid, 0, 0) != 0) {
diff --git a/test/137-cfi/run b/test/137-cfi/run
index 66575fc..6f4bcfe 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -15,7 +15,9 @@
 # limitations under the License.
 
 # Test with full DWARF debugging information.
-${RUN} "$@" -Xcompiler-option --generate-debug-info
+# Check full signatures of methods.
+${RUN} "$@" -Xcompiler-option --generate-debug-info --args --full-signatures
 
 # Test with minimal compressed debugging information.
+# Check only method names (parameters are omitted to save space).
 ${RUN} "$@" -Xcompiler-option --generate-mini-debug-info
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 5474c9b..7755338 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -34,19 +34,28 @@
 
   private boolean secondary;
 
+  private boolean full_signatures;
+
   private boolean passed;
 
-  public Main(boolean secondary) {
+  public Main(boolean secondary, boolean full_signatures) {
       this.secondary = secondary;
+      this.full_signatures = full_signatures;
   }
 
   public static void main(String[] args) throws Exception {
     System.loadLibrary(args[0]);
       boolean secondary = false;
-      if (args.length > 0 && args[args.length - 1].equals("--secondary")) {
+      boolean full_signatures = false;
+      for (String arg : args) {
+        if (arg.equals("--secondary")) {
           secondary = true;
+        }
+        if (arg.equals("--full-signatures")) {
+          full_signatures = true;
+        }
       }
-      new Main(secondary).run();
+      new Main(secondary, full_signatures).run();
   }
 
   private void run() {
@@ -96,7 +105,7 @@
               throw new RuntimeException(e);
           }
 
-          if (!unwindOtherProcess(pid)) {
+          if (!unwindOtherProcess(full_signatures, pid)) {
               System.out.println("Unwinding other process failed.");
           }
       } finally {
@@ -154,7 +163,7 @@
       if (b) {
           return sleep(2, b, 1.0);
       } else {
-          return unwindInProcess(1, b);
+          return unwindInProcess(full_signatures, 1, b);
       }
   }
 
@@ -162,6 +171,6 @@
 
   public native boolean sleep(int i, boolean b, double dummy);
 
-  public native boolean unwindInProcess(int i, boolean b);
-  public native boolean unwindOtherProcess(int pid);
+  public native boolean unwindInProcess(boolean full_signatures, int i, boolean b);
+  public native boolean unwindOtherProcess(boolean full_signatures, int pid);
 }
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index e004b6c..63ec2a0 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -74,6 +74,14 @@
         fi
         ARGS="${ARGS} $1"
         shift
+    elif [ "x$1" = "x--args" ]; then
+        shift
+        if [ "x$1" = "x" ]; then
+            echo "$0 missing argument to --args" 1>&2
+            exit 1
+        fi
+        ARGS="${ARGS} $1"
+        shift
     elif [ "x$1" = "x-Xcompiler-option" ]; then
         shift
         option="$1"