From c36b15544475987834059e004ee93c79acc7633c Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Wed, 25 Mar 2026 11:43:58 -0700 Subject: [PATCH 01/11] Implement GetTieredVersions for cDAC --- src/coreclr/vm/codeversion.h | 3 + .../vm/datadescriptor/datadescriptor.inc | 13 ++ src/coreclr/vm/eeconfig.h | 12 +- .../Contracts/ICodeVersions.cs | 13 ++ .../Contracts/ILoader.cs | 10 ++ .../Contracts/IRuntimeTypeSystem.cs | 11 ++ .../DataType.cs | 1 + .../Constants.cs | 2 + .../Contracts/CodeVersions_1.cs | 27 ++++ .../Contracts/Loader_1.cs | 17 +++ .../Contracts/RuntimeTypeSystem_1.cs | 80 ++++++++++++ .../Data/EEConfig.cs | 23 ++++ .../Data/MethodDescCodeData.cs | 5 + .../Data/NativeCodeVersionNode.cs | 5 + .../ISOSDacInterface.cs | 22 +++- .../SOSDacImpl.cs | 111 ++++++++++++++++- .../managed/cdac/tests/CodeVersionsTests.cs | 117 ++++++++++++++++++ .../MockDescriptors.CodeVersions.cs | 7 +- 18 files changed, 474 insertions(+), 5 deletions(-) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 990085695f5345..50c4b82e28fd2d 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -340,6 +340,9 @@ struct cdac_data #ifdef HAVE_GCCOVER static constexpr size_t GCCoverageInfo = offsetof(NativeCodeVersionNode, m_gcCover); #endif // HAVE_GCCOVER +#ifdef FEATURE_TIERED_COMPILATION + static constexpr size_t OptimizationTier = offsetof(NativeCodeVersionNode, m_optTier); +#endif // FEATURE_TIERED_COMPILATION }; class NativeCodeVersionCollection diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 3e7993b5dbb078..300fe56343d51b 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -600,6 +600,7 @@ CDAC_TYPE_INDETERMINATE(MethodDescCodeData) CDAC_TYPE_FIELD(MethodDescCodeData, /*CodePointer*/, TemporaryEntryPoint, offsetof(MethodDescCodeData,TemporaryEntryPoint)) #ifdef FEATURE_CODE_VERSIONING CDAC_TYPE_FIELD(MethodDescCodeData, /*pointer*/, VersioningState, offsetof(MethodDescCodeData,VersioningState)) +CDAC_TYPE_FIELD(MethodDescCodeData, /*uint32*/, OptimizationTier, offsetof(MethodDescCodeData,OptimizationTier)) #endif // FEATURE_CODE_VERSIONING CDAC_TYPE_END(MethodDescCodeData) @@ -845,6 +846,9 @@ CDAC_TYPE_FIELD(NativeCodeVersionNode, /*nuint*/, ILVersionId, cdac_data::GCCoverageInfo) #endif // HAVE_GCCOVER +#ifdef FEATURE_TIERED_COMPILATION +CDAC_TYPE_FIELD(NativeCodeVersionNode, /*uint32*/, OptimizationTier, cdac_data::OptimizationTier) +#endif // FEATURE_TIERED_COMPILATION CDAC_TYPE_END(NativeCodeVersionNode) CDAC_TYPE_BEGIN(ILCodeVersionNode) @@ -1240,6 +1244,13 @@ CDAC_TYPE_FIELD(WebcilSectionHeader, /*uint32*/, PointerToRawData, offsetof(Webc CDAC_TYPE_END(WebcilSectionHeader) #endif +CDAC_TYPE_BEGIN(EEConfig) +CDAC_TYPE_INDETERMINATE(EEConfig) +CDAC_TYPE_FIELD(EEConfig, /*uint8*/, JitMinOpts, cdac_data::JitMinOpts) +CDAC_TYPE_FIELD(EEConfig, /*uint8*/, GenDebuggable, cdac_data::GenDebuggable) +CDAC_TYPE_FIELD(EEConfig, /*uint32*/, TieredCompilation_DefaultTier, cdac_data::TieredCompilation_DefaultTier) +CDAC_TYPE_END(EEConfig) + CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() @@ -1285,6 +1296,7 @@ CDAC_GLOBAL_STRING(RID, RID_STRING) CDAC_GLOBAL(GCInfoVersion, uint32, GCINFO_VERSION) +CDAC_GLOBAL_POINTER(EEConfig, &::g_pConfig) CDAC_GLOBAL_POINTER(AppDomain, &AppDomain::m_pTheAppDomain) CDAC_GLOBAL_POINTER(SystemDomain, cdac_data::SystemDomainPtr) CDAC_GLOBAL_POINTER(ThreadStore, &ThreadStore::s_pThreadStore) @@ -1299,6 +1311,7 @@ CDAC_GLOBAL_POINTER(GCThread, &::g_pSuspensionThread) #undef FRAME_TYPE_NAME CDAC_GLOBAL(MethodDescTokenRemainderBitCount, uint8, METHOD_TOKEN_REMAINDER_BIT_COUNT) +CDAC_GLOBAL_POINTER(CORDebuggerControlFlags, &g_CORDebuggerControlFlags) #if FEATURE_COMINTEROP CDAC_GLOBAL(FeatureCOMInterop, uint8, 1) #else diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index fecb76eb69fb41..28b54665e80ceb 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -96,7 +96,7 @@ class EEConfig bool TieredCompilation_UseCallCountingStubs() const { LIMITED_METHOD_CONTRACT; return fTieredCompilation_UseCallCountingStubs; } DWORD TieredCompilation_DeleteCallCountingStubsAfter() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_DeleteCallCountingStubsAfter; } #endif // FEATURE_TIERED_COMPILATION - DWORD TieredCompilation_DefaultTier() const + DWORD TieredCompilation_DefaultTier() const { LIMITED_METHOD_CONTRACT; return tieredCompilation_DefaultTier; @@ -713,6 +713,16 @@ 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 GenDebuggable = offsetof(EEConfig, fDebuggable); + static constexpr size_t TieredCompilation_DefaultTier = offsetof(EEConfig, tieredCompilation_DefaultTier); }; 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 e406b26df6bc82..8ec9054fa40b23 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 @@ -30,6 +30,8 @@ public interface ICodeVersions : IContract public virtual TargetPointer GetIL(ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); public virtual bool HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); + public virtual NativeCodeVersionOptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle) + => throw new NotImplementedException(); } public readonly struct ILCodeVersionHandle @@ -100,3 +102,14 @@ public static NativeCodeVersionHandle CreateSynthetic(TargetPointer methodDescAd { // throws NotImplementedException for all methods } + +public enum NativeCodeVersionOptimizationTier : uint +{ + OptimizationTier0, + OptimizationTier1, + OptimizationTier1OSR, + OptimizationTierOptimized, + OptimizationTier0Instrumented, + OptimizationTier1Instrumented, + OptimizationTierUnknown = 0xFFFFFFFF +} 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 11593d1b302e1a..d9b39adf4a526c 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 @@ -22,6 +22,14 @@ public enum ModuleFlags 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 + ProfilerDisableOpt = 0x80, // Profiler disabled JIT optimizations when module was loaded +} + +[Flags] +public enum DebuggerAssemblyControlFlags +{ + DACF_USER_OVERRIDE = 0x01, + DACF_ALLOW_JIT_OPTS = 0x02, } [Flags] @@ -75,6 +83,8 @@ public interface ILoader : IContract bool IsProbeExtensionResultValid(ModuleHandle handle) => throw new NotImplementedException(); ModuleFlags GetFlags(ModuleHandle handle) => throw new NotImplementedException(); + bool IsReadyToRun(ModuleHandle handle) => throw new NotImplementedException(); + DebuggerAssemblyControlFlags GetDebuggerInfoBits(ModuleHandle handle) => throw new NotImplementedException(); bool TryGetSimpleName(ModuleHandle handle, out string simpleName) => throw new NotImplementedException(); string GetPath(ModuleHandle handle) => throw new NotImplementedException(); string GetFileName(ModuleHandle handle) => 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 19f20929911633..067bc745c1a55d 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 @@ -78,6 +78,12 @@ public enum ArrayFunctionType Constructor = 3 } +[Flags] +public enum DebuggerControlFlag +{ + DBCF_ALLOW_JIT_OPT = 0x0008, +} + public interface IRuntimeTypeSystem : IContract { static string IContract.Name => nameof(RuntimeTypeSystem); @@ -204,6 +210,11 @@ public interface IRuntimeTypeSystem : IContract TargetPointer GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc) => throw new NotImplementedException(); TargetPointer GetGCStressCodeCopy(MethodDescHandle methodDesc) => throw new NotImplementedException(); + + NativeCodeVersionOptimizationTier GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); + NativeCodeVersionOptimizationTier GetInitialOptimizationTier(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); + bool IsEligibleForTieredCompilation(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); + bool IsJitOptimizationDisabled(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); #endregion MethodDesc inspection APIs #region FieldDesc inspection APIs TargetPointer GetMTOfEnclosingClass(TargetPointer fieldDescPointer) => 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 89f9f2e5559378..266437e05ad46e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -135,6 +135,7 @@ public enum DataType PatchpointInfo, PortableEntryPoint, VirtualCallStubManager, + EEConfig, TransitionBlock, DebuggerEval, 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 eafeb8137df884..e97ed6e9ed53b1 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -73,6 +73,7 @@ public static class Globals public const string SizeOfGenericModeBlock = nameof(SizeOfGenericModeBlock); public const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount); + public const string CORDebuggerControlFlags = nameof(CORDebuggerControlFlags); public const string DirectorySeparator = nameof(DirectorySeparator); public const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); @@ -154,6 +155,7 @@ public static class Globals public const string HandlesPerBlock = nameof(HandlesPerBlock); public const string BlockInvalid = nameof(BlockInvalid); public const string TotalCpuCount = nameof(TotalCpuCount); + public const string EEConfig = nameof(EEConfig); } public static class FieldNames { 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 fc50c95ffbf16f..1fa1e3ed88b636 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 @@ -413,4 +413,31 @@ bool ICodeVersions.HasDefaultIL(ILCodeVersionHandle iLCodeVersionHandle) { return iLCodeVersionHandle.IsExplicit ? AsNode(iLCodeVersionHandle).ILAddress == TargetPointer.Null : true; } + + NativeCodeVersionOptimizationTier ICodeVersions.GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle) + { + if (!codeVersionHandle.Valid) + { + throw new ArgumentException("Invalid NativeCodeVersionHandle"); + } + + if (codeVersionHandle.IsExplicit) + { + NativeCodeVersionNode nativeCodeVersionNode = _target.ProcessedData.GetOrAdd(codeVersionHandle.CodeVersionNodeAddress); + return nativeCodeVersionNode.OptimizationTier is null + ? NativeCodeVersionOptimizationTier.OptimizationTierUnknown + : (NativeCodeVersionOptimizationTier) nativeCodeVersionNode.OptimizationTier; + } + else + { + IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle methodDescHandle = rtsContract.GetMethodDescHandle(codeVersionHandle.MethodDescAddress); + NativeCodeVersionOptimizationTier optimizationTier = rtsContract.GetMethodDescOptimizationTier(methodDescHandle); + if (optimizationTier == NativeCodeVersionOptimizationTier.OptimizationTierUnknown) + { + return rtsContract.GetInitialOptimizationTier(methodDescHandle); + } + return 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 1a80d73c95cc90..205087b405355d 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 @@ -14,6 +14,8 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; { private const string DefaultDomainFriendlyName = "DefaultDomain"; private const uint ASSEMBLY_NOTIFYFLAGS_PROFILER_NOTIFIED = 0x1; // Assembly Notify Flag for profiler notification + private const uint DEBUGGER_INFO_MASK_PRIV = 0x0000FC00; + private const int DEBUGGER_INFO_SHIFT_PRIV = 10; private const ushort MaxWebcilSections = 16; // Must stay in sync with native WEBCIL_MAX_SECTIONS. private enum ModuleFlags_1 : uint @@ -21,6 +23,7 @@ private enum ModuleFlags_1 : uint 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 + ProfilerDisableOpt = 0x80, // Profiler disabled JIT optimizations when module was loaded } private enum PEImageFlags : uint @@ -366,6 +369,8 @@ private static ModuleFlags GetFlags(Data.Module module) flags |= ModuleFlags.EditAndContinue; if (runtimeFlags.HasFlag(ModuleFlags_1.ReflectionEmit)) flags |= ModuleFlags.ReflectionEmit; + if (runtimeFlags.HasFlag(ModuleFlags_1.ProfilerDisableOpt)) + flags |= ModuleFlags.ProfilerDisableOpt; return flags; } @@ -376,6 +381,18 @@ ModuleFlags ILoader.GetFlags(ModuleHandle handle) return GetFlags(module); } + bool ILoader.IsReadyToRun(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return module.ReadyToRunInfo != TargetPointer.Null; + } + + DebuggerAssemblyControlFlags ILoader.GetDebuggerInfoBits(ModuleHandle handle) + { + Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); + return (DebuggerAssemblyControlFlags)((module.Flags & DEBUGGER_INFO_MASK_PRIV) >> DEBUGGER_INFO_SHIFT_PRIV); + } + bool ILoader.TryGetSimpleName(ModuleHandle handle, out string simpleName) { simpleName = string.Empty; 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 62279bd90c1172..623da0e34741a3 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 @@ -1629,6 +1629,86 @@ TargetPointer IRuntimeTypeSystem.GetGCStressCodeCopy(MethodDescHandle methodDesc return TargetPointer.Null; } + NativeCodeVersionOptimizationTier IRuntimeTypeSystem.GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) + { + MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + TargetPointer codeDataAddress = methodDesc.CodeData; + if (codeDataAddress == TargetPointer.Null) + return NativeCodeVersionOptimizationTier.OptimizationTierUnknown; + + Data.MethodDescCodeData codeData = _target.ProcessedData.GetOrAdd(codeDataAddress); + return codeData.OptimizationTier is null + ? NativeCodeVersionOptimizationTier.OptimizationTierUnknown + : (NativeCodeVersionOptimizationTier)codeData.OptimizationTier; + } + + bool IRuntimeTypeSystem.IsEligibleForTieredCompilation(MethodDescHandle methodDescHandle) + { + MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + return methodDesc.IsEligibleForTieredCompilation; + } + + private bool IsJitOptimizationDisabledForSpecificMethod(MethodDescHandle methodDescHandle) + { + MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(methodDesc); + ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(methodTable.Module); + MetadataReader? mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); + + bool isNoMetadata = methodDesc.Classification == MethodClassification.Dynamic; + bool isMiNoOptimization = false; + if (mdReader is not null) + { + MethodDefinitionHandle methodDefHandle = MetadataTokens.MethodDefinitionHandle((int)methodDesc.Token); + MethodDefinition methodDef = mdReader.GetMethodDefinition(methodDefHandle); + MethodImplAttributes implAttrs = methodDef.ImplAttributes; + isMiNoOptimization = (implAttrs & MethodImplAttributes.NoOptimization) != 0; + } + else if (!isNoMetadata) + { + throw new InvalidOperationException("Failed to get metadata for method"); + } + + return !isNoMetadata && isMiNoOptimization; + } + + private bool IsJitOptimizationDisabledForAllMethodsInChunk(MethodDescHandle methodDescHandle) + { + MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + MethodTable methodTable = GetOrCreateMethodTable(methodDesc); + ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(methodTable.Module); + DebuggerAssemblyControlFlags debuggerInfoBits = _target.Contracts.Loader.GetDebuggerInfoBits(moduleHandle); + DebuggerControlFlag corDebuggerControlFlags = (DebuggerControlFlag)_target.Read(_target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags)); + TargetPointer eeConfigPtr = _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); + Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(eeConfigPtr); + + bool corDebuggerAllowJITOpts = debuggerInfoBits.HasFlag(DebuggerAssemblyControlFlags.DACF_ALLOW_JIT_OPTS) + || (corDebuggerControlFlags.HasFlag(DebuggerControlFlag.DBCF_ALLOW_JIT_OPT) + && !debuggerInfoBits.HasFlag(DebuggerAssemblyControlFlags.DACF_USER_OVERRIDE)); + bool profilerDisabledOptimizations = _target.Contracts.Loader.GetFlags(moduleHandle).HasFlag(ModuleFlags.ProfilerDisableOpt); + bool areJITOptimizationsDisabled = !corDebuggerAllowJITOpts || profilerDisabledOptimizations; + + return eeConfig.JitMinOpts || eeConfig.GenDebuggable || areJITOptimizationsDisabled; + } + + bool IRuntimeTypeSystem.IsJitOptimizationDisabled(MethodDescHandle methodDescHandle) + { + return IsJitOptimizationDisabledForAllMethodsInChunk(methodDescHandle) || IsJitOptimizationDisabledForSpecificMethod(methodDescHandle); + } + + NativeCodeVersionOptimizationTier IRuntimeTypeSystem.GetInitialOptimizationTier(MethodDescHandle methodDescHandle) + { + MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; + if (!methodDesc.IsEligibleForTieredCompilation) + { + return NativeCodeVersionOptimizationTier.OptimizationTierOptimized; + } + + TargetPointer eeConfigPtr = _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); + Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(eeConfigPtr); + return (NativeCodeVersionOptimizationTier)eeConfig.TieredCompilation_DefaultTier; + } + private sealed class NonValidatedMethodTableQueries : MethodValidation.IMethodTableQueries { private readonly RuntimeTypeSystem_1 _rts; 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..6b9afa03a56bcb --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs @@ -0,0 +1,23 @@ +// 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; + GenDebuggable = target.Read(address + (ulong)type.Fields[nameof(GenDebuggable)].Offset) != 0; + TieredCompilation_DefaultTier = target.Read(address + (ulong)type.Fields[nameof(TieredCompilation_DefaultTier)].Offset); + } + + public bool JitMinOpts { get; init; } + public bool GenDebuggable { get; init; } + public uint TieredCompilation_DefaultTier { get; init; } +} 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..6cd0d58144c810 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,13 @@ 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); + if (type.Fields.ContainsKey(nameof(OptimizationTier))) + { + OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); + } } public TargetCodePointer TemporaryEntryPoint { get; set; } public TargetPointer VersioningState { get; set; } + public uint? OptimizationTier { 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 e68345e4499d23..55f79823fdf024 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,6 +21,10 @@ public NativeCodeVersionNode(Target target, TargetPointer address) { GCCoverageInfo = target.ReadPointer(address + (ulong)type.Fields[nameof(GCCoverageInfo)].Offset); } + if (type.Fields.ContainsKey(nameof(OptimizationTier))) + { + OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); + } } public TargetPointer Next { get; init; } @@ -31,4 +35,5 @@ public NativeCodeVersionNode(Target target, TargetPointer address) public TargetNUInt ILVersionId { get; init; } public TargetPointer? GCCoverageInfo { get; init; } + public uint? OptimizationTier { get; init; } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs index 4fca56fce16a90..fd1b858aae8b09 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs @@ -944,12 +944,32 @@ public unsafe partial interface ISOSDacInterface4 int GetClrNotification([In, Out, MarshalUsing(CountElementName = nameof(count))] ClrDataAddress[] arguments, int count, int* pNeeded); }; +public struct DacpTieredVersionData +{ + public enum OptimizationTier + { + Unknown, + MinOptJitted, + Optimized, + QuickJitted, + OptimizedTier1, + ReadyToRun, + OptimizedTier1OSR, + QuickJittedInstrumented, + OptimizedTier1Instrumented, + } + + public ClrDataAddress nativeCodeAddr; + public OptimizationTier optimizationTier; + public ClrDataAddress nativeCodeVersionNodePtr; +} + [GeneratedComInterface] [Guid("127d6abe-6c86-4e48-8e7b-220781c58101")] public 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); }; public struct DacpMethodTableCollectibleData diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 33cea4425e5c30..68d0d2dc2fcc64 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -4806,8 +4806,115 @@ 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) + { + if (methodDesc == 0 || cNativeCodeAddrs == 0 || pcNativeCodeAddrs == null) + { + return HResults.E_INVALIDARG; + } + + *pcNativeCodeAddrs = 0; + int hr = HResults.S_OK; +#if FEATURE_REJIT + try + { + ILoader loader = _target.Contracts.Loader; + ICodeVersions codeVersions = _target.Contracts.CodeVersions; + IReJIT rejitContract = _target.Contracts.ReJIT; + TargetPointer methodDescPtr = methodDesc.ToTargetPointer(_target); + ILCodeVersionHandle ilCodeVersionHandle = codeVersions.GetILCodeVersions(methodDescPtr) + .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode).Value == (ulong)rejitId, ILCodeVersionHandle.Invalid); + + if (!ilCodeVersionHandle.IsValid) + throw new ArgumentException(); + + IRuntimeTypeSystem runtimeTypeSystemContract = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle methodDescHandle = runtimeTypeSystemContract.GetMethodDescHandle(methodDescPtr); + TargetPointer modulePtr = runtimeTypeSystemContract.GetModule(methodDescHandle); + ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); + + TargetPointer r2rImageBase = TargetPointer.Null; + TargetPointer r2rImageEnd = TargetPointer.Null; + if (loader.IsReadyToRun(moduleHandle) + && loader.TryGetLoadedImageContents(moduleHandle, out r2rImageBase, out uint r2rSize, out _)) + { + r2rImageEnd = r2rImageBase + r2rSize; + } + ClrDataAddress r2rImageBaseAddr = r2rImageBase.toClrDataAddress(_target); + ClrDataAddress r2rImageEndAddr = r2rImageEnd.toClrDataAddress(_target); + + int count = 0; + foreach (NativeCodeVersionHandle nativeCodeVersionHandle in codeVersions.GetNativeCodeVersions(methodDescPtr, ilCodeVersionHandle)) + { + ClrDataAddress nativeCodeAddr = codeVersions.GetNativeCode(nativeCodeVersionHandle).Value; + nativeCodeAddrs[count].nativeCodeAddr = nativeCodeAddr; + nativeCodeAddrs[count].nativeCodeVersionNodePtr = nativeCodeVersionHandle.CodeVersionNodeAddress.ToClrDataAddress(_target); + + if (r2rImageBaseAddr <= nativeCodeAddr && nativeCodeAddr < r2rImageEndAddr) + { + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.ReadyToRun; + } + else if (runtimeTypeSystemContract.IsEligibleForTieredCompilation(methodDescHandle)) + { + switch (codeVersions.GetOptimizationTier(nativeCodeVersionHandle)) + { + default: + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.Unknown; + break; + case NativeCodeVersionOptimizationTier.OptimizationTier0: + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.QuickJitted; + break; + case NativeCodeVersionOptimizationTier.OptimizationTier1: + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.OptimizedTier1; + break; + case NativeCodeVersionOptimizationTier.OptimizationTier1OSR: + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.OptimizedTier1OSR; + break; + case NativeCodeVersionOptimizationTier.OptimizationTierOptimized: + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.Optimized; + break; + case NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented: + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.QuickJittedInstrumented; + break; + case NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented: + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.OptimizedTier1Instrumented; + break; + } + } + else if (runtimeTypeSystemContract.IsJitOptimizationDisabled(methodDescHandle)) + { + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.MinOptJitted; + } + else + { + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.Optimized; + } + + count++; + + if (count >= cNativeCodeAddrs) + { + hr = HResults.S_FALSE; + break; + } + } + + *pcNativeCodeAddrs = count; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacyImpl5 is not null) + { + int hrLocal = _legacyImpl5.GetTieredVersions(methodDesc, rejitId, nativeCodeAddrs, cNativeCodeAddrs, pcNativeCodeAddrs); + Debug.ValidateHResult(hr, hrLocal); + } +#endif // DEBUG +#endif // FEATURE_REJIT + return hr; + } #endregion ISOSDacInterface5 #region ISOSDacInterface6 diff --git a/src/native/managed/cdac/tests/CodeVersionsTests.cs b/src/native/managed/cdac/tests/CodeVersionsTests.cs index 7ceaeea2433ef4..5acd3e08e10377 100644 --- a/src/native/managed/cdac/tests/CodeVersionsTests.cs +++ b/src/native/managed/cdac/tests/CodeVersionsTests.cs @@ -722,4 +722,121 @@ public void GetGCStressCodeCopy_NotNull(MockTarget.Architecture arch) { GetGCStressCodeCopy_Impl(arch, returnsNull: false); } + + public static IEnumerable GetOptimizationTierValues() + { + foreach (var archData in new MockTarget.StdArch()) + { + var arch = (MockTarget.Architecture)archData[0]; + yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier0]; + yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier1]; + yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier1OSR]; + yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTierOptimized]; + yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented]; + yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented]; + } + } + + [Theory] + [MemberData(nameof(GetOptimizationTierValues))] + public void GetOptimizationTier_Explicit(MockTarget.Architecture arch, NativeCodeVersionOptimizationTier expectedTier) + { + MockCodeVersions builder = new(arch); + + TargetPointer nativeCodeVersionNode = builder.AddNativeCodeVersionNode(); + builder.FillNativeCodeVersionNode( + nativeCodeVersionNode, + methodDesc: new TargetPointer(0x1a0a_0000), + nativeCode: new TargetCodePointer(0x0a0a_0000), + next: TargetPointer.Null, + isActive: true, + ilVersionId: new(1), + optimizationTier: (uint)expectedTier); + + var target = CreateTarget(arch, builder); + var codeVersions = target.Contracts.CodeVersions; + + NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateExplicit(nativeCodeVersionNode); + NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); + Assert.Equal(expectedTier, tier); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetOptimizationTier_Explicit_MissingField(MockTarget.Architecture arch) + { + MockCodeVersions builder = new(arch); + + TargetPointer nativeCodeVersionNode = builder.AddNativeCodeVersionNode(); + builder.FillNativeCodeVersionNode( + nativeCodeVersionNode, + methodDesc: new TargetPointer(0x1a0a_0000), + nativeCode: new TargetCodePointer(0x0a0a_0000), + next: TargetPointer.Null, + isActive: true, + ilVersionId: new(1)); + + // Remove the OptimizationTier field from the type info to simulate a runtime + // that doesn't expose it (e.g. FEATURE_TIERED_COMPILATION disabled). + var typesWithoutTier = new Dictionary(builder.Types); + var ncvnType = typesWithoutTier[DataType.NativeCodeVersionNode]; + var fieldsWithoutTier = new Dictionary(ncvnType.Fields); + fieldsWithoutTier.Remove(nameof(Data.NativeCodeVersionNode.OptimizationTier)); + typesWithoutTier[DataType.NativeCodeVersionNode] = ncvnType with { Fields = fieldsWithoutTier }; + + TestPlaceholderTarget target = new TestPlaceholderTarget(arch, builder.Builder.GetMemoryContext().ReadFromTarget, typesWithoutTier); + IContractFactory cvfactory = new CodeVersionsFactory(); + ContractRegistry reg = Mock.Of( + c => c.CodeVersions == cvfactory.CreateContract(target, 1) + && c.RuntimeTypeSystem == Mock.Of() + && c.ExecutionManager == Mock.Of() + && c.Loader == Mock.Of()); + target.SetContracts(reg); + + var codeVersions = target.Contracts.CodeVersions; + NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateExplicit(nativeCodeVersionNode); + NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); + Assert.Equal(NativeCodeVersionOptimizationTier.OptimizationTierUnknown, tier); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetOptimizationTier_Synthetic_DelegatesToRuntimeTypeSystem(MockTarget.Architecture arch) + { + MockCodeVersions builder = new(arch); + TargetPointer methodDescAddress = new(0x1a0a_0000); + + Mock mockRTS = new(); + MethodDescHandle mdHandle = new(methodDescAddress); + mockRTS.Setup(r => r.GetMethodDescHandle(methodDescAddress)).Returns(mdHandle); + mockRTS.Setup(r => r.GetMethodDescOptimizationTier(mdHandle)).Returns(NativeCodeVersionOptimizationTier.OptimizationTierOptimized); + + var target = CreateTarget(arch, builder, mockRuntimeTypeSystem: mockRTS); + var codeVersions = target.Contracts.CodeVersions; + + NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateSynthetic(methodDescAddress); + NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); + Assert.Equal(NativeCodeVersionOptimizationTier.OptimizationTierOptimized, tier); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetOptimizationTier_Synthetic_FallsBackToInitialTier(MockTarget.Architecture arch) + { + MockCodeVersions builder = new(arch); + TargetPointer methodDescAddress = new(0x1a0a_0000); + + Mock mockRTS = new(); + MethodDescHandle mdHandle = new(methodDescAddress); + mockRTS.Setup(r => r.GetMethodDescHandle(methodDescAddress)).Returns(mdHandle); + mockRTS.Setup(r => r.GetMethodDescOptimizationTier(mdHandle)).Returns(NativeCodeVersionOptimizationTier.OptimizationTierUnknown); + mockRTS.Setup(r => r.GetInitialOptimizationTier(mdHandle)).Returns(NativeCodeVersionOptimizationTier.OptimizationTier0); + + var target = CreateTarget(arch, builder, mockRuntimeTypeSystem: mockRTS); + var codeVersions = target.Contracts.CodeVersions; + + NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateSynthetic(methodDescAddress); + NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); + Assert.Equal(NativeCodeVersionOptimizationTier.OptimizationTier0, tier); + } } diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs index feee26fc9c24f8..76b691b2052604 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs @@ -35,6 +35,7 @@ public class CodeVersions new(nameof(Data.NativeCodeVersionNode.Flags), DataType.uint32), new(nameof(Data.NativeCodeVersionNode.ILVersionId), DataType.nuint), new(nameof(Data.NativeCodeVersionNode.GCCoverageInfo), DataType.pointer), + new(nameof(Data.NativeCodeVersionNode.OptimizationTier), DataType.uint32), ] }; @@ -119,7 +120,7 @@ public TargetPointer AddNativeCodeVersionNode() return fragment.Address; } - public void FillNativeCodeVersionNode(TargetPointer dest, TargetPointer methodDesc, TargetCodePointer nativeCode, TargetPointer next, bool isActive, TargetNUInt ilVersionId, TargetPointer? gcCoverageInfo = null) + public void FillNativeCodeVersionNode(TargetPointer dest, TargetPointer methodDesc, TargetCodePointer nativeCode, TargetPointer next, bool isActive, TargetNUInt ilVersionId, TargetPointer? gcCoverageInfo = null, uint? optimizationTier = null) { Target.TypeInfo info = Types[DataType.NativeCodeVersionNode]; Span ncvn = Builder.BorrowAddressRange(dest, (int)info.Size!); @@ -129,6 +130,10 @@ public void FillNativeCodeVersionNode(TargetPointer dest, TargetPointer methodDe Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.Flags)].Offset, sizeof(uint)), isActive ? (uint)CodeVersions_1.NativeCodeVersionNodeFlags.IsActiveChild : 0u); Builder.TargetTestHelpers.WriteNUInt(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.ILVersionId)].Offset, Builder.TargetTestHelpers.PointerSize), ilVersionId); Builder.TargetTestHelpers.WritePointer(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.GCCoverageInfo)].Offset, Builder.TargetTestHelpers.PointerSize), gcCoverageInfo ?? TargetPointer.Null); + if (optimizationTier.HasValue) + { + Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.OptimizationTier)].Offset, sizeof(uint)), optimizationTier.Value); + } } public (TargetPointer First, TargetPointer Active) AddNativeCodeVersionNodesForMethod(TargetPointer methodDesc, int count, int activeIndex, TargetCodePointer activeNativeCode, TargetNUInt ilVersion, TargetPointer? firstNode = null) From f9782cdc23f3c4b72cf9b771f9c8db9a12c1a1f9 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Fri, 27 Mar 2026 15:19:40 -0700 Subject: [PATCH 02/11] Apply pr suggestions --- docs/design/datacontracts/CodeVersions.md | 18 + docs/design/datacontracts/Loader.md | 14 + .../design/datacontracts/RuntimeTypeSystem.md | 12 + src/coreclr/inc/cordbpriv.h | 6 +- src/coreclr/vm/ceeload.cpp | 4 + src/coreclr/vm/ceeload.h | 27 +- .../Contracts/ILoader.cs | 1 + .../Contracts/RuntimeTypeSystem_1.cs | 19 +- .../ISOSDacInterface.cs | 7 +- .../SOSDacImpl.cs | 55 ++- .../cdac/tests/SOSDacInterface5Tests.cs | 326 ++++++++++++++++++ 11 files changed, 453 insertions(+), 36 deletions(-) create mode 100644 src/native/managed/cdac/tests/SOSDacInterface5Tests.cs diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 63d637129e007c..0cb8fd68de5a15 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -51,7 +51,24 @@ public virtual TargetPointer GetIL(ILCodeVersionHandle ilCodeVersionHandle); // Determines whether an IL code version has default IL public virtual bool HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle); + +// Gets the optimization tier for a native code version +public virtual NativeCodeVersionOptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle); ``` + +```csharp +public enum NativeCodeVersionOptimizationTier : uint +{ + OptimizationTier0, + OptimizationTier1, + OptimizationTier1OSR, + OptimizationTierOptimized, + OptimizationTier0Instrumented, + OptimizationTier1Instrumented, + OptimizationTierUnknown = 0xFFFFFFFF +} +``` + ### Extension Methods ```csharp // Return a handle to the active version of the native code for a given method descriptor @@ -73,6 +90,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 | OptimizationTier | The optimization tier of this native code version | | 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 | diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index c6943aacd0c33f..bac6574dca751b 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -18,6 +18,15 @@ 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 + ProfilerDisableOpt = 0x00000080, // Profiler disabled JIT optimizations when module was loaded + AllMethodsJitOptimizationDisabled = 0x00200000, // Precomputed: JIT optimization is disabled for all methods in this module +} + +[Flags] +enum DebuggerAssemblyControlFlags +{ + DACF_USER_OVERRIDE = 0x01, + DACF_ALLOW_JIT_OPTS = 0x02, } [Flags] @@ -69,6 +78,8 @@ IEnumerable GetInstantiatedMethods(ModuleHandle handle); bool IsProbeExtensionResultValid(ModuleHandle handle); ModuleFlags GetFlags(ModuleHandle handle); +bool IsReadyToRun(ModuleHandle handle); +DebuggerAssemblyControlFlags GetDebuggerInfoBits(ModuleHandle handle); bool TryGetSimpleName(ModuleHandle handle, out string simpleName); string GetPath(ModuleHandle handle); string GetFileName(ModuleHandle handle); @@ -209,6 +220,7 @@ private enum ModuleFlags_1 : uint 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 + AllMethodsJitOptimizationDisabled = 0x00200000, // Precomputed: JIT optimization is disabled for all methods in this module } private enum PEImageFlags : uint @@ -569,6 +581,8 @@ private static ModuleFlags GetFlags(uint flags) flags |= ModuleFlags.EditAndContinue; if (runtimeFlags.HasFlag(ModuleFlags_1.ReflectionEmit)) flags |= ModuleFlags.ReflectionEmit; + if (runtimeFlags.HasFlag(ModuleFlags_1.AllMethodsJitOptimizationDisabled)) + flags |= ModuleFlags.AllMethodsJitOptimizationDisabled; return flags; } diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index ab521583c3edcb..2019979f677d02 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -196,6 +196,18 @@ partial interface IRuntimeTypeSystem : IContract // Gets the GCStressCodeCopy pointer if available, otherwise returns TargetPointer.Null public virtual TargetPointer GetGCStressCodeCopy(MethodDescHandle methodDesc); + // Gets the optimization tier stored on the MethodDesc's code data + public virtual NativeCodeVersionOptimizationTier GetMethodDescOptimizationTier(MethodDescHandle methodDesc); + + // Gets the initial optimization tier for a method + public virtual NativeCodeVersionOptimizationTier GetInitialOptimizationTier(MethodDescHandle methodDesc); + + // Returns true if the method is eligible for tiered compilation + public virtual bool IsEligibleForTieredCompilation(MethodDescHandle methodDesc); + + // Returns true if JIT optimization is disabled for the method (module-level + per-method checks) + public virtual bool IsJitOptimizationDisabled(MethodDescHandle methodDesc); + } ``` diff --git a/src/coreclr/inc/cordbpriv.h b/src/coreclr/inc/cordbpriv.h index 32a85c28b07401..83a615b2de6f83 100644 --- a/src/coreclr/inc/cordbpriv.h +++ b/src/coreclr/inc/cordbpriv.h @@ -36,7 +36,7 @@ enum DebuggerControlFlag DBCF_USER_MASK = 0x00FF, DBCF_GENERATE_DEBUG_CODE = 0x0001, - DBCF_ALLOW_JIT_OPT = 0x0008, + DBCF_ALLOW_JIT_OPT = 0x0008, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value. DBCF_PROFILER_ENABLED = 0x0020, // DBCF_ACTIVATE_REMOTE_DEBUGGING = 0x0040, Deprecated. DO NOT USE @@ -53,8 +53,8 @@ enum DebuggerControlFlag enum DebuggerAssemblyControlFlags { DACF_NONE = 0x00, - DACF_USER_OVERRIDE = 0x01, - DACF_ALLOW_JIT_OPTS = 0x02, + DACF_USER_OVERRIDE = 0x01, // [cDAC] [Loader]: Contract depends on this value. + DACF_ALLOW_JIT_OPTS = 0x02, // [cDAC] [Loader]: Contract depends on this value. DACF_OBSOLETE_TRACK_JIT_INFO = 0x04, // obsolete in V2.0, we're always tracking. DACF_ENC_ENABLED = 0x08, DACF_IGNORE_PDBS = 0x20, diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index e04a30dfd958f7..57d0a10d587d30 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -521,6 +521,8 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) #endif // PROFILING_SUPPORTED LOG((LF_CLASSLOADER, LL_INFO10, "Loaded pModule: \"%s\".\n", GetDebugName())); + + UpdateAllMethodsJITOptimizationDisabledFlag(); } #endif // DACCESS_COMPILE @@ -549,6 +551,8 @@ void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits) } #endif // DEBUGGING_SUPPORTED + UpdateAllMethodsJITOptimizationDisabledFlag(); + #if defined(DACCESS_COMPILE) // Now that we've changed m_dwTransientFlags, update that in the target too. // This will fail for read-only target. diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 1bcc3b2bda95e1..9a3c6d43c58789 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -618,7 +618,7 @@ class Module : public ModuleBase enum { // These are the values set in m_dwTransientFlags. - // [cDAC] [Loader]: Contract depends on the values of MODULE_IS_TENURED, IS_EDIT_AND_CONTINUE, and IS_REFLECTION_EMIT. + // [cDAC] [Loader]: Contract depends on the values of MODULE_IS_TENURED, IS_EDIT_AND_CONTINUE, IS_REFLECTION_EMIT, and PROF_DISABLE_OPTIMIZATIONS. MODULE_IS_TENURED = 0x00000001, // Set once we know for sure the Module will not be freed until the appdomain itself exits // unused = 0x00000002, @@ -643,12 +643,17 @@ class Module : public ModuleBase DEBUGGER_ENC_ENABLED_PRIV = 0x00002000, // this is what was attempted to be set. IS_EDIT_AND_CONTINUE is actual result. DEBUGGER_PDBS_COPIED = 0x00004000, DEBUGGER_IGNORE_PDBS = 0x00008000, - DEBUGGER_INFO_MASK_PRIV = 0x0000Fc00, - DEBUGGER_INFO_SHIFT_PRIV = 10, + DEBUGGER_INFO_MASK_PRIV = 0x0000Fc00, // [cDAC] [Loader]: Contract depends on this value. + DEBUGGER_INFO_SHIFT_PRIV = 10, // [cDAC] [Loader]: Contract depends on this value. // Used to indicate that this module has had it's IJW fixups properly installed. IS_IJW_FIXED_UP = 0x00080000, IS_BEING_UNLOADED = 0x00100000, + + // [cDAC] [RuntimeTypeSystem]: Contract depends on this value. + // Precomputed flag combining debugger, profiler, and EEConfig checks. + // Set during module initialization; see UpdateAllMethodsJITOptimizationDisabledFlag(). + ALL_METHODS_JIT_OPTIMIZATION_DISABLED = 0x00200000, }; static_assert(DEBUGGER_USER_OVERRIDE_PRIV >> DEBUGGER_INFO_SHIFT_PRIV == DebuggerAssemblyControlFlags::DACF_USER_OVERRIDE); @@ -961,6 +966,22 @@ class Module : public ModuleBase return FALSE; } + // Updates the ALL_METHODS_JIT_OPTIMIZATION_DISABLED precomputed flag. + // Must be called after debugger info bits, profiler flags, or EEConfig are finalized. + void UpdateAllMethodsJITOptimizationDisabledFlag() + { + WRAPPER_NO_CONTRACT; + + BOOL disabled = AreJITOptimizationsDisabled() || + g_pConfig->JitMinOpts() || + g_pConfig->GenDebuggableCode(); + + if (disabled) + SetTransientFlagInterlocked(ALL_METHODS_JIT_OPTIMIZATION_DISABLED); + else + SetTransientFlagInterlockedWithMask(0, ALL_METHODS_JIT_OPTIMIZATION_DISABLED); + } + #ifdef FEATURE_METADATA_UPDATER // Holds a table of EnCEEClassData object for classes in this module that have been modified CUnorderedArray m_ClassList; 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 d9b39adf4a526c..f453d48fd54382 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 @@ -23,6 +23,7 @@ public enum ModuleFlags EditAndContinue = 0x8, // Edit and Continue is enabled for this module ReflectionEmit = 0x40, // Reflection.Emit was used to create this module ProfilerDisableOpt = 0x80, // Profiler disabled JIT optimizations when module was loaded + AllMethodsJitOptimizationDisabled = 0x00200000, // Precomputed: JIT optimization is disabled for all methods in this module } [Flags] 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 464887c6f3adbf..0d948da921704b 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 @@ -1682,34 +1682,23 @@ private bool IsJitOptimizationDisabledForSpecificMethod(MethodDescHandle methodD } else if (!isNoMetadata) { - throw new InvalidOperationException("Failed to get metadata for method"); + return false; } return !isNoMetadata && isMiNoOptimization; } - private bool IsJitOptimizationDisabledForAllMethodsInChunk(MethodDescHandle methodDescHandle) + private bool IsJitOptimizationDisabledForModule(MethodDescHandle methodDescHandle) { MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; MethodTable methodTable = GetOrCreateMethodTable(methodDesc); ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(methodTable.Module); - DebuggerAssemblyControlFlags debuggerInfoBits = _target.Contracts.Loader.GetDebuggerInfoBits(moduleHandle); - DebuggerControlFlag corDebuggerControlFlags = (DebuggerControlFlag)_target.Read(_target.ReadGlobalPointer(Constants.Globals.CORDebuggerControlFlags)); - TargetPointer eeConfigPtr = _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); - Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(eeConfigPtr); - - bool corDebuggerAllowJITOpts = debuggerInfoBits.HasFlag(DebuggerAssemblyControlFlags.DACF_ALLOW_JIT_OPTS) - || (corDebuggerControlFlags.HasFlag(DebuggerControlFlag.DBCF_ALLOW_JIT_OPT) - && !debuggerInfoBits.HasFlag(DebuggerAssemblyControlFlags.DACF_USER_OVERRIDE)); - bool profilerDisabledOptimizations = _target.Contracts.Loader.GetFlags(moduleHandle).HasFlag(ModuleFlags.ProfilerDisableOpt); - bool areJITOptimizationsDisabled = !corDebuggerAllowJITOpts || profilerDisabledOptimizations; - - return eeConfig.JitMinOpts || eeConfig.GenDebuggable || areJITOptimizationsDisabled; + return _target.Contracts.Loader.GetFlags(moduleHandle).HasFlag(ModuleFlags.AllMethodsJitOptimizationDisabled); } bool IRuntimeTypeSystem.IsJitOptimizationDisabled(MethodDescHandle methodDescHandle) { - return IsJitOptimizationDisabledForAllMethodsInChunk(methodDescHandle) || IsJitOptimizationDisabledForSpecificMethod(methodDescHandle); + return IsJitOptimizationDisabledForModule(methodDescHandle) || IsJitOptimizationDisabledForSpecificMethod(methodDescHandle); } NativeCodeVersionOptimizationTier IRuntimeTypeSystem.GetInitialOptimizationTier(MethodDescHandle methodDescHandle) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs index fd1b858aae8b09..f913642a7a02ce 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs @@ -969,7 +969,12 @@ public enum OptimizationTier public unsafe partial interface ISOSDacInterface5 { [PreserveSig] - int GetTieredVersions(ClrDataAddress methodDesc, int rejitId, DacpTieredVersionData* nativeCodeAddrs, int cNativeCodeAddrs, int* pcNativeCodeAddrs); + int GetTieredVersions( + ClrDataAddress methodDesc, + int rejitId, + [In, MarshalUsing(CountElementName = nameof(cNativeCodeAddrs)), Out] DacpTieredVersionData[]? nativeCodeAddrs, + int cNativeCodeAddrs, + int* pcNativeCodeAddrs); }; public struct DacpMethodTableCollectibleData diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 68d0d2dc2fcc64..9948beaa6ccd79 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -4806,18 +4806,23 @@ int ISOSDacInterface4.GetClrNotification(ClrDataAddress[] arguments, int count, #endregion ISOSDacInterface4 #region ISOSDacInterface5 - int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, DacpTieredVersionData* nativeCodeAddrs, int cNativeCodeAddrs, int* pcNativeCodeAddrs) + int ISOSDacInterface5.GetTieredVersions( + ClrDataAddress methodDesc, + int rejitId, + [In, MarshalUsing(CountElementName = nameof(cNativeCodeAddrs)), Out] DacpTieredVersionData[]? nativeCodeAddrs, + int cNativeCodeAddrs, + int* pcNativeCodeAddrs) { - if (methodDesc == 0 || cNativeCodeAddrs == 0 || pcNativeCodeAddrs == null) - { - return HResults.E_INVALIDARG; - } - - *pcNativeCodeAddrs = 0; int hr = HResults.S_OK; -#if FEATURE_REJIT try { + if (methodDesc == 0 || cNativeCodeAddrs == 0 || pcNativeCodeAddrs == null || nativeCodeAddrs is null) + { + throw new ArgumentException(); + } + + *pcNativeCodeAddrs = 0; + ILoader loader = _target.Contracts.Loader; ICodeVersions codeVersions = _target.Contracts.CodeVersions; IReJIT rejitContract = _target.Contracts.ReJIT; @@ -4830,8 +4835,8 @@ int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, IRuntimeTypeSystem runtimeTypeSystemContract = _target.Contracts.RuntimeTypeSystem; MethodDescHandle methodDescHandle = runtimeTypeSystemContract.GetMethodDescHandle(methodDescPtr); - TargetPointer modulePtr = runtimeTypeSystemContract.GetModule(methodDescHandle); - ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); + TargetPointer modulePtr = runtimeTypeSystemContract.GetModule(runtimeTypeSystemContract.GetTypeHandle(runtimeTypeSystemContract.GetMethodTable(methodDescHandle))); + Contracts.ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(modulePtr); TargetPointer r2rImageBase = TargetPointer.Null; TargetPointer r2rImageEnd = TargetPointer.Null; @@ -4840,8 +4845,8 @@ int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, { r2rImageEnd = r2rImageBase + r2rSize; } - ClrDataAddress r2rImageBaseAddr = r2rImageBase.toClrDataAddress(_target); - ClrDataAddress r2rImageEndAddr = r2rImageEnd.toClrDataAddress(_target); + ClrDataAddress r2rImageBaseAddr = r2rImageBase.ToClrDataAddress(_target); + ClrDataAddress r2rImageEndAddr = r2rImageEnd.ToClrDataAddress(_target); int count = 0; foreach (NativeCodeVersionHandle nativeCodeVersionHandle in codeVersions.GetNativeCodeVersions(methodDescPtr, ilCodeVersionHandle)) @@ -4901,6 +4906,11 @@ int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, *pcNativeCodeAddrs = count; } + catch (NotImplementedException) + { + // ReJIT contract not available — feature not active in the target runtime + return HResults.S_OK; + } catch (System.Exception ex) { hr = ex.HResult; @@ -4908,11 +4918,28 @@ int ISOSDacInterface5.GetTieredVersions(ClrDataAddress methodDesc, int rejitId, #if DEBUG if (_legacyImpl5 is not null) { - int hrLocal = _legacyImpl5.GetTieredVersions(methodDesc, rejitId, nativeCodeAddrs, cNativeCodeAddrs, pcNativeCodeAddrs); + var legacyBuffer = new DacpTieredVersionData[cNativeCodeAddrs]; + int legacyCount; + int hrLocal = _legacyImpl5.GetTieredVersions(methodDesc, rejitId, legacyBuffer, cNativeCodeAddrs, &legacyCount); Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK || hr == HResults.S_FALSE) + { + Debug.Assert(*pcNativeCodeAddrs == legacyCount, $"cDAC count: {*pcNativeCodeAddrs}, DAC count: {legacyCount}"); + if (nativeCodeAddrs is not null) + { + for (int i = 0; i < *pcNativeCodeAddrs; i++) + { + Debug.Assert(nativeCodeAddrs[i].nativeCodeAddr == legacyBuffer[i].nativeCodeAddr, + $"[{i}] cDAC nativeCodeAddr: 0x{(ulong)nativeCodeAddrs[i].nativeCodeAddr:x}, DAC: 0x{(ulong)legacyBuffer[i].nativeCodeAddr:x}"); + Debug.Assert(nativeCodeAddrs[i].nativeCodeVersionNodePtr == legacyBuffer[i].nativeCodeVersionNodePtr, + $"[{i}] cDAC nodePtr: 0x{(ulong)nativeCodeAddrs[i].nativeCodeVersionNodePtr:x}, DAC: 0x{(ulong)legacyBuffer[i].nativeCodeVersionNodePtr:x}"); + Debug.Assert(nativeCodeAddrs[i].optimizationTier == legacyBuffer[i].optimizationTier, + $"[{i}] cDAC tier: {nativeCodeAddrs[i].optimizationTier}, DAC: {legacyBuffer[i].optimizationTier}"); + } + } + } } #endif // DEBUG -#endif // FEATURE_REJIT return hr; } #endregion ISOSDacInterface5 diff --git a/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs b/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs new file mode 100644 index 00000000000000..a9ee6b4472bc54 --- /dev/null +++ b/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs @@ -0,0 +1,326 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using Microsoft.Diagnostics.DataContractReader.Contracts; +using Microsoft.Diagnostics.DataContractReader.Legacy; +using Moq; +using Xunit; + +namespace Microsoft.Diagnostics.DataContractReader.Tests; + +public unsafe class SOSDacInterface5Tests +{ + private const int S_OK = 0; + private const int S_FALSE = 1; + + private static readonly TargetPointer s_methodDescAddr = new(0x1000_0000); + private static readonly TargetPointer s_moduleAddr = new(0x2000_0000); + private static readonly TargetPointer s_methodTableAddr = new(0x3000_0000); + + private record struct VersionInfo( + TargetCodePointer NativeCode, + TargetPointer CodeVersionNodeAddress, + NativeCodeVersionOptimizationTier Tier); + + private static ISOSDacInterface5 CreateDac5( + MockTarget.Architecture arch, + VersionInfo[]? versions = null, + bool isEligibleForTieredCompilation = false, + bool isJitOptimizationDisabled = false, + bool isReadyToRun = false, + TargetPointer r2rBase = default, + uint r2rSize = 0, + int rejitId = 0) + { + var mockCodeVersions = new Mock(); + var mockRts = new Mock(); + var mockLoader = new Mock(); + var mockReJIT = new Mock(); + + ILCodeVersionHandle ilCodeVersion = ILCodeVersionHandle.CreateSynthetic(s_moduleAddr, 0x06000001); + MethodDescHandle methodDescHandle = new MethodDescHandle(s_methodDescAddr); + TypeHandle typeHandle = new TypeHandle(s_methodTableAddr); + Contracts.ModuleHandle moduleHandle = new Contracts.ModuleHandle(s_moduleAddr); + + mockCodeVersions + .Setup(c => c.GetILCodeVersions(s_methodDescAddr)) + .Returns(new[] { ilCodeVersion }); + + mockReJIT + .Setup(r => r.GetRejitId(It.IsAny())) + .Returns(new TargetNUInt((ulong)rejitId)); + + mockRts + .Setup(r => r.GetMethodDescHandle(s_methodDescAddr)) + .Returns(methodDescHandle); + mockRts + .Setup(r => r.GetMethodTable(methodDescHandle)) + .Returns(s_methodTableAddr); + mockRts + .Setup(r => r.GetTypeHandle(s_methodTableAddr)) + .Returns(typeHandle); + mockRts + .Setup(r => r.GetModule(typeHandle)) + .Returns(s_moduleAddr); + mockRts + .Setup(r => r.IsEligibleForTieredCompilation(methodDescHandle)) + .Returns(isEligibleForTieredCompilation); + mockRts + .Setup(r => r.IsJitOptimizationDisabled(methodDescHandle)) + .Returns(isJitOptimizationDisabled); + + mockLoader + .Setup(l => l.GetModuleHandleFromModulePtr(s_moduleAddr)) + .Returns(moduleHandle); + mockLoader + .Setup(l => l.IsReadyToRun(moduleHandle)) + .Returns(isReadyToRun); + if (isReadyToRun) + { + uint imageFlags = 0; + TargetPointer outBase = r2rBase; + mockLoader + .Setup(l => l.TryGetLoadedImageContents(moduleHandle, out outBase, out r2rSize, out imageFlags)) + .Returns(true); + } + + versions ??= []; + + var nativeVersionHandles = new NativeCodeVersionHandle[versions.Length]; + for (int i = 0; i < versions.Length; i++) + { + NativeCodeVersionHandle handle = versions[i].CodeVersionNodeAddress != TargetPointer.Null + ? NativeCodeVersionHandle.CreateExplicit(versions[i].CodeVersionNodeAddress) + : NativeCodeVersionHandle.CreateSynthetic(s_methodDescAddr); + + nativeVersionHandles[i] = handle; + + mockCodeVersions + .Setup(c => c.GetNativeCode(handle)) + .Returns(versions[i].NativeCode); + mockCodeVersions + .Setup(c => c.GetOptimizationTier(handle)) + .Returns(versions[i].Tier); + } + + mockCodeVersions + .Setup(c => c.GetNativeCodeVersions(s_methodDescAddr, It.IsAny())) + .Returns(nativeVersionHandles); + + var target = new TestPlaceholderTarget( + arch, + (_, _) => -1, + types: []); + target.SetContracts(Mock.Of( + c => c.CodeVersions == mockCodeVersions.Object + && c.RuntimeTypeSystem == mockRts.Object + && c.Loader == mockLoader.Object + && c.ReJIT == mockReJIT.Object)); + + return new SOSDacImpl(target, legacyObj: null); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_ZeroMethodDesc(MockTarget.Architecture arch) + { + ISOSDacInterface5 dac5 = CreateDac5(arch); + var buffer = new DacpTieredVersionData[1]; + int count; + int hr = dac5.GetTieredVersions(0, 0, buffer, 1, &count); + Assert.NotEqual(S_OK, hr); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_ZeroBufferSize(MockTarget.Architecture arch) + { + ISOSDacInterface5 dac5 = CreateDac5(arch); + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, null, 0, &count); + Assert.NotEqual(S_OK, hr); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_NullOutputPtr(MockTarget.Architecture arch) + { + ISOSDacInterface5 dac5 = CreateDac5(arch); + var buffer = new DacpTieredVersionData[1]; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 1, null); + Assert.NotEqual(S_OK, hr); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_InvalidRejitId(MockTarget.Architecture arch) + { + ISOSDacInterface5 dac5 = CreateDac5(arch, rejitId: 0); + var buffer = new DacpTieredVersionData[1]; + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 999, buffer, 1, &count); + Assert.NotEqual(S_OK, hr); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_ReadyToRun(MockTarget.Architecture arch) + { + var r2rBase = new TargetPointer(0x5000_0000); + uint r2rSize = 0x1000; + var versions = new[] + { + new VersionInfo(new TargetCodePointer(0x5000_0100), new TargetPointer(0x7000_0001), NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + }; + + ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isReadyToRun: true, r2rBase: r2rBase, r2rSize: r2rSize); + var buffer = new DacpTieredVersionData[2]; + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + + Assert.Equal(S_OK, hr); + Assert.Equal(1, count); + Assert.Equal(DacpTieredVersionData.OptimizationTier.ReadyToRun, buffer[0].optimizationTier); + } + + public static IEnumerable TierMappingData + { + get + { + (NativeCodeVersionOptimizationTier, DacpTieredVersionData.OptimizationTier)[] tiers = + [ + (NativeCodeVersionOptimizationTier.OptimizationTier0, DacpTieredVersionData.OptimizationTier.QuickJitted), + (NativeCodeVersionOptimizationTier.OptimizationTier1, DacpTieredVersionData.OptimizationTier.OptimizedTier1), + (NativeCodeVersionOptimizationTier.OptimizationTier1OSR, DacpTieredVersionData.OptimizationTier.OptimizedTier1OSR), + (NativeCodeVersionOptimizationTier.OptimizationTierOptimized, DacpTieredVersionData.OptimizationTier.Optimized), + (NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented, DacpTieredVersionData.OptimizationTier.QuickJittedInstrumented), + (NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented, DacpTieredVersionData.OptimizationTier.OptimizedTier1Instrumented), + (NativeCodeVersionOptimizationTier.OptimizationTierUnknown, DacpTieredVersionData.OptimizationTier.Unknown), + ]; + + foreach (var arch in new MockTarget.StdArch()) + { + foreach (var (internalTier, expectedTier) in tiers) + { + yield return [(MockTarget.Architecture)arch[0], internalTier, expectedTier]; + } + } + } + } + + [Theory] + [MemberData(nameof(TierMappingData))] + public void GetTieredVersions_TieredCompilation( + MockTarget.Architecture arch, + NativeCodeVersionOptimizationTier internalTier, + DacpTieredVersionData.OptimizationTier expectedTier) + { + var versions = new[] + { + new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), internalTier), + }; + + ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isEligibleForTieredCompilation: true); + var buffer = new DacpTieredVersionData[2]; + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + + Assert.Equal(S_OK, hr); + Assert.Equal(1, count); + Assert.Equal(expectedTier, buffer[0].optimizationTier); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_JitOptimizationDisabled(MockTarget.Architecture arch) + { + var versions = new[] + { + new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + }; + + ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isJitOptimizationDisabled: true); + var buffer = new DacpTieredVersionData[2]; + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + + Assert.Equal(S_OK, hr); + Assert.Equal(1, count); + Assert.Equal(DacpTieredVersionData.OptimizationTier.MinOptJitted, buffer[0].optimizationTier); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_DefaultFallthrough(MockTarget.Architecture arch) + { + var versions = new[] + { + new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + }; + + ISOSDacInterface5 dac5 = CreateDac5(arch, versions); + var buffer = new DacpTieredVersionData[2]; + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + + Assert.Equal(S_OK, hr); + Assert.Equal(1, count); + Assert.Equal(DacpTieredVersionData.OptimizationTier.Optimized, buffer[0].optimizationTier); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_BufferTooSmall(MockTarget.Architecture arch) + { + var versions = new[] + { + new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), NativeCodeVersionOptimizationTier.OptimizationTier0), + new VersionInfo(new TargetCodePointer(0x6000_0200), new TargetPointer(0x7000_0002), NativeCodeVersionOptimizationTier.OptimizationTier1), + new VersionInfo(new TargetCodePointer(0x6000_0300), new TargetPointer(0x7000_0003), NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + }; + + ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isEligibleForTieredCompilation: true); + var buffer = new DacpTieredVersionData[2]; + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + + Assert.Equal(S_FALSE, hr); + Assert.Equal(2, count); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_PopulatesCodeAddrAndNodePtr(MockTarget.Architecture arch) + { + var codeAddr = new TargetCodePointer(0x6000_0100); + var nodeAddr = new TargetPointer(0x7000_0001); + var versions = new[] + { + new VersionInfo(codeAddr, nodeAddr, NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + }; + + ISOSDacInterface5 dac5 = CreateDac5(arch, versions); + var buffer = new DacpTieredVersionData[2]; + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + + Assert.Equal(S_OK, hr); + Assert.Equal(1, count); + Assert.Equal((ulong)codeAddr.Value, (ulong)buffer[0].nativeCodeAddr); + Assert.Equal(nodeAddr.Value, (ulong)buffer[0].nativeCodeVersionNodePtr); + } + + [Theory] + [ClassData(typeof(MockTarget.StdArch))] + public void GetTieredVersions_NoVersions(MockTarget.Architecture arch) + { + ISOSDacInterface5 dac5 = CreateDac5(arch, versions: []); + var buffer = new DacpTieredVersionData[1]; + int count; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 1, &count); + + Assert.Equal(S_OK, hr); + Assert.Equal(0, count); + } +} From 2c080d7d0b6471ad59e2d6c736af6842e779e49f Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Tue, 31 Mar 2026 13:09:58 -0700 Subject: [PATCH 03/11] Apply pr suggestions --- docs/design/datacontracts/CodeVersions.md | 28 ++++----- docs/design/datacontracts/Loader.md | 13 ----- .../design/datacontracts/RuntimeTypeSystem.md | 8 +-- src/coreclr/debug/daccess/request.cpp | 6 +- src/coreclr/inc/cordbpriv.h | 6 +- src/coreclr/vm/ceeload.cpp | 4 -- src/coreclr/vm/ceeload.h | 27 +-------- .../vm/datadescriptor/datadescriptor.inc | 9 --- src/coreclr/vm/eeconfig.h | 10 ---- .../Contracts/ILoader.cs | 10 ---- .../Contracts/IRuntimeTypeSystem.cs | 8 --- .../DataType.cs | 1 - .../Constants.cs | 2 - .../Contracts/CodeVersions_1.cs | 4 -- .../Contracts/Loader_1.cs | 11 ---- .../Contracts/RuntimeTypeSystem_1.cs | 50 ---------------- .../Data/EEConfig.cs | 23 -------- .../SOSDacImpl.cs | 6 +- .../managed/cdac/tests/CodeVersionsTests.cs | 5 +- .../cdac/tests/SOSDacInterface5Tests.cs | 58 ++++++------------- 20 files changed, 42 insertions(+), 247 deletions(-) delete mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 0cb8fd68de5a15..36a159da84e71d 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -22,6 +22,19 @@ internal struct NativeCodeVersionHandle } ``` +```csharp +public enum NativeCodeVersionOptimizationTier : uint +{ + OptimizationTier0, + OptimizationTier1, + OptimizationTier1OSR, + OptimizationTierOptimized, + OptimizationTier0Instrumented, + OptimizationTier1Instrumented, + OptimizationTierUnknown = 0xFFFFFFFF +} +``` + ```csharp // Return a handle to the active version of the IL code for a given method descriptor public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc); @@ -56,19 +69,6 @@ public virtual bool HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle); public virtual NativeCodeVersionOptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle); ``` -```csharp -public enum NativeCodeVersionOptimizationTier : uint -{ - OptimizationTier0, - OptimizationTier1, - OptimizationTier1OSR, - OptimizationTierOptimized, - OptimizationTier0Instrumented, - OptimizationTier1Instrumented, - OptimizationTierUnknown = 0xFFFFFFFF -} -``` - ### Extension Methods ```csharp // Return a handle to the active version of the native code for a given method descriptor @@ -408,4 +408,4 @@ bool ICodeVersions.HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle) { return ilCodeVersionHandle.IsExplicit ? AsNode(ilCodeVersionHandle).ILAddress == TargetPointer.Null : true; } -``` \ No newline at end of file +``` diff --git a/docs/design/datacontracts/Loader.md b/docs/design/datacontracts/Loader.md index bac6574dca751b..7bbb2c31f1d98e 100644 --- a/docs/design/datacontracts/Loader.md +++ b/docs/design/datacontracts/Loader.md @@ -18,15 +18,6 @@ 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 - ProfilerDisableOpt = 0x00000080, // Profiler disabled JIT optimizations when module was loaded - AllMethodsJitOptimizationDisabled = 0x00200000, // Precomputed: JIT optimization is disabled for all methods in this module -} - -[Flags] -enum DebuggerAssemblyControlFlags -{ - DACF_USER_OVERRIDE = 0x01, - DACF_ALLOW_JIT_OPTS = 0x02, } [Flags] @@ -79,7 +70,6 @@ IEnumerable GetInstantiatedMethods(ModuleHandle handle); bool IsProbeExtensionResultValid(ModuleHandle handle); ModuleFlags GetFlags(ModuleHandle handle); bool IsReadyToRun(ModuleHandle handle); -DebuggerAssemblyControlFlags GetDebuggerInfoBits(ModuleHandle handle); bool TryGetSimpleName(ModuleHandle handle, out string simpleName); string GetPath(ModuleHandle handle); string GetFileName(ModuleHandle handle); @@ -220,7 +210,6 @@ private enum ModuleFlags_1 : uint 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 - AllMethodsJitOptimizationDisabled = 0x00200000, // Precomputed: JIT optimization is disabled for all methods in this module } private enum PEImageFlags : uint @@ -581,8 +570,6 @@ private static ModuleFlags GetFlags(uint flags) flags |= ModuleFlags.EditAndContinue; if (runtimeFlags.HasFlag(ModuleFlags_1.ReflectionEmit)) flags |= ModuleFlags.ReflectionEmit; - if (runtimeFlags.HasFlag(ModuleFlags_1.AllMethodsJitOptimizationDisabled)) - flags |= ModuleFlags.AllMethodsJitOptimizationDisabled; return flags; } diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 2019979f677d02..42bc56d6ae968d 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -199,15 +199,9 @@ partial interface IRuntimeTypeSystem : IContract // Gets the optimization tier stored on the MethodDesc's code data public virtual NativeCodeVersionOptimizationTier GetMethodDescOptimizationTier(MethodDescHandle methodDesc); - // Gets the initial optimization tier for a method - public virtual NativeCodeVersionOptimizationTier GetInitialOptimizationTier(MethodDescHandle methodDesc); - // Returns true if the method is eligible for tiered compilation public virtual bool IsEligibleForTieredCompilation(MethodDescHandle methodDesc); - // Returns true if JIT optimization is disabled for the method (module-level + per-method checks) - public virtual bool IsJitOptimizationDisabled(MethodDescHandle methodDesc); - } ``` @@ -1810,4 +1804,4 @@ void GetCoreLibFieldDescAndDef(string @namespace, string typeName, string fieldN MetadataReader mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle)!; fieldDef = mdReader.GetFieldDefinition(fieldHandle); } -``` \ No newline at end of file +``` diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index b644768a3e90c1..0d44575531dc4f 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -1279,13 +1279,9 @@ HRESULT ClrDataAccess::GetTieredVersions( break; } } - else if (pMD->IsJitOptimizationDisabled()) - { - nativeCodeAddrs[count].OptimizationTier = DacpTieredVersionData::OptimizationTier_MinOptJitted; - } else { - nativeCodeAddrs[count].OptimizationTier = DacpTieredVersionData::OptimizationTier_Optimized; + nativeCodeAddrs[count].OptimizationTier = DacpTieredVersionData::OptimizationTier_Unknown; } ++count; diff --git a/src/coreclr/inc/cordbpriv.h b/src/coreclr/inc/cordbpriv.h index 83a615b2de6f83..32a85c28b07401 100644 --- a/src/coreclr/inc/cordbpriv.h +++ b/src/coreclr/inc/cordbpriv.h @@ -36,7 +36,7 @@ enum DebuggerControlFlag DBCF_USER_MASK = 0x00FF, DBCF_GENERATE_DEBUG_CODE = 0x0001, - DBCF_ALLOW_JIT_OPT = 0x0008, // [cDAC] [RuntimeTypeSystem]: Contract depends on this value. + DBCF_ALLOW_JIT_OPT = 0x0008, DBCF_PROFILER_ENABLED = 0x0020, // DBCF_ACTIVATE_REMOTE_DEBUGGING = 0x0040, Deprecated. DO NOT USE @@ -53,8 +53,8 @@ enum DebuggerControlFlag enum DebuggerAssemblyControlFlags { DACF_NONE = 0x00, - DACF_USER_OVERRIDE = 0x01, // [cDAC] [Loader]: Contract depends on this value. - DACF_ALLOW_JIT_OPTS = 0x02, // [cDAC] [Loader]: Contract depends on this value. + DACF_USER_OVERRIDE = 0x01, + DACF_ALLOW_JIT_OPTS = 0x02, DACF_OBSOLETE_TRACK_JIT_INFO = 0x04, // obsolete in V2.0, we're always tracking. DACF_ENC_ENABLED = 0x08, DACF_IGNORE_PDBS = 0x20, diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 57d0a10d587d30..e04a30dfd958f7 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -521,8 +521,6 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) #endif // PROFILING_SUPPORTED LOG((LF_CLASSLOADER, LL_INFO10, "Loaded pModule: \"%s\".\n", GetDebugName())); - - UpdateAllMethodsJITOptimizationDisabledFlag(); } #endif // DACCESS_COMPILE @@ -551,8 +549,6 @@ void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits) } #endif // DEBUGGING_SUPPORTED - UpdateAllMethodsJITOptimizationDisabledFlag(); - #if defined(DACCESS_COMPILE) // Now that we've changed m_dwTransientFlags, update that in the target too. // This will fail for read-only target. diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 9a3c6d43c58789..1bcc3b2bda95e1 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -618,7 +618,7 @@ class Module : public ModuleBase enum { // These are the values set in m_dwTransientFlags. - // [cDAC] [Loader]: Contract depends on the values of MODULE_IS_TENURED, IS_EDIT_AND_CONTINUE, IS_REFLECTION_EMIT, and PROF_DISABLE_OPTIMIZATIONS. + // [cDAC] [Loader]: Contract depends on the values of MODULE_IS_TENURED, IS_EDIT_AND_CONTINUE, and IS_REFLECTION_EMIT. MODULE_IS_TENURED = 0x00000001, // Set once we know for sure the Module will not be freed until the appdomain itself exits // unused = 0x00000002, @@ -643,17 +643,12 @@ class Module : public ModuleBase DEBUGGER_ENC_ENABLED_PRIV = 0x00002000, // this is what was attempted to be set. IS_EDIT_AND_CONTINUE is actual result. DEBUGGER_PDBS_COPIED = 0x00004000, DEBUGGER_IGNORE_PDBS = 0x00008000, - DEBUGGER_INFO_MASK_PRIV = 0x0000Fc00, // [cDAC] [Loader]: Contract depends on this value. - DEBUGGER_INFO_SHIFT_PRIV = 10, // [cDAC] [Loader]: Contract depends on this value. + DEBUGGER_INFO_MASK_PRIV = 0x0000Fc00, + DEBUGGER_INFO_SHIFT_PRIV = 10, // Used to indicate that this module has had it's IJW fixups properly installed. IS_IJW_FIXED_UP = 0x00080000, IS_BEING_UNLOADED = 0x00100000, - - // [cDAC] [RuntimeTypeSystem]: Contract depends on this value. - // Precomputed flag combining debugger, profiler, and EEConfig checks. - // Set during module initialization; see UpdateAllMethodsJITOptimizationDisabledFlag(). - ALL_METHODS_JIT_OPTIMIZATION_DISABLED = 0x00200000, }; static_assert(DEBUGGER_USER_OVERRIDE_PRIV >> DEBUGGER_INFO_SHIFT_PRIV == DebuggerAssemblyControlFlags::DACF_USER_OVERRIDE); @@ -966,22 +961,6 @@ class Module : public ModuleBase return FALSE; } - // Updates the ALL_METHODS_JIT_OPTIMIZATION_DISABLED precomputed flag. - // Must be called after debugger info bits, profiler flags, or EEConfig are finalized. - void UpdateAllMethodsJITOptimizationDisabledFlag() - { - WRAPPER_NO_CONTRACT; - - BOOL disabled = AreJITOptimizationsDisabled() || - g_pConfig->JitMinOpts() || - g_pConfig->GenDebuggableCode(); - - if (disabled) - SetTransientFlagInterlocked(ALL_METHODS_JIT_OPTIMIZATION_DISABLED); - else - SetTransientFlagInterlockedWithMask(0, ALL_METHODS_JIT_OPTIMIZATION_DISABLED); - } - #ifdef FEATURE_METADATA_UPDATER // Holds a table of EnCEEClassData object for classes in this module that have been modified CUnorderedArray m_ClassList; diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 300fe56343d51b..d8b144b8e6d63e 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1244,13 +1244,6 @@ CDAC_TYPE_FIELD(WebcilSectionHeader, /*uint32*/, PointerToRawData, offsetof(Webc CDAC_TYPE_END(WebcilSectionHeader) #endif -CDAC_TYPE_BEGIN(EEConfig) -CDAC_TYPE_INDETERMINATE(EEConfig) -CDAC_TYPE_FIELD(EEConfig, /*uint8*/, JitMinOpts, cdac_data::JitMinOpts) -CDAC_TYPE_FIELD(EEConfig, /*uint8*/, GenDebuggable, cdac_data::GenDebuggable) -CDAC_TYPE_FIELD(EEConfig, /*uint32*/, TieredCompilation_DefaultTier, cdac_data::TieredCompilation_DefaultTier) -CDAC_TYPE_END(EEConfig) - CDAC_TYPES_END() CDAC_GLOBALS_BEGIN() @@ -1296,7 +1289,6 @@ CDAC_GLOBAL_STRING(RID, RID_STRING) CDAC_GLOBAL(GCInfoVersion, uint32, GCINFO_VERSION) -CDAC_GLOBAL_POINTER(EEConfig, &::g_pConfig) CDAC_GLOBAL_POINTER(AppDomain, &AppDomain::m_pTheAppDomain) CDAC_GLOBAL_POINTER(SystemDomain, cdac_data::SystemDomainPtr) CDAC_GLOBAL_POINTER(ThreadStore, &ThreadStore::s_pThreadStore) @@ -1311,7 +1303,6 @@ CDAC_GLOBAL_POINTER(GCThread, &::g_pSuspensionThread) #undef FRAME_TYPE_NAME CDAC_GLOBAL(MethodDescTokenRemainderBitCount, uint8, METHOD_TOKEN_REMAINDER_BIT_COUNT) -CDAC_GLOBAL_POINTER(CORDebuggerControlFlags, &g_CORDebuggerControlFlags) #if FEATURE_COMINTEROP CDAC_GLOBAL(FeatureCOMInterop, uint8, 1) #else diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index 28b54665e80ceb..07ce98696e4e46 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -713,16 +713,6 @@ 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 GenDebuggable = offsetof(EEConfig, fDebuggable); - static constexpr size_t TieredCompilation_DefaultTier = offsetof(EEConfig, tieredCompilation_DefaultTier); }; 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 f453d48fd54382..1a3828bb3de62c 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 @@ -22,15 +22,6 @@ public enum ModuleFlags 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 - ProfilerDisableOpt = 0x80, // Profiler disabled JIT optimizations when module was loaded - AllMethodsJitOptimizationDisabled = 0x00200000, // Precomputed: JIT optimization is disabled for all methods in this module -} - -[Flags] -public enum DebuggerAssemblyControlFlags -{ - DACF_USER_OVERRIDE = 0x01, - DACF_ALLOW_JIT_OPTS = 0x02, } [Flags] @@ -85,7 +76,6 @@ public interface ILoader : IContract bool IsProbeExtensionResultValid(ModuleHandle handle) => throw new NotImplementedException(); ModuleFlags GetFlags(ModuleHandle handle) => throw new NotImplementedException(); bool IsReadyToRun(ModuleHandle handle) => throw new NotImplementedException(); - DebuggerAssemblyControlFlags GetDebuggerInfoBits(ModuleHandle handle) => throw new NotImplementedException(); bool TryGetSimpleName(ModuleHandle handle, out string simpleName) => throw new NotImplementedException(); string GetPath(ModuleHandle handle) => throw new NotImplementedException(); string GetFileName(ModuleHandle handle) => 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 6c5cfde6f26501..69ec13d3a24893 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 @@ -78,12 +78,6 @@ public enum ArrayFunctionType Constructor = 3 } -[Flags] -public enum DebuggerControlFlag -{ - DBCF_ALLOW_JIT_OPT = 0x0008, -} - public interface IRuntimeTypeSystem : IContract { static string IContract.Name => nameof(RuntimeTypeSystem); @@ -215,9 +209,7 @@ public interface IRuntimeTypeSystem : IContract TargetPointer GetGCStressCodeCopy(MethodDescHandle methodDesc) => throw new NotImplementedException(); NativeCodeVersionOptimizationTier GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); - NativeCodeVersionOptimizationTier GetInitialOptimizationTier(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); bool IsEligibleForTieredCompilation(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); - bool IsJitOptimizationDisabled(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); #endregion MethodDesc inspection APIs #region FieldDesc inspection APIs TargetPointer GetMTOfEnclosingClass(TargetPointer fieldDescPointer) => 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 266437e05ad46e..89f9f2e5559378 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs @@ -135,7 +135,6 @@ public enum DataType PatchpointInfo, PortableEntryPoint, VirtualCallStubManager, - EEConfig, TransitionBlock, DebuggerEval, 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 e97ed6e9ed53b1..eafeb8137df884 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -73,7 +73,6 @@ public static class Globals public const string SizeOfGenericModeBlock = nameof(SizeOfGenericModeBlock); public const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount); - public const string CORDebuggerControlFlags = nameof(CORDebuggerControlFlags); public const string DirectorySeparator = nameof(DirectorySeparator); public const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress); @@ -155,7 +154,6 @@ public static class Globals public const string HandlesPerBlock = nameof(HandlesPerBlock); public const string BlockInvalid = nameof(BlockInvalid); public const string TotalCpuCount = nameof(TotalCpuCount); - public const string EEConfig = nameof(EEConfig); } public static class FieldNames { 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 1fa1e3ed88b636..45c67873adeba1 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 @@ -433,10 +433,6 @@ NativeCodeVersionOptimizationTier ICodeVersions.GetOptimizationTier(NativeCodeVe IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; MethodDescHandle methodDescHandle = rtsContract.GetMethodDescHandle(codeVersionHandle.MethodDescAddress); NativeCodeVersionOptimizationTier optimizationTier = rtsContract.GetMethodDescOptimizationTier(methodDescHandle); - if (optimizationTier == NativeCodeVersionOptimizationTier.OptimizationTierUnknown) - { - return rtsContract.GetInitialOptimizationTier(methodDescHandle); - } return 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 205087b405355d..9f23be73d90167 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 @@ -14,8 +14,6 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; { private const string DefaultDomainFriendlyName = "DefaultDomain"; private const uint ASSEMBLY_NOTIFYFLAGS_PROFILER_NOTIFIED = 0x1; // Assembly Notify Flag for profiler notification - private const uint DEBUGGER_INFO_MASK_PRIV = 0x0000FC00; - private const int DEBUGGER_INFO_SHIFT_PRIV = 10; private const ushort MaxWebcilSections = 16; // Must stay in sync with native WEBCIL_MAX_SECTIONS. private enum ModuleFlags_1 : uint @@ -23,7 +21,6 @@ private enum ModuleFlags_1 : uint 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 - ProfilerDisableOpt = 0x80, // Profiler disabled JIT optimizations when module was loaded } private enum PEImageFlags : uint @@ -369,8 +366,6 @@ private static ModuleFlags GetFlags(Data.Module module) flags |= ModuleFlags.EditAndContinue; if (runtimeFlags.HasFlag(ModuleFlags_1.ReflectionEmit)) flags |= ModuleFlags.ReflectionEmit; - if (runtimeFlags.HasFlag(ModuleFlags_1.ProfilerDisableOpt)) - flags |= ModuleFlags.ProfilerDisableOpt; return flags; } @@ -387,12 +382,6 @@ bool ILoader.IsReadyToRun(ModuleHandle handle) return module.ReadyToRunInfo != TargetPointer.Null; } - DebuggerAssemblyControlFlags ILoader.GetDebuggerInfoBits(ModuleHandle handle) - { - Data.Module module = _target.ProcessedData.GetOrAdd(handle.Address); - return (DebuggerAssemblyControlFlags)((module.Flags & DEBUGGER_INFO_MASK_PRIV) >> DEBUGGER_INFO_SHIFT_PRIV); - } - bool ILoader.TryGetSimpleName(ModuleHandle handle, out string simpleName) { simpleName = string.Empty; 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 0d948da921704b..05e45112aac5ed 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 @@ -1664,56 +1664,6 @@ bool IRuntimeTypeSystem.IsEligibleForTieredCompilation(MethodDescHandle methodDe return methodDesc.IsEligibleForTieredCompilation; } - private bool IsJitOptimizationDisabledForSpecificMethod(MethodDescHandle methodDescHandle) - { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; - MethodTable methodTable = GetOrCreateMethodTable(methodDesc); - ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(methodTable.Module); - MetadataReader? mdReader = _target.Contracts.EcmaMetadata.GetMetadata(moduleHandle); - - bool isNoMetadata = methodDesc.Classification == MethodClassification.Dynamic; - bool isMiNoOptimization = false; - if (mdReader is not null) - { - MethodDefinitionHandle methodDefHandle = MetadataTokens.MethodDefinitionHandle((int)methodDesc.Token); - MethodDefinition methodDef = mdReader.GetMethodDefinition(methodDefHandle); - MethodImplAttributes implAttrs = methodDef.ImplAttributes; - isMiNoOptimization = (implAttrs & MethodImplAttributes.NoOptimization) != 0; - } - else if (!isNoMetadata) - { - return false; - } - - return !isNoMetadata && isMiNoOptimization; - } - - private bool IsJitOptimizationDisabledForModule(MethodDescHandle methodDescHandle) - { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; - MethodTable methodTable = GetOrCreateMethodTable(methodDesc); - ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(methodTable.Module); - return _target.Contracts.Loader.GetFlags(moduleHandle).HasFlag(ModuleFlags.AllMethodsJitOptimizationDisabled); - } - - bool IRuntimeTypeSystem.IsJitOptimizationDisabled(MethodDescHandle methodDescHandle) - { - return IsJitOptimizationDisabledForModule(methodDescHandle) || IsJitOptimizationDisabledForSpecificMethod(methodDescHandle); - } - - NativeCodeVersionOptimizationTier IRuntimeTypeSystem.GetInitialOptimizationTier(MethodDescHandle methodDescHandle) - { - MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; - if (!methodDesc.IsEligibleForTieredCompilation) - { - return NativeCodeVersionOptimizationTier.OptimizationTierOptimized; - } - - TargetPointer eeConfigPtr = _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.EEConfig)); - Data.EEConfig eeConfig = _target.ProcessedData.GetOrAdd(eeConfigPtr); - return (NativeCodeVersionOptimizationTier)eeConfig.TieredCompilation_DefaultTier; - } - private sealed class NonValidatedMethodTableQueries : MethodValidation.IMethodTableQueries { private readonly RuntimeTypeSystem_1 _rts; 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 deleted file mode 100644 index 6b9afa03a56bcb..00000000000000 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EEConfig.cs +++ /dev/null @@ -1,23 +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 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; - GenDebuggable = target.Read(address + (ulong)type.Fields[nameof(GenDebuggable)].Offset) != 0; - TieredCompilation_DefaultTier = target.Read(address + (ulong)type.Fields[nameof(TieredCompilation_DefaultTier)].Offset); - } - - public bool JitMinOpts { get; init; } - public bool GenDebuggable { get; init; } - public uint TieredCompilation_DefaultTier { get; init; } -} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 9948beaa6ccd79..71fcd14fa46429 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -4886,13 +4886,9 @@ int ISOSDacInterface5.GetTieredVersions( break; } } - else if (runtimeTypeSystemContract.IsJitOptimizationDisabled(methodDescHandle)) - { - nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.MinOptJitted; - } else { - nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.Optimized; + nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.Unknown; } count++; diff --git a/src/native/managed/cdac/tests/CodeVersionsTests.cs b/src/native/managed/cdac/tests/CodeVersionsTests.cs index 5acd3e08e10377..fd2f02c4bacced 100644 --- a/src/native/managed/cdac/tests/CodeVersionsTests.cs +++ b/src/native/managed/cdac/tests/CodeVersionsTests.cs @@ -821,7 +821,7 @@ public void GetOptimizationTier_Synthetic_DelegatesToRuntimeTypeSystem(MockTarge [Theory] [ClassData(typeof(MockTarget.StdArch))] - public void GetOptimizationTier_Synthetic_FallsBackToInitialTier(MockTarget.Architecture arch) + public void GetOptimizationTier_Synthetic_NoCodeData(MockTarget.Architecture arch) { MockCodeVersions builder = new(arch); TargetPointer methodDescAddress = new(0x1a0a_0000); @@ -830,13 +830,12 @@ public void GetOptimizationTier_Synthetic_FallsBackToInitialTier(MockTarget.Arch MethodDescHandle mdHandle = new(methodDescAddress); mockRTS.Setup(r => r.GetMethodDescHandle(methodDescAddress)).Returns(mdHandle); mockRTS.Setup(r => r.GetMethodDescOptimizationTier(mdHandle)).Returns(NativeCodeVersionOptimizationTier.OptimizationTierUnknown); - mockRTS.Setup(r => r.GetInitialOptimizationTier(mdHandle)).Returns(NativeCodeVersionOptimizationTier.OptimizationTier0); var target = CreateTarget(arch, builder, mockRuntimeTypeSystem: mockRTS); var codeVersions = target.Contracts.CodeVersions; NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateSynthetic(methodDescAddress); NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); - Assert.Equal(NativeCodeVersionOptimizationTier.OptimizationTier0, tier); + Assert.Equal(NativeCodeVersionOptimizationTier.OptimizationTierUnknown, tier); } } diff --git a/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs b/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs index a9ee6b4472bc54..c6d5b7ba422ce1 100644 --- a/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs +++ b/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs @@ -27,7 +27,6 @@ private static ISOSDacInterface5 CreateDac5( MockTarget.Architecture arch, VersionInfo[]? versions = null, bool isEligibleForTieredCompilation = false, - bool isJitOptimizationDisabled = false, bool isReadyToRun = false, TargetPointer r2rBase = default, uint r2rSize = 0, @@ -66,9 +65,6 @@ private static ISOSDacInterface5 CreateDac5( mockRts .Setup(r => r.IsEligibleForTieredCompilation(methodDescHandle)) .Returns(isEligibleForTieredCompilation); - mockRts - .Setup(r => r.IsJitOptimizationDisabled(methodDescHandle)) - .Returns(isJitOptimizationDisabled); mockLoader .Setup(l => l.GetModuleHandleFromModulePtr(s_moduleAddr)) @@ -121,6 +117,14 @@ private static ISOSDacInterface5 CreateDac5( return new SOSDacImpl(target, legacyObj: null); } + private static int CallGetTieredVersions(ISOSDacInterface5 dac5, DacpTieredVersionData[] buffer, out int count, int rejitId = 0) + { + int localCount; + int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, rejitId, buffer, buffer.Length, &localCount); + count = localCount; + return hr; + } + [Theory] [ClassData(typeof(MockTarget.StdArch))] public void GetTieredVersions_ZeroMethodDesc(MockTarget.Architecture arch) @@ -157,9 +161,7 @@ public void GetTieredVersions_NullOutputPtr(MockTarget.Architecture arch) public void GetTieredVersions_InvalidRejitId(MockTarget.Architecture arch) { ISOSDacInterface5 dac5 = CreateDac5(arch, rejitId: 0); - var buffer = new DacpTieredVersionData[1]; - int count; - int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 999, buffer, 1, &count); + int hr = CallGetTieredVersions(dac5, new DacpTieredVersionData[1], out _, rejitId: 999); Assert.NotEqual(S_OK, hr); } @@ -176,8 +178,7 @@ public void GetTieredVersions_ReadyToRun(MockTarget.Architecture arch) ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isReadyToRun: true, r2rBase: r2rBase, r2rSize: r2rSize); var buffer = new DacpTieredVersionData[2]; - int count; - int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + int hr = CallGetTieredVersions(dac5, buffer, out int count); Assert.Equal(S_OK, hr); Assert.Equal(1, count); @@ -223,8 +224,7 @@ public void GetTieredVersions_TieredCompilation( ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isEligibleForTieredCompilation: true); var buffer = new DacpTieredVersionData[2]; - int count; - int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + int hr = CallGetTieredVersions(dac5, buffer, out int count); Assert.Equal(S_OK, hr); Assert.Equal(1, count); @@ -233,26 +233,7 @@ public void GetTieredVersions_TieredCompilation( [Theory] [ClassData(typeof(MockTarget.StdArch))] - public void GetTieredVersions_JitOptimizationDisabled(MockTarget.Architecture arch) - { - var versions = new[] - { - new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), NativeCodeVersionOptimizationTier.OptimizationTierOptimized), - }; - - ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isJitOptimizationDisabled: true); - var buffer = new DacpTieredVersionData[2]; - int count; - int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); - - Assert.Equal(S_OK, hr); - Assert.Equal(1, count); - Assert.Equal(DacpTieredVersionData.OptimizationTier.MinOptJitted, buffer[0].optimizationTier); - } - - [Theory] - [ClassData(typeof(MockTarget.StdArch))] - public void GetTieredVersions_DefaultFallthrough(MockTarget.Architecture arch) + public void GetTieredVersions_NotEligibleForTieredCompilation(MockTarget.Architecture arch) { var versions = new[] { @@ -261,12 +242,11 @@ public void GetTieredVersions_DefaultFallthrough(MockTarget.Architecture arch) ISOSDacInterface5 dac5 = CreateDac5(arch, versions); var buffer = new DacpTieredVersionData[2]; - int count; - int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + int hr = CallGetTieredVersions(dac5, buffer, out int count); Assert.Equal(S_OK, hr); Assert.Equal(1, count); - Assert.Equal(DacpTieredVersionData.OptimizationTier.Optimized, buffer[0].optimizationTier); + Assert.Equal(DacpTieredVersionData.OptimizationTier.Unknown, buffer[0].optimizationTier); } [Theory] @@ -282,8 +262,7 @@ public void GetTieredVersions_BufferTooSmall(MockTarget.Architecture arch) ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isEligibleForTieredCompilation: true); var buffer = new DacpTieredVersionData[2]; - int count; - int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + int hr = CallGetTieredVersions(dac5, buffer, out int count); Assert.Equal(S_FALSE, hr); Assert.Equal(2, count); @@ -302,8 +281,7 @@ public void GetTieredVersions_PopulatesCodeAddrAndNodePtr(MockTarget.Architectur ISOSDacInterface5 dac5 = CreateDac5(arch, versions); var buffer = new DacpTieredVersionData[2]; - int count; - int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 2, &count); + int hr = CallGetTieredVersions(dac5, buffer, out int count); Assert.Equal(S_OK, hr); Assert.Equal(1, count); @@ -316,9 +294,7 @@ public void GetTieredVersions_PopulatesCodeAddrAndNodePtr(MockTarget.Architectur public void GetTieredVersions_NoVersions(MockTarget.Architecture arch) { ISOSDacInterface5 dac5 = CreateDac5(arch, versions: []); - var buffer = new DacpTieredVersionData[1]; - int count; - int hr = dac5.GetTieredVersions((ClrDataAddress)s_methodDescAddr.Value, 0, buffer, 1, &count); + int hr = CallGetTieredVersions(dac5, new DacpTieredVersionData[1], out int count); Assert.Equal(S_OK, hr); Assert.Equal(0, count); From 813d2da3c9973046e6a3f89d4e1dd47706672379 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Tue, 31 Mar 2026 13:45:09 -0700 Subject: [PATCH 04/11] Apply pr suggestions --- .../ISOSDacInterface.cs | 18 +++++++++--------- .../SOSDacImpl.cs | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs index f913642a7a02ce..89ecf06a331fb8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs @@ -948,15 +948,15 @@ public struct DacpTieredVersionData { public enum OptimizationTier { - Unknown, - MinOptJitted, - Optimized, - QuickJitted, - OptimizedTier1, - ReadyToRun, - OptimizedTier1OSR, - QuickJittedInstrumented, - OptimizedTier1Instrumented, + Unknown = 0, + MinOptJitted = 1, + Optimized = 2, + QuickJitted = 3, + OptimizedTier1 = 4, + ReadyToRun = 5, + OptimizedTier1OSR = 6, + QuickJittedInstrumented = 7, + OptimizedTier1Instrumented = 8, } public ClrDataAddress nativeCodeAddr; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 29d65f101f66d4..ad33061a1b88b2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -4991,6 +4991,8 @@ int ISOSDacInterface5.GetTieredVersions( ClrDataAddress r2rImageBaseAddr = r2rImageBase.ToClrDataAddress(_target); ClrDataAddress r2rImageEndAddr = r2rImageEnd.ToClrDataAddress(_target); + bool isEligibleForTieredCompilation = runtimeTypeSystemContract.IsEligibleForTieredCompilation(methodDescHandle); + int count = 0; foreach (NativeCodeVersionHandle nativeCodeVersionHandle in codeVersions.GetNativeCodeVersions(methodDescPtr, ilCodeVersionHandle)) { @@ -5002,7 +5004,7 @@ int ISOSDacInterface5.GetTieredVersions( { nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.ReadyToRun; } - else if (runtimeTypeSystemContract.IsEligibleForTieredCompilation(methodDescHandle)) + else if (isEligibleForTieredCompilation) { switch (codeVersions.GetOptimizationTier(nativeCodeVersionHandle)) { From 281f91c0e495260b0204b3a6eedea355485b7c24 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Wed, 1 Apr 2026 14:44:55 -0700 Subject: [PATCH 05/11] Remove redundant conditional checks, separate native optimization tier enum from the managed --- docs/design/datacontracts/CodeVersions.md | 13 ----- .../design/datacontracts/RuntimeTypeSystem.md | 27 ++++++++++ .../Contracts/ICodeVersions.cs | 11 ---- .../Contracts/IRuntimeTypeSystem.cs | 12 +++++ .../Contracts/CodeVersions_1.cs | 4 +- .../Contracts/RuntimeTypeSystem_1.cs | 29 ++++++++-- .../Data/MethodDescCodeData.cs | 5 +- .../Data/NativeCodeVersionNode.cs | 5 +- .../managed/cdac/tests/CodeVersionsTests.cs | 54 +++---------------- 9 files changed, 76 insertions(+), 84 deletions(-) diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 36a159da84e71d..454be4e3d43000 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -22,19 +22,6 @@ internal struct NativeCodeVersionHandle } ``` -```csharp -public enum NativeCodeVersionOptimizationTier : uint -{ - OptimizationTier0, - OptimizationTier1, - OptimizationTier1OSR, - OptimizationTierOptimized, - OptimizationTier0Instrumented, - OptimizationTier1Instrumented, - OptimizationTierUnknown = 0xFFFFFFFF -} -``` - ```csharp // Return a handle to the active version of the IL code for a given method descriptor public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc); diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 42bc56d6ae968d..e6657eb0a2f2e8 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -126,6 +126,19 @@ public enum ArrayFunctionType } ``` +```csharp +public enum NativeCodeVersionOptimizationTier +{ + OptimizationTierUnknown, + OptimizationTier0, + OptimizationTier1, + OptimizationTier1OSR, + OptimizationTierOptimized, + OptimizationTier0Instrumented, + OptimizationTier1Instrumented, +} +``` + ```csharp partial interface IRuntimeTypeSystem : IContract { @@ -430,6 +443,20 @@ The contract additionally depends on these data descriptors | `GenericsDictInfo` | `NumDicts` | Number of instantiation dictionaries, including inherited ones, in this `GenericsDictInfo` | | `GenericsDictInfo` | `NumTypeArgs` | Number of type arguments in the type or method instantiation described by this `GenericsDictInfo` | +The value of the `NativeCodeVersionNode::OptimizationTier` field is one of: +```csharp +private enum NativeCodeVersionOptimizationTier_1 : uint +{ + OptimizationTier0 = 0, + OptimizationTier1 = 1, + OptimizationTier1OSR = 2, + OptimizationTierOptimized = 3, + OptimizationTier0Instrumented = 4, + OptimizationTier1Instrumented = 5, + OptimizationTierUnknown = 0xFFFFFFFF +} +``` + Contracts used: | Contract Name | | --- | 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 8ec9054fa40b23..370f1282e1d3f3 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 @@ -102,14 +102,3 @@ public static NativeCodeVersionHandle CreateSynthetic(TargetPointer methodDescAd { // throws NotImplementedException for all methods } - -public enum NativeCodeVersionOptimizationTier : uint -{ - OptimizationTier0, - OptimizationTier1, - OptimizationTier1OSR, - OptimizationTierOptimized, - OptimizationTier0Instrumented, - OptimizationTier1Instrumented, - OptimizationTierUnknown = 0xFFFFFFFF -} 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 69ec13d3a24893..078d8dc53bdc3f 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 @@ -78,6 +78,18 @@ public enum ArrayFunctionType Constructor = 3 } +public enum NativeCodeVersionOptimizationTier : uint +{ + OptimizationTierUnknown, + OptimizationTier0, + OptimizationTier1, + OptimizationTier1OSR, + OptimizationTierOptimized, + OptimizationTier0Instrumented, + OptimizationTier1Instrumented, +} + + public interface IRuntimeTypeSystem : IContract { static string IContract.Name => nameof(RuntimeTypeSystem); 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 45c67873adeba1..1396c12e28289b 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 @@ -424,9 +424,7 @@ NativeCodeVersionOptimizationTier ICodeVersions.GetOptimizationTier(NativeCodeVe if (codeVersionHandle.IsExplicit) { NativeCodeVersionNode nativeCodeVersionNode = _target.ProcessedData.GetOrAdd(codeVersionHandle.CodeVersionNodeAddress); - return nativeCodeVersionNode.OptimizationTier is null - ? NativeCodeVersionOptimizationTier.OptimizationTierUnknown - : (NativeCodeVersionOptimizationTier) nativeCodeVersionNode.OptimizationTier; + return RuntimeTypeSystem_1.GetOptimizationTier(nativeCodeVersionNode.OptimizationTier); } else { 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 05e45112aac5ed..3b2d3e83994d08 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 @@ -325,6 +325,17 @@ public ulong SizeOfChunk } + private enum NativeCodeVersionOptimizationTier_1 : uint + { + OptimizationTier0, + OptimizationTier1, + OptimizationTier1OSR, + OptimizationTierOptimized, + OptimizationTier0Instrumented, + OptimizationTier1Instrumented, + OptimizationTierUnknown = 0xFFFFFFFF + } + private sealed class InstantiatedMethodDesc : IData { public static InstantiatedMethodDesc Create(Target target, TargetPointer address) => new InstantiatedMethodDesc(target, address); @@ -1645,6 +1656,20 @@ TargetPointer IRuntimeTypeSystem.GetGCStressCodeCopy(MethodDescHandle methodDesc return TargetPointer.Null; } + internal static NativeCodeVersionOptimizationTier GetOptimizationTier(uint? optimizationTier) + { + return (NativeCodeVersionOptimizationTier_1?)optimizationTier switch + { + NativeCodeVersionOptimizationTier_1.OptimizationTier0 => NativeCodeVersionOptimizationTier.OptimizationTier0, + NativeCodeVersionOptimizationTier_1.OptimizationTier1 => NativeCodeVersionOptimizationTier.OptimizationTier1, + NativeCodeVersionOptimizationTier_1.OptimizationTier1OSR => NativeCodeVersionOptimizationTier.OptimizationTier1OSR, + NativeCodeVersionOptimizationTier_1.OptimizationTierOptimized => NativeCodeVersionOptimizationTier.OptimizationTierOptimized, + NativeCodeVersionOptimizationTier_1.OptimizationTier0Instrumented => NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented, + NativeCodeVersionOptimizationTier_1.OptimizationTier1Instrumented => NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented, + _ => NativeCodeVersionOptimizationTier.OptimizationTierUnknown, + }; + } + NativeCodeVersionOptimizationTier IRuntimeTypeSystem.GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) { MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; @@ -1653,9 +1678,7 @@ NativeCodeVersionOptimizationTier IRuntimeTypeSystem.GetMethodDescOptimizationTi return NativeCodeVersionOptimizationTier.OptimizationTierUnknown; Data.MethodDescCodeData codeData = _target.ProcessedData.GetOrAdd(codeDataAddress); - return codeData.OptimizationTier is null - ? NativeCodeVersionOptimizationTier.OptimizationTierUnknown - : (NativeCodeVersionOptimizationTier)codeData.OptimizationTier; + return GetOptimizationTier(codeData.OptimizationTier); } bool IRuntimeTypeSystem.IsEligibleForTieredCompilation(MethodDescHandle methodDescHandle) 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 6cd0d58144c810..2cb6aa90b7bd63 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,10 +13,7 @@ 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); - if (type.Fields.ContainsKey(nameof(OptimizationTier))) - { - OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); - } + OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); } public TargetCodePointer TemporaryEntryPoint { get; set; } 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 55f79823fdf024..f849ad5da10f56 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,10 +21,7 @@ public NativeCodeVersionNode(Target target, TargetPointer address) { GCCoverageInfo = target.ReadPointer(address + (ulong)type.Fields[nameof(GCCoverageInfo)].Offset); } - if (type.Fields.ContainsKey(nameof(OptimizationTier))) - { - OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); - } + OptimizationTier = target.Read(address + (ulong)type.Fields[nameof(OptimizationTier)].Offset); } public TargetPointer Next { get; init; } diff --git a/src/native/managed/cdac/tests/CodeVersionsTests.cs b/src/native/managed/cdac/tests/CodeVersionsTests.cs index fd2f02c4bacced..8eb60ab275452b 100644 --- a/src/native/managed/cdac/tests/CodeVersionsTests.cs +++ b/src/native/managed/cdac/tests/CodeVersionsTests.cs @@ -728,18 +728,18 @@ public static IEnumerable GetOptimizationTierValues() foreach (var archData in new MockTarget.StdArch()) { var arch = (MockTarget.Architecture)archData[0]; - yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier0]; - yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier1]; - yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier1OSR]; - yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTierOptimized]; - yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented]; - yield return [arch, NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented]; + yield return [arch, 0u, NativeCodeVersionOptimizationTier.OptimizationTier0]; + yield return [arch, 1u, NativeCodeVersionOptimizationTier.OptimizationTier1]; + yield return [arch, 2u, NativeCodeVersionOptimizationTier.OptimizationTier1OSR]; + yield return [arch, 3u, NativeCodeVersionOptimizationTier.OptimizationTierOptimized]; + yield return [arch, 4u, NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented]; + yield return [arch, 5u, NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented]; } } [Theory] [MemberData(nameof(GetOptimizationTierValues))] - public void GetOptimizationTier_Explicit(MockTarget.Architecture arch, NativeCodeVersionOptimizationTier expectedTier) + public void GetOptimizationTier_Explicit(MockTarget.Architecture arch, uint nativeTier, NativeCodeVersionOptimizationTier expectedTier) { MockCodeVersions builder = new(arch); @@ -751,7 +751,7 @@ public void GetOptimizationTier_Explicit(MockTarget.Architecture arch, NativeCod next: TargetPointer.Null, isActive: true, ilVersionId: new(1), - optimizationTier: (uint)expectedTier); + optimizationTier: nativeTier); var target = CreateTarget(arch, builder); var codeVersions = target.Contracts.CodeVersions; @@ -761,44 +761,6 @@ public void GetOptimizationTier_Explicit(MockTarget.Architecture arch, NativeCod Assert.Equal(expectedTier, tier); } - [Theory] - [ClassData(typeof(MockTarget.StdArch))] - public void GetOptimizationTier_Explicit_MissingField(MockTarget.Architecture arch) - { - MockCodeVersions builder = new(arch); - - TargetPointer nativeCodeVersionNode = builder.AddNativeCodeVersionNode(); - builder.FillNativeCodeVersionNode( - nativeCodeVersionNode, - methodDesc: new TargetPointer(0x1a0a_0000), - nativeCode: new TargetCodePointer(0x0a0a_0000), - next: TargetPointer.Null, - isActive: true, - ilVersionId: new(1)); - - // Remove the OptimizationTier field from the type info to simulate a runtime - // that doesn't expose it (e.g. FEATURE_TIERED_COMPILATION disabled). - var typesWithoutTier = new Dictionary(builder.Types); - var ncvnType = typesWithoutTier[DataType.NativeCodeVersionNode]; - var fieldsWithoutTier = new Dictionary(ncvnType.Fields); - fieldsWithoutTier.Remove(nameof(Data.NativeCodeVersionNode.OptimizationTier)); - typesWithoutTier[DataType.NativeCodeVersionNode] = ncvnType with { Fields = fieldsWithoutTier }; - - TestPlaceholderTarget target = new TestPlaceholderTarget(arch, builder.Builder.GetMemoryContext().ReadFromTarget, typesWithoutTier); - IContractFactory cvfactory = new CodeVersionsFactory(); - ContractRegistry reg = Mock.Of( - c => c.CodeVersions == cvfactory.CreateContract(target, 1) - && c.RuntimeTypeSystem == Mock.Of() - && c.ExecutionManager == Mock.Of() - && c.Loader == Mock.Of()); - target.SetContracts(reg); - - var codeVersions = target.Contracts.CodeVersions; - NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateExplicit(nativeCodeVersionNode); - NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); - Assert.Equal(NativeCodeVersionOptimizationTier.OptimizationTierUnknown, tier); - } - [Theory] [ClassData(typeof(MockTarget.StdArch))] public void GetOptimizationTier_Synthetic_DelegatesToRuntimeTypeSystem(MockTarget.Architecture arch) From ccd0b4784f093b4149bea6f6cef2c8b2cbcb2047 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Wed, 1 Apr 2026 14:56:29 -0700 Subject: [PATCH 06/11] Fix type --- .../Data/MethodDescCodeData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2cb6aa90b7bd63..69240ebb7bd86b 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 @@ -18,5 +18,5 @@ public MethodDescCodeData(Target target, TargetPointer address) public TargetCodePointer TemporaryEntryPoint { get; set; } public TargetPointer VersioningState { get; set; } - public uint? OptimizationTier { get; init; } + public uint OptimizationTier { get; init; } } From 53641b5f8dd7246356c6085a300ba3d4d9b320f7 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Wed, 1 Apr 2026 15:06:38 -0700 Subject: [PATCH 07/11] Fix nullable type --- .../Data/NativeCodeVersionNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f849ad5da10f56..37a9655c15534c 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 @@ -32,5 +32,5 @@ public NativeCodeVersionNode(Target target, TargetPointer address) public TargetNUInt ILVersionId { get; init; } public TargetPointer? GCCoverageInfo { get; init; } - public uint? OptimizationTier { get; init; } + public uint OptimizationTier { get; init; } } From f5f520509754c8863ff88a35f4787cee771dd875 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Wed, 1 Apr 2026 16:54:39 -0700 Subject: [PATCH 08/11] Fix tests --- src/native/managed/cdac/tests/CodeVersionsTests.cs | 1 + .../tests/MockDescriptors/MockDescriptors.CodeVersions.cs | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/native/managed/cdac/tests/CodeVersionsTests.cs b/src/native/managed/cdac/tests/CodeVersionsTests.cs index 8eb60ab275452b..06ce14af04cfc4 100644 --- a/src/native/managed/cdac/tests/CodeVersionsTests.cs +++ b/src/native/managed/cdac/tests/CodeVersionsTests.cs @@ -734,6 +734,7 @@ public static IEnumerable GetOptimizationTierValues() yield return [arch, 3u, NativeCodeVersionOptimizationTier.OptimizationTierOptimized]; yield return [arch, 4u, NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented]; yield return [arch, 5u, NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented]; + yield return [arch, 0xFFFFFFFFu, NativeCodeVersionOptimizationTier.OptimizationTierUnknown]; } } diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs index 76b691b2052604..9cea0d2b4c8e8e 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs @@ -130,10 +130,8 @@ public void FillNativeCodeVersionNode(TargetPointer dest, TargetPointer methodDe Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.Flags)].Offset, sizeof(uint)), isActive ? (uint)CodeVersions_1.NativeCodeVersionNodeFlags.IsActiveChild : 0u); Builder.TargetTestHelpers.WriteNUInt(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.ILVersionId)].Offset, Builder.TargetTestHelpers.PointerSize), ilVersionId); Builder.TargetTestHelpers.WritePointer(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.GCCoverageInfo)].Offset, Builder.TargetTestHelpers.PointerSize), gcCoverageInfo ?? TargetPointer.Null); - if (optimizationTier.HasValue) - { - Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.OptimizationTier)].Offset, sizeof(uint)), optimizationTier.Value); - } + uint optimizationTierValue = optimizationTier ?? (uint)NativeCodeVersionOptimizationTier.OptimizationTierUnknown; + Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.OptimizationTier)].Offset, sizeof(uint)), optimizationTierValue); } public (TargetPointer First, TargetPointer Active) AddNativeCodeVersionNodesForMethod(TargetPointer methodDesc, int count, int activeIndex, TargetCodePointer activeNativeCode, TargetNUInt ilVersion, TargetPointer? firstNode = null) From 2cf6328dc69808849d3f2e42761b5f04b40c7fc9 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak <76071368+barosiak@users.noreply.github.com> Date: Thu, 2 Apr 2026 12:36:14 -0700 Subject: [PATCH 09/11] Apply suggestions from code review Co-authored-by: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> --- .../Contracts/ICodeVersions.cs | 3 +-- .../ISOSDacInterface.cs | 2 +- 2 files changed, 2 insertions(+), 3 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 370f1282e1d3f3..fc8726fa86c1ff 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 @@ -30,8 +30,7 @@ public interface ICodeVersions : IContract public virtual TargetPointer GetIL(ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); public virtual bool HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); - public virtual NativeCodeVersionOptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle) - => throw new NotImplementedException(); + public virtual NativeCodeVersionOptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); } public readonly struct ILCodeVersionHandle diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs index 032eef70262e3c..d531aa3f6e99dd 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ISOSDacInterface.cs @@ -972,7 +972,7 @@ public unsafe partial interface ISOSDacInterface5 int GetTieredVersions( ClrDataAddress methodDesc, int rejitId, - [In, MarshalUsing(CountElementName = nameof(cNativeCodeAddrs)), Out] DacpTieredVersionData[]? nativeCodeAddrs, + [In, Out, MarshalUsing(CountElementName = nameof(cNativeCodeAddrs))] DacpTieredVersionData[]? nativeCodeAddrs, int cNativeCodeAddrs, int* pcNativeCodeAddrs); }; From 53b5008ea8fd2cf3dba189c40d023d619be65951 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Thu, 2 Apr 2026 12:57:10 -0700 Subject: [PATCH 10/11] Rename NativeCodeVersionOptimizationTier to OptimizationTier --- docs/design/datacontracts/CodeVersions.md | 2 +- .../design/datacontracts/RuntimeTypeSystem.md | 6 ++-- .../Contracts/ICodeVersions.cs | 2 +- .../Contracts/IRuntimeTypeSystem.cs | 4 +-- .../Contracts/CodeVersions_1.cs | 4 +-- .../Contracts/RuntimeTypeSystem_1.cs | 24 +++++++------- .../SOSDacImpl.cs | 12 +++---- .../managed/cdac/tests/CodeVersionsTests.cs | 30 ++++++++--------- .../MockDescriptors.CodeVersions.cs | 2 +- .../cdac/tests/SOSDacInterface5Tests.cs | 32 +++++++++---------- 10 files changed, 59 insertions(+), 59 deletions(-) diff --git a/docs/design/datacontracts/CodeVersions.md b/docs/design/datacontracts/CodeVersions.md index 454be4e3d43000..6961f63478faa7 100644 --- a/docs/design/datacontracts/CodeVersions.md +++ b/docs/design/datacontracts/CodeVersions.md @@ -53,7 +53,7 @@ public virtual TargetPointer GetIL(ILCodeVersionHandle ilCodeVersionHandle); public virtual bool HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle); // Gets the optimization tier for a native code version -public virtual NativeCodeVersionOptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle); +public virtual OptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle); ``` ### Extension Methods diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index e6657eb0a2f2e8..5d4c5c8080c6c9 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -127,7 +127,7 @@ public enum ArrayFunctionType ``` ```csharp -public enum NativeCodeVersionOptimizationTier +public enum OptimizationTier { OptimizationTierUnknown, OptimizationTier0, @@ -210,7 +210,7 @@ partial interface IRuntimeTypeSystem : IContract public virtual TargetPointer GetGCStressCodeCopy(MethodDescHandle methodDesc); // Gets the optimization tier stored on the MethodDesc's code data - public virtual NativeCodeVersionOptimizationTier GetMethodDescOptimizationTier(MethodDescHandle methodDesc); + public virtual OptimizationTier GetMethodDescOptimizationTier(MethodDescHandle methodDesc); // Returns true if the method is eligible for tiered compilation public virtual bool IsEligibleForTieredCompilation(MethodDescHandle methodDesc); @@ -445,7 +445,7 @@ The contract additionally depends on these data descriptors The value of the `NativeCodeVersionNode::OptimizationTier` field is one of: ```csharp -private enum NativeCodeVersionOptimizationTier_1 : uint +private enum OptimizationTier_1 : uint { OptimizationTier0 = 0, OptimizationTier1 = 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 fc8726fa86c1ff..8b31a943fe2a03 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 @@ -30,7 +30,7 @@ public interface ICodeVersions : IContract public virtual TargetPointer GetIL(ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); public virtual bool HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); - public virtual NativeCodeVersionOptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + public virtual OptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); } public readonly struct ILCodeVersionHandle 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 078d8dc53bdc3f..202b4f37df8c0f 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 @@ -78,7 +78,7 @@ public enum ArrayFunctionType Constructor = 3 } -public enum NativeCodeVersionOptimizationTier : uint +public enum OptimizationTier : uint { OptimizationTierUnknown, OptimizationTier0, @@ -220,7 +220,7 @@ public interface IRuntimeTypeSystem : IContract TargetPointer GetGCStressCodeCopy(MethodDescHandle methodDesc) => throw new NotImplementedException(); - NativeCodeVersionOptimizationTier GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); + OptimizationTier GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); bool IsEligibleForTieredCompilation(MethodDescHandle methodDescHandle) => throw new NotImplementedException(); #endregion MethodDesc inspection APIs #region FieldDesc inspection APIs 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 1396c12e28289b..1856cdef05606e 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 @@ -414,7 +414,7 @@ bool ICodeVersions.HasDefaultIL(ILCodeVersionHandle iLCodeVersionHandle) return iLCodeVersionHandle.IsExplicit ? AsNode(iLCodeVersionHandle).ILAddress == TargetPointer.Null : true; } - NativeCodeVersionOptimizationTier ICodeVersions.GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle) + OptimizationTier ICodeVersions.GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle) { if (!codeVersionHandle.Valid) { @@ -430,7 +430,7 @@ NativeCodeVersionOptimizationTier ICodeVersions.GetOptimizationTier(NativeCodeVe { IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; MethodDescHandle methodDescHandle = rtsContract.GetMethodDescHandle(codeVersionHandle.MethodDescAddress); - NativeCodeVersionOptimizationTier optimizationTier = rtsContract.GetMethodDescOptimizationTier(methodDescHandle); + OptimizationTier optimizationTier = rtsContract.GetMethodDescOptimizationTier(methodDescHandle); return optimizationTier; } } 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 3b2d3e83994d08..92d50cd31f8d5e 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 @@ -325,7 +325,7 @@ public ulong SizeOfChunk } - private enum NativeCodeVersionOptimizationTier_1 : uint + private enum OptimizationTier_1 : uint { OptimizationTier0, OptimizationTier1, @@ -1656,26 +1656,26 @@ TargetPointer IRuntimeTypeSystem.GetGCStressCodeCopy(MethodDescHandle methodDesc return TargetPointer.Null; } - internal static NativeCodeVersionOptimizationTier GetOptimizationTier(uint? optimizationTier) + internal static OptimizationTier GetOptimizationTier(uint? optimizationTier) { - return (NativeCodeVersionOptimizationTier_1?)optimizationTier switch + return (OptimizationTier_1?)optimizationTier switch { - NativeCodeVersionOptimizationTier_1.OptimizationTier0 => NativeCodeVersionOptimizationTier.OptimizationTier0, - NativeCodeVersionOptimizationTier_1.OptimizationTier1 => NativeCodeVersionOptimizationTier.OptimizationTier1, - NativeCodeVersionOptimizationTier_1.OptimizationTier1OSR => NativeCodeVersionOptimizationTier.OptimizationTier1OSR, - NativeCodeVersionOptimizationTier_1.OptimizationTierOptimized => NativeCodeVersionOptimizationTier.OptimizationTierOptimized, - NativeCodeVersionOptimizationTier_1.OptimizationTier0Instrumented => NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented, - NativeCodeVersionOptimizationTier_1.OptimizationTier1Instrumented => NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented, - _ => NativeCodeVersionOptimizationTier.OptimizationTierUnknown, + OptimizationTier_1.OptimizationTier0 => OptimizationTier.OptimizationTier0, + OptimizationTier_1.OptimizationTier1 => OptimizationTier.OptimizationTier1, + OptimizationTier_1.OptimizationTier1OSR => OptimizationTier.OptimizationTier1OSR, + OptimizationTier_1.OptimizationTierOptimized => OptimizationTier.OptimizationTierOptimized, + OptimizationTier_1.OptimizationTier0Instrumented => OptimizationTier.OptimizationTier0Instrumented, + OptimizationTier_1.OptimizationTier1Instrumented => OptimizationTier.OptimizationTier1Instrumented, + _ => OptimizationTier.OptimizationTierUnknown, }; } - NativeCodeVersionOptimizationTier IRuntimeTypeSystem.GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) + OptimizationTier IRuntimeTypeSystem.GetMethodDescOptimizationTier(MethodDescHandle methodDescHandle) { MethodDesc methodDesc = _methodDescs[methodDescHandle.Address]; TargetPointer codeDataAddress = methodDesc.CodeData; if (codeDataAddress == TargetPointer.Null) - return NativeCodeVersionOptimizationTier.OptimizationTierUnknown; + return OptimizationTier.OptimizationTierUnknown; Data.MethodDescCodeData codeData = _target.ProcessedData.GetOrAdd(codeDataAddress); return GetOptimizationTier(codeData.OptimizationTier); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 8b32758a48f87b..97891774d0c5e2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -5082,22 +5082,22 @@ int ISOSDacInterface5.GetTieredVersions( default: nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.Unknown; break; - case NativeCodeVersionOptimizationTier.OptimizationTier0: + case OptimizationTier.OptimizationTier0: nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.QuickJitted; break; - case NativeCodeVersionOptimizationTier.OptimizationTier1: + case OptimizationTier.OptimizationTier1: nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.OptimizedTier1; break; - case NativeCodeVersionOptimizationTier.OptimizationTier1OSR: + case OptimizationTier.OptimizationTier1OSR: nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.OptimizedTier1OSR; break; - case NativeCodeVersionOptimizationTier.OptimizationTierOptimized: + case OptimizationTier.OptimizationTierOptimized: nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.Optimized; break; - case NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented: + case OptimizationTier.OptimizationTier0Instrumented: nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.QuickJittedInstrumented; break; - case NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented: + case OptimizationTier.OptimizationTier1Instrumented: nativeCodeAddrs[count].optimizationTier = DacpTieredVersionData.OptimizationTier.OptimizedTier1Instrumented; break; } diff --git a/src/native/managed/cdac/tests/CodeVersionsTests.cs b/src/native/managed/cdac/tests/CodeVersionsTests.cs index 06ce14af04cfc4..2d4551b777eca4 100644 --- a/src/native/managed/cdac/tests/CodeVersionsTests.cs +++ b/src/native/managed/cdac/tests/CodeVersionsTests.cs @@ -728,19 +728,19 @@ public static IEnumerable GetOptimizationTierValues() foreach (var archData in new MockTarget.StdArch()) { var arch = (MockTarget.Architecture)archData[0]; - yield return [arch, 0u, NativeCodeVersionOptimizationTier.OptimizationTier0]; - yield return [arch, 1u, NativeCodeVersionOptimizationTier.OptimizationTier1]; - yield return [arch, 2u, NativeCodeVersionOptimizationTier.OptimizationTier1OSR]; - yield return [arch, 3u, NativeCodeVersionOptimizationTier.OptimizationTierOptimized]; - yield return [arch, 4u, NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented]; - yield return [arch, 5u, NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented]; - yield return [arch, 0xFFFFFFFFu, NativeCodeVersionOptimizationTier.OptimizationTierUnknown]; + yield return [arch, 0u, OptimizationTier.OptimizationTier0]; + yield return [arch, 1u, OptimizationTier.OptimizationTier1]; + yield return [arch, 2u, OptimizationTier.OptimizationTier1OSR]; + yield return [arch, 3u, OptimizationTier.OptimizationTierOptimized]; + yield return [arch, 4u, OptimizationTier.OptimizationTier0Instrumented]; + yield return [arch, 5u, OptimizationTier.OptimizationTier1Instrumented]; + yield return [arch, 0xFFFFFFFFu, OptimizationTier.OptimizationTierUnknown]; } } [Theory] [MemberData(nameof(GetOptimizationTierValues))] - public void GetOptimizationTier_Explicit(MockTarget.Architecture arch, uint nativeTier, NativeCodeVersionOptimizationTier expectedTier) + public void GetOptimizationTier_Explicit(MockTarget.Architecture arch, uint nativeTier, OptimizationTier expectedTier) { MockCodeVersions builder = new(arch); @@ -758,7 +758,7 @@ public void GetOptimizationTier_Explicit(MockTarget.Architecture arch, uint nati var codeVersions = target.Contracts.CodeVersions; NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateExplicit(nativeCodeVersionNode); - NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); + OptimizationTier tier = codeVersions.GetOptimizationTier(handle); Assert.Equal(expectedTier, tier); } @@ -772,14 +772,14 @@ public void GetOptimizationTier_Synthetic_DelegatesToRuntimeTypeSystem(MockTarge Mock mockRTS = new(); MethodDescHandle mdHandle = new(methodDescAddress); mockRTS.Setup(r => r.GetMethodDescHandle(methodDescAddress)).Returns(mdHandle); - mockRTS.Setup(r => r.GetMethodDescOptimizationTier(mdHandle)).Returns(NativeCodeVersionOptimizationTier.OptimizationTierOptimized); + mockRTS.Setup(r => r.GetMethodDescOptimizationTier(mdHandle)).Returns(OptimizationTier.OptimizationTierOptimized); var target = CreateTarget(arch, builder, mockRuntimeTypeSystem: mockRTS); var codeVersions = target.Contracts.CodeVersions; NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateSynthetic(methodDescAddress); - NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); - Assert.Equal(NativeCodeVersionOptimizationTier.OptimizationTierOptimized, tier); + OptimizationTier tier = codeVersions.GetOptimizationTier(handle); + Assert.Equal(OptimizationTier.OptimizationTierOptimized, tier); } [Theory] @@ -792,13 +792,13 @@ public void GetOptimizationTier_Synthetic_NoCodeData(MockTarget.Architecture arc Mock mockRTS = new(); MethodDescHandle mdHandle = new(methodDescAddress); mockRTS.Setup(r => r.GetMethodDescHandle(methodDescAddress)).Returns(mdHandle); - mockRTS.Setup(r => r.GetMethodDescOptimizationTier(mdHandle)).Returns(NativeCodeVersionOptimizationTier.OptimizationTierUnknown); + mockRTS.Setup(r => r.GetMethodDescOptimizationTier(mdHandle)).Returns(OptimizationTier.OptimizationTierUnknown); var target = CreateTarget(arch, builder, mockRuntimeTypeSystem: mockRTS); var codeVersions = target.Contracts.CodeVersions; NativeCodeVersionHandle handle = NativeCodeVersionHandle.CreateSynthetic(methodDescAddress); - NativeCodeVersionOptimizationTier tier = codeVersions.GetOptimizationTier(handle); - Assert.Equal(NativeCodeVersionOptimizationTier.OptimizationTierUnknown, tier); + OptimizationTier tier = codeVersions.GetOptimizationTier(handle); + Assert.Equal(OptimizationTier.OptimizationTierUnknown, tier); } } diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs index 9cea0d2b4c8e8e..ae4bd4f6ca08d9 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs @@ -130,7 +130,7 @@ public void FillNativeCodeVersionNode(TargetPointer dest, TargetPointer methodDe Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.Flags)].Offset, sizeof(uint)), isActive ? (uint)CodeVersions_1.NativeCodeVersionNodeFlags.IsActiveChild : 0u); Builder.TargetTestHelpers.WriteNUInt(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.ILVersionId)].Offset, Builder.TargetTestHelpers.PointerSize), ilVersionId); Builder.TargetTestHelpers.WritePointer(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.GCCoverageInfo)].Offset, Builder.TargetTestHelpers.PointerSize), gcCoverageInfo ?? TargetPointer.Null); - uint optimizationTierValue = optimizationTier ?? (uint)NativeCodeVersionOptimizationTier.OptimizationTierUnknown; + uint optimizationTierValue = optimizationTier ?? (uint)OptimizationTier.OptimizationTierUnknown; Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.OptimizationTier)].Offset, sizeof(uint)), optimizationTierValue); } diff --git a/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs b/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs index c6d5b7ba422ce1..7677152b38f48c 100644 --- a/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs +++ b/src/native/managed/cdac/tests/SOSDacInterface5Tests.cs @@ -21,7 +21,7 @@ public unsafe class SOSDacInterface5Tests private record struct VersionInfo( TargetCodePointer NativeCode, TargetPointer CodeVersionNodeAddress, - NativeCodeVersionOptimizationTier Tier); + OptimizationTier Tier); private static ISOSDacInterface5 CreateDac5( MockTarget.Architecture arch, @@ -173,7 +173,7 @@ public void GetTieredVersions_ReadyToRun(MockTarget.Architecture arch) uint r2rSize = 0x1000; var versions = new[] { - new VersionInfo(new TargetCodePointer(0x5000_0100), new TargetPointer(0x7000_0001), NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + new VersionInfo(new TargetCodePointer(0x5000_0100), new TargetPointer(0x7000_0001), OptimizationTier.OptimizationTierOptimized), }; ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isReadyToRun: true, r2rBase: r2rBase, r2rSize: r2rSize); @@ -189,15 +189,15 @@ public static IEnumerable TierMappingData { get { - (NativeCodeVersionOptimizationTier, DacpTieredVersionData.OptimizationTier)[] tiers = + (OptimizationTier, DacpTieredVersionData.OptimizationTier)[] tiers = [ - (NativeCodeVersionOptimizationTier.OptimizationTier0, DacpTieredVersionData.OptimizationTier.QuickJitted), - (NativeCodeVersionOptimizationTier.OptimizationTier1, DacpTieredVersionData.OptimizationTier.OptimizedTier1), - (NativeCodeVersionOptimizationTier.OptimizationTier1OSR, DacpTieredVersionData.OptimizationTier.OptimizedTier1OSR), - (NativeCodeVersionOptimizationTier.OptimizationTierOptimized, DacpTieredVersionData.OptimizationTier.Optimized), - (NativeCodeVersionOptimizationTier.OptimizationTier0Instrumented, DacpTieredVersionData.OptimizationTier.QuickJittedInstrumented), - (NativeCodeVersionOptimizationTier.OptimizationTier1Instrumented, DacpTieredVersionData.OptimizationTier.OptimizedTier1Instrumented), - (NativeCodeVersionOptimizationTier.OptimizationTierUnknown, DacpTieredVersionData.OptimizationTier.Unknown), + (OptimizationTier.OptimizationTier0, DacpTieredVersionData.OptimizationTier.QuickJitted), + (OptimizationTier.OptimizationTier1, DacpTieredVersionData.OptimizationTier.OptimizedTier1), + (OptimizationTier.OptimizationTier1OSR, DacpTieredVersionData.OptimizationTier.OptimizedTier1OSR), + (OptimizationTier.OptimizationTierOptimized, DacpTieredVersionData.OptimizationTier.Optimized), + (OptimizationTier.OptimizationTier0Instrumented, DacpTieredVersionData.OptimizationTier.QuickJittedInstrumented), + (OptimizationTier.OptimizationTier1Instrumented, DacpTieredVersionData.OptimizationTier.OptimizedTier1Instrumented), + (OptimizationTier.OptimizationTierUnknown, DacpTieredVersionData.OptimizationTier.Unknown), ]; foreach (var arch in new MockTarget.StdArch()) @@ -214,7 +214,7 @@ public static IEnumerable TierMappingData [MemberData(nameof(TierMappingData))] public void GetTieredVersions_TieredCompilation( MockTarget.Architecture arch, - NativeCodeVersionOptimizationTier internalTier, + OptimizationTier internalTier, DacpTieredVersionData.OptimizationTier expectedTier) { var versions = new[] @@ -237,7 +237,7 @@ public void GetTieredVersions_NotEligibleForTieredCompilation(MockTarget.Archite { var versions = new[] { - new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), OptimizationTier.OptimizationTierOptimized), }; ISOSDacInterface5 dac5 = CreateDac5(arch, versions); @@ -255,9 +255,9 @@ public void GetTieredVersions_BufferTooSmall(MockTarget.Architecture arch) { var versions = new[] { - new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), NativeCodeVersionOptimizationTier.OptimizationTier0), - new VersionInfo(new TargetCodePointer(0x6000_0200), new TargetPointer(0x7000_0002), NativeCodeVersionOptimizationTier.OptimizationTier1), - new VersionInfo(new TargetCodePointer(0x6000_0300), new TargetPointer(0x7000_0003), NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + new VersionInfo(new TargetCodePointer(0x6000_0100), new TargetPointer(0x7000_0001), OptimizationTier.OptimizationTier0), + new VersionInfo(new TargetCodePointer(0x6000_0200), new TargetPointer(0x7000_0002), OptimizationTier.OptimizationTier1), + new VersionInfo(new TargetCodePointer(0x6000_0300), new TargetPointer(0x7000_0003), OptimizationTier.OptimizationTierOptimized), }; ISOSDacInterface5 dac5 = CreateDac5(arch, versions, isEligibleForTieredCompilation: true); @@ -276,7 +276,7 @@ public void GetTieredVersions_PopulatesCodeAddrAndNodePtr(MockTarget.Architectur var nodeAddr = new TargetPointer(0x7000_0001); var versions = new[] { - new VersionInfo(codeAddr, nodeAddr, NativeCodeVersionOptimizationTier.OptimizationTierOptimized), + new VersionInfo(codeAddr, nodeAddr, OptimizationTier.OptimizationTierOptimized), }; ISOSDacInterface5 dac5 = CreateDac5(arch, versions); From 4e8ad4484ac15c87597a2cc2040c710c5330ce94 Mon Sep 17 00:00:00 2001 From: Barbara Rosiak Date: Thu, 2 Apr 2026 15:15:14 -0700 Subject: [PATCH 11/11] Fix wrong value in mock --- .../cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs index ae4bd4f6ca08d9..343da91d347009 100644 --- a/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs +++ b/src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.CodeVersions.cs @@ -130,7 +130,7 @@ public void FillNativeCodeVersionNode(TargetPointer dest, TargetPointer methodDe Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.Flags)].Offset, sizeof(uint)), isActive ? (uint)CodeVersions_1.NativeCodeVersionNodeFlags.IsActiveChild : 0u); Builder.TargetTestHelpers.WriteNUInt(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.ILVersionId)].Offset, Builder.TargetTestHelpers.PointerSize), ilVersionId); Builder.TargetTestHelpers.WritePointer(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.GCCoverageInfo)].Offset, Builder.TargetTestHelpers.PointerSize), gcCoverageInfo ?? TargetPointer.Null); - uint optimizationTierValue = optimizationTier ?? (uint)OptimizationTier.OptimizationTierUnknown; + uint optimizationTierValue = optimizationTier ?? 0xFFFFFFFFu; Builder.TargetTestHelpers.Write(ncvn.Slice(info.Fields[nameof(Data.NativeCodeVersionNode.OptimizationTier)].Offset, sizeof(uint)), optimizationTierValue); }