riscv64: Enable JNI compiler.

Implement the required `WriteCIE()`, fix a bug in the
`art_jni_dlsym_lookup_critical_stub`, fix reference loads
to be zero-extended and enable the JNI compiler for riscv64.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: run-gtests.sh
Test: testrunner.py --target --64 --ndebug --prebuild --no-prebuild -t 178
Test: # Edit `run-test` to disable checker, then
      testrunner.py --target --64 --ndebug --cdex-none --optimizing
      # 7 tests fail (pre-existing failures): 004-StackWalk, 137-cfi,
      # 2042-reference-processing, 597-deopt-busy-loop, 629-vdex-speed,
      # 638-checker-inline-cache-intrinsic and 661-oat-writer-layout.
Test: aosp_cf_riscv64_phone-userdebug boots without crashes.
Bug: 283082089
Change-Id: Ifd47098b7428919b601dd22a130ad1bd51ae516d
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
index 6b72262..fe98a57 100644
--- a/compiler/debug/elf_debug_frame_writer.h
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -90,7 +90,26 @@
       return;
     }
     case InstructionSet::kRiscv64: {
-      UNIMPLEMENTED(FATAL);
+      dwarf::DebugFrameOpCodeWriter<> opcodes;
+      opcodes.DefCFA(Reg::Riscv64Core(2), 0);  // X2(SP).
+      // core registers.
+      for (int reg = 3; reg < 32; reg++) {  // Skip X0 (Zero), X1 (RA) and X2 (SP).
+        if ((reg >= 5 && reg < 8) || (reg >= 10 && reg < 18) || reg >= 28) {
+          opcodes.Undefined(Reg::Riscv64Core(reg));
+        } else {
+          opcodes.SameValue(Reg::Riscv64Core(reg));
+        }
+      }
+      // fp registers.
+      for (int reg = 0; reg < 32; reg++) {
+        if (reg < 8 || (reg >=10 && reg < 18) || reg >= 28) {
+          opcodes.Undefined(Reg::Riscv64Fp(reg));
+        } else {
+          opcodes.SameValue(Reg::Riscv64Fp(reg));
+        }
+      }
+      auto return_reg = Reg::Riscv64Core(1);  // X1(RA).
+      WriteCIE(is64bit, return_reg, opcodes, buffer);
       return;
     }
     case InstructionSet::kX86: {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index c8a41ce..74d081d 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -115,9 +115,7 @@
   }
 
   bool IsAnyCompilationEnabled() const {
-    return CompilerFilter::IsAnyCompilationEnabled(compiler_filter_) &&
-           // TODO(riscv64): remove this when we have compiler support for RISC-V
-           GetInstructionSet() != InstructionSet::kRiscv64;
+    return CompilerFilter::IsAnyCompilationEnabled(compiler_filter_);
   }
 
   size_t GetHugeMethodThreshold() const {
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 03d784b..9349d2c 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -621,7 +621,7 @@
           main_jni_conv->CalleeSaveScratchRegisters()[0], kObjectReferenceSize);
       // Load the declaring class reference.
       DCHECK_EQ(ArtMethod::DeclaringClassOffset().SizeValue(), 0u);
-      __ Load(temp, method_register, MemberOffset(0u), kObjectReferenceSize);
+      __ LoadGcRootWithoutReadBarrier(temp, method_register, MemberOffset(0u));
       // Return to main path if the class object is marked.
       __ TestMarkBit(temp, jclass_read_barrier_return.get(), JNIMacroUnaryCondition::kNotZero);
     }
diff --git a/compiler/utils/jni_macro_assembler.cc b/compiler/utils/jni_macro_assembler.cc
index a0230e3..dc7ec60 100644
--- a/compiler/utils/jni_macro_assembler.cc
+++ b/compiler/utils/jni_macro_assembler.cc
@@ -37,6 +37,7 @@
 #include "base/casts.h"
 #include "base/globals.h"
 #include "base/memory_region.h"
+#include "gc_root.h"
 
 namespace art HIDDEN {
 
@@ -97,4 +98,21 @@
   }
 }
 
+template <PointerSize kPointerSize>
+void JNIMacroAssembler<kPointerSize>::LoadGcRootWithoutReadBarrier(ManagedRegister dest,
+                                                                   ManagedRegister base,
+                                                                   MemberOffset offs) {
+  static_assert(sizeof(uint32_t) == sizeof(GcRoot<mirror::Object>));
+  Load(dest, base, offs, sizeof(uint32_t));
+}
+
+template
+void JNIMacroAssembler<PointerSize::k32>::LoadGcRootWithoutReadBarrier(ManagedRegister dest,
+                                                                       ManagedRegister base,
+                                                                       MemberOffset offs);
+template
+void JNIMacroAssembler<PointerSize::k64>::LoadGcRootWithoutReadBarrier(ManagedRegister dest,
+                                                                       ManagedRegister base,
+                                                                       MemberOffset offs);
+
 }  // namespace art
diff --git a/compiler/utils/jni_macro_assembler.h b/compiler/utils/jni_macro_assembler.h
index 286c378..2d51439 100644
--- a/compiler/utils/jni_macro_assembler.h
+++ b/compiler/utils/jni_macro_assembler.h
@@ -129,9 +129,14 @@
   // Load routines
   virtual void Load(ManagedRegister dest, FrameOffset src, size_t size) = 0;
   virtual void Load(ManagedRegister dest, ManagedRegister base, MemberOffset offs, size_t size) = 0;
-
   virtual void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset<kPointerSize> offs) = 0;
 
