ART: Add ClassVerifier

Remove class handling from MethodVerifier.

Test: m test-art-host
Change-Id: I0e125e0c8a852936ed7cff0f349a7fde97f62826
diff --git a/dex2oat/dex/dex_to_dex_decompiler_test.cc b/dex2oat/dex/dex_to_dex_decompiler_test.cc
index b5525dc..9d65436 100644
--- a/dex2oat/dex/dex_to_dex_decompiler_test.cc
+++ b/dex2oat/dex/dex_to_dex_decompiler_test.cc
@@ -31,7 +31,6 @@
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread.h"
-#include "verifier/method_verifier-inl.h"
 #include "verifier/verifier_deps.h"
 
 namespace art {
diff --git a/dex2oat/dex/quick_compiler_callbacks.cc b/dex2oat/dex/quick_compiler_callbacks.cc
index c277f03..f6f8267 100644
--- a/dex2oat/dex/quick_compiler_callbacks.cc
+++ b/dex2oat/dex/quick_compiler_callbacks.cc
@@ -19,10 +19,6 @@
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
 #include "mirror/class-inl.h"
-#include "mirror/object.h"
-#include "obj_ptr-inl.h"
-#include "thread-current-inl.h"
-#include "verifier/method_verifier-inl.h"
 
 namespace art {
 
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index b73a7d8..520b455 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -85,8 +85,7 @@
 #include "utils/dex_cache_arrays_layout-inl.h"
 #include "utils/swap_space.h"
 #include "vdex_file.h"
-#include "verifier/method_verifier-inl.h"
-#include "verifier/method_verifier.h"
+#include "verifier/class_verifier.h"
 #include "verifier/verifier_deps.h"
 #include "verifier/verifier_enums.h"
 
@@ -1884,16 +1883,16 @@
           soa.Self(), dex_file)));
       std::string error_msg;
       failure_kind =
-          verifier::MethodVerifier::VerifyClass(soa.Self(),
-                                                &dex_file,
-                                                dex_cache,
-                                                class_loader,
-                                                class_def,
-                                                Runtime::Current()->GetCompilerCallbacks(),
-                                                true /* allow soft failures */,
-                                                log_level_,
-                                                sdk_version_,
-                                                &error_msg);
+          verifier::ClassVerifier::VerifyClass(soa.Self(),
+                                               &dex_file,
+                                               dex_cache,
+                                               class_loader,
+                                               class_def,
+                                               Runtime::Current()->GetCompilerCallbacks(),
+                                               true /* allow soft failures */,
+                                               log_level_,
+                                               sdk_version_,
+                                               &error_msg);
       if (failure_kind == verifier::FailureKind::kHardFailure) {
         LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor)
                    << " because: " << error_msg;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index e51ae4d..b500130 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -80,7 +80,7 @@
 #include "ti_breakpoint.h"
 #include "ti_class_loader.h"
 #include "transform.h"
