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