Only look for method optimization annotations in the bootstrap class loader.

When checking for an optimization annotation (FastNative or
CriticalNative) on a method, do not resolve the method's annotations'
classes as a side effect -- instead, look them up in the bootstrap
class loader's resolved types. This is to prevent exceptions from being
thrown (during class resolution) in JNI transitions.

This change does not affect annotation lookup rules in the context of
reflection.

(cherry-picked from commit 35e42f0ab3b70203038fe037ee50d39e2d37af9a)

Test: art/test/testrunner/testrunner.py -t 656-annotation-lookup-generic-jni
Bug: 38454151
Bug: 34659969
Change-Id: Ie6b8b30b96a08baa629c449e3803a031515508d1
(cherry picked from commit 2ed6cce6fcfd031b0f9d83111f01b6b48ead1a32)
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 7de8916..67038b4 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -403,15 +403,19 @@
 
 bool ArtMethod::IsAnnotatedWithFastNative() {
   return IsAnnotatedWith(WellKnownClasses::dalvik_annotation_optimization_FastNative,
-                         DexFile::kDexVisibilityBuild);
+                         DexFile::kDexVisibilityBuild,
+                         /* lookup_in_resolved_boot_classes */ true);
 }
 
 bool ArtMethod::IsAnnotatedWithCriticalNative() {
   return IsAnnotatedWith(WellKnownClasses::dalvik_annotation_optimization_CriticalNative,
-                         DexFile::kDexVisibilityBuild);
+                         DexFile::kDexVisibilityBuild,
+                         /* lookup_in_resolved_boot_classes */ true);
 }
 
-bool ArtMethod::IsAnnotatedWith(jclass klass, uint32_t visibility) {
+bool ArtMethod::IsAnnotatedWith(jclass klass,
+                                uint32_t visibility,
+                                bool lookup_in_resolved_boot_classes) {
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
   StackHandleScope<1> shs(self);
@@ -420,10 +424,8 @@
   DCHECK(annotation->IsAnnotation());
   Handle<mirror::Class> annotation_handle(shs.NewHandle(annotation));
 
-  // Note: Resolves any method annotations' classes as a side-effect.
-  // -- This seems allowed by the spec since it says we can preload any classes
-  //    referenced by another classes's constant pool table.
-  return annotations::IsMethodAnnotationPresent(this, annotation_handle, visibility);
+  return annotations::IsMethodAnnotationPresent(
+      this, annotation_handle, visibility, lookup_in_resolved_boot_classes);
 }
 
 static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file,
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 856bfd2..9ed056a 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -716,7 +716,10 @@
  private:
   uint16_t FindObsoleteDexClassDefIndex() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  bool IsAnnotatedWith(jclass klass, uint32_t visibility);
+  // If `lookup_in_resolved_boot_classes` is true, look up any of the
+  // method's annotations' classes in the bootstrap class loader's
+  // resolved types; otherwise, resolve them as a side effect.
+  bool IsAnnotatedWith(jclass klass, uint32_t visibility, bool lookup_in_resolved_boot_classes);
 
   static constexpr size_t PtrSizedFieldsOffset(PointerSize pointer_size) {
     // Round up to pointer size for padding field. Tested in art_method.cc.
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 005bb4a..ebacb27 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -751,7 +751,8 @@
     const ClassData& klass,
     const DexFile::AnnotationSetItem* annotation_set,
     uint32_t visibility,
-    Handle<mirror::Class> annotation_class)
+    Handle<mirror::Class> annotation_class,
+    bool lookup_in_resolved_boot_classes = false)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile& dex_file = klass.GetDexFile();
   for (uint32_t i = 0; i < annotation_set->size_; ++i) {
@@ -761,19 +762,37 @@
     }
     const uint8_t* annotation = annotation_item->annotation_;
     uint32_t type_index = DecodeUnsignedLeb128(&annotation);
