ART: Refactor class-def retrieval

Peel the first loop iteration to avoid excessive branches and loads.

Bug: 78568168
Test: m test-art-host
Change-Id: I22f403254b01d34837dde1decc05e2d00700ffeb
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index e0bfdcf..3f72a25 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -994,31 +994,16 @@
   return false;
 }
 
-bool DexFileVerifier::CheckOrderAndGetClassDef(bool is_field,
-                                               const char* type_descr,
-                                               uint32_t curr_index,
-                                               uint32_t prev_index,
-                                               bool* have_class,
-                                               dex::TypeIndex* class_type_index,
-                                               const DexFile::ClassDef** class_def) {
-  if (curr_index < prev_index) {
+bool DexFileVerifier::CheckOrder(const char* type_descr,
+                                 uint32_t curr_index,
+                                 uint32_t prev_index) {
+  if (UNLIKELY(curr_index < prev_index)) {
     ErrorStringPrintf("out-of-order %s indexes %" PRIu32 " and %" PRIu32,
                       type_descr,
                       prev_index,
                       curr_index);
     return false;
   }
-
-  if (!*have_class) {
-    *have_class = FindClassIndexAndDef(curr_index, is_field, class_type_index, class_def);
-    if (!*have_class) {
-      // Should have really found one.
-      ErrorStringPrintf("could not find declaring class for %s index %" PRIu32,
-                        type_descr,
-                        curr_index);
-      return false;
-    }
-  }
   return true;
 }
 
@@ -1123,20 +1108,29 @@
                                                     dex::TypeIndex* class_type_index,
                                                     const DexFile::ClassDef** class_def) {
   DCHECK(it != nullptr);
+  constexpr const char* kTypeDescr = kStatic ? "static field" : "instance field";
+
   // These calls use the raw access flags to check whether the whole dex field is valid.
+
+  if (!*have_class && (kStatic ? it->HasNextStaticField() : it->HasNextInstanceField())) {
+    *have_class = FindClassIndexAndDef(it->GetMemberIndex(), true, class_type_index, class_def);
+    if (!*have_class) {
+      // Should have really found one.
+      ErrorStringPrintf("could not find declaring class for %s index %" PRIu32,
+                        kTypeDescr,
+                        it->GetMemberIndex());
+      return false;
+    }
+  }
+  DCHECK(*class_def != nullptr ||
+         !(kStatic ? it->HasNextStaticField() : it->HasNextInstanceField()));
+
   uint32_t prev_index = 0;
   for (; kStatic ? it->HasNextStaticField() : it->HasNextInstanceField(); it->Next()) {
     uint32_t curr_index = it->GetMemberIndex();
-    if (!CheckOrderAndGetClassDef(true,
-                                  kStatic ? "static field" : "instance field",
-                                  curr_index,
-                                  prev_index,
-                                  have_class,
-                                  class_type_index,
-                                  class_def)) {
+    if (!CheckOrder(kTypeDescr, curr_index, prev_index)) {
       return false;
     }
-    DCHECK(class_def != nullptr);
     if (!CheckClassDataItemField(curr_index,
                                  it->GetRawMemberAccessFlags(),
                                  (*class_def)->access_flags_,
@@ -1158,19 +1152,28 @@
     bool* have_class,
     dex::TypeIndex* class_type_index,
     const DexFile::ClassDef** class_def) {
+  DCHECK(it != nullptr);
+  constexpr const char* kTypeDescr = kDirect ? "direct method" : "virtual method";
+
+  if (!*have_class && (kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod())) {
+    *have_class = FindClassIndexAndDef(it->GetMemberIndex(), false, class_type_index, class_def);
+    if (!*have_class) {
+      // Should have really found one.
+      ErrorStringPrintf("could not find declaring class for %s index %" PRIu32,
+                        kTypeDescr,
+                        it->GetMemberIndex());
+      return false;
+    }
+  }
+  DCHECK(*class_def != nullptr ||
+         !(kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod()));
+
   uint32_t prev_index = 0;
   for (; kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod(); it->Next()) {
     uint32_t curr_index = it->GetMemberIndex();
-    if (!CheckOrderAndGetClassDef(false,
-                                  kDirect ? "direct method" : "virtual method",
-                                  curr_index,
-                                  prev_index,
-                                  have_class,
-                                  class_type_index,
-                                  class_def)) {
+    if (!CheckOrder(kTypeDescr, curr_index, prev_index)) {
       return false;
     }
-    DCHECK(class_def != nullptr);
     if (!CheckClassDataItemMethod(curr_index,
                                   it->GetRawMemberAccessFlags(),
                                   (*class_def)->access_flags_,
diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h
index 3bddc77..4b73363 100644
--- a/libdexfile/dex/dex_file_verifier.h
+++ b/libdexfile/dex/dex_file_verifier.h
@@ -87,13 +87,8 @@
                                 uint32_t code_offset,
                                 ClassDataItemIterator* direct_it,
                                 bool expect_direct);
-  bool CheckOrderAndGetClassDef(bool is_field,
-                                const char* type_descr,
-                                uint32_t curr_index,
-                                uint32_t prev_index,
-                                bool* have_class,
-                                dex::TypeIndex* class_type_index,
-                                const DexFile::ClassDef** class_def);
+  ALWAYS_INLINE
+  bool CheckOrder(const char* type_descr, uint32_t curr_index, uint32_t prev_index);
   bool CheckStaticFieldTypes(const DexFile::ClassDef* class_def);
 
   bool CheckPadding(size_t offset, uint32_t aligned_offset, DexFile::MapItemType type);