Introduce Signature type to avoid string comparisons.

Method resolution currently creates strings to then compare with strings formed
from methods in other dex files. The temporary strings are purely created for
the sake of comparisons. This change creates a new Signature type that
represents a method signature but not as a string. This type supports
comparisons and so can be used when searching for methods in resolution.

With this change malloc is no longer the hottest method during dex2oat (now its
memset) and allocations during verification have been reduced. The verifier is
commonly what is populating the dex cache for methods and fields not declared
in the dex file itself.

Change-Id: I5ef0542823fbcae868aaa4a2457e8da7df0e9dae
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 4ce752f..6e49f0b 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -248,12 +248,12 @@
 }
 
 /* Dump a mapping table */
-void Mir2Lir::DumpMappingTable(const char* table_name, const std::string& descriptor,
-                               const std::string& name, const std::string& signature,
+void Mir2Lir::DumpMappingTable(const char* table_name, const char* descriptor,
+                               const char* name, const Signature& signature,
                                const std::vector<uint32_t>& v) {
   if (v.size() > 0) {
     std::string line(StringPrintf("\n  %s %s%s_%s_table[%zu] = {", table_name,
-                     descriptor.c_str(), name.c_str(), signature.c_str(), v.size()));
+                     descriptor, name, signature.ToString().c_str(), v.size()));
     std::replace(line.begin(), line.end(), ';', '_');
     LOG(INFO) << line;
     for (uint32_t i = 0; i < v.size(); i+=2) {
@@ -293,9 +293,9 @@
 
   const DexFile::MethodId& method_id =
       cu_->dex_file->GetMethodId(cu_->method_idx);
-  std::string signature(cu_->dex_file->GetMethodSignature(method_id));
-  std::string name(cu_->dex_file->GetMethodName(method_id));
-  std::string descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id));
+  const Signature signature = cu_->dex_file->GetMethodSignature(method_id);
+  const char* name = cu_->dex_file->GetMethodName(method_id);
+  const char* descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id));
 
   // Dump mapping tables
   DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, pc2dex_mapping_table_);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 401e3d5..7d6f968 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -283,8 +283,8 @@
     bool EvaluateBranch(Instruction::Code opcode, int src1, int src2);
     bool IsInexpensiveConstant(RegLocation rl_src);
     ConditionCode FlipComparisonOrder(ConditionCode before);
-    void DumpMappingTable(const char* table_name, const std::string& descriptor,
-                          const std::string& name, const std::string& signature,
+    void DumpMappingTable(const char* table_name, const char* descriptor,
+                          const char* name, const Signature& signature,
                           const std::vector<uint32_t>& v);
     void InstallLiteralPools();
     void InstallSwitchTables();
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index e227715..056be1f 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1227,8 +1227,9 @@
                   if (name != NULL) {
                     uint16_t return_type_idx;
                     std::vector<uint16_t> param_type_idxs;
-                    bool success = dexfile->CreateTypeList(&return_type_idx, &param_type_idxs,
-                                                           cm_dexfile->GetMethodSignature(cm_method_id));
+                    bool success =
+                        dexfile->CreateTypeList(cm_dexfile->GetMethodSignature(cm_method_id).ToString(),
+                                                &return_type_idx, &param_type_idxs);
                     if (success) {
                       const DexFile::ProtoId* sig =
                           dexfile->FindProtoId(return_type_idx, param_type_idxs);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 6aae63e..17a179f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2823,12 +2823,12 @@
   CHECK(constructor->IsConstructor());
   MethodHelper mh(constructor);
   CHECK_STREQ(mh.GetName(), "<init>");
-  CHECK_EQ(mh.GetSignature(), std::string("(Ljava/lang/reflect/InvocationHandler;)V"));
+  CHECK_STREQ(mh.GetSignature().ToString().c_str(), "(Ljava/lang/reflect/InvocationHandler;)V");
   DCHECK(constructor->IsPublic());
 }
 
 mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, SirtRef<mirror::Class>& klass,
-                                                       SirtRef<mirror::ArtMethod>& prototype) {
+                                                  SirtRef<mirror::ArtMethod>& prototype) {
   // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
   // prototype method
   prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(),
@@ -2892,7 +2892,7 @@
   }
   if (!can_init_statics) {
     // Check if there's a class initializer.
-    mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
+    mirror::ArtMethod* clinit = klass->FindClassInitializer();
     if (clinit != NULL) {
       return false;
     }
@@ -3039,7 +3039,7 @@
     }
   }
 
