jni: Add read barrier fast path to jni compiler

Static method dispatch via JNI requires a read barrier
for the ArtMethod::GetDeclaringClass() load before adding it to the
JNI StackHandleScope.

We used to call ReadBarrierJni unconditionally but add a branch
to skip calling it if the GC is not currently in the marking phase.

Test: ART_USE_READ_BARRIER=true make test-art-host test-art-target
Bug: 30437917
Change-Id: I4f505ebde17c0a67209c7bb51b3f39e37a06373a
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index bfb342f..13d8c16 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -276,10 +276,32 @@
   __ IncreaseFrameSize(main_out_arg_size);
 
   // Call the read barrier for the declaring class loaded from the method for a static call.
+  // Skip this for @CriticalNative because we didn't build a HandleScope to begin with.
   // Note that we always have outgoing param space available for at least two params.
   if (kUseReadBarrier && is_static && !is_critical_native) {
-    // XX: Why is this necessary only for the jclass? Why not for every single object ref?
-    // Skip this for @CriticalNative because we didn't build a HandleScope to begin with.
+    const bool kReadBarrierFastPath =
+        (instruction_set != kMips) && (instruction_set != kMips64);
+    std::unique_ptr<JNIMacroLabel> skip_cold_path_label;
+    if (kReadBarrierFastPath) {
+      skip_cold_path_label = __ CreateLabel();
+      // Fast path for supported targets.
+      //
+      // Check if gc_is_marking is set -- if it's not, we don't need
+      // a read barrier so skip it.
+      __ LoadFromThread(main_jni_conv->InterproceduralScratchRegister(),
+                        Thread::IsGcMarkingOffset<kPointerSize>(),
+                        Thread::IsGcMarkingSize());
+      // Jump over the slow path if gc is marking is false.
+      __ Jump(skip_cold_path_label.get(),
+              JNIMacroUnaryCondition::kZero,
+              main_jni_conv->InterproceduralScratchRegister());
+    }
+
+    // Construct slow path for read barrier:
+    //
+    // Call into the runtime's ReadBarrierJni and have it fix up
+    // the object address if it was moved.
+
     ThreadOffset<kPointerSize> read_barrier = QUICK_ENTRYPOINT_OFFSET(kPointerSize,
                                                                       pReadBarrierJni);
     main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
@@ -310,6 +332,10 @@
       __ CallFromThread(read_barrier, main_jni_conv->InterproceduralScratchRegister());
     }
     main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));  // Reset.
+
+    if (kReadBarrierFastPath) {
+      __ Bind(skip_cold_path_label.get());
+    }
   }
 
   // 6. Call into appropriate JniMethodStart passing Thread* so that transition out of Runnable