Merge "ART: Faster PrettyMethod()."
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index ece853f..d4297df 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -777,26 +777,16 @@
 }
 
 std::string ArtMethod::PrettyMethod(bool with_signature) {
-  ArtMethod* m = this;
-  if (!m->IsRuntimeMethod()) {
-    m = m->GetInterfaceMethodIfProxy(Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+  if (UNLIKELY(IsRuntimeMethod())) {
+    std::string result = GetDeclaringClassDescriptor();
+    result += '.';
+    result += GetName();
+    // Do not add "<no signature>" even if `with_signature` is true.
+    return result;
   }
-  std::string result(PrettyDescriptor(m->GetDeclaringClassDescriptor()));
-  result += '.';
-  result += m->GetName();
-  if (UNLIKELY(m->IsFastNative())) {
-    result += "!";
-  }
-  if (with_signature) {
-    const Signature signature = m->GetSignature();
-    std::string sig_as_string(signature.ToString());
-    if (signature == Signature::NoSignature()) {
-      return result + sig_as_string;
-    }
-    result = PrettyReturnType(sig_as_string.c_str()) + " " + result +
-        PrettyArguments(sig_as_string.c_str());
-  }
-  return result;
+  ArtMethod* m =
+      GetInterfaceMethodIfProxy(Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+  return m->GetDexFile()->PrettyMethod(m->GetDexMethodIndex(), with_signature);
 }
 
 std::string ArtMethod::JniShortName() {
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index f70846b..be157a3 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -1302,17 +1302,27 @@
     return StringPrintf("<<invalid-method-idx-%d>>", method_idx);
   }
   const DexFile::MethodId& method_id = GetMethodId(method_idx);
-  std::string result(PrettyDescriptor(GetMethodDeclaringClassDescriptor(method_id)));
+  std::string result;
+  const DexFile::ProtoId* proto_id = with_signature ? &GetProtoId(method_id.proto_idx_) : nullptr;
+  if (with_signature) {
+    AppendPrettyDescriptor(StringByTypeIdx(proto_id->return_type_idx_), &result);
+    result += ' ';
+  }
+  AppendPrettyDescriptor(GetMethodDeclaringClassDescriptor(method_id), &result);
   result += '.';
   result += GetMethodName(method_id);
   if (with_signature) {
-    const Signature signature = GetMethodSignature(method_id);
-    std::string sig_as_string(signature.ToString());
-    if (signature == Signature::NoSignature()) {
-      return result + sig_as_string;
+    result += '(';
+    const DexFile::TypeList* params = GetProtoParameters(*proto_id);
+    if (params != nullptr) {
+      const char* separator = "";
+      for (uint32_t i = 0u, size = params->Size(); i != size; ++i) {
+        result += separator;
+        separator = ", ";
+        AppendPrettyDescriptor(StringByTypeIdx(params->GetTypeItem(i).type_idx_), &result);
+      }
     }
-    result = PrettyReturnType(sig_as_string.c_str()) + " " + result +
-        PrettyArguments(sig_as_string.c_str());
+    result += ')';
   }
   return result;
 }
@@ -1327,7 +1337,7 @@
     result += GetFieldTypeDescriptor(field_id);
     result += ' ';
   }
-  result += PrettyDescriptor(GetFieldDeclaringClassDescriptor(field_id));
+  AppendPrettyDescriptor(GetFieldDeclaringClassDescriptor(field_id), &result);
   result += '.';
   result += GetFieldName(field_id);
   return result;
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 1a73062..a7bf59e 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -423,28 +423,83 @@
     ASSERT_EQ("()V", signature);
   }
 
-  // Check both virtual methods.
-  ASSERT_EQ(2U, it.NumVirtualMethods());
-  {
+  // Check all virtual methods.
+  struct Result {
+    const char* name;
+    const char* signature;
+    const char* pretty_method;
+  };
+  static const Result results[] = {
+      {
+          "m1",
+          "(IDJLjava/lang/Object;)Ljava/lang/Float;",
+          "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m2",
+          "(ZSC)LGetMethodSignature;",
+          "GetMethodSignature GetMethodSignature.m2(boolean, short, char)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m3",
+          "()V",
+          "void GetMethodSignature.m3()"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m4",
+          "(I)V",
+          "void GetMethodSignature.m4(int)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m5",
+          "(II)V",
+          "void GetMethodSignature.m5(int, int)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m6",
+          "(II[[I)V",
+          "void GetMethodSignature.m6(int, int, int[][])"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m7",
+          "(II[[ILjava/lang/Object;)V",
+          "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m8",
+          "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V",
+          "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "m9",
+          "()I",
+          "int GetMethodSignature.m9()"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "mA",
+          "()[[I",
+          "int[][] GetMethodSignature.mA()"
+      },
+      {  // NOLINT [whitespace/braces] [4]
+          "mB",
+          "()[[Ljava/lang/Object;",
+          "java.lang.Object[][] GetMethodSignature.mB()"
+      },
+  };
+  ASSERT_EQ(arraysize(results), it.NumVirtualMethods());
+  for (const Result& r : results) {
     it.Next();
     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
 
     const char* name = raw->StringDataByIdx(method_id.name_idx_);
-    ASSERT_STREQ("m1", name);
+    ASSERT_STREQ(r.name, name);
 
     std::string signature(raw->GetMethodSignature(method_id).ToString());
-    ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature);
-  }
+    ASSERT_EQ(r.signature, signature);
 
-  {
-    it.Next();
-    const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
-
-    const char* name = raw->StringDataByIdx(method_id.name_idx_);
-    ASSERT_STREQ("m2", name);
-
-    std::string signature(raw->GetMethodSignature(method_id).ToString());
-    ASSERT_EQ("(ZSC)LGetMethodSignature;", signature);
+    std::string plain_method = std::string("GetMethodSignature.") + r.name;
+    ASSERT_EQ(plain_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ false));
+    ASSERT_EQ(r.pretty_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ true));
   }
 }
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 3fe18c7..fc1c91a 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -148,7 +148,7 @@
   }
 }
 