-  mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
+  mirror::ArtMethod* clinit = klass->FindClassInitializer();
   if (clinit != NULL) {
     CHECK(can_init_statics);
     if (LIKELY(Runtime::Current()->IsStarted())) {
@@ -3992,11 +3992,11 @@
 }
 
 mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
-                                                   uint32_t method_idx,
-                                                   mirror::DexCache* dex_cache,
-                                                   mirror::ClassLoader* class_loader,
-                                                   const mirror::ArtMethod* referrer,
-                                                   InvokeType type) {
+                                              uint32_t method_idx,
+                                              mirror::DexCache* dex_cache,
+                                              mirror::ClassLoader* class_loader,
+                                              const mirror::ArtMethod* referrer,
+                                              InvokeType type) {
   DCHECK(dex_cache != NULL);
   // Check for hit in the dex cache.
   mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
@@ -4031,7 +4031,7 @@
   if (resolved == NULL) {
     // Search by name, which works across dex files.
     const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
-    std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL));
+    const Signature signature = dex_file.GetMethodSignature(method_id);
     switch (type) {
       case kDirect:  // Fall-through.
       case kStatic:
@@ -4061,7 +4061,7 @@
     // We failed to find the method which means either an access error, an incompatible class
     // change, or no such method. First try to find the method among direct and virtual methods.
     const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
-    std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL));
+    const Signature signature = dex_file.GetMethodSignature(method_id);
     switch (type) {
       case kDirect:
       case kStatic:
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index bea1139..ad9347f 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -152,7 +152,7 @@
     EXPECT_TRUE(method != NULL);
     EXPECT_TRUE(method->GetClass() != NULL);
     EXPECT_TRUE(mh.GetName() != NULL);
-    EXPECT_TRUE(mh.GetSignature() != NULL);
+    EXPECT_TRUE(mh.GetSignature() != Signature::NoSignature());
 
     EXPECT_TRUE(method->GetDexCacheStrings() != NULL);
     EXPECT_TRUE(method->GetDexCacheResolvedMethods() != NULL);
@@ -942,15 +942,16 @@
   EXPECT_TRUE(K->IsAssignableFrom(B));
   EXPECT_TRUE(J->IsAssignableFrom(B));
 
-  mirror::ArtMethod* Ii = I->FindVirtualMethod("i", "()V");
-  mirror::ArtMethod* Jj1 = J->FindVirtualMethod("j1", "()V");
-  mirror::ArtMethod* Jj2 = J->FindVirtualMethod("j2", "()V");
-  mirror::ArtMethod* Kj1 = K->FindInterfaceMethod("j1", "()V");
-  mirror::ArtMethod* Kj2 = K->FindInterfaceMethod("j2", "()V");
-  mirror::ArtMethod* Kk = K->FindInterfaceMethod("k", "()V");
-  mirror::ArtMethod* Ai = A->FindVirtualMethod("i", "()V");
-  mirror::ArtMethod* Aj1 = A->FindVirtualMethod("j1", "()V");
-  mirror::ArtMethod* Aj2 = A->FindVirtualMethod("j2", "()V");
+  const Signature void_sig = I->GetDexCache()->GetDexFile()->CreateSignature("()V");
+  mirror::ArtMethod* Ii = I->FindVirtualMethod("i", void_sig);
+  mirror::ArtMethod* Jj1 = J->FindVirtualMethod("j1", void_sig);
+  mirror::ArtMethod* Jj2 = J->FindVirtualMethod("j2", void_sig);
+  mirror::ArtMethod* Kj1 = K->FindInterfaceMethod("j1", void_sig);
+  mirror::ArtMethod* Kj2 = K->FindInterfaceMethod("j2", void_sig);
+  mirror::ArtMethod* Kk = K->FindInterfaceMethod("k", void_sig);
+  mirror::ArtMethod* Ai = A->FindVirtualMethod("i", void_sig);
+  mirror::ArtMethod* Aj1 = A->FindVirtualMethod("j1", void_sig);
+  mirror::ArtMethod* Aj2 = A->FindVirtualMethod("j2", void_sig);
   ASSERT_TRUE(Ii != NULL);
   ASSERT_TRUE(Jj1 != NULL);
   ASSERT_TRUE(Jj2 != NULL);
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 26ce5be..189e3ed 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -265,7 +265,7 @@
 // NoSuchMethodError
 
 void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name,
-                            const StringPiece& signature) {
+                            const Signature& signature) {
   std::ostringstream msg;
   ClassHelper kh(c);
   msg << "No " << type << " method " << name << signature
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 99c6343..1d77e2d 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -27,6 +27,7 @@
 class Class;
 class Object;
 }  // namespace mirror
