Use the method descriptor for prototype and return type comparisons.

Change-Id: If2623b53e069d6f51c08849ac2798f792d465234
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 0d7c1dc..1bfa009 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -961,44 +961,6 @@
   return true;
 }
 
-bool ClassLinker::HasSameArgumentTypes(const Method* m1, const Method* m2) const {
-  const DexFile& dex1 = FindDexFile(m1->GetClass()->GetDexCache());
-  const DexFile& dex2 = FindDexFile(m2->GetClass()->GetDexCache());
-  const DexFile::ProtoId& proto1 = dex1.GetProtoId(m1->proto_idx_);
-  const DexFile::ProtoId& proto2 = dex2.GetProtoId(m2->proto_idx_);
-
-  // TODO: compare ProtoId objects for equality and exit early
-  const DexFile::TypeList* type_list1 = dex1.GetProtoParameters(proto1);
-  const DexFile::TypeList* type_list2 = dex2.GetProtoParameters(proto2);
-  size_t arity1 = (type_list1 == NULL) ? 0 : type_list1->Size();
-  size_t arity2 = (type_list2 == NULL) ? 0 : type_list2->Size();
-  if (arity1 != arity2) {
-    return false;
-  }
-
-  for (size_t i = 0; i < arity1; ++i) {
-    uint32_t type_idx1 = type_list1->GetTypeItem(i).type_idx_;
-    uint32_t type_idx2 = type_list2->GetTypeItem(i).type_idx_;
-    const char* type1 = dex1.dexStringByTypeIdx(type_idx1);
-    const char* type2 = dex2.dexStringByTypeIdx(type_idx2);
-    if (strcmp(type1, type2) != 0) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool ClassLinker::HasSameReturnType(const Method* m1, const Method* m2) const {
-  const DexFile& dex1 = FindDexFile(m1->GetClass()->GetDexCache());
-  const DexFile& dex2 = FindDexFile(m2->GetClass()->GetDexCache());
-  const DexFile::ProtoId& proto1 = dex1.GetProtoId(m1->proto_idx_);
-  const DexFile::ProtoId& proto2 = dex2.GetProtoId(m2->proto_idx_);
-  const char* type1 = dex1.dexStringByTypeIdx(proto1.return_type_idx_);
-  const char* type2 = dex2.dexStringByTypeIdx(proto2.return_type_idx_);
-  return (strcmp(type1, type2) == 0);
-}
-
 bool ClassLinker::InitializeSuperClass(Class* klass) {
   CHECK(klass != NULL);
   // TODO: assert klass lock is acquired
@@ -1195,7 +1157,7 @@
       size_t j = 0;
       for (; j < actual_count; ++j) {
         Method* super_method = klass->vtable_->Get(j);
-        if (HasSameNameAndPrototype(local_method, super_method)) {
+        if (local_method->HasSameNameAndDescriptor(super_method)) {
           // Verify
           if (super_method->IsFinal()) {
             LG << "Method overrides final method";  // TODO: VirtualMachineError
@@ -1303,8 +1265,9 @@
       Method* interface_method = interface->GetVirtualMethod(j);
       int k;  // must be signed
       for (k = klass->vtable_->GetLength() - 1; k >= 0; --k) {
-        if (HasSameNameAndPrototype(interface_method, klass->vtable_->Get(k))) {
-          if (!klass->vtable_->Get(k)->IsPublic()) {
+        Method* vtable_method = klass->vtable_->Get(k);
+        if (interface_method->HasSameNameAndDescriptor(vtable_method)) {
+          if (!vtable_method->IsPublic()) {
             LG << "Implementation not public";
             return false;
           }
@@ -1323,7 +1286,8 @@
         }
         int mir;
         for (mir = 0; mir < miranda_count; mir++) {
-          if (HasSameNameAndPrototype(miranda_list[mir], interface_method)) {
+          Method* miranda_method = miranda_list[mir];
+          if (miranda_method->HasSameNameAndDescriptor(interface_method)) {
             break;
           }
         }
diff --git a/src/class_linker.h b/src/class_linker.h
index 013196b..70d268d 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -122,22 +122,6 @@
                                       const Class* klass1,
                                       const Class* klass2);
 
-  bool HasSameNameAndPrototype(const Method* m1, const Method* m2) const {
-    return HasSameName(m1, m2) && HasSamePrototype(m1, m2);
-  }
-
-  bool HasSameName(const Method* m1, const Method* m2) const {
-    return String::Equals(m1->GetName(), m2->GetName());
-  }
-
-  bool HasSamePrototype(const Method* m1, const Method* m2) const {
-    return HasSameReturnType(m1, m2) && HasSameArgumentTypes(m1, m2);
-  }
-
-  bool HasSameReturnType(const Method* m1, const Method* m2) const;
-
-  bool HasSameArgumentTypes(const Method* m1, const Method* m2) const;
-
   bool LinkClass(Class* klass, const DexFile& dex_file);
 
   bool LinkSuperClass(Class* klass);
@@ -211,8 +195,6 @@
   bool init_done_;
 
   friend class RuntimeTest;
-  FRIEND_TEST(ClassLinkerTest, ProtoCompare);
-  FRIEND_TEST(ClassLinkerTest, ProtoCompare2);
   FRIEND_TEST(DexCacheTest, Open);
   friend class ObjectTest;
   FRIEND_TEST(ObjectTest, AllocObjectArray);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index d521183..a9c3e50 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -103,7 +103,7 @@
     if (klass->IsInterface()) {
       EXPECT_TRUE(klass->IsAbstract());
       if (klass->NumDirectMethods() == 1) {
-        EXPECT_PRED2(String::EqualsUtf8, klass->GetDirectMethod(0)->GetName(), "<clinit>");
+        EXPECT_TRUE(klass->GetDirectMethod(0)->GetName()->Equals("<clinit>"));
       } else {
         EXPECT_EQ(0U, klass->NumDirectMethods());
       }
@@ -298,104 +298,6 @@
   AssertNonExistantClass("[[[[LNonExistantClass;");
 }
 
-TEST_F(ClassLinkerTest, ProtoCompare) {
-  ClassLinker* linker = class_linker_;
-
-  scoped_ptr<DexFile> dex(OpenDexFileBase64(kProtoCompareDex));
-  PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
-  Class* klass = linker->FindClass("LProtoCompare;", class_loader);
-  ASSERT_TRUE(klass != NULL);
-
-  ASSERT_EQ(4U, klass->NumVirtualMethods());
-
-  Method* m1 = klass->GetVirtualMethod(0);
-  EXPECT_PRED2(String::EqualsUtf8, m1->GetName(), "m1");
-
-  Method* m2 = klass->GetVirtualMethod(1);
-  EXPECT_PRED2(String::EqualsUtf8, m2->GetName(), "m2");
-
-  Method* m3 = klass->GetVirtualMethod(2);
-  EXPECT_PRED2(String::EqualsUtf8, m3->GetName(), "m3");
-
-  Method* m4 = klass->GetVirtualMethod(3);
-  EXPECT_PRED2(String::EqualsUtf8, m4->GetName(), "m4");
-
-  EXPECT_TRUE(linker->HasSameReturnType(m1, m2));
-  EXPECT_TRUE(linker->HasSameReturnType(m2, m1));
-
-  EXPECT_TRUE(linker->HasSameReturnType(m1, m2));
-  EXPECT_TRUE(linker->HasSameReturnType(m2, m1));
-
-  EXPECT_FALSE(linker->HasSameReturnType(m1, m4));
-  EXPECT_FALSE(linker->HasSameReturnType(m4, m1));
-
-  EXPECT_TRUE(linker->HasSameArgumentTypes(m1, m2));
-  EXPECT_TRUE(linker->HasSameArgumentTypes(m2, m1));
-
-  EXPECT_FALSE(linker->HasSameArgumentTypes(m1, m3));
-  EXPECT_FALSE(linker->HasSameArgumentTypes(m3, m1));
-
-  EXPECT_FALSE(linker->HasSameArgumentTypes(m1, m4));
-  EXPECT_FALSE(linker->HasSameArgumentTypes(m4, m1));
-
-  EXPECT_TRUE(linker->HasSamePrototype(m1, m2));
-  EXPECT_TRUE(linker->HasSamePrototype(m2, m1));
-
-  EXPECT_FALSE(linker->HasSamePrototype(m1, m3));
-  EXPECT_FALSE(linker->HasSamePrototype(m3, m1));
-
-  EXPECT_FALSE(linker->HasSamePrototype(m3, m4));
-  EXPECT_FALSE(linker->HasSamePrototype(m4, m3));
-
-  EXPECT_FALSE(linker->HasSameName(m1, m2));
-  EXPECT_FALSE(linker->HasSameNameAndPrototype(m1, m2));
-}
-
-TEST_F(ClassLinkerTest, ProtoCompare2) {
-  ClassLinker* linker = class_linker_;
-
-  scoped_ptr<DexFile> proto1_dex_file(OpenDexFileBase64(kProtoCompareDex));
-  PathClassLoader* class_loader_1 = AllocPathClassLoader(proto1_dex_file.get());
-  scoped_ptr<DexFile> proto2_dex_file(OpenDexFileBase64(kProtoCompare2Dex));
-  PathClassLoader* class_loader_2 = AllocPathClassLoader(proto2_dex_file.get());
-
-  Class* klass1 = linker->FindClass("LProtoCompare;", class_loader_1);
-  ASSERT_TRUE(klass1 != NULL);
-  Class* klass2 = linker->FindClass("LProtoCompare2;", class_loader_2);
-  ASSERT_TRUE(klass2 != NULL);
-
-  Method* m1_1 = klass1->GetVirtualMethod(0);
-  EXPECT_PRED2(String::EqualsUtf8, m1_1->GetName(), "m1");
-  Method* m2_1 = klass1->GetVirtualMethod(1);
-  EXPECT_PRED2(String::EqualsUtf8, m2_1->GetName(), "m2");
-  Method* m3_1 = klass1->GetVirtualMethod(2);
-  EXPECT_PRED2(String::EqualsUtf8, m3_1->GetName(), "m3");
-  Method* m4_1 = klass1->GetVirtualMethod(3);
-  EXPECT_PRED2(String::EqualsUtf8, m4_1->GetName(), "m4");
-
-  Method* m1_2 = klass2->GetVirtualMethod(0);
-  EXPECT_PRED2(String::EqualsUtf8, m1_2->GetName(), "m1");
-  Method* m2_2 = klass2->GetVirtualMethod(1);
-  EXPECT_PRED2(String::EqualsUtf8, m2_2->GetName(), "m2");
-  Method* m3_2 = klass2->GetVirtualMethod(2);
-  EXPECT_PRED2(String::EqualsUtf8, m3_2->GetName(), "m3");
-  Method* m4_2 = klass2->GetVirtualMethod(3);
-  EXPECT_PRED2(String::EqualsUtf8, m4_2->GetName(), "m4");
-
-  EXPECT_TRUE(linker->HasSameNameAndPrototype(m1_1, m1_2));
-  EXPECT_TRUE(linker->HasSameNameAndPrototype(m1_2, m1_1));
-
-  EXPECT_TRUE(linker->HasSameNameAndPrototype(m2_1, m2_2));
-  EXPECT_TRUE(linker->HasSameNameAndPrototype(m2_2, m2_1));
-
-  EXPECT_TRUE(linker->HasSameNameAndPrototype(m3_1, m3_2));
-  EXPECT_TRUE(linker->HasSameNameAndPrototype(m3_2, m3_1));
-
-  EXPECT_TRUE(linker->HasSameNameAndPrototype(m4_1, m4_2));
-  EXPECT_TRUE(linker->HasSameNameAndPrototype(m4_2, m4_1));
-}
-
 TEST_F(ClassLinkerTest, LibCore) {
   UseLibCoreDex();
   scoped_ptr<DexFile> libcore_dex_file(GetLibCoreDex());
@@ -410,47 +312,47 @@
   UseLibCoreDex();
   Class* string = class_linker_->FindSystemClass( "Ljava/lang/String;");
   ASSERT_EQ(4U, string->NumInstanceFields());
-  EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(0)->GetName(), "value");
-  EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(1)->GetName(), "hashCode");
-  EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(2)->GetName(), "offset");
-  EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(3)->GetName(), "count");
+  EXPECT_TRUE(string->GetInstanceField(0)->GetName()->Equals("value"));
+  EXPECT_TRUE(string->GetInstanceField(1)->GetName()->Equals("hashCode"));
+  EXPECT_TRUE(string->GetInstanceField(2)->GetName()->Equals("offset"));
+  EXPECT_TRUE(string->GetInstanceField(3)->GetName()->Equals("count"));
 
   Class* accessible_object = class_linker_->FindSystemClass("Ljava/lang/reflect/AccessibleObject;");
   ASSERT_EQ(1U, accessible_object->NumInstanceFields());
-  EXPECT_PRED2(String::EqualsUtf8, accessible_object->GetInstanceField(0)->GetName(), "flag");
+  EXPECT_TRUE(accessible_object->GetInstanceField(0)->GetName()->Equals("flag"));
 
   Class* field = class_linker_->FindSystemClass("Ljava/lang/reflect/Field;");
   ASSERT_EQ(6U, field->NumInstanceFields());
-  EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(0)->GetName(), "declaringClass");
-  EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(1)->GetName(), "genericType");
-  EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(2)->GetName(), "type");
-  EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(3)->GetName(), "name");
-  EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(4)->GetName(), "slot");
-  EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(5)->GetName(), "genericTypesAreInitialized");
+  EXPECT_TRUE(field->GetInstanceField(0)->GetName()->Equals("declaringClass"));
+  EXPECT_TRUE(field->GetInstanceField(1)->GetName()->Equals("genericType"));
+  EXPECT_TRUE(field->GetInstanceField(2)->GetName()->Equals("type"));
+  EXPECT_TRUE(field->GetInstanceField(3)->GetName()->Equals("name"));
+  EXPECT_TRUE(field->GetInstanceField(4)->GetName()->Equals("slot"));
+  EXPECT_TRUE(field->GetInstanceField(5)->GetName()->Equals("genericTypesAreInitialized"));
 
   Class* method = class_linker_->FindSystemClass("Ljava/lang/reflect/Method;");
   ASSERT_EQ(11U, method->NumInstanceFields());
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 0)->GetName(), "declaringClass");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 1)->GetName(), "exceptionTypes");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 2)->GetName(), "formalTypeParameters");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 3)->GetName(), "genericExceptionTypes");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 4)->GetName(), "genericParameterTypes");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 5)->GetName(), "genericReturnType");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 6)->GetName(), "returnType");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 7)->GetName(), "name");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 8)->GetName(), "parameterTypes");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 9)->GetName(), "genericTypesAreInitialized");
-  EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField(10)->GetName(), "slot");
+  EXPECT_TRUE(method->GetInstanceField( 0)->GetName()->Equals("declaringClass"));
+  EXPECT_TRUE(method->GetInstanceField( 1)->GetName()->Equals("exceptionTypes"));
+  EXPECT_TRUE(method->GetInstanceField( 2)->GetName()->Equals("formalTypeParameters"));
+  EXPECT_TRUE(method->GetInstanceField( 3)->GetName()->Equals("genericExceptionTypes"));
+  EXPECT_TRUE(method->GetInstanceField( 4)->GetName()->Equals("genericParameterTypes"));
+  EXPECT_TRUE(method->GetInstanceField( 5)->GetName()->Equals("genericReturnType"));
+  EXPECT_TRUE(method->GetInstanceField( 6)->GetName()->Equals("returnType"));
+  EXPECT_TRUE(method->GetInstanceField( 7)->GetName()->Equals("name"));
+  EXPECT_TRUE(method->GetInstanceField( 8)->GetName()->Equals("parameterTypes"));
+  EXPECT_TRUE(method->GetInstanceField( 9)->GetName()->Equals("genericTypesAreInitialized"));
+  EXPECT_TRUE(method->GetInstanceField(10)->GetName()->Equals("slot"));
 
   Class* class_loader = class_linker_->FindSystemClass("Ljava/lang/ClassLoader;");
   ASSERT_EQ(2U, class_loader->NumInstanceFields());
