jni: Implement generic JNI support for @CriticalNative/@FastNative

Also:
* Extend existing test cases to check generic JNI for the above.
* Re-enable previously blacklisted @CriticalNative JNI run-tests.

Bug: 31400248
Change-Id: I436ed00c8b8880e936a0c3483bc0dc251f0c0ce2
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 76b5456..446e343 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -169,22 +169,33 @@
                                     HandleScope* handle_scope)
     // TODO: NO_THREAD_SAFETY_ANALYSIS as GoToRunnable() is NO_THREAD_SAFETY_ANALYSIS
     NO_THREAD_SAFETY_ANALYSIS {
-  GoToRunnable(self);
+  bool critical_native = called->IsAnnotatedWithCriticalNative();
+  bool fast_native = called->IsAnnotatedWithFastNative();
+  bool normal_native = !critical_native && !fast_native;
+
+  // @Fast and @CriticalNative do not do a state transition.
+  if (LIKELY(normal_native)) {
+    GoToRunnable(self);
+  }
   // We need the mutator lock (i.e., calling GoToRunnable()) before accessing the shorty or the
   // locked object.
   jobject locked = called->IsSynchronized() ? handle_scope->GetHandle(0).ToJObject() : nullptr;
   char return_shorty_char = called->GetShorty()[0];
   if (return_shorty_char == 'L') {
     if (locked != nullptr) {
+      DCHECK(normal_native) << " @FastNative and synchronize is not supported";
       UnlockJniSynchronizedMethod(locked, self);
     }
     return reinterpret_cast<uint64_t>(JniMethodEndWithReferenceHandleResult(
         result.l, saved_local_ref_cookie, self));
   } else {
     if (locked != nullptr) {
+      DCHECK(normal_native) << " @FastNative and synchronize is not supported";
       UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
     }
-    PopLocalReferences(saved_local_ref_cookie, self);
+    if (LIKELY(!critical_native)) {
+      PopLocalReferences(saved_local_ref_cookie, self);
+    }
     switch (return_shorty_char) {
       case 'F': {
         if (kRuntimeISA == kX86) {