+class Signature;
 class StringPiece;
 class ThrowLocation;
 
@@ -140,7 +141,7 @@
 // NoSuchMethodError
 
 void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name,
-                            const StringPiece& signature)
+                            const Signature& signature)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 void ThrowNoSuchMethodError(uint32_t method_idx)
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index e57137f..ae57aa3 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1287,7 +1287,7 @@
     MethodHelper mh(m);
     expandBufAddMethodId(pReply, ToMethodId(m));
     expandBufAddUtf8String(pReply, mh.GetName());
-    expandBufAddUtf8String(pReply, mh.GetSignature());
+    expandBufAddUtf8String(pReply, mh.GetSignature().ToString());
     if (with_generic) {
       static const char genericSignature[1] = "";
       expandBufAddUtf8String(pReply, genericSignature);
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 2ee9244..c57a1e7 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -47,6 +47,10 @@
   return StringPiece(data, static_cast<int>(length));
 }
 
+inline const Signature DexFile::GetMethodSignature(const MethodId& method_id) const {
+  return Signature(this, GetProtoId(method_id.proto_idx_));
+}
+
 inline const DexFile::TryItem* DexFile::GetTryItems(const CodeItem& code_item, uint32_t offset) {
   const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_in_code_units_];
   return reinterpret_cast<const TryItem*>
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 098ab67..275dcc5 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -503,8 +503,8 @@
 }
 
 // Given a signature place the type ids into the given vector
-bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector<uint16_t>* param_type_idxs,
-                             const std::string& signature) const {
+bool DexFile::CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx,
+                             std::vector<uint16_t>* param_type_idxs) const {
   if (signature[0] != '(') {
     return false;
   }
@@ -518,6 +518,7 @@
       process_return = true;
       continue;
     }
+    // TODO: avoid building a string.
     std::string descriptor;
     descriptor += c;
     while (c == '[') {  // process array prefix
@@ -557,35 +558,18 @@
   return false;  // failed to correctly parse return type
 }
 
-// Materializes the method descriptor for a method prototype.  Method
-// descriptors are not stored directly in the dex file.  Instead, one
-// must assemble the descriptor from references in the prototype.
-std::string DexFile::CreateMethodSignature(uint32_t proto_idx, int32_t* unicode_length) const {
-  const ProtoId& proto_id = GetProtoId(proto_idx);
-  std::string descriptor;
-  descriptor.push_back('(');
-  const TypeList* type_list = GetProtoParameters(proto_id);
-  size_t parameter_length = 0;
-  if (type_list != NULL) {
-    // A non-zero number of arguments.  Append the type names.
-    for (size_t i = 0; i < type_list->Size(); ++i) {
-      const TypeItem& type_item = type_list->GetTypeItem(i);
-      uint32_t type_idx = type_item.type_idx_;
-      uint32_t type_length;
-      const char* name = StringByTypeIdx(type_idx, &type_length);
-      parameter_length += type_length;
-      descriptor.append(name);
-    }
+const Signature DexFile::CreateSignature(const StringPiece& signature) const {
+  uint16_t return_type_idx;
+  std::vector<uint16_t> param_type_indices;
+  bool success = CreateTypeList(signature, &return_type_idx, &param_type_indices);
+  if (!success) {
+    return Signature::NoSignature();
   }
-  descriptor.push_back(')');
-  uint32_t return_type_idx = proto_id.return_type_idx_;
-  uint32_t return_type_length;
-  const char* name = StringByTypeIdx(return_type_idx, &return_type_length);
-  descriptor.append(name);
-  if (unicode_length != NULL) {
-    *unicode_length = parameter_length + return_type_length + 2;  // 2 for ( and )
+  const ProtoId* proto_id = FindProtoId(return_type_idx, param_type_indices);
+  if (proto_id == NULL) {
+    return Signature::NoSignature();
   }
-  return descriptor;
+  return Signature(this, *proto_id);
 }
 
 int32_t DexFile::GetLineNumFromPC(const mirror::ArtMethod* method, uint32_t rel_pc) const {
@@ -831,6 +815,30 @@
   }
 }
 
+std::string Signature::ToString() const {
+  if (dex_file_ == nullptr) {
+    CHECK(proto_id_ == nullptr);
+    return "<no signature>";
+  }
+  const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_);
+  std::string result;
+  if (params == nullptr) {
+    result += "()";
+  } else {
+    result += "(";
+    for (uint32_t i = 0; i < params->Size(); ++i) {
+      result += dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_);
+    }
+    result += ")";
+  }
+  result += dex_file_->StringByTypeIdx(proto_id_->return_type_idx_);
+  return result;
+}
+
+std::ostream& operator<<(std::ostream& os, const Signature& sig) {
+  return os << sig.ToString();
+}
+
 // Decodes the header section from the class data bytes.
 void ClassDataItemIterator::ReadClassDataHeader() {
   CHECK(ptr_pos_ != NULL);
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 4534b41..40e4c72 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -40,6 +40,7 @@
   class DexCache;
 }  // namespace mirror
 class ClassLinker;
