Allow late lookup for @CriticalNative methods.

Test: Add and enable tests in 178-app-image-native-method
Test: Add and enable tests in jni_compiler_test
Test: Manually step through the new stub in GDB and check
      that backtrace works at various points.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: aosp_taimen-userdebug boots.
Test: run-gtests.sh
Test: testrunner.py --target --optimizing
Bug: 112189621
Change-Id: If094e5062acbb99eefa88f2afb4815f93730cb82
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index fb9704a..405c9ec 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -45,10 +45,25 @@
   return count + 1;
 }
 
+// Note: JNI name mangling "_" -> "_1".
+extern "C" JNIEXPORT jint JNICALL Java_MyClassNatives_bar_1Fast(JNIEnv*, jobject, jint count) {
+  return count + 1;
+}
+
 extern "C" JNIEXPORT jint JNICALL Java_MyClassNatives_sbar(JNIEnv*, jclass, jint count) {
   return count + 1;
 }
 
+// Note: JNI name mangling "_" -> "_1".
+extern "C" JNIEXPORT jint JNICALL Java_MyClassNatives_sbar_1Fast(JNIEnv*, jclass, jint count) {
+  return count + 1;
+}
+
+// Note: JNI name mangling "_" -> "_1".
+extern "C" JNIEXPORT jint JNICALL Java_MyClassNatives_sbar_1Critical(jint count) {
+  return count + 1;
+}
+
 // TODO: In the Baker read barrier configuration, add checks to ensure
 // the Marking Register's value is correct.
 
@@ -71,6 +86,11 @@
   return gCurrentJni == static_cast<uint32_t>(JniKind::kCritical);
 }
 
