Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c3940f6

Browse files
tomeksowiyurai007
andauthored
[RISC-V] Implement replacing safe-point call instructions under GC_STRESS (#97818)
* [RISC-V] Fix the System.NullReferenceException: Object reference not set to an instance of an object. in Methodical_r2.sh-deep_array_nz_r.dll when DOTNET_GCStress=4. * [RISC-V] Implement correctly replacing safe-point instructions under GC_STRESS and getting the target of call instructions jal and jalr * Add missing assign to shift --------- Co-authored-by: Dawid Jurczak <[email protected]>
1 parent 8aa6afc commit c3940f6

File tree

2 files changed

+65
-12
lines changed

2 files changed

+65
-12
lines changed

src/coreclr/vm/gccover.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,14 +343,12 @@ void ReplaceInstrAfterCall(PBYTE instrToReplace, MethodDesc* callMD)
343343
{
344344
*instrToReplace = INTERRUPT_INSTR;
345345
}
346-
#elif defined(TARGET_LOONGARCH64)
346+
#elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
347347
bool protectReturn = ispointerKind;
348348
if (protectReturn)
349349
*(DWORD*)instrToReplace = INTERRUPT_INSTR_PROTECT_RET;
350350
else
351351
*(DWORD*)instrToReplace = INTERRUPT_INSTR;
352-
#elif defined(TARGET_RISCV64)
353-
_ASSERTE(!"not implemented for RISCV64 NYI");
354352
#else
355353
_ASSERTE(!"not implemented for platform");
356354
#endif
@@ -680,6 +678,15 @@ void GCCoverageInfo::SprinkleBreakpoints(
680678

681679
#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
682680

681+
#ifdef TARGET_RISCV64
682+
enum
683+
{
684+
REG_RA = 1,
685+
JAL = 0x6f,
686+
JALR = 0x67,
687+
};
688+
#endif
689+
683690
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
684691

685692
void replaceSafePointInstructionWithGcStressInstr(UINT32 safePointOffset, LPVOID pGCCover)
@@ -780,7 +787,15 @@ void replaceSafePointInstructionWithGcStressInstr(UINT32 safePointOffset, LPVOID
780787
instructionIsACallThroughRegister = TRUE;
781788
}
782789
#elif defined(TARGET_RISCV64)
783-
_ASSERTE(!"not implemented for RISCV64 NYI");
790+
const INT32 instr = *((INT32*)savedInstrPtr - 1);
791+
792+
int opcode = instr & ~(-1 << 7);
793+
int linkReg = (instr >> 7) & ~(-1 << 5);
794+
795+
if ((opcode == JAL) && (linkReg == REG_RA))
796+
instructionIsACallThroughImmediate = TRUE;
797+
else if ((opcode == JALR) && (linkReg == REG_RA))
798+
instructionIsACallThroughRegister = TRUE;
784799
#endif // _TARGET_XXXX_
785800

786801
// safe point must always be after a call instruction
@@ -1028,7 +1043,38 @@ static PBYTE getTargetOfCall(PBYTE instrPtr, PCONTEXT regs, PBYTE* nextInstr) {
10281043
return 0; // Fail
10291044
}
10301045
#elif defined(TARGET_RISCV64)
1031-
_ASSERTE(!"not implemented for RISCV64 NYI");
1046+
INT32 instr = *reinterpret_cast<INT32*>(instrPtr);
1047+
int opcode = instr & ~(-1 << 7);
1048+
int linkReg = (instr >> 7) & ~(-1 << 5);
1049+
1050+
if ((opcode == JAL) && (linkReg == REG_RA))
1051+
{
1052+
// call through immediate
1053+
int imm = (instr >> 12);
1054+
1055+
int bits12to19 = imm & ~(-1 << 8);
1056+
imm >>= 8;
1057+
int bit11 = imm & ~(-1 << 1);
1058+
imm >>= 1;
1059+
int bits1to10 = imm & ~(-1 << 10);
1060+
imm >>= 10;
1061+
int signBits = imm;
1062+
1063+
int offset = (bits1to10 << 1) | (bit11 << 11) | (bits12to19 << 12) | (signBits << 20);
1064+
1065+
*nextInstr = instrPtr + 4;
1066+
return PC + offset;
1067+
}
1068+
else if ((opcode == JALR) && (linkReg == REG_RA))
1069+
{
1070+
// call through register
1071+
*nextInstr = instrPtr + 4; // TODO: adjust once we support "C" (compressed instructions)
1072+
1073+
int offset = (instr >> 20);
1074+
int jumpBaseReg = (instr >> 15) & ~(-1 << 5);
1075+
size_t value = (getRegVal(jumpBaseReg, regs) + offset) & ~(size_t)1;
1076+
return (BYTE *)value;
1077+
}
10321078
#endif
10331079

10341080
#ifdef TARGET_AMD64
@@ -1495,7 +1541,7 @@ void DoGcStress (PCONTEXT regs, NativeCodeVersion nativeCodeVersion)
14951541
atCall = (instrVal == INTERRUPT_INSTR_CALL);
14961542
afterCallProtect[0] = (instrVal == INTERRUPT_INSTR_PROTECT_RET);
14971543
#elif defined(TARGET_RISCV64)
1498-
_ASSERTE(!"not implemented for RISCV64 NYI");
1544+
14991545
DWORD instrVal = *(DWORD *)instrPtr;
15001546
forceStack[6] = &instrVal; // This is so I can see it fastchecked
15011547

src/coreclr/vm/gccover.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ typedef DPTR(GCCoverageInfo) PTR_GCCoverageInfo; // see code:GCCoverageInfo::sav
113113
#define INTERRUPT_INSTR_PROTECT_RET 0xffffff0d
114114

115115
#elif defined(TARGET_RISCV64)
116-
// TODO-RISCV64: Confirm the following encodings are undefined
117-
#define INTERRUPT_INSTR 0x20000000
118-
#define INTERRUPT_INSTR_CALL 0x20010000
119-
#define INTERRUPT_INSTR_PROTECT_RET 0x20020000
116+
// The following encodings are undefined.
117+
#define INTERRUPT_INSTR 0x20000000 // unimp, fld
118+
#define INTERRUPT_INSTR_CALL 0x20010000 // unimp, jal
119+
#define INTERRUPT_INSTR_PROTECT_RET 0x20020000 // unimp, fld
120120

121121
#endif // _TARGET_*
122122

@@ -181,8 +181,15 @@ inline bool IsGcCoverageInterruptInstructionVal(UINT32 instrVal)
181181
}
182182
}
183183
#elif defined(TARGET_RISCV64)
184-
_ASSERTE(!"RISCV64:NYI");
185-
return false;
184+
switch (instrVal)
185+
{
186+
case INTERRUPT_INSTR:
187+
case INTERRUPT_INSTR_CALL:
188+
case INTERRUPT_INSTR_PROTECT_RET:
189+
return true;
190+
default:
191+
return false;
192+
}
186193

187194
#else // x64 and x86
188195

0 commit comments

Comments
 (0)