diff --git a/src/coreclr/gcinfo/gcinfoencoder.cpp b/src/coreclr/gcinfo/gcinfoencoder.cpp index fb2f06a80c44a5..d1988ba34a5394 100644 --- a/src/coreclr/gcinfo/gcinfoencoder.cpp +++ b/src/coreclr/gcinfo/gcinfoencoder.cpp @@ -490,13 +490,6 @@ GcInfoEncoder::GcInfoEncoder( m_IsSlotTableFrozen = FALSE; #endif //_DEBUG -#ifndef TARGET_X86 - // If the compiler doesn't set the GCInfo, report RT_Unset. - // This is used for compatibility with JITs that aren't updated to use the new API. - m_ReturnKind = RT_Unset; -#else - m_ReturnKind = RT_Illegal; -#endif // TARGET_X86 m_CodeLength = 0; #ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA m_SizeOfStackOutgoingAndScratchArea = -1; @@ -776,13 +769,6 @@ void GcInfoEncoder::SetReversePInvokeFrameSlot(INT32 spOffset) m_ReversePInvokeFrameSlot = spOffset; } -void GcInfoEncoder::SetReturnKind(ReturnKind returnKind) -{ - _ASSERTE(IsValidReturnKind(returnKind)); - - m_ReturnKind = returnKind; -} - struct GcSlotDescAndId { GcSlotDesc m_SlotDesc; @@ -1045,16 +1031,15 @@ void GcInfoEncoder::Build() BOOL slimHeader = (!m_IsVarArg && !hasGSCookie && (m_PSPSymStackSlot == NO_PSP_SYM) && !hasContextParamType && (m_InterruptibleRanges.Count() == 0) && !hasReversePInvokeFrame && ((m_StackBaseRegister == NO_STACK_BASE_REGISTER) || (NORMALIZE_STACK_BASE_REGISTER(m_StackBaseRegister) == 0))) && - (m_SizeOfEditAndContinuePreservedArea == NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA) && #ifdef TARGET_AMD64 !m_WantsReportOnlyLeaf && #elif defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) !m_HasTailCalls && #endif // TARGET_AMD64 - !IsStructReturnKind(m_ReturnKind); + (m_SizeOfEditAndContinuePreservedArea == NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA); // All new code is generated for the latest GCINFO_VERSION. - // So, always encode RetunrKind and encode ReversePInvokeFrameSlot where applicable. + // So, always encode ReversePInvokeFrameSlot where applicable. if (slimHeader) { // Slim encoding means nothing special, partially interruptible, maybe a default frame register @@ -1065,8 +1050,6 @@ void GcInfoEncoder::Build() assert(m_StackBaseRegister == 8 || 2 == m_StackBaseRegister); #endif GCINFO_WRITE(m_Info1, (m_StackBaseRegister == NO_STACK_BASE_REGISTER) ? 0 : 1, 1, FlagsSize); - - GCINFO_WRITE(m_Info1, m_ReturnKind, SIZE_OF_RETURN_KIND_IN_SLIM_HEADER, RetKindSize); } else { @@ -1089,8 +1072,6 @@ void GcInfoEncoder::Build() #endif // TARGET_AMD64 GCINFO_WRITE(m_Info1, ((m_SizeOfEditAndContinuePreservedArea != NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA) ? 1 : 0), 1, FlagsSize); GCINFO_WRITE(m_Info1, (hasReversePInvokeFrame ? 1 : 0), 1, FlagsSize); - - GCINFO_WRITE(m_Info1, m_ReturnKind, SIZE_OF_RETURN_KIND_IN_FAT_HEADER, RetKindSize); } _ASSERTE( m_CodeLength > 0 ); @@ -1217,42 +1198,19 @@ void GcInfoEncoder::Build() /////////////////////////////////////////////////////////////////////// // Normalize call sites - // Eliminate call sites that fall inside interruptible ranges /////////////////////////////////////////////////////////////////////// + _ASSERTE(m_NumCallSites == 0 || numInterruptibleRanges == 0); + UINT32 numCallSites = 0; for(UINT32 callSiteIndex = 0; callSiteIndex < m_NumCallSites; callSiteIndex++) { UINT32 callSite = m_pCallSites[callSiteIndex]; - // There's a contract with the EE that says for non-leaf stack frames, where the - // method is stopped at a call site, the EE will not query with the return PC, but - // rather the return PC *minus 1*. - // The reason is that variable/register liveness may change at the instruction immediately after the - // call, so we want such frames to appear as if they are "within" the call. - // Since we use "callSite" as the "key" when we search for the matching descriptor, also subtract 1 here - // (after, of course, adding the size of the call instruction to get the return PC). - callSite += m_pCallSiteSizes[callSiteIndex] - 1; + callSite += m_pCallSiteSizes[callSiteIndex]; _ASSERTE(DENORMALIZE_CODE_OFFSET(NORMALIZE_CODE_OFFSET(callSite)) == callSite); UINT32 normOffset = NORMALIZE_CODE_OFFSET(callSite); - - BOOL keepIt = TRUE; - - for(UINT32 intRangeIndex = 0; intRangeIndex < numInterruptibleRanges; intRangeIndex++) - { - InterruptibleRange *pRange = &pRanges[intRangeIndex]; - if(pRange->NormStopOffset > normOffset) - { - if(pRange->NormStartOffset <= normOffset) - { - keepIt = FALSE; - } - break; - } - } - - if(keepIt) - m_pCallSites[numCallSites++] = normOffset; + m_pCallSites[numCallSites++] = normOffset; } GCINFO_WRITE_VARL_U(m_Info1, NORMALIZE_NUM_SAFE_POINTS(numCallSites), NUM_SAFE_POINTS_ENCBASE, NumCallSitesSize); @@ -1419,7 +1377,7 @@ void GcInfoEncoder::Build() for(pCurrent = pTransitions; pCurrent < pEndTransitions; ) { - if(pCurrent->CodeOffset > callSite) + if(pCurrent->CodeOffset >= callSite) { couldBeLive |= liveState; @@ -1774,7 +1732,7 @@ void GcInfoEncoder::Build() { for(pCurrent = pTransitions; pCurrent < pEndTransitions; ) { - if(pCurrent->CodeOffset > callSite) + if(pCurrent->CodeOffset >= callSite) { // Time to record the call site @@ -1873,7 +1831,7 @@ void GcInfoEncoder::Build() for(pCurrent = pTransitions; pCurrent < pEndTransitions; ) { - if(pCurrent->CodeOffset > callSite) + if(pCurrent->CodeOffset >= callSite) { // Time to encode the call site @@ -1920,7 +1878,7 @@ void GcInfoEncoder::Build() for(pCurrent = pTransitions; pCurrent < pEndTransitions; ) { - if(pCurrent->CodeOffset > callSite) + if(pCurrent->CodeOffset >= callSite) { // Time to encode the call site GCINFO_WRITE_VECTOR(m_Info1, liveState, CallSiteStateSize); diff --git a/src/coreclr/inc/gcinfo.h b/src/coreclr/inc/gcinfo.h index a400ecfbf5c9e8..80ff267d583e0e 100644 --- a/src/coreclr/inc/gcinfo.h +++ b/src/coreclr/inc/gcinfo.h @@ -36,7 +36,7 @@ const unsigned this_OFFSET_FLAG = 0x2; // the offset is "this" // The current GCInfo Version //----------------------------------------------------------------------------- -#define GCINFO_VERSION 3 +#define GCINFO_VERSION 4 //----------------------------------------------------------------------------- // GCInfoToken: A wrapper that contains the GcInfo data and version number. diff --git a/src/coreclr/inc/gcinfoencoder.h b/src/coreclr/inc/gcinfoencoder.h index 0cf7f67800b9c3..8c5daf92c23b3f 100644 --- a/src/coreclr/inc/gcinfoencoder.h +++ b/src/coreclr/inc/gcinfoencoder.h @@ -409,13 +409,6 @@ class GcInfoEncoder GcSlotState slotState ); - - //------------------------------------------------------------------------ - // ReturnKind - //------------------------------------------------------------------------ - - void SetReturnKind(ReturnKind returnKind); - //------------------------------------------------------------------------ // Miscellaneous method information //------------------------------------------------------------------------ @@ -509,7 +502,6 @@ class GcInfoEncoder INT32 m_PSPSymStackSlot; INT32 m_GenericsInstContextStackSlot; GENERIC_CONTEXTPARAM_TYPE m_contextParamType; - ReturnKind m_ReturnKind; UINT32 m_CodeLength; UINT32 m_StackBaseRegister; UINT32 m_SizeOfEditAndContinuePreservedArea; diff --git a/src/coreclr/inc/gcinfotypes.h b/src/coreclr/inc/gcinfotypes.h index b770bb1bbcff9b..ef33fc275fe282 100644 --- a/src/coreclr/inc/gcinfotypes.h +++ b/src/coreclr/inc/gcinfotypes.h @@ -637,8 +637,6 @@ void FASTCALL decodeCallPattern(int pattern, #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6 #define GS_COOKIE_STACK_SLOT_ENCBASE 6 #define CODE_LENGTH_ENCBASE 8 -#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2 -#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 4 #define STACK_BASE_REGISTER_ENCBASE 3 #define SIZE_OF_STACK_AREA_ENCBASE 3 #define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 4 @@ -679,8 +677,8 @@ void FASTCALL decodeCallPattern(int pattern, #define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>2) #define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<2) #define CODE_OFFSETS_NEED_NORMALIZATION 1 -#define NORMALIZE_CODE_OFFSET(x) (x) // Instructions are 2/4 bytes long in Thumb/ARM states, -#define DENORMALIZE_CODE_OFFSET(x) (x) // but the safe-point offsets are encoded with a -1 adjustment. +#define NORMALIZE_CODE_OFFSET(x) ((x)>>1) // Instructions are 2/4 bytes long in Thumb/ARM states, +#define DENORMALIZE_CODE_OFFSET(x) ((x)<<1) #define NORMALIZE_REGISTER(x) (x) #define DENORMALIZE_REGISTER(x) (x) #define NORMALIZE_NUM_SAFE_POINTS(x) (x) @@ -695,8 +693,6 @@ void FASTCALL decodeCallPattern(int pattern, #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 5 #define GS_COOKIE_STACK_SLOT_ENCBASE 5 #define CODE_LENGTH_ENCBASE 7 -#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2 -#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 2 #define STACK_BASE_REGISTER_ENCBASE 1 #define SIZE_OF_STACK_AREA_ENCBASE 3 #define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 3 @@ -735,9 +731,9 @@ void FASTCALL decodeCallPattern(int pattern, #define DENORMALIZE_STACK_BASE_REGISTER(x) ((x)^29) #define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>3) #define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<3) -#define CODE_OFFSETS_NEED_NORMALIZATION 0 -#define NORMALIZE_CODE_OFFSET(x) (x) // Instructions are 4 bytes long, but the safe-point -#define DENORMALIZE_CODE_OFFSET(x) (x) // offsets are encoded with a -1 adjustment. +#define CODE_OFFSETS_NEED_NORMALIZATION 1 +#define NORMALIZE_CODE_OFFSET(x) ((x)>>2) // Instructions are 4 bytes long +#define DENORMALIZE_CODE_OFFSET(x) ((x)<<2) #define NORMALIZE_REGISTER(x) (x) #define DENORMALIZE_REGISTER(x) (x) #define NORMALIZE_NUM_SAFE_POINTS(x) (x) @@ -750,8 +746,6 @@ void FASTCALL decodeCallPattern(int pattern, #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6 #define GS_COOKIE_STACK_SLOT_ENCBASE 6 #define CODE_LENGTH_ENCBASE 8 -#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2 -#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 4 #define STACK_BASE_REGISTER_ENCBASE 2 // FP encoded as 0, SP as 2. #define SIZE_OF_STACK_AREA_ENCBASE 3 #define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 4 @@ -790,9 +784,9 @@ void FASTCALL decodeCallPattern(int pattern, #define DENORMALIZE_STACK_BASE_REGISTER(x) ((x) == 0 ? 22 : 3) #define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>3) #define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<3) -#define CODE_OFFSETS_NEED_NORMALIZATION 0 -#define NORMALIZE_CODE_OFFSET(x) (x) // Instructions are 4 bytes long, but the safe-point -#define DENORMALIZE_CODE_OFFSET(x) (x) // offsets are encoded with a -1 adjustment. +#define CODE_OFFSETS_NEED_NORMALIZATION 1 +#define NORMALIZE_CODE_OFFSET(x) ((x)>>2) // Instructions are 4 bytes long +#define DENORMALIZE_CODE_OFFSET(x) ((x)<<2) #define NORMALIZE_REGISTER(x) (x) #define DENORMALIZE_REGISTER(x) (x) #define NORMALIZE_NUM_SAFE_POINTS(x) (x) @@ -805,8 +799,6 @@ void FASTCALL decodeCallPattern(int pattern, #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6 #define GS_COOKIE_STACK_SLOT_ENCBASE 6 #define CODE_LENGTH_ENCBASE 8 -#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2 -#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 4 // FP/SP encoded as 0 or 1. #define STACK_BASE_REGISTER_ENCBASE 2 #define SIZE_OF_STACK_AREA_ENCBASE 3 @@ -845,9 +837,9 @@ void FASTCALL decodeCallPattern(int pattern, #define DENORMALIZE_STACK_BASE_REGISTER(x) ((x) == 0 ? 8 : 2) #define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>3) #define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<3) -#define CODE_OFFSETS_NEED_NORMALIZATION 0 -#define NORMALIZE_CODE_OFFSET(x) (x) // Instructions are 4 bytes long, but the safe-point -#define DENORMALIZE_CODE_OFFSET(x) (x) // offsets are encoded with a -1 adjustment. +#define CODE_OFFSETS_NEED_NORMALIZATION 1 +#define NORMALIZE_CODE_OFFSET(x) ((x)>>2) // Instructions are 4 bytes long +#define DENORMALIZE_CODE_OFFSET(x) ((x)<<2) #define NORMALIZE_REGISTER(x) (x) #define DENORMALIZE_REGISTER(x) (x) #define NORMALIZE_NUM_SAFE_POINTS(x) (x) @@ -860,8 +852,6 @@ void FASTCALL decodeCallPattern(int pattern, #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6 #define GS_COOKIE_STACK_SLOT_ENCBASE 6 #define CODE_LENGTH_ENCBASE 8 -#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2 -#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 4 #define STACK_BASE_REGISTER_ENCBASE 2 // FP encoded as 0, SP as 1 #define SIZE_OF_STACK_AREA_ENCBASE 3 @@ -924,8 +914,6 @@ PORTABILITY_WARNING("Please specialize these definitions for your platform!") #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6 #define GS_COOKIE_STACK_SLOT_ENCBASE 6 #define CODE_LENGTH_ENCBASE 6 -#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2 -#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 2 #define STACK_BASE_REGISTER_ENCBASE 3 #define SIZE_OF_STACK_AREA_ENCBASE 6 #define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 3 diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index f5737ab0de97c3..1ca6b12b594132 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -19,10 +19,10 @@ // src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h // If you update this, ensure you run `git grep MINIMUM_READYTORUN_MAJOR_VERSION` // and handle pending work. -#define READYTORUN_MAJOR_VERSION 10 -#define READYTORUN_MINOR_VERSION 0x0001 +#define READYTORUN_MAJOR_VERSION 11 +#define READYTORUN_MINOR_VERSION 0x0000 -#define MINIMUM_READYTORUN_MAJOR_VERSION 10 +#define MINIMUM_READYTORUN_MAJOR_VERSION 11 // R2R Version 2.1 adds the InliningInfo section // R2R Version 2.2 adds the ProfileDataInfo section @@ -38,6 +38,7 @@ // uses GCInfo v3, which makes safe points in partially interruptible code interruptible. // R2R Version 10.0 adds support for the statics being allocated on a per type basis instead of on a per module basis, disable support for LogMethodEnter helper // R2R Version 10.1 adds Unbox_TypeTest helper +// R2R Version 11 uses GCInfo v4, which encodes safe points without -1 offset and does not track return kinds in GCInfo struct READYTORUN_CORE_HEADER { diff --git a/src/coreclr/jit/gcencode.cpp b/src/coreclr/jit/gcencode.cpp index 60b0de33c83836..8a62434e99a98e 100644 --- a/src/coreclr/jit/gcencode.cpp +++ b/src/coreclr/jit/gcencode.cpp @@ -3709,15 +3709,6 @@ class GcInfoEncoderWithLogging } } - void SetReturnKind(ReturnKind returnKind) - { - m_gcInfoEncoder->SetReturnKind(returnKind); - if (m_doLogging) - { - printf("Set ReturnKind to %s.\n", ReturnKindToString(returnKind)); - } - } - void SetStackBaseRegister(UINT32 registerNumber) { m_gcInfoEncoder->SetStackBaseRegister(registerNumber); @@ -3832,8 +3823,6 @@ void GCInfo::gcInfoBlockHdrSave(GcInfoEncoder* gcInfoEncoder, unsigned methodSiz gcInfoEncoderWithLog->SetCodeLength(methodSize); - gcInfoEncoderWithLog->SetReturnKind(getReturnKind()); - if (compiler->isFramePointerUsed()) { gcInfoEncoderWithLog->SetStackBaseRegister(REG_FPBASE); diff --git a/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h b/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h index 37e5883b4059b4..358807e6ab563e 100644 --- a/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h +++ b/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h @@ -11,8 +11,8 @@ struct ReadyToRunHeaderConstants { static const uint32_t Signature = 0x00525452; // 'RTR' - static const uint32_t CurrentMajorVersion = 10; - static const uint32_t CurrentMinorVersion = 1; + static const uint32_t CurrentMajorVersion = 11; + static const uint32_t CurrentMinorVersion = 0; }; struct ReadyToRunHeader diff --git a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp index 7f1fdfecc58662..d7e0cce13655e4 100644 --- a/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp @@ -213,44 +213,18 @@ void UnixNativeCodeManager::EnumGcRefs(MethodInfo * pMethodInfo, #ifdef TARGET_ARM // Ensure that code offset doesn't have the Thumb bit set. We need - // it to be aligned to instruction start to make the !isActiveStackFrame - // branch below work. + // it to be aligned to instruction start ASSERT(((uintptr_t)codeOffset & 1) == 0); #endif - bool executionAborted = ((UnixNativeMethodInfo*)pMethodInfo)->executionAborted; - - if (!isActiveStackFrame && !executionAborted) - { - // the reasons for this adjustment are explained in EECodeManager::EnumGcRefs - codeOffset--; - } - GcInfoDecoder decoder( GCInfoToken(gcInfo), GcInfoDecoderFlags(DECODE_GC_LIFETIMES | DECODE_SECURITY_OBJECT | DECODE_VARARG), codeOffset ); - if (isActiveStackFrame) - { - // CONSIDER: We can optimize this by remembering the need to adjust in IsSafePoint and propagating into here. - // Or, better yet, maybe we should change the decoder to not require this adjustment. - // The scenario that adjustment tries to handle (fallthrough into BB with random liveness) - // does not seem possible. - if (!decoder.HasInterruptibleRanges()) - { - decoder = GcInfoDecoder( - GCInfoToken(gcInfo), - GcInfoDecoderFlags(DECODE_GC_LIFETIMES | DECODE_SECURITY_OBJECT | DECODE_VARARG), - codeOffset - 1 - ); - - assert(decoder.IsSafePoint()); - } - } - ICodeManagerFlags flags = (ICodeManagerFlags)0; + bool executionAborted = ((UnixNativeMethodInfo*)pMethodInfo)->executionAborted; if (executionAborted) flags = ICodeManagerFlags::ExecutionAborted; diff --git a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp index 5fe6e446702836..a6437b56ac7b80 100644 --- a/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp +++ b/src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp @@ -440,9 +440,8 @@ void CoffNativeCodeManager::EnumGcRefs(MethodInfo * pMethodInfo, PTR_uint8_t gcInfo; uint32_t codeOffset = GetCodeOffset(pMethodInfo, safePointAddress, &gcInfo); - bool executionAborted = ((CoffNativeMethodInfo *)pMethodInfo)->executionAborted; - ICodeManagerFlags flags = (ICodeManagerFlags)0; + bool executionAborted = ((CoffNativeMethodInfo *)pMethodInfo)->executionAborted; if (executionAborted) flags = ICodeManagerFlags::ExecutionAborted; @@ -453,11 +452,6 @@ void CoffNativeCodeManager::EnumGcRefs(MethodInfo * pMethodInfo, flags = (ICodeManagerFlags)(flags | ICodeManagerFlags::ActiveStackFrame); #ifdef USE_GC_INFO_DECODER - if (!isActiveStackFrame && !executionAborted) - { - // the reasons for this adjustment are explained in EECodeManager::EnumGcRefs - codeOffset--; - } GcInfoDecoder decoder( GCInfoToken(gcInfo), @@ -465,24 +459,6 @@ void CoffNativeCodeManager::EnumGcRefs(MethodInfo * pMethodInfo, codeOffset ); - if (isActiveStackFrame) - { - // CONSIDER: We can optimize this by remembering the need to adjust in IsSafePoint and propagating into here. - // Or, better yet, maybe we should change the decoder to not require this adjustment. - // The scenario that adjustment tries to handle (fallthrough into BB with random liveness) - // does not seem possible. - if (!decoder.HasInterruptibleRanges()) - { - decoder = GcInfoDecoder( - GCInfoToken(gcInfo), - GcInfoDecoderFlags(DECODE_GC_LIFETIMES | DECODE_SECURITY_OBJECT | DECODE_VARARG), - codeOffset - 1 - ); - - assert(decoder.IsSafePoint()); - } - } - if (!decoder.EnumerateLiveSlots( pRegisterSet, isActiveStackFrame /* reportScratchSlots */, diff --git a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs index 51860d1341c7b8..bca68c323f6523 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -15,8 +15,8 @@ internal struct ReadyToRunHeaderConstants { public const uint Signature = 0x00525452; // 'RTR' - public const ushort CurrentMajorVersion = 10; - public const ushort CurrentMinorVersion = 1; + public const ushort CurrentMajorVersion = 11; + public const ushort CurrentMinorVersion = 0; } #if READYTORUN #pragma warning disable 0169 diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcInfo.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcInfo.cs index b934e36719e8a2..860a18b73565a2 100644 --- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcInfo.cs +++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/Amd64/GcInfo.cs @@ -47,7 +47,9 @@ public SafePointOffset(int index, uint value) } private const int MIN_GCINFO_VERSION_WITH_RETURN_KIND = 2; + private const int MAX_GCINFO_VERSION_WITH_RETURN_KIND = 3; private const int MIN_GCINFO_VERSION_WITH_REV_PINVOKE_FRAME = 2; + private const int MIN_GCINFO_VERSION_WITH_NORMALIZED_CODE_OFFSETS = 3; private bool _slimHeader; private bool _hasSecurityObject; @@ -88,7 +90,9 @@ public GcInfo() { } public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion, ushort minorVersion) { Offset = offset; - _gcInfoTypes = new GcInfoTypes(machine); + Version = ReadyToRunVersionToGcInfoVersion(majorVersion, minorVersion); + bool denormalizeCodeOffsets = Version > MIN_GCINFO_VERSION_WITH_NORMALIZED_CODE_OFFSETS; + _gcInfoTypes = new GcInfoTypes(machine, denormalizeCodeOffsets); _machine = machine; SecurityObjectStackSlot = -1; @@ -100,12 +104,11 @@ public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion, us SizeOfEditAndContinuePreservedArea = 0xffffffff; ReversePInvokeFrameStackSlot = -1; - Version = ReadyToRunVersionToGcInfoVersion(majorVersion, minorVersion); int bitOffset = offset * 8; ParseHeaderFlags(image, ref bitOffset); - if (Version >= MIN_GCINFO_VERSION_WITH_RETURN_KIND) // IsReturnKindAvailable + if (Version >= MIN_GCINFO_VERSION_WITH_RETURN_KIND && Version <= MAX_GCINFO_VERSION_WITH_RETURN_KIND) // IsReturnKindAvailable { int returnKindBits = (_slimHeader) ? _gcInfoTypes.SIZE_OF_RETURN_KIND_SLIM : _gcInfoTypes.SIZE_OF_RETURN_KIND_FAT; ReturnKind = (ReturnKinds)NativeReader.ReadBits(image, returnKindBits, ref bitOffset); @@ -118,12 +121,13 @@ public GcInfo(byte[] image, int offset, Machine machine, ushort majorVersion, us uint normPrologSize = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_PROLOG_SIZE_ENCBASE, ref bitOffset) + 1; uint normEpilogSize = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_EPILOG_SIZE_ENCBASE, ref bitOffset); - ValidRangeStart = normPrologSize; - ValidRangeEnd = (uint)CodeLength - normEpilogSize; + ValidRangeStart = _gcInfoTypes.DenormalizeCodeOffset(normPrologSize); + ValidRangeEnd = (uint)CodeLength - _gcInfoTypes.DenormalizeCodeOffset(normEpilogSize); } else if (_hasSecurityObject || _hasGenericsInstContext) { - ValidRangeStart = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_PROLOG_SIZE_ENCBASE, ref bitOffset) + 1; + uint normValidRangeStart = NativeReader.DecodeVarLengthUnsigned(image, _gcInfoTypes.NORM_PROLOG_SIZE_ENCBASE, ref bitOffset) + 1; + ValidRangeStart = _gcInfoTypes.DenormalizeCodeOffset(normValidRangeStart); ValidRangeEnd = ValidRangeStart + 1; } @@ -352,11 +356,11 @@ private void ParseHeaderFlags(byte[] image, ref int bitOffset) private List EnumerateSafePoints(byte[] image, ref int bitOffset) { List safePoints = new List(); - uint numBitsPerOffset = GcInfoTypes.CeilOfLog2(CodeLength); + uint numBitsPerOffset = GcInfoTypes.CeilOfLog2((int)_gcInfoTypes.NormalizeCodeOffset((uint)CodeLength)); for (int i = 0; i < NumSafePoints; i++) { uint normOffset = (uint)NativeReader.ReadBits(image, (int)numBitsPerOffset, ref bitOffset); - safePoints.Add(new SafePointOffset(i, normOffset)); + safePoints.Add(new SafePointOffset(i, _gcInfoTypes.DenormalizeCodeOffset(normOffset))); } return safePoints; } @@ -367,18 +371,21 @@ private List EnumerateSafePoints(byte[] image, ref int bitOffse private List EnumerateInterruptibleRanges(byte[] image, int interruptibleRangeDelta1EncBase, int interruptibleRangeDelta2EncBase, ref int bitOffset) { List ranges = new List(); - uint lastinterruptibleRangeStopOffset = 0; + uint normLastinterruptibleRangeStopOffset = 0; for (uint i = 0; i < NumInterruptibleRanges; i++) { uint normStartDelta = NativeReader.DecodeVarLengthUnsigned(image, interruptibleRangeDelta1EncBase, ref bitOffset); uint normStopDelta = NativeReader.DecodeVarLengthUnsigned(image, interruptibleRangeDelta2EncBase, ref bitOffset) + 1; - uint rangeStartOffset = lastinterruptibleRangeStopOffset + normStartDelta; - uint rangeStopOffset = rangeStartOffset + normStopDelta; + uint normRangeStartOffset = normLastinterruptibleRangeStopOffset + normStartDelta; + uint normRangeStopOffset = normRangeStartOffset + normStopDelta; + + uint rangeStartOffset = _gcInfoTypes.DenormalizeCodeOffset(normRangeStopOffset); + uint rangeStopOffset = _gcInfoTypes.DenormalizeCodeOffset(normRangeStartOffset); ranges.Add(new InterruptibleRange(i, rangeStartOffset, rangeStopOffset)); - lastinterruptibleRangeStopOffset = rangeStopOffset; + normLastinterruptibleRangeStopOffset = normRangeStopOffset; } return ranges; } @@ -397,7 +404,11 @@ private int ReadyToRunVersionToGcInfoVersion(int readyToRunMajorVersion, int rea if (readyToRunMajorVersion < 9 || (readyToRunMajorVersion == 9 && readyToRunMinorVersion < 2)) return 2; - return 3; + // R2R 11.0+ uses GCInfo v4 + if (readyToRunMajorVersion < 11) + return 3; + + return 4; } private List> GetLiveSlotsAtSafepoints(byte[] image, ref int bitOffset) diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/GCInfoTypes.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/GCInfoTypes.cs index d3adc462409589..653425781a7cf6 100644 --- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/GCInfoTypes.cs +++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/GCInfoTypes.cs @@ -73,6 +73,7 @@ enum InfoHdrAdjust public class GcInfoTypes { private Machine _target; + private bool _denormalizeCodeOffsets; internal int SIZE_OF_RETURN_KIND_SLIM { get; } = 2; internal int SIZE_OF_RETURN_KIND_FAT { get; } = 2; @@ -105,9 +106,10 @@ public class GcInfoTypes internal int LIVESTATE_RLE_SKIP_ENCBASE { get; } = 4; internal int NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 { get; } = 6; - internal GcInfoTypes(Machine machine) + internal GcInfoTypes(Machine machine, bool denormalizeCodeOffsets) { _target = machine; + _denormalizeCodeOffsets = denormalizeCodeOffsets; switch (machine) { @@ -176,6 +178,34 @@ internal int DenormalizeCodeLength(int x) return x; } + internal int NormalizeCodeLength(int x) + { + switch (_target) + { + case Machine.ArmThumb2: + return (x >> 1); + case Machine.Arm64: + case Machine.LoongArch64: + case Machine.RiscV64: + return (x >> 2); + } + return x; + } + + internal uint DenormalizeCodeOffset(uint x) + { + return _denormalizeCodeOffsets ? + (uint)DenormalizeCodeLength((int)x) : + x; + } + + internal uint NormalizeCodeOffset(uint x) + { + return _denormalizeCodeOffsets ? + (uint)NormalizeCodeLength((int)x) : + x; + } + internal int DenormalizeStackSlot(int x) { switch (_target) diff --git a/src/coreclr/vm/eetwain.cpp b/src/coreclr/vm/eetwain.cpp index 25a4c73b65ea0b..0c06eaf159e6f3 100644 --- a/src/coreclr/vm/eetwain.cpp +++ b/src/coreclr/vm/eetwain.cpp @@ -1426,37 +1426,6 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD, } #endif - /* If we are not in the active method, we are currently pointing - * to the return address; at the return address stack variables - * can become dead if the call is the last instruction of a try block - * and the return address is the jump around the catch block. Therefore - * we simply assume an offset inside of call instruction. - * NOTE: The GcInfoDecoder depends on this; if you change it, you must - * revisit the GcInfoEncoder/Decoder - */ - - if (!(flags & ExecutionAborted)) - { - if (!(flags & ActiveStackFrame)) - { - curOffs--; - LOG((LF_GCINFO, LL_INFO1000, "Adjusted GC reporting offset due to flags !ExecutionAborted && !ActiveStackFrame. Now reporting GC refs for %s at offset %04x.\n", - methodName, curOffs)); - } - } - else - { - // Since we are aborting execution, we are either in a frame that actually faulted or in a throwing call. - // * We do not need to adjust in a leaf - // * A throwing call will have unreachable after it, thus GC info is the same as before the call. - // - // Either way we do not need to adjust. - - // NOTE: only fully interruptible methods may need to report anything here as without - // exception handling all current local variables are already unreachable. - // EnumerateLiveSlots will shortcircuit the partially interruptible case just a bit later. - } - // Check if we have been given an override value for relOffset if (relOffsetOverride != NO_OVERRIDE_OFFSET) { @@ -1500,7 +1469,6 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD, // A frame is non-leaf if we are executing a call, or a fault occurred in the function. // The only case in which we need to report scratch slots for a non-leaf frame // is when execution has to be resumed at the point of interruption (via ResumableFrame) - //Implement ResumableFrame _ASSERTE( sizeof( BOOL ) >= sizeof( ActiveStackFrame ) ); reportScratchSlots = (flags & ActiveStackFrame) != 0; @@ -1511,24 +1479,6 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD, curOffs ); - if ((flags & ActiveStackFrame) != 0) - { - // CONSIDER: We can optimize this by remembering the need to adjust in IsSafePoint and propagating into here. - // Or, better yet, maybe we should change the decoder to not require this adjustment. - // The scenario that adjustment tries to handle (fallthrough into BB with random liveness) - // does not seem possible. - if (!gcInfoDecoder.HasInterruptibleRanges()) - { - gcInfoDecoder = GcInfoDecoder( - gcInfoToken, - GcInfoDecoderFlags(DECODE_GC_LIFETIMES | DECODE_SECURITY_OBJECT | DECODE_VARARG), - curOffs - 1 - ); - - _ASSERTE(gcInfoDecoder.CouldBeSafePoint()); - } - } - if (!gcInfoDecoder.EnumerateLiveSlots( pRD, reportScratchSlots, diff --git a/src/coreclr/vm/gcinfodecoder.cpp b/src/coreclr/vm/gcinfodecoder.cpp index 4197e456d8263f..1b11a3e8f7ceee 100644 --- a/src/coreclr/vm/gcinfodecoder.cpp +++ b/src/coreclr/vm/gcinfodecoder.cpp @@ -91,9 +91,6 @@ bool GcInfoDecoder::PredecodeFatHeader(int remainingFlags) int numFlagBits = (m_Version == 1) ? GC_INFO_FLAGS_BIT_SIZE_VERSION_1 : GC_INFO_FLAGS_BIT_SIZE; m_headerFlags = (GcInfoHeaderFlags)m_Reader.Read(numFlagBits); - // skip over the unused return kind. - m_Reader.Read(SIZE_OF_RETURN_KIND_IN_FAT_HEADER); - remainingFlags &= ~DECODE_VARARG; #if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) remainingFlags &= ~DECODE_HAS_TAILCALLS; @@ -299,9 +296,6 @@ GcInfoDecoder::GcInfoDecoder( m_StackBaseRegister = NO_STACK_BASE_REGISTER; } - // skip over the unused return kind. - m_Reader.Read(SIZE_OF_RETURN_KIND_IN_SLIM_HEADER); - remainingFlags &= ~DECODE_VARARG; #if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) remainingFlags &= ~DECODE_HAS_TAILCALLS; @@ -370,11 +364,7 @@ GcInfoDecoder::GcInfoDecoder( { if(m_NumSafePoints) { - // Safepoints are encoded with a -1 adjustment - // DECODE_GC_LIFETIMES adjusts the offset accordingly, but DECODE_INTERRUPTIBILITY does not - // adjust here - UINT32 offset = flags & DECODE_INTERRUPTIBILITY ? m_InstructionOffset - 1 : m_InstructionOffset; - m_SafePointIndex = FindSafePoint(offset); + m_SafePointIndex = FindSafePoint(m_InstructionOffset); } } else if(flags & DECODE_FOR_RANGES_CALLBACK) @@ -450,10 +440,6 @@ bool GcInfoDecoder::IsSafePoint(UINT32 codeOffset) if(m_NumSafePoints == 0) return false; -#if defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - // Safepoints are encoded with a -1 adjustment - codeOffset--; -#endif size_t savedPos = m_Reader.GetCurrentPos(); UINT32 safePointIndex = FindSafePoint(codeOffset); m_Reader.SetCurrentPos(savedPos); @@ -500,32 +486,26 @@ UINT32 GcInfoDecoder::FindSafePoint(UINT32 breakOffset) const size_t savedPos = m_Reader.GetCurrentPos(); const UINT32 numBitsPerOffset = CeilOfLog2(NORMALIZE_CODE_OFFSET(m_CodeLength)); -#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - // Safepoints are encoded with a -1 adjustment - if ((breakOffset & 1) != 0) -#endif + const UINT32 normBreakOffset = NORMALIZE_CODE_OFFSET(breakOffset); + UINT32 linearSearchStart = 0; + UINT32 linearSearchEnd = m_NumSafePoints; + if (linearSearchEnd - linearSearchStart > MAX_LINEAR_SEARCH) { - const UINT32 normBreakOffset = NORMALIZE_CODE_OFFSET(breakOffset); - UINT32 linearSearchStart = 0; - UINT32 linearSearchEnd = m_NumSafePoints; - if (linearSearchEnd - linearSearchStart > MAX_LINEAR_SEARCH) + linearSearchStart = NarrowSafePointSearch(savedPos, normBreakOffset, &linearSearchEnd); + } + + for (UINT32 i = linearSearchStart; i < linearSearchEnd; i++) + { + UINT32 spOffset = (UINT32)m_Reader.Read(numBitsPerOffset); + if (spOffset == normBreakOffset) { - linearSearchStart = NarrowSafePointSearch(savedPos, normBreakOffset, &linearSearchEnd); + result = i; + break; } - for (UINT32 i = linearSearchStart; i < linearSearchEnd; i++) + if (spOffset > normBreakOffset) { - UINT32 spOffset = (UINT32)m_Reader.Read(numBitsPerOffset); - if (spOffset == normBreakOffset) - { - result = i; - break; - } - - if (spOffset > normBreakOffset) - { - break; - } + break; } } @@ -546,13 +526,7 @@ void GcInfoDecoder::EnumerateSafePoints(EnumerateSafePointsCallback *pCallback, for(UINT32 i = 0; i < m_NumSafePoints; i++) { UINT32 normOffset = (UINT32)m_Reader.Read(numBitsPerOffset); - UINT32 offset = DENORMALIZE_CODE_OFFSET(normOffset) + 2; - -#if defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - // Safepoints are encoded with a -1 adjustment - offset--; -#endif - + UINT32 offset = DENORMALIZE_CODE_OFFSET(normOffset); pCallback(this, offset, hCallback); } } @@ -715,15 +689,6 @@ bool GcInfoDecoder::EnumerateLiveSlots( return true; } - // - // If this is a non-leaf frame and we are executing a call, the unwinder has given us the PC - // of the call instruction. We should adjust it to the PC of the instruction after the call in order to - // obtain transition information for scratch slots. However, we always assume scratch slots to be - // dead for non-leaf frames (except for ResumableFrames), so we don't need to adjust the PC. - // If this is a non-leaf frame and we are not executing a call (i.e.: a fault occurred in the function), - // then it would be incorrect to adjust the PC - // - _ASSERTE(GC_SLOT_INTERIOR == GC_CALL_INTERIOR); _ASSERTE(GC_SLOT_PINNED == GC_CALL_PINNED);