ART: Add API level to verifier

Pass API level to verifier. In preparation for API-level dependent
checks.

Bug: 111969862
Test: m test-art-host
Change-Id: I700ef52e28436a7fda8b9d9ef29841110ed6d3bb
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 6eca304..3f28aa7 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1886,7 +1886,9 @@
 class VerifyClassVisitor : public CompilationVisitor {
  public:
   VerifyClassVisitor(const ParallelCompilationManager* manager, verifier::HardFailLogMode log_level)
-     : manager_(manager), log_level_(log_level) {}
+     : manager_(manager),
+       log_level_(log_level),
+       sdk_version_(Runtime::Current()->GetTargetSdkVersion()) {}
 
   virtual void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
     ScopedTrace trace(__FUNCTION__);
@@ -1923,6 +1925,7 @@
                                                 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)
@@ -1995,6 +1998,7 @@
  private:
   const ParallelCompilationManager* const manager_;
   const verifier::HardFailLogMode log_level_;
+  const uint32_t sdk_version_;
 };
 
 void CompilerDriver::VerifyDexFile(jobject class_loader,
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index c223549..5d76329 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -178,7 +178,8 @@
                                 true /* allow_soft_failures */,
                                 true /* need_precise_constants */,
                                 false /* verify to dump */,
-                                true /* allow_thread_suspension */);
+                                true /* allow_thread_suspension */,
+                                0 /* api_level */);
         verifier.Verify();
         soa.Self()->SetVerifierDeps(nullptr);
         has_failures = verifier.HasFailures();
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index a5cc38b..b6bfec6 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1474,7 +1474,7 @@
       }
       return verifier::MethodVerifier::VerifyMethodAndDump(
           soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
-          class_def, code_item, method, method_access_flags);
+          class_def, code_item, method, method_access_flags, /* api_level */ 0);
     }
 
     return nullptr;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 8707e27..f8c1172 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -1122,6 +1122,7 @@
                                                  true, /*allow_soft_failures*/
                                                  /*log_level*/
                                                  art::verifier::HardFailLogMode::kLogWarning,
+                                                 art::Runtime::Current()->GetTargetSdkVersion(),
                                                  &error);
   switch (failure) {
     case art::verifier::FailureKind::kNoFailure:
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f80d34c..bc28a66 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4169,6 +4169,7 @@
                                                runtime->GetCompilerCallbacks(),
                                                runtime->IsAotCompiler(),
                                                log_level,
+                                               Runtime::Current()->GetTargetSdkVersion(),
                                                error_msg);
 }
 
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index d47bc0d..7eabe1d 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1401,7 +1401,10 @@
   // Ask the verifier for the dex pcs of all the monitor-enter instructions corresponding to
   // the locks held in this stack frame.
   std::vector<verifier::MethodVerifier::DexLockInfo> monitor_enter_dex_pcs;