+class Signature;
 class StringPiece;
 class ZipArchive;
 
@@ -559,10 +560,8 @@
     return GetProtoId(method_id.proto_idx_);
   }
 
-  // Returns the signature of a method id.
-  const std::string GetMethodSignature(const MethodId& method_id) const {
-    return CreateMethodSignature(method_id.proto_idx_, NULL);
-  }
+  // Returns a representation of the signature of a method id.
+  const Signature GetMethodSignature(const MethodId& method_id) const;
 
   // Returns the name of a method id.
   const char* GetMethodName(const MethodId& method_id) const {
@@ -656,15 +655,16 @@
   }
 
   // Looks up a proto id for a given return type and signature type list
-  const ProtoId* FindProtoId(uint16_t return_type_id,
+  const ProtoId* FindProtoId(uint16_t return_type_idx,
                              const std::vector<uint16_t>& signature_type_idxs_) const;
 
   // Given a signature place the type ids into the given vector, returns true on success
-  bool CreateTypeList(uint16_t* return_type_idx, std::vector<uint16_t>* param_type_idxs,
-                      const std::string& signature) const;
+  bool CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx,
+                      std::vector<uint16_t>* param_type_idxs) const;
 
-  // Given a proto_idx decode the type list and return type into a method signature
-  std::string CreateMethodSignature(uint32_t proto_idx, int32_t* unicode_length) const;
+  // Create a Signature from the given string signature or return Signature::NoSignature if not
+  // possible.
+  const Signature CreateSignature(const StringPiece& signature) const;
 
   // Returns the short form method descriptor for the given prototype.
   const char* GetShorty(uint32_t proto_idx) const {
@@ -942,6 +942,83 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(DexFileParameterIterator);
 };
 
