Improve `verified`, add `redefined` class status in VerifierDeps

Changes implementation of `unverified_classes_` in VerifierDeps from
std::set<dex::TypeIndex> to `verified_classes_` of type std::vector<bool>
indexed by class def indices. This cleans up the implementation and speeds
up access during fast-verify. Encoding remains the same - a set of indices
of unverified classes - only these are now class def indices.

A second bit vector `redefined_classes_` is added, also indexed by class
def indices. It records classes that were not verified because they were
eclipsed by classes that took precedence during resolution. This allows
VerifierDeps::VerifyInternalClasses to succeed when a class redefined
now was also redefined when the deps were being created because the
class was treated as external and dependencies on it were recorded.

Test: m test-art-gtest-verifier_deps_test
Change-Id: I7bcbe947c3c74535306e6dbb5b288076f320a7bc
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f39d8fc..54e94d0 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1799,11 +1799,11 @@
   // time. So instead we assume these classes still need to be verified at
   // runtime.
   for (const DexFile* dex_file : dex_files) {
-    // Fetch the list of unverified classes.
-    const std::set<dex::TypeIndex>& unverified_classes =
-        verifier_deps->GetUnverifiedClasses(*dex_file);
+    // Fetch the list of verified classes.
+    const std::vector<bool>& verified_classes = verifier_deps->GetVerifiedClasses(*dex_file);
+    DCHECK_EQ(verified_classes.size(), dex_file->NumClassDefs());
     for (ClassAccessor accessor : dex_file->GetClasses()) {
-      if (unverified_classes.find(accessor.GetClassIdx()) == unverified_classes.end()) {
+      if (verified_classes[accessor.GetClassDefIndex()]) {
         if (compiler_only_verifies) {
           // Just update the compiled_classes_ map. The compiler doesn't need to resolve
           // the type.
@@ -1953,6 +1953,16 @@
       }
     } else if (&klass->GetDexFile() != &dex_file) {
       // Skip a duplicate class (as the resolved class is from another, earlier dex file).
+      // Record the information that we skipped this class in the vdex.
+      // If the class resolved to a dex file not covered by the vdex, e.g. boot class path,
+      // it is considered external, dependencies on it will be recorded and the vdex will
+      // remain usable regardless of whether the class remains redefined or not (in the
+      // latter case, this class will be verify-at-runtime).
+      // On the other hand, if the class resolved to a dex file covered by the vdex, i.e.
+      // a different dex file within the same APK, this class will always be eclipsed by it.
+      // Recording that it was redefined is not necessary but will save class resolution
+      // time during fast-verify.
+      verifier::VerifierDeps::MaybeRecordClassRedefinition(dex_file, class_def);
       return;  // Do not update state.
     } else if (!SkipClass(jclass_loader, dex_file, klass.Get())) {
       CHECK(klass->IsResolved()) << klass->PrettyClass();
@@ -2001,8 +2011,7 @@
       // Make the skip a soft failure, essentially being considered as verify at runtime.
       failure_kind = verifier::FailureKind::kSoftFailure;
     }
-    verifier::VerifierDeps::MaybeRecordVerificationStatus(
-        dex_file, class_def.class_idx_, failure_kind);
+    verifier::VerifierDeps::MaybeRecordVerificationStatus(dex_file, class_def, failure_kind);
     soa.Self()->AssertNoPendingException();
   }