Move compiler/ to ClassAccessor

Remove usages of ClassDataItemIterator to reduces boiler plate code.

Bug: 79758018
Bug: 77709234
Test: test-art-host

Change-Id: Id41db3299bba3ea8debcbb0b9c721fa675adc064
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index be8641f..68155d8 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -26,6 +26,7 @@
 #include "base/mutex.h"
 #include "compiled_method.h"
 #include "dex/bytecode_utils.h"
+#include "dex/class_accessor-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_instruction-inl.h"
 #include "dex_to_dex_decompiler.h"
@@ -633,21 +634,14 @@
   // item.
   std::unordered_set<const DexFile::CodeItem*> seen_code_items;
   for (const DexFile* dex_file : dex_files) {
-    for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
-      const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-      const uint8_t* class_data = dex_file->GetClassData(class_def);
-      if (class_data == nullptr) {
-        continue;
-      }
-      ClassDataItemIterator it(*dex_file, class_data);
-      it.SkipAllFields();
-      for (; it.HasNextMethod(); it.Next()) {
-        const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+    for (ClassAccessor accessor : dex_file->GetClasses()) {
+      accessor.VisitMethods([&](const ClassAccessor::Method& method) {
+        const DexFile::CodeItem* code_item = method.GetCodeItem();
         // Detect the shared code items.
         if (!seen_code_items.insert(code_item).second) {
           shared_code_items_.insert(code_item);
         }
-      }
+      });
     }
   }
   VLOG(compiler) << "Shared code items " << shared_code_items_.size();
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 7dc44fa..1b809d2 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -42,6 +42,7 @@
 #include "compiler.h"
 #include "compiler_callbacks.h"
 #include "compiler_driver-inl.h"
+#include "dex/class_accessor-inl.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_annotations.h"
@@ -771,39 +772,6 @@
   }
 }
 
-// Resolve const-strings in the code. Done to have deterministic allocation behavior. Right now
-// this is single-threaded for simplicity.
-// TODO: Collect the relevant string indices in parallel, then allocate them sequentially in a
-//       stable order.
-
-static void ResolveConstStrings(ClassLinker* class_linker,
-                                Handle<mirror::DexCache> dex_cache,
-                                const DexFile& dex_file,
-                                const DexFile::CodeItem* code_item)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-  if (code_item == nullptr) {
-    // Abstract or native method.
-    return;
-  }
-
-  for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(dex_file, code_item)) {
-    switch (inst->Opcode()) {
-      case Instruction::CONST_STRING:
-      case Instruction::CONST_STRING_JUMBO: {
-        dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING)
-            ? inst->VRegB_21c()
-            : inst->VRegB_31c());
-        ObjPtr<mirror::String> string = class_linker->ResolveString(string_index, dex_cache);
-        CHECK(string != nullptr) << "Could not allocate a string when forcing determinism";
-        break;
-      }
-
-      default:
-        break;
-    }
-  }
-}
-
 static void ResolveConstStrings(CompilerDriver* driver,
                                 const std::vector<const DexFile*>& dex_files,
                                 TimingLogger* timings) {
@@ -816,33 +784,35 @@
     dex_cache.Assign(class_linker->FindDexCache(soa.Self(), *dex_file));
     TimingLogger::ScopedTiming t("Resolve const-string Strings", timings);
 
-    size_t class_def_count = dex_file->NumClassDefs();
-    for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
-      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
-
-      const uint8_t* class_data = dex_file->GetClassData(class_def);
-      if (class_data == nullptr) {
-        // empty class, probably a marker interface
-        continue;
-      }
-
-      ClassDataItemIterator it(*dex_file, class_data);
-      it.SkipAllFields();
-
-      bool compilation_enabled = driver->IsClassToCompile(
-          dex_file->StringByTypeIdx(class_def.class_idx_));
-      if (!compilation_enabled) {
+    for (ClassAccessor accessor : dex_file->GetClasses()) {
+      if (!driver->IsClassToCompile(accessor.GetDescriptor())) {
         // Compilation is skipped, do not resolve const-string in code of this class.
         // FIXME: Make sure that inlining honors this. b/26687569
         continue;
       }
+      accessor.VisitMethods([&](const ClassAccessor::Method& method)
+          REQUIRES_SHARED(Locks::mutator_lock_) {
+        // Resolve const-strings in the code. Done to have deterministic allocation behavior. Right
+        // now this is single-threaded for simplicity.
+        // TODO: Collect the relevant string indices in parallel, then allocate them sequentially
+        // in a stable order.
+        for (const DexInstructionPcPair& inst : method.GetInstructions()) {
+          switch (inst->Opcode()) {
+            case Instruction::CONST_STRING:
+            case Instruction::CONST_STRING_JUMBO: {
+              dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING)
+                  ? inst->VRegB_21c()
+                  : inst->VRegB_31c());
+              ObjPtr<mirror::String> string = class_linker->ResolveString(string_index, dex_cache);
+              CHECK(string != nullptr) << "Could not allocate a string when forcing determinism";
+              break;
+            }
 
-      // Direct and virtual methods.
-      while (it.HasNextMethod()) {
-        ResolveConstStrings(class_linker, dex_cache, *dex_file, it.GetMethodCodeItem());
-        it.Next();
-      }
-      DCHECK(!it.HasNext());
+            default:
+              break;
+          }
+        }
+      });
     }
   }
 }