+// Abstract the signature of a method.
+class Signature {
+ public:
+  std::string ToString() const;
+
+  static Signature NoSignature() {
+    return Signature();
+  }
+
+  bool operator==(const Signature& rhs) const {
+    if (dex_file_ == nullptr) {
+      return rhs.dex_file_ == nullptr;
+    }
+    if (rhs.dex_file_ == nullptr) {
+      return false;
+    }
+    if (dex_file_ == rhs.dex_file_) {
+      return proto_id_ == rhs.proto_id_;
+    }
+    StringPiece shorty(dex_file_->StringDataAsStringPieceByIdx(proto_id_->shorty_idx_));
+    if (shorty != rhs.dex_file_->StringDataAsStringPieceByIdx(rhs.proto_id_->shorty_idx_)) {
+      return false;  // Shorty mismatch.
+    }
+    if (shorty[0] == 'L') {
+      const DexFile::TypeId& return_type_id = dex_file_->GetTypeId(proto_id_->return_type_idx_);
+      const DexFile::TypeId& rhs_return_type_id =
+          rhs.dex_file_->GetTypeId(rhs.proto_id_->return_type_idx_);
+      if (dex_file_->StringDataAsStringPieceByIdx(return_type_id.descriptor_idx_) !=
+          rhs.dex_file_->StringDataAsStringPieceByIdx(rhs_return_type_id.descriptor_idx_)) {
+        return false;  // Return type mismatch.
+      }
+    }
+    if (shorty.find('L', 1) != StringPiece::npos) {
+      const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_);
+      const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_);
+      // Both lists are empty or have contents, or else shorty is broken.
+      DCHECK_EQ(params == nullptr, rhs_params == nullptr);
+      if (params != nullptr) {
+        uint32_t params_size = params->Size();
+        DCHECK_EQ(params_size, rhs_params->Size());  // Parameter list size must match.
+        for (uint32_t i = 0; i < params_size; ++i) {
+          const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_);
+          const DexFile::TypeId& rhs_param_id =
+              rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_);
+          if (dex_file_->StringDataAsStringPieceByIdx(param_id.descriptor_idx_) !=
+              rhs.dex_file_->StringDataAsStringPieceByIdx(rhs_param_id.descriptor_idx_)) {
+            return false;  // Parameter type mismatch.
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+  bool operator!=(const Signature& rhs) const {
+    return !(*this == rhs);
+  }
+
+  bool operator==(const StringPiece& rhs) const {
+    // TODO: Avoid temporary string allocation.
+    return ToString() == rhs;
+  }
+
+ private:
+  Signature(const DexFile* dex, const DexFile::ProtoId& proto) : dex_file_(dex), proto_id_(&proto) {
+  }
+
+  Signature() : dex_file_(nullptr), proto_id_(nullptr) {
+  }
+
+  friend class DexFile;
+
+  const DexFile* const dex_file_;
+  const DexFile::ProtoId* const proto_id_;
+};
+std::ostream& operator<<(std::ostream& os, const Signature& sig);
+
 // Iterate and decode class_data_item
 class ClassDataItemIterator {
  public:
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 32a8354..1b40529 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -137,14 +137,14 @@
   EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1));
 }
 
-TEST_F(DexFileTest, CreateMethodSignature) {
+TEST_F(DexFileTest, GetMethodSignature) {
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* raw(OpenTestDexFile("CreateMethodSignature"));
+  const DexFile* raw(OpenTestDexFile("GetMethodSignature"));
   ASSERT_TRUE(raw != NULL);
   EXPECT_EQ(1U, raw->NumClassDefs());
 
   const DexFile::ClassDef& class_def = raw->GetClassDef(0);
-  ASSERT_STREQ("LCreateMethodSignature;", raw->GetClassDescriptor(class_def));
+  ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
 
   const byte* class_data = raw->GetClassData(class_def);
   ASSERT_TRUE(class_data != NULL);
@@ -156,11 +156,9 @@
   {
     ASSERT_EQ(1U, it.NumDirectMethods());
     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
-    uint32_t proto_idx = method_id.proto_idx_;
     const char* name = raw->StringDataByIdx(method_id.name_idx_);
     ASSERT_STREQ("<init>", name);
-    int32_t length;
-    std::string signature(raw->CreateMethodSignature(proto_idx, &length));
+    std::string signature(raw->GetMethodSignature(method_id).ToString());
     ASSERT_EQ("()V", signature);
   }
 
@@ -173,9 +171,7 @@
     const char* name = raw->StringDataByIdx(method_id.name_idx_);
     ASSERT_STREQ("m1", name);
 
-    uint32_t proto_idx = method_id.proto_idx_;
-    int32_t length;
-    std::string signature(raw->CreateMethodSignature(proto_idx, &length));
+    std::string signature(raw->GetMethodSignature(method_id).ToString());
     ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature);
   }
 
@@ -186,20 +182,18 @@
     const char* name = raw->StringDataByIdx(method_id.name_idx_);
     ASSERT_STREQ("m2", name);
 