-  EXPECT_PRED2(String::EqualsUtf8, class_loader->GetInstanceField(0)->GetName(), "packages");
-  EXPECT_PRED2(String::EqualsUtf8, class_loader->GetInstanceField(1)->GetName(), "parent");
+  EXPECT_TRUE(class_loader->GetInstanceField(0)->GetName()->Equals("packages"));
+  EXPECT_TRUE(class_loader->GetInstanceField(1)->GetName()->Equals("parent"));
 
   Class* dex_base_class_loader = class_linker_->FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
   ASSERT_EQ(2U, dex_base_class_loader->NumInstanceFields());
-  EXPECT_PRED2(String::EqualsUtf8, dex_base_class_loader->GetInstanceField(0)->GetName(), "originalPath");
-  EXPECT_PRED2(String::EqualsUtf8, dex_base_class_loader->GetInstanceField(1)->GetName(), "pathList");
+  EXPECT_TRUE(dex_base_class_loader->GetInstanceField(0)->GetName()->Equals("originalPath"));
+  EXPECT_TRUE(dex_base_class_loader->GetInstanceField(1)->GetName()->Equals("pathList"));
 }
 
 TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 79806f6..7677a7a 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -508,7 +508,7 @@
 
 int gSuspendCounterHandler_calls;
 void SuspendCountHandler(Method** frame) {
-  EXPECT_PRED2(String::EqualsUtf8, (*frame)->GetName(), "fooI");
+  EXPECT_TRUE((*frame)->GetName()->Equals("fooI"));
   gSuspendCounterHandler_calls++;
   Thread::Current()->DecrementSuspendCount();
 }
