Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Test Only] Ignore, just to run some tests. #99025

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
60d7330
allow async interruptions on safepoints
VSadov Dec 4, 2023
4ca6727
ARM64 TODO
VSadov Dec 4, 2023
2027c2c
comments
VSadov Dec 4, 2023
081c421
report GC ref/byref returns at partially interruptible callsites
VSadov Dec 9, 2023
97626c5
enable on all platforms
VSadov Dec 9, 2023
fa329fd
tweak
VSadov Dec 10, 2023
a56c2b4
fix after rebasing
VSadov Jan 27, 2024
f588658
do not record tailcalls
VSadov Feb 16, 2024
4a8d580
IsInterruptibleSafePoint
VSadov Feb 16, 2024
f0c0242
update gccover
VSadov Feb 17, 2024
28f68aa
turn on new behavior on a gcinfo version
VSadov Feb 17, 2024
4731011
ensure a breakpoint after all throwing calls
VSadov Feb 18, 2024
9da9c4c
tailcalls tweak
VSadov Feb 18, 2024
bee227a
do not report unused returns
VSadov Feb 21, 2024
a849f0c
CORINFO_HELP_FAIL_FAST should not be a safepoint
VSadov Feb 21, 2024
98a2df7
treat tailcalls as emitNoGChelper
VSadov Feb 21, 2024
d9457cf
versioning tweak
VSadov Feb 21, 2024
4663817
enable in CoreCLR (not just for GC stress scenarios)
VSadov Feb 21, 2024
dcd676c
fix x86 build
VSadov Feb 22, 2024
db0d6bc
other architectures
VSadov Feb 22, 2024
90eb255
an assert
VSadov Feb 22, 2024
3f64252
make gcc happy
VSadov Feb 22, 2024
abe44f9
added a knob DOTNET_InterruptibleCallSites
VSadov Feb 22, 2024
5f509c0
code formatting
VSadov Feb 22, 2024
7e73806
moved DOTNET_InterruptibleCallSites check to the code manager
VSadov Feb 23, 2024
562c18b
JIT_StackProbe should not be a safepoint (stack is not cleaned yet)
VSadov Feb 23, 2024
2174cd7
Hooked up GCInfo version to R2R file version
VSadov Feb 23, 2024
bca871d
formatting
VSadov Feb 24, 2024
9360aa2
GCStress support for RISC architectures
VSadov Feb 25, 2024
f9055f5
Update src/coreclr/inc/gcinfo.h
VSadov Feb 25, 2024
3d1b18a
make InterruptibleSafePointsEnabled static
VSadov Feb 25, 2024
b6a6542
fix linux-x86 build.
VSadov Feb 25, 2024
d53ba90
ARM32 actually can`t return 2 GC references, so can filter out R1 early
VSadov Feb 27, 2024
78ac29c
try disabling on ARM32
VSadov Feb 28, 2024
5af592e
emit jumps
VSadov Feb 28, 2024
b8b2bfe
rev gcencode
VSadov Feb 28, 2024
f26b3c4
report unused
VSadov Feb 28, 2024
9a22f30
no br
VSadov Feb 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions src/coreclr/gcinfo/gcinfoencoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,11 @@ void GcInfoEncoder::FinalizeSlotIds()
#endif
}

bool GcInfoEncoder::IsAlwaysScratch(GcSlotDesc &slotDesc)
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED

// tells whether a slot cannot contain an object reference
// at call instruction or right after returning
bool GcInfoEncoder::DoNotTrackInPartiallyInterruptible(GcSlotDesc &slotDesc)
{
#if defined(TARGET_ARM)

Expand All @@ -933,7 +937,31 @@ bool GcInfoEncoder::IsAlwaysScratch(GcSlotDesc &slotDesc)
_ASSERTE(regNum >= 0 && regNum <= 14);
_ASSERTE(regNum != 13); // sp

return ((regNum <= 3) || (regNum >= 12)); // R12 and R14/LR are both scratch registers
return ((regNum <= 3) || (regNum >= 12)) // R12 is volatile and SP/LR can't contain objects around calls
&& regNum != 0 // R0 can contain return value
;
}
else if (!slotDesc.IsUntracked() && (slotDesc.Slot.Stack.Base == GC_SP_REL) &&
((UINT32)slotDesc.Slot.Stack.SpOffset < m_SizeOfStackOutgoingAndScratchArea))
{
return TRUE;
}
else
return FALSE;

#elif defined(TARGET_ARM64)

_ASSERTE(m_SizeOfStackOutgoingAndScratchArea != (UINT32)-1);
if (slotDesc.IsRegister())
{
int regNum = (int)slotDesc.Slot.RegisterNumber;
_ASSERTE(regNum >= 0 && regNum <= 30);
_ASSERTE(regNum != 18);

return (regNum <= 17 || regNum >= 29) // X0 through X17 are scratch, FP/LR can't be used for objects around calls
&& regNum != 0 // X0 can contain return value
&& regNum != 1 // X1 can contain return value
;
}
else if (!slotDesc.IsUntracked() && (slotDesc.Slot.Stack.Base == GC_SP_REL) &&
((UINT32)slotDesc.Slot.Stack.SpOffset < m_SizeOfStackOutgoingAndScratchArea))
Expand All @@ -953,7 +981,7 @@ bool GcInfoEncoder::IsAlwaysScratch(GcSlotDesc &slotDesc)
_ASSERTE(regNum != 4); // rsp

UINT16 PreservedRegMask =
(1 << 3) // rbx
(1 << 3) // rbx
| (1 << 5) // rbp
#ifndef UNIX_AMD64_ABI
| (1 << 6) // rsi
Expand All @@ -962,7 +990,12 @@ bool GcInfoEncoder::IsAlwaysScratch(GcSlotDesc &slotDesc)
| (1 << 12) // r12
| (1 << 13) // r13
| (1 << 14) // r14
| (1 << 15); // r15
| (1 << 15) // r15
| (1 << 0) // rax - may contain return value
#ifdef UNIX_AMD64_ABI
| (1 << 2) // rdx - may contain return value
#endif
;

return !(PreservedRegMask & (1 << regNum));
}
Expand All @@ -978,6 +1011,7 @@ bool GcInfoEncoder::IsAlwaysScratch(GcSlotDesc &slotDesc)
return FALSE;
#endif
}
#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED

void GcInfoEncoder::Build()
{
Expand Down Expand Up @@ -1396,7 +1430,7 @@ void GcInfoEncoder::Build()
else
{
UINT32 slotIndex = pCurrent->SlotId;
if(!IsAlwaysScratch(m_SlotTable[slotIndex]))
if(!DoNotTrackInPartiallyInterruptible(m_SlotTable[slotIndex]))
{
BYTE becomesLive = pCurrent->BecomesLive;
_ASSERTE((liveState.ReadBit(slotIndex) && !becomesLive)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ CONFIG_DWORD_INFO(INTERNAL_DiagnosticSuspend, W("DiagnosticSuspend"), 0, "")
CONFIG_DWORD_INFO(INTERNAL_SuspendDeadlockTimeout, W("SuspendDeadlockTimeout"), 40000, "")
CONFIG_DWORD_INFO(INTERNAL_SuspendThreadDeadlockTimeoutMs, W("SuspendThreadDeadlockTimeoutMs"), 2000, "")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_ThreadSuspendInjection, W("INTERNAL_ThreadSuspendInjection"), 1, "Specifies whether to inject activations for thread suspension on Unix")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterruptibleCallSites, W("InterruptibleCallSites"), 1, "Specifies whether to allow asynchronous thread interruptions at call sites (requires GCInfo v3)")

///
/// Thread (miscellaneous)
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/inc/eetwain.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,9 @@ virtual
bool IsGcSafe( EECodeInfo *pCodeInfo,
DWORD dwRelOffset);

static
bool InterruptibleSafePointsEnabled();

#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
virtual
bool HasTailCalls(EECodeInfo *pCodeInfo);
Expand Down
13 changes: 10 additions & 3 deletions src/coreclr/inc/gcinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const unsigned this_OFFSET_FLAG = 0x2; // the offset is "this"
// The current GCInfo Version
//-----------------------------------------------------------------------------

#define GCINFO_VERSION 2
#define GCINFO_VERSION 3

//-----------------------------------------------------------------------------
// GCInfoToken: A wrapper that contains the GcInfo data and version number.
Expand All @@ -59,9 +59,16 @@ struct GCInfoToken
PTR_VOID Info;
UINT32 Version;

static UINT32 ReadyToRunVersionToGcInfoVersion(UINT32 readyToRunMajorVersion)
static UINT32 ReadyToRunVersionToGcInfoVersion(UINT32 readyToRunMajorVersion, UINT32 readyToRunMinorVersion)
{
// GcInfo version is current from ReadyToRun version 2.0
// Once MINIMUM_READYTORUN_MAJOR_VERSION is bumped to 10+
// delete the following and just return GCINFO_VERSION
//
// R2R 9.0 and 9.1 use GCInfo v2
// R2R 9.2 uses GCInfo v3
if (readyToRunMajorVersion == 9 && readyToRunMinorVersion < 2)
return 2;

return GCINFO_VERSION;
}
};
Expand Down
9 changes: 7 additions & 2 deletions src/coreclr/inc/gcinfodecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct GCInfoToken
GCInfoToken(PTR_VOID info)
{
Info = info;
Version = 2;
Version = 3;
}
};

Expand Down Expand Up @@ -499,12 +499,17 @@ class GcInfoDecoder
//------------------------------------------------------------------------

bool IsInterruptible();
bool HasInterruptibleRanges();

#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
bool IsSafePoint();
bool AreSafePointsInterruptible();
bool IsInterruptibleSafePoint();

// This is used for gccoverage
bool IsSafePoint(UINT32 codeOffset);

typedef void EnumerateSafePointsCallback (UINT32 offset, void * hCallback);
typedef void EnumerateSafePointsCallback (GcInfoDecoder* decoder, UINT32 offset, void * hCallback);
void EnumerateSafePoints(EnumerateSafePointsCallback * pCallback, void * hCallback);

#endif
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/inc/gcinfoencoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,9 @@ class GcInfoEncoder
void SizeofSlotStateVarLengthVector(const BitArray& vector, UINT32 baseSkip, UINT32 baseRun, UINT32 * pSizeofSimple, UINT32 * pSizeofRLE, UINT32 * pSizeofRLENeg);
UINT32 WriteSlotStateVarLengthVector(BitStreamWriter &writer, const BitArray& vector, UINT32 baseSkip, UINT32 baseRun);

bool IsAlwaysScratch(GcSlotDesc &slot);
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
bool DoNotTrackInPartiallyInterruptible(GcSlotDesc &slot);
#endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED

// Assumes that "*ppTransitions" is has size "numTransitions", is sorted by CodeOffset then by SlotId,
// and that "*ppEndTransitions" points one beyond the end of the array. If "*ppTransitions" contains
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
// R2R Version 8.0 Changes the alignment of the Int128 type
// R2R Version 9.0 adds support for the Vector512 type
// R2R Version 9.1 adds new helpers to allocate objects on frozen segments
// R2R Version 9.2 adds MemZero and NativeMemSet helpers

// R2R Version 9.2 adds MemZero and NativeMemSet helpers,
// uses GCInfo v3, which makes safe points in partially interruptible code interruptible.

struct READYTORUN_CORE_HEADER
{
Expand Down
34 changes: 22 additions & 12 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3497,25 +3497,35 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
emitAttr retSize = EA_PTRSIZE;
emitAttr secondRetSize = EA_UNKNOWN;

if (call->HasMultiRegRetVal())
// unused values are of no interest to GC.
// if (!call->IsUnusedValue())
{
retSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(0));
secondRetSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(1));
}
else
{
assert(call->gtType != TYP_STRUCT);

if (call->gtType == TYP_REF)
if (call->HasMultiRegRetVal())
{
retSize = EA_GCREF;
retSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(0));
secondRetSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(1));
}
else if (call->gtType == TYP_BYREF)
else
{
retSize = EA_BYREF;
assert(call->gtType != TYP_STRUCT);

if (call->gtType == TYP_REF)
{
retSize = EA_GCREF;
}
else if (call->gtType == TYP_BYREF)
{
retSize = EA_BYREF;
}
}
}

#ifdef TARGET_ARM
// ARM32 support multireg returns, but only to return 64bit primitives.
assert(secondRetSize != EA_GCREF);
assert(secondRetSize != EA_BYREF);
#endif

DebugInfo di;
// We need to propagate the debug information to the call instruction, so we can emit
// an IL to native mapping record for the call, to support managed return value debugging.
Expand Down
13 changes: 11 additions & 2 deletions src/coreclr/jit/codegenlinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,8 +704,7 @@ void CodeGen::genCodeForBBlist()
}
// Do likewise for blocks that end in DOES_NOT_RETURN calls
// that were not caught by the above rules. This ensures that
// gc register liveness doesn't change across call instructions
// in fully-interruptible mode.
// gc register liveness doesn't change to some random state after call instructions
else
{
GenTree* call = block->lastNode();
Expand Down Expand Up @@ -756,6 +755,16 @@ void CodeGen::genCodeForBBlist()

case BBJ_ALWAYS:
{
#if DEBUG
GenTree* call = block->lastNode();
if ((call != nullptr) && (call->gtOper == GT_CALL))
{
if ((call->AsCall()->gtCallMoreFlags & GTF_CALL_M_DOES_NOT_RETURN) != 0)
{
assert(!"Unexpected fallthrough after GTF_CALL_M_DOES_NOT_RETURN");
}
}
#endif
// If this block jumps to the next one, we might be able to skip emitting the jump
if (block->CanRemoveJumpToNext(compiler))
{
Expand Down
28 changes: 16 additions & 12 deletions src/coreclr/jit/codegenloongarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6575,22 +6575,26 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
emitAttr retSize = EA_PTRSIZE;
emitAttr secondRetSize = EA_UNKNOWN;

if (call->HasMultiRegRetVal())
// unused values are of no interest to GC.
if (!call->IsUnusedValue())
{
retSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(0));
secondRetSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(1));
}
else
{
assert(call->gtType != TYP_STRUCT);

if (call->gtType == TYP_REF)
if (call->HasMultiRegRetVal())
{
retSize = EA_GCREF;
retSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(0));
secondRetSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(1));
}
else if (call->gtType == TYP_BYREF)
else
{
retSize = EA_BYREF;
assert(call->gtType != TYP_STRUCT);

if (call->gtType == TYP_REF)
{
retSize = EA_GCREF;
}
else if (call->gtType == TYP_BYREF)
{
retSize = EA_BYREF;
}
}
}

Expand Down
28 changes: 16 additions & 12 deletions src/coreclr/jit/codegenriscv64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6597,22 +6597,26 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
emitAttr retSize = EA_PTRSIZE;
emitAttr secondRetSize = EA_UNKNOWN;

if (call->HasMultiRegRetVal())
// unused values are of no interest to GC.
if (!call->IsUnusedValue())
{
retSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(0));
secondRetSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(1));
}
else
{
assert(call->gtType != TYP_STRUCT);

if (call->gtType == TYP_REF)
if (call->HasMultiRegRetVal())
{
retSize = EA_GCREF;
retSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(0));
secondRetSize = emitTypeSize(pRetTypeDesc->GetReturnRegType(1));
}
else if (call->gtType == TYP_BYREF)
else
{
retSize = EA_BYREF;
assert(call->gtType != TYP_STRUCT);

if (call->gtType == TYP_REF)
{
retSize = EA_GCREF;
}
else if (call->gtType == TYP_BYREF)
{
retSize = EA_BYREF;
}
}
}

Expand Down
28 changes: 16 additions & 12 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6233,22 +6233,26 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA
emitAttr retSize = EA_PTRSIZE;
emitAttr secondRetSize = EA_UNKNOWN;

if (call->HasMultiRegRetVal())
// unused values are of no interest to GC.
if (!call->IsUnusedValue())
{
retSize = emitTypeSize(retTypeDesc->GetReturnRegType(0));
secondRetSize = emitTypeSize(retTypeDesc->GetReturnRegType(1));
}
else
{
assert(!varTypeIsStruct(call));

if (call->gtType == TYP_REF)
if (call->HasMultiRegRetVal())
{
retSize = EA_GCREF;
retSize = emitTypeSize(retTypeDesc->GetReturnRegType(0));
secondRetSize = emitTypeSize(retTypeDesc->GetReturnRegType(1));
}
else if (call->gtType == TYP_BYREF)
else
{
retSize = EA_BYREF;
assert(!varTypeIsStruct(call));

if (call->gtType == TYP_REF)
{
retSize = EA_GCREF;
}
else if (call->gtType == TYP_BYREF)
{
retSize = EA_BYREF;
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/coreclr/jit/emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2856,6 +2856,9 @@ bool emitter::emitNoGChelper(CorInfoHelpFunc helpFunc)

case CORINFO_HELP_INIT_PINVOKE_FRAME:

case CORINFO_HELP_FAIL_FAST:
case CORINFO_HELP_STACK_PROBE:

case CORINFO_HELP_VALIDATE_INDIRECT_CALL:
return true;

Expand Down Expand Up @@ -10044,7 +10047,7 @@ void emitter::emitStackPopLargeStk(BYTE* addr, bool isCall, unsigned char callIn

// We make a bitmask whose bits correspond to callee-saved register indices (in the sequence
// of callee-saved registers only).
for (unsigned calleeSavedRegIdx = 0; calleeSavedRegIdx < CNT_CALLEE_SAVED; calleeSavedRegIdx++)
for (unsigned calleeSavedRegIdx = 0; calleeSavedRegIdx < CNT_CALL_GC_REGS; calleeSavedRegIdx++)
{
regMaskTP calleeSavedRbm = raRbmCalleeSaveOrder[calleeSavedRegIdx];
if (emitThisGCrefRegs & calleeSavedRbm)
Expand Down
Loading
Loading