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/utils/arm64/jni_macro_assembler_arm64.cc b/compiler/utils/arm64/jni_macro_assembler_arm64.cc
index dfdcd11..9cd6884 100644
--- a/compiler/utils/arm64/jni_macro_assembler_arm64.cc
+++ b/compiler/utils/arm64/jni_macro_assembler_arm64.cc
@@ -262,9 +262,12 @@
     ___ Ldr(reg_w(dest.AsWRegister()), MEM_OP(reg_x(base), offset));
   } else if (dest.IsXRegister()) {
     CHECK_NE(dest.AsXRegister(), SP) << dest;
-    if (size == 4u) {
+
+    if (size == 1u) {
+      ___ Ldrb(reg_w(dest.AsOverlappingWRegister()), MEM_OP(reg_x(base), offset));
+    } else if (size == 4u) {
       ___ Ldr(reg_w(dest.AsOverlappingWRegister()), MEM_OP(reg_x(base), offset));
-    } else {
+    }  else {
       CHECK_EQ(8u, size) << dest;
       ___ Ldr(reg_x(dest.AsXRegister()), MEM_OP(reg_x(base), offset));
     }
@@ -627,6 +630,38 @@
   ___ Cbnz(reg_x(scratch.AsXRegister()), exception_blocks_.back()->Entry());
 }
 
+std::unique_ptr<JNIMacroLabel> Arm64JNIMacroAssembler::CreateLabel() {
+  return std::unique_ptr<JNIMacroLabel>(new Arm64JNIMacroLabel());
+}
+
+void Arm64JNIMacroAssembler::Jump(JNIMacroLabel* label) {
+  CHECK(label != nullptr);
+  ___ B(Arm64JNIMacroLabel::Cast(label)->AsArm64());
+}
+
+void Arm64JNIMacroAssembler::Jump(JNIMacroLabel* label,
+                                  JNIMacroUnaryCondition condition,
+                                  ManagedRegister test) {
+  CHECK(label != nullptr);
+
+  switch (condition) {
+    case JNIMacroUnaryCondition::kZero:
+      ___ Cbz(reg_x(test.AsArm64().AsXRegister()), Arm64JNIMacroLabel::Cast(label)->AsArm64());
+      break;
+    case JNIMacroUnaryCondition::kNotZero:
+      ___ Cbnz(reg_x(test.AsArm64().AsXRegister()), Arm64JNIMacroLabel::Cast(label)->AsArm64());
+      break;
+    default:
+      LOG(FATAL) << "Not implemented unary condition: " << static_cast<int>(condition);
+      UNREACHABLE();
+  }
+}
+
+void Arm64JNIMacroAssembler::Bind(JNIMacroLabel* label) {
+  CHECK(label != nullptr);
+  ___ Bind(Arm64JNIMacroLabel::Cast(label)->AsArm64());
+}
+
 void Arm64JNIMacroAssembler::EmitExceptionPoll(Arm64Exception *exception) {
   UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
   temps.Exclude(reg_x(exception->scratch_.AsXRegister()));
diff --git a/compiler/utils/arm64/jni_macro_assembler_arm64.h b/compiler/utils/arm64/jni_macro_assembler_arm64.h
index b9f6854..264e99a 100644
--- a/compiler/utils/arm64/jni_macro_assembler_arm64.h
+++ b/compiler/utils/arm64/jni_macro_assembler_arm64.h
@@ -168,6 +168,15 @@
   // and branch to a ExceptionSlowPath if it is.
   void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
 
+  // Create a new label that can be used with Jump/Bind calls.
+  std::unique_ptr<JNIMacroLabel> CreateLabel() OVERRIDE;
+  // Emit an unconditional jump to the label.
+  void Jump(JNIMacroLabel* label) OVERRIDE;
+  // Emit a conditional jump to the label by applying a unary condition test to the register.
+  void Jump(JNIMacroLabel* label, JNIMacroUnaryCondition cond, ManagedRegister test) OVERRIDE;
+  // Code at this offset will serve as the target for the Jump call.
+  void Bind(JNIMacroLabel* label) OVERRIDE;
+
  private:
   class Arm64Exception {
    public:
@@ -222,6 +231,16 @@
   ArenaVector<std::unique_ptr<Arm64Exception>> exception_blocks_;
 };
 
+class Arm64JNIMacroLabel FINAL
+    : public JNIMacroLabelCommon<Arm64JNIMacroLabel,
+                                 vixl::aarch64::Label,
+                                 kArm64> {
+ public:
+  vixl::aarch64::Label* AsArm64() {
+    return AsPlatformLabel();
+  }
+};
+
 }  // namespace arm64
 }  // namespace art