@@ -553,7 +553,7 @@
 
 int gExceptionHandler_calls;
 void ExceptionHandler(Method** frame) {
-  EXPECT_PRED2(String::EqualsUtf8, (*frame)->GetName(), "foo");
+  EXPECT_TRUE((*frame)->GetName()->Equals("foo"));
   gExceptionHandler_calls++;
   Thread::Current()->ClearException();
 }
diff --git a/src/object.cc b/src/object.cc
index 98b6e43..2369954 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -157,12 +157,17 @@
   return ShortyCharToSize(shorty_[0]);
 }
 
+bool Method::HasSameNameAndDescriptor(const Method* that) const {
+  return (this->GetName()->Equals(that->GetName()) &&
+          this->GetDescriptor()->Equals(that->GetDescriptor()));
+}
+
 Method* Class::FindDeclaredDirectMethod(const StringPiece& name,
                                         const StringPiece& descriptor) {
   for (size_t i = 0; i < NumDirectMethods(); ++i) {
     Method* method = GetDirectMethod(i);
-    if (String::EqualsUtf8(method->GetName(), name.data()) &&
-        String::EqualsUtf8(method->GetDescriptor(), descriptor.data())) {
+    if (method->GetName()->Equals(name) &&
+        method->GetDescriptor()->Equals(descriptor)) {
       return method;
     }
   }
@@ -184,8 +189,8 @@
                                          const StringPiece& descriptor) {
   for (size_t i = 0; i < NumVirtualMethods(); ++i) {
     Method* method = GetVirtualMethod(i);
-    if (String::EqualsUtf8(method->GetName(), name.data()) &&
-        String::EqualsUtf8(method->GetDescriptor(), descriptor.data())) {
+    if (method->GetName()->Equals(name) &&
+        method->GetDescriptor()->Equals(descriptor)) {
       return method;
     }
   }
diff --git a/src/object.h b/src/object.h
index d0f4a63..0e0728d 100644
--- a/src/object.h
+++ b/src/object.h
@@ -395,11 +395,6 @@
     return MemberOffset(OFFSETOF_MEMBER(Method, klass_));
   }
 
-  // const char* GetReturnTypeDescriptor() const {
-  //   return FindDexFile(declaring_class_->GetDexCache()
-  //          ->dexStringByTypeIdx(proto_id_.return_type_id_);
-  // }
-
   // Returns true if the method is declared public.
   bool IsPublic() const {
     return (access_flags_ & kAccPublic) != 0;
@@ -525,6 +520,8 @@
     return MemberOffset(OFFSETOF_MEMBER(Method, native_method_));
   }
 
+  bool HasSameNameAndDescriptor(const Method* that) const;
+
  public:  // TODO: private/const
   // the class we are a part of
   Class* declaring_class_;
@@ -1110,6 +1107,26 @@
 
 class String : public Object {
  public:
+  const CharArray* GetCharArray() const {
+    return array_;
+  }
+
+  uint32_t GetHashCode() const {
+    return hash_code_;
+  }
+
+  uint32_t GetOffset() const {
+    return offset_;
+  }
+
+  uint32_t GetLength() const {
+    return count_;
+  }
+
+  uint16_t CharAt(uint32_t index) const {
+    return GetCharArray()->GetChar(index + GetOffset());
+  }
+
   static String* AllocFromUtf16(Class* java_lang_String,
                                 Class* char_array,
                                 int32_t utf16_length,
@@ -1151,16 +1168,6 @@
     return AllocFromModifiedUtf8(java_lang_String_, char_array_, utf16_length, utf8_data_in);
   }
 
- public: // TODO: private
-  // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
-  CharArray* array_;
-
-  int32_t hash_code_;
-
-  int32_t offset_;
-
-  int32_t count_;
-
   static void InitClasses(Class* java_lang_String, Class* char_array);
 
   static String* Alloc(Class* java_lang_String,
@@ -1251,29 +1258,27 @@
     return hash;
   }
 
-  static bool EqualsUtf8(const String* string, const char* other) {
-    uint16_t* chars = string->array_->GetChars();
-    for (int32_t i = 0; i < string->count_; i++) {
-      uint16_t c = GetUtf16FromUtf8(&other);
-      if (c == '\0' || c != chars[string->offset_ + i]) {
+  bool Equals(const char* modified_utf8) const {
+    for (size_t i = 0; i < GetLength(); ++i) {
+      uint16_t ch = GetUtf16FromUtf8(&modified_utf8);
+      if (ch == '\0' || ch != CharAt(i)) {
         return false;
       }
     }
-    return *other == '\0';
+    return *modified_utf8 == '\0';
   }
 
-  static bool Equals(const String* a, const String* b) {
-    // TODO short circuit on hash_code_
-    int32_t a_count = a->count_;
-    if (a_count != b->count_) {
+  bool Equals(const StringPiece& modified_utf8) const {
+    // TODO: do not assume C-string representation.
+    return Equals(modified_utf8.data());
+  }
+
+  bool Equals(const String* that) const {
+    if (this->GetLength() != that->GetLength()) {
       return false;
     }
-    int32_t a_offset = a->offset_;
-    int32_t b_offset = b->offset_;
-    uint16_t* a_chars = a->array_->GetChars();
-    uint16_t* b_chars = b->array_->GetChars();
-    for (int32_t i = 0; i < a_count; i++) {
-      if (a_chars[a_offset + i] != b_chars[b_offset + i]) {
+    for (size_t i = 0; i < that->GetLength(); ++i) {
+      if (this->CharAt(i) != that->CharAt(i)) {
         return false;
       }
     }
@@ -1281,10 +1286,19 @@
   }
 
  private:
-  String();
+  // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+  CharArray* array_;
+
+  uint32_t hash_code_;
+
+  uint32_t offset_;
+
+  uint32_t count_;
 
   static Class* java_lang_String_;
   static Class* char_array_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(String);
 };
 
 class InterfaceEntry {
diff --git a/src/object_test.cc b/src/object_test.cc
index d240d0c..18e8e77 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -19,7 +19,7 @@
   void AssertString(size_t length,
                     const char* utf8_in,
                     const char* utf16_expected_le,
-                    int32_t hash_expected) {
+                    uint32_t hash_expected) {
     uint16_t utf16_expected[length];
     for (size_t i = 0; i < length; i++) {
       uint16_t ch = (((utf16_expected_le[i*2 + 0] & 0xff) << 8) |
@@ -28,15 +28,15 @@
     }
 
     String* string = String::AllocFromModifiedUtf8(length, utf8_in);
-    ASSERT_EQ(length,  static_cast<size_t>(string->count_));
-    ASSERT_TRUE(string->array_ != NULL);
-    ASSERT_TRUE(string->array_->GetChars() != NULL);
+    ASSERT_EQ(length, string->GetLength());
+    ASSERT_TRUE(string->GetCharArray() != NULL);
+    ASSERT_TRUE(string->GetCharArray()->GetChars() != NULL);
     // strlen is necessary because the 1-character string "\0" is interpreted as ""
-    ASSERT_TRUE(String::EqualsUtf8(string, utf8_in) || length != strlen(utf8_in));
+    ASSERT_TRUE(string->Equals(utf8_in) || length != strlen(utf8_in));
     for (size_t i = 0; i < length; i++) {
-      EXPECT_EQ(utf16_expected[i], string->array_->GetChar(i));
+      EXPECT_EQ(utf16_expected[i], string->GetCharArray()->GetChar(i));
     }
-    EXPECT_EQ(hash_expected, string->hash_code_);
+    EXPECT_EQ(hash_expected, string->GetHashCode());
   }
 };
 
@@ -90,40 +90,76 @@
   AssertString(3, "h\xe1\x88\xb4i", "\x00\x68\x12\x34\x00\x69", (31 * ((31 * 0x68) + 0x1234)) + 0x69);
 }
 
-static bool StringNotEqualsUtf8(const String* a, const char* b) {
-  return !String::EqualsUtf8(a, b);
-}
-
 TEST_F(ObjectTest, StringEqualsUtf8) {
   String* string = String::AllocFromAscii("android");
-  EXPECT_PRED2(String::EqualsUtf8, string, "android");
-  EXPECT_PRED2(StringNotEqualsUtf8, string, "Android");
-  EXPECT_PRED2(StringNotEqualsUtf8, string, "ANDROID");
-  EXPECT_PRED2(StringNotEqualsUtf8, string, "");
-  EXPECT_PRED2(StringNotEqualsUtf8, string, "and");
-  EXPECT_PRED2(StringNotEqualsUtf8, string, "androids");
+  EXPECT_TRUE(string->Equals("android"));
+  EXPECT_FALSE(string->Equals("Android"));
+  EXPECT_FALSE(string->Equals("ANDROID"));
+  EXPECT_FALSE(string->Equals(""));
+  EXPECT_FALSE(string->Equals("and"));
+  EXPECT_FALSE(string->Equals("androids"));
 
   String* empty = String::AllocFromAscii("");
-  EXPECT_PRED2(String::EqualsUtf8, empty, "");
-  EXPECT_PRED2(StringNotEqualsUtf8, empty, "a");
-}
-
-static bool StringNotEquals(const String* a, const String* b) {
-  return !String::Equals(a, b);
+  EXPECT_TRUE(empty->Equals(""));
+  EXPECT_FALSE(empty->Equals("a"));
 }
 
 TEST_F(ObjectTest, StringEquals) {
   String* string = String::AllocFromAscii("android");
-  EXPECT_PRED2(String::Equals, string, String::AllocFromAscii("android"));
-  EXPECT_PRED2(StringNotEquals, string, String::AllocFromAscii("Android"));
-  EXPECT_PRED2(StringNotEquals, string, String::AllocFromAscii("ANDROID"));
-  EXPECT_PRED2(StringNotEquals, string, String::AllocFromAscii(""));
-  EXPECT_PRED2(StringNotEquals, string, String::AllocFromAscii("and"));
-  EXPECT_PRED2(StringNotEquals, string, String::AllocFromAscii("androids"));
+  EXPECT_TRUE(string->Equals(String::AllocFromAscii("android")));
+  EXPECT_FALSE(string->Equals("Android"));
+  EXPECT_FALSE(string->Equals("ANDROID"));
+  EXPECT_FALSE(string->Equals(""));
+  EXPECT_FALSE(string->Equals("and"));
+  EXPECT_FALSE(string->Equals("androids"));
 
   String* empty = String::AllocFromAscii("");
-  EXPECT_PRED2(String::Equals, empty, String::AllocFromAscii(""));
-  EXPECT_PRED2(StringNotEquals, empty, String::AllocFromAscii("a"));
+  EXPECT_TRUE(empty->Equals(""));
+  EXPECT_FALSE(empty->Equals("a"));
+}
+
+TEST_F(ObjectTest, DescriptorCompare) {
+  ClassLinker* linker = class_linker_;
+
+  scoped_ptr<DexFile> proto1_dex_file(OpenDexFileBase64(kProtoCompareDex));
+  PathClassLoader* class_loader_1 = AllocPathClassLoader(proto1_dex_file.get());
+  scoped_ptr<DexFile> proto2_dex_file(OpenDexFileBase64(kProtoCompare2Dex));
+  PathClassLoader* class_loader_2 = AllocPathClassLoader(proto2_dex_file.get());
+
+  Class* klass1 = linker->FindClass("LProtoCompare;", class_loader_1);
+  ASSERT_TRUE(klass1 != NULL);
+  Class* klass2 = linker->FindClass("LProtoCompare2;", class_loader_2);
+  ASSERT_TRUE(klass2 != NULL);
+
+  Method* m1_1 = klass1->GetVirtualMethod(0);
+  EXPECT_TRUE(m1_1->GetName()->Equals("m1"));
+  Method* m2_1 = klass1->GetVirtualMethod(1);
+  EXPECT_TRUE(m2_1->GetName()->Equals("m2"));
+  Method* m3_1 = klass1->GetVirtualMethod(2);
+  EXPECT_TRUE(m3_1->GetName()->Equals("m3"));
+  Method* m4_1 = klass1->GetVirtualMethod(3);
+  EXPECT_TRUE(m4_1->GetName()->Equals("m4"));
+
+  Method* m1_2 = klass2->GetVirtualMethod(0);
+  EXPECT_TRUE(m1_2->GetName()->Equals("m1"));
+  Method* m2_2 = klass2->GetVirtualMethod(1);
+  EXPECT_TRUE(m2_2->GetName()->Equals("m2"));
+  Method* m3_2 = klass2->GetVirtualMethod(2);
+  EXPECT_TRUE(m3_2->GetName()->Equals("m3"));
+  Method* m4_2 = klass2->GetVirtualMethod(3);
+  EXPECT_TRUE(m4_2->GetName()->Equals("m4"));
+
+  EXPECT_TRUE(m1_1->HasSameNameAndDescriptor(m1_2));
+  EXPECT_TRUE(m1_2->HasSameNameAndDescriptor(m1_1));
+
+  EXPECT_TRUE(m2_1->HasSameNameAndDescriptor(m2_2));
+  EXPECT_TRUE(m2_2->HasSameNameAndDescriptor(m2_1));
+
+  EXPECT_TRUE(m3_1->HasSameNameAndDescriptor(m3_2));
+  EXPECT_TRUE(m3_2->HasSameNameAndDescriptor(m3_1));
+
+  EXPECT_TRUE(m4_1->HasSameNameAndDescriptor(m4_2));
+  EXPECT_TRUE(m4_2->HasSameNameAndDescriptor(m4_1));
 }
 
 }  // namespace art