ART: Allow oatstatus verification for app dependencies

Allow taking verification state from the oat file durin compilation
if the class is a dependency (thus not being compiled itself). This
is necessary in case the dependency itself has been quickened and
stripped, as quickened bytecodes are not supported during compile-
time verification.

Expose this through the CompilerCallbacks.

Bug: 72237763
Test: m test-art-host
Change-Id: I9b7d3a353d81a6422c3b145fd5c5b71f36c6f257
diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc
index 540bd0c..baf97a8 100644
--- a/compiler/dex/quick_compiler_callbacks.cc
+++ b/compiler/dex/quick_compiler_callbacks.cc
@@ -17,6 +17,10 @@
 #include "quick_compiler_callbacks.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 "verification_results.h"
 #include "verifier/method_verifier-inl.h"
 
@@ -54,4 +58,15 @@
   }
 }
 
+bool QuickCompilerCallbacks::CanUseOatStatusForVerification(mirror::Class* klass) {
+  // No dex files: conservatively false.
+  if (dex_files_ == nullptr) {
+    return false;
+  }
+
+  // If the class isn't from one of the dex files, accept oat file data.
+  const DexFile* dex_file = &klass->GetDexFile();
+  return std::find(dex_files_->begin(), dex_files_->end(), dex_file) == dex_files_->end();
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick_compiler_callbacks.h b/compiler/dex/quick_compiler_callbacks.h
index 6d22f95..8a07e9c 100644
--- a/compiler/dex/quick_compiler_callbacks.h
+++ b/compiler/dex/quick_compiler_callbacks.h
@@ -23,12 +23,13 @@
 namespace art {
 
 class CompilerDriver;
+class DexFile;
 class VerificationResults;
 
 class QuickCompilerCallbacks FINAL : public CompilerCallbacks {
  public:
   explicit QuickCompilerCallbacks(CompilerCallbacks::CallbackMode mode)
-      : CompilerCallbacks(mode) {}
+      : CompilerCallbacks(mode), dex_files_(nullptr) {}
 
   ~QuickCompilerCallbacks() { }
 
@@ -65,11 +66,19 @@
 
   void UpdateClassState(ClassReference ref, ClassStatus state) OVERRIDE;
 
+  bool CanUseOatStatusForVerification(mirror::Class* klass) OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  void SetDexFiles(const std::vector<const DexFile*>* dex_files) {
+    dex_files_ = dex_files;
+  }
+
  private:
   VerificationResults* verification_results_ = nullptr;
   bool does_class_unloading_ = false;
   CompilerDriver* compiler_driver_ = nullptr;
   std::unique_ptr<verifier::VerifierDeps> verifier_deps_;
+  const std::vector<const DexFile*>* dex_files_;
 };
 
 }  // namespace art
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 7796b3a..34ba4b3 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1829,6 +1829,7 @@
     jobject class_loader = nullptr;
     if (!IsBootImage()) {
       class_loader = class_loader_context_->CreateClassLoader(dex_files_);
+      callbacks_->SetDexFiles(&dex_files);
     }
 
     // Register dex caches and key them to the class loader so that they only unload when the
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b61fb4a..af45a69 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4252,17 +4252,16 @@
                                           ClassStatus& oat_file_class_status) {
   // If we're compiling, we can only verify the class using the oat file if
   // we are not compiling the image or if the class we're verifying is not part of
-  // the app.  In other words, we will only check for preverification of bootclasspath
-  // classes.
+  // the compilation unit (app - dependencies). We will let the compiler callback
+  // tell us about the latter.
   if (Runtime::Current()->IsAotCompiler()) {
+    CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
     // Are we compiling the bootclasspath?
-    if (Runtime::Current()->GetCompilerCallbacks()->IsBootImage()) {
+    if (callbacks->IsBootImage()) {
       return false;
     }
     // We are compiling an app (not the image).
-
-    // Is this an app class? (I.e. not a bootclasspath class)
-    if (klass->GetClassLoader() != nullptr) {
+    if (!callbacks->CanUseOatStatusForVerification(klass.Ptr())) {
       return false;
     }
   }
diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h
index 4560bca..8395966 100644
--- a/runtime/compiler_callbacks.h
+++ b/runtime/compiler_callbacks.h
@@ -25,6 +25,12 @@
 
 class CompilerDriver;
 
+namespace mirror {
+
+class Class;
+
+}  // namespace mirror
+
 namespace verifier {
 
 class MethodVerifier;
@@ -68,6 +74,11 @@
   virtual void UpdateClassState(ClassReference ref ATTRIBUTE_UNUSED,
                                 ClassStatus state ATTRIBUTE_UNUSED) {}
 
+  virtual bool CanUseOatStatusForVerification(mirror::Class* klass ATTRIBUTE_UNUSED)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    return false;
+  }
+
  protected:
   explicit CompilerCallbacks(CallbackMode mode) : mode_(mode) { }