-std::string PrettyDescriptor(const char* descriptor) {
+void AppendPrettyDescriptor(const char* descriptor, std::string* result) {
   // Count the number of '['s to get the dimensionality.
   const char* c = descriptor;
   size_t dim = 0;
@@ -166,74 +166,41 @@
     // To make life easier, we make primitives look like unqualified
     // reference types.
     switch (*c) {
-    case 'B': c = "byte;"; break;
-    case 'C': c = "char;"; break;
-    case 'D': c = "double;"; break;
-    case 'F': c = "float;"; break;
-    case 'I': c = "int;"; break;
-    case 'J': c = "long;"; break;
-    case 'S': c = "short;"; break;
-    case 'Z': c = "boolean;"; break;
-    case 'V': c = "void;"; break;  // Used when decoding return types.
-    default: return descriptor;
+      case 'B': c = "byte;"; break;
+      case 'C': c = "char;"; break;
+      case 'D': c = "double;"; break;
+      case 'F': c = "float;"; break;
+      case 'I': c = "int;"; break;
+      case 'J': c = "long;"; break;
+      case 'S': c = "short;"; break;
+      case 'Z': c = "boolean;"; break;
+      case 'V': c = "void;"; break;  // Used when decoding return types.
+      default: result->append(descriptor); return;
     }
   }
 
   // At this point, 'c' is a string of the form "fully/qualified/Type;"
   // or "primitive;". Rewrite the type with '.' instead of '/':
-  std::string result;
   const char* p = c;
   while (*p != ';') {
     char ch = *p++;
     if (ch == '/') {
       ch = '.';
     }
-    result.push_back(ch);
+    result->push_back(ch);
   }
   // ...and replace the semicolon with 'dim' "[]" pairs:
   for (size_t i = 0; i < dim; ++i) {
-    result += "[]";
+    result->append("[]");
   }
-  return result;
 }
 
