Use strcmp() for checking @{Fast,Critical}Native annotations.

Instead of looking up the descriptor in boot class path
loader (where @{Fast,Critical}Native are guaranteed to
be already resolved) and then checking if it's the
@{Fast,Critical}Native annotation, just check the
descriptor with strcmp().

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 65574695
Change-Id: I765590d039981d169fb3c606b6166580a84303b6
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index b5e0f66..8709643 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -429,30 +429,15 @@
 }
 
 bool ArtMethod::IsAnnotatedWithFastNative() {
-  return IsAnnotatedWith(WellKnownClasses::dalvik_annotation_optimization_FastNative,
-                         DexFile::kDexVisibilityBuild,
-                         /* lookup_in_resolved_boot_classes */ true);
+  ScopedObjectAccess soa(Thread::Current());
+  return annotations::HasFastNativeMethodBuildAnnotation(
+      *GetDexFile(), GetClassDef(), GetDexMethodIndex());
 }
 
 bool ArtMethod::IsAnnotatedWithCriticalNative() {
-  return IsAnnotatedWith(WellKnownClasses::dalvik_annotation_optimization_CriticalNative,
-                         DexFile::kDexVisibilityBuild,
-                         /* lookup_in_resolved_boot_classes */ true);
-}
-
-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);
-
-  ObjPtr<mirror::Class> annotation = soa.Decode<mirror::Class>(klass);
-  DCHECK(annotation->IsAnnotation());
-  Handle<mirror::Class> annotation_handle(shs.NewHandle(annotation));
-
-  return annotations::IsMethodAnnotationPresent(
-      this, annotation_handle, visibility, lookup_in_resolved_boot_classes);
+  ScopedObjectAccess soa(Thread::Current());
+  return annotations::HasCriticalNativeMethodBuildAnnotation(
+      *GetDexFile(), GetClassDef(), GetDexMethodIndex());
 }
 
 static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file,
diff --git a/runtime/art_method.h b/runtime/art_method.h
index ca2e34e..8927481 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -751,11 +751,6 @@
  private:
   uint16_t FindObsoleteDexClassDefIndex() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // 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.
     return RoundUp(offsetof(ArtMethod, hotness_count_) + sizeof(hotness_count_),
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 845202f..5496efd 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -261,32 +261,38 @@
   return nullptr;
 }
 
-const DexFile::AnnotationSetItem* FindAnnotationSetForMethod(ArtMethod* method)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  if (method->IsProxyMethod()) {
-    return nullptr;
-  }
-  const DexFile* dex_file = method->GetDexFile();
+const DexFile::AnnotationSetItem* FindAnnotationSetForMethod(const DexFile& dex_file,
+                                                             const DexFile::ClassDef& class_def,
+                                                             uint32_t method_index) {
   const DexFile::AnnotationsDirectoryItem* annotations_dir =
-      dex_file->GetAnnotationsDirectory(method->GetClassDef());
+      dex_file.GetAnnotationsDirectory(class_def);
   if (annotations_dir == nullptr) {
     return nullptr;
   }
   const DexFile::MethodAnnotationsItem* method_annotations =
-      dex_file->GetMethodAnnotations(annotations_dir);
+      dex_file.GetMethodAnnotations(annotations_dir);
   if (method_annotations == nullptr) {
     return nullptr;
   }
-  uint32_t method_index = method->GetDexMethodIndex();
   uint32_t method_count = annotations_dir->methods_size_;
   for (uint32_t i = 0; i < method_count; ++i) {
     if (method_annotations[i].method_idx_ == method_index) {
-      return dex_file->GetMethodAnnotationSetItem(method_annotations[i]);
+      return dex_file.GetMethodAnnotationSetItem(method_annotations[i]);
     }
   }
   return nullptr;
 }
 
+inline const DexFile::AnnotationSetItem* FindAnnotationSetForMethod(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (method->IsProxyMethod()) {
+    return nullptr;
+  }
+  return FindAnnotationSetForMethod(*method->GetDexFile(),
+                                    method->GetClassDef(),
+                                    method->GetDexMethodIndex());
+}
+
 const DexFile::ParameterAnnotationsItem* FindAnnotationsItemForMethod(ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile* dex_file = method->GetDexFile();
@@ -764,8 +770,7 @@
     const ClassData& klass,
     const DexFile::AnnotationSetItem* annotation_set,
     uint32_t visibility,
-    Handle<mirror::Class> annotation_class,
-    bool lookup_in_resolved_boot_classes = false)
+    Handle<mirror::Class> annotation_class)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const DexFile& dex_file = klass.GetDexFile();
   for (uint32_t i = 0; i < annotation_set->size_; ++i) {
@@ -778,35 +783,19 @@
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     Thread* self = Thread::Current();
     mirror::Class* resolved_class;
-    if (lookup_in_resolved_boot_classes) {
-      // Note: We cannot use ClassLinker::LookupResolvedType() because the current DexCache
-      // may not be registered with the boot class path ClassLoader and we must not pollute
-      // the DexCache with classes that are not in the associated ClassLoader's ClassTable.
-      const char* descriptor = dex_file.StringByTypeIdx(dex::TypeIndex(type_index));
-      ObjPtr<mirror::Class> looked_up_class =
-          class_linker->LookupClass(self, descriptor, /* class_loader */ 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(self);
-      resolved_class = class_linker->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(self->IsExceptionPending());
-        self->ClearException();
-        continue;
-      }
+    StackHandleScope<2> hs(self);
+    resolved_class = class_linker->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(self->IsExceptionPending());
+      self->ClearException();
+      continue;
     }
     if (resolved_class == annotation_class.Get()) {
       return annotation_item;
@@ -822,8 +811,8 @@
     uint32_t visibility,
     Handle<mirror::Class> annotation_class)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile::AnnotationItem* annotation_item =
-      GetAnnotationItemFromAnnotationSet(klass, annotation_set, visibility, annotation_class);
+  const DexFile::AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
+      klass, annotation_set, visibility, annotation_class);
   if (annotation_item == nullptr) {
     return nullptr;
   }
