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);