-  verifier::MethodVerifier::FindLocksAtDexPc(m, dex_pc, &monitor_enter_dex_pcs);
+  verifier::MethodVerifier::FindLocksAtDexPc(m,
+                                             dex_pc,
+                                             &monitor_enter_dex_pcs,
+                                             Runtime::Current()->GetTargetSdkVersion());
   for (verifier::MethodVerifier::DexLockInfo& dex_lock_info : monitor_enter_dex_pcs) {
     // As a debug check, check that dex PC corresponds to a monitor-enter.
     if (kIsDebugBuild) {
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index a1b8938..2064fc4 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -149,6 +149,7 @@
                                         CompilerCallbacks* callbacks,
                                         bool allow_soft_failures,
                                         HardFailLogMode log_level,
+                                        uint32_t api_level,
                                         std::string* error) {
   if (klass->IsVerified()) {
     return FailureKind::kNoFailure;
@@ -188,6 +189,7 @@
                      callbacks,
                      allow_soft_failures,
                      log_level,
+                     api_level,
                      error);
 }
 
@@ -211,6 +213,7 @@
                                         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)) {
@@ -261,6 +264,7 @@
                                                       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) {
@@ -322,6 +326,7 @@
                                                          bool allow_soft_failures,
                                                          HardFailLogMode log_level,
                                                          bool need_precise_constants,
+                                                         uint32_t api_level,
                                                          std::string* hard_failure_msg) {
   MethodVerifier::FailureData result;
   uint64_t start_ns = kTimeVerifyMethod ? NanoTime() : 0;
@@ -339,7 +344,8 @@
                           allow_soft_failures,
                           need_precise_constants,
                           false /* verify to dump */,
-                          true /* allow_thread_suspension */);
+                          true /* allow_thread_suspension */,
+                          api_level);
   if (verifier.Verify()) {
     // Verification completed, however failures may be pending that didn't cause the verification
     // to hard fail.
@@ -458,7 +464,8 @@
                                                     const DexFile::ClassDef& class_def,
                                                     const DexFile::CodeItem* code_item,
                                                     ArtMethod* method,
-                                                    uint32_t method_access_flags) {
+                                                    uint32_t method_access_flags,
+                                                    uint32_t api_level) {
   MethodVerifier* verifier = new MethodVerifier(self,
                                                 dex_file,
                                                 dex_cache,
@@ -472,7 +479,8 @@
                                                 true /* allow_soft_failures */,
                                                 true /* need_precise_constants */,
                                                 true /* verify_to_dump */,
-                                                true /* allow_thread_suspension */);
+                                                true /* allow_thread_suspension */,
+                                                api_level);
   verifier->Verify();
   verifier->DumpFailures(vios->Stream());
   vios->Stream() << verifier->info_messages_.str();
@@ -500,7 +508,8 @@
                                bool allow_soft_failures,
                                bool need_precise_constants,
                                bool verify_to_dump,
-                               bool allow_thread_suspension)
+                               bool allow_thread_suspension,
+                               uint32_t api_level)
     : self_(self),
       arena_stack_(Runtime::Current()->GetArenaPool()),
       allocator_(&arena_stack_),
@@ -534,7 +543,8 @@
       verify_to_dump_(verify_to_dump),
       allow_thread_suspension_(allow_thread_suspension),
       is_constructor_(false),
-      link_(nullptr) {
+      link_(nullptr),
+      api_level_(api_level == 0 ? std::numeric_limits<uint32_t>::max() : api_level) {
   self->PushVerifier(this);
 }
 
@@ -546,7 +556,8 @@
 void MethodVerifier::FindLocksAtDexPc(
     ArtMethod* m,
     uint32_t dex_pc,
-    std::vector<MethodVerifier::DexLockInfo>* monitor_enter_dex_pcs) {
+    std::vector<MethodVerifier::DexLockInfo>* monitor_enter_dex_pcs,
+    uint32_t api_level) {
   StackHandleScope<2> hs(Thread::Current());
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache()));
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader()));
@@ -563,7 +574,8 @@
                           true  /* allow_soft_failures */,
                           false /* need_precise_constants */,
                           false /* verify_to_dump */,
-                          false /* allow_thread_suspension */);
+                          false /* allow_thread_suspension */,
+                          api_level);
   verifier.interesting_dex_pc_ = dex_pc;
   verifier.monitor_enter_dex_pcs_ = monitor_enter_dex_pcs;
   verifier.FindLocksAtDexPc();
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 9890af9..eef2280 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -100,6 +100,7 @@
                                  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,
@@ -110,6 +111,7 @@
                                  CompilerCallbacks* callbacks,
                                  bool allow_soft_failures,
                                  HardFailLogMode log_level,
+                                 uint32_t api_level,
                                  std::string* error)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -121,7 +123,8 @@
                                              Handle<mirror::ClassLoader> class_loader,
                                              const DexFile::ClassDef& class_def,
                                              const DexFile::CodeItem* code_item, ArtMethod* method,