+// Is the current native method under test @FastNative?
+static bool IsCurrentJniFast() {
+  return gCurrentJni == static_cast<uint32_t>(JniKind::kFast);
+}
+
 // Is the current native method a plain-old non-annotated native?
 static bool IsCurrentJniNormal() {
   return gCurrentJni == static_cast<uint32_t>(JniKind::kNormal);
@@ -352,6 +372,7 @@
   void MaxParamNumberImpl();
   void WithoutImplementationImpl();
   void WithoutImplementationRefReturnImpl();
+  void StaticWithoutImplementationImpl();
   void StackArgsIntsFirstImpl();
   void StackArgsFloatsFirstImpl();
   void StackArgsMixedImpl();
@@ -373,9 +394,7 @@
 
 // Test the normal compiler and normal generic JNI only.
 // The following features are unsupported in @FastNative:
-// 1) JNI stubs (lookup via dlsym) when methods aren't explicitly registered
-// 2) synchronized keyword
-// -- TODO: We can support (1) if we remove the mutator lock assert during stub lookup.
+// 1) synchronized keyword
 # define JNI_TEST_NORMAL_ONLY(TestName)          \
   TEST_F(JniCompilerTest, TestName ## NormalCompiler) { \
     ScopedCheckHandleScope top_handle_scope_check;  \
@@ -612,8 +631,8 @@
 #define NORMAL_JNI_ONLY_NOWRAP(func) \
     ({ ASSERT_TRUE(IsCurrentJniNormal()); reinterpret_cast<void*>(&(func)); })
 // Same as above, but with nullptr. When we want to test the stub functionality.
-#define NORMAL_JNI_ONLY_NULLPTR \
-    ({ ASSERT_TRUE(IsCurrentJniNormal()); nullptr; })
+#define NORMAL_OR_FAST_JNI_ONLY_NULLPTR \
+    ({ ASSERT_TRUE(IsCurrentJniNormal() || IsCurrentJniFast()); nullptr; })
 
 
 int gJava_MyClassNatives_foo_calls[kJniKindCount] = {};
@@ -636,8 +655,8 @@
 JNI_TEST(CompileAndRunNoArgMethod)
 
 void JniCompilerTest::CompileAndRunIntMethodThroughStubImpl() {
-  SetUpForTest(false, "bar", "(I)I", NORMAL_JNI_ONLY_NULLPTR);
-  // calling through stub will link with &Java_MyClassNatives_bar
+  SetUpForTest(false, "bar", "(I)I", NORMAL_OR_FAST_JNI_ONLY_NULLPTR);
+  // calling through stub will link with &Java_MyClassNatives_bar{,_1Fast}
 
   std::string reason;
   ASSERT_TRUE(Runtime::Current()->GetJavaVM()->
@@ -648,12 +667,12 @@
   EXPECT_EQ(25, result);
 }
 
-// TODO: Support @FastNative and @CriticalNative through stubs.
-JNI_TEST_NORMAL_ONLY(CompileAndRunIntMethodThroughStub)
+// Note: @CriticalNative is only for static methods.
+JNI_TEST(CompileAndRunIntMethodThroughStub)
 
 void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() {
-  SetUpForTest(true, "sbar", "(I)I", NORMAL_JNI_ONLY_NULLPTR);
-  // calling through stub will link with &Java_MyClassNatives_sbar
+  SetUpForTest(true, "sbar", "(I)I", nullptr);
+  // calling through stub will link with &Java_MyClassNatives_sbar{,_1Fast,_1Critical}
 
   std::string reason;
   ASSERT_TRUE(Runtime::Current()->GetJavaVM()->
@@ -664,8 +683,7 @@
   EXPECT_EQ(43, result);
 }
 
-// TODO: Support @FastNative and @CriticalNative through stubs.
-JNI_TEST_NORMAL_ONLY(CompileAndRunStaticIntMethodThroughStub)
+JNI_TEST_CRITICAL(CompileAndRunStaticIntMethodThroughStub)
 
 int gJava_MyClassNatives_fooI_calls[kJniKindCount] = {};
 jint Java_MyClassNatives_fooI(JNIEnv*, jobject, jint x) {
@@ -1894,7 +1912,7 @@
   // This will lead to error messages in the log.
   ScopedLogSeverity sls(LogSeverity::FATAL);
 
-  SetUpForTest(false, "withoutImplementation", "()V", NORMAL_JNI_ONLY_NULLPTR);
+  SetUpForTest(false, "withoutImplementation", "()V", NORMAL_OR_FAST_JNI_ONLY_NULLPTR);
 
   env_->CallVoidMethod(jobj_, jmethod_);
 
@@ -1902,9 +1920,7 @@
   EXPECT_TRUE(env_->ExceptionCheck() == JNI_TRUE);
 }
 
-// TODO: Don't test @FastNative here since it goes through a stub lookup (unsupported) which would
-// normally fail with an exception, but fails with an assert.
-JNI_TEST_NORMAL_ONLY(WithoutImplementation)
+JNI_TEST(WithoutImplementation)
 
 void JniCompilerTest::WithoutImplementationRefReturnImpl() {
   // This will lead to error messages in the log.
@@ -1913,7 +1929,7 @@
   SetUpForTest(false,
                "withoutImplementationRefReturn",
                "()Ljava/lang/Object;",
-               NORMAL_JNI_ONLY_NULLPTR);
+               NORMAL_OR_FAST_JNI_ONLY_NULLPTR);
 
   env_->CallObjectMethod(jobj_, jmethod_);
 
@@ -1921,8 +1937,21 @@
   EXPECT_TRUE(env_->ExceptionCheck() == JNI_TRUE);
 }
 
-// TODO: Should work for @FastNative too.
-JNI_TEST_NORMAL_ONLY(WithoutImplementationRefReturn)
+JNI_TEST(WithoutImplementationRefReturn)
+
+void JniCompilerTest::StaticWithoutImplementationImpl() {
+  // This will lead to error messages in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+
+  SetUpForTest(true, "staticWithoutImplementation", "()V", nullptr);
+
+  env_->CallStaticVoidMethod(jklass_, jmethod_);
+
+  EXPECT_TRUE(Thread::Current()->IsExceptionPending());
+  EXPECT_TRUE(env_->ExceptionCheck() == JNI_TRUE);
+}
+
+JNI_TEST_CRITICAL(StaticWithoutImplementation)
 
 void Java_MyClassNatives_stackArgsIntsFirst(JNIEnv*, jclass, jint i1, jint i2, jint i3,
                                             jint i4, jint i5, jint i6, jint i7, jint i8, jint i9,