summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/code_generator_riscv64.cc2
-rw-r--r--compiler/optimizing/optimizing_compiler.cc9
-rw-r--r--runtime/arch/riscv64/asm_support_riscv64.S16
-rw-r--r--runtime/arch/riscv64/quick_entrypoints_riscv64.S179
4 files changed, 203 insertions, 3 deletions
diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc
index 648fa88727..c77d069478 100644
--- a/compiler/optimizing/code_generator_riscv64.cc
+++ b/compiler/optimizing/code_generator_riscv64.cc
@@ -2286,7 +2286,7 @@ void CodeGeneratorRISCV64::MarkGCCard(XRegister object,
// This dual use of the value in register `card` (1. to calculate the location
// of the card to mark; and 2. to load the `kCardDirty` value) saves a load
// (no need to explicitly load `kCardDirty` as an immediate value).
- __ Storeb(card, temp, 0);
+ __ Sb(card, temp, 0); // No scratch register left for `Storeb()`.
if (value_can_be_null) {
__ Bind(&done);
}
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 040c2449a7..325fb87fc5 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -743,6 +743,10 @@ static bool CanAssembleGraphForRiscv64(HGraph* graph) {
UNREACHABLE();
case HInstruction::kExit:
case HInstruction::kGoto:
+ case HInstruction::kPackedSwitch:
+ case HInstruction::kTryBoundary:
+ case HInstruction::kClearException:
+ case HInstruction::kLoadException:
case HInstruction::kParameterValue:
case HInstruction::kReturn:
case HInstruction::kReturnVoid:
@@ -757,8 +761,13 @@ static bool CanAssembleGraphForRiscv64(HGraph* graph) {
case HInstruction::kLoadMethodHandle:
case HInstruction::kLoadMethodType:
case HInstruction::kInstanceFieldGet:
+ case HInstruction::kInstanceFieldSet:
case HInstruction::kStaticFieldGet:
+ case HInstruction::kStaticFieldSet:
case HInstruction::kArrayGet:
+ case HInstruction::kArrayLength:
+ case HInstruction::kArraySet:
+ case HInstruction::kBoundsCheck:
case HInstruction::kAbove:
case HInstruction::kAboveOrEqual:
case HInstruction::kBelow:
diff --git a/runtime/arch/riscv64/asm_support_riscv64.S b/runtime/arch/riscv64/asm_support_riscv64.S
index dd9d107291..6896f7c789 100644
--- a/runtime/arch/riscv64/asm_support_riscv64.S
+++ b/runtime/arch/riscv64/asm_support_riscv64.S
@@ -90,6 +90,22 @@
.endm
+// Macro to poison (negate) the reference for heap poisoning.
+.macro POISON_HEAP_REF ref
+#ifdef USE_HEAP_POISONING
+ neg \ref, \ref
+#endif // USE_HEAP_POISONING
+.endm
+
+
+// Macro to unpoison (negate) the reference for heap poisoning.
+.macro UNPOISON_HEAP_REF ref
+#ifdef USE_HEAP_POISONING
+ neg \ref, \ref
+#endif // USE_HEAP_POISONING
+.endm
+
+
.macro INCREASE_FRAME frame_adjustment
addi sp, sp, -(\frame_adjustment)
.cfi_adjust_cfa_offset (\frame_adjustment)
diff --git a/runtime/arch/riscv64/quick_entrypoints_riscv64.S b/runtime/arch/riscv64/quick_entrypoints_riscv64.S
index 61beee94e6..2a67d0d578 100644
--- a/runtime/arch/riscv64/quick_entrypoints_riscv64.S
+++ b/runtime/arch/riscv64/quick_entrypoints_riscv64.S
@@ -555,7 +555,7 @@ END art_quick_do_long_jump
CFI_RESTORE_STATE_AND_DEF_CFA sp, FRAME_SIZE_SAVE_EVERYTHING
sd a0, SAVE_EVERYTHING_FRAME_OFFSET_A0(sp) // update result in the frame
li a2, \is_ref // pass if result is a reference
- mv a1, x0 // pass the result
+ mv a1, a0 // pass the result
mv a0, xSELF // Thread::Current
call artDeoptimizeIfNeeded
CFI_REMEMBER_STATE
@@ -1083,6 +1083,182 @@ ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_method_type, artResolveMethod
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
+// Helper macros for `art_quick_aput_obj`.
+#ifdef USE_READ_BARRIER
+#ifdef USE_BAKER_READ_BARRIER
+.macro BAKER_RB_CHECK_GRAY_BIT_AND_LOAD dest, obj, offset, gray_slow_path_label
+ lw t6, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
+ slliw t6, t6, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT // Shift the state bit to sign bit.
+ bltz t6, \gray_slow_path_label
+ // False dependency to avoid needing load/load fence.
+ xor t6, t6, t6
+ add \obj, \obj, t6
+ lwu \dest, \offset(\obj) // Heap reference = 32b; zero-extends to `dest`.
+ UNPOISON_HEAP_REF \dest
+.endm
+
+.macro BAKER_RB_LOAD_AND_MARK dest, obj, offset, mark_function
+ lwu \dest, \offset(\obj) // Heap reference = 32b; zero-extends to `dest`.
+ UNPOISON_HEAP_REF \dest
+ // Save RA in a register preserved by `art_quick_read_barrier_mark_regNN`
+ // and unused by the `art_quick_aput_obj`.
+ mv t2, ra
+ call \mark_function
+ mv ra, t2 // Restore RA.
+.endm
+#else // USE_BAKER_READ_BARRIER
+ .extern artReadBarrierSlow
+.macro READ_BARRIER_SLOW dest, obj, offset
+ // Store registers used in art_quick_aput_obj (a0-a4, RA), stack is 16B aligned.
+ INCREASE_FRAME 48
+ SAVE_GPR a0, 0*8
+ SAVE_GPR a1, 1*8
+ SAVE_GPR a2, 2*8
+ SAVE_GPR a3, 3*8
+ SAVE_GPR a4, 4*8
+ SAVE_GPR ra, 5*8
+
+ // mv a0, \ref // Pass ref in A0 (no-op for now since parameter ref is unused).
+ .ifnc \obj, a1
+ mv a1, \obj // Pass `obj`.
+ .endif
+ li a2, #\offset // Pass offset.
+ call artReadBarrierSlow // artReadBarrierSlow(ref, obj, offset)
+ // No need to unpoison return value in A0, `artReadBarrierSlow()` would do the unpoisoning.
+ .ifnc \dest, a0
+ mv \dest, a0 // save return value in dest
+ .endif
+
+ // Conditionally restore saved registers
+ RESTORE_GPR_NE a0, 0*8, \dest
+ RESTORE_GPR_NE a1, 1*8, \dest
+ RESTORE_GPR_NE a2, 2*8, \dest
+ RESTORE_GPR_NE a3, 3*8, \dest
+ RESTORE_GPR_NE a4, 4*8, \dest
+ RESTORE_GPR ra, 5*8
+ DECREASE_FRAME 48
+.endm
+#endif // USE_BAKER_READ_BARRIER
+#endif // USE_READ_BARRIER
+
+ENTRY art_quick_aput_obj
+ beqz a2, .Laput_obj_null
+#if defined(USE_READ_BARRIER) && !defined(USE_BAKER_READ_BARRIER)
+ READ_BARRIER_SLOW a3, a0, MIRROR_OBJECT_CLASS_OFFSET
+ READ_BARRIER_SLOW a3, a3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET
+ READ_BARRIER_SLOW a4, a2, MIRROR_OBJECT_CLASS_OFFSET
+#else // !defined(USE_READ_BARRIER) || defined(USE_BAKER_READ_BARRIER)
+#ifdef USE_READ_BARRIER
+ // TODO(riscv64): Define marking register to avoid this load.
+ lw t6, THREAD_IS_GC_MARKING_OFFSET(xSELF)
+ bnez t6, .Laput_obj_gc_marking
+#endif // USE_READ_BARRIER
+ lwu a3, MIRROR_OBJECT_CLASS_OFFSET(a0) // Heap reference = 32b; zero-extends to a3.
+ UNPOISON_HEAP_REF a3
+ lwu a3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET(a3) // Heap reference = 32b; zero-extends to a3.
+ UNPOISON_HEAP_REF a3
+ lwu a4, MIRROR_OBJECT_CLASS_OFFSET(a2) // Heap reference = 32b; zero-extends to a4.
+ UNPOISON_HEAP_REF a4
+#endif // !defined(USE_READ_BARRIER) || defined(USE_BAKER_READ_BARRIER)
+ // value's type == array's component type - trivial assignability
+ bne a3, a4, .Laput_obj_check_assignability
+.Laput_obj_store:
+ sh2add a3, a1, a0
+ POISON_HEAP_REF a2
+ sw a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET(a3) // Heap reference = 32b.
+ ld a3, THREAD_CARD_TABLE_OFFSET(xSELF)
+ srli a0, a0, CARD_TABLE_CARD_SHIFT
+ add a0, a0, a3
+ sb a3, (a0)
+ ret
+
+.Laput_obj_null:
+ sh2add a3, a1, a0
+ sw a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET(a3) // Heap reference = 32b.
+ ret
+
+.Laput_obj_check_assignability:
+ // Store arguments and return register
+ INCREASE_FRAME 32
+ SAVE_GPR a0, 0*8
+ SAVE_GPR a1, 1*8
+ SAVE_GPR a2, 2*8
+ SAVE_GPR ra, 3*8
+
+ // Call runtime code
+ mv a0, a3 // Heap reference, 32b, "uncompress" = do nothing, already zero-extended.
+ mv a1, a4 // Heap reference, 32b, "uncompress" = do nothing, already zero-extended.
+ call artIsAssignableFromCode
+
+ // Check for exception
+ CFI_REMEMBER_STATE
+ beqz a0, .Laput_obj_throw_array_store_exception
+
+ // Restore
+ RESTORE_GPR a0, 0*8
+ RESTORE_GPR a1, 1*8
+ RESTORE_GPR a2, 2*8
+ RESTORE_GPR ra, 3*8
+ DECREASE_FRAME 32
+
+ sh2add a3, a1, a0
+ POISON_HEAP_REF a2
+ sw a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET(a3) // Heap reference = 32b.
+ ld a3, THREAD_CARD_TABLE_OFFSET(xSELF)
+ srli a0, a0, CARD_TABLE_CARD_SHIFT
+ add a0, a0, a3
+ sb a3, (a0)
+ ret
+
+.Laput_obj_throw_array_store_exception:
+ CFI_RESTORE_STATE_AND_DEF_CFA sp, 32
+ RESTORE_GPR a0, 0*8
+ RESTORE_GPR a1, 1*8
+ RESTORE_GPR a2, 2*8
+ RESTORE_GPR ra, 3*8
+ DECREASE_FRAME 32
+
+#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
+ CFI_REMEMBER_STATE
+#endif // defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
+ SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ mv a1, a2 // Pass value.
+ mv a2, xSELF // Pass Thread::Current().
+ call artThrowArrayStoreException // (Object*, Object*, Thread*).
+ unimp // Unreachable.
+
+#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
+ CFI_RESTORE_STATE_AND_DEF_CFA sp, 0
+.Laput_obj_gc_marking:
+ BAKER_RB_CHECK_GRAY_BIT_AND_LOAD \
+ a3, a0, MIRROR_OBJECT_CLASS_OFFSET, .Laput_obj_mark_array_class
+.Laput_obj_mark_array_class_continue:
+ BAKER_RB_CHECK_GRAY_BIT_AND_LOAD \
+ a3, a3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET, .Laput_obj_mark_array_element
+.Laput_obj_mark_array_element_continue:
+ BAKER_RB_CHECK_GRAY_BIT_AND_LOAD \
+ a4, a2, MIRROR_OBJECT_CLASS_OFFSET, .Laput_obj_mark_object_class
+.Laput_obj_mark_object_class_continue:
+ // value's type == array's component type - trivial assignability
+ bne a3, a4, .Laput_obj_check_assignability
+ j .Laput_obj_store
+
+.Laput_obj_mark_array_class:
+ BAKER_RB_LOAD_AND_MARK a3, a0, MIRROR_OBJECT_CLASS_OFFSET, art_quick_read_barrier_mark_reg13
+ j .Laput_obj_mark_array_class_continue
+
+.Laput_obj_mark_array_element:
+ BAKER_RB_LOAD_AND_MARK \
+ a3, a3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET, art_quick_read_barrier_mark_reg13
+ j .Laput_obj_mark_array_element_continue
+
+.Laput_obj_mark_object_class:
+ BAKER_RB_LOAD_AND_MARK a4, a2, MIRROR_OBJECT_CLASS_OFFSET, art_quick_read_barrier_mark_reg14
+ j .Laput_obj_mark_object_class_continue
+#endif // defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
+END art_quick_aput_obj
+
+
// Create a function `name` calling the art::ReadBarrier::Mark routine, getting its argument and
// returning its result through \reg, saving and restoring all caller-save registers.
//
@@ -1418,5 +1594,4 @@ UNDEFINED art_quick_get_char_static
UNDEFINED art_quick_get32_static
UNDEFINED art_quick_get64_static
UNDEFINED art_quick_get_obj_static
-UNDEFINED art_quick_aput_obj
UNDEFINED art_quick_indexof