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"