-#include "verifier/method_verifier.h"
+#include "verifier/class_verifier.h"
 #include "verifier/verifier_enums.h"
 
 namespace openjdkjvmti {
@@ -1119,17 +1119,17 @@
   std::string error;
   // TODO Make verification log level lower
   art::verifier::FailureKind failure =
-      art::verifier::MethodVerifier::VerifyClass(driver_->self_,
-                                                 dex_file_.get(),
-                                                 hs.NewHandle(iter.GetNewDexCache()),
-                                                 hs.NewHandle(GetClassLoader()),
-                                                 /*class_def=*/ dex_file_->GetClassDef(0),
-                                                 /*callbacks=*/ nullptr,
-                                                 /*allow_soft_failures=*/ true,
-                                                 /*log_level=*/
-                                                 art::verifier::HardFailLogMode::kLogWarning,
-                                                 art::Runtime::Current()->GetTargetSdkVersion(),
-                                                 &error);
+      art::verifier::ClassVerifier::VerifyClass(driver_->self_,
+                                                dex_file_.get(),
+                                                hs.NewHandle(iter.GetNewDexCache()),
+                                                hs.NewHandle(GetClassLoader()),
+                                                /*class_def=*/ dex_file_->GetClassDef(0),
+                                                /*callbacks=*/ nullptr,
+                                                /*allow_soft_failures=*/ true,
+                                                /*log_level=*/
+                                                art::verifier::HardFailLogMode::kLogWarning,
+                                                art::Runtime::Current()->GetTargetSdkVersion(),
+                                                &error);
   switch (failure) {
     case art::verifier::FailureKind::kNoFailure:
     case art::verifier::FailureKind::kSoftFailure:
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 2170e95..56c84a6 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -203,6 +203,7 @@
         "transaction.cc",
         "var_handles.cc",
         "vdex_file.cc",
+        "verifier/class_verifier.cc",
         "verifier/instruction_flags.cc",
         "verifier/method_verifier.cc",
         "verifier/reg_type.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e5dcc0d..4364590 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -133,7 +133,7 @@
 #include "thread_list.h"
 #include "trace.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
-#include "verifier/method_verifier.h"
+#include "verifier/class_verifier.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -900,7 +900,7 @@
   // initialize the StackOverflowError class (as it might require running the verifier). Instead,
   // ensure that the class will be initialized.
   if (kMemoryToolIsAvailable && !Runtime::Current()->IsAotCompiler()) {
-    verifier::MethodVerifier::Init();  // Need to prepare the verifier.
+    verifier::ClassVerifier::Init();  // Need to prepare the verifier.
 
     ObjPtr<mirror::Class> soe_klass = FindSystemClass(self, "Ljava/lang/StackOverflowError;");
     if (soe_klass == nullptr || !EnsureInitialized(self, hs.NewHandle(soe_klass), true, true)) {
@@ -4608,13 +4608,13 @@
                                                             verifier::HardFailLogMode log_level,
                                                             std::string* error_msg) {
   Runtime* const runtime = Runtime::Current();
-  return verifier::MethodVerifier::VerifyClass(self,
-                                               klass.Get(),
-                                               runtime->GetCompilerCallbacks(),
-                                               runtime->IsAotCompiler(),
-                                               log_level,
-                                               Runtime::Current()->GetTargetSdkVersion(),
-                                               error_msg);
+  return verifier::ClassVerifier::VerifyClass(self,
+                                              klass.Get(),
+                                              runtime->GetCompilerCallbacks(),
+                                              runtime->IsAotCompiler(),
+                                              log_level,
+                                              Runtime::Current()->GetTargetSdkVersion(),
+                                              error_msg);
 }
 
 bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 499bf28..a1168af 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -35,8 +35,6 @@
 #include "nativehelper/scoped_local_ref.h"
 #include "obj_ptr-inl.h"
 #include "thread.h"
-#include "vdex_file.h"
-#include "verifier/method_verifier.h"
 #include "well_known_classes.h"
 
 namespace art {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 0d32e0b..d698d48 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -162,7 +162,7 @@
 #include "trace.h"
 #include "transaction.h"
 #include "vdex_file.h"
-#include "verifier/method_verifier.h"
+#include "verifier/class_verifier.h"
 #include "well_known_classes.h"
 
 #ifdef ART_TARGET_ANDROID
@@ -464,7 +464,7 @@
   delete oat_file_manager_;
   Thread::Shutdown();
   QuasiAtomic::Shutdown();
-  verifier::MethodVerifier::Shutdown();
+  verifier::ClassVerifier::Shutdown();
 
   // Destroy allocators before shutting down the MemMap because they may use it.
   java_vm_.reset();
@@ -1541,7 +1541,7 @@
 
   CHECK(class_linker_ != nullptr);
 
-  verifier::MethodVerifier::Init();
+  verifier::ClassVerifier::Init();
 
   if (runtime_options.Exists(Opt::MethodTrace)) {
     trace_config_.reset(new TraceConfig());
@@ -2096,7 +2096,7 @@
       .VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
   pre_allocated_NoClassDefFoundError_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
   VisitImageRoots(visitor);
-  verifier::MethodVerifier::VisitStaticRoots(visitor);
+  verifier::ClassVerifier::VisitStaticRoots(visitor);
   VisitTransactionRoots(visitor);
 }
 
diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc
new file mode 100644
index 0000000..649fb11
--- /dev/null
+++ b/runtime/verifier/class_verifier.cc
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_verifier.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "art_method-inl.h"
+#include "base/systrace.h"
+#include "base/utils.h"
+#include "class_linker.h"
+#include "compiler_callbacks.h"
+#include "dex/class_accessor-inl.h"
+#include "dex/class_reference.h"
+#include "dex/descriptors_names.h"
+#include "dex/dex_file-inl.h"
+#include "handle_scope-inl.h"
+#include "method_verifier-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/dex_cache.h"
+#include "runtime.h"
+
+namespace art {
+namespace verifier {
+
+using android::base::StringPrintf;
+
+// We print a warning blurb about "dx --no-optimize" when we find monitor-locking issues. Make
+// sure we only print this once.
+static bool gPrintedDxMonitorText = false;
+
+FailureKind ClassVerifier::VerifyClass(Thread* self,
+                                       ObjPtr<mirror::Class> klass,
+                                       CompilerCallbacks* callbacks,
+                                       bool allow_soft_failures,
+                                       HardFailLogMode log_level,
+                                       uint32_t api_level,
+                                       std::string* error) {
+  if (klass->IsVerified()) {
+    return FailureKind::kNoFailure;
+  }
+  bool early_failure = false;
+  std::string failure_message;
+  const DexFile& dex_file = klass->GetDexFile();
+  const dex::ClassDef* class_def = klass->GetClassDef();
+  ObjPtr<mirror::Class> super = klass->GetSuperClass();
+  std::string temp;
+  if (super == nullptr && strcmp("Ljava/lang/Object;", klass->GetDescriptor(&temp)) != 0) {
+    early_failure = true;
+    failure_message = " that has no super class";
+  } else if (super != nullptr && super->IsFinal()) {
+    early_failure = true;
+    failure_message = " that attempts to sub-class final class " + super->PrettyDescriptor();
+  } else if (class_def == nullptr) {
+    early_failure = true;
+    failure_message = " that isn't present in dex file " + dex_file.GetLocation();
+  }
+  if (early_failure) {
+    *error = "Verifier rejected class " + klass->PrettyDescriptor() + failure_message;
+    if (callbacks != nullptr) {
+      ClassReference ref(&dex_file, klass->GetDexClassDefIndex());
+      callbacks->ClassRejected(ref);
+    }
+    return FailureKind::kHardFailure;
+  }
+  StackHandleScope<2> hs(self);
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+  return VerifyClass(self,
+                     &dex_file,
+                     dex_cache,
+                     class_loader,
+                     *class_def,
+                     callbacks,
+                     allow_soft_failures,
+                     log_level,
+                     api_level,
+                     error);
+}
+
+FailureKind ClassVerifier::VerifyClass(Thread* self,
+                                       const DexFile* dex_file,
+                                       Handle<mirror::DexCache> dex_cache,
+                                       Handle<mirror::ClassLoader> class_loader,
+                                       const dex::ClassDef& class_def,
+                                       CompilerCallbacks* callbacks,
+                                       bool allow_soft_failures,
+                                       HardFailLogMode log_level,
+                                       uint32_t api_level,
+                                       std::string* error) {
+  // A class must not be abstract and final.
+  if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
+    *error = "Verifier rejected class ";
+    *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+    *error += ": class is abstract and final.";
+    return FailureKind::kHardFailure;
+  }
+
+  ClassAccessor accessor(*dex_file, class_def);
+  SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(accessor.GetDescriptor());
+
+  int64_t previous_method_idx[2] = { -1, -1 };
+  MethodVerifier::FailureData failure_data;
+  ClassLinker* const linker = Runtime::Current()->GetClassLinker();
+
+  for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+    int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u];
+    self->AllowThreadSuspension();
+    const uint32_t method_idx = method.GetIndex();
+    if (method_idx == *previous_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
+      continue;
+    }
+    *previous_idx = method_idx;
+    const InvokeType type = method.GetInvokeType(class_def.access_flags_);
+    ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
+        method_idx, dex_cache, class_loader, /* referrer= */ nullptr, type);
+    if (resolved_method == nullptr) {
+      DCHECK(self->IsExceptionPending());
+      // We couldn't resolve the method, but continue regardless.
+      self->ClearException();
+    } else {
+      DCHECK(resolved_method->GetDeclaringClassUnchecked() != nullptr) << type;
+    }
+    std::string hard_failure_msg;
+    MethodVerifier::FailureData result =
+        MethodVerifier::VerifyMethod(self,
+                                     method_idx,
+                                     dex_file,
+                                     dex_cache,
+                                     class_loader,
+                                     class_def,
+                                     method.GetCodeItem(),
+                                     resolved_method,
+                                     method.GetAccessFlags(),
+                                     callbacks,
+                                     allow_soft_failures,
+                                     log_level,
+                                     /*need_precise_constants=*/ false,
+                                     api_level,
+                                     &hard_failure_msg);
+    if (result.kind == FailureKind::kHardFailure) {
+      if (failure_data.kind == FailureKind::kHardFailure) {
+        // If we logged an error before, we need a newline.
+        *error += "\n";
+      } else {
+        // If we didn't log a hard failure before, print the header of the message.
+        *error += "Verifier rejected class ";
+        *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+        *error += ":";
+      }
+      *error += " ";
+      *error += hard_failure_msg;
+    }
+    failure_data.Merge(result);
+  }
+
+  if (failure_data.kind == FailureKind::kNoFailure) {
+    return FailureKind::kNoFailure;
+  } else {
+    if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) {
+      // Print a warning about expected slow-down. Use a string temporary to print one contiguous
+      // warning.
+      std::string tmp =
+          StringPrintf("Class %s failed lock verification and will run slower.",
+                       PrettyDescriptor(accessor.GetDescriptor()).c_str());
+      if (!gPrintedDxMonitorText) {
+        tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n"
+                    "and incorrect proguard optimizations.";
+        gPrintedDxMonitorText = true;
+      }
+      LOG(WARNING) << tmp;
+    }
+    return failure_data.kind;
+  }
+}
+
+void ClassVerifier::Init() {
+  MethodVerifier::Init();
+}
+
+void ClassVerifier::Shutdown() {
+  MethodVerifier::Shutdown();
+}
+
+void ClassVerifier::VisitStaticRoots(RootVisitor* visitor) {
+  MethodVerifier::VisitStaticRoots(visitor);
+}
+
+}  // namespace verifier
+}  // namespace art
diff --git a/runtime/verifier/class_verifier.h b/runtime/verifier/class_verifier.h
new file mode 100644
index 0000000..b7d3850
--- /dev/null
+++ b/runtime/verifier/class_verifier.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_VERIFIER_CLASS_VERIFIER_H_
+#define ART_RUNTIME_VERIFIER_CLASS_VERIFIER_H_
+
+#include <string>
+
+#include <android-base/macros.h>
+#include <android-base/thread_annotations.h>
+
+#include "base/locks.h"
+#include "handle.h"
+#include "obj_ptr.h"
+#include "verifier_enums.h"
+
+namespace art {
+
+class CompilerCallbacks;
+class DexFile;
+class RootVisitor;
+class Thread;
+
+namespace dex {
+struct ClassDef;
+}  // namespace dex
+
+namespace mirror {
+class Class;
+class DexCache;
+class ClassLoader;
+}  // namespace mirror
+
+namespace verifier {
+
+// Verifier that ensures the complete class is OK.
+class ClassVerifier {
+ public:
+  // Verify a class. Returns "kNoFailure" on success.
+  static FailureKind VerifyClass(Thread* self,
+                                 ObjPtr<mirror::Class> klass,
+                                 CompilerCallbacks* callbacks,
+                                 bool allow_soft_failures,
+                                 HardFailLogMode log_level,
+                                 uint32_t api_level,
+                                 std::string* error)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  static FailureKind VerifyClass(Thread* self,
+                                 const DexFile* dex_file,
+                                 Handle<mirror::DexCache> dex_cache,
+                                 Handle<mirror::ClassLoader> class_loader,
+                                 const dex::ClassDef& class_def,
+                                 CompilerCallbacks* callbacks,
+                                 bool allow_soft_failures,
+                                 HardFailLogMode log_level,
+                                 uint32_t api_level,
+                                 std::string* error)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  static void Init() REQUIRES_SHARED(Locks::mutator_lock_);
+  static void Shutdown();
+
+  static void VisitStaticRoots(RootVisitor* visitor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ClassVerifier);
+};
+
+}  // namespace verifier
+}  // namespace art
+
+#endif  // ART_RUNTIME_VERIFIER_CLASS_VERIFIER_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 91eba21..f32dd73 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -73,10 +73,6 @@
 // On VLOG(verifier), should we dump the whole state when we run into a hard failure?
 static constexpr bool kDumpRegLinesOnHardFailureIfVLOG = true;
 