@@ -1235,21 +1224,74 @@
 
 bool IsMethodAnnotationPresent(ArtMethod* method,
                                Handle<mirror::Class> annotation_class,
-                               uint32_t visibility /* = DexFile::kDexVisibilityRuntime */,
-                               bool lookup_in_resolved_boot_classes /* = false */) {
+                               uint32_t visibility /* = DexFile::kDexVisibilityRuntime */) {
   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,
-                                         lookup_in_resolved_boot_classes);
+  const DexFile::AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
+      ClassData(method), annotation_set, visibility, annotation_class);
   return annotation_item != nullptr;
 }
 
+static void DCheckNativeAnnotation(const char* descriptor, jclass cls) {
+  if (kIsDebugBuild) {
+    ScopedObjectAccess soa(Thread::Current());
+    ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
+    ClassLinker* linker = Runtime::Current()->GetClassLinker();
+    // Lookup using the boot class path loader should yield the annotation class.
+    CHECK_EQ(klass, linker->LookupClass(soa.Self(), descriptor, /* class_loader */ nullptr));
+  }
+}
+
+// Check whether a method from the `dex_file` with the given `annotation_set`
+// is annotated with `annotation_descriptor` with build visibility.
+static bool IsMethodBuildAnnotationPresent(const DexFile& dex_file,
+                                           const DexFile::AnnotationSetItem& annotation_set,
+                                           const char* annotation_descriptor,
+                                           jclass annotation_class) {
+  for (uint32_t i = 0; i < annotation_set.size_; ++i) {
+    const DexFile::AnnotationItem* annotation_item = dex_file.GetAnnotationItem(&annotation_set, i);
+    if (!IsVisibilityCompatible(annotation_item->visibility_, DexFile::kDexVisibilityBuild)) {
+      continue;
+    }
+    const uint8_t* annotation = annotation_item->annotation_;
+    uint32_t type_index = DecodeUnsignedLeb128(&annotation);
+    const char* descriptor = dex_file.StringByTypeIdx(dex::TypeIndex(type_index));
+    if (strcmp(descriptor, annotation_descriptor) == 0) {
+      DCheckNativeAnnotation(descriptor, annotation_class);
+      return true;
+    }
+  }
+  return false;
+}
+
+uint32_t HasFastNativeMethodBuildAnnotation(const DexFile& dex_file,
+                                            const DexFile::ClassDef& class_def,
+                                            uint32_t method_index) {
+  const DexFile::AnnotationSetItem* annotation_set =
+      FindAnnotationSetForMethod(dex_file, class_def, method_index);
+  return annotation_set != nullptr &&
+         IsMethodBuildAnnotationPresent(
+             dex_file,
+             *annotation_set,
+             "Ldalvik/annotation/optimization/FastNative;",
+             WellKnownClasses::dalvik_annotation_optimization_FastNative);
+}
+
+uint32_t HasCriticalNativeMethodBuildAnnotation(const DexFile& dex_file,
+                                                const DexFile::ClassDef& class_def,
+                                                uint32_t method_index) {
+  const DexFile::AnnotationSetItem* annotation_set =
+      FindAnnotationSetForMethod(dex_file, class_def, method_index);
+  return annotation_set != nullptr &&
+         IsMethodBuildAnnotationPresent(
+             dex_file,
+             *annotation_set,
+             "Ldalvik/annotation/optimization/CriticalNative;",
+             WellKnownClasses::dalvik_annotation_optimization_CriticalNative);
+}
+
 mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass,
                                       Handle<mirror::Class> annotation_class) {
   ClassData data(klass);
diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h
index e108882..04ff3a1 100644
--- a/runtime/dex_file_annotations.h
+++ b/runtime/dex_file_annotations.h
@@ -72,9 +72,18 @@
 // side effect.
 bool IsMethodAnnotationPresent(ArtMethod* method,
                                Handle<mirror::Class> annotation_class,
-                               uint32_t visibility = DexFile::kDexVisibilityRuntime,
-                               bool lookup_in_resolved_boot_classes = false)
+                               uint32_t visibility = DexFile::kDexVisibilityRuntime)
     REQUIRES_SHARED(Locks::mutator_lock_);
+// Check whether a method from the `dex_file` with the given `method_index`
+// is annotated with @dalvik.annotation.optimization.FastNative with build visibility.
+uint32_t HasFastNativeMethodBuildAnnotation(const DexFile& dex_file,
+                                            const DexFile::ClassDef& class_def,
+                                            uint32_t method_index);
+// Check whether a method from the `dex_file` with the given `method_index`
+// is annotated with @dalvik.annotation.optimization.CriticalNative with build visibility.
+uint32_t HasCriticalNativeMethodBuildAnnotation(const DexFile& dex_file,
+                                                const DexFile::ClassDef& class_def,
+                                                uint32_t method_index);
 
 // Class annotations.
 mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass,
diff --git a/runtime/image.cc b/runtime/image.cc
index aae572b..cf5feac 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '4', 'A', '\0' };  // VarHandle fence intrinsics
+const uint8_t ImageHeader::kImageVersion[] = { '0', '5', '0', '\0' };  // strcmp() @FastNative.
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,