@@ -856,14 +826,9 @@
                                           ClassLinker* class_linker,
                                           Handle<mirror::DexCache> dex_cache,
                                           const DexFile& dex_file,
-                                          const DexFile::CodeItem* code_item)
+                                          const ClassAccessor::Method& method)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-  if (code_item == nullptr) {
-    // Abstract or native method.
-    return;
-  }
-
-  for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(dex_file, code_item)) {
+  for (const DexInstructionPcPair& inst : method.GetInstructions()) {
     switch (inst->Opcode()) {
       case Instruction::CHECK_CAST:
       case Instruction::INSTANCE_OF: {
@@ -907,34 +872,18 @@
     dex_cache.Assign(class_linker->FindDexCache(soa.Self(), *dex_file));
     TimingLogger::ScopedTiming t("Initialize type check bitstrings", timings);
 
-    size_t class_def_count = dex_file->NumClassDefs();
-    for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
-      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
-
-      const uint8_t* class_data = dex_file->GetClassData(class_def);
-      if (class_data == nullptr) {
-        // empty class, probably a marker interface
-        continue;
-      }
-
-      ClassDataItemIterator it(*dex_file, class_data);
-      it.SkipAllFields();
-
-      bool compilation_enabled = driver->IsClassToCompile(
-          dex_file->StringByTypeIdx(class_def.class_idx_));
-      if (!compilation_enabled) {
+    for (ClassAccessor accessor : dex_file->GetClasses()) {
+      if (!driver->IsClassToCompile(accessor.GetDescriptor())) {
         // Compilation is skipped, do not look for type checks in code of this class.
         // FIXME: Make sure that inlining honors this. b/26687569
         continue;
       }
 
       // Direct and virtual methods.
-      while (it.HasNextMethod()) {
-        InitializeTypeCheckBitstrings(
-            driver, class_linker, dex_cache, *dex_file, it.GetMethodCodeItem());
-        it.Next();
-      }
-      DCHECK(!it.HasNext());
+      accessor.VisitMethods([&](const ClassAccessor::Method& method)
+          REQUIRES_SHARED(Locks::mutator_lock_) {
+        InitializeTypeCheckBitstrings(driver, class_linker, dex_cache, *dex_file, method);
+      });
     }
   }
 }
@@ -954,10 +903,8 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   for (const DexFile* dex_file : dex_files) {
-    for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
-      const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-      const char* descriptor = dex_file->GetClassDescriptor(class_def);
-      cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader));
+    for (ClassAccessor accessor : dex_file->GetClasses()) {
+      cls.Assign(class_linker->FindClass(soa.Self(), accessor.GetDescriptor(), class_loader));
       if (cls == nullptr) {
         soa.Self()->ClearException();
       } else if (&cls->GetDexFile() == dex_file) {
@@ -1740,22 +1687,16 @@
 
 bool CompilerDriver::RequiresConstructorBarrier(const DexFile& dex_file,
                                                 uint16_t class_def_idx) const {
-  const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx);
-  const uint8_t* class_data = dex_file.GetClassData(class_def);
-  if (class_data == nullptr) {
-    // Empty class such as a marker interface.
-    return false;
-  }
-  ClassDataItemIterator it(dex_file, class_data);
-  it.SkipStaticFields();
+  ClassAccessor accessor(dex_file, dex_file.GetClassDef(class_def_idx));
+  bool has_is_final = false;
   // We require a constructor barrier if there are final instance fields.
-  while (it.HasNextInstanceField()) {
-    if (it.MemberIsFinal()) {
-      return true;
+  accessor.VisitFields(/*static*/ VoidFunctor(),
+                       [&](const ClassAccessor::Field& field) {
+    if (field.IsFinal()) {
+      has_is_final = true;
     }
-    it.Next();
-  }
-  return false;
+  });
+  return has_is_final;
 }
 
 class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor {
@@ -1770,11 +1711,6 @@
     const DexFile& dex_file = *manager_->GetDexFile();
     ClassLinker* class_linker = manager_->GetClassLinker();
 
-    // If an instance field is final then we need to have a barrier on the return, static final
-    // fields are assigned within the lock held for class initialization. Conservatively assume
-    // constructor barriers are always required.
-    bool requires_constructor_barrier = true;
-
     // Method and Field are the worst. We can't resolve without either
     // context from the code use (to disambiguate virtual vs direct
     // method and instance vs static field) or from class
@@ -1806,56 +1742,53 @@
       // We want to resolve the methods and fields eagerly.
       resolve_fields_and_methods = true;
     }
-    // Note the class_data pointer advances through the headers,
-    // static fields, instance fields, direct methods, and virtual
-    // methods.
-    const uint8_t* class_data = dex_file.GetClassData(class_def);
-    if (class_data == nullptr) {
-      // Empty class such as a marker interface.
-      requires_constructor_barrier = false;
-    } else {
-      ClassDataItemIterator it(dex_file, class_data);
-      while (it.HasNextStaticField()) {
-        if (resolve_fields_and_methods) {
-          ArtField* field = class_linker->ResolveField(
-              it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true);
-          if (field == nullptr) {
-            CheckAndClearResolveException(soa.Self());
-          }
-        }
-        it.Next();
-      }
-      // We require a constructor barrier if there are final instance fields.
-      requires_constructor_barrier = false;
-      while (it.HasNextInstanceField()) {
-        if (it.MemberIsFinal()) {
-          requires_constructor_barrier = true;
-        }
-        if (resolve_fields_and_methods) {
-          ArtField* field = class_linker->ResolveField(
-              it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ false);
-          if (field == nullptr) {
-            CheckAndClearResolveException(soa.Self());
-          }
-        }
-        it.Next();
-      }
+    // If an instance field is final then we need to have a barrier on the return, static final
+    // fields are assigned within the lock held for class initialization.
+    bool requires_constructor_barrier = false;
+
+    ClassAccessor accessor(dex_file, class_def);
+    // Optionally resolve fields and methods and figure out if we need a constructor barrier.
+    auto method_visitor = [&](const ClassAccessor::Method& method)
+        REQUIRES_SHARED(Locks::mutator_lock_) {
       if (resolve_fields_and_methods) {
-        while (it.HasNextMethod()) {
-          ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
-              it.GetMemberIndex(),
-              dex_cache,
-              class_loader,
-              /* referrer */ nullptr,
-              it.GetMethodInvokeType(class_def));
-          if (method == nullptr) {
-            CheckAndClearResolveException(soa.Self());
-          }
-          it.Next();
+        ArtMethod* resolved = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
+            method.GetIndex(),
+            dex_cache,
+            class_loader,
+            /* referrer */ nullptr,
+            method.GetInvokeType(class_def.access_flags_));
+        if (resolved == nullptr) {
+          CheckAndClearResolveException(soa.Self());
         }
-        DCHECK(!it.HasNext());
       }
-    }
+    };
+    accessor.VisitFieldsAndMethods(
+        // static fields
+        [&](ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
+          if (resolve_fields_and_methods) {
+            ArtField* resolved = class_linker->ResolveField(
+                field.GetIndex(), dex_cache, class_loader, /* is_static */ true);
+            if (resolved == nullptr) {
+              CheckAndClearResolveException(soa.Self());
+            }
+          }
+        },
+        // instance fields
+        [&](ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
+          if (field.IsFinal()) {
+            // We require a constructor barrier if there are final instance fields.
+            requires_constructor_barrier = true;
+          }
+          if (resolve_fields_and_methods) {
+            ArtField* resolved = class_linker->ResolveField(
+                field.GetIndex(), dex_cache, class_loader, /* is_static */ false);
+            if (resolved == nullptr) {
+              CheckAndClearResolveException(soa.Self());
+            }
+          }
+        },
+        /*direct methods*/ method_visitor,
+        /*virtual methods*/ method_visitor);
     manager_->GetCompiler()->SetRequiresConstructorBarrier(self,
                                                            &dex_file,
                                                            class_def_index,
@@ -1942,32 +1875,13 @@
   }
 }
 
-static void PopulateVerifiedMethods(const DexFile& dex_file,
-                                    uint32_t class_def_index,
-                                    VerificationResults* verification_results) {
-  const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
-  const uint8_t* class_data = dex_file.GetClassData(class_def);
-  if (class_data == nullptr) {
-    return;
-  }
-  ClassDataItemIterator it(dex_file, class_data);
-  it.SkipAllFields();
-
-  while (it.HasNextMethod()) {
-    verification_results->CreateVerifiedMethodFor(MethodReference(&dex_file, it.GetMemberIndex()));
-    it.Next();
-  }
-  DCHECK(!it.HasNext());
-}
-
-static void LoadAndUpdateStatus(const DexFile& dex_file,
-                                const DexFile::ClassDef& class_def,
+static void LoadAndUpdateStatus(const ClassAccessor& accessor,
                                 ClassStatus status,
                                 Handle<mirror::ClassLoader> class_loader,
                                 Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
-  const char* descriptor = dex_file.GetClassDescriptor(class_def);
+  const char* descriptor = accessor.GetDescriptor();
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Handle<mirror::Class> cls(hs.NewHandle<mirror::Class>(
       class_linker->FindClass(self, descriptor, class_loader)));
@@ -1975,7 +1889,7 @@
     // Check that the class is resolved with the current dex file. We might get
     // a boot image class, or a class in a different dex file for multidex, and
     // we should not update the status in that case.
-    if (&cls->GetDexFile() == &dex_file) {
+    if (&cls->GetDexFile() == &accessor.GetDexFile()) {
       ObjectLock<mirror::Class> lock(self, cls);
       mirror::Class::SetStatus(cls, status, self);
     }
@@ -2014,13 +1928,13 @@
     // Fetch the list of unverified classes.
     const std::set<dex::TypeIndex>& unverified_classes =
         verifier_deps->GetUnverifiedClasses(*dex_file);
-    for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
-      const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-      if (unverified_classes.find(class_def.class_idx_) == unverified_classes.end()) {
+    uint32_t class_def_idx = 0u;
+    for (ClassAccessor accessor : dex_file->GetClasses()) {
+      if (unverified_classes.find(accessor.GetClassIdx()) == unverified_classes.end()) {
         if (compiler_only_verifies) {
           // Just update the compiled_classes_ map. The compiler doesn't need to resolve
           // the type.
-          ClassReference ref(dex_file, i);
+          ClassReference ref(dex_file, class_def_idx);
           ClassStatus existing = ClassStatus::kNotReady;
           DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation();
           ClassStateTable::InsertResult result =
@@ -2029,26 +1943,27 @@
         } else {
           // Update the class status, so later compilation stages know they don't need to verify
           // the class.
-          LoadAndUpdateStatus(
-              *dex_file, class_def, ClassStatus::kVerified, class_loader, soa.Self());
+          LoadAndUpdateStatus(accessor, ClassStatus::kVerified, class_loader, soa.Self());
           // Create `VerifiedMethod`s for each methods, the compiler expects one for
           // quickening or compiling.
           // Note that this means:
           // - We're only going to compile methods that did verify.
           // - Quickening will not do checkcast ellision.
           // TODO(ngeoffray): Reconsider this once we refactor compiler filters.
-          PopulateVerifiedMethods(*dex_file, i, verification_results_);
+          accessor.VisitMethods([&](const ClassAccessor::Method& method) {
+            verification_results_->CreateVerifiedMethodFor(method.GetReference());
+          });
         }
       } else if (!compiler_only_verifies) {
         // Make sure later compilation stages know they should not try to verify
         // this class again.
-        LoadAndUpdateStatus(*dex_file,
-                            class_def,
+        LoadAndUpdateStatus(accessor,
                             ClassStatus::kRetryVerificationAtRuntime,
                             class_loader,
                             soa.Self());
       }
     }
+    ++class_def_idx;
   }
   return true;
 }
@@ -2784,22 +2699,22 @@
   auto compile = [&context, &compile_fn](size_t class_def_index) {
     ScopedTrace trace(__FUNCTION__);
     const DexFile& dex_file = *context.GetDexFile();
-    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     ClassLinker* class_linker = context.GetClassLinker();
     jobject jclass_loader = context.GetClassLoader();
     ClassReference ref(&dex_file, class_def_index);
+    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+    ClassAccessor accessor(dex_file, class_def);
     // Skip compiling classes with generic verifier failures since they will still fail at runtime
     if (context.GetCompiler()->GetVerificationResults()->IsClassRejected(ref)) {
       return;
     }
     // Use a scoped object access to perform to the quick SkipClass check.
-    const char* descriptor = dex_file.GetClassDescriptor(class_def);
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<3> hs(soa.Self());
     Handle<mirror::ClassLoader> class_loader(
         hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
     Handle<mirror::Class> klass(
-        hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
+        hs.NewHandle(class_linker->FindClass(soa.Self(), accessor.GetDescriptor(), class_loader)));
     Handle<mirror::DexCache> dex_cache;
     if (klass == nullptr) {
       soa.Self()->AssertPendingException();
@@ -2814,9 +2729,8 @@
       dex_cache = hs.NewHandle(klass->GetDexCache());
     }
 
-    const uint8_t* class_data = dex_file.GetClassData(class_def);
-    if (class_data == nullptr) {
-      // empty class, probably a marker interface
+    // Avoid suspension if there are no methods to compile.
+    if (accessor.NumDirectMethods() + accessor.NumVirtualMethods() == 0) {
       return;
     }
 
@@ -2829,28 +2743,24 @@
     optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level =
         GetDexToDexCompilationLevel(soa.Self(), *driver, jclass_loader, dex_file, class_def);
 
-    ClassDataItemIterator it(dex_file, class_data);
-    it.SkipAllFields();
 
-    bool compilation_enabled = driver->IsClassToCompile(
-        dex_file.StringByTypeIdx(class_def.class_idx_));
+    const bool compilation_enabled = driver->IsClassToCompile(accessor.GetDescriptor());
 
     // Compile direct and virtual methods.
     int64_t previous_method_idx = -1;
-    while (it.HasNextMethod()) {
-      uint32_t method_idx = it.GetMemberIndex();
+    accessor.VisitMethods([&](const ClassAccessor::Method& method) {
+      const uint32_t method_idx = method.GetIndex();
       if (method_idx == previous_method_idx) {
         // smali can create dex files with two encoded_methods sharing the same method_idx
         // http://code.google.com/p/smali/issues/detail?id=119
-        it.Next();
-        continue;
+        return;
       }
       previous_method_idx = method_idx;
       compile_fn(soa.Self(),
                  driver,
-                 it.GetMethodCodeItem(),
-                 it.GetMethodAccessFlags(),
-                 it.GetMethodInvokeType(class_def),
+                 method.GetCodeItem(),
+                 method.GetAccessFlags(),
+                 method.GetInvokeType(class_def.access_flags_),
                  class_def_index,
                  method_idx,
                  class_loader,
@@ -2858,9 +2768,7 @@
                  dex_to_dex_compilation_level,
                  compilation_enabled,
                  dex_cache);
-      it.Next();
-    }
-    DCHECK(!it.HasNext());
+    });
   };
   context.ForAllLambda(0, dex_file.NumClassDefs(), compile, thread_count);
 }
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 06f0bcd..103862b 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -22,6 +22,8 @@
 #include "class_linker.h"
 #include "common_compiler_test.h"
 #include "compiler_callbacks.h"
+#include "dex/class_accessor-inl.h"
+#include "dex/class_iterator.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_types.h"
 #include "dex/verification_results.h"
@@ -148,48 +150,45 @@
     Handle<mirror::DexCache> dex_cache_handle(hs.NewHandle(klass_Main_->GetDexCache()));
 
     const DexFile::ClassDef* class_def = klass_Main_->GetClassDef();
-    const uint8_t* class_data = primary_dex_file_->GetClassData(*class_def);
-    CHECK(class_data != nullptr);
+    ClassAccessor accessor(*primary_dex_file_, *class_def);
 
-    ClassDataItemIterator it(*primary_dex_file_, class_data);
-    it.SkipAllFields();
+    bool has_failures = true;
+    bool found_method = false;
 
-    ArtMethod* method = nullptr;
-    while (it.HasNextDirectMethod()) {
+    accessor.VisitMethods([&](const ClassAccessor::Method& method)
+        REQUIRES_SHARED(Locks::mutator_lock_) {
       ArtMethod* resolved_method =
           class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
-              it.GetMemberIndex(),
+              method.GetIndex(),
               dex_cache_handle,
               class_loader_handle,
               /* referrer */ nullptr,
-              it.GetMethodInvokeType(*class_def));
+              method.GetInvokeType(class_def->access_flags_));
       CHECK(resolved_method != nullptr);
       if (method_name == resolved_method->GetName()) {
-        method = resolved_method;
-        break;
+        soa.Self()->SetVerifierDeps(callbacks_->GetVerifierDeps());
+        MethodVerifier verifier(soa.Self(),
+                                primary_dex_file_,
+                                dex_cache_handle,
+                                class_loader_handle,
+                                *class_def,
+                                method.GetCodeItem(),
+                                method.GetIndex(),
+                                resolved_method,
+                                method.GetAccessFlags(),
+                                true /* can_load_classes */,
+                                true /* allow_soft_failures */,
+                                true /* need_precise_constants */,
+                                false /* verify to dump */,
+                                true /* allow_thread_suspension */);
+        verifier.Verify();
+        soa.Self()->SetVerifierDeps(nullptr);
+        has_failures = verifier.HasFailures();
+        found_method = true;
       }
-      it.Next();
-    }
-    CHECK(method != nullptr);
-
-    Thread::Current()->SetVerifierDeps(callbacks_->GetVerifierDeps());
-    MethodVerifier verifier(Thread::Current(),
-                            primary_dex_file_,
-                            dex_cache_handle,
-                            class_loader_handle,
-                            *class_def,
-                            it.GetMethodCodeItem(),
-                            it.GetMemberIndex(),
-                            method,
-                            it.GetMethodAccessFlags(),
-                            true /* can_load_classes */,
-                            true /* allow_soft_failures */,
-                            true /* need_precise_constants */,
-                            false /* verify to dump */,
-                            true /* allow_thread_suspension */);
-    verifier.Verify();
-    Thread::Current()->SetVerifierDeps(nullptr);
-    return !verifier.HasFailures();
+    });
+    CHECK(found_method) << "Expected to find method " << method_name;
+    return !has_failures;
   }
 
   void VerifyDexFile(const char* multidex = nullptr) {
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h
index 5cfbcaa..a082142 100644
--- a/libdexfile/dex/class_accessor-inl.h
+++ b/libdexfile/dex/class_accessor-inl.h
@@ -38,14 +38,14 @@
       num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {}
 
 inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) {
-  method_idx_ += DecodeUnsignedLeb128(&ptr);
+  index_ += DecodeUnsignedLeb128(&ptr);
   access_flags_ = DecodeUnsignedLeb128(&ptr);
   code_off_ = DecodeUnsignedLeb128(&ptr);
   return ptr;
 }
 
 inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) {
-  field_idx_ += DecodeUnsignedLeb128(&ptr);
+  index_ += DecodeUnsignedLeb128(&ptr);
   access_flags_ = DecodeUnsignedLeb128(&ptr);
   return ptr;
 }
@@ -54,7 +54,7 @@
           typename InstanceFieldVisitor,
           typename DirectMethodVisitor,
           typename VirtualMethodVisitor>
-inline void ClassAccessor::VisitMethodsAndFields(
+inline void ClassAccessor::VisitFieldsAndMethods(
     const StaticFieldVisitor& static_field_visitor,
     const InstanceFieldVisitor& instance_field_visitor,
     const DirectMethodVisitor& direct_method_visitor,
@@ -75,14 +75,14 @@
     }
   }
   {
-    Method data(dex_file_);
+    Method data(dex_file_, /*is_static_or_direct*/ true);
     for (size_t i = 0; i < num_direct_methods_; ++i) {
       ptr = data.Read(ptr);
       direct_method_visitor(data);
     }
   }
   {
-    Method data(dex_file_);
+    Method data(dex_file_, /*is_static_or_direct*/ false);
     for (size_t i = 0; i < num_virtual_methods_; ++i) {
       ptr = data.Read(ptr);
       virtual_method_visitor(data);
@@ -94,12 +94,22 @@
           typename VirtualMethodVisitor>
 inline void ClassAccessor::VisitMethods(const DirectMethodVisitor& direct_method_visitor,
                                         const VirtualMethodVisitor& virtual_method_visitor) const {
-  VisitMethodsAndFields(VoidFunctor(),
+  VisitFieldsAndMethods(VoidFunctor(),
                         VoidFunctor(),
                         direct_method_visitor,
                         virtual_method_visitor);
 }
 
+template <typename StaticFieldVisitor,
+          typename InstanceFieldVisitor>
+inline void ClassAccessor::VisitFields(const StaticFieldVisitor& static_field_visitor,
+                                       const InstanceFieldVisitor& instance_field_visitor) const {
+  VisitFieldsAndMethods(static_field_visitor,
+                        instance_field_visitor,
+                        VoidFunctor(),
+                        VoidFunctor());
+}
+
 // Visit direct and virtual methods.
 template <typename MethodVisitor>
 inline void ClassAccessor::VisitMethods(const MethodVisitor& method_visitor) const {
@@ -114,6 +124,14 @@
   return CodeItemInstructionAccessor(dex_file_, dex_file_.GetCodeItem(GetCodeItemOffset()));
 }
 
+inline const char* ClassAccessor::GetDescriptor() const {
+  return dex_file_.StringByTypeIdx(descriptor_index_);
+}
+
+inline const DexFile::CodeItem* ClassAccessor::Method::GetCodeItem() const {
+  return dex_file_.GetCodeItem(code_off_);
+}
+
 }  // namespace art
 
 #endif  // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index 835c4e2..72bc50b 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -20,6 +20,9 @@
 #include "base/utils.h"
 #include "code_item_accessors.h"
 #include "dex_file.h"
+#include "invoke_type.h"
+#include "method_reference.h"
+#include "modifiers.h"
 
 namespace art {
 
@@ -27,56 +30,82 @@
 
 // Classes to access Dex data.
 class ClassAccessor {
- public:
-  // Class method data.
-  class Method {
+ private:
+  class BaseItem {
    public:
     uint32_t GetIndex() const {
-      return method_idx_;
+      return index_;
     }
 
     uint32_t GetAccessFlags() const {
       return access_flags_;
     }
 
+    bool IsFinal() const {
+      return (GetAccessFlags() & kAccFinal) != 0;
+    }
+
+   public:
+    uint32_t index_ = 0u;
+    uint32_t access_flags_ = 0u;
+  };
+
+ public:
+  // A decoded version of the method of a class_data_item.
+  class Method : public BaseItem {
+   public:
     uint32_t GetCodeItemOffset() const {
       return code_off_;
     }
 
+    InvokeType GetInvokeType(uint32_t class_access_flags) const {
+      return is_static_or_direct_
+          ? GetDirectMethodInvokeType()
+          : GetVirtualMethodInvokeType(class_access_flags);
+    }
+
+    MethodReference GetReference() const {
+      return MethodReference(&dex_file_, GetIndex());
+    }
+
     CodeItemInstructionAccessor GetInstructions() const;
 
+    const DexFile::CodeItem* GetCodeItem() const;
+
    private:
-    explicit Method(const DexFile& dex_file) : dex_file_(dex_file) {}
+    explicit Method(const DexFile& dex_file, bool is_static_or_direct)
+        : dex_file_(dex_file),
+          is_static_or_direct_(is_static_or_direct) {}
 
     const uint8_t* Read(const uint8_t* ptr);
 
-    // A decoded version of the method of a class_data_item.
+    InvokeType GetDirectMethodInvokeType() const {
+      return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect;
+    }
+
+    InvokeType GetVirtualMethodInvokeType(uint32_t class_access_flags) const {
+      DCHECK_EQ(GetAccessFlags() & kAccStatic, 0U);
+      if ((class_access_flags & kAccInterface) != 0) {
+        return kInterface;
+      } else if ((GetAccessFlags() & kAccConstructor) != 0) {
+        return kSuper;
+      } else {
+        return kVirtual;
+      }
+    }
+
     const DexFile& dex_file_;
-    uint32_t method_idx_ = 0u;
-    uint32_t access_flags_ = 0u;
+    const bool is_static_or_direct_;
     uint32_t code_off_ = 0u;
 
     friend class ClassAccessor;
   };
 
-  // Class field data.
-  class Field {
-   public:
-    uint32_t GetIndex() const {
-      return field_idx_;
-    }
-
-    uint32_t GetAccessFlags() const {
-      return access_flags_;
-    }
-
+  // A decoded version of the field of a class_data_item.
+  class Field : public BaseItem {
    private:
     const uint8_t* Read(const uint8_t* ptr);
 
-    // A decoded version of the field of a class_data_item.
-    uint32_t field_idx_ = 0u;
-    uint32_t access_flags_ = 0u;
-
     friend class ClassAccessor;
   };
 
@@ -89,20 +118,27 @@
   const DexFile::CodeItem* GetCodeItem(const Method& method) const;
 
   // Iterator data is not very iterator friendly, use visitors to get around this.
+  // No thread safety analysis since the visitor may require capabilities.
   template <typename StaticFieldVisitor,
             typename InstanceFieldVisitor,
             typename DirectMethodVisitor,
             typename VirtualMethodVisitor>
-  void VisitMethodsAndFields(const StaticFieldVisitor& static_field_visitor,
+  void VisitFieldsAndMethods(const StaticFieldVisitor& static_field_visitor,
                              const InstanceFieldVisitor& instance_field_visitor,
                              const DirectMethodVisitor& direct_method_visitor,
-                             const VirtualMethodVisitor& virtual_method_visitor) const;
+                             const VirtualMethodVisitor& virtual_method_visitor) const
+      NO_THREAD_SAFETY_ANALYSIS;
 
   template <typename DirectMethodVisitor,
             typename VirtualMethodVisitor>
   void VisitMethods(const DirectMethodVisitor& direct_method_visitor,
                     const VirtualMethodVisitor& virtual_method_visitor) const;
 
+  template <typename StaticFieldVisitor,
+            typename InstanceFieldVisitor>
+  void VisitFields(const StaticFieldVisitor& static_field_visitor,
+                   const InstanceFieldVisitor& instance_field_visitor) const;
+
   // Visit direct and virtual methods.
   template <typename MethodVisitor>
   void VisitMethods(const MethodVisitor& method_visitor) const;
@@ -123,11 +159,16 @@
     return num_virtual_methods_;
   }
 
-  // TODO: Deprecate
-  dex::TypeIndex GetDescriptorIndex() const {
+  const char* GetDescriptor() const;
+
+  dex::TypeIndex GetClassIdx() const {
     return descriptor_index_;
   }
 
+  const DexFile& GetDexFile() const {
+    return dex_file_;
+  }
+
  protected:
   const DexFile& dex_file_;
   const dex::TypeIndex descriptor_index_ = {};
diff --git a/libdexfile/dex/dex_instruction_iterator.h b/libdexfile/dex/dex_instruction_iterator.h
index db3ff95..b75a95b 100644
--- a/libdexfile/dex/dex_instruction_iterator.h
+++ b/libdexfile/dex/dex_instruction_iterator.h
@@ -123,7 +123,7 @@
   using DexInstructionIteratorBase::DexInstructionIteratorBase;
 
   explicit DexInstructionIterator(const uint16_t* inst, uint32_t dex_pc)
-      : DexInstructionIteratorBase(Instruction::At(inst), dex_pc) {}
+      : DexInstructionIteratorBase(inst != nullptr ? Instruction::At(inst) : nullptr, dex_pc) {}
 
   explicit DexInstructionIterator(const DexInstructionPcPair& pair)
       : DexInstructionIterator(pair.Instructions(), pair.DexPc()) {}
diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc
index 427a465..312a7b3 100644
--- a/tools/dexanalyze/dexanalyze_experiments.cc
+++ b/tools/dexanalyze/dexanalyze_experiments.cc
@@ -150,7 +150,7 @@
           case Instruction::INVOKE_VIRTUAL_RANGE: {
             bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE);
             uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
-            if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) {
+            if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) {
               ++same_class_virtual_;
             } else {
               ++other_class_virtual_;
@@ -162,7 +162,7 @@
           case Instruction::INVOKE_DIRECT_RANGE: {
             bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
             uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
-            if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) {
+            if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) {
               ++same_class_direct_;
             } else {
               ++other_class_direct_;
@@ -174,7 +174,7 @@
           case Instruction::INVOKE_STATIC_RANGE: {
             bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
             uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
-            if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) {
+            if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetClassIdx()) {
               ++same_class_static_;
             } else {
               ++other_class_static_;