-                                             uint32_t method_access_flags)
+                                             uint32_t method_access_flags,
+                                             uint32_t api_level)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   uint8_t EncodePcToReferenceMapData() const;
@@ -163,8 +166,10 @@
   // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
   // to the locks held at 'dex_pc' in method 'm'.
   // Note: this is the only situation where the verifier will visit quickened instructions.
-  static void FindLocksAtDexPc(ArtMethod* m, uint32_t dex_pc,
-                               std::vector<DexLockInfo>* monitor_enter_dex_pcs)
+  static void FindLocksAtDexPc(ArtMethod* m,
+                               uint32_t dex_pc,
+                               std::vector<DexLockInfo>* monitor_enter_dex_pcs,
+                               uint32_t api_level)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   static void Init() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -242,7 +247,8 @@
                  bool allow_soft_failures,
                  bool need_precise_constants,
                  bool verify_to_dump,
-                 bool allow_thread_suspension)
+                 bool allow_thread_suspension,
+                 uint32_t api_level)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   void UninstantiableError(const char* descriptor);
@@ -299,6 +305,7 @@
                                   bool allow_soft_failures,
                                   HardFailLogMode log_level,
                                   bool need_precise_constants,
+                                  uint32_t api_level,
                                   std::string* hard_failure_msg)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -790,6 +797,10 @@
   // Link, for the method verifier root linked list.
   MethodVerifier* link_;
 
+  // API level, for dependent checks. Note: we do not use '0' for unset here, to simplify checks.
+  // Instead, unset level should correspond to max().
+  const uint32_t api_level_;
+
   friend class art::Thread;
   friend class VerifierDepsTest;
 
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index d1be9fa..cedc583 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -42,7 +42,7 @@
     // Verify the class
     std::string error_msg;
     FailureKind failure = MethodVerifier::VerifyClass(
-        self, klass, nullptr, true, HardFailLogMode::kLogWarning, &error_msg);
+        self, klass, nullptr, true, HardFailLogMode::kLogWarning, /* api_level */ 0u, &error_msg);
 
     if (android::base::StartsWith(descriptor, "Ljava/lang/invoke")) {
       ASSERT_TRUE(failure == FailureKind::kSoftFailure ||
diff --git a/tools/art_verifier/art_verifier.cc b/tools/art_verifier/art_verifier.cc
index fc62410..1a76a86 100644
--- a/tools/art_verifier/art_verifier.cc
+++ b/tools/art_verifier/art_verifier.cc
@@ -112,6 +112,9 @@
     } else if (option.starts_with("--repetitions=")) {
       char* end;
       repetitions_ = strtoul(option.substr(strlen("--repetitions=")).data(), &end, 10);
+    } else if (option.starts_with("--api-level=")) {
+      char* end;
+      api_level_ = strtoul(option.substr(strlen("--api-level=")).data(), &end, 10);
     } else {
       return kParseUnknownArgument;
     }
@@ -147,6 +150,7 @@
         "  --verbose: use verbose verifier mode.\n"
         "  --verbose-debug: use verbose verifier debug mode.\n"
         "  --repetitions=<count>: repeat the verification count times.\n"
+        "  --api-level=<level>: use API level for verification.\n"
         "\n";
 
     usage += Base::GetUsage();
@@ -163,6 +167,8 @@
   bool method_verifier_verbose_debug_ = false;
 
   size_t repetitions_ = 0u;
+
+  uint32_t api_level_ = 0u;
 };
 
 struct MethodVerifierMain : public CmdlineMain<MethodVerifierArgs> {
@@ -242,6 +248,7 @@
                                                   runtime->GetCompilerCallbacks(),
                                                   true,
                                                   verifier::HardFailLogMode::kLogWarning,
+                                                  args_->api_level_,
                                                   &error_msg);
           if (args_->repetitions_ == 0) {
             LOG(INFO) << descriptor << ": " << res << " " << error_msg;