ART: Change direct-method overlap detection

Avoid allocations in a hash set when trying to ensure that there are no
method-ids denoting both direct and virtual methods. Instead use a copy
of the item iterator, as the methods are guaranteed to be sorted.

Saves 1% of instructions for a compiler-filter=extract compact-dex-level=none
compile:

                 Before             After
Small app      545,345,563       540,654,732
Large app    8,040,713,801     7,956,413,657

Bug: 78568168
Test: m test-art-host
Change-Id: Ia2a0fbb82dad5d9fa781cbab46fe543d1dd0645e
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index 4098b42..4ca735a 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -1346,9 +1346,6 @@
     uint32_t field_idx_delta_;  // delta of index into the field_ids array for FieldId
     uint32_t access_flags_;  // access flags for the field
     ClassDataField() :  field_idx_delta_(0), access_flags_(0) {}
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(ClassDataField);
   };
   ClassDataField field_;
 
@@ -1361,9 +1358,6 @@
     uint32_t access_flags_;
     uint32_t code_off_;
     ClassDataMethod() : method_idx_delta_(0), access_flags_(0), code_off_(0) {}
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(ClassDataMethod);
   };
   ClassDataMethod method_;
 
@@ -1374,7 +1368,6 @@
   size_t pos_;  // integral number of items passed
   const uint8_t* ptr_pos_;  // pointer into stream of class_data_item
   uint32_t last_idx_;  // last read field or method index to apply delta to
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ClassDataItemIterator);
 };
 
 class EncodedArrayValueIterator {
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index 68bd19e..e0bfdcf 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -674,9 +674,9 @@
                                                uint32_t class_access_flags,
                                                dex::TypeIndex class_type_index,
                                                uint32_t code_offset,
-                                               std::unordered_set<uint32_t>* direct_method_indexes,
+                                               ClassDataItemIterator* direct_it,
                                                bool expect_direct) {
-  DCHECK(direct_method_indexes != nullptr);
+  DCHECK(expect_direct || direct_it != nullptr);
   // Check for overflow.
   if (!CheckIndex(idx, header_->method_ids_size_, "class_data_item method_idx")) {
     return false;
@@ -694,11 +694,19 @@
   }
 
   // Check that it's not defined as both direct and virtual.
-  if (expect_direct) {
-    direct_method_indexes->insert(idx);
-  } else if (direct_method_indexes->find(idx) != direct_method_indexes->end()) {
-    ErrorStringPrintf("Found virtual method with same index as direct method: %d", idx);
-    return false;
+  if (!expect_direct) {
+    // The direct methods are already known to be in ascending index order. So just keep up
+    // with the current index.
+    for (; direct_it->HasNextDirectMethod(); direct_it->Next()) {
+      uint32_t direct_idx = direct_it->GetMemberIndex();
+      if (direct_idx > idx) {
+        break;
+      }
+      if (direct_idx == idx) {
+        ErrorStringPrintf("Found virtual method with same index as direct method: %d", idx);
+        return false;
+      }
+    }
   }
 
   std::string error_msg;
@@ -1146,7 +1154,7 @@
 template <bool kDirect>
 bool DexFileVerifier::CheckIntraClassDataItemMethods(
     ClassDataItemIterator* it,
-    std::unordered_set<uint32_t>* direct_method_indexes,
+    ClassDataItemIterator* direct_it,
     bool* have_class,
     dex::TypeIndex* class_type_index,
     const DexFile::ClassDef** class_def) {
@@ -1168,7 +1176,7 @@
                                   (*class_def)->access_flags_,
                                   *class_type_index,
                                   it->GetMethodCodeItemOffset(),
-                                  direct_method_indexes,
+                                  direct_it,
                                   kDirect)) {
       return false;
     }
@@ -1181,7 +1189,6 @@
 
 bool DexFileVerifier::CheckIntraClassDataItem() {
   ClassDataItemIterator it(*dex_file_, ptr_);
-  std::unordered_set<uint32_t> direct_method_indexes;
 
   // This code is complicated by the fact that we don't directly know which class this belongs to.
   // So we need to explicitly search with the first item we find (either field or method), and then,
@@ -1205,15 +1212,17 @@
   }
 
   // Check methods.
+  ClassDataItemIterator direct_it = it;
+
   if (!CheckIntraClassDataItemMethods<true>(&it,
-                                            &direct_method_indexes,
+                                            nullptr /* direct_it */,
                                             &have_class,
                                             &class_type_index,
                                             &class_def)) {
     return false;
   }
   if (!CheckIntraClassDataItemMethods<false>(&it,
-                                             &direct_method_indexes,
+                                             &direct_it,
                                              &have_class,
                                              &class_type_index,
                                              &class_def)) {
diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h
index a80a9d5..3bddc77 100644
--- a/libdexfile/dex/dex_file_verifier.h
+++ b/libdexfile/dex/dex_file_verifier.h
@@ -85,7 +85,7 @@
                                 uint32_t class_access_flags,
                                 dex::TypeIndex class_type_index,
                                 uint32_t code_offset,
-                                std::unordered_set<uint32_t>* direct_method_indexes,
+                                ClassDataItemIterator* direct_it,
                                 bool expect_direct);
   bool CheckOrderAndGetClassDef(bool is_field,
                                 const char* type_descr,
@@ -113,7 +113,7 @@
   // method, if necessary (and return it), or use the given values.
   template <bool kDirect>
   bool CheckIntraClassDataItemMethods(ClassDataItemIterator* it,
-                                      std::unordered_set<uint32_t>* direct_method_indexes,
+                                      ClassDataItemIterator* direct_it,
                                       bool* have_class,
                                       dex::TypeIndex* class_type_index,
                                       const DexFile::ClassDef** class_def);