-    uint32_t proto_idx = method_id.proto_idx_;
-    int32_t length;
-    std::string signature(raw->CreateMethodSignature(proto_idx, &length));
-    ASSERT_EQ("(ZSC)LCreateMethodSignature;", signature);
+    std::string signature(raw->GetMethodSignature(method_id).ToString());
+    ASSERT_EQ("(ZSC)LGetMethodSignature;", signature);
   }
 }
 
 TEST_F(DexFileTest, FindStringId) {
   ScopedObjectAccess soa(Thread::Current());
-  const DexFile* raw(OpenTestDexFile("CreateMethodSignature"));
+  const DexFile* raw(OpenTestDexFile("GetMethodSignature"));
   ASSERT_TRUE(raw != NULL);
   EXPECT_EQ(1U, raw->NumClassDefs());
 
-  const char* strings[] = { "LCreateMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
+  const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
       "D", "I", "J", NULL };
   for (size_t i = 0; strings[i] != NULL; i++) {
     const char* str = strings[i];
@@ -245,11 +239,10 @@
     const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
     const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
     const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature);
-    int32_t length;
     ASSERT_TRUE(found != NULL) << "Didn't find method " << i << ": "
         << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
         << java_lang_dex_file_->GetStringData(name)
-        << java_lang_dex_file_->CreateMethodSignature(to_find.proto_idx_, &length);
+        << java_lang_dex_file_->GetMethodSignature(to_find);
     EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i);
   }
 }
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 60fad6e..8be9b21 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -228,6 +228,7 @@
                               const char* name, const char* sig, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Class* c = soa.Decode<Class*>(jni_class);
+  DCHECK(c != nullptr);
   if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
     return NULL;
   }
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 287e8b0..c6db5b9 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -325,7 +325,7 @@
   SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
 }
 
-ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const StringPiece& signature) const {
+ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) const {
   // Check the current class before checking the interfaces.
   ArtMethod* method = FindDeclaredVirtualMethod(name, signature);
   if (method != NULL) {
@@ -361,12 +361,23 @@
   return NULL;
 }
 
-
 ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const {
   MethodHelper mh;
   for (size_t i = 0; i < NumDirectMethods(); ++i) {
     ArtMethod* method = GetDirectMethod(i);
     mh.ChangeMethod(method);
+    if (name == mh.GetNameAsStringPiece() && mh.GetSignature() == signature) {
+      return method;
+    }
+  }
+  return NULL;
+}
+
+ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) const {
+  MethodHelper mh;
+  for (size_t i = 0; i < NumDirectMethods(); ++i) {
+    ArtMethod* method = GetDirectMethod(i);
+    mh.ChangeMethod(method);
     if (name == mh.GetNameAsStringPiece() && signature == mh.GetSignature()) {
       return method;
     }
@@ -396,6 +407,16 @@
   return NULL;
 }
 
+ArtMethod* Class::FindDirectMethod(const StringPiece& name, const Signature& signature) const {
+  for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+    ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature);
+    if (method != NULL) {
+      return method;
+    }
+  }
+  return NULL;
+}
+
 ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const {
   for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
     ArtMethod* method = klass->FindDeclaredDirectMethod(dex_cache, dex_method_idx);
@@ -406,8 +427,20 @@
   return NULL;
 }
 
+ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const {
+  MethodHelper mh;
+  for (size_t i = 0; i < NumVirtualMethods(); ++i) {
+    ArtMethod* method = GetVirtualMethod(i);
+    mh.ChangeMethod(method);
+    if (name == mh.GetNameAsStringPiece() && mh.GetSignature() == signature) {
+      return method;
+    }
+  }
+  return NULL;
+}
+
 ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name,
-                                         const StringPiece& signature) const {
+                                            const Signature& signature) const {
   MethodHelper mh;
   for (size_t i = 0; i < NumVirtualMethods(); ++i) {
     ArtMethod* method = GetVirtualMethod(i);
@@ -441,6 +474,16 @@
   return NULL;
 }
 
+ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const Signature& signature) const {
+  for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+    ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature);
+    if (method != NULL) {
+      return method;
+    }
+  }
+  return NULL;
+}
+
 ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const {
   for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
     ArtMethod* method = klass->FindDeclaredVirtualMethod(dex_cache, dex_method_idx);
@@ -451,6 +494,21 @@
   return NULL;
 }
 