-// We print a warning blurb about "dx --no-optimize" when we find monitor-locking issues. Make
-// sure we only print this once.
-static bool gPrintedDxMonitorText = false;
-
 PcToRegisterLineTable::PcToRegisterLineTable(ScopedArenaAllocator& allocator)
     : register_lines_(allocator.Adapter(kArenaAllocVerifier)) {}
 
@@ -145,55 +141,6 @@
   reg_line->MarkAllRegistersAsConflicts(verifier);
 }
 
-FailureKind MethodVerifier::VerifyClass(Thread* self,
-                                        ObjPtr<mirror::Class> klass,
-                                        CompilerCallbacks* callbacks,
-                                        bool allow_soft_failures,
-                                        HardFailLogMode log_level,
-                                        uint32_t api_level,
-                                        std::string* error) {
-  if (klass->IsVerified()) {
-    return FailureKind::kNoFailure;
-  }
-  bool early_failure = false;
-  std::string failure_message;
-  const DexFile& dex_file = klass->GetDexFile();
-  const dex::ClassDef* class_def = klass->GetClassDef();
-  ObjPtr<mirror::Class> super = klass->GetSuperClass();
-  std::string temp;
-  if (super == nullptr && strcmp("Ljava/lang/Object;", klass->GetDescriptor(&temp)) != 0) {
-    early_failure = true;
-    failure_message = " that has no super class";
-  } else if (super != nullptr && super->IsFinal()) {
-    early_failure = true;
-    failure_message = " that attempts to sub-class final class " + super->PrettyDescriptor();
-  } else if (class_def == nullptr) {
-    early_failure = true;
-    failure_message = " that isn't present in dex file " + dex_file.GetLocation();
-  }
-  if (early_failure) {
-    *error = "Verifier rejected class " + klass->PrettyDescriptor() + failure_message;
-    if (callbacks != nullptr) {
-      ClassReference ref(&dex_file, klass->GetDexClassDefIndex());
-      callbacks->ClassRejected(ref);
-    }
-    return FailureKind::kHardFailure;
-  }
-  StackHandleScope<2> hs(self);
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
-  return VerifyClass(self,
-                     &dex_file,
-                     dex_cache,
-                     class_loader,
-                     *class_def,
-                     callbacks,
-                     allow_soft_failures,
-                     log_level,
-                     api_level,
-                     error);
-}
-
 static FailureKind FailureKindMax(FailureKind fk1, FailureKind fk2) {
   static_assert(FailureKind::kNoFailure < FailureKind::kSoftFailure
                     && FailureKind::kSoftFailure < FailureKind::kHardFailure,
@@ -206,103 +153,6 @@
   types |= fd.types;
 }
 
-FailureKind MethodVerifier::VerifyClass(Thread* self,
-                                        const DexFile* dex_file,
-                                        Handle<mirror::DexCache> dex_cache,
-                                        Handle<mirror::ClassLoader> class_loader,
-                                        const dex::ClassDef& class_def,
-                                        CompilerCallbacks* callbacks,
-                                        bool allow_soft_failures,
-                                        HardFailLogMode log_level,
-                                        uint32_t api_level,
-                                        std::string* error) {
-  // A class must not be abstract and final.
-  if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) {
-    *error = "Verifier rejected class ";
-    *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
-    *error += ": class is abstract and final.";
-    return FailureKind::kHardFailure;
-  }
-
-  ClassAccessor accessor(*dex_file, class_def);
-  SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(accessor.GetDescriptor());
-
-  int64_t previous_method_idx[2] = { -1, -1 };
-  MethodVerifier::FailureData failure_data;
-  ClassLinker* const linker = Runtime::Current()->GetClassLinker();
-
-  for (const ClassAccessor::Method& method : accessor.GetMethods()) {
-    int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u];
-    self->AllowThreadSuspension();
-    const uint32_t method_idx = method.GetIndex();
-    if (method_idx == *previous_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
-      continue;
-    }
-    *previous_idx = method_idx;
-    const InvokeType type = method.GetInvokeType(class_def.access_flags_);
-    ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
-        method_idx, dex_cache, class_loader, /* referrer= */ nullptr, type);
-    if (resolved_method == nullptr) {
-      DCHECK(self->IsExceptionPending());
-      // We couldn't resolve the method, but continue regardless.
-      self->ClearException();
-    } else {
-      DCHECK(resolved_method->GetDeclaringClassUnchecked() != nullptr) << type;
-    }
-    std::string hard_failure_msg;
-    MethodVerifier::FailureData result = VerifyMethod(self,
-                                                      method_idx,
-                                                      dex_file,
-                                                      dex_cache,
-                                                      class_loader,
-                                                      class_def,
-                                                      method.GetCodeItem(),
-                                                      resolved_method,
-                                                      method.GetAccessFlags(),
-                                                      callbacks,
-                                                      allow_soft_failures,
-                                                      log_level,
-                                                      /*need_precise_constants=*/ false,
-                                                      api_level,
-                                                      &hard_failure_msg);
-    if (result.kind == FailureKind::kHardFailure) {
-      if (failure_data.kind == FailureKind::kHardFailure) {
-        // If we logged an error before, we need a newline.
-        *error += "\n";
-      } else {
-        // If we didn't log a hard failure before, print the header of the message.
-        *error += "Verifier rejected class ";
-        *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
-        *error += ":";
-      }
-      *error += " ";
-      *error += hard_failure_msg;
-    }
-    failure_data.Merge(result);
-  }
-
-  if (failure_data.kind == FailureKind::kNoFailure) {
-    return FailureKind::kNoFailure;
-  } else {
-    if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) {
-      // Print a warning about expected slow-down. Use a string temporary to print one contiguous
-      // warning.
-      std::string tmp =
-          StringPrintf("Class %s failed lock verification and will run slower.",
-                       PrettyDescriptor(accessor.GetDescriptor()).c_str());
-      if (!gPrintedDxMonitorText) {
-        tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n"
-                    "and incorrect proguard optimizations.";
-        gPrintedDxMonitorText = true;
-      }
-      LOG(WARNING) << tmp;
-    }
-    return failure_data.kind;
-  }
-}
-
 static bool IsLargeMethod(const CodeItemDataAccessor& accessor) {
   if (!accessor.HasCodeItem()) {
     return false;
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index c178df0..92abe9b 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -99,27 +99,6 @@
 // The verifier
 class MethodVerifier {
  public:
-  // Verify a class. Returns "kNoFailure" on success.
-  static FailureKind VerifyClass(Thread* self,
-                                 ObjPtr<mirror::Class> klass,
-                                 CompilerCallbacks* callbacks,
-                                 bool allow_soft_failures,
-                                 HardFailLogMode log_level,
-                                 uint32_t api_level,
-                                 std::string* error)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static FailureKind VerifyClass(Thread* self,
-                                 const DexFile* dex_file,
-                                 Handle<mirror::DexCache> dex_cache,
-                                 Handle<mirror::ClassLoader> class_loader,
-                                 const dex::ClassDef& class_def,
-                                 CompilerCallbacks* callbacks,
-                                 bool allow_soft_failures,
-                                 HardFailLogMode log_level,
-                                 uint32_t api_level,
-                                 std::string* error)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   static MethodVerifier* VerifyMethodAndDump(Thread* self,
                                              VariableIndentationOutputStream* vios,
                                              uint32_t method_idx,
@@ -807,6 +786,7 @@
   const uint32_t api_level_;
 
   friend class art::Thread;
+  friend class ClassVerifier;
   friend class VerifierDepsTest;
 
   DISALLOW_COPY_AND_ASSIGN(MethodVerifier);
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 09171a4..e56cde9 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -23,6 +23,7 @@
 
 #include "base/utils.h"
 #include "class_linker-inl.h"
+#include "class_verifier.h"
 #include "common_runtime_test.h"
 #include "dex/dex_file-inl.h"
 #include "scoped_thread_state_change-inl.h"
@@ -41,7 +42,7 @@
 
     // Verify the class
     std::string error_msg;
-    FailureKind failure = MethodVerifier::VerifyClass(
+    FailureKind failure = ClassVerifier::VerifyClass(
         self, klass, nullptr, true, HardFailLogMode::kLogWarning, /* api_level= */ 0u, &error_msg);
 
     if (android::base::StartsWith(descriptor, "Ljava/lang/invoke")) {
diff --git a/tools/art_verifier/art_verifier.cc b/tools/art_verifier/art_verifier.cc
index b4aa678..6fe27d6 100644
--- a/tools/art_verifier/art_verifier.cc
+++ b/tools/art_verifier/art_verifier.cc
@@ -30,7 +30,7 @@
 #include "mirror/dex_cache-inl.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
-#include "verifier/method_verifier.h"
+#include "verifier/class_verifier.h"
 #include "well_known_classes.h"
 
 #include <sys/stat.h>
@@ -246,13 +246,13 @@
           }
           std::string error_msg;
           verifier::FailureKind res =
-            verifier::MethodVerifier::VerifyClass(soa.Self(),
-                                                  h_klass.Get(),
-                                                  runtime->GetCompilerCallbacks(),
-                                                  true,
-                                                  verifier::HardFailLogMode::kLogWarning,
-                                                  args_->api_level_,
-                                                  &error_msg);
+            verifier::ClassVerifier::VerifyClass(soa.Self(),
+                                                 h_klass.Get(),
+                                                 runtime->GetCompilerCallbacks(),
+                                                 true,
+                                                 verifier::HardFailLogMode::kLogWarning,
+                                                 args_->api_level_,
+                                                 &error_msg);
           if (args_->repetitions_ == 0) {
             LOG(INFO) << descriptor << ": " << res << " " << error_msg;
           }