From 755b7af5298974722e1eb9cc376b0a07260d49ee Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sun, 7 Sep 2025 16:06:14 -0700 Subject: [PATCH 01/13] e --- src/coreclr/vm/codeversion.h | 1 + .../vm/datadescriptor/datadescriptor.inc | 1 + src/coreclr/vm/readytoruninfo.h | 1 + .../Contracts/ICodeVersions.cs | 1 + .../Contracts/ILoader.cs | 1 + .../Contracts/IRuntimeTypeSystem.cs | 2 +- .../Contracts/CodeVersions_1.cs | 130 ++++++++++++++++++ .../Contracts/Loader_1.cs | 13 ++ .../Contracts/RuntimeTypeSystem_1.cs | 6 + .../Signature/SignatureTypeProvider.cs | 0 .../Data/NativeCodeVersionNode.cs | 2 + .../Legacy/ISOSDacInterface.cs | 21 ++- .../Legacy/SOSDacImpl.cs | 23 +++- 13 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 8633769f053ce1..f69fbb25f209a9 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -332,6 +332,7 @@ struct cdac_data static constexpr size_t NativeCode = offsetof(NativeCodeVersionNode, m_pNativeCode); static constexpr size_t Flags = offsetof(NativeCodeVersionNode, m_flags); static constexpr size_t ILVersionId = offsetof(NativeCodeVersionNode, m_parentId); + static constexpr size_t OptimizationTier = offsetof(NativeCodeVersionNode, m_optTier); #ifdef HAVE_GCCOVER static constexpr size_t GCCoverageInfo = offsetof(NativeCodeVersionNode, m_gcCover); #endif // HAVE_GCCOVER diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index fe45dfa97290fa..256de92e55bdfd 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -667,6 +667,7 @@ CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, MethodDesc, cdac_data::NativeCode) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, Flags, cdac_data::Flags) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*nuint*/, ILVersionId, cdac_data::ILVersionId) +CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, OptimizationTier, cdac_data::OptimizationTier) #ifdef HAVE_GCCOVER CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, GCCoverageInfo, cdac_data::GCCoverageInfo) #endif // HAVE_GCCOVER diff --git a/src/coreclr/vm/readytoruninfo.h b/src/coreclr/vm/readytoruninfo.h index 5b7d071c171eb9..63e92e4e2ec107 100644 --- a/src/coreclr/vm/readytoruninfo.h +++ b/src/coreclr/vm/readytoruninfo.h @@ -347,6 +347,7 @@ struct cdac_data { static constexpr size_t ReadyToRunHeader = offsetof(ReadyToRunInfo, m_pHeader); static constexpr size_t CompositeInfo = offsetof(ReadyToRunInfo, m_pCompositeInfo); + static constexpr size_t Composite = offsetof(ReadyToRunInfo, m_pComposite); static constexpr size_t NumRuntimeFunctions = offsetof(ReadyToRunInfo, m_nRuntimeFunctions); static constexpr size_t RuntimeFunctions = offsetof(ReadyToRunInfo, m_pRuntimeFunctions); static constexpr size_t NumHotColdMap = offsetof(ReadyToRunInfo, m_nHotColdMap); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs index 3817368120e7fc..fa245b7be93d1e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs @@ -9,6 +9,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; public interface ICodeVersions : IContract { static string IContract.Name { get; } = nameof(CodeVersions); + public virtual int GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs, out Span nativeCodeAddrs, out int pcNativeCodeAddrs) => throw new NotImplementedException(); public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs index f0e90c38af13c9..40d55d740f2dad 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs @@ -83,6 +83,7 @@ public interface ILoader : IContract TargetPointer GetModule(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetAssembly(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetPEAssembly(ModuleHandle handle) => throw new NotImplementedException(); + bool GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) => throw new NotImplementedException(); bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags) => throw new NotImplementedException(); TargetPointer GetILAddr(TargetPointer peAssemblyPtr, int rva) => throw new NotImplementedException(); bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index c7194d551c119c..9ea69bfe159a40 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -175,7 +175,7 @@ public interface IRuntimeTypeSystem : IContract bool IsCollectibleMethod(MethodDescHandle methodDesc) => throw new NotImplementedException(); bool IsVersionable(MethodDescHandle methodDesc) => throw new NotImplementedException(); - + bool IsEligibleForTieredCompilation(MethodDescHandle methodDesc) => throw new NotImplementedException(); TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException(); TargetCodePointer GetNativeCode(MethodDescHandle methodDesc) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index 29be26f871c9f7..b2d5109abaa284 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -18,6 +19,135 @@ public CodeVersions_1(Target target) _target = target; } + internal struct DacpTieredVersionData + { + public enum OptimizationTierEnum + { + OptimizationTier_Unknown, + OptimizationTier_MinOptJitted, + OptimizationTier_Optimized, + OptimizationTier_QuickJitted, + OptimizationTier_OptimizedTier1, + OptimizationTier_ReadyToRun, + OptimizationTier_OptimizedTier1OSR, + OptimizationTier_QuickJittedInstrumented, + OptimizationTier_OptimizedTier1Instrumented, + }; + public TargetPointer NativeCodeAddr; + public OptimizationTierEnum OptimizationTier; + public TargetPointer NativeCodeVersionNodePtr; + }; + + private IEnumerable GetNativeCodeVersionNodes(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle) + { + if (!ilCodeVersionHandle.IsValid) + yield break; + + // Iterate through versioning state nodes and return the active one, matching any IL code version + Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); + TargetNUInt ilVersionId = GetId(ilCodeVersionHandle); + + // ImplicitCodeVersion stage of NativeCodeVersionIterator::Next() + TargetPointer versioningStateAddr = rts.GetMethodDescVersioningState(md); + if (versioningStateAddr == TargetPointer.Null) + yield break; + + Data.MethodDescVersioningState versioningState = _target.ProcessedData.GetOrAdd(versioningStateAddr); + + // LinkedList stage of NativeCodeVersion::Next, heavily inlined + TargetPointer currentAddress = versioningState.NativeCodeVersionNode; + while (currentAddress != TargetPointer.Null) + { + Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd(currentAddress); + if (current.ILVersionId == ilVersionId) + { + yield return current; + } + currentAddress = current.Next; + } + yield break; + } + int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs, out Span nativeCodeAddrs, out int pcNativeCodeAddrs) + { + pcNativeCodeAddrs = 0; + DacpTieredVersionData[] dacpTieredVersionDataArray = new DacpTieredVersionData[cNativeCodeAddrs]; + Contracts.ICodeVersions codeVersionsContract = this; + Contracts.IReJIT rejitContract = _target.Contracts.ReJIT; + + // r2r stuff todo + ILCodeVersionHandle ilCodeVersion = codeVersionsContract.GetILCodeVersions(methodDesc) + .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode).Value == (ulong)rejitId, + ILCodeVersionHandle.Invalid); + + if (!ilCodeVersion.IsValid) + throw new ArgumentException(); + // Iterate through versioning state nodes and return the active one, matching any IL code version + Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + Contracts.ILoader loader = _target.Contracts.Loader; + MethodDescHandle mdh = rts.GetMethodDescHandle(methodDesc); + TargetPointer methodTable = rts.GetMethodTable(mdh); + TypeHandle mtTypeHandle = rts.GetTypeHandle(methodTable); + TargetPointer modulePtr = rts.GetModule(mtTypeHandle); + ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); + + bool isReadyToRun = loader.GetReadyToRunInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); + int count = 0; + foreach (NativeCodeVersionNode nativeCodeVersionNode in GetNativeCodeVersionNodes(methodDesc, ilCodeVersion)) + { + if (r2rImageBase <= nativeCodeVersionNode.NativeCode && nativeCodeVersionNode.NativeCode < r2rImageEnd) + { + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_ReadyToRun; + } + + else if (rts.IsEligibleForTieredCompilation(mdh)) + { + uint optimizationTier = nativeCodeVersionNode.OptimizationTier; + switch (optimizationTier) + { + case 0: + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJitted; + break; + case 1: + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1; + break; + case 2: + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1OSR; + break; + case 3: + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized; + break; + case 4: + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJittedInstrumented; + break; + case 5: + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1Instrumented; + break; + default: + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Unknown; + break; + } + } + else if (2 == modulePtr) + { + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_MinOptJitted; + } + else + { + dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized; + } + count++; + + if (count >= cNativeCodeAddrs) + { + nativeCodeAddrs = MemoryMarshal.AsBytes(dacpTieredVersionDataArray.AsSpan()); + return 1; + } + } + pcNativeCodeAddrs = count; + nativeCodeAddrs = MemoryMarshal.AsBytes(dacpTieredVersionDataArray.AsSpan()); + return 0; + } ILCodeVersionHandle ICodeVersions.GetActiveILCodeVersion(TargetPointer methodDesc) { // CodeVersionManager::GetActiveILCodeVersion diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index 0c2cf5bacf5dcb..af7ed550578e03 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -171,6 +171,19 @@ TargetPointer ILoader.GetPEAssembly(ModuleHandle handle) return module.PEAssembly; } + bool ILoader.GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) + { + r2rImageBase = TargetPointer.Null; + r2rImageEnd = TargetPointer.Null; + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + if (module.ReadyToRunInfo == TargetPointer.Null) + return false; + + Data.ReadyToRunInfo readyToRunInfo = _target.ProcessedData.GetOrAdd(module.ReadyToRunInfo); + // r2rImageBase = readyToRunInfo. tbd + return true; + } + bool ILoader.TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags) { baseAddress = TargetPointer.Null; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index b1be8f2522c076..e73ccb949f4052 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -1030,6 +1030,12 @@ bool IRuntimeTypeSystem.IsVersionable(MethodDescHandle methodDesc) return false; } + bool IRuntimeTypeSystem.IsEligibleForTieredCompilation(MethodDescHandle methodDesc) + { + MethodDesc md = _methodDescs[methodDesc.Address]; + return md.IsEligibleForTieredCompilation; + } + TargetPointer IRuntimeTypeSystem.GetMethodDescVersioningState(MethodDescHandle methodDesc) { MethodDesc md = _methodDescs[methodDesc.Address]; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs index e68345e4499d23..22256404b14f82 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs @@ -17,6 +17,7 @@ public NativeCodeVersionNode(Target target, TargetPointer address) NativeCode = target.ReadCodePointer(address + (ulong)type.Fields[nameof(NativeCode)].Offset); Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); ILVersionId = target.ReadNUInt(address + (ulong)type.Fields[nameof(ILVersionId)].Offset); + OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); if (type.Fields.ContainsKey(nameof(GCCoverageInfo))) { GCCoverageInfo = target.ReadPointer(address + (ulong)type.Fields[nameof(GCCoverageInfo)].Offset); @@ -29,6 +30,7 @@ public NativeCodeVersionNode(Target target, TargetPointer address) public TargetCodePointer NativeCode { get; init; } public uint Flags { get; init; } public TargetNUInt ILVersionId { get; init; } + public uint OptimizationTier { get; init; } public TargetPointer? GCCoverageInfo { get; init; } } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index 9b59a9a5ba6106..44279771bc69c2 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -231,6 +231,25 @@ public enum Flags : uint public ClrDataAddress NativeCodeAddr; }; +internal struct DacpTieredVersionData +{ + public enum OptimizationTierEnum + { + OptimizationTier_Unknown, + OptimizationTier_MinOptJitted, + OptimizationTier_Optimized, + OptimizationTier_QuickJitted, + OptimizationTier_OptimizedTier1, + OptimizationTier_ReadyToRun, + OptimizationTier_OptimizedTier1OSR, + OptimizationTier_QuickJittedInstrumented, + OptimizationTier_OptimizedTier1Instrumented, + }; + public ClrDataAddress NativeCodeAddr; + public OptimizationTierEnum OptimizationTier; + public ClrDataAddress NativeCodeVersionNodePtr; +}; + internal struct DacpMethodDescData { public int bHasNativeCode; @@ -639,7 +658,7 @@ internal unsafe partial interface ISOSDacInterface4 internal unsafe partial interface ISOSDacInterface5 { [PreserveSig] - int GetTieredVersions(ClrDataAddress methodDesc, int rejitId, /*struct DacpTieredVersionData*/void* nativeCodeAddrs, int cNativeCodeAddrs, int* pcNativeCodeAddrs); + int GetTieredVersions(ClrDataAddress methodDesc, int rejitId, DacpTieredVersionData* nativeCodeAddrs, int cNativeCodeAddrs, int* pcNativeCodeAddrs); }; [GeneratedComInterface] diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 7c9cafe70de75b..4f42ca240c54ef 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -2980,8 +2980,27 @@ int ISOSDacInterface4.GetClrNotification(ClrDataAddress[] arguments, int count, #endregion ISOSDacInterface4 #region ISOSDacInterface5 - int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, /*struct DacpTieredVersionData*/ void* nativeCodeAddrs, int cNativeCodeAddrs, int* pcNativeCodeAddrs) - => _legacyImpl5 is not null ? _legacyImpl5.GetTieredVersions(methodDesc, rejitId, nativeCodeAddrs, cNativeCodeAddrs, pcNativeCodeAddrs) : HResults.E_NOTIMPL; + int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, DacpTieredVersionData* nativeCodeAddrs, int cNativeCodeAddrs, int* pcNativeCodeAddrs) + { + int hr = HResults.S_OK; + try + { + if (methodDesc == 0 || cNativeCodeAddrs == 0 || pcNativeCodeAddrs == null) + throw new ArgumentException(); + + TargetPointer methodDescPtr = methodDesc.ToTargetPointer(_target); + hr = _target.Contracts.CodeVersions.GetTieredVersions(methodDescPtr, rejitId, cNativeCodeAddrs, out Span nativeCodeData, out int nativeCodeCount); + *pcNativeCodeAddrs = nativeCodeCount; + Span dest = new Span(nativeCodeAddrs, nativeCodeData.Length); + nativeCodeData.CopyTo(dest); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if + } #endregion ISOSDacInterface5 #region ISOSDacInterface6 From 97870a17b104cd04bc9c58786204b6d48fda4cb5 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Tue, 9 Sep 2025 12:48:20 -0700 Subject: [PATCH 02/13] e --- .../vm/datadescriptor/datadescriptor.inc | 8 ++++ src/coreclr/vm/eeconfig.h | 8 +++- .../Contracts/ILoader.cs | 7 +++ .../Contracts/IRuntimeTypeSystem.cs | 1 + .../DataType.cs | 1 + .../Constants.cs | 2 + .../Contracts/CodeVersions_1.cs | 2 +- .../Contracts/RuntimeTypeSystem_1.cs | 46 +++++++++++++++++++ .../Data/EEConfig.cs | 19 ++++++++ 9 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 256de92e55bdfd..8f7391b98891d7 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -304,6 +304,12 @@ CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumThreadStaticFields, cdac_data:: CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumNonVirtualSlots, cdac_data::NumNonVirtualSlots) CDAC_TYPE_END(EEClass) +CDAC_TYPE_BEGIN(EEConfig) +CDAC_TYPE_INDETERMINATE(EEConfig) +CDAC_TYPE_FIELD(EEConfig, /*bool*/, JitMinOpts, cdac_data::JitMinOpts) +CDAC_TYPE_FIELD(EEConfig, /*bool*/, Debuggable, cdac_data::Debuggable) +CDAC_TYPE_END(EEConfig) + CDAC_TYPE_BEGIN(ArrayClass) CDAC_TYPE_INDETERMINATE(ArrayClass) CDAC_TYPE_FIELD(ArrayClass, /*uint8*/, Rank, cdac_data::Rank) @@ -974,6 +980,8 @@ CDAC_GLOBAL(StaticsPointerMask, uintptr_t, DynamicStaticsInfo::STATICSPOINTERMAS CDAC_GLOBAL(PtrArrayOffsetToDataArray, uintptr_t, offsetof(PtrArray, m_Array)) CDAC_GLOBAL(NumberOfTlsOffsetsNotUsedInNoncollectibleArray, uint8, NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY) CDAC_GLOBAL(MaxClrNotificationArgs, uint32, MAX_CLR_NOTIFICATION_ARGS) +CDAC_GLOBAL_POINTER(EEConfig, &::g_pConfig) +CDAC_GLOBAL_POINTER(CORDebuggerControlFlags, &::g_CORDebuggerControlFlags) CDAC_GLOBAL_POINTER(ClrNotificationArguments, &::g_clrNotificationArguments) CDAC_GLOBAL_POINTER(ArrayBoundsZero, cdac_data::ArrayBoundsZero) CDAC_GLOBAL_POINTER(ExceptionMethodTable, &::g_pExceptionClass) diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index 9c008ae7647cc2..8d4cf680e79fa1 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -695,8 +695,14 @@ class EEConfig public: DWORD GetSleepOnExit() { return dwSleepOnExit; } -}; + friend struct ::cdac_data; +}; +template<> struct cdac_data +{ + static constexpr size_t JitMinOpts = offsetof(EEConfig, fJitMinOpts); + static constexpr size_t Debuggable = offsetof(EEConfig, fDebuggable); +}; #ifdef _DEBUG_IMPL diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs index 40d55d740f2dad..f3a01b1dd6ba2a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs @@ -41,6 +41,13 @@ public enum ModuleFlags BeingUnloaded = 0x100000, } +[Flags] + +public enum DebuggerControlFlags +{ + AllowJitOpt = 0x0008, +}; + [Flags] public enum AssemblyIterationFlags { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index 9ea69bfe159a40..f22f66cef0d3cd 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -176,6 +176,7 @@ public interface IRuntimeTypeSystem : IContract bool IsCollectibleMethod(MethodDescHandle methodDesc) => throw new NotImplementedException(); bool IsVersionable(MethodDescHandle methodDesc) => throw new NotImplementedException(); bool IsEligibleForTieredCompilation(MethodDescHandle methodDesc) => throw new NotImplementedException(); + bool IsJitOptimizationDisabled(MethodDescHandle methodDesc) => throw new NotImplementedException(); TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException(); TargetCodePointer GetNativeCode(MethodDescHandle methodDesc) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index 5dcb0078bf9854..0842cc781c0fd4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -49,6 +49,7 @@ public enum DataType ProbeExtensionResult, MethodTable, DynamicStaticsInfo, + EEConfig, EEClass, ArrayClass, MethodTableAuxiliaryData, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index 3ea7cdfa963a2f..1ea8fdaa0e638d 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -61,6 +61,8 @@ public static class Globals public const string PtrArrayOffsetToDataArray = nameof(PtrArrayOffsetToDataArray); public const string NumberOfTlsOffsetsNotUsedInNoncollectibleArray = nameof(NumberOfTlsOffsetsNotUsedInNoncollectibleArray); public const string MaxClrNotificationArgs = nameof(MaxClrNotificationArgs); + public const string EEConfig = nameof(EEConfig); + public const string CORDebuggerControlFlags = nameof(CORDebuggerControlFlags); public const string ClrNotificationArguments = nameof(ClrNotificationArguments); public const string PlatformMetadata = nameof(PlatformMetadata); public const string ProfilerControlBlock = nameof(ProfilerControlBlock); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index b2d5109abaa284..befe49c74214d7 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -128,7 +128,7 @@ int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int c break; } } - else if (2 == modulePtr) + else if (rts.IsJitOptimizationDisabled(mdh)) { dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_MinOptJitted; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index e73ccb949f4052..b30c8f0cbe81fa 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -7,6 +7,7 @@ using System.Reflection.Metadata.Ecma335; using Microsoft.Diagnostics.DataContractReader.RuntimeTypeSystemHelpers; using Microsoft.Diagnostics.DataContractReader.Data; +using System.Reflection.Metadata; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -105,6 +106,7 @@ internal struct MethodDesc internal TargetPointer Address { get; init; } internal TargetPointer ChunkAddress { get; init; } + internal bool IsJitOptimizationDisabledForSpecificMethod { get; init; } internal MethodDesc(Target target, TargetPointer methodDescPointer, Data.MethodDesc desc, TargetPointer methodDescChunkAddress, Data.MethodDescChunk chunk) { @@ -116,6 +118,7 @@ internal MethodDesc(Target target, TargetPointer methodDescPointer, Data.MethodD Token = ComputeToken(target, desc, chunk); Size = ComputeSize(target, desc); + IsJitOptimizationDisabledForSpecificMethod = ComputeIsJitOptimizationDisabledForSpecificMethod(target, Token, chunk, desc); } public TargetPointer MethodTable => _chunk.MethodTable; @@ -151,6 +154,19 @@ private static uint ComputeSize(Target target, Data.MethodDesc desc) return target.Read(methodDescSizeTable + arrayOffset); } + private static bool ComputeIsJitOptimizationDisabledForSpecificMethod(Target target, uint token, Data.MethodDescChunk chunk, Data.MethodDesc desc) + { + if ((MethodClassification)(desc.Flags & (int)MethodDescFlags_1.MethodDescFlags.ClassificationMask) != MethodClassification.Dynamic) + return false; + EntityHandle entityHandle = MetadataTokens.EntityHandle((int)token); + TypeHandle mt = target.Contracts.RuntimeTypeSystem.GetTypeHandle(chunk.MethodTable); + TargetPointer modulePtr = target.Contracts.RuntimeTypeSystem.GetModule(mt); + ModuleHandle moduleHandle = target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePtr); + MetadataReader reader = target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; + MethodDefinition md = reader.GetMethodDefinition((MethodDefinitionHandle)entityHandle); + return (md.ImplAttributes & System.Reflection.MethodImplAttributes.NoOptimization) != 0; + } + public MethodClassification Classification => (MethodClassification)((int)_desc.Flags & (int)MethodDescFlags_1.MethodDescFlags.ClassificationMask); private bool HasFlags(MethodDescFlags_1.MethodDescFlags flags) => (_desc.Flags & (ushort)flags) != 0; @@ -1036,6 +1052,36 @@ bool IRuntimeTypeSystem.IsEligibleForTieredCompilation(MethodDescHandle methodDe return md.IsEligibleForTieredCompilation; } + private bool ModuleJitOptsDisabled(MethodDesc md) + { + TypeHandle mt = GetTypeHandle(md.MethodTable); + TargetPointer modulePtr = GetModule(mt); + ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePtr); + ModuleFlags flags = _target.Contracts.Loader.GetFlags(moduleHandle); + + TargetPointer corDebuggerControlFlagsPtr = _target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags); + uint corDebuggerControlFlags = _target.Read(corDebuggerControlFlagsPtr); + // debugger + if ((flags & ModuleFlags.DebuggerAllowJitOptsPriv) != 0 || + (((corDebuggerControlFlags & (uint)DebuggerControlFlags.AllowJitOpt) != 0) && (flags & ModuleFlags.DebuggerUserOverridePriv) == 0)) + return true; + // profiler + if ((flags & ModuleFlags.ProfilerDisableOptimizations) != 0) + return true; + return false; + } + private bool IsJitOptimizationDisabledForAllMethodsInChunk(MethodDesc md) + { + TargetPointer eeConfigPtr = _target.ReadGlobalPointer(Constants.Globals.EEConfig); + Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadPointer(eeConfigPtr)); + return eeConfig.JitMinOpts || eeConfig.Debuggable || ModuleJitOptsDisabled(md); + } + + bool IRuntimeTypeSystem.IsJitOptimizationDisabled(MethodDescHandle methodDesc) + { + MethodDesc md = _methodDescs[methodDesc.Address]; + return md.IsJitOptimizationDisabledForSpecificMethod && IsJitOptimizationDisabledForAllMethodsInChunk(md); + } TargetPointer IRuntimeTypeSystem.GetMethodDescVersioningState(MethodDescHandle methodDesc) { MethodDesc md = _methodDescs[methodDesc.Address]; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs new file mode 100644 index 00000000000000..9a64d483dc8d09 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class EEConfig : IData +{ + static EEConfig IData.Create(Target target, TargetPointer address) => new EEConfig(target, address); + public EEConfig(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.EEConfig); + + JitMinOpts = target.Read(address + (ulong)type.Fields[nameof(JitMinOpts)].Offset) != 0; + Debuggable = target.Read(address + (ulong)type.Fields[nameof(Debuggable)].Offset) != 0; + } + + public bool JitMinOpts { get; init; } + public bool Debuggable { get; init; } +} From e83981edba86e1d289738a93847c9dd20c9e6757 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Tue, 16 Sep 2025 12:59:10 -0700 Subject: [PATCH 03/13] e --- .../vm/datadescriptor/datadescriptor.inc | 9 +++ src/coreclr/vm/eeconfig.h | 4 ++ .../Constants.cs | 1 + .../Contracts/CodeVersions_1.cs | 60 ++++++++++--------- .../Data/EEConfig.cs | 4 ++ 5 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 7a6306089013d3..eaa72466c7895c 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -314,6 +314,10 @@ CDAC_TYPE_BEGIN(EEConfig) CDAC_TYPE_INDETERMINATE(EEConfig) CDAC_TYPE_FIELD(EEConfig, /*bool*/, JitMinOpts, cdac_data::JitMinOpts) CDAC_TYPE_FIELD(EEConfig, /*bool*/, Debuggable, cdac_data::Debuggable) +#if defined(FEATURE_PGO) +CDAC_TYPE_FIELD(EEConfig, /*bool*/, TieredPGO, cdac_data::TieredPGO) +CDAC_TYPE_FIELD(EEConfig, /*bool*/, TieredPGO_InstrumentOnlyHotCode, cdac_data::TieredPGO_InstrumentOnlyHotCode) +#endif CDAC_TYPE_END(EEConfig) CDAC_TYPE_BEGIN(ArrayClass) @@ -983,6 +987,11 @@ CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 1 | 1 << 1 | 1 << 2) #else CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 1 | 1 << 1) #endif //TARGET_64BIT +#ifdef FEATURE_TIERED_COMPILATION +CDAC_GLOBAL(FeatureTieredCompilation, uint8, 1) +#else +CDAC_GLOBAL(FeatureTieredCompilation, uint8, 0) +#endif // FEATURE_TIERED_COMPILATION CDAC_GLOBAL(SOSBreakingChangeVersion, uint8, SOS_BREAKING_CHANGE_VERSION) CDAC_GLOBAL(DirectorySeparator, uint8, (uint8_t)DIRECTORY_SEPARATOR_CHAR_A) CDAC_GLOBAL(HashMapSlotsPerBucket, uint32, SLOTS_PER_BUCKET) diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index 8d4cf680e79fa1..8439b690240a5a 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -702,6 +702,10 @@ template<> struct cdac_data { static constexpr size_t JitMinOpts = offsetof(EEConfig, fJitMinOpts); static constexpr size_t Debuggable = offsetof(EEConfig, fDebuggable); +#if defined(FEATURE_PGO) + static constexpr size_t TieredPGO = offsetof(EEConfig, fTieredPGO); + static constexpr size_t TieredPGO_InstrumentOnlyHotCode = offsetof(EEConfig, tieredPGO_InstrumentOnlyHotCode); +#endif }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs index e6b9d6d6fc6180..79c32addc876d1 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -19,6 +19,7 @@ public static class Globals public const string ObjectToMethodTableUnmask = nameof(ObjectToMethodTableUnmask); public const string SOSBreakingChangeVersion = nameof(SOSBreakingChangeVersion); + public const string FeatureTieredCompilation = nameof(FeatureTieredCompilation); public const string ExceptionMethodTable = nameof(ExceptionMethodTable); public const string FreeObjectMethodTable = nameof(FreeObjectMethodTable); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index 8cbbddaaa86683..6c130ea96a0bb0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -37,37 +37,36 @@ public enum OptimizationTierEnum public OptimizationTierEnum OptimizationTier; public TargetPointer NativeCodeVersionNodePtr; }; - - private IEnumerable GetNativeCodeVersionNodes(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle) + + internal enum NativeOptimizationTier : uint { - if (!ilCodeVersionHandle.IsValid) - yield break; - - // Iterate through versioning state nodes and return the active one, matching any IL code version - Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); - TargetNUInt ilVersionId = GetId(ilCodeVersionHandle); - - // ImplicitCodeVersion stage of NativeCodeVersionIterator::Next() - TargetPointer versioningStateAddr = rts.GetMethodDescVersioningState(md); - if (versioningStateAddr == TargetPointer.Null) - yield break; + OptimizationTier0 = 0, + OptimizationTier1 = 1, + OptimizationTier1OSR = 2, + OptimizationTierOptimized = 3, // may do less optimizations than tier 1 + OptimizationTier0Instrumented = 4, + OptimizationTier1Instrumented = 5, + }; - Data.MethodDescVersioningState versioningState = _target.ProcessedData.GetOrAdd(versioningStateAddr); + private DacpTieredVersionData.OptimizationTierEnum GetInitialOptimizationTier(bool isEligibleForTieredCompilation, bool isReadyToRun) + { + if (_target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) == 0 || !isEligibleForTieredCompilation) + return (DacpTieredVersionData.OptimizationTierEnum)NativeOptimizationTier.OptimizationTierOptimized; - // LinkedList stage of NativeCodeVersion::Next, heavily inlined - TargetPointer currentAddress = versioningState.NativeCodeVersionNode; - while (currentAddress != TargetPointer.Null) + Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); + else if (1 == count) // get the call counting stuff { - Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd(currentAddress); - if (current.ILVersionId == ilVersionId) - { - yield return current; - } - currentAddress = current.Next; + return DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJitted; + } + else if (eeConfig.TieredPGO) // tiered pgo + { + if (eeConfig.TieredPGO_InstrumentOnlyHotCode || isReadyToRun) + return DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_MinOptJitted; + else + return DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized; } - yield break; } + int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs, out Span nativeCodeAddrs, out int pcNativeCodeAddrs) { pcNativeCodeAddrs = 0; @@ -92,15 +91,22 @@ int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int c ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); bool isReadyToRun = loader.GetReadyToRunInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); + bool isEligibleForTieredCompilation = rts.IsEligibleForTieredCompilation(mdh); int count = 0; - foreach (NativeCodeVersionNode nativeCodeVersionNode in GetNativeCodeVersionNodes(methodDesc, ilCodeVersion)) + foreach (NativeCodeVersionHandle nativeCodeVersionHandle in ((ICodeVersions)this).GetNativeCodeVersions(methodDesc, ilCodeVersion)) { + if (!nativeCodeVersionHandle.IsExplicit) + { + // get the default optimization level + dacpTieredVersionDataArray[count].OptimizationTier = GetInitialOptimizationTier(isEligibleForTieredCompilation, isReadyToRun); + } + NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); if (r2rImageBase <= nativeCodeVersionNode.NativeCode && nativeCodeVersionNode.NativeCode < r2rImageEnd) { dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_ReadyToRun; } - else if (rts.IsEligibleForTieredCompilation(mdh)) + else if (isEligibleForTieredCompilation) { uint optimizationTier = nativeCodeVersionNode.OptimizationTier; switch (optimizationTier) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs index 9a64d483dc8d09..cb6141878e8a50 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs @@ -12,8 +12,12 @@ public EEConfig(Target target, TargetPointer address) JitMinOpts = target.Read(address + (ulong)type.Fields[nameof(JitMinOpts)].Offset) != 0; Debuggable = target.Read(address + (ulong)type.Fields[nameof(Debuggable)].Offset) != 0; + TieredPGO = target.Read(address + (ulong)type.Fields[nameof(TieredPGO)].Offset) != 0; + TieredPGO_InstrumentOnlyHotCode = target.Read(address + (ulong)type.Fields[nameof(TieredPGO_InstrumentOnlyHotCode)].Offset) != 0; } public bool JitMinOpts { get; init; } public bool Debuggable { get; init; } + public bool TieredPGO { get; init; } + public bool TieredPGO_InstrumentOnlyHotCode { get; init; } } From fd126abde68686a16be959427dc4a4d64226d6b5 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 17 Sep 2025 16:04:09 -0700 Subject: [PATCH 04/13] e --- src/coreclr/vm/callcounting.h | 15 +- src/coreclr/vm/codeversion.h | 10 +- .../vm/datadescriptor/datadescriptor.inc | 21 +++ src/coreclr/vm/loaderallocator.hpp | 1 + .../DataType.cs | 4 + .../Contracts/CodeVersions_1.cs | 150 +++++++++++++----- .../Data/CallCountingInfo.cs | 28 ++++ .../Data/CallCountingManager.cs | 19 +++ .../Data/LoaderAllocator.cs | 2 + .../Data/NativeCodeVersion.cs | 27 ++++ .../Data/NativeCodeVersionNode.cs | 2 + 11 files changed, 240 insertions(+), 39 deletions(-) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingInfo.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingManager.cs create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersion.cs diff --git a/src/coreclr/vm/callcounting.h b/src/coreclr/vm/callcounting.h index 59071aa51f140b..f56553da6156b5 100644 --- a/src/coreclr/vm/callcounting.h +++ b/src/coreclr/vm/callcounting.h @@ -248,6 +248,7 @@ class CallCountingManager static BOOL Equals(const key_t &k1, const key_t &k2); static count_t Hash(const key_t &k); }; + friend struct ::cdac_data; }; typedef SHash CallCountingInfoByCodeVersionHash; @@ -388,10 +389,22 @@ class CallCountingManager #ifdef DACCESS_COMPILE static void DacEnumerateCallCountingStubHeapRanges(CLRDataEnumMemoryFlags flags); #endif - + friend struct ::cdac_data; DISABLE_COPY(CallCountingManager); }; +template<> +struct cdac_data +{ + static constexpr size_t CallCountingHash = offsetof(CallCountingManager, m_callCountingInfoByCodeVersionHash); +}; + +template<> +struct cdac_data +{ + static constexpr size_t CodeVersion = offsetof(CallCountingManager::CallCountingInfo, m_codeVersion); + static constexpr size_t Stage = offsetof(CallCountingManager::CallCountingInfo, m_stage); +}; //////////////////////////////////////////////////////////////// // CallCountingStub definitions diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index c738347927fbc3..2a0590bfee856d 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -140,10 +140,17 @@ class NativeCodeVersion PTR_MethodDesc m_pMethodDesc; } m_synthetic; }; -#endif // FEATURE_CODE_VERSIONING +friend struct ::cdac_data; }; +template<> +struct cdac_data +{ + static constexpr size_t StorageKind = offsetof(NativeCodeVersion, m_storageKind); + static constexpr size_t VersionNode = offsetof(NativeCodeVersion, m_pVersionNode); +}; +#endif // FEATURE_CODE_VERSIONING #ifdef FEATURE_CODE_VERSIONING @@ -333,6 +340,7 @@ struct cdac_data static constexpr size_t Flags = offsetof(NativeCodeVersionNode, m_flags); static constexpr size_t ILVersionId = offsetof(NativeCodeVersionNode, m_parentId); static constexpr size_t OptimizationTier = offsetof(NativeCodeVersionNode, m_optTier); + static constexpr size_t NativeId = offsetof(NativeCodeVersionNode, m_id); #ifdef HAVE_GCCOVER static constexpr size_t GCCoverageInfo = offsetof(NativeCodeVersionNode, m_gcCover); #endif // HAVE_GCCOVER diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index eaa72466c7895c..145e2abb574972 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -206,8 +206,22 @@ CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, HighFrequencyHeap, cdac_data::LowFrequencyHeap) CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, StubHeap, cdac_data::StubHeap) CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, ObjectHandle, cdac_data::ObjectHandle) +CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, CallCountingManager, cdac_data::CallCountingManager) CDAC_TYPE_END(LoaderAllocator) +CDAC_TYPE_BEGIN(CallCountingManager) +CDAC_TYPE_INDETERMINATE(CallCountingManager) +CDAC_TYPE_FIELD(CallCountingManager, /*pointer*/, CallCountingHash, cdac_data::CallCountingHash) +CDAC_TYPE_END(CallCountingManager) + +// the size is pointer size because this is for an SHash +// and the entry is a pointer to this data structure +CDAC_TYPE_BEGIN(CallCountingInfo) +CDAC_TYPE_SIZE(sizeof(uintptr_t)) +CDAC_TYPE_FIELD(CallCountingInfo, /*pointer*/, CodeVersion, cdac_data::CodeVersion) +CDAC_TYPE_FIELD(CallCountingInfo, /*int32*/, Stage, cdac_data::Stage) +CDAC_TYPE_END(CallCountingInfo) + CDAC_TYPE_BEGIN(PEAssembly) CDAC_TYPE_INDETERMINATE(PEAssembly) CDAC_TYPE_FIELD(PEAssembly, /*pointer*/, PEImage, cdac_data::PEImage) @@ -684,11 +698,18 @@ CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, NativeCode, cdac_data::Flags) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*nuint*/, ILVersionId, cdac_data::ILVersionId) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, OptimizationTier, cdac_data::OptimizationTier) +CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, NativeId, cdac_data::NativeId) #ifdef HAVE_GCCOVER CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, GCCoverageInfo, cdac_data::GCCoverageInfo) #endif // HAVE_GCCOVER CDAC_TYPE_END(NativeCodeVersionNode) +CDAC_TYPE_BEGIN(NativeCodeVersion) +CDAC_TYPE_INDETERMINATE(NativeCodeVersion) +CDAC_TYPE_FIELD(NativeCodeVersion, /*uint8*/, StorageKind, cdac_data::StorageKind) +CDAC_TYPE_FIELD(NativeCodeVersion, /*pointer*/, VersionNode, cdac_data::VersionNode) +CDAC_TYPE_END(NativeCodeVersion) + CDAC_TYPE_BEGIN(ILCodeVersionNode) CDAC_TYPE_INDETERMINATE(ILCodeVersionNode) CDAC_TYPE_FIELD(ILCodeVersionNode, /*nuint*/, VersionId, cdac_data::VersionId) diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index eaf327588f9a99..b9aa9bfacb96fb 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -912,6 +912,7 @@ struct cdac_data static constexpr size_t LowFrequencyHeap = offsetof(LoaderAllocator, m_pLowFrequencyHeap); static constexpr size_t StubHeap = offsetof(LoaderAllocator, m_pStubHeap); static constexpr size_t ObjectHandle = offsetof(LoaderAllocator, m_hLoaderAllocatorObjectHandle); + static constexpr size_t CallCountingManager = offsetof(LoaderAllocator, m_callCountingManager); }; typedef VPTR(LoaderAllocator) PTR_LoaderAllocator; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index ebed4c064d6902..b7abc5fe464163 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -41,6 +41,10 @@ public enum DataType SystemDomain, Assembly, LoaderAllocator, + CallCountingManager, + CallCountingInfo, + CallCountingTable, + NativeCodeVersion, PEAssembly, AssemblyBinder, PEImage, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index 6c130ea96a0bb0..e92a1f387f1a02 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -37,7 +37,7 @@ public enum OptimizationTierEnum public OptimizationTierEnum OptimizationTier; public TargetPointer NativeCodeVersionNodePtr; }; - + internal enum NativeOptimizationTier : uint { OptimizationTier0 = 0, @@ -48,25 +48,114 @@ internal enum NativeOptimizationTier : uint OptimizationTier1Instrumented = 5, }; - private DacpTieredVersionData.OptimizationTierEnum GetInitialOptimizationTier(bool isEligibleForTieredCompilation, bool isReadyToRun) + internal enum Stage : byte { - if (_target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) == 0 || !isEligibleForTieredCompilation) - return (DacpTieredVersionData.OptimizationTierEnum)NativeOptimizationTier.OptimizationTierOptimized; + StubIsNotActive, + StubMayBeActive, + PendingCompletion, + Complete, + Disabled + }; + + internal enum StorageKind + { + Unknown, + Explicit, + Synthetic + }; - Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); - else if (1 == count) // get the call counting stuff + + private sealed class CodeVersionHashTraits : ITraits + { + private readonly Target _target; + public CodeVersionHashTraits(Target target) + { + _target = target; + } + public NativeCodeVersion GetKey(CallCountingInfo entry) { - return DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJitted; + return _target.ProcessedData.GetOrAdd(entry.CodeVersion); } - else if (eeConfig.TieredPGO) // tiered pgo + public bool Equals(NativeCodeVersion left, NativeCodeVersion right) => left.StorageKind == right.StorageKind && left.MethodDescOrNode == right.MethodDescOrNode; + public uint Hash(NativeCodeVersion key) + { + switch ((StorageKind)key.StorageKind) + { + case StorageKind.Synthetic: // SK_Synthetic + return (uint)key.MethodDescOrNode; + case StorageKind.Explicit: // SK_Explicit + NativeCodeVersionNode node = _target.ProcessedData.GetOrAdd(key.MethodDescOrNode); + return (uint)node.MethodDesc + node.NativeId; + default: + throw new NotSupportedException(); + } + } + public bool IsNull(CallCountingInfo entry) => entry.Address == TargetPointer.Null; + public CallCountingInfo Null() => new CallCountingInfo(TargetPointer.Null); + public bool IsDeleted(CallCountingInfo entry) => false; + } + + private sealed class CallCountingTable : IData + { + static CallCountingTable IData.Create(Target target, TargetPointer address) + => new CallCountingTable(target, address); + + public CallCountingTable(Target target, TargetPointer address) { + ISHash sHashContract = target.Contracts.SHash; + Target.TypeInfo type = target.GetTypeInfo(DataType.CallCountingInfo); + HashTable = sHashContract.CreateSHash(target, address, type, new CodeVersionHashTraits(target)); + } + public ISHash HashTable { get; init; } + } + private bool IsCallCountingEnabled(MethodDescHandle mdh) + { + Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + Contracts.ILoader loaderContract = _target.Contracts.Loader; + TargetPointer mt = rtsContract.GetMethodTable(mdh); + TargetPointer modulePtr = rtsContract.GetLoaderModule(rtsContract.GetTypeHandle(mt)); + Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(modulePtr); + TargetPointer loaderAllocator = loaderContract.GetLoaderAllocator(moduleHandle); + + Data.LoaderAllocator loaderAllocatorData = _target.ProcessedData.GetOrAdd(loaderAllocator); + TargetPointer callCountingMgr = loaderAllocatorData.CallCountingManager; + TargetPointer callCountingHash = _target.ProcessedData.GetOrAdd(callCountingMgr).CallCountingHash; + CallCountingTable callCountingTable = _target.ProcessedData.GetOrAdd(callCountingHash); + + ISHash shashContract = _target.Contracts.SHash; + CallCountingInfo entry = shashContract.LookupSHash(callCountingTable.HashTable, new NativeCodeVersion((uint)StorageKind.Synthetic, mdh.Address)); + return entry.Address != TargetPointer.Null && entry.Stage != (byte)Stage.Disabled; + } + private NativeOptimizationTier GetInitialOptimizationTier(bool isEligibleForTieredCompilation, bool isReadyToRun, MethodDescHandle mdh) + { + if (_target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) == 0 + || !isEligibleForTieredCompilation + || !IsCallCountingEnabled(mdh)) + return NativeOptimizationTier.OptimizationTierOptimized; + else + { + Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); if (eeConfig.TieredPGO_InstrumentOnlyHotCode || isReadyToRun) - return DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_MinOptJitted; + return NativeOptimizationTier.OptimizationTier0; else - return DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized; + return NativeOptimizationTier.OptimizationTier0Instrumented; } } + private static DacpTieredVersionData.OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) + { + return nativeOptimizationTier switch + { + NativeOptimizationTier.OptimizationTier0 => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJitted, + NativeOptimizationTier.OptimizationTier1 => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1, + NativeOptimizationTier.OptimizationTier1OSR => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1OSR, + NativeOptimizationTier.OptimizationTierOptimized => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized, + NativeOptimizationTier.OptimizationTier0Instrumented => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJittedInstrumented, + NativeOptimizationTier.OptimizationTier1Instrumented => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1Instrumented, + _ => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Unknown, + }; + } + int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs, out Span nativeCodeAddrs, out int pcNativeCodeAddrs) { pcNativeCodeAddrs = 0; @@ -97,8 +186,14 @@ int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int c { if (!nativeCodeVersionHandle.IsExplicit) { - // get the default optimization level - dacpTieredVersionDataArray[count].OptimizationTier = GetInitialOptimizationTier(isEligibleForTieredCompilation, isReadyToRun); + dacpTieredVersionDataArray[count].NativeCodeVersionNodePtr = TargetPointer.Null; + dacpTieredVersionDataArray[count].NativeCodeAddr = rts.GetNativeCode(mdh).AsTargetPointer; + } + else + { + NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); + dacpTieredVersionDataArray[count].NativeCodeVersionNodePtr = nativeCodeVersionHandle.CodeVersionNodeAddress; + dacpTieredVersionDataArray[count].NativeCodeAddr = nativeCodeVersionNode.NativeCode; } NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); if (r2rImageBase <= nativeCodeVersionNode.NativeCode && nativeCodeVersionNode.NativeCode < r2rImageEnd) @@ -108,31 +203,12 @@ int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int c else if (isEligibleForTieredCompilation) { - uint optimizationTier = nativeCodeVersionNode.OptimizationTier; - switch (optimizationTier) - { - case 0: - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJitted; - break; - case 1: - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1; - break; - case 2: - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1OSR; - break; - case 3: - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized; - break; - case 4: - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJittedInstrumented; - break; - case 5: - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1Instrumented; - break; - default: - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Unknown; - break; - } + NativeOptimizationTier optTier; + if (!nativeCodeVersionHandle.IsExplicit) + optTier = GetInitialOptimizationTier(isEligibleForTieredCompilation, isReadyToRun, mdh); + else + optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier; + dacpTieredVersionDataArray[count].OptimizationTier = GetOptimizationTier(optTier); } else if (rts.IsJitOptimizationDisabled(mdh)) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingInfo.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingInfo.cs new file mode 100644 index 00000000000000..c0a9a2e84df2da --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingInfo.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class CallCountingInfo : IData +{ + static CallCountingInfo IData.Create(Target target, TargetPointer address) + => new CallCountingInfo(target, address); + + public CallCountingInfo(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.CallCountingInfo); + + Stage = target.Read(address + (ulong)type.Fields[nameof(Stage)].Offset); + CodeVersion = target.ReadPointer(address + (ulong)type.Fields[nameof(CodeVersion)].Offset); + Address = address; + } + + public CallCountingInfo(TargetPointer address) + { + Address = address; + } + + public byte Stage { get; init; } + public TargetPointer CodeVersion { get; init; } + public TargetPointer Address { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingManager.cs new file mode 100644 index 00000000000000..66725a24b4b77f --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingManager.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class CallCountingManager : IData +{ + static CallCountingManager IData.Create(Target target, TargetPointer address) + => new CallCountingManager(target, address); + + public CallCountingManager(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.CallCountingManager); + + CallCountingHash = address + (ulong)type.Fields[nameof(CallCountingHash)].Offset; + } + + public TargetPointer CallCountingHash { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs index c00af4c5264f06..846070a5f1ab04 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs @@ -18,6 +18,7 @@ public LoaderAllocator(Target target, TargetPointer address) StubHeap = target.ReadPointer(address + (ulong)type.Fields[nameof(StubHeap)].Offset); ObjectHandle = target.ProcessedData.GetOrAdd( target.ReadPointer(address + (ulong)type.Fields[nameof(ObjectHandle)].Offset)); + CallCountingManager = target.ReadPointer(address + (ulong)type.Fields[nameof(CallCountingManager)].Offset); } public uint ReferenceCount { get; init; } @@ -25,6 +26,7 @@ public LoaderAllocator(Target target, TargetPointer address) public TargetPointer LowFrequencyHeap { get; init; } public TargetPointer StubHeap { get; init; } public ObjectHandle ObjectHandle { get; init; } + public TargetPointer CallCountingManager { get; init; } public bool IsAlive => ReferenceCount != 0; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersion.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersion.cs new file mode 100644 index 00000000000000..ec3149dcd467fb --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersion.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Diagnostics.DataContractReader.Data; + +internal sealed class NativeCodeVersion : IData +{ + static NativeCodeVersion IData.Create(Target target, TargetPointer address) => new NativeCodeVersion(target, address); + public NativeCodeVersion(Target target, TargetPointer address) + { + Target.TypeInfo type = target.GetTypeInfo(DataType.NativeCodeVersion); + + StorageKind = target.Read(address + (ulong)type.Fields[nameof(StorageKind)].Offset); + MethodDescOrNode = target.ReadPointer(address + (ulong)type.Fields[nameof(MethodDescOrNode)].Offset); + } + + public NativeCodeVersion(uint storageKind, TargetPointer methodDescOrNode) + { + StorageKind = storageKind; + MethodDescOrNode = methodDescOrNode; + } + + public uint StorageKind { get; init; } + public TargetPointer MethodDescOrNode { get; init; } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs index 22256404b14f82..44a647a384abea 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs @@ -18,6 +18,7 @@ public NativeCodeVersionNode(Target target, TargetPointer address) Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); ILVersionId = target.ReadNUInt(address + (ulong)type.Fields[nameof(ILVersionId)].Offset); OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); + NativeId = target.Read(address + (ulong)type.Fields[nameof(NativeId)].Offset); if (type.Fields.ContainsKey(nameof(GCCoverageInfo))) { GCCoverageInfo = target.ReadPointer(address + (ulong)type.Fields[nameof(GCCoverageInfo)].Offset); @@ -31,6 +32,7 @@ public NativeCodeVersionNode(Target target, TargetPointer address) public uint Flags { get; init; } public TargetNUInt ILVersionId { get; init; } public uint OptimizationTier { get; init; } + public uint NativeId {get; init; } public TargetPointer? GCCoverageInfo { get; init; } } From c4e12e60d214803a999c13dcede61dcc3dbf7bd6 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 17 Sep 2025 17:44:28 -0700 Subject: [PATCH 05/13] e --- .../Contracts/ICodeVersions.cs | 2 +- .../Contracts/CodeVersions_1.cs | 42 +++++++------------ .../Data/NativeCodeVersionNode.cs | 4 +- .../Legacy/SOSDacImpl.cs | 38 ++++++++++++++--- 4 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs index f13187aadf2d9c..a62e33edd6372e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs @@ -9,7 +9,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; public interface ICodeVersions : IContract { static string IContract.Name { get; } = nameof(CodeVersions); - public virtual int GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs, out Span nativeCodeAddrs, out int pcNativeCodeAddrs) => throw new NotImplementedException(); + public virtual IEnumerable<(TargetPointer, TargetPointer, int)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) => throw new NotImplementedException(); public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index e92a1f387f1a02..8f6525edb81409 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -156,10 +156,8 @@ private static DacpTieredVersionData.OptimizationTierEnum GetOptimizationTier(Na }; } - int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs, out Span nativeCodeAddrs, out int pcNativeCodeAddrs) + IEnumerable<(TargetPointer, TargetPointer, int)> ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) { - pcNativeCodeAddrs = 0; - DacpTieredVersionData[] dacpTieredVersionDataArray = new DacpTieredVersionData[cNativeCodeAddrs]; Contracts.ICodeVersions codeVersionsContract = this; Contracts.IReJIT rejitContract = _target.Contracts.ReJIT; @@ -184,21 +182,13 @@ int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int c int count = 0; foreach (NativeCodeVersionHandle nativeCodeVersionHandle in ((ICodeVersions)this).GetNativeCodeVersions(methodDesc, ilCodeVersion)) { - if (!nativeCodeVersionHandle.IsExplicit) + TargetPointer nativeCode = codeVersionsContract.GetNativeCode(nativeCodeVersionHandle).AsTargetPointer; + TargetPointer nativeCodeAddr = nativeCode; + TargetPointer nativeCodeVersionNodePtr = nativeCodeVersionHandle.IsExplicit ? AsNode(nativeCodeVersionHandle).Address : TargetPointer.Null; + int optimizationTier; + if (r2rImageBase <= nativeCode && nativeCode < r2rImageEnd) { - dacpTieredVersionDataArray[count].NativeCodeVersionNodePtr = TargetPointer.Null; - dacpTieredVersionDataArray[count].NativeCodeAddr = rts.GetNativeCode(mdh).AsTargetPointer; - } - else - { - NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); - dacpTieredVersionDataArray[count].NativeCodeVersionNodePtr = nativeCodeVersionHandle.CodeVersionNodeAddress; - dacpTieredVersionDataArray[count].NativeCodeAddr = nativeCodeVersionNode.NativeCode; - } - NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); - if (r2rImageBase <= nativeCodeVersionNode.NativeCode && nativeCodeVersionNode.NativeCode < r2rImageEnd) - { - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_ReadyToRun; + optimizationTier = (int)DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_ReadyToRun; } else if (isEligibleForTieredCompilation) @@ -207,28 +197,26 @@ int ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int c if (!nativeCodeVersionHandle.IsExplicit) optTier = GetInitialOptimizationTier(isEligibleForTieredCompilation, isReadyToRun, mdh); else + { + NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier; - dacpTieredVersionDataArray[count].OptimizationTier = GetOptimizationTier(optTier); + } + optimizationTier = (int)GetOptimizationTier(optTier); } else if (rts.IsJitOptimizationDisabled(mdh)) { - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_MinOptJitted; + optimizationTier = (int)DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_MinOptJitted; } else { - dacpTieredVersionDataArray[count].OptimizationTier = DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized; + optimizationTier = (int)DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized; } count++; + yield return (nativeCodeAddr, nativeCodeVersionNodePtr, optimizationTier); if (count >= cNativeCodeAddrs) - { - nativeCodeAddrs = MemoryMarshal.AsBytes(dacpTieredVersionDataArray.AsSpan()); - return 1; - } + yield break; } - pcNativeCodeAddrs = count; - nativeCodeAddrs = MemoryMarshal.AsBytes(dacpTieredVersionDataArray.AsSpan()); - return 0; } ILCodeVersionHandle ICodeVersions.GetActiveILCodeVersion(TargetPointer methodDesc) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs index 44a647a384abea..eed5fc97d79d90 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs @@ -23,6 +23,7 @@ public NativeCodeVersionNode(Target target, TargetPointer address) { GCCoverageInfo = target.ReadPointer(address + (ulong)type.Fields[nameof(GCCoverageInfo)].Offset); } + Address = address; } public TargetPointer Next { get; init; } @@ -32,7 +33,8 @@ public NativeCodeVersionNode(Target target, TargetPointer address) public uint Flags { get; init; } public TargetNUInt ILVersionId { get; init; } public uint OptimizationTier { get; init; } - public uint NativeId {get; init; } + public uint NativeId { get; init; } public TargetPointer? GCCoverageInfo { get; init; } + public TargetPointer Address { get; init; } } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 7b1fc4c34d7b25..8b09d4b77278b8 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -3106,17 +3106,45 @@ int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, throw new ArgumentException(); TargetPointer methodDescPtr = methodDesc.ToTargetPointer(_target); - hr = _target.Contracts.CodeVersions.GetTieredVersions(methodDescPtr, rejitId, cNativeCodeAddrs, out Span nativeCodeData, out int nativeCodeCount); - *pcNativeCodeAddrs = nativeCodeCount; - Span dest = new Span(nativeCodeAddrs, nativeCodeData.Length); - nativeCodeData.CopyTo(dest); + int count = 0; + foreach ((TargetPointer nativeCode, TargetPointer nativeCodeVersionNodePtr, int optTier) in _target.Contracts.CodeVersions.GetTieredVersions(methodDescPtr, rejitId, cNativeCodeAddrs)) + { + nativeCodeAddrs[count++] = default; + nativeCodeAddrs[count].NativeCodeAddr = nativeCode.ToClrDataAddress(_target); + nativeCodeAddrs[count].NativeCodeVersionNodePtr = nativeCodeVersionNodePtr.ToClrDataAddress(_target); + nativeCodeAddrs[count].OptimizationTier = (DacpTieredVersionData.OptimizationTierEnum)optTier; + } + *pcNativeCodeAddrs = count; + if (count >= cNativeCodeAddrs) + hr = HResults.S_FALSE; } catch (System.Exception ex) { hr = ex.HResult; } #if DEBUG - if + if (_legacyImpl5 is not null) + { + DacpTieredVersionData[] nativeCodeAddrsLocal = new DacpTieredVersionData[cNativeCodeAddrs]; + int neededLocal; + fixed (DacpTieredVersionData* ptr = nativeCodeAddrsLocal) + { + int hrLocal = _legacyImpl5.GetTieredVersions(methodDesc, rejitId, ptr, cNativeCodeAddrs, &neededLocal); + Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}"); + if (hr == HResults.S_OK || hr == HResults.S_FALSE) + { + Debug.Assert(*pcNativeCodeAddrs == neededLocal, $"cDAC: {*pcNativeCodeAddrs}, DAC: {neededLocal}"); + for (int i = 0; i < *pcNativeCodeAddrs; i++) + { + Debug.Assert(nativeCodeAddrs[i].NativeCodeAddr == nativeCodeAddrsLocal[i].NativeCodeAddr, $"cDAC: {nativeCodeAddrs[i].NativeCodeAddr:x}, DAC: {nativeCodeAddrsLocal[i].NativeCodeAddr:x}"); + Debug.Assert(nativeCodeAddrs[i].NativeCodeVersionNodePtr == nativeCodeAddrsLocal[i].NativeCodeVersionNodePtr, $"cDAC: {nativeCodeAddrs[i].NativeCodeVersionNodePtr:x}, DAC: {nativeCodeAddrsLocal[i].NativeCodeVersionNodePtr:x}"); + Debug.Assert(nativeCodeAddrs[i].OptimizationTier == nativeCodeAddrsLocal[i].OptimizationTier, $"cDAC: {nativeCodeAddrs[i].OptimizationTier}, DAC: {nativeCodeAddrsLocal[i].OptimizationTier}"); + } + } + } + } +#endif + return hr; } #endregion ISOSDacInterface5 From 388f07e75820a09ae86cf498e5efa285632e12ac Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 18 Sep 2025 11:47:43 -0700 Subject: [PATCH 06/13] adding GetTieredVersions cDAC API --- docs/design/datacontracts/CodeVersions.md | 239 +++++++++++++++++- docs/design/datacontracts/Loader.md | 29 ++- .../design/datacontracts/RuntimeTypeSystem.md | 48 +++- src/coreclr/vm/callcounting.h | 16 +- src/coreclr/vm/ceeload.cpp | 4 +- src/coreclr/vm/ceeload.h | 2 + src/coreclr/vm/codeversion.h | 6 +- .../vm/datadescriptor/datadescriptor.inc | 11 +- src/coreclr/vm/readytoruninfo.h | 1 - .../Contracts/ICodeVersions.cs | 15 +- .../Contracts/IRuntimeTypeSystem.cs | 1 + .../DataType.cs | 1 - .../Contracts/CodeVersions_1.cs | 92 +++---- .../Contracts/Loader_1.cs | 5 +- .../Contracts/RuntimeTypeSystem_1.cs | 11 +- .../Signature/SignatureTypeProvider.cs | 0 .../Data/Module.cs | 2 + .../Legacy/ISOSDacInterface.cs | 24 +- .../Legacy/SOSDacImpl.cs | 6 +- 19 files changed, 399 insertions(+), 114 deletions(-) delete mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 2a3e186739df22..91f1ea7a78f58f 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -22,6 +22,22 @@ internal struct NativeCodeVersionHandle } ``` +Native code version optimization enum: +```csharp +public enum OptimizationTierEnum +{ + Unknown = 0, + MinOptJitted = 1, + Optimized = 2, + QuickJitted = 3, + OptimizedTier1 = 4, + ReadyToRun = 5, + OptimizedTier1OSR = 6, + QuickJittedInstrumented = 7, + OptimizedTier1Instrumented = 8, +} +``` + ```csharp // Return a handle to the active version of the IL code for a given method descriptor public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc); @@ -62,7 +78,15 @@ See [code versioning](../features/code-versioning.md) for a general overview and Data descriptors used: | Data Descriptor Name | Field | Meaning | | --- | --- | --- | +| CallCountingInfo | CodeVersion | pointer to native code version | +| CallCountingInfo | Stage | call counting enum, see below | +| CallCountingInfo | Table | pointer to call counting info SHash table | +| CallCountingInfo | TableSize | number of entries in CallCountingInfo SHash table | +| CallCountingManager | CallCountingHash | SHash of native code versions to call counting info | +| EEConfig | TieredPGO_InstrumentOnlyHotCode | boolean, for deciding optimization tier of default native code version | | MethodDescVersioningState | Flags | `MethodDescVersioningStateFlags` flags, see below | +| NativeCodeVersion | StorageKind | storage kind enum, see below | +| NativeCodeVersion | MethodDescOrNode | pointer to method desc (synthetic) or version node (explicit) | | MethodDescVersioningState | NativeCodeVersionNode | code version node of this method desc, if active | | NativeCodeVersionNode | Next | pointer to the next native code version | | NativeCodeVersionNode | MethodDesc | indicates a synthetic native code version node | @@ -70,6 +94,7 @@ Data descriptors used: | NativeCodeVersionNode | Flags | `NativeCodeVersionNodeFlags` flags, see below | | NativeCodeVersionNode | VersionId | Version ID corresponding to the parent IL code version | | NativeCodeVersionNode | GCCoverageInfo | GCStress debug info, if supported | +| NativeCodeVersionNode | NativeId | ID corresponding to the version node | | ILCodeVersioningState | FirstVersionNode | pointer to the first `ILCodeVersionNode` | | ILCodeVersioningState | ActiveVersionKind | an `ILCodeVersionKind` value indicating which fields of the active version are value | | ILCodeVersioningState | ActiveVersionNode | if the active version is explicit, the NativeCodeVersionNode for the active version | @@ -107,7 +132,46 @@ private enum ILCodeVersionKind } ``` -Global variables used: *none* +The value of `NativeCodeVersionNode::OptimizationTier` is one of +```csharp +private enum NativeOptimizationTier : uint +{ + OptimizationTier0 = 0, + OptimizationTier1 = 1, + OptimizationTier1OSR = 2, + OptimizationTierOptimized = 3, + OptimizationTier0Instrumented = 4, + OptimizationTier1Instrumented = 5, +}; +``` + +The value of `CallCountingInfo::Stage` is one of +```csharp +private enum Stage : byte +{ + StubIsNotActive = 0, + StubMayBeActive = 1, + PendingCompletion = 2, + Complete = 3, + Disabled = 4 +}; +``` + +The value of `NativeCodeVersion::StorageKind` is one of +```csharp +private enum StorageKind +{ + Unknown = 0, + Explicit = 1, + Synthetic = 2 +}; +``` + +### Global variables used: +| Global Name | Type | Purpose | +| --- | --- | --- | +| `FeatureTieredCompilation` | byte | is FEATURE_TIERED_COMPILATION on (1) or off (0) | +| `EEConfig` | TargetPointer | Pointer to the global EEConfig | Contracts used: | Contract Name | @@ -115,6 +179,7 @@ Contracts used: | ExecutionManager | | Loader | | RuntimeTypeSystem | +| SHash | Implementation of CodeVersionHandles @@ -193,9 +258,9 @@ IEnumerable ICodeVersions.GetILCodeVersions(TargetPointer m // CodeVersionManager::GetILCodeVersions GetModuleAndMethodDesc(methodDesc, out TargetPointer module, out uint methodDefToken); - ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(module); - TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState; - TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _); + ModuleHandle moduleHandle = target.Contracts.Loader.GetModuleHandleFromModulePtr(module); + TargetPointer ilCodeVersionTable = target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState; + TargetPointer ilVersionStateAddress = target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _); // always add the synthetic version yield return new ILCodeVersionHandle(module, methodDefToken, TargetPointer.Null); @@ -203,11 +268,11 @@ IEnumerable ICodeVersions.GetILCodeVersions(TargetPointer m // if explicit versions exist, iterate linked list and return them if (ilVersionStateAddress != TargetPointer.Null) { - Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd(ilVersionStateAddress); + Data.ILCodeVersioningState ilState = target.ProcessedData.GetOrAdd(ilVersionStateAddress); TargetPointer nodePointer = ilState.FirstVersionNode; while (nodePointer != TargetPointer.Null) { - Data.ILCodeVersionNode current = _target.ProcessedData.GetOrAdd(nodePointer); + Data.ILCodeVersionNode current = target.ProcessedData.GetOrAdd(nodePointer); yield return new ILCodeVersionHandle(TargetPointer.Null, 0, nodePointer); nodePointer = current.Next; } @@ -220,7 +285,7 @@ IEnumerable ICodeVersions.GetILCodeVersions(TargetPointer m ```csharp NativeCodeVersionHandle ICodeVersions.GetNativeCodeVersionForIP(TargetCodePointer ip) { - Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager; + Contracts.IExecutionManager executionManager = target.Contracts.ExecutionManager; EECodeInfoHandle? info = executionManager.GetEECodeInfoHandle(ip); if (!info.HasValue) { @@ -231,7 +296,7 @@ NativeCodeVersionHandle ICodeVersions.GetNativeCodeVersionForIP(TargetCodePointe { return NativeCodeVersionHandle.Invalid; } - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem; MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); if (!rts.IsVersionable(md)) { @@ -267,13 +332,13 @@ IEnumerable FindNativeCodeVersionNodes(IRuntimeTypeSyst if (versioningStateAddr == TargetPointer.Null) yield break; - Data.MethodDescVersioningState versioningState = _target.ProcessedData.GetOrAdd(versioningStateAddr); + Data.MethodDescVersioningState versioningState = target.ProcessedData.GetOrAdd(versioningStateAddr); // LinkedList stage of NativeCodeVersion::Next, heavily inlined TargetPointer currentAddress = versioningState.NativeCodeVersionNode; while (currentAddress != TargetPointer.Null) { - Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd(currentAddress); + Data.NativeCodeVersionNode current = target.ProcessedData.GetOrAdd(currentAddress); if (predicate(current)) { yield return NativeCodeVersionHandle.OfExplicit(currentAddress); @@ -300,7 +365,7 @@ IEnumerable ICodeVersions.GetNativeCodeVersions(TargetP } // Iterate through versioning state nodes and return the active one, matching any IL code version - Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + Contracts.IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem; MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); TargetNUInt ilVersionId = GetId(ilCodeVersionHandle); IEnumerable nativeCodeVersions = FindNativeCodeVersionNodes( @@ -314,6 +379,152 @@ IEnumerable ICodeVersions.GetNativeCodeVersions(TargetP } ``` +### Iterating through native code versions given a MethodDesc and a rejit ID +Here we need an SHash, the SHash traits are below: +```csharp + private sealed class CodeVersionHashTraits : ITraits + { + private readonly Target _target; + public CodeVersionHashTraits(Target target) + { + _target = target; + } + public NativeCodeVersion GetKey(CallCountingInfo entry) + { + return // read version node or method desc ptr from entry + } + public bool Equals(NativeCodeVersion left, NativeCodeVersion right) => // storage kind and pointer match + public uint Hash(NativeCodeVersion key) + { + // switch on the storage kind + // if synthetic the key is the method desc pointer + // if explicit we read the pointer (node pointer) + // and then sum the ID of the node and the method desc of the node + // otherwise throw not supported + } + public bool IsNull(CallCountingInfo entry) => // address is null + public CallCountingInfo Null() => new CallCountingInfo(TargetPointer.Null); + public bool IsDeleted(CallCountingInfo entry) => false; + } +``` + +```csharp +private bool IsCallCountingEnabled(MethodDescHandle mdh) +{ + // get loader allocator + Contracts.IRuntimeTypeSystem rtsContract = target.Contracts.RuntimeTypeSystem; + Contracts.ILoader loaderContract = target.Contracts.Loader; + TargetPointer loaderAllocator = // get loader allocator using rtsContract and loaderContract + Data.LoaderAllocator loaderAllocatorData = target.ProcessedData.GetOrAdd(loaderAllocator); + + // get call counting manager and hash + TargetPointer callCountingMgr = target.ReadPointer(loaderAllocator + /* LoaderAllocator::CallCountingManager offset */); + TargetPointer callCountingHash = callCountingMgr + /* CallCountingManager::CallCountingHash offset */; + + CodeVersionHashTraits traits = new(target); + ISHash shashContract = target.Contracts.SHash; + /* To construct an SHash we must pass a DataType enum. + We must be able to look up this enum in a dictionary of known types and retrieve a Target.TypeInfo struct. + This struct contains a dictionary of fields with keys corresponding to the names of offsets + and values corresponding to the offset values. Optionally, it contains a Size field. + Here this is the CallCountingInfo DataType which contains the appropriate offsets for the hashtable data, number of entries, as well as the shape and size of each entry. + */ + SHash shash = shashContract.CreateSHash(target, callCountingHash, DataType.CallCountingInfo, traits) + CallCountingInfo entry = shashContract.LookupSHash(callCountingTable.HashTable, new NativeCodeVersion((uint)StorageKind.Synthetic, mdh.Address)); + return // entry is not null and the stage of the entry is not Disabled +} + +private NativeOptimizationTier GetInitialOptimizationTier(bool isReadyToRun, MethodDescHandle mdh) +{ + if (target.ReadGlobal("FeatureTieredCompilation") == 0 + || !IsCallCountingEnabled(mdh)) + return NativeOptimizationTier.TierOptimized; + else + { + TargetPointer eeConfig = // read EEConfig global variable + bool tieredPGO_InstrumentOnlyHotCode = // read from EEConfig + if (tieredPGO_InstrumentOnlyHotCode || isReadyToRun) + return NativeOptimizationTier.Tier0; + else + return NativeOptimizationTier.Tier0Instrumented; + } +} + +IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) +{ + Contracts.ICodeVersions codeVersionsContract = this; + Contracts.IReJIT rejitContract = target.Contracts.ReJIT; + + ILCodeVersionHandle ilCodeVersion = codeVersionsContract.GetILCodeVersions(methodDesc) + .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode).Value == (ulong)rejitId, + ILCodeVersionHandle.Invalid); + + if (!ilCodeVersion.IsValid) + throw new ArgumentException(); + // Iterate through versioning state nodes and return the active one, matching any IL code version + Contracts.IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem; + Contracts.ILoader loader = target.Contracts.Loader; + ModuleHandle moduleHandle = // get the module handle from the method desc using rts + + bool isReadyToRun = loader.GetReadyToRunInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); + bool isEligibleForTieredCompilation = rts.IsEligibleForTieredCompilation(mdh); + int count = 0; + foreach (NativeCodeVersionHandle nativeCodeVersionHandle in ((ICodeVersions)this).GetNativeCodeVersions(methodDesc, ilCodeVersion)) + { + TargetPointer nativeCode = codeVersionsContract.GetNativeCode(nativeCodeVersionHandle).AsTargetPointer; + TargetPointer nativeCodeAddr = nativeCode; + TargetPointer nativeCodeVersionNodePtr = nativeCodeVersionHandle.IsExplicit ? AsNode(nativeCodeVersionHandle).Address : TargetPointer.Null; + OptimizationTierEnum optimizationTier; + if (r2rImageBase <= nativeCode && nativeCode < r2rImageEnd) + { + optimizationTier = OptimizationTierEnum.ReadyToRun; + } + + else if (isEligibleForTieredCompilation) + { + NativeOptimizationTier optTier; + if (!nativeCodeVersionHandle.IsExplicit) + optTier = GetInitialOptimizationTier(isReadyToRun, mdh); + else + { + NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); + optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier; + } + optimizationTier = GetOptimizationTier(optTier); + } + else if (rts.IsJitOptimizationDisabled(mdh)) + { + optimizationTier = OptimizationTierEnum.MinOptJitted; + } + else + { + optimizationTier = OptimizationTierEnum.Optimized; + } + count++; + yield return (nativeCodeAddr, nativeCodeVersionNodePtr, optimizationTier); + + if (count >= cNativeCodeAddrs) + yield break; + } +} +``` + +Helper for the above to translate from internal to external optimization tier +```csharp +private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) +{ + return nativeOptimizationTier switch + { + NativeOptimizationTier.Tier0 => OptimizationTierEnum.QuickJitted, + NativeOptimizationTier.Tier1 => OptimizationTierEnum.OptimizedTier1, + NativeOptimizationTier.Tier1OSR => OptimizationTierEnum.OptimizedTier1OSR, + NativeOptimizationTier.TierOptimized => OptimizationTierEnum.Optimized, + NativeOptimizationTier.Tier0Instrumented => OptimizationTierEnum.QuickJittedInstrumented, + NativeOptimizationTier.Tier1Instrumented => OptimizationTierEnum.OptimizedTier1Instrumented, + _ => OptimizationTierEnum.Unknown, + }; +} +``` ### Finding the active native code version of an ILCodeVersion for a method descriptor ```csharp @@ -329,7 +540,7 @@ public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersio ```csharp bool ICodeVersions.CodeVersionManagerSupportsMethod(TargetPointer methodDescAddress) { - IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem; MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress); if (rts.IsDynamicMethod(md)) return false; @@ -338,7 +549,7 @@ bool ICodeVersions.CodeVersionManagerSupportsMethod(TargetPointer methodDescAddr TargetPointer mtAddr = rts.GetMethodTable(md); TypeHandle mt = rts.GetTypeHandle(mtAddr); TargetPointer modAddr = rts.GetModule(mt); - ILoader loader = _target.Contracts.Loader; + ILoader loader = target.Contracts.Loader; ModuleHandle mod = loader.GetModuleHandleFromModulePtr(modAddr); ModuleFlags modFlags = loader.GetFlags(mod); if (modFlags.HasFlag(ModuleFlags.EditAndContinue)) @@ -372,7 +583,7 @@ TargetPointer ICodeVersions.GetIL(ILCodeVersionHandle ilCodeVersionHandle, Targe { // Synthetic ILCodeVersion, get the IL from the module and method def - ILoader loader = _target.Contracts.Loader; + ILoader loader = target.Contracts.Loader; ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(ilCodeVersionHandle.Module); ilAddress = loader.GetILHeader(moduleHandle, ilCodeVersionHandle.MethodDefinition); } diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index 77ef18e9e8cff6..3960da5ffaddc5 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -15,9 +15,15 @@ readonly struct ModuleHandle [Flags] enum ModuleFlags { - Tenured = 0x00000001, // Set once we know for sure the Module will not be freed until the appdomain itself exits - EditAndContinue = 0x00000008, // Edit and Continue is enabled for this module - ReflectionEmit = 0x00000040, // Reflection.Emit was used to create this module + Tenured = 0x1, // Set once we know for sure the Module will not be freed until the appdomain itself exits + EditAndContinue = 0x8, // Edit and Continue is enabled for this module + + ReflectionEmit = 0x40, // Reflection.Emit was used to create this module + ProfilerDisableOptimizations = 0x80, + + DebuggerUserOverridePriv = 0x400, + DebuggerAllowJitOptsPriv = 0x800, + DebuggerTrackJitInfoPriv = 0x1000 } [Flags] @@ -60,6 +66,7 @@ string GetAppDomainFriendlyName(); TargetPointer GetModule(ModuleHandle handle); TargetPointer GetAssembly(ModuleHandle handle); TargetPointer GetPEAssembly(ModuleHandle handle); +bool GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags); TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva); bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size); @@ -95,6 +102,8 @@ TargetPointer GetObjectHandle(TargetPointer loaderAllocatorPointer); | `Module` | `Base` | Pointer to start of PE file in memory | | `Module` | `Flags` | Assembly of the Module | | `Module` | `LoaderAllocator` | LoaderAllocator of the Module | +| `Module` | `ReadyToRunInfo` | Pointer to ready to run info | +| `Module` | `ReadyToRunImage` | Pointer to PE image layout structure | | `Module` | `Path` | Path of the Module (UTF-16, null-terminated) | | `Module` | `FileName` | File name of the Module (UTF-16, null-terminated) | | `Module` | `GrowableSymbolStream` | Pointer to the in memory symbol stream | @@ -335,6 +344,20 @@ TargetPointer GetPEAssembly(ModuleHandle handle) return target.ReadPointer(handle.Address + /* Module::PEAssembly offset */); } +bool GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) +{ + r2rImageBase = TargetPointer.Null; + r2rImageEnd = TargetPointer.Null; + TargetPointer readyToRunInfo = target.ReadPointer(handle.Address + /* Module::ReadyToRunInfo offset */); + if (readyToRunInfo == TargetPointer.Null) + return false; + + TargetPointer pEImageLayout = target.ReadPointer(handle.Address + /*Module::ReadyToRunImage offset */); + uint r2rImageBase = target.Read(pEImageLayout + /* pEImageLayout::Base offset */); + uint r2rImageEnd = r2rImageBase + target.Read(pEImageLayout + /*PEImageLayout::Size offset */); + return true; +} + bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags) { baseAddress = TargetPointer.Null; diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 013d6a76efd650..227e7e5024e5d4 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -161,6 +161,12 @@ partial interface IRuntimeTypeSystem : IContract // Return true if a MethodDesc supports mulitiple code versions public virtual bool IsVersionable(MethodDescHandle methodDesc); + // Returns true if the MethodDesc is eligible for tiered compilation + public virtual bool IsEligibleForTieredCompilation(MethodDescHandle methodDesc); + + // Returns true if JIT optimization has been disabled for this MethodDesc + bool IsJitOptimizationDisabled(MethodDescHandle methodDesc); + // Return a pointer to the IL versioning state of the MethodDesc public virtual TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc); @@ -794,7 +800,8 @@ The version 1 `MethodDesc` APIs depend on the following globals: | `MethodDescAlignment` | `MethodDescChunk` trailing data is allocated in multiples of this constant. The size (in bytes) of each `MethodDesc` (or subclass) instance is a multiple of this constant. | | `MethodDescTokenRemainderBitCount` | Number of bits in the token remainder in `MethodDesc` | | `MethodDescSizeTable` | A pointer to the MethodDesc size table. The MethodDesc flags are used as an offset into this table to lookup the MethodDesc size. | - +| `CORDebuggerControlFlags` | A pointer to debugger control flags, that the debugger can set to control optimizations, etc. | +| `EEConfig` | A pointer to the global EEConfig that contains global settings, etc. | In the runtime a `MethodDesc` implicitly belongs to a single `MethodDescChunk` and some common data is shared between method descriptors that belong to the same chunk. A single method table will typically have multiple chunks. There are subkinds of MethodDescs at runtime of varying sizes (but the sizes must be mutliples of `MethodDescAlignment`) and each chunk contains method descriptors of the same size. @@ -802,6 +809,9 @@ will typically have multiple chunks. There are subkinds of MethodDescs at runti We depend on the following data descriptors: | Data Descriptor Name | Field | Meaning | | --- | --- | --- | +jitMinOpts +| `EEConfig` | `JitMinOpts` | Flag for minimal JIT optimization | +| `EEConfig` | `Debuggable` | Flag for debuggable code generation | | `MethodDesc` | `ChunkIndex` | Offset of this `MethodDesc` relative to the end of its containing `MethodDescChunk` - in multiples of `MethodDescAlignment` | | `MethodDesc` | `Slot` | The method's slot | | `MethodDesc` | `Flags` | The method's flags | @@ -1238,6 +1248,42 @@ Determining if a method supports multiple code versions: } ``` +Determining if a method has JIT optimizations disabled: +```csharp +private bool ModuleJitOptsDisabled(MethodDesc md) +{ + TypeHandle mt = GetTypeHandle(md.MethodTable); + TargetPointer modulePtr = GetModule(mt); + ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(modulePtr); + ModuleFlags flags = _target.Contracts.Loader.GetFlags(moduleHandle); + + TargetPointer corDebuggerControlFlagsPtr = _target.ReadGlobalPointer("CORDebuggerControlFlags"); + uint corDebuggerControlFlags = _target.Read(corDebuggerControlFlagsPtr); + + bool allowJitOpts = // complex condition checking on the flags to see if JIT opts have been disabled module-wide by the debugger + if (!allowJitOpts) + return true; + // have the jit opts been disabled by the profiler? + return (flags & ModuleFlags.ProfilerDisableOptimizations) != 0; +} +private bool IsJitOptimizationDisabledForAllMethodsInChunk(MethodDesc md) +{ + TargetPointer eeConfigPtr = _target.ReadGlobalPointer("EEConfig"); + bool jitMinOpts = // read from EEConfig + bool debuggable = // read from EEConfig + return jitMinOpts || debuggable || ModuleJitOptsDisabled(md); +} + +bool IRuntimeTypeSystem.IsJitOptimizationDisabled(MethodDescHandle methodDesc) +{ + MethodDesc md = _methodDescs[methodDesc.Address]; + // we have cached the boolean isJitOptimizationDisabledForSpecificMethod on each method desc + // if there is no metadata then optimization cannot have been disabled + // we then read the metadata, if the NoOptimization attribute is set then JIT optimization has been disabled + return isJitOptimizationDisabledForSpecificMethod || IsJitOptimizationDisabledForAllMethodsInChunk(md); +} +``` + Extracting a pointer to the `MethodDescVersioningState` data for a given method ```csharp diff --git a/src/coreclr/vm/callcounting.h b/src/coreclr/vm/callcounting.h index f56553da6156b5..afa92705043325 100644 --- a/src/coreclr/vm/callcounting.h +++ b/src/coreclr/vm/callcounting.h @@ -4,6 +4,7 @@ #pragma once #include "codeversion.h" +#include "cdacdata.h" #ifdef FEATURE_TIERED_COMPILATION @@ -248,10 +249,12 @@ class CallCountingManager static BOOL Equals(const key_t &k1, const key_t &k2); static count_t Hash(const key_t &k); }; - friend struct ::cdac_data; + friend struct ::cdac_data; + friend struct ::cdac_data>; }; typedef SHash CallCountingInfoByCodeVersionHash; + friend struct ::cdac_data>; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CallCountingManager::CallCountingStubAllocator @@ -390,20 +393,25 @@ class CallCountingManager static void DacEnumerateCallCountingStubHeapRanges(CLRDataEnumMemoryFlags flags); #endif friend struct ::cdac_data; + DISABLE_COPY(CallCountingManager); }; template<> -struct cdac_data +struct cdac_data> { - static constexpr size_t CallCountingHash = offsetof(CallCountingManager, m_callCountingInfoByCodeVersionHash); + static constexpr size_t Table = offsetof(SHash, m_table); + static constexpr size_t TableSize = offsetof(SHash, m_tableSize); }; template<> -struct cdac_data +struct cdac_data { + static constexpr size_t CallCountingHash = offsetof(CallCountingManager, m_callCountingInfoByCodeVersionHash); static constexpr size_t CodeVersion = offsetof(CallCountingManager::CallCountingInfo, m_codeVersion); static constexpr size_t Stage = offsetof(CallCountingManager::CallCountingInfo, m_stage); + static constexpr size_t Table = cdac_data>::Table; + static constexpr size_t TableSize = cdac_data>::TableSize; }; //////////////////////////////////////////////////////////////// // CallCountingStub definitions diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index bb0f2037816852..227f1d8b9b08e6 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -436,9 +436,11 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) #ifdef FEATURE_READYTORUN m_pNativeImage = NULL; + m_pReadyToRunImage = NULL; if ((m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker)) != NULL) { m_pNativeImage = m_pReadyToRunInfo->GetNativeImage(); + m_pReadyToRunImage = m_pReadyToRunInfo->GetImage(); if (m_pNativeImage != NULL) { m_NativeMetadataAssemblyRefMap = m_pNativeImage->GetManifestMetadataAssemblyRefMap(); @@ -2052,7 +2054,7 @@ PEImageLayout * Module::GetReadyToRunImage() #ifdef FEATURE_READYTORUN if (IsReadyToRun()) - return GetReadyToRunInfo()->GetImage(); + return m_pReadyToRunImage; #endif return NULL; diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index c4d02b6e02dbb6..23e8546f817691 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -831,6 +831,7 @@ class Module : public ModuleBase #ifdef FEATURE_READYTORUN private: PTR_ReadyToRunInfo m_pReadyToRunInfo; + PTR_PEImageLayout m_pReadyToRunImage; // cached on the module for easy access PTR_NativeImage m_pNativeImage; #endif @@ -1705,6 +1706,7 @@ struct cdac_data static constexpr size_t Path = offsetof(Module, m_path); static constexpr size_t FileName = offsetof(Module, m_fileName); static constexpr size_t ReadyToRunInfo = offsetof(Module, m_pReadyToRunInfo); + static constexpr size_t ReadyToRunImage = offsetof(Module, m_pReadyToRunImage); static constexpr size_t GrowableSymbolStream = offsetof(Module, m_pIStreamSym); // Lookup map pointers diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 2a0590bfee856d..18bd649118b671 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -147,13 +147,9 @@ template<> struct cdac_data { static constexpr size_t StorageKind = offsetof(NativeCodeVersion, m_storageKind); - static constexpr size_t VersionNode = offsetof(NativeCodeVersion, m_pVersionNode); + static constexpr size_t MethodDescOrNode = offsetof(NativeCodeVersion, m_pVersionNode); }; -#endif // FEATURE_CODE_VERSIONING - -#ifdef FEATURE_CODE_VERSIONING - enum class RejitFlags : uint32_t { // The profiler has requested a ReJit, so we've allocated stuff, but we haven't diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 145e2abb574972..c1d610023b40bc 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -166,6 +166,7 @@ CDAC_TYPE_FIELD(Module, /*pointer*/, DynamicMetadata, cdac_data::Dynamic CDAC_TYPE_FIELD(Module, /*pointer*/, Path, cdac_data::Path) CDAC_TYPE_FIELD(Module, /*pointer*/, FileName, cdac_data::FileName) CDAC_TYPE_FIELD(Module, /*pointer*/, ReadyToRunInfo, cdac_data::ReadyToRunInfo) +CDAC_TYPE_FIELD(Module, /*pointer*/, ReadyToRunImage, cdac_data::ReadyToRunImage) CDAC_TYPE_FIELD(Module, /*pointer*/, GrowableSymbolStream, cdac_data::GrowableSymbolStream) CDAC_TYPE_FIELD(Module, /*pointer*/, AvailableTypeParams, offsetof(Module, m_pAvailableParamTypes)) CDAC_TYPE_FIELD(Module, /*pointer*/, InstMethodHashTable, offsetof(Module, m_pInstMethodHashTable)) @@ -218,8 +219,10 @@ CDAC_TYPE_END(CallCountingManager) // and the entry is a pointer to this data structure CDAC_TYPE_BEGIN(CallCountingInfo) CDAC_TYPE_SIZE(sizeof(uintptr_t)) -CDAC_TYPE_FIELD(CallCountingInfo, /*pointer*/, CodeVersion, cdac_data::CodeVersion) -CDAC_TYPE_FIELD(CallCountingInfo, /*int32*/, Stage, cdac_data::Stage) +CDAC_TYPE_FIELD(CallCountingInfo, /*pointer*/, CodeVersion, cdac_data::CodeVersion) +CDAC_TYPE_FIELD(CallCountingInfo, /*int8*/, Stage, cdac_data::Stage) +CDAC_TYPE_FIELD(CallCountingInfo, /*pointer*/, Table, cdac_data::Table) +CDAC_TYPE_FIELD(CallCountingInfo, /*int32*/, TableSize, cdac_data::TableSize) CDAC_TYPE_END(CallCountingInfo) CDAC_TYPE_BEGIN(PEAssembly) @@ -706,8 +709,8 @@ CDAC_TYPE_END(NativeCodeVersionNode) CDAC_TYPE_BEGIN(NativeCodeVersion) CDAC_TYPE_INDETERMINATE(NativeCodeVersion) -CDAC_TYPE_FIELD(NativeCodeVersion, /*uint8*/, StorageKind, cdac_data::StorageKind) -CDAC_TYPE_FIELD(NativeCodeVersion, /*pointer*/, VersionNode, cdac_data::VersionNode) +CDAC_TYPE_FIELD(NativeCodeVersion, /*uint32*/, StorageKind, cdac_data::StorageKind) +CDAC_TYPE_FIELD(NativeCodeVersion, /*pointer*/, MethodDescOrNode, cdac_data::MethodDescOrNode) CDAC_TYPE_END(NativeCodeVersion) CDAC_TYPE_BEGIN(ILCodeVersionNode) diff --git a/src/coreclr/vm/readytoruninfo.h b/src/coreclr/vm/readytoruninfo.h index 63e92e4e2ec107..5b7d071c171eb9 100644 --- a/src/coreclr/vm/readytoruninfo.h +++ b/src/coreclr/vm/readytoruninfo.h @@ -347,7 +347,6 @@ struct cdac_data { static constexpr size_t ReadyToRunHeader = offsetof(ReadyToRunInfo, m_pHeader); static constexpr size_t CompositeInfo = offsetof(ReadyToRunInfo, m_pCompositeInfo); - static constexpr size_t Composite = offsetof(ReadyToRunInfo, m_pComposite); static constexpr size_t NumRuntimeFunctions = offsetof(ReadyToRunInfo, m_nRuntimeFunctions); static constexpr size_t RuntimeFunctions = offsetof(ReadyToRunInfo, m_pRuntimeFunctions); static constexpr size_t NumHotColdMap = offsetof(ReadyToRunInfo, m_nHotColdMap); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs index a62e33edd6372e..3b4d0fd5b3d966 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs @@ -6,10 +6,23 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; +public enum OptimizationTierEnum +{ + Unknown = 0, + MinOptJitted = 1, + Optimized = 2, + QuickJitted = 3, + OptimizedTier1 = 4, + ReadyToRun = 5, + OptimizedTier1OSR = 6, + QuickJittedInstrumented = 7, + OptimizedTier1Instrumented = 8, +} + public interface ICodeVersions : IContract { static string IContract.Name { get; } = nameof(CodeVersions); - public virtual IEnumerable<(TargetPointer, TargetPointer, int)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) => throw new NotImplementedException(); + public virtual IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) => throw new NotImplementedException(); public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index 3fcb15712ac6ea..99fa658d517e02 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -177,6 +177,7 @@ public interface IRuntimeTypeSystem : IContract bool IsCollectibleMethod(MethodDescHandle methodDesc) => throw new NotImplementedException(); bool IsVersionable(MethodDescHandle methodDesc) => throw new NotImplementedException(); + bool IsEligibleForTieredCompilation(MethodDescHandle methodDesc) => throw new NotImplementedException(); bool IsJitOptimizationDisabled(MethodDescHandle methodDesc) => throw new NotImplementedException(); TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index b7abc5fe464163..35b011962bd005 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -43,7 +43,6 @@ public enum DataType LoaderAllocator, CallCountingManager, CallCountingInfo, - CallCountingTable, NativeCodeVersion, PEAssembly, AssemblyBinder, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index 8f6525edb81409..7c14dcfe8b0dd5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Runtime.InteropServices; using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -19,49 +18,30 @@ public CodeVersions_1(Target target) _target = target; } - internal struct DacpTieredVersionData - { - public enum OptimizationTierEnum - { - OptimizationTier_Unknown, - OptimizationTier_MinOptJitted, - OptimizationTier_Optimized, - OptimizationTier_QuickJitted, - OptimizationTier_OptimizedTier1, - OptimizationTier_ReadyToRun, - OptimizationTier_OptimizedTier1OSR, - OptimizationTier_QuickJittedInstrumented, - OptimizationTier_OptimizedTier1Instrumented, - }; - public TargetPointer NativeCodeAddr; - public OptimizationTierEnum OptimizationTier; - public TargetPointer NativeCodeVersionNodePtr; - }; - - internal enum NativeOptimizationTier : uint + private enum NativeOptimizationTier : uint { OptimizationTier0 = 0, OptimizationTier1 = 1, OptimizationTier1OSR = 2, - OptimizationTierOptimized = 3, // may do less optimizations than tier 1 + OptimizationTierOptimized = 3, OptimizationTier0Instrumented = 4, OptimizationTier1Instrumented = 5, }; - internal enum Stage : byte + private enum Stage : byte { - StubIsNotActive, - StubMayBeActive, - PendingCompletion, - Complete, - Disabled + StubIsNotActive = 0, + StubMayBeActive = 1, + PendingCompletion = 2, + Complete = 3, + Disabled = 4 }; - internal enum StorageKind + private enum StorageKind { - Unknown, - Explicit, - Synthetic + Unknown = 0, + Explicit = 1, + Synthetic = 2 }; @@ -81,9 +61,9 @@ public uint Hash(NativeCodeVersion key) { switch ((StorageKind)key.StorageKind) { - case StorageKind.Synthetic: // SK_Synthetic + case StorageKind.Synthetic: return (uint)key.MethodDescOrNode; - case StorageKind.Explicit: // SK_Explicit + case StorageKind.Explicit: NativeCodeVersionNode node = _target.ProcessedData.GetOrAdd(key.MethodDescOrNode); return (uint)node.MethodDesc + node.NativeId; default: @@ -110,14 +90,16 @@ public CallCountingTable(Target target, TargetPointer address) } private bool IsCallCountingEnabled(MethodDescHandle mdh) { + // get loader allocator Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; Contracts.ILoader loaderContract = _target.Contracts.Loader; TargetPointer mt = rtsContract.GetMethodTable(mdh); TargetPointer modulePtr = rtsContract.GetLoaderModule(rtsContract.GetTypeHandle(mt)); Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(modulePtr); TargetPointer loaderAllocator = loaderContract.GetLoaderAllocator(moduleHandle); - Data.LoaderAllocator loaderAllocatorData = _target.ProcessedData.GetOrAdd(loaderAllocator); + + // get call counting manager and hash TargetPointer callCountingMgr = loaderAllocatorData.CallCountingManager; TargetPointer callCountingHash = _target.ProcessedData.GetOrAdd(callCountingMgr).CallCountingHash; CallCountingTable callCountingTable = _target.ProcessedData.GetOrAdd(callCountingHash); @@ -126,42 +108,40 @@ private bool IsCallCountingEnabled(MethodDescHandle mdh) CallCountingInfo entry = shashContract.LookupSHash(callCountingTable.HashTable, new NativeCodeVersion((uint)StorageKind.Synthetic, mdh.Address)); return entry.Address != TargetPointer.Null && entry.Stage != (byte)Stage.Disabled; } - private NativeOptimizationTier GetInitialOptimizationTier(bool isEligibleForTieredCompilation, bool isReadyToRun, MethodDescHandle mdh) + private NativeOptimizationTier GetInitialOptimizationTier(bool isReadyToRun, MethodDescHandle mdh) { if (_target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) == 0 - || !isEligibleForTieredCompilation || !IsCallCountingEnabled(mdh)) - return NativeOptimizationTier.OptimizationTierOptimized; + return NativeOptimizationTier.TierOptimized; else { Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); if (eeConfig.TieredPGO_InstrumentOnlyHotCode || isReadyToRun) - return NativeOptimizationTier.OptimizationTier0; + return NativeOptimizationTier.Tier0; else - return NativeOptimizationTier.OptimizationTier0Instrumented; + return NativeOptimizationTier.Tier0Instrumented; } } - private static DacpTieredVersionData.OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) + private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) { return nativeOptimizationTier switch { - NativeOptimizationTier.OptimizationTier0 => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJitted, - NativeOptimizationTier.OptimizationTier1 => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1, - NativeOptimizationTier.OptimizationTier1OSR => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1OSR, - NativeOptimizationTier.OptimizationTierOptimized => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized, - NativeOptimizationTier.OptimizationTier0Instrumented => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_QuickJittedInstrumented, - NativeOptimizationTier.OptimizationTier1Instrumented => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_OptimizedTier1Instrumented, - _ => DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Unknown, + NativeOptimizationTier.Tier0 => OptimizationTierEnum.QuickJitted, + NativeOptimizationTier.Tier1 => OptimizationTierEnum.OptimizedTier1, + NativeOptimizationTier.Tier1OSR => OptimizationTierEnum.OptimizedTier1OSR, + NativeOptimizationTier.TierOptimized => OptimizationTierEnum.Optimized, + NativeOptimizationTier.Tier0Instrumented => OptimizationTierEnum.QuickJittedInstrumented, + NativeOptimizationTier.Tier1Instrumented => OptimizationTierEnum.OptimizedTier1Instrumented, + _ => OptimizationTierEnum.Unknown, }; } - IEnumerable<(TargetPointer, TargetPointer, int)> ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) + IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) { Contracts.ICodeVersions codeVersionsContract = this; Contracts.IReJIT rejitContract = _target.Contracts.ReJIT; - // r2r stuff todo ILCodeVersionHandle ilCodeVersion = codeVersionsContract.GetILCodeVersions(methodDesc) .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode).Value == (ulong)rejitId, ILCodeVersionHandle.Invalid); @@ -185,31 +165,31 @@ private static DacpTieredVersionData.OptimizationTierEnum GetOptimizationTier(Na TargetPointer nativeCode = codeVersionsContract.GetNativeCode(nativeCodeVersionHandle).AsTargetPointer; TargetPointer nativeCodeAddr = nativeCode; TargetPointer nativeCodeVersionNodePtr = nativeCodeVersionHandle.IsExplicit ? AsNode(nativeCodeVersionHandle).Address : TargetPointer.Null; - int optimizationTier; + OptimizationTierEnum optimizationTier; if (r2rImageBase <= nativeCode && nativeCode < r2rImageEnd) { - optimizationTier = (int)DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_ReadyToRun; + optimizationTier = OptimizationTierEnum.ReadyToRun; } else if (isEligibleForTieredCompilation) { NativeOptimizationTier optTier; if (!nativeCodeVersionHandle.IsExplicit) - optTier = GetInitialOptimizationTier(isEligibleForTieredCompilation, isReadyToRun, mdh); + optTier = GetInitialOptimizationTier(isReadyToRun, mdh); else { NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier; } - optimizationTier = (int)GetOptimizationTier(optTier); + optimizationTier = GetOptimizationTier(optTier); } else if (rts.IsJitOptimizationDisabled(mdh)) { - optimizationTier = (int)DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_MinOptJitted; + optimizationTier = OptimizationTierEnum.MinOptJitted; } else { - optimizationTier = (int)DacpTieredVersionData.OptimizationTierEnum.OptimizationTier_Optimized; + optimizationTier = OptimizationTierEnum.Optimized; } count++; yield return (nativeCodeAddr, nativeCodeVersionNodePtr, optimizationTier); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index 886169e4ff59f8..549a8f851641d4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -181,8 +181,9 @@ bool ILoader.GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBa if (module.ReadyToRunInfo == TargetPointer.Null) return false; - Data.ReadyToRunInfo readyToRunInfo = _target.ProcessedData.GetOrAdd(module.ReadyToRunInfo); - // r2rImageBase = readyToRunInfo. tbd + Data.PEImageLayout pEImageLayout = _target.ProcessedData.GetOrAdd(module.ReadyToRunImage); + r2rImageBase = pEImageLayout.Base; + r2rImageEnd = pEImageLayout.Base + pEImageLayout.Size; return true; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 880092b46c8dd1..f9a4a1195a1bc8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -1062,13 +1062,12 @@ private bool ModuleJitOptsDisabled(MethodDesc md) TargetPointer corDebuggerControlFlagsPtr = _target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags); uint corDebuggerControlFlags = _target.Read(corDebuggerControlFlagsPtr); // debugger - if ((flags & ModuleFlags.DebuggerAllowJitOptsPriv) != 0 || - (((corDebuggerControlFlags & (uint)DebuggerControlFlags.AllowJitOpt) != 0) && (flags & ModuleFlags.DebuggerUserOverridePriv) == 0)) + bool allowJitOpts = (flags & ModuleFlags.DebuggerAllowJitOptsPriv) != 0 || + (((corDebuggerControlFlags & (uint)DebuggerControlFlags.AllowJitOpt) != 0) && (flags & ModuleFlags.DebuggerUserOverridePriv) == 0); + if (!allowJitOpts) return true; // profiler - if ((flags & ModuleFlags.ProfilerDisableOptimizations) != 0) - return true; - return false; + return (flags & ModuleFlags.ProfilerDisableOptimizations) != 0; } private bool IsJitOptimizationDisabledForAllMethodsInChunk(MethodDesc md) { @@ -1080,7 +1079,7 @@ private bool IsJitOptimizationDisabledForAllMethodsInChunk(MethodDesc md) bool IRuntimeTypeSystem.IsJitOptimizationDisabled(MethodDescHandle methodDesc) { MethodDesc md = _methodDescs[methodDesc.Address]; - return md.IsJitOptimizationDisabledForSpecificMethod && IsJitOptimizationDisabledForAllMethodsInChunk(md); + return md.IsJitOptimizationDisabledForSpecificMethod || IsJitOptimizationDisabledForAllMethodsInChunk(md); } TargetPointer IRuntimeTypeSystem.GetMethodDescVersioningState(MethodDescHandle methodDesc) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureTypeProvider.cs deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Module.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Module.cs index 7fc833df437e84..c187e2aaac57ba 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Module.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Module.cs @@ -23,6 +23,7 @@ public Module(Target target, TargetPointer address) Path = target.ReadPointer(address + (ulong)type.Fields[nameof(Path)].Offset); FileName = target.ReadPointer(address + (ulong)type.Fields[nameof(FileName)].Offset); ReadyToRunInfo = target.ReadPointer(address + (ulong)type.Fields[nameof(ReadyToRunInfo)].Offset); + ReadyToRunImage = target.ReadPointer(address + (ulong)type.Fields[nameof(ReadyToRunImage)].Offset); GrowableSymbolStream = target.ReadPointer(address + (ulong)type.Fields[nameof(GrowableSymbolStream)].Offset); AvailableTypeParams = target.ReadPointer(address + (ulong)type.Fields[nameof(AvailableTypeParams)].Offset); InstMethodHashTable = target.ReadPointer(address + (ulong)type.Fields[nameof(InstMethodHashTable)].Offset); @@ -46,6 +47,7 @@ public Module(Target target, TargetPointer address) public TargetPointer Path { get; init; } public TargetPointer FileName { get; init; } public TargetPointer ReadyToRunInfo { get; init; } + public TargetPointer ReadyToRunImage { get; init; } public TargetPointer GrowableSymbolStream { get; init; } public TargetPointer AvailableTypeParams { get; init; } public TargetPointer InstMethodHashTable { get; init; } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index 730ab08e1821dc..290547d1ff9e90 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -231,20 +231,20 @@ public enum Flags : uint public ClrDataAddress NativeCodeAddr; }; +public enum OptimizationTierEnum +{ + Unknown = 0, + MinOptJitted = 1, + Optimized = 2, + QuickJitted = 3, + OptimizedTier1 = 4, + ReadyToRun = 5, + OptimizedTier1OSR = 6, + QuickJittedInstrumented = 7, + OptimizedTier1Instrumented = 8, +} internal struct DacpTieredVersionData { - public enum OptimizationTierEnum - { - OptimizationTier_Unknown, - OptimizationTier_MinOptJitted, - OptimizationTier_Optimized, - OptimizationTier_QuickJitted, - OptimizationTier_OptimizedTier1, - OptimizationTier_ReadyToRun, - OptimizationTier_OptimizedTier1OSR, - OptimizationTier_QuickJittedInstrumented, - OptimizationTier_OptimizedTier1Instrumented, - }; public ClrDataAddress NativeCodeAddr; public OptimizationTierEnum OptimizationTier; public ClrDataAddress NativeCodeVersionNodePtr; diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index 8b09d4b77278b8..d5168d82f5777a 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -3107,12 +3107,12 @@ int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, TargetPointer methodDescPtr = methodDesc.ToTargetPointer(_target); int count = 0; - foreach ((TargetPointer nativeCode, TargetPointer nativeCodeVersionNodePtr, int optTier) in _target.Contracts.CodeVersions.GetTieredVersions(methodDescPtr, rejitId, cNativeCodeAddrs)) + foreach ((TargetPointer nativeCode, TargetPointer nativeCodeVersionNodePtr, Contracts.OptimizationTierEnum optTier) in _target.Contracts.CodeVersions.GetTieredVersions(methodDescPtr, rejitId, cNativeCodeAddrs)) { - nativeCodeAddrs[count++] = default; + nativeCodeAddrs[count] = default; nativeCodeAddrs[count].NativeCodeAddr = nativeCode.ToClrDataAddress(_target); nativeCodeAddrs[count].NativeCodeVersionNodePtr = nativeCodeVersionNodePtr.ToClrDataAddress(_target); - nativeCodeAddrs[count].OptimizationTier = (DacpTieredVersionData.OptimizationTierEnum)optTier; + nativeCodeAddrs[count++].OptimizationTier = (OptimizationTierEnum)optTier; } *pcNativeCodeAddrs = count; if (count >= cNativeCodeAddrs) From f67f1f0ec07c806bb6e427d03df77d0ad55d846b Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 18 Sep 2025 23:16:05 -0700 Subject: [PATCH 07/13] fix --- .../Legacy/ISOSDacInterface.cs | 24 +++++++++---------- .../Legacy/SOSDacImpl.cs | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs index 290547d1ff9e90..609b7cbc69ace1 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/ISOSDacInterface.cs @@ -231,20 +231,20 @@ public enum Flags : uint public ClrDataAddress NativeCodeAddr; }; -public enum OptimizationTierEnum -{ - Unknown = 0, - MinOptJitted = 1, - Optimized = 2, - QuickJitted = 3, - OptimizedTier1 = 4, - ReadyToRun = 5, - OptimizedTier1OSR = 6, - QuickJittedInstrumented = 7, - OptimizedTier1Instrumented = 8, -} internal struct DacpTieredVersionData { + public enum OptimizationTierEnum + { + Unknown = 0, + MinOptJitted = 1, + Optimized = 2, + QuickJitted = 3, + OptimizedTier1 = 4, + ReadyToRun = 5, + OptimizedTier1OSR = 6, + QuickJittedInstrumented = 7, + OptimizedTier1Instrumented = 8, + } public ClrDataAddress NativeCodeAddr; public OptimizationTierEnum OptimizationTier; public ClrDataAddress NativeCodeVersionNodePtr; diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index d5168d82f5777a..b3f8e0102efee8 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -3112,7 +3112,7 @@ int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, nativeCodeAddrs[count] = default; nativeCodeAddrs[count].NativeCodeAddr = nativeCode.ToClrDataAddress(_target); nativeCodeAddrs[count].NativeCodeVersionNodePtr = nativeCodeVersionNodePtr.ToClrDataAddress(_target); - nativeCodeAddrs[count++].OptimizationTier = (OptimizationTierEnum)optTier; + nativeCodeAddrs[count++].OptimizationTier = (DacpTieredVersionData.OptimizationTierEnum)optTier; } *pcNativeCodeAddrs = count; if (count >= cNativeCodeAddrs) From 312179c5b7e83b89f154008964a12d2fc2918afd Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 18 Sep 2025 23:37:38 -0700 Subject: [PATCH 08/13] fix --- docs/design/datacontracts/CodeVersions.md | 7 +++++-- .../Contracts/CodeVersions_1.cs | 20 ++++++++++--------- .../Data/EEConfig.cs | 10 ++++++---- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 91f1ea7a78f58f..7c6d9587a549cc 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -439,15 +439,18 @@ private NativeOptimizationTier GetInitialOptimizationTier(bool isReadyToRun, Met if (target.ReadGlobal("FeatureTieredCompilation") == 0 || !IsCallCountingEnabled(mdh)) return NativeOptimizationTier.TierOptimized; - else + + TargetPointer eeConfig = // read EEConfig global variable + if (/* eeConfig is TieredPGO enabled */) { - TargetPointer eeConfig = // read EEConfig global variable bool tieredPGO_InstrumentOnlyHotCode = // read from EEConfig if (tieredPGO_InstrumentOnlyHotCode || isReadyToRun) return NativeOptimizationTier.Tier0; else return NativeOptimizationTier.Tier0Instrumented; } + else + return NativeOptimizationTier.Tier0; } IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index 7c14dcfe8b0dd5..e3f5c888c4eba5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -20,12 +20,12 @@ public CodeVersions_1(Target target) private enum NativeOptimizationTier : uint { - OptimizationTier0 = 0, - OptimizationTier1 = 1, - OptimizationTier1OSR = 2, - OptimizationTierOptimized = 3, - OptimizationTier0Instrumented = 4, - OptimizationTier1Instrumented = 5, + Tier0 = 0, + Tier1 = 1, + Tier1OSR = 2, + TierOptimized = 3, + Tier0Instrumented = 4, + Tier1Instrumented = 5, }; private enum Stage : byte @@ -113,14 +113,16 @@ private NativeOptimizationTier GetInitialOptimizationTier(bool isReadyToRun, Met if (_target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) == 0 || !IsCallCountingEnabled(mdh)) return NativeOptimizationTier.TierOptimized; - else + Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); + if (eeConfig.TieredPGO!.Value) { - Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); - if (eeConfig.TieredPGO_InstrumentOnlyHotCode || isReadyToRun) + if (eeConfig.TieredPGO_InstrumentOnlyHotCode!.Value || isReadyToRun) return NativeOptimizationTier.Tier0; else return NativeOptimizationTier.Tier0Instrumented; } + else + return NativeOptimizationTier.Tier0; } private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs index cb6141878e8a50..9d60ae27b51413 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs @@ -12,12 +12,14 @@ public EEConfig(Target target, TargetPointer address) JitMinOpts = target.Read(address + (ulong)type.Fields[nameof(JitMinOpts)].Offset) != 0; Debuggable = target.Read(address + (ulong)type.Fields[nameof(Debuggable)].Offset) != 0; - TieredPGO = target.Read(address + (ulong)type.Fields[nameof(TieredPGO)].Offset) != 0; - TieredPGO_InstrumentOnlyHotCode = target.Read(address + (ulong)type.Fields[nameof(TieredPGO_InstrumentOnlyHotCode)].Offset) != 0; + if (type.Fields.ContainsKey(nameof(TieredPGO))) + TieredPGO = target.Read(address + (ulong)type.Fields[nameof(TieredPGO)].Offset) != 0; + if (type.Fields.ContainsKey(nameof(TieredPGO_InstrumentOnlyHotCode))) + TieredPGO_InstrumentOnlyHotCode = target.Read(address + (ulong)type.Fields[nameof(TieredPGO_InstrumentOnlyHotCode)].Offset) != 0; } public bool JitMinOpts { get; init; } public bool Debuggable { get; init; } - public bool TieredPGO { get; init; } - public bool TieredPGO_InstrumentOnlyHotCode { get; init; } + public bool? TieredPGO { get; init; } + public bool? TieredPGO_InstrumentOnlyHotCode { get; init; } } From 0b59ecfb93ca8b73feecd72805075c3db581853f Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 19 Sep 2025 09:04:35 -0700 Subject: [PATCH 09/13] ifdef --- docs/design/datacontracts/RuntimeTypeSystem.md | 2 +- src/coreclr/vm/codeversion.h | 2 ++ src/coreclr/vm/datadescriptor/datadescriptor.inc | 4 ++++ src/coreclr/vm/loaderallocator.hpp | 2 ++ .../Contracts/CodeVersions_1.cs | 4 ++-- .../Contracts/RuntimeTypeSystem_1.cs | 2 +- .../Data/LoaderAllocator.cs | 7 +++++-- .../Data/NativeCodeVersionNode.cs | 7 +++++-- 8 files changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 227e7e5024e5d4..bbaa5d4102dc49 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -964,7 +964,7 @@ internal struct MethodDesc } } - public bool IsEligibleForTieredCompilation => HasFlags(MethodDescFlags3.IsEligibleForTieredCompilation); + public bool IsEligibleForTieredCompilation => HasFlags(MethodDescFlags3.IsEligibleForTieredCompilation) && && _target.ReadGlobal("FeatureTieredCompilation") != 0; // non-vtable slot, native code slot and MethodImpl slots are stored after the MethodDesc itself, packed tightly // in the order: [non-vtable; methhod impl; native code]. diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 18bd649118b671..07b17c2edbc1ff 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -335,7 +335,9 @@ struct cdac_data static constexpr size_t NativeCode = offsetof(NativeCodeVersionNode, m_pNativeCode); static constexpr size_t Flags = offsetof(NativeCodeVersionNode, m_flags); static constexpr size_t ILVersionId = offsetof(NativeCodeVersionNode, m_parentId); +#ifdef FEATURE_TIERED_COMPILATION static constexpr size_t OptimizationTier = offsetof(NativeCodeVersionNode, m_optTier); +#endif // FEATURE_TIERED_COMPILATION static constexpr size_t NativeId = offsetof(NativeCodeVersionNode, m_id); #ifdef HAVE_GCCOVER static constexpr size_t GCCoverageInfo = offsetof(NativeCodeVersionNode, m_gcCover); diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index c1d610023b40bc..423cf161a98ff4 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -207,7 +207,9 @@ CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, HighFrequencyHeap, cdac_data::LowFrequencyHeap) CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, StubHeap, cdac_data::StubHeap) CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, ObjectHandle, cdac_data::ObjectHandle) +#ifdef FEATURE_TIERED_COMPILATION CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, CallCountingManager, cdac_data::CallCountingManager) +#endif // FEATURE_TIERED_COMPILATION CDAC_TYPE_END(LoaderAllocator) CDAC_TYPE_BEGIN(CallCountingManager) @@ -700,7 +702,9 @@ CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, MethodDesc, cdac_data::NativeCode) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, Flags, cdac_data::Flags) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*nuint*/, ILVersionId, cdac_data::ILVersionId) +#ifdef FEATURE_TIERED_COMPILATION CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, OptimizationTier, cdac_data::OptimizationTier) +#endif // FEATURE_TIERED_COMPILATION CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, NativeId, cdac_data::NativeId) #ifdef HAVE_GCCOVER CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, GCCoverageInfo, cdac_data::GCCoverageInfo) diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index b9aa9bfacb96fb..03a6ef681fb276 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -912,7 +912,9 @@ struct cdac_data static constexpr size_t LowFrequencyHeap = offsetof(LoaderAllocator, m_pLowFrequencyHeap); static constexpr size_t StubHeap = offsetof(LoaderAllocator, m_pStubHeap); static constexpr size_t ObjectHandle = offsetof(LoaderAllocator, m_hLoaderAllocatorObjectHandle); +#ifdef FEATURE_TIERED_COMPILATION static constexpr size_t CallCountingManager = offsetof(LoaderAllocator, m_callCountingManager); +#endif // FEATURE_TIERED_COMPILATION }; typedef VPTR(LoaderAllocator) PTR_LoaderAllocator; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index e3f5c888c4eba5..c49624617e4038 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -100,7 +100,7 @@ private bool IsCallCountingEnabled(MethodDescHandle mdh) Data.LoaderAllocator loaderAllocatorData = _target.ProcessedData.GetOrAdd(loaderAllocator); // get call counting manager and hash - TargetPointer callCountingMgr = loaderAllocatorData.CallCountingManager; + TargetPointer callCountingMgr = loaderAllocatorData.CallCountingManager!.Value; TargetPointer callCountingHash = _target.ProcessedData.GetOrAdd(callCountingMgr).CallCountingHash; CallCountingTable callCountingTable = _target.ProcessedData.GetOrAdd(callCountingHash); @@ -181,7 +181,7 @@ private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier n else { NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); - optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier; + optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier!.Value; } optimizationTier = GetOptimizationTier(optTier); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index f9a4a1195a1bc8..a51101a1eb90b1 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -173,7 +173,7 @@ private static bool ComputeIsJitOptimizationDisabledForSpecificMethod(Target tar private bool HasFlags(MethodDescFlags_1.MethodDescFlags3 flags) => (_desc.Flags3AndTokenRemainder & (ushort)flags) != 0; internal bool HasFlags(MethodDescChunkFlags flags) => (_chunk.FlagsAndTokenRange & (ushort)flags) != 0; - public bool IsEligibleForTieredCompilation => HasFlags(MethodDescFlags_1.MethodDescFlags3.IsEligibleForTieredCompilation); + public bool IsEligibleForTieredCompilation => HasFlags(MethodDescFlags_1.MethodDescFlags3.IsEligibleForTieredCompilation) && _target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) != 0; public bool IsUnboxingStub => HasFlags(MethodDescFlags_1.MethodDescFlags3.IsUnboxingStub); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs index 846070a5f1ab04..bd9102b78247a5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs @@ -18,7 +18,10 @@ public LoaderAllocator(Target target, TargetPointer address) StubHeap = target.ReadPointer(address + (ulong)type.Fields[nameof(StubHeap)].Offset); ObjectHandle = target.ProcessedData.GetOrAdd( target.ReadPointer(address + (ulong)type.Fields[nameof(ObjectHandle)].Offset)); - CallCountingManager = target.ReadPointer(address + (ulong)type.Fields[nameof(CallCountingManager)].Offset); + if (type.Fields.ContainsKey(nameof(CallCountingManager))) + { + CallCountingManager = target.ReadPointer(address + (ulong)type.Fields[nameof(CallCountingManager)].Offset); + } } public uint ReferenceCount { get; init; } @@ -26,7 +29,7 @@ public LoaderAllocator(Target target, TargetPointer address) public TargetPointer LowFrequencyHeap { get; init; } public TargetPointer StubHeap { get; init; } public ObjectHandle ObjectHandle { get; init; } - public TargetPointer CallCountingManager { get; init; } + public TargetPointer? CallCountingManager { get; init; } public bool IsAlive => ReferenceCount != 0; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs index eed5fc97d79d90..4774a9f2739c80 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs @@ -17,7 +17,10 @@ public NativeCodeVersionNode(Target target, TargetPointer address) NativeCode = target.ReadCodePointer(address + (ulong)type.Fields[nameof(NativeCode)].Offset); Flags = target.Read(address + (ulong)type.Fields[nameof(Flags)].Offset); ILVersionId = target.ReadNUInt(address + (ulong)type.Fields[nameof(ILVersionId)].Offset); - OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); + if (type.Fields.ContainsKey(nameof(OptimizationTier))) + { + OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); + } NativeId = target.Read(address + (ulong)type.Fields[nameof(NativeId)].Offset); if (type.Fields.ContainsKey(nameof(GCCoverageInfo))) { @@ -32,7 +35,7 @@ public NativeCodeVersionNode(Target target, TargetPointer address) public TargetCodePointer NativeCode { get; init; } public uint Flags { get; init; } public TargetNUInt ILVersionId { get; init; } - public uint OptimizationTier { get; init; } + public uint? OptimizationTier { get; init; } public uint NativeId { get; init; } public TargetPointer? GCCoverageInfo { get; init; } From 12c746bffcb4fd5d6bed833f998748a5c53a6d5a Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 19 Sep 2025 10:48:16 -0700 Subject: [PATCH 10/13] code review --- docs/design/datacontracts/CodeVersions.md | 2 +- docs/design/datacontracts/Loader.md | 4 +- .../design/datacontracts/RuntimeTypeSystem.md | 1 + src/coreclr/vm/ceeload.h | 2 +- .../Contracts/ICodeVersions.cs | 15 -- .../Contracts/ILoader.cs | 2 +- .../Contracts/IReJIT.cs | 14 ++ .../Contracts/CodeVersions_1.cs | 182 ----------------- .../Contracts/Loader_1.cs | 2 +- .../Contracts/ReJIT_1.cs | 186 ++++++++++++++++++ .../Legacy/SOSDacImpl.cs | 9 +- .../MockDescriptors.CodeVersions.cs | 4 +- .../tests/MockDescriptors/MockDescriptors.cs | 1 + 13 files changed, 217 insertions(+), 207 deletions(-) diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 7c6d9587a549cc..0437671a77bc02 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -469,7 +469,7 @@ IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersi Contracts.ILoader loader = target.Contracts.Loader; ModuleHandle moduleHandle = // get the module handle from the method desc using rts - bool isReadyToRun = loader.GetReadyToRunInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); + bool isReadyToRun = loader.GetReadyToRunImageInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); bool isEligibleForTieredCompilation = rts.IsEligibleForTieredCompilation(mdh); int count = 0; foreach (NativeCodeVersionHandle nativeCodeVersionHandle in ((ICodeVersions)this).GetNativeCodeVersions(methodDesc, ilCodeVersion)) diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index 3960da5ffaddc5..d11518f72951e7 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -66,7 +66,7 @@ string GetAppDomainFriendlyName(); TargetPointer GetModule(ModuleHandle handle); TargetPointer GetAssembly(ModuleHandle handle); TargetPointer GetPEAssembly(ModuleHandle handle); -bool GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); +bool GetReadyToRunImageInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags); TargetPointer ILoader.GetILAddr(TargetPointer peAssemblyPtr, int rva); bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size); @@ -344,7 +344,7 @@ TargetPointer GetPEAssembly(ModuleHandle handle) return target.ReadPointer(handle.Address + /* Module::PEAssembly offset */); } -bool GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) +bool GetReadyToRunImageInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) { r2rImageBase = TargetPointer.Null; r2rImageEnd = TargetPointer.Null; diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index bbaa5d4102dc49..05cd15075fa003 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -846,6 +846,7 @@ The contract depends on the following other contracts | ReJIT | | ExecutionManager | | PrecodeStubs | +| EcmaMetadata | And the following enumeration definitions diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 23e8546f817691..67ea617af398c6 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -831,7 +831,7 @@ class Module : public ModuleBase #ifdef FEATURE_READYTORUN private: PTR_ReadyToRunInfo m_pReadyToRunInfo; - PTR_PEImageLayout m_pReadyToRunImage; // cached on the module for easy access + PTR_PEImageLayout m_pReadyToRunImage; // cached on the module for easy access PTR_NativeImage m_pNativeImage; #endif diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs index 3b4d0fd5b3d966..5f6ea59d69ca83 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs @@ -6,24 +6,9 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; -public enum OptimizationTierEnum -{ - Unknown = 0, - MinOptJitted = 1, - Optimized = 2, - QuickJitted = 3, - OptimizedTier1 = 4, - ReadyToRun = 5, - OptimizedTier1OSR = 6, - QuickJittedInstrumented = 7, - OptimizedTier1Instrumented = 8, -} - public interface ICodeVersions : IContract { static string IContract.Name { get; } = nameof(CodeVersions); - public virtual IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) => throw new NotImplementedException(); - public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); public virtual ILCodeVersionHandle GetILCodeVersion(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs index 5e2c551ac00677..c4f01f130518eb 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs @@ -90,7 +90,7 @@ public interface ILoader : IContract TargetPointer GetModule(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetAssembly(ModuleHandle handle) => throw new NotImplementedException(); TargetPointer GetPEAssembly(ModuleHandle handle) => throw new NotImplementedException(); - bool GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) => throw new NotImplementedException(); + bool GetReadyToRunImageInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) => throw new NotImplementedException(); bool TryGetLoadedImageContents(ModuleHandle handle, out TargetPointer baseAddress, out uint size, out uint imageFlags) => throw new NotImplementedException(); TargetPointer GetILAddr(TargetPointer peAssemblyPtr, int rva) => throw new NotImplementedException(); bool TryGetSymbolStream(ModuleHandle handle, out TargetPointer buffer, out uint size) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs index e01fca40002b73..1d45a6e1fa732c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs @@ -12,6 +12,19 @@ public enum RejitState Active } +public enum OptimizationTierEnum +{ + Unknown = 0, + MinOptJitted = 1, + Optimized = 2, + QuickJitted = 3, + OptimizedTier1 = 4, + ReadyToRun = 5, + OptimizedTier1OSR = 6, + QuickJittedInstrumented = 7, + OptimizedTier1Instrumented = 8, +} + public interface IReJIT : IContract { static string IContract.Name { get; } = nameof(ReJIT); @@ -21,6 +34,7 @@ public interface IReJIT : IContract RejitState GetRejitState(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); TargetNUInt GetRejitId(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersions(TargetPointer methodDesc, int rejitId) => throw new NotImplementedException(); } public readonly struct ReJIT : IReJIT diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index c49624617e4038..7c3ff205309c27 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -18,188 +18,6 @@ public CodeVersions_1(Target target) _target = target; } - private enum NativeOptimizationTier : uint - { - Tier0 = 0, - Tier1 = 1, - Tier1OSR = 2, - TierOptimized = 3, - Tier0Instrumented = 4, - Tier1Instrumented = 5, - }; - - private enum Stage : byte - { - StubIsNotActive = 0, - StubMayBeActive = 1, - PendingCompletion = 2, - Complete = 3, - Disabled = 4 - }; - - private enum StorageKind - { - Unknown = 0, - Explicit = 1, - Synthetic = 2 - }; - - - private sealed class CodeVersionHashTraits : ITraits - { - private readonly Target _target; - public CodeVersionHashTraits(Target target) - { - _target = target; - } - public NativeCodeVersion GetKey(CallCountingInfo entry) - { - return _target.ProcessedData.GetOrAdd(entry.CodeVersion); - } - public bool Equals(NativeCodeVersion left, NativeCodeVersion right) => left.StorageKind == right.StorageKind && left.MethodDescOrNode == right.MethodDescOrNode; - public uint Hash(NativeCodeVersion key) - { - switch ((StorageKind)key.StorageKind) - { - case StorageKind.Synthetic: - return (uint)key.MethodDescOrNode; - case StorageKind.Explicit: - NativeCodeVersionNode node = _target.ProcessedData.GetOrAdd(key.MethodDescOrNode); - return (uint)node.MethodDesc + node.NativeId; - default: - throw new NotSupportedException(); - } - } - public bool IsNull(CallCountingInfo entry) => entry.Address == TargetPointer.Null; - public CallCountingInfo Null() => new CallCountingInfo(TargetPointer.Null); - public bool IsDeleted(CallCountingInfo entry) => false; - } - - private sealed class CallCountingTable : IData - { - static CallCountingTable IData.Create(Target target, TargetPointer address) - => new CallCountingTable(target, address); - - public CallCountingTable(Target target, TargetPointer address) - { - ISHash sHashContract = target.Contracts.SHash; - Target.TypeInfo type = target.GetTypeInfo(DataType.CallCountingInfo); - HashTable = sHashContract.CreateSHash(target, address, type, new CodeVersionHashTraits(target)); - } - public ISHash HashTable { get; init; } - } - private bool IsCallCountingEnabled(MethodDescHandle mdh) - { - // get loader allocator - Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - Contracts.ILoader loaderContract = _target.Contracts.Loader; - TargetPointer mt = rtsContract.GetMethodTable(mdh); - TargetPointer modulePtr = rtsContract.GetLoaderModule(rtsContract.GetTypeHandle(mt)); - Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(modulePtr); - TargetPointer loaderAllocator = loaderContract.GetLoaderAllocator(moduleHandle); - Data.LoaderAllocator loaderAllocatorData = _target.ProcessedData.GetOrAdd(loaderAllocator); - - // get call counting manager and hash - TargetPointer callCountingMgr = loaderAllocatorData.CallCountingManager!.Value; - TargetPointer callCountingHash = _target.ProcessedData.GetOrAdd(callCountingMgr).CallCountingHash; - CallCountingTable callCountingTable = _target.ProcessedData.GetOrAdd(callCountingHash); - - ISHash shashContract = _target.Contracts.SHash; - CallCountingInfo entry = shashContract.LookupSHash(callCountingTable.HashTable, new NativeCodeVersion((uint)StorageKind.Synthetic, mdh.Address)); - return entry.Address != TargetPointer.Null && entry.Stage != (byte)Stage.Disabled; - } - private NativeOptimizationTier GetInitialOptimizationTier(bool isReadyToRun, MethodDescHandle mdh) - { - if (_target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) == 0 - || !IsCallCountingEnabled(mdh)) - return NativeOptimizationTier.TierOptimized; - Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); - if (eeConfig.TieredPGO!.Value) - { - if (eeConfig.TieredPGO_InstrumentOnlyHotCode!.Value || isReadyToRun) - return NativeOptimizationTier.Tier0; - else - return NativeOptimizationTier.Tier0Instrumented; - } - else - return NativeOptimizationTier.Tier0; - } - - private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) - { - return nativeOptimizationTier switch - { - NativeOptimizationTier.Tier0 => OptimizationTierEnum.QuickJitted, - NativeOptimizationTier.Tier1 => OptimizationTierEnum.OptimizedTier1, - NativeOptimizationTier.Tier1OSR => OptimizationTierEnum.OptimizedTier1OSR, - NativeOptimizationTier.TierOptimized => OptimizationTierEnum.Optimized, - NativeOptimizationTier.Tier0Instrumented => OptimizationTierEnum.QuickJittedInstrumented, - NativeOptimizationTier.Tier1Instrumented => OptimizationTierEnum.OptimizedTier1Instrumented, - _ => OptimizationTierEnum.Unknown, - }; - } - - IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> ICodeVersions.GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) - { - Contracts.ICodeVersions codeVersionsContract = this; - Contracts.IReJIT rejitContract = _target.Contracts.ReJIT; - - ILCodeVersionHandle ilCodeVersion = codeVersionsContract.GetILCodeVersions(methodDesc) - .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode).Value == (ulong)rejitId, - ILCodeVersionHandle.Invalid); - - if (!ilCodeVersion.IsValid) - throw new ArgumentException(); - // Iterate through versioning state nodes and return the active one, matching any IL code version - Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; - Contracts.ILoader loader = _target.Contracts.Loader; - MethodDescHandle mdh = rts.GetMethodDescHandle(methodDesc); - TargetPointer methodTable = rts.GetMethodTable(mdh); - TypeHandle mtTypeHandle = rts.GetTypeHandle(methodTable); - TargetPointer modulePtr = rts.GetModule(mtTypeHandle); - ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); - - bool isReadyToRun = loader.GetReadyToRunInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); - bool isEligibleForTieredCompilation = rts.IsEligibleForTieredCompilation(mdh); - int count = 0; - foreach (NativeCodeVersionHandle nativeCodeVersionHandle in ((ICodeVersions)this).GetNativeCodeVersions(methodDesc, ilCodeVersion)) - { - TargetPointer nativeCode = codeVersionsContract.GetNativeCode(nativeCodeVersionHandle).AsTargetPointer; - TargetPointer nativeCodeAddr = nativeCode; - TargetPointer nativeCodeVersionNodePtr = nativeCodeVersionHandle.IsExplicit ? AsNode(nativeCodeVersionHandle).Address : TargetPointer.Null; - OptimizationTierEnum optimizationTier; - if (r2rImageBase <= nativeCode && nativeCode < r2rImageEnd) - { - optimizationTier = OptimizationTierEnum.ReadyToRun; - } - - else if (isEligibleForTieredCompilation) - { - NativeOptimizationTier optTier; - if (!nativeCodeVersionHandle.IsExplicit) - optTier = GetInitialOptimizationTier(isReadyToRun, mdh); - else - { - NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); - optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier!.Value; - } - optimizationTier = GetOptimizationTier(optTier); - } - else if (rts.IsJitOptimizationDisabled(mdh)) - { - optimizationTier = OptimizationTierEnum.MinOptJitted; - } - else - { - optimizationTier = OptimizationTierEnum.Optimized; - } - count++; - yield return (nativeCodeAddr, nativeCodeVersionNodePtr, optimizationTier); - - if (count >= cNativeCodeAddrs) - yield break; - } - } ILCodeVersionHandle ICodeVersions.GetActiveILCodeVersion(TargetPointer methodDesc) { // CodeVersionManager::GetActiveILCodeVersion diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs index 549a8f851641d4..1ebe4cb3668aa5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs @@ -173,7 +173,7 @@ TargetPointer ILoader.GetPEAssembly(ModuleHandle handle) return module.PEAssembly; } - bool ILoader.GetReadyToRunInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) + bool ILoader.GetReadyToRunImageInfo(ModuleHandle handle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd) { r2rImageBase = TargetPointer.Null; r2rImageEnd = TargetPointer.Null; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs index 6e9e80022a5738..5cd329ecdb808e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -34,6 +35,28 @@ public enum RejitFlags : uint kSuppressParams = 0x80000000 } + [Flags] + private enum NativeOptimizationTier : uint + { + Tier0 = 0, + Tier1 = 1, + Tier1OSR = 2, + TierOptimized = 3, + Tier0Instrumented = 4, + Tier1Instrumented = 5, + }; + + + public enum CallCountingStage : byte + { + StubIsNotActive = 0, + StubMayBeActive = 1, + PendingCompletion = 2, + Complete = 3, + Disabled = 4 + }; + + public ReJIT_1(Target target, Data.ProfControlBlock profControlBlock) { _target = target; @@ -77,6 +100,159 @@ TargetNUInt IReJIT.GetRejitId(ILCodeVersionHandle ilCodeVersionHandle) return ilCodeVersionNode.VersionId; } + private sealed class CodeVersionHashTraits : ITraits + { + private readonly Target _target; + public CodeVersionHashTraits(Target target) + { + _target = target; + } + public NativeCodeVersion GetKey(CallCountingInfo entry) + { + return _target.ProcessedData.GetOrAdd(entry.CodeVersion); + } + public bool Equals(NativeCodeVersion left, NativeCodeVersion right) => left.StorageKind == right.StorageKind && left.MethodDescOrNode == right.MethodDescOrNode; + public uint Hash(NativeCodeVersion key) + { + switch (key.StorageKind) + { + case 1: + return (uint)key.MethodDescOrNode; + case 2: + NativeCodeVersionNode node = _target.ProcessedData.GetOrAdd(key.MethodDescOrNode); + return (uint)node.MethodDesc + node.NativeId; + default: + throw new NotSupportedException(); + } + } + public bool IsNull(CallCountingInfo entry) => entry.Address == TargetPointer.Null; + public CallCountingInfo Null() => new CallCountingInfo(TargetPointer.Null); + public bool IsDeleted(CallCountingInfo entry) => false; + } + + private sealed class CallCountingTable : IData + { + static CallCountingTable IData.Create(Target target, TargetPointer address) + => new CallCountingTable(target, address); + + public CallCountingTable(Target target, TargetPointer address) + { + ISHash sHashContract = target.Contracts.SHash; + Target.TypeInfo type = target.GetTypeInfo(DataType.CallCountingInfo); + HashTable = sHashContract.CreateSHash(target, address, type, new CodeVersionHashTraits(target)); + } + public ISHash HashTable { get; init; } + } + private bool IsCallCountingEnabled(MethodDescHandle mdh) + { + // get loader allocator + Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + Contracts.ILoader loaderContract = _target.Contracts.Loader; + TargetPointer mt = rtsContract.GetMethodTable(mdh); + TargetPointer modulePtr = rtsContract.GetLoaderModule(rtsContract.GetTypeHandle(mt)); + Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(modulePtr); + TargetPointer loaderAllocator = loaderContract.GetLoaderAllocator(moduleHandle); + Data.LoaderAllocator loaderAllocatorData = _target.ProcessedData.GetOrAdd(loaderAllocator); + + // get call counting manager and hash + TargetPointer callCountingMgr = loaderAllocatorData.CallCountingManager!.Value; + TargetPointer callCountingHash = _target.ProcessedData.GetOrAdd(callCountingMgr).CallCountingHash; + CallCountingTable callCountingTable = _target.ProcessedData.GetOrAdd(callCountingHash); + + ISHash shashContract = _target.Contracts.SHash; + CallCountingInfo entry = shashContract.LookupSHash(callCountingTable.HashTable, new NativeCodeVersion(2, mdh.Address)); + return entry.Address != TargetPointer.Null && entry.Stage != (byte)CallCountingStage.Disabled; + } + private NativeOptimizationTier GetInitialOptimizationTier(bool isReadyToRun, MethodDescHandle mdh) + { + if (_target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) == 0 + || !IsCallCountingEnabled(mdh)) + return NativeOptimizationTier.TierOptimized; + Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); + if (eeConfig.TieredPGO!.Value) + { + if (eeConfig.TieredPGO_InstrumentOnlyHotCode!.Value || isReadyToRun) + return NativeOptimizationTier.Tier0; + else + return NativeOptimizationTier.Tier0Instrumented; + } + else + return NativeOptimizationTier.Tier0; + } + + private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) + { + return nativeOptimizationTier switch + { + NativeOptimizationTier.Tier0 => OptimizationTierEnum.QuickJitted, + NativeOptimizationTier.Tier1 => OptimizationTierEnum.OptimizedTier1, + NativeOptimizationTier.Tier1OSR => OptimizationTierEnum.OptimizedTier1OSR, + NativeOptimizationTier.TierOptimized => OptimizationTierEnum.Optimized, + NativeOptimizationTier.Tier0Instrumented => OptimizationTierEnum.QuickJittedInstrumented, + NativeOptimizationTier.Tier1Instrumented => OptimizationTierEnum.OptimizedTier1Instrumented, + _ => OptimizationTierEnum.Unknown, + }; + } + + IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> IReJIT.GetTieredVersions(TargetPointer methodDesc, int rejitId) + { + Contracts.ICodeVersions codeVersionsContract = _target.Contracts.CodeVersions; + Contracts.IReJIT rejitContract = this; + + ILCodeVersionHandle ilCodeVersion = codeVersionsContract.GetILCodeVersions(methodDesc) + .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode).Value == (ulong)rejitId, + ILCodeVersionHandle.Invalid); + + if (!ilCodeVersion.IsValid) + throw new ArgumentException(); + // Iterate through versioning state nodes and return the active one, matching any IL code version + Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + Contracts.ILoader loader = _target.Contracts.Loader; + MethodDescHandle mdh = rts.GetMethodDescHandle(methodDesc); + TargetPointer methodTable = rts.GetMethodTable(mdh); + TypeHandle mtTypeHandle = rts.GetTypeHandle(methodTable); + TargetPointer modulePtr = rts.GetModule(mtTypeHandle); + ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); + + bool isReadyToRun = loader.GetReadyToRunImageInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); + bool isEligibleForTieredCompilation = rts.IsEligibleForTieredCompilation(mdh); + int count = 0; + foreach (NativeCodeVersionHandle nativeCodeVersionHandle in codeVersionsContract.GetNativeCodeVersions(methodDesc, ilCodeVersion)) + { + TargetPointer nativeCode = codeVersionsContract.GetNativeCode(nativeCodeVersionHandle).AsTargetPointer; + TargetPointer nativeCodeAddr = nativeCode; + TargetPointer nativeCodeVersionNodePtr = nativeCodeVersionHandle.IsExplicit ? AsNode(nativeCodeVersionHandle).Address : TargetPointer.Null; + OptimizationTierEnum optimizationTier; + if (r2rImageBase <= nativeCode && nativeCode < r2rImageEnd) + { + optimizationTier = OptimizationTierEnum.ReadyToRun; + } + + else if (isEligibleForTieredCompilation) + { + NativeOptimizationTier optTier; + if (!nativeCodeVersionHandle.IsExplicit) + optTier = GetInitialOptimizationTier(isReadyToRun, mdh); + else + { + NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); + optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier!.Value; + } + optimizationTier = GetOptimizationTier(optTier); + } + else if (rts.IsJitOptimizationDisabled(mdh)) + { + optimizationTier = OptimizationTierEnum.MinOptJitted; + } + else + { + optimizationTier = OptimizationTierEnum.Optimized; + } + count++; + yield return (nativeCodeAddr, nativeCodeVersionNodePtr, optimizationTier); + } + } + private ILCodeVersionNode AsNode(ILCodeVersionHandle ilCodeVersionHandle) { if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null) @@ -86,4 +262,14 @@ private ILCodeVersionNode AsNode(ILCodeVersionHandle ilCodeVersionHandle) return _target.ProcessedData.GetOrAdd(ilCodeVersionHandle.ILCodeVersionNode); } + + private NativeCodeVersionNode AsNode(NativeCodeVersionHandle nativeCodeVersionHandle) + { + if (!nativeCodeVersionHandle.IsExplicit) + { + throw new InvalidOperationException("Synthetic NativeCodeVersion does not have a backing node."); + } + + return _target.ProcessedData.GetOrAdd(nativeCodeVersionHandle.CodeVersionNodeAddress); + } } diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs index b3f8e0102efee8..5c5e82520cd03a 100644 --- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs @@ -3107,16 +3107,19 @@ int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, TargetPointer methodDescPtr = methodDesc.ToTargetPointer(_target); int count = 0; - foreach ((TargetPointer nativeCode, TargetPointer nativeCodeVersionNodePtr, Contracts.OptimizationTierEnum optTier) in _target.Contracts.CodeVersions.GetTieredVersions(methodDescPtr, rejitId, cNativeCodeAddrs)) + foreach ((TargetPointer nativeCode, TargetPointer nativeCodeVersionNodePtr, Contracts.OptimizationTierEnum optTier) in _target.Contracts.ReJIT.GetTieredVersions(methodDescPtr, rejitId)) { nativeCodeAddrs[count] = default; nativeCodeAddrs[count].NativeCodeAddr = nativeCode.ToClrDataAddress(_target); nativeCodeAddrs[count].NativeCodeVersionNodePtr = nativeCodeVersionNodePtr.ToClrDataAddress(_target); nativeCodeAddrs[count++].OptimizationTier = (DacpTieredVersionData.OptimizationTierEnum)optTier; + if (count >= cNativeCodeAddrs) + { + hr = HResults.S_FALSE; + break; + } } *pcNativeCodeAddrs = count; - if (count >= cNativeCodeAddrs) - hr = HResults.S_FALSE; } catch (System.Exception ex) { diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs index feee26fc9c24f8..fc687002ae6102 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs @@ -23,7 +23,7 @@ public class CodeVersions new(nameof(Data.MethodDescVersioningState.Flags), DataType.uint8), ] }; - + // note: we aren't testing this on wasm so we can go ahead and include both OptimizationTier and NativeId private static readonly TypeFields NativeCodeVersionNodeFields = new TypeFields() { DataType = DataType.NativeCodeVersionNode, @@ -34,6 +34,8 @@ public class CodeVersions new(nameof(Data.NativeCodeVersionNode.NativeCode), DataType.pointer), new(nameof(Data.NativeCodeVersionNode.Flags), DataType.uint32), new(nameof(Data.NativeCodeVersionNode.ILVersionId), DataType.nuint), + new(nameof(Data.NativeCodeVersionNode.OptimizationTier), DataType.uint32), + new(nameof(Data.NativeCodeVersionNode.NativeId), DataType.uint32), new(nameof(Data.NativeCodeVersionNode.GCCoverageInfo), DataType.pointer), ] }; diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.cs index aab00bacc85251..ca825ac583b0ef 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.cs @@ -143,6 +143,7 @@ internal record TypeFields new(nameof(Data.Module.Path), DataType.pointer), new(nameof(Data.Module.FileName), DataType.pointer), new(nameof(Data.Module.ReadyToRunInfo), DataType.pointer), + new(nameof(Data.Module.ReadyToRunImage), DataType.pointer), new(nameof(Data.Module.GrowableSymbolStream), DataType.pointer), new(nameof(Data.Module.AvailableTypeParams), DataType.pointer), new(nameof(Data.Module.InstMethodHashTable), DataType.pointer), From 81846329600632847e60313526b3ddc8062e565b Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 19 Sep 2025 12:57:55 -0700 Subject: [PATCH 11/13] e --- .../vm/datadescriptor/datadescriptor.inc | 2 + .../Contracts/ICodeVersions.cs | 1 - .../Contracts/CodeVersions_1.cs | 63 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 5b8c2b71c8b5ef..2ccc8436f521b5 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1095,7 +1095,9 @@ CDAC_GLOBAL_CONTRACT(Loader, 1) CDAC_GLOBAL_CONTRACT(Object, 1) CDAC_GLOBAL_CONTRACT(PlatformMetadata, 1) CDAC_GLOBAL_CONTRACT(PrecodeStubs, 3) +#ifdef FEATURE_REJIT CDAC_GLOBAL_CONTRACT(ReJIT, 1) +#endif // FEATURE_REJIT CDAC_GLOBAL_CONTRACT(RuntimeInfo, 1) CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, 1) CDAC_GLOBAL_CONTRACT(SHash, 1) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs index 5f6ea59d69ca83..321296ec2c4e72 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs @@ -24,7 +24,6 @@ public interface ICodeVersions : IContract public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); public virtual TargetPointer GetGCStressCodeCopy(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); - public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException(); public virtual TargetPointer GetIL(ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index 7c3ff205309c27..ffa6ecbc527a9e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -234,6 +234,69 @@ TargetPointer ICodeVersions.GetGCStressCodeCopy(NativeCodeVersionHandle codeVers } } + private enum NativeStorageKind + { + Unknown = 0, + Explicit = 1, + Synthetic = 2 + }; + + internal sealed class CodeVersionHashTraits : ITraits + { + private readonly Target _target; + public CodeVersionHashTraits(Target target) + { + _target = target; + } + public NativeCodeVersionHandle GetKey(CallCountingInfo entry) + { + if (entry.CodeVersion == TargetPointer.Null) + { + return NativeCodeVersionHandle.Invalid; + } + + Data.NativeCodeVersion codeVersion = _target.ProcessedData.GetOrAdd(entry.CodeVersion); + switch ((NativeStorageKind)codeVersion.StorageKind) + { + case NativeStorageKind.Explicit: + return NativeCodeVersionHandle.CreateExplicit(codeVersion.MethodDescOrNode); + case NativeStorageKind.Synthetic: + return NativeCodeVersionHandle.CreateSynthetic(codeVersion.MethodDescOrNode); + default: + throw new InvalidOperationException($"Unknown NativeCodeVersionKind {codeVersion.StorageKind}"); + } + } + public bool Equals(NativeCodeVersionHandle left, NativeCodeVersionHandle right) + { + if (!left.Valid || !right.Valid) + return !left.Valid && !right.Valid; + + if (left.IsExplicit != right.IsExplicit) + return false; + + if (left.IsExplicit) + return left.CodeVersionNodeAddress == right.CodeVersionNodeAddress; + return left.MethodDescAddress == right.MethodDescAddress; + } + public uint Hash(NativeCodeVersionHandle key) + { + if (!key.Valid) + { + return 0; + } + + if (key.IsExplicit) + { + return (uint)key.CodeVersionNodeAddress; + } + NativeCodeVersionNode node = _target.ProcessedData.GetOrAdd(key.CodeVersionNodeAddress); + return (uint)(node.NativeId + node.MethodDesc); + } + public bool IsNull(CallCountingInfo entry) => entry.Address == TargetPointer.Null; + public CallCountingInfo Null() => new CallCountingInfo(TargetPointer.Null); + public bool IsDeleted(CallCountingInfo entry) => false; + } + [Flags] internal enum MethodDescVersioningStateFlags : byte { From aaa03ebc74cd8aef47951b5a1b35cfe295d76ad3 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sat, 20 Sep 2025 09:24:16 -0700 Subject: [PATCH 12/13] restructuring runtime to store tiered comp info for default codeversion --- docs/design/datacontracts/CodeVersions.md | 216 +----------------- docs/design/datacontracts/ReJIT.md | 113 ++++++++- .../design/datacontracts/RuntimeTypeSystem.md | 1 + src/coreclr/vm/callcounting.h | 21 -- src/coreclr/vm/codeversion.h | 13 +- .../vm/datadescriptor/datadescriptor.inc | 33 +-- src/coreclr/vm/eeconfig.h | 4 - src/coreclr/vm/loaderallocator.hpp | 3 - src/coreclr/vm/method.cpp | 24 ++ src/coreclr/vm/method.hpp | 3 + src/coreclr/vm/tieredcompilation.cpp | 37 +-- .../Contracts/ICodeVersions.cs | 2 + .../DataType.cs | 3 - .../Contracts/CodeVersions_1.cs | 63 ----- .../Contracts/ReJIT_1.cs | 121 ++-------- .../Contracts/RuntimeTypeSystem_1.cs | 2 +- .../Data/CallCountingInfo.cs | 28 --- .../Data/CallCountingManager.cs | 19 -- .../Data/EEConfig.cs | 6 - .../Data/LoaderAllocator.cs | 5 - .../Data/MethodDescCodeData.cs | 2 + .../Data/NativeCodeVersion.cs | 27 --- .../Data/NativeCodeVersionNode.cs | 2 - .../MockDescriptors.CodeVersions.cs | 4 +- 24 files changed, 193 insertions(+), 559 deletions(-) delete mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingInfo.cs delete mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingManager.cs delete mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersion.cs diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 0437671a77bc02..4968a750113605 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -22,22 +22,6 @@ internal struct NativeCodeVersionHandle } ``` -Native code version optimization enum: -```csharp -public enum OptimizationTierEnum -{ - Unknown = 0, - MinOptJitted = 1, - Optimized = 2, - QuickJitted = 3, - OptimizedTier1 = 4, - ReadyToRun = 5, - OptimizedTier1OSR = 6, - QuickJittedInstrumented = 7, - OptimizedTier1Instrumented = 8, -} -``` - ```csharp // Return a handle to the active version of the IL code for a given method descriptor public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc); @@ -78,15 +62,7 @@ See [code versioning](../features/code-versioning.md) for a general overview and Data descriptors used: | Data Descriptor Name | Field | Meaning | | --- | --- | --- | -| CallCountingInfo | CodeVersion | pointer to native code version | -| CallCountingInfo | Stage | call counting enum, see below | -| CallCountingInfo | Table | pointer to call counting info SHash table | -| CallCountingInfo | TableSize | number of entries in CallCountingInfo SHash table | -| CallCountingManager | CallCountingHash | SHash of native code versions to call counting info | -| EEConfig | TieredPGO_InstrumentOnlyHotCode | boolean, for deciding optimization tier of default native code version | | MethodDescVersioningState | Flags | `MethodDescVersioningStateFlags` flags, see below | -| NativeCodeVersion | StorageKind | storage kind enum, see below | -| NativeCodeVersion | MethodDescOrNode | pointer to method desc (synthetic) or version node (explicit) | | MethodDescVersioningState | NativeCodeVersionNode | code version node of this method desc, if active | | NativeCodeVersionNode | Next | pointer to the next native code version | | NativeCodeVersionNode | MethodDesc | indicates a synthetic native code version node | @@ -94,7 +70,6 @@ Data descriptors used: | NativeCodeVersionNode | Flags | `NativeCodeVersionNodeFlags` flags, see below | | NativeCodeVersionNode | VersionId | Version ID corresponding to the parent IL code version | | NativeCodeVersionNode | GCCoverageInfo | GCStress debug info, if supported | -| NativeCodeVersionNode | NativeId | ID corresponding to the version node | | ILCodeVersioningState | FirstVersionNode | pointer to the first `ILCodeVersionNode` | | ILCodeVersioningState | ActiveVersionKind | an `ILCodeVersionKind` value indicating which fields of the active version are value | | ILCodeVersioningState | ActiveVersionNode | if the active version is explicit, the NativeCodeVersionNode for the active version | @@ -132,46 +107,7 @@ private enum ILCodeVersionKind } ``` -The value of `NativeCodeVersionNode::OptimizationTier` is one of -```csharp -private enum NativeOptimizationTier : uint -{ - OptimizationTier0 = 0, - OptimizationTier1 = 1, - OptimizationTier1OSR = 2, - OptimizationTierOptimized = 3, - OptimizationTier0Instrumented = 4, - OptimizationTier1Instrumented = 5, -}; -``` - -The value of `CallCountingInfo::Stage` is one of -```csharp -private enum Stage : byte -{ - StubIsNotActive = 0, - StubMayBeActive = 1, - PendingCompletion = 2, - Complete = 3, - Disabled = 4 -}; -``` - -The value of `NativeCodeVersion::StorageKind` is one of -```csharp -private enum StorageKind -{ - Unknown = 0, - Explicit = 1, - Synthetic = 2 -}; -``` - -### Global variables used: -| Global Name | Type | Purpose | -| --- | --- | --- | -| `FeatureTieredCompilation` | byte | is FEATURE_TIERED_COMPILATION on (1) or off (0) | -| `EEConfig` | TargetPointer | Pointer to the global EEConfig | +Global variables used: *none* Contracts used: | Contract Name | @@ -179,7 +115,6 @@ Contracts used: | ExecutionManager | | Loader | | RuntimeTypeSystem | -| SHash | Implementation of CodeVersionHandles @@ -379,155 +314,6 @@ IEnumerable ICodeVersions.GetNativeCodeVersions(TargetP } ``` -### Iterating through native code versions given a MethodDesc and a rejit ID -Here we need an SHash, the SHash traits are below: -```csharp - private sealed class CodeVersionHashTraits : ITraits - { - private readonly Target _target; - public CodeVersionHashTraits(Target target) - { - _target = target; - } - public NativeCodeVersion GetKey(CallCountingInfo entry) - { - return // read version node or method desc ptr from entry - } - public bool Equals(NativeCodeVersion left, NativeCodeVersion right) => // storage kind and pointer match - public uint Hash(NativeCodeVersion key) - { - // switch on the storage kind - // if synthetic the key is the method desc pointer - // if explicit we read the pointer (node pointer) - // and then sum the ID of the node and the method desc of the node - // otherwise throw not supported - } - public bool IsNull(CallCountingInfo entry) => // address is null - public CallCountingInfo Null() => new CallCountingInfo(TargetPointer.Null); - public bool IsDeleted(CallCountingInfo entry) => false; - } -``` - -```csharp -private bool IsCallCountingEnabled(MethodDescHandle mdh) -{ - // get loader allocator - Contracts.IRuntimeTypeSystem rtsContract = target.Contracts.RuntimeTypeSystem; - Contracts.ILoader loaderContract = target.Contracts.Loader; - TargetPointer loaderAllocator = // get loader allocator using rtsContract and loaderContract - Data.LoaderAllocator loaderAllocatorData = target.ProcessedData.GetOrAdd(loaderAllocator); - - // get call counting manager and hash - TargetPointer callCountingMgr = target.ReadPointer(loaderAllocator + /* LoaderAllocator::CallCountingManager offset */); - TargetPointer callCountingHash = callCountingMgr + /* CallCountingManager::CallCountingHash offset */; - - CodeVersionHashTraits traits = new(target); - ISHash shashContract = target.Contracts.SHash; - /* To construct an SHash we must pass a DataType enum. - We must be able to look up this enum in a dictionary of known types and retrieve a Target.TypeInfo struct. - This struct contains a dictionary of fields with keys corresponding to the names of offsets - and values corresponding to the offset values. Optionally, it contains a Size field. - Here this is the CallCountingInfo DataType which contains the appropriate offsets for the hashtable data, number of entries, as well as the shape and size of each entry. - */ - SHash shash = shashContract.CreateSHash(target, callCountingHash, DataType.CallCountingInfo, traits) - CallCountingInfo entry = shashContract.LookupSHash(callCountingTable.HashTable, new NativeCodeVersion((uint)StorageKind.Synthetic, mdh.Address)); - return // entry is not null and the stage of the entry is not Disabled -} - -private NativeOptimizationTier GetInitialOptimizationTier(bool isReadyToRun, MethodDescHandle mdh) -{ - if (target.ReadGlobal("FeatureTieredCompilation") == 0 - || !IsCallCountingEnabled(mdh)) - return NativeOptimizationTier.TierOptimized; - - TargetPointer eeConfig = // read EEConfig global variable - if (/* eeConfig is TieredPGO enabled */) - { - bool tieredPGO_InstrumentOnlyHotCode = // read from EEConfig - if (tieredPGO_InstrumentOnlyHotCode || isReadyToRun) - return NativeOptimizationTier.Tier0; - else - return NativeOptimizationTier.Tier0Instrumented; - } - else - return NativeOptimizationTier.Tier0; -} - -IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) -{ - Contracts.ICodeVersions codeVersionsContract = this; - Contracts.IReJIT rejitContract = target.Contracts.ReJIT; - - ILCodeVersionHandle ilCodeVersion = codeVersionsContract.GetILCodeVersions(methodDesc) - .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode).Value == (ulong)rejitId, - ILCodeVersionHandle.Invalid); - - if (!ilCodeVersion.IsValid) - throw new ArgumentException(); - // Iterate through versioning state nodes and return the active one, matching any IL code version - Contracts.IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem; - Contracts.ILoader loader = target.Contracts.Loader; - ModuleHandle moduleHandle = // get the module handle from the method desc using rts - - bool isReadyToRun = loader.GetReadyToRunImageInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); - bool isEligibleForTieredCompilation = rts.IsEligibleForTieredCompilation(mdh); - int count = 0; - foreach (NativeCodeVersionHandle nativeCodeVersionHandle in ((ICodeVersions)this).GetNativeCodeVersions(methodDesc, ilCodeVersion)) - { - TargetPointer nativeCode = codeVersionsContract.GetNativeCode(nativeCodeVersionHandle).AsTargetPointer; - TargetPointer nativeCodeAddr = nativeCode; - TargetPointer nativeCodeVersionNodePtr = nativeCodeVersionHandle.IsExplicit ? AsNode(nativeCodeVersionHandle).Address : TargetPointer.Null; - OptimizationTierEnum optimizationTier; - if (r2rImageBase <= nativeCode && nativeCode < r2rImageEnd) - { - optimizationTier = OptimizationTierEnum.ReadyToRun; - } - - else if (isEligibleForTieredCompilation) - { - NativeOptimizationTier optTier; - if (!nativeCodeVersionHandle.IsExplicit) - optTier = GetInitialOptimizationTier(isReadyToRun, mdh); - else - { - NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); - optTier = (NativeOptimizationTier)nativeCodeVersionNode.OptimizationTier; - } - optimizationTier = GetOptimizationTier(optTier); - } - else if (rts.IsJitOptimizationDisabled(mdh)) - { - optimizationTier = OptimizationTierEnum.MinOptJitted; - } - else - { - optimizationTier = OptimizationTierEnum.Optimized; - } - count++; - yield return (nativeCodeAddr, nativeCodeVersionNodePtr, optimizationTier); - - if (count >= cNativeCodeAddrs) - yield break; - } -} -``` - -Helper for the above to translate from internal to external optimization tier -```csharp -private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) -{ - return nativeOptimizationTier switch - { - NativeOptimizationTier.Tier0 => OptimizationTierEnum.QuickJitted, - NativeOptimizationTier.Tier1 => OptimizationTierEnum.OptimizedTier1, - NativeOptimizationTier.Tier1OSR => OptimizationTierEnum.OptimizedTier1OSR, - NativeOptimizationTier.TierOptimized => OptimizationTierEnum.Optimized, - NativeOptimizationTier.Tier0Instrumented => OptimizationTierEnum.QuickJittedInstrumented, - NativeOptimizationTier.Tier1Instrumented => OptimizationTierEnum.OptimizedTier1Instrumented, - _ => OptimizationTierEnum.Unknown, - }; -} -``` ### Finding the active native code version of an ILCodeVersion for a method descriptor ```csharp diff --git a/docs/design/datacontracts/ReJIT.md b/docs/design/datacontracts/ReJIT.md index 106360c6d97685..0ebcf397daa7fd 100644 --- a/docs/design/datacontracts/ReJIT.md +++ b/docs/design/datacontracts/ReJIT.md @@ -12,6 +12,21 @@ public enum RejitState } ``` +```csharp +public enum OptimizationTierEnum +{ + Unknown = 0, + MinOptJitted = 1, + Optimized = 2, + QuickJitted = 3, + OptimizedTier1 = 4, + ReadyToRun = 5, + OptimizedTier1OSR = 6, + QuickJittedInstrumented = 7, + OptimizedTier1Instrumented = 8, +} +``` + ```csharp bool IsEnabled(); @@ -19,7 +34,8 @@ RejitState GetRejitState(ILCodeVersionHandle codeVersionHandle); TargetNUInt GetRejitId(ILCodeVersionHandle codeVersionHandle); -IEnumerable GetRejitIds(TargetPointer methodDesc) +IEnumerable GetRejitIds(TargetPointer methodDesc); +IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs); ``` ## Version 1 @@ -30,16 +46,21 @@ Data descriptors used: | ProfControlBlock | GlobalEventMask | an `ICorProfiler` `COR_PRF_MONITOR` value | | ILCodeVersionNode | VersionId | `ILCodeVersion` ReJIT ID | ILCodeVersionNode | RejitState | a `RejitFlags` value | +| MethodDesc | CodeData | Pointer to CodeData (additional info about native code) | +| MethodDescCodeData | OptimizationTier | Optimization tier of default native code version | Global variables used: | Global Name | Type | Purpose | | --- | --- | --- | |ProfilerControlBlock | TargetPointer | pointer to the `ProfControlBlock` | +| `EEConfig` | TargetPointer | Pointer to the global EEConfig | Contracts used: | Contract Name | | --- | | CodeVersions | +| RuntimeTypeSystem | +| Loader | ```csharp // see src/coreclr/inc/corprof.idl @@ -64,6 +85,19 @@ public enum RejitFlags : uint kSuppressParams = 0x80000000 } +private enum NativeOptimizationTier : uint +{ + OptimizationTier0 = 0, + OptimizationTier1 = 1, + OptimizationTier1OSR = 2, + OptimizationTierOptimized = 3, + OptimizationTier0Instrumented = 4, + OptimizationTier1Instrumented = 5, + OptimizationTierUnknown = 0xFFFFFFFF +}; +``` +```csharp + bool IsEnabled() { TargetPointer address = target.ReadGlobalPointer("ProfilerControlBlock"); @@ -124,4 +158,81 @@ IEnumerable GetRejitIds(TargetPointer methodDesc) } } } + +IEnumerable<(TargetPointer, TargetPointer, OptimizationTierEnum)> GetTieredVersions(TargetPointer methodDesc, int rejitId, int cNativeCodeAddrs) +{ + ICodeVersions codeVersionsContract = target.Contracts.CodeVersions; + IReJIT rejitContract = this; + + ILCodeVersionHandle ilCodeVersion = codeVersionsContract.GetILCodeVersions(methodDesc) + MethodDescHandle mdh = rts.GetMethodDescHandle(methodDesc); + .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode).Value == (ulong)rejitId, + ILCodeVersionHandle.Invalid); + + if (!ilCodeVersion.IsValid) + throw new ArgumentException(); + // Iterate through versioning state nodes and return the active one, matching any IL code version + IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem; + ILoader loader = target.Contracts.Loader; + ModuleHandle moduleHandle = // get the module handle from the method desc using rts + + bool isReadyToRun = loader.GetReadyToRunImageInfo(moduleHandle, out TargetPointer r2rImageBase, out TargetPointer r2rImageEnd); + bool isEligibleForTieredCompilation = rts.IsEligibleForTieredCompilation(mdh); + int count = 0; + foreach (NativeCodeVersionHandle nativeCodeVersionHandle in codeVersionsContract.GetNativeCodeVersions(methodDesc, ilCodeVersion)) + { + TargetPointer nativeCode = codeVersionsContract.GetNativeCode(nativeCodeVersionHandle).AsTargetPointer; + TargetPointer nativeCodeAddr = nativeCode; + TargetPointer nativeCodeVersionNodePtr = nativeCodeVersionHandle.IsExplicit ? AsNode(nativeCodeVersionHandle).Address : TargetPointer.Null; + OptimizationTierEnum optimizationTier; + if (r2rImageBase <= nativeCode && nativeCode < r2rImageEnd) + { + optimizationTier = OptimizationTierEnum.ReadyToRun; + } + + else if (isEligibleForTieredCompilation) + { + NativeOptimizationTier optTier; + if (!nativeCodeVersionHandle.IsExplicit) + optTier = GetInitialOptimizationTier(mdh); + else + { + optTier = (NativeOptimizationTier)target.ReadPointer(/* native code version address + NativeCodeVersionNode::OptimizationTier offset */); + } + optimizationTier = GetOptimizationTier(optTier); + } + else if (rts.IsJitOptimizationDisabled(mdh)) + { + optimizationTier = OptimizationTierEnum.MinOptJitted; + } + else + { + optimizationTier = OptimizationTierEnum.Optimized; + } + count++; + yield return (nativeCodeAddr, nativeCodeVersionNodePtr, optimizationTier); + } +} + +private NativeOptimizationTier GetInitialOptimizationTier(TargetPointer mdPointer) +{ + // validation of the method desc + MethodDescHandle _ = target.Contracts.RuntimeTypeSystem.GetMethodDescHandle(mdPointer); + TargetPointer codeData = target.ReadPointer(mdPointer + /* MethodDesc::CodeData offset */); + return (NativeOptimizationTier)target.Read(codeData + /* MethodDescCodeData::OptimizationTier offset */); +} + +private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) +{ + return nativeOptimizationTier switch + { + NativeOptimizationTier.OptimizationTier0 => OptimizationTierEnum.QuickJitted, + NativeOptimizationTier.OptimizationTier1 => OptimizationTierEnum.OptimizedTier1, + NativeOptimizationTier.OptimizationTier1OSR => OptimizationTierEnum.OptimizedTier1OSR, + NativeOptimizationTier.OptimizationTierOptimized => OptimizationTierEnum.Optimized, + NativeOptimizationTier.OptimizationTier0Instrumented => OptimizationTierEnum.QuickJittedInstrumented, + NativeOptimizationTier.OptimizationTier1Instrumented => OptimizationTierEnum.OptimizedTier1Instrumented, + _ => OptimizationTierEnum.Unknown, + }; +} ``` diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index f7ebdef25461b1..4913be2e861d14 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -806,6 +806,7 @@ The version 1 `MethodDesc` APIs depend on the following globals: | `CORDebuggerControlFlags` | A pointer to debugger control flags, that the debugger can set to control optimizations, etc. | | `EEConfig` | A pointer to the global EEConfig that contains global settings, etc. | + In the runtime a `MethodDesc` implicitly belongs to a single `MethodDescChunk` and some common data is shared between method descriptors that belong to the same chunk. A single method table will typically have multiple chunks. There are subkinds of MethodDescs at runtime of varying sizes (but the sizes must be mutliples of `MethodDescAlignment`) and each chunk contains method descriptors of the same size. diff --git a/src/coreclr/vm/callcounting.h b/src/coreclr/vm/callcounting.h index afa92705043325..59071aa51f140b 100644 --- a/src/coreclr/vm/callcounting.h +++ b/src/coreclr/vm/callcounting.h @@ -4,7 +4,6 @@ #pragma once #include "codeversion.h" -#include "cdacdata.h" #ifdef FEATURE_TIERED_COMPILATION @@ -249,12 +248,9 @@ class CallCountingManager static BOOL Equals(const key_t &k1, const key_t &k2); static count_t Hash(const key_t &k); }; - friend struct ::cdac_data; - friend struct ::cdac_data>; }; typedef SHash CallCountingInfoByCodeVersionHash; - friend struct ::cdac_data>; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CallCountingManager::CallCountingStubAllocator @@ -392,27 +388,10 @@ class CallCountingManager #ifdef DACCESS_COMPILE static void DacEnumerateCallCountingStubHeapRanges(CLRDataEnumMemoryFlags flags); #endif - friend struct ::cdac_data; DISABLE_COPY(CallCountingManager); }; -template<> -struct cdac_data> -{ - static constexpr size_t Table = offsetof(SHash, m_table); - static constexpr size_t TableSize = offsetof(SHash, m_tableSize); -}; - -template<> -struct cdac_data -{ - static constexpr size_t CallCountingHash = offsetof(CallCountingManager, m_callCountingInfoByCodeVersionHash); - static constexpr size_t CodeVersion = offsetof(CallCountingManager::CallCountingInfo, m_codeVersion); - static constexpr size_t Stage = offsetof(CallCountingManager::CallCountingInfo, m_stage); - static constexpr size_t Table = cdac_data>::Table; - static constexpr size_t TableSize = cdac_data>::TableSize; -}; //////////////////////////////////////////////////////////////// // CallCountingStub definitions diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 07b17c2edbc1ff..437cd14d996338 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -82,6 +82,7 @@ class NativeCodeVersion OptimizationTierOptimized, // may do less optimizations than tier 1 OptimizationTier0Instrumented, OptimizationTier1Instrumented, + OptimizationTierUnknown = 0xFFFFFFFF }; #ifdef FEATURE_TIERED_COMPILATION OptimizationTier GetOptimizationTier() const; @@ -140,14 +141,6 @@ class NativeCodeVersion PTR_MethodDesc m_pMethodDesc; } m_synthetic; }; -friend struct ::cdac_data; -}; - -template<> -struct cdac_data -{ - static constexpr size_t StorageKind = offsetof(NativeCodeVersion, m_storageKind); - static constexpr size_t MethodDescOrNode = offsetof(NativeCodeVersion, m_pVersionNode); }; enum class RejitFlags : uint32_t @@ -335,10 +328,6 @@ struct cdac_data static constexpr size_t NativeCode = offsetof(NativeCodeVersionNode, m_pNativeCode); static constexpr size_t Flags = offsetof(NativeCodeVersionNode, m_flags); static constexpr size_t ILVersionId = offsetof(NativeCodeVersionNode, m_parentId); -#ifdef FEATURE_TIERED_COMPILATION - static constexpr size_t OptimizationTier = offsetof(NativeCodeVersionNode, m_optTier); -#endif // FEATURE_TIERED_COMPILATION - static constexpr size_t NativeId = offsetof(NativeCodeVersionNode, m_id); #ifdef HAVE_GCCOVER static constexpr size_t GCCoverageInfo = offsetof(NativeCodeVersionNode, m_gcCover); #endif // HAVE_GCCOVER diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 2ccc8436f521b5..39f4dd5cd44470 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -214,26 +214,8 @@ CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, HighFrequencyHeap, cdac_data::LowFrequencyHeap) CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, StubHeap, cdac_data::StubHeap) CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, ObjectHandle, cdac_data::ObjectHandle) -#ifdef FEATURE_TIERED_COMPILATION -CDAC_TYPE_FIELD(LoaderAllocator, /*pointer*/, CallCountingManager, cdac_data::CallCountingManager) -#endif // FEATURE_TIERED_COMPILATION CDAC_TYPE_END(LoaderAllocator) -CDAC_TYPE_BEGIN(CallCountingManager) -CDAC_TYPE_INDETERMINATE(CallCountingManager) -CDAC_TYPE_FIELD(CallCountingManager, /*pointer*/, CallCountingHash, cdac_data::CallCountingHash) -CDAC_TYPE_END(CallCountingManager) - -// the size is pointer size because this is for an SHash -// and the entry is a pointer to this data structure -CDAC_TYPE_BEGIN(CallCountingInfo) -CDAC_TYPE_SIZE(sizeof(uintptr_t)) -CDAC_TYPE_FIELD(CallCountingInfo, /*pointer*/, CodeVersion, cdac_data::CodeVersion) -CDAC_TYPE_FIELD(CallCountingInfo, /*int8*/, Stage, cdac_data::Stage) -CDAC_TYPE_FIELD(CallCountingInfo, /*pointer*/, Table, cdac_data::Table) -CDAC_TYPE_FIELD(CallCountingInfo, /*int32*/, TableSize, cdac_data::TableSize) -CDAC_TYPE_END(CallCountingInfo) - CDAC_TYPE_BEGIN(PEAssembly) CDAC_TYPE_INDETERMINATE(PEAssembly) CDAC_TYPE_FIELD(PEAssembly, /*pointer*/, PEImage, cdac_data::PEImage) @@ -340,10 +322,6 @@ CDAC_TYPE_BEGIN(EEConfig) CDAC_TYPE_INDETERMINATE(EEConfig) CDAC_TYPE_FIELD(EEConfig, /*bool*/, JitMinOpts, cdac_data::JitMinOpts) CDAC_TYPE_FIELD(EEConfig, /*bool*/, Debuggable, cdac_data::Debuggable) -#if defined(FEATURE_PGO) -CDAC_TYPE_FIELD(EEConfig, /*bool*/, TieredPGO, cdac_data::TieredPGO) -CDAC_TYPE_FIELD(EEConfig, /*bool*/, TieredPGO_InstrumentOnlyHotCode, cdac_data::TieredPGO_InstrumentOnlyHotCode) -#endif CDAC_TYPE_END(EEConfig) CDAC_TYPE_BEGIN(ArrayClass) @@ -522,6 +500,7 @@ CDAC_TYPE_BEGIN(MethodDescCodeData) CDAC_TYPE_INDETERMINATE(MethodDescCodeData) CDAC_TYPE_FIELD(MethodDescCodeData, /*CodePointer*/, TemporaryEntryPoint, offsetof(MethodDescCodeData,TemporaryEntryPoint)) CDAC_TYPE_FIELD(MethodDescCodeData, /*pointer*/, VersioningState, offsetof(MethodDescCodeData,VersioningState)) +CDAC_TYPE_FIELD(MethodDescCodeData, /*OptimizationTier*/, OptimizationTier, offsetof(MethodDescCodeData,OptimizationTier)) CDAC_TYPE_END(MethodDescCodeData) CDAC_TYPE_BEGIN(MethodDescVersioningState) @@ -709,21 +688,11 @@ CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, MethodDesc, cdac_data::NativeCode) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, Flags, cdac_data::Flags) CDAC_TYPE_FIELD(NativeCodeVersionNode, /*nuint*/, ILVersionId, cdac_data::ILVersionId) -#ifdef FEATURE_TIERED_COMPILATION -CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, OptimizationTier, cdac_data::OptimizationTier) -#endif // FEATURE_TIERED_COMPILATION -CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, NativeId, cdac_data::NativeId) #ifdef HAVE_GCCOVER CDAC_TYPE_FIELD(NativeCodeVersionNode, /*pointer*/, GCCoverageInfo, cdac_data::GCCoverageInfo) #endif // HAVE_GCCOVER CDAC_TYPE_END(NativeCodeVersionNode) -CDAC_TYPE_BEGIN(NativeCodeVersion) -CDAC_TYPE_INDETERMINATE(NativeCodeVersion) -CDAC_TYPE_FIELD(NativeCodeVersion, /*uint32*/, StorageKind, cdac_data::StorageKind) -CDAC_TYPE_FIELD(NativeCodeVersion, /*pointer*/, MethodDescOrNode, cdac_data::MethodDescOrNode) -CDAC_TYPE_END(NativeCodeVersion) - CDAC_TYPE_BEGIN(ILCodeVersionNode) CDAC_TYPE_INDETERMINATE(ILCodeVersionNode) CDAC_TYPE_FIELD(ILCodeVersionNode, /*nuint*/, VersionId, cdac_data::VersionId) diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index 8439b690240a5a..8d4cf680e79fa1 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -702,10 +702,6 @@ template<> struct cdac_data { static constexpr size_t JitMinOpts = offsetof(EEConfig, fJitMinOpts); static constexpr size_t Debuggable = offsetof(EEConfig, fDebuggable); -#if defined(FEATURE_PGO) - static constexpr size_t TieredPGO = offsetof(EEConfig, fTieredPGO); - static constexpr size_t TieredPGO_InstrumentOnlyHotCode = offsetof(EEConfig, tieredPGO_InstrumentOnlyHotCode); -#endif }; diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 03a6ef681fb276..eaf327588f9a99 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -912,9 +912,6 @@ struct cdac_data static constexpr size_t LowFrequencyHeap = offsetof(LoaderAllocator, m_pLowFrequencyHeap); static constexpr size_t StubHeap = offsetof(LoaderAllocator, m_pStubHeap); static constexpr size_t ObjectHandle = offsetof(LoaderAllocator, m_hLoaderAllocatorObjectHandle); -#ifdef FEATURE_TIERED_COMPILATION - static constexpr size_t CallCountingManager = offsetof(LoaderAllocator, m_callCountingManager); -#endif // FEATURE_TIERED_COMPILATION }; typedef VPTR(LoaderAllocator) PTR_LoaderAllocator; diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 93920ad4975114..5eee80e5504876 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -253,6 +253,20 @@ HRESULT MethodDesc::SetMethodDescVersionState(PTR_MethodDescVersioningState stat return S_OK; } +HRESULT MethodDesc::SetMethodDescOptimizationTier(NativeCodeVersion::OptimizationTier tier) +{ + WRAPPER_NO_CONTRACT; + + HRESULT hr; + IfFailRet(EnsureCodeDataExists(NULL)); + + _ASSERTE(m_codeData != NULL); + if (InterlockedExchangeT(&m_codeData->OptimizationTier, tier) != NativeCodeVersion::OptimizationTierUnknown) + return S_FALSE; + + return S_OK; +} + #ifdef FEATURE_INTERPRETER // Set the call stub for the interpreter to JIT/AOT calls // Returns true if the current call set the stub, false if it was already set @@ -288,6 +302,15 @@ PTR_MethodDescVersioningState MethodDesc::GetMethodDescVersionState() return VolatileLoadWithoutBarrier(&codeData->VersioningState); } +NativeCodeVersion::OptimizationTier MethodDesc::GetMethodDescOptimizationTier() +{ + WRAPPER_NO_CONTRACT; + PTR_MethodDescCodeData codeData = VolatileLoadWithoutBarrier(&m_codeData); + if (codeData == NULL) + return NativeCodeVersion::OptimizationTierUnknown; + return VolatileLoadWithoutBarrier(&codeData->OptimizationTier); +} + //******************************************************************************* LPCUTF8 MethodDesc::GetNameThrowing() { @@ -2766,6 +2789,7 @@ void MethodDesc::EnsureTemporaryEntryPointCore(AllocMemTracker *pamTracker) #endif // FEATURE_PORTABLE_ENTRYPOINTS IfFailThrow(EnsureCodeDataExists(pamTracker)); + InterlockedExchangeT(&m_codeData->OptimizationTier, NativeCodeVersion::OptimizationTierUnknown); if (InterlockedCompareExchangeT(&m_codeData->TemporaryEntryPoint, entryPoint, (PCODE)NULL) == (PCODE)NULL) amt.SuppressRelease(); // We only need to suppress the release if we are working with a MethodDesc which is not newly allocated diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 07683f725f4a8d..0e55272432b1d0 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -239,6 +239,7 @@ struct MethodDescCodeData final #ifdef FEATURE_INTERPRETER CallStubHeader *CallStub; #endif // FEATURE_INTERPRETER + NativeCodeVersion::OptimizationTier OptimizationTier; }; using PTR_MethodDescCodeData = DPTR(MethodDescCodeData); @@ -1844,6 +1845,7 @@ class MethodDesc HRESULT EnsureCodeDataExists(AllocMemTracker *pamTracker); HRESULT SetMethodDescVersionState(PTR_MethodDescVersioningState state); + HRESULT SetMethodDescOptimizationTier(NativeCodeVersion::OptimizationTier tier); #ifdef FEATURE_INTERPRETER bool SetCallStub(CallStubHeader *pHeader); CallStubHeader *GetCallStub(); @@ -1852,6 +1854,7 @@ class MethodDesc #endif //!DACCESS_COMPILE PTR_MethodDescVersioningState GetMethodDescVersionState(); + NativeCodeVersion::OptimizationTier GetMethodDescOptimizationTier(); public: inline DWORD GetClassification() const diff --git a/src/coreclr/vm/tieredcompilation.cpp b/src/coreclr/vm/tieredcompilation.cpp index 5a66f26ef328b3..fc20c56f6a26f1 100644 --- a/src/coreclr/vm/tieredcompilation.cpp +++ b/src/coreclr/vm/tieredcompilation.cpp @@ -91,25 +91,27 @@ NativeCodeVersion::OptimizationTier TieredCompilationManager::GetInitialOptimiza { WRAPPER_NO_CONTRACT; _ASSERTE(pMethodDesc != NULL); - + NativeCodeVersion::OptimizationTier initialTier = pMethodDesc->GetMethodDescOptimizationTier(); + if (initialTier != NativeCodeVersion::OptimizationTierUnknown) + { + return initialTier; + } #ifdef FEATURE_TIERED_COMPILATION if (!pMethodDesc->IsEligibleForTieredCompilation()) { // The optimization tier is not used - return NativeCodeVersion::OptimizationTierOptimized; + initialTier = NativeCodeVersion::OptimizationTierOptimized; } - _ASSERT(!pMethodDesc->RequestedAggressiveOptimization()); - - if (!pMethodDesc->GetLoaderAllocator()->GetCallCountingManager()->IsCallCountingEnabled(NativeCodeVersion(pMethodDesc))) + else if (!pMethodDesc->GetLoaderAllocator()->GetCallCountingManager()->IsCallCountingEnabled(NativeCodeVersion(pMethodDesc))) { // Tier 0 call counting may have been disabled for several reasons, the intention is to start with and stay at an // optimized tier - return NativeCodeVersion::OptimizationTierOptimized; + initialTier = NativeCodeVersion::OptimizationTierOptimized; } #ifdef FEATURE_PGO - if (g_pConfig->TieredPGO()) + else if (g_pConfig->TieredPGO()) { // Initial tier for R2R is always just OptimizationTier0 // For ILOnly it depends on TieredPGO_InstrumentOnlyHotCode: @@ -118,16 +120,23 @@ NativeCodeVersion::OptimizationTier TieredCompilationManager::GetInitialOptimiza if (g_pConfig->TieredPGO_InstrumentOnlyHotCode() || ExecutionManager::IsReadyToRunCode(pMethodDesc->GetNativeCode())) { - return NativeCodeVersion::OptimizationTier0; + initialTier = NativeCodeVersion::OptimizationTier0; + } + else + { + initialTier = NativeCodeVersion::OptimizationTier0Instrumented; } - return NativeCodeVersion::OptimizationTier0Instrumented; } -#endif - - return NativeCodeVersion::OptimizationTier0; +#endif // FEATURE_PGO + else + initialTier = NativeCodeVersion::OptimizationTier0; #else - return NativeCodeVersion::OptimizationTierOptimized; -#endif + initialTier = NativeCodeVersion::OptimizationTierOptimized; +#endif // FEATURE_TIERED_COMPILATION +#ifndef DACCESS_COMPILE + pMethodDesc->SetMethodDescOptimizationTier(initialTier); +#endif // DACCESS_COMPILE + return initialTier; } bool TieredCompilationManager::IsTieringDelayActive() diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs index 321296ec2c4e72..8b2562b99c7d33 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs @@ -9,6 +9,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; public interface ICodeVersions : IContract { static string IContract.Name { get; } = nameof(CodeVersions); + public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); public virtual ILCodeVersionHandle GetILCodeVersion(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); @@ -24,6 +25,7 @@ public interface ICodeVersions : IContract public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); public virtual TargetPointer GetGCStressCodeCopy(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException(); public virtual TargetPointer GetIL(ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs index d0bab39c9d56a1..357d39f2db166a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -41,9 +41,6 @@ public enum DataType SystemDomain, Assembly, LoaderAllocator, - CallCountingManager, - CallCountingInfo, - NativeCodeVersion, PEAssembly, AssemblyBinder, PEImage, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index ffa6ecbc527a9e..7c3ff205309c27 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -234,69 +234,6 @@ TargetPointer ICodeVersions.GetGCStressCodeCopy(NativeCodeVersionHandle codeVers } } - private enum NativeStorageKind - { - Unknown = 0, - Explicit = 1, - Synthetic = 2 - }; - - internal sealed class CodeVersionHashTraits : ITraits - { - private readonly Target _target; - public CodeVersionHashTraits(Target target) - { - _target = target; - } - public NativeCodeVersionHandle GetKey(CallCountingInfo entry) - { - if (entry.CodeVersion == TargetPointer.Null) - { - return NativeCodeVersionHandle.Invalid; - } - - Data.NativeCodeVersion codeVersion = _target.ProcessedData.GetOrAdd(entry.CodeVersion); - switch ((NativeStorageKind)codeVersion.StorageKind) - { - case NativeStorageKind.Explicit: - return NativeCodeVersionHandle.CreateExplicit(codeVersion.MethodDescOrNode); - case NativeStorageKind.Synthetic: - return NativeCodeVersionHandle.CreateSynthetic(codeVersion.MethodDescOrNode); - default: - throw new InvalidOperationException($"Unknown NativeCodeVersionKind {codeVersion.StorageKind}"); - } - } - public bool Equals(NativeCodeVersionHandle left, NativeCodeVersionHandle right) - { - if (!left.Valid || !right.Valid) - return !left.Valid && !right.Valid; - - if (left.IsExplicit != right.IsExplicit) - return false; - - if (left.IsExplicit) - return left.CodeVersionNodeAddress == right.CodeVersionNodeAddress; - return left.MethodDescAddress == right.MethodDescAddress; - } - public uint Hash(NativeCodeVersionHandle key) - { - if (!key.Valid) - { - return 0; - } - - if (key.IsExplicit) - { - return (uint)key.CodeVersionNodeAddress; - } - NativeCodeVersionNode node = _target.ProcessedData.GetOrAdd(key.CodeVersionNodeAddress); - return (uint)(node.NativeId + node.MethodDesc); - } - public bool IsNull(CallCountingInfo entry) => entry.Address == TargetPointer.Null; - public CallCountingInfo Null() => new CallCountingInfo(TargetPointer.Null); - public bool IsDeleted(CallCountingInfo entry) => false; - } - [Flags] internal enum MethodDescVersioningStateFlags : byte { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs index 5cd329ecdb808e..8d69952db08be1 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs @@ -38,25 +38,15 @@ public enum RejitFlags : uint [Flags] private enum NativeOptimizationTier : uint { - Tier0 = 0, - Tier1 = 1, - Tier1OSR = 2, - TierOptimized = 3, - Tier0Instrumented = 4, - Tier1Instrumented = 5, + OptimizationTier0 = 0, + OptimizationTier1 = 1, + OptimizationTier1OSR = 2, + OptimizationTierOptimized = 3, + OptimizationTier0Instrumented = 4, + OptimizationTier1Instrumented = 5, + OptimizationTierUnknown = 0xffffffff }; - - public enum CallCountingStage : byte - { - StubIsNotActive = 0, - StubMayBeActive = 1, - PendingCompletion = 2, - Complete = 3, - Disabled = 4 - }; - - public ReJIT_1(Target target, Data.ProfControlBlock profControlBlock) { _target = target; @@ -100,96 +90,25 @@ TargetNUInt IReJIT.GetRejitId(ILCodeVersionHandle ilCodeVersionHandle) return ilCodeVersionNode.VersionId; } - private sealed class CodeVersionHashTraits : ITraits - { - private readonly Target _target; - public CodeVersionHashTraits(Target target) - { - _target = target; - } - public NativeCodeVersion GetKey(CallCountingInfo entry) - { - return _target.ProcessedData.GetOrAdd(entry.CodeVersion); - } - public bool Equals(NativeCodeVersion left, NativeCodeVersion right) => left.StorageKind == right.StorageKind && left.MethodDescOrNode == right.MethodDescOrNode; - public uint Hash(NativeCodeVersion key) - { - switch (key.StorageKind) - { - case 1: - return (uint)key.MethodDescOrNode; - case 2: - NativeCodeVersionNode node = _target.ProcessedData.GetOrAdd(key.MethodDescOrNode); - return (uint)node.MethodDesc + node.NativeId; - default: - throw new NotSupportedException(); - } - } - public bool IsNull(CallCountingInfo entry) => entry.Address == TargetPointer.Null; - public CallCountingInfo Null() => new CallCountingInfo(TargetPointer.Null); - public bool IsDeleted(CallCountingInfo entry) => false; - } - - private sealed class CallCountingTable : IData - { - static CallCountingTable IData.Create(Target target, TargetPointer address) - => new CallCountingTable(target, address); - - public CallCountingTable(Target target, TargetPointer address) - { - ISHash sHashContract = target.Contracts.SHash; - Target.TypeInfo type = target.GetTypeInfo(DataType.CallCountingInfo); - HashTable = sHashContract.CreateSHash(target, address, type, new CodeVersionHashTraits(target)); - } - public ISHash HashTable { get; init; } - } - private bool IsCallCountingEnabled(MethodDescHandle mdh) - { - // get loader allocator - Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; - Contracts.ILoader loaderContract = _target.Contracts.Loader; - TargetPointer mt = rtsContract.GetMethodTable(mdh); - TargetPointer modulePtr = rtsContract.GetLoaderModule(rtsContract.GetTypeHandle(mt)); - Contracts.ModuleHandle moduleHandle = loaderContract.GetModuleHandleFromModulePtr(modulePtr); - TargetPointer loaderAllocator = loaderContract.GetLoaderAllocator(moduleHandle); - Data.LoaderAllocator loaderAllocatorData = _target.ProcessedData.GetOrAdd(loaderAllocator); - - // get call counting manager and hash - TargetPointer callCountingMgr = loaderAllocatorData.CallCountingManager!.Value; - TargetPointer callCountingHash = _target.ProcessedData.GetOrAdd(callCountingMgr).CallCountingHash; - CallCountingTable callCountingTable = _target.ProcessedData.GetOrAdd(callCountingHash); - - ISHash shashContract = _target.Contracts.SHash; - CallCountingInfo entry = shashContract.LookupSHash(callCountingTable.HashTable, new NativeCodeVersion(2, mdh.Address)); - return entry.Address != TargetPointer.Null && entry.Stage != (byte)CallCountingStage.Disabled; - } - private NativeOptimizationTier GetInitialOptimizationTier(bool isReadyToRun, MethodDescHandle mdh) + private NativeOptimizationTier GetInitialOptimizationTier(TargetPointer mdPointer) { - if (_target.ReadGlobal(Constants.Globals.FeatureTieredCompilation) == 0 - || !IsCallCountingEnabled(mdh)) - return NativeOptimizationTier.TierOptimized; - Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); - if (eeConfig.TieredPGO!.Value) - { - if (eeConfig.TieredPGO_InstrumentOnlyHotCode!.Value || isReadyToRun) - return NativeOptimizationTier.Tier0; - else - return NativeOptimizationTier.Tier0Instrumented; - } - else - return NativeOptimizationTier.Tier0; + // validation of the method desc + MethodDescHandle _ = _target.Contracts.RuntimeTypeSystem.GetMethodDescHandle(mdPointer); + Data.MethodDesc md = _target.ProcessedData.GetOrAdd(mdPointer); + Data.MethodDescCodeData codeData = _target.ProcessedData.GetOrAdd(md.CodeData); + return (NativeOptimizationTier)codeData.OptimizationTier; } private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier nativeOptimizationTier) { return nativeOptimizationTier switch { - NativeOptimizationTier.Tier0 => OptimizationTierEnum.QuickJitted, - NativeOptimizationTier.Tier1 => OptimizationTierEnum.OptimizedTier1, - NativeOptimizationTier.Tier1OSR => OptimizationTierEnum.OptimizedTier1OSR, - NativeOptimizationTier.TierOptimized => OptimizationTierEnum.Optimized, - NativeOptimizationTier.Tier0Instrumented => OptimizationTierEnum.QuickJittedInstrumented, - NativeOptimizationTier.Tier1Instrumented => OptimizationTierEnum.OptimizedTier1Instrumented, + NativeOptimizationTier.OptimizationTier0 => OptimizationTierEnum.QuickJitted, + NativeOptimizationTier.OptimizationTier1 => OptimizationTierEnum.OptimizedTier1, + NativeOptimizationTier.OptimizationTier1OSR => OptimizationTierEnum.OptimizedTier1OSR, + NativeOptimizationTier.OptimizationTierOptimized => OptimizationTierEnum.Optimized, + NativeOptimizationTier.OptimizationTier0Instrumented => OptimizationTierEnum.QuickJittedInstrumented, + NativeOptimizationTier.OptimizationTier1Instrumented => OptimizationTierEnum.OptimizedTier1Instrumented, _ => OptimizationTierEnum.Unknown, }; } @@ -232,7 +151,7 @@ private static OptimizationTierEnum GetOptimizationTier(NativeOptimizationTier n { NativeOptimizationTier optTier; if (!nativeCodeVersionHandle.IsExplicit) - optTier = GetInitialOptimizationTier(isReadyToRun, mdh); + optTier = GetInitialOptimizationTier(nativeCodeVersionHandle.MethodDescAddress); else { NativeCodeVersionNode nativeCodeVersionNode = AsNode(nativeCodeVersionHandle); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 4fa0ec9b525f0b..ae2e88e5e51c9e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -114,7 +114,6 @@ internal struct MethodDesc internal TargetPointer Address { get; init; } internal TargetPointer ChunkAddress { get; init; } - internal bool IsJitOptimizationDisabledForSpecificMethod { get; init; } internal MethodDesc(Target target, TargetPointer methodDescPointer, Data.MethodDesc desc, TargetPointer methodDescChunkAddress, Data.MethodDescChunk chunk) { @@ -133,6 +132,7 @@ internal MethodDesc(Target target, TargetPointer methodDescPointer, Data.MethodD public ushort Slot => _desc.Slot; public uint Token { get; } public uint Size { get; } + internal bool IsJitOptimizationDisabledForSpecificMethod { get; } private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.MethodDescChunk chunk) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingInfo.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingInfo.cs deleted file mode 100644 index c0a9a2e84df2da..00000000000000 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingInfo.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.Diagnostics.DataContractReader.Data; - -internal sealed class CallCountingInfo : IData -{ - static CallCountingInfo IData.Create(Target target, TargetPointer address) - => new CallCountingInfo(target, address); - - public CallCountingInfo(Target target, TargetPointer address) - { - Target.TypeInfo type = target.GetTypeInfo(DataType.CallCountingInfo); - - Stage = target.Read(address + (ulong)type.Fields[nameof(Stage)].Offset); - CodeVersion = target.ReadPointer(address + (ulong)type.Fields[nameof(CodeVersion)].Offset); - Address = address; - } - - public CallCountingInfo(TargetPointer address) - { - Address = address; - } - - public byte Stage { get; init; } - public TargetPointer CodeVersion { get; init; } - public TargetPointer Address { get; init; } -} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingManager.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingManager.cs deleted file mode 100644 index 66725a24b4b77f..00000000000000 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CallCountingManager.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.Diagnostics.DataContractReader.Data; - -internal sealed class CallCountingManager : IData -{ - static CallCountingManager IData.Create(Target target, TargetPointer address) - => new CallCountingManager(target, address); - - public CallCountingManager(Target target, TargetPointer address) - { - Target.TypeInfo type = target.GetTypeInfo(DataType.CallCountingManager); - - CallCountingHash = address + (ulong)type.Fields[nameof(CallCountingHash)].Offset; - } - - public TargetPointer CallCountingHash { get; init; } -} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs index 9d60ae27b51413..9a64d483dc8d09 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs @@ -12,14 +12,8 @@ public EEConfig(Target target, TargetPointer address) JitMinOpts = target.Read(address + (ulong)type.Fields[nameof(JitMinOpts)].Offset) != 0; Debuggable = target.Read(address + (ulong)type.Fields[nameof(Debuggable)].Offset) != 0; - if (type.Fields.ContainsKey(nameof(TieredPGO))) - TieredPGO = target.Read(address + (ulong)type.Fields[nameof(TieredPGO)].Offset) != 0; - if (type.Fields.ContainsKey(nameof(TieredPGO_InstrumentOnlyHotCode))) - TieredPGO_InstrumentOnlyHotCode = target.Read(address + (ulong)type.Fields[nameof(TieredPGO_InstrumentOnlyHotCode)].Offset) != 0; } public bool JitMinOpts { get; init; } public bool Debuggable { get; init; } - public bool? TieredPGO { get; init; } - public bool? TieredPGO_InstrumentOnlyHotCode { get; init; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs index bd9102b78247a5..c00af4c5264f06 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/LoaderAllocator.cs @@ -18,10 +18,6 @@ public LoaderAllocator(Target target, TargetPointer address) StubHeap = target.ReadPointer(address + (ulong)type.Fields[nameof(StubHeap)].Offset); ObjectHandle = target.ProcessedData.GetOrAdd( target.ReadPointer(address + (ulong)type.Fields[nameof(ObjectHandle)].Offset)); - if (type.Fields.ContainsKey(nameof(CallCountingManager))) - { - CallCountingManager = target.ReadPointer(address + (ulong)type.Fields[nameof(CallCountingManager)].Offset); - } } public uint ReferenceCount { get; init; } @@ -29,7 +25,6 @@ public LoaderAllocator(Target target, TargetPointer address) public TargetPointer LowFrequencyHeap { get; init; } public TargetPointer StubHeap { get; init; } public ObjectHandle ObjectHandle { get; init; } - public TargetPointer? CallCountingManager { get; init; } public bool IsAlive => ReferenceCount != 0; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/MethodDescCodeData.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/MethodDescCodeData.cs index dc76b8981b6101..fdce2c5c9c7591 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/MethodDescCodeData.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/MethodDescCodeData.cs @@ -13,8 +13,10 @@ public MethodDescCodeData(Target target, TargetPointer address) TemporaryEntryPoint = target.ReadCodePointer(address + (ulong)type.Fields[nameof(TemporaryEntryPoint)].Offset); VersioningState = target.ReadPointer(address + (ulong)type.Fields[nameof(VersioningState)].Offset); + OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); } public TargetCodePointer TemporaryEntryPoint { get; set; } public TargetPointer VersioningState { get; set; } + public uint OptimizationTier { get; set; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersion.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersion.cs deleted file mode 100644 index ec3149dcd467fb..00000000000000 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersion.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -namespace Microsoft.Diagnostics.DataContractReader.Data; - -internal sealed class NativeCodeVersion : IData -{ - static NativeCodeVersion IData.Create(Target target, TargetPointer address) => new NativeCodeVersion(target, address); - public NativeCodeVersion(Target target, TargetPointer address) - { - Target.TypeInfo type = target.GetTypeInfo(DataType.NativeCodeVersion); - - StorageKind = target.Read(address + (ulong)type.Fields[nameof(StorageKind)].Offset); - MethodDescOrNode = target.ReadPointer(address + (ulong)type.Fields[nameof(MethodDescOrNode)].Offset); - } - - public NativeCodeVersion(uint storageKind, TargetPointer methodDescOrNode) - { - StorageKind = storageKind; - MethodDescOrNode = methodDescOrNode; - } - - public uint StorageKind { get; init; } - public TargetPointer MethodDescOrNode { get; init; } -} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs index 4774a9f2739c80..0c936b499612d3 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/NativeCodeVersionNode.cs @@ -21,7 +21,6 @@ public NativeCodeVersionNode(Target target, TargetPointer address) { OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); } - NativeId = target.Read(address + (ulong)type.Fields[nameof(NativeId)].Offset); if (type.Fields.ContainsKey(nameof(GCCoverageInfo))) { GCCoverageInfo = target.ReadPointer(address + (ulong)type.Fields[nameof(GCCoverageInfo)].Offset); @@ -36,7 +35,6 @@ public NativeCodeVersionNode(Target target, TargetPointer address) public uint Flags { get; init; } public TargetNUInt ILVersionId { get; init; } public uint? OptimizationTier { get; init; } - public uint NativeId { get; init; } public TargetPointer? GCCoverageInfo { get; init; } public TargetPointer Address { get; init; } diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs index fc687002ae6102..5430ac4492addb 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs @@ -23,7 +23,8 @@ public class CodeVersions new(nameof(Data.MethodDescVersioningState.Flags), DataType.uint8), ] }; - // note: we aren't testing this on wasm so we can go ahead and include both OptimizationTier and NativeId + + // note: we aren't testing this on wasm so we can go ahead and include OptimizationTier private static readonly TypeFields NativeCodeVersionNodeFields = new TypeFields() { DataType = DataType.NativeCodeVersionNode, @@ -35,7 +36,6 @@ public class CodeVersions new(nameof(Data.NativeCodeVersionNode.Flags), DataType.uint32), new(nameof(Data.NativeCodeVersionNode.ILVersionId), DataType.nuint), new(nameof(Data.NativeCodeVersionNode.OptimizationTier), DataType.uint32), - new(nameof(Data.NativeCodeVersionNode.NativeId), DataType.uint32), new(nameof(Data.NativeCodeVersionNode.GCCoverageInfo), DataType.pointer), ] }; From 777e93de97a96f0f34c5c31b0be08a68a38b2e91 Mon Sep 17 00:00:00 2001 From: Rachel Date: Sat, 20 Sep 2025 13:08:29 -0700 Subject: [PATCH 13/13] Fix formatting in ReJIT.md --- docs/design/datacontracts/ReJIT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/datacontracts/ReJIT.md b/docs/design/datacontracts/ReJIT.md index 0ebcf397daa7fd..c32a10d5d11147 100644 --- a/docs/design/datacontracts/ReJIT.md +++ b/docs/design/datacontracts/ReJIT.md @@ -47,7 +47,7 @@ Data descriptors used: | ILCodeVersionNode | VersionId | `ILCodeVersion` ReJIT ID | ILCodeVersionNode | RejitState | a `RejitFlags` value | | MethodDesc | CodeData | Pointer to CodeData (additional info about native code) | -| MethodDescCodeData | OptimizationTier | Optimization tier of default native code version | +| MethodDescCodeData | OptimizationTier | Optimization tier of default native code version | Global variables used: | Global Name | Type | Purpose |