Fast JNI support.

Use a modifier to signal a native method is a fast JNI method. If the
modifier is set then don't perform runnable transitions.

Change-Id: I7835b4d837bfdd1cb8e2d54b919c0d5e6cf90499
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 27ae59b..59da7a0 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -30,10 +30,14 @@
 // Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
 extern uint32_t JniMethodStart(Thread* self) {
   JNIEnvExt* env = self->GetJniEnv();
-  DCHECK(env != NULL);
+  DCHECK(env != nullptr);
   uint32_t saved_local_ref_cookie = env->local_ref_cookie;
   env->local_ref_cookie = env->locals.GetSegmentState();
-  self->TransitionFromRunnableToSuspended(kNative);
+  mirror::ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
+  if (!native_method->IsFastNative()) {
+    // When not fast JNI we transition out of runnable.
+    self->TransitionFromRunnableToSuspended(kNative);
+  }
   return saved_local_ref_cookie;
 }
 
@@ -42,6 +46,20 @@
   return JniMethodStart(self);
 }
 
+// TODO: NO_THREAD_SAFETY_ANALYSIS due to different control paths depending on fast JNI.
+static void GoToRunnable(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
+  mirror::ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
+  bool is_fast = native_method->IsFastNative();
+  if (!is_fast) {
+    self->TransitionFromSuspendedToRunnable();
+  } else if (UNLIKELY(self->TestAllFlags())) {
+    // In fast JNI mode we never transitioned out of runnable. Perform a suspend check if there
+    // is a flag raised.
+    DCHECK(Locks::mutator_lock_->IsSharedHeld(self));
+    CheckSuspend(self);
+  }
+}
+
 static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) {
   JNIEnvExt* env = self->GetJniEnv();
   env->locals.SetSegmentState(env->local_ref_cookie);
@@ -50,21 +68,21 @@
 }
 
 extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {
-  self->TransitionFromSuspendedToRunnable();
+  GoToRunnable(self);
   PopLocalReferences(saved_local_ref_cookie, self);
 }
 
 
 extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
                                      Thread* self) {
-  self->TransitionFromSuspendedToRunnable();
+  GoToRunnable(self);
   UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
   PopLocalReferences(saved_local_ref_cookie, self);
 }
 
 extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
                                                  Thread* self) {
-  self->TransitionFromSuspendedToRunnable();
+  GoToRunnable(self);
   mirror::Object* o = self->DecodeJObject(result);  // Must decode before pop.
   PopLocalReferences(saved_local_ref_cookie, self);
   // Process result.
@@ -80,7 +98,7 @@
 extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result,
                                                              uint32_t saved_local_ref_cookie,
                                                              jobject locked, Thread* self) {
-  self->TransitionFromSuspendedToRunnable();
+  GoToRunnable(self);
   UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
   mirror::Object* o = self->DecodeJObject(result);
   PopLocalReferences(saved_local_ref_cookie, self);