-    StackHandleScope<2> hs(Thread::Current());
-    mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
-        klass.GetDexFile(),
-        dex::TypeIndex(type_index),
-        hs.NewHandle(klass.GetDexCache()),
-        hs.NewHandle(klass.GetClassLoader()));
-    if (resolved_class == nullptr) {
-      std::string temp;
-      LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
-                                   klass.GetRealClass()->GetDescriptor(&temp), type_index);
-      CHECK(Thread::Current()->IsExceptionPending());
-      Thread::Current()->ClearException();
-      continue;
+    mirror::Class* resolved_class;
+    if (lookup_in_resolved_boot_classes) {
+      ObjPtr<mirror::Class> looked_up_class =
+          Runtime::Current()->GetClassLinker()->LookupResolvedType(
+              klass.GetDexFile(),
+              dex::TypeIndex(type_index),
+              klass.GetDexCache(),
+              // Force the use of the bootstrap class loader.
+              static_cast<mirror::ClassLoader*>(nullptr));
+      resolved_class = looked_up_class.Ptr();
+      if (resolved_class == nullptr) {
+        // If `resolved_class` is null, this is fine: just ignore that
+        // annotation item. We expect this to happen, as we do not
+        // attempt to resolve the annotation's class in this code path.
+        continue;
+      }
+    } else {
+      StackHandleScope<2> hs(Thread::Current());
+      resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
+          klass.GetDexFile(),
+          dex::TypeIndex(type_index),
+          hs.NewHandle(klass.GetDexCache()),
+          hs.NewHandle(klass.GetClassLoader()));
+      if (resolved_class == nullptr) {
+        std::string temp;
+        LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
+                                     klass.GetRealClass()->GetDescriptor(&temp), type_index);
+        CHECK(Thread::Current()->IsExceptionPending());
+        Thread::Current()->ClearException();
+        continue;
+      }
     }
     if (resolved_class == annotation_class.Get()) {
       return annotation_item;
@@ -1200,15 +1219,20 @@
   return GetSignatureValue(ClassData(method), annotation_set);
 }
 
-bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
-                               uint32_t visibility /* = DexFile::kDexVisibilityRuntime */) {
+bool IsMethodAnnotationPresent(ArtMethod* method,
+                               Handle<mirror::Class> annotation_class,
+                               uint32_t visibility /* = DexFile::kDexVisibilityRuntime */,
+                               bool lookup_in_resolved_boot_classes /* = false */) {
   const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
   if (annotation_set == nullptr) {
     return false;
   }
   const DexFile::AnnotationItem* annotation_item =
       GetAnnotationItemFromAnnotationSet(ClassData(method),
-                                         annotation_set, visibility, annotation_class);
+                                         annotation_set,
+                                         visibility,
+                                         annotation_class,
+                                         lookup_in_resolved_boot_classes);
   return annotation_item != nullptr;
 }
 
diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h
index 651c984..e108882 100644
--- a/runtime/dex_file_annotations.h
+++ b/runtime/dex_file_annotations.h
@@ -65,8 +65,15 @@
     REQUIRES_SHARED(Locks::mutator_lock_);
 mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_);
-bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
-                               uint32_t visibility = DexFile::kDexVisibilityRuntime)
+// Check whether `method` is annotated with `annotation_class`.
+// If `lookup_in_resolved_boot_classes` is true, look up any of the
+// method's annotations' classes in the bootstrap class loader's
+// resolved types; if it is false (default value), resolve them as a
+// side effect.
+bool IsMethodAnnotationPresent(ArtMethod* method,
+                               Handle<mirror::Class> annotation_class,
+                               uint32_t visibility = DexFile::kDexVisibilityRuntime,
+                               bool lookup_in_resolved_boot_classes = false)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // Class annotations.
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index c1016aa..629148e 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2086,6 +2086,11 @@
   self->SetTopOfStack(sp);
   uint32_t shorty_len = 0;
   const char* shorty = called->GetShorty(&shorty_len);
+  // Optimization annotations lookup does not try to resolve classes,
+  // as this may throw an exception, which is not supported by the
+  // Generic JNI trampoline at this stage; instead, method's
+  // annotations' classes are looked up in the bootstrap class
+  // loader's resolved types (which won't trigger an exception).
   bool critical_native = called->IsAnnotatedWithCriticalNative();
   // ArtMethod::IsAnnotatedWithCriticalNative should not throw
   // an exception; clear it if it happened anyway.