-std::string PrettyArguments(const char* signature) {
+std::string PrettyDescriptor(const char* descriptor) {
   std::string result;
-  result += '(';
-  CHECK_EQ(*signature, '(');
-  ++signature;  // Skip the '('.
-  while (*signature != ')') {
-    size_t argument_length = 0;
-    while (signature[argument_length] == '[') {
-      ++argument_length;
-    }
-    if (signature[argument_length] == 'L') {
-      argument_length = (strchr(signature, ';') - signature + 1);
-    } else {
-      ++argument_length;
-    }
-    {
-      std::string argument_descriptor(signature, argument_length);
-      result += PrettyDescriptor(argument_descriptor.c_str());
-    }
-    if (signature[argument_length] != ')') {
-      result += ", ";
-    }
-    signature += argument_length;
-  }
-  CHECK_EQ(*signature, ')');
-  ++signature;  // Skip the ')'.
-  result += ')';
+  AppendPrettyDescriptor(descriptor, &result);
   return result;
 }
 
-std::string PrettyReturnType(const char* signature) {
-  const char* return_type = strchr(signature, ')');
-  CHECK(return_type != nullptr);
-  ++return_type;  // Skip ')'.
-  return PrettyDescriptor(return_type);
-}
-
 std::string PrettyJavaAccessFlags(uint32_t access_flags) {
   std::string result;
   if ((access_flags & kAccPublic) != 0) {
diff --git a/runtime/utils.h b/runtime/utils.h
index 739681d..9945298 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -81,13 +81,10 @@
 // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
 // "[[I" would be "int[][]", "[Ljava/lang/String;" would be
 // "java.lang.String[]", and so forth.
+void AppendPrettyDescriptor(const char* descriptor, std::string* result);
 std::string PrettyDescriptor(const char* descriptor);
 std::string PrettyDescriptor(Primitive::Type type);
 
-// Utilities for printing the types for method signatures.
-std::string PrettyArguments(const char* signature);
-std::string PrettyReturnType(const char* signature);
-
 // Returns a human-readable version of the Java part of the access flags, e.g., "private static "
 // (note the trailing whitespace).
 std::string PrettyJavaAccessFlags(uint32_t access_flags);
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index ee8eb36..decb243 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -91,23 +91,6 @@
   EXPECT_EQ("short", PrettyDescriptor("S"));
 }
 
-TEST_F(UtilsTest, PrettyArguments) {
-  EXPECT_EQ("()", PrettyArguments("()V"));
-  EXPECT_EQ("(int)", PrettyArguments("(I)V"));
-  EXPECT_EQ("(int, int)", PrettyArguments("(II)V"));
-  EXPECT_EQ("(int, int, int[][])", PrettyArguments("(II[[I)V"));
-  EXPECT_EQ("(int, int, int[][], java.lang.Poop)", PrettyArguments("(II[[ILjava/lang/Poop;)V"));
-  EXPECT_EQ("(int, int, int[][], java.lang.Poop, java.lang.Poop[][])", PrettyArguments("(II[[ILjava/lang/Poop;[[Ljava/lang/Poop;)V"));
-}
-
-TEST_F(UtilsTest, PrettyReturnType) {
-  EXPECT_EQ("void", PrettyReturnType("()V"));
-  EXPECT_EQ("int", PrettyReturnType("()I"));
-  EXPECT_EQ("int[][]", PrettyReturnType("()[[I"));
-  EXPECT_EQ("java.lang.Poop", PrettyReturnType("()Ljava/lang/Poop;"));
-  EXPECT_EQ("java.lang.Poop[][]", PrettyReturnType("()[[Ljava/lang/Poop;"));
-}
-
 TEST_F(UtilsTest, PrettyTypeOf) {
   ScopedObjectAccess soa(Thread::Current());
   EXPECT_EQ("null", mirror::Object::PrettyTypeOf(nullptr));
diff --git a/test/GetMethodSignature/GetMethodSignature.java b/test/GetMethodSignature/GetMethodSignature.java
index c2ba948..d2f96bb 100644
--- a/test/GetMethodSignature/GetMethodSignature.java
+++ b/test/GetMethodSignature/GetMethodSignature.java
@@ -17,4 +17,13 @@
 class GetMethodSignature {
     Float m1(int a, double b, long c, Object d) { return null; }
     GetMethodSignature m2(boolean x, short y, char z) { return null; }
+    void m3() { }
+    void m4(int i) { }
+    void m5(int i, int j) { }
+    void m6(int i, int j, int[][] array1) { }
+    void m7(int i, int j, int[][] array1, Object o) { }
+    void m8(int i, int j, int[][] array1, Object o, Object[][] array2) { }
+    int m9() { return 0; }
+    int[][] mA() { return null; }
+    Object[][] mB() { return null; }
 }