+  // Load reference from a `GcRoot<>`. The default is to load as `jint`. Some architectures
+  // (say, RISC-V) override this to provide a different sign- or zero-extension.
+  virtual void LoadGcRootWithoutReadBarrier(ManagedRegister dest,
+                                            ManagedRegister base,
+                                            MemberOffset offs);
+
   // Copying routines
 
   // Move arguments from `srcs` locations to `dests` locations.
diff --git a/compiler/utils/riscv64/jni_macro_assembler_riscv64.cc b/compiler/utils/riscv64/jni_macro_assembler_riscv64.cc
index a05e9b4..d7e8030 100644
--- a/compiler/utils/riscv64/jni_macro_assembler_riscv64.cc
+++ b/compiler/utils/riscv64/jni_macro_assembler_riscv64.cc
@@ -236,6 +236,14 @@
   Load(m_dest, tr, MemberOffset(offs.Int32Value()), static_cast<size_t>(kRiscv64PointerSize));
 }
 
+void Riscv64JNIMacroAssembler::LoadGcRootWithoutReadBarrier(ManagedRegister m_dest,
+                                                            ManagedRegister m_base,
+                                                            MemberOffset offs) {
+  Riscv64ManagedRegister base = m_base.AsRiscv64();
+  Riscv64ManagedRegister dest = m_dest.AsRiscv64();
+  __ Loadwu(dest.AsXRegister(), base.AsXRegister(), offs.Int32Value());
+}
+
 void Riscv64JNIMacroAssembler::MoveArguments(ArrayRef<ArgumentLocation> dests,
                                              ArrayRef<ArgumentLocation> srcs,
                                              ArrayRef<FrameOffset> refs) {
@@ -291,7 +299,13 @@
           ? src.GetRegister().AsRiscv64()
           : Riscv64ManagedRegister::FromXRegister(TMP2);
       if (!src.IsRegister()) {
-        Load(reg, src.GetFrameOffset(), src.GetSize());
+        if (ref != kInvalidReferenceOffset) {
+          // We're loading the reference only for comparison with null, so it does not matter
+          // if we sign- or zero-extend but let's correctly zero-extend the reference anyway.
+          __ Loadwu(reg.AsRiscv64().AsXRegister(), SP, src.GetFrameOffset().SizeValue());
+        } else {
+          Load(reg, src.GetFrameOffset(), src.GetSize());
+        }
       }
       if (ref != kInvalidReferenceOffset) {
         DCHECK_NE(i, 0u);
diff --git a/compiler/utils/riscv64/jni_macro_assembler_riscv64.h b/compiler/utils/riscv64/jni_macro_assembler_riscv64.h
index 93c0001..79618e2 100644
--- a/compiler/utils/riscv64/jni_macro_assembler_riscv64.h
+++ b/compiler/utils/riscv64/jni_macro_assembler_riscv64.h
@@ -68,6 +68,9 @@
   void Load(ManagedRegister dest, FrameOffset offs, size_t size) override;
   void Load(ManagedRegister dest, ManagedRegister base, MemberOffset offs, size_t size) override;
   void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset64 offs) override;
+  void LoadGcRootWithoutReadBarrier(ManagedRegister dest,
+                                    ManagedRegister base,
+                                    MemberOffset offs) override;
 
   // Copying routines.
   void MoveArguments(ArrayRef<ArgumentLocation> dests,
diff --git a/compiler/utils/riscv64/jni_macro_assembler_riscv64_test.cc b/compiler/utils/riscv64/jni_macro_assembler_riscv64_test.cc
index 8aa4156..ec5bb9d 100644
--- a/compiler/utils/riscv64/jni_macro_assembler_riscv64_test.cc
+++ b/compiler/utils/riscv64/jni_macro_assembler_riscv64_test.cc
@@ -266,6 +266,12 @@
   expected += "addi t6, s1, 0x7f8\n"
               "ld s11, 0x408(t6)\n";
 
+  __ LoadGcRootWithoutReadBarrier(AsManaged(T0), AsManaged(A0), MemberOffset(0));
+  expected += "lwu t0, 0(a0)\n";
+  __ LoadGcRootWithoutReadBarrier(AsManaged(T1), AsManaged(S2), MemberOffset(0x800));
+  expected += "addi t6, s2, 0x7f8\n"
+              "lwu t1, 8(t6)\n";
+
   DriverStr(expected, "Load");
 }
 
@@ -428,7 +434,7 @@
               "1:\n"
               "ld t5, 76(sp)\n"
               "sd t5, 0(sp)\n"
-              "lw t5, 84(sp)\n"
+              "lwu t5, 84(sp)\n"
               "beqz t5, 2f\n"
               "addi t5, sp, 84\n"
               "2:\n"
diff --git a/runtime/arch/riscv64/jni_entrypoints_riscv64.S b/runtime/arch/riscv64/jni_entrypoints_riscv64.S
index 92289be..c9d034b 100644
--- a/runtime/arch/riscv64/jni_entrypoints_riscv64.S
+++ b/runtime/arch/riscv64/jni_entrypoints_riscv64.S
@@ -348,7 +348,7 @@
     sd    t3, FRAME_SIZE_SAVE_REFS_AND_ARGS+0(t1)
     sd    t4, FRAME_SIZE_SAVE_REFS_AND_ARGS+8(t1)
     addi  t1, t1, -16
-    bnez  t2, .Lcritical_skip_copy_args_back
+    bnez  t2, .Lcritical_copy_args_back_loop
 .Lcritical_skip_copy_args_back:
 
     // Remove the frame reservation.