+ArtMethod* Class::FindClassInitializer() const {
+  for (size_t i = 0; i < NumDirectMethods(); ++i) {
+    ArtMethod* method = GetDirectMethod(i);
+    if (method->IsConstructor() && method->IsStatic()) {
+      if (kIsDebugBuild) {
+        MethodHelper mh(method);
+        CHECK_STREQ(mh.GetName(), "<clinit>");
+        CHECK_STREQ(mh.GetSignature().ToString().c_str(), "()V");
+      }
+      return method;
+    }
+  }
+  return NULL;
+}
+
 ArtField* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type) {
   // Is the field in this class?
   // Interfaces are not relevant because they can't contain instance fields.
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 4f8ab7d..586151d 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -59,6 +59,7 @@
 
 struct ClassClassOffsets;
 struct ClassOffsets;
+class Signature;
 class StringPiece;
 
 namespace mirror {
@@ -565,39 +566,53 @@
   ArtMethod* FindVirtualMethodForInterface(ArtMethod* method) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
 
-  ArtMethod* FindInterfaceMethod(const StringPiece& name, const StringPiece& descriptor) const
+  ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ArtMethod* FindInterfaceMethod(const StringPiece& name, const Signature& signature) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   ArtMethod* FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  ArtMethod* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& descriptor) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  ArtMethod* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   ArtMethod* FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   ArtMethod* FindDirectMethod(const StringPiece& name, const StringPiece& signature) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  ArtMethod* FindDirectMethod(const StringPiece& name, const Signature& signature) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   ArtMethod* FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ArtMethod* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& signature) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ArtMethod* FindVirtualMethod(const StringPiece& name, const Signature& signature) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ArtMethod* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ArtMethod* FindClassInitializer() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   int32_t GetIfTableCount() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   IfTable* GetIfTable() const;
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 9e107a4..f83db90 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -504,13 +504,13 @@
     return shorty_len_;
   }
 
-  const std::string GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const Signature GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const DexFile& dex_file = GetDexFile();
     uint32_t dex_method_idx = method_->GetDexMethodIndex();
     if (dex_method_idx != DexFile::kDexNoIndex) {
       return dex_file.GetMethodSignature(dex_file.GetMethodId(dex_method_idx));
     } else {
-      return "<no signature>";
+      return Signature::NoSignature();
     }
   }
 
@@ -638,42 +638,7 @@
         other_dex_file.StringDataAsStringPieceByIdx(other_mid.name_idx_)) {
       return false;  // Name mismatch.
     }
-    const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(mid);
-    const DexFile::ProtoId& other_proto_id = other_dex_file.GetMethodPrototype(other_mid);
-    if (dex_file.StringDataAsStringPieceByIdx(proto_id.shorty_idx_) !=
-        other_dex_file.StringDataAsStringPieceByIdx(other_proto_id.shorty_idx_)) {
-      return false;  // Shorty mismatch.
-    }
-    const DexFile::TypeId& return_type_id = dex_file.GetTypeId(proto_id.return_type_idx_);
-    const DexFile::TypeId& other_return_type_id =
-        other_dex_file.GetTypeId(other_proto_id.return_type_idx_);
-    if (dex_file.StringDataAsStringPieceByIdx(return_type_id.descriptor_idx_) !=
-        other_dex_file.StringDataAsStringPieceByIdx(other_return_type_id.descriptor_idx_)) {
-      return false;  // Return type mismatch.
-    }
-    const DexFile::TypeList* params = dex_file.GetProtoParameters(proto_id);
-    const DexFile::TypeList* other_params = other_dex_file.GetProtoParameters(other_proto_id);
-    if (params == nullptr) {
-      return other_params == nullptr;  // Check both lists are empty.
-    }
-    if (other_params == nullptr) {
-      return false;  // Parameter list size mismatch.
-    }
-    uint32_t params_size = params->Size();
-    uint32_t other_params_size = other_params->Size();
-    if (params_size != other_params_size) {
-      return false;  // Parameter list size mismatch.
-    }
-    for (uint32_t i = 0; i < params_size; ++i) {
-      const DexFile::TypeId& param_id = dex_file.GetTypeId(params->GetTypeItem(i).type_idx_);
-      const DexFile::TypeId& other_param_id =
-          other_dex_file.GetTypeId(other_params->GetTypeItem(i).type_idx_);
-      if (dex_file.StringDataAsStringPieceByIdx(param_id.descriptor_idx_) !=
-          other_dex_file.StringDataAsStringPieceByIdx(other_param_id.descriptor_idx_)) {
-        return false;  // Parameter type mismatch.
-      }
-    }
-    return true;
+    return dex_file.GetMethodSignature(mid) == other_dex_file.GetMethodSignature(other_mid);
   }
 
   const DexFile::CodeItem* GetCodeItem()
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 7b25306..ec95a87 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -667,7 +667,7 @@
     mh.ChangeMethod(method);
     os << StringPrintf("%p\t%s\t%s\t%s\t%s\n", method,
         PrettyDescriptor(mh.GetDeclaringClassDescriptor()).c_str(), mh.GetName(),
-        mh.GetSignature().c_str(), mh.GetDeclaringClassSourceFile());
+        mh.GetSignature().ToString().c_str(), mh.GetDeclaringClassSourceFile());
   }
 }
 
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 23dcde3..b97239f 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -367,11 +367,13 @@
   result += '.';
   result += mh.GetName();
   if (with_signature) {
-    std::string signature(mh.GetSignature());
-    if (signature == "<no signature>") {
-      return result + signature;
+    const Signature signature = mh.GetSignature();
+    std::string sig_as_string(signature.ToString());
+    if (signature == Signature::NoSignature()) {
+      return result + sig_as_string;
     }
-    result = PrettyReturnType(signature.c_str()) + " " + result + PrettyArguments(signature.c_str());
+    result = PrettyReturnType(sig_as_string.c_str()) + " " + result +
+        PrettyArguments(sig_as_string.c_str());
   }
   return result;
 }
@@ -385,11 +387,13 @@
   result += '.';
   result += dex_file.GetMethodName(method_id);
   if (with_signature) {
-    std::string signature(dex_file.GetMethodSignature(method_id));
-    if (signature == "<no signature>") {
-      return result + signature;
+    const Signature signature = dex_file.GetMethodSignature(method_id);
+    std::string sig_as_string(signature.ToString());
+    if (signature == Signature::NoSignature()) {
+      return result + sig_as_string;
     }
-    result = PrettyReturnType(signature.c_str()) + " " + result + PrettyArguments(signature.c_str());
+    result = PrettyReturnType(sig_as_string.c_str()) + " " + result +
+        PrettyArguments(sig_as_string.c_str());
   }
   return result;
 }
@@ -641,7 +645,7 @@
   long_name += JniShortName(m);
   long_name += "__";
 
-  std::string signature(MethodHelper(m).GetSignature());
+  std::string signature(MethodHelper(m).GetSignature().ToString());
   signature.erase(0, 1);
   signature.erase(signature.begin() + signature.find(')'), signature.end());
 
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 6b13517..36b409d 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2910,7 +2910,7 @@
 }
 
 mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_method_idx,
-                                                                    MethodType method_type) {
+                                                               MethodType method_type) {
   const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx);
   const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_);
   if (klass_type.IsConflict()) {
@@ -2927,7 +2927,7 @@
   mirror::ArtMethod* res_method = dex_cache_->GetResolvedMethod(dex_method_idx);
   if (res_method == NULL) {
     const char* name = dex_file_->GetMethodName(method_id);
-    std::string signature(dex_file_->CreateMethodSignature(method_id.proto_idx_, NULL));
+    const Signature signature = dex_file_->GetMethodSignature(method_id);
 
     if (method_type == METHOD_DIRECT || method_type == METHOD_STATIC) {
       res_method = klass->FindDirectMethod(name, signature);
diff --git a/test/Android.mk b/test/Android.mk
index 6f498e8..08ec03a 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -23,8 +23,8 @@
 TEST_DEX_DIRECTORIES := \
 	AbstractMethod \
 	AllFields \
-	CreateMethodSignature \
 	ExceptionHandle \
+	GetMethodSignature \
 	Interfaces \
 	Main \
 	MyClass \
diff --git a/test/CreateMethodSignature/CreateMethodSignature.java b/test/GetMethodSignature/GetMethodSignature.java
similarity index 86%
rename from test/CreateMethodSignature/CreateMethodSignature.java
rename to test/GetMethodSignature/GetMethodSignature.java
index f6cd6ae..c2ba948 100644
--- a/test/CreateMethodSignature/CreateMethodSignature.java
+++ b/test/GetMethodSignature/GetMethodSignature.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-class CreateMethodSignature {
+class GetMethodSignature {
     Float m1(int a, double b, long c, Object d) { return null; }
-    CreateMethodSignature m2(boolean x, short y, char z) { return null; }
+    GetMethodSignature m2(boolean x, short y, char z) { return null; }
 }