Introduce a Marking Register in ARM64 code generation.

When generating code for ARM64, maintain the status of
Thread::Current()->GetIsGcMarking() in register X20,
dubbed MR (Marking Register), and check the value of that
register (instead of loading and checking a read barrier
marking entrypoint) in read barriers.

Test: m test-art-target
Test: m test-art-target with tree built with ART_USE_READ_BARRIER=false
Test: ARM64 device boot test
Bug: 37707231
Change-Id: Ibe9bc5c99a2176b0a0476e9e9ad7fcc9f745017b
diff --git a/compiler/jni/jni_cfi_test_expected.inc b/compiler/jni/jni_cfi_test_expected.inc
index 2710ae9..acb8a57 100644
--- a/compiler/jni/jni_cfi_test_expected.inc
+++ b/compiler/jni/jni_cfi_test_expected.inc
@@ -89,7 +89,8 @@
     0xF3, 0x53, 0x46, 0xA9, 0xF5, 0x5B, 0x47, 0xA9, 0xF7, 0x63, 0x48, 0xA9,
     0xF9, 0x6B, 0x49, 0xA9, 0xFB, 0x73, 0x4A, 0xA9, 0xFD, 0x7B, 0x4B, 0xA9,
     0xE8, 0x27, 0x42, 0x6D, 0xEA, 0x2F, 0x43, 0x6D, 0xEC, 0x37, 0x44, 0x6D,
-    0xEE, 0x3F, 0x45, 0x6D, 0xFF, 0x03, 0x03, 0x91, 0xC0, 0x03, 0x5F, 0xD6,
+    0xEE, 0x3F, 0x45, 0x6D, 0x74, 0x36, 0x40, 0xB9, 0xFF, 0x03, 0x03, 0x91,
+    0xC0, 0x03, 0x5F, 0xD6,
 };
 static constexpr uint8_t expected_cfi_kArm64[] = {
     0x44, 0x0E, 0xC0, 0x01, 0x44, 0x93, 0x18, 0x94, 0x16, 0x44, 0x95, 0x14,
@@ -101,7 +102,7 @@
     0xD3, 0xD4, 0x44, 0xD5, 0xD6, 0x44, 0xD7, 0xD8, 0x44, 0xD9, 0xDA, 0x44,
     0xDB, 0xDC, 0x44, 0xDD, 0xDE, 0x44, 0x06, 0x48, 0x06, 0x49, 0x44, 0x06,
     0x4A, 0x06, 0x4B, 0x44, 0x06, 0x4C, 0x06, 0x4D, 0x44, 0x06, 0x4E, 0x06,
-    0x4F, 0x44, 0x0E, 0x00, 0x44, 0x0B, 0x0E, 0xC0, 0x01,
+    0x4F, 0x48, 0x0E, 0x00, 0x44, 0x0B, 0x0E, 0xC0, 0x01,
 };
 // 0x00000000: sub sp, sp, #0xc0 (192)
 // 0x00000004: .cfi_def_cfa_offset: 192
@@ -175,11 +176,12 @@
 // 0x0000006c: ldp d14, d15, [sp, #80]
 // 0x00000070: .cfi_restore_extended: r78
 // 0x00000070: .cfi_restore_extended: r79
-// 0x00000070: add sp, sp, #0xc0 (192)
-// 0x00000074: .cfi_def_cfa_offset: 0
-// 0x00000074: ret
-// 0x00000078: .cfi_restore_state
-// 0x00000078: .cfi_def_cfa_offset: 192
+// 0x00000070: ldr w20, [tr, #52] ; is_gc_marking
+// 0x00000074: add sp, sp, #0xc0 (192)
+// 0x00000078: .cfi_def_cfa_offset: 0
+// 0x00000078: ret
+// 0x0000007c: .cfi_restore_state
+// 0x0000007c: .cfi_def_cfa_offset: 192
 
 static constexpr uint8_t expected_asm_kX86[] = {
     0x57, 0x56, 0x55, 0x83, 0xC4, 0xE4, 0x50, 0x89, 0x4C, 0x24, 0x34, 0xF3,
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index b34d938..6ce7d75 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -49,6 +49,9 @@
   return count + 1;
 }
 
+// TODO: In the Baker read barrier configuration, add checks to ensure
+// the Marking Register's value is correct.
+
 namespace art {
 
 enum class JniKind {
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index 33f4d77..e086455 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -108,11 +108,25 @@
 
 // Calling convention
 ManagedRegister Arm64ManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
-  return Arm64ManagedRegister::FromXRegister(X20);  // saved on entry restored on exit
+  // X20 is safe to use as a scratch register:
+  // - with Baker read barriers, it is reserved as Marking Register,
+  //   and thus does not actually need to be saved/restored; it is
+  //   refreshed on exit (see Arm64JNIMacroAssembler::RemoveFrame);
+  // - in other cases, it is saved on entry (in
+  //   Arm64JNIMacroAssembler::BuildFrame) and restored on exit (in
+  //   Arm64JNIMacroAssembler::RemoveFrame).
+  return Arm64ManagedRegister::FromXRegister(X20);
 }
 
 ManagedRegister Arm64JniCallingConvention::InterproceduralScratchRegister() {
-  return Arm64ManagedRegister::FromXRegister(X20);  // saved on entry restored on exit
+  // X20 is safe to use as a scratch register:
+  // - with Baker read barriers, it is reserved as Marking Register,
+  //   and thus does not actually need to be saved/restored; it is
+  //   refreshed on exit (see Arm64JNIMacroAssembler::RemoveFrame);
+  // - in other cases, it is saved on entry (in
+  //   Arm64JNIMacroAssembler::BuildFrame) and restored on exit (in
+  //   Arm64JNIMacroAssembler::RemoveFrame).
+  return Arm64ManagedRegister::FromXRegister(X20);
 }
 
 static ManagedRegister ReturnRegisterForShorty(const char* shorty) {