From 7f71d96bba2d76eeaf4792146d9c807d09f69635 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Wed, 17 Jun 2026 10:09:04 -0400 Subject: [PATCH 1/4] [cDAC] Add RuntimeFlavor to IRuntimeInfo and expand NAOT data descriptor - Add RuntimeInfoRuntimeFlavor enum (Unknown, Coreclr, Mono, NativeAot) and GetRuntimeFlavor() to the IRuntimeInfo contract. - RuntimeInfo_1: convert to sealed class, lazily cache values, and clear cached values on Flush. - CoreCLR datadescriptor: add CDAC_GLOBAL_STRING(RuntimeFlavor, Coreclr). - NativeAOT datadescriptor: register the RuntimeInfo c1 contract and expose OperatingSystem, Architecture, RuntimeFlavor (NativeAot), RID, and RecommendedReaderVersion globals - matching the CoreCLR surface so diagnostic tools can resolve the contract against NAOT dumps. - Add unit tests for GetRuntimeFlavor and caching/flush behavior, plus a dump test asserting flavor==Coreclr on CoreCLR dumps. - Update RuntimeInfo.md design doc. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/design/datacontracts/RuntimeInfo.md | 18 ++- .../Runtime/datadescriptor/CMakeLists.txt | 8 +- .../Runtime/datadescriptor/configure.h.in | 6 + .../Runtime/datadescriptor/datadescriptor.h | 2 + .../Runtime/datadescriptor/datadescriptor.inc | 60 ++++++++++ .../vm/datadescriptor/datadescriptor.inc | 2 + .../Contracts/IRuntimeInfo.cs | 9 ++ .../Constants.cs | 1 + .../Contracts/RuntimeInfo_1.cs | 50 +++++++- .../tests/DumpTests/RuntimeInfoDumpTests.cs | 12 ++ .../cdac/tests/UnitTests/RuntimeInfoTests.cs | 110 ++++++++++++++++++ 11 files changed, 269 insertions(+), 9 deletions(-) create mode 100644 src/coreclr/nativeaot/Runtime/datadescriptor/configure.h.in diff --git a/docs/design/datacontracts/RuntimeInfo.md b/docs/design/datacontracts/RuntimeInfo.md index 94d4245e8fc208..cc73bd77645193 100644 --- a/docs/design/datacontracts/RuntimeInfo.md +++ b/docs/design/datacontracts/RuntimeInfo.md @@ -24,6 +24,14 @@ public enum RuntimeInfoOperatingSystem : uint Browser, Apple, } + +public enum RuntimeInfoRuntimeFlavor : uint +{ + Unknown = 0, + Coreclr, + Mono, + NativeAot, +} ``` ```csharp @@ -33,6 +41,10 @@ RuntimeInfoArchitecture GetTargetArchitecture(); // Gets the targets operating system. If this information is not available returns Unknown. RuntimeInfoOperatingSystem GetTargetOperatingSystem(); +// Gets the target's runtime flavor. If this information is not +// available returns Unknown. +RuntimeInfoRuntimeFlavor GetRuntimeFlavor(); + // Returns the runtime's RecommendedReaderVersion global. Returns 0 if the global is absent. uint GetRecommendedReaderVersion(); @@ -47,10 +59,12 @@ Global variables used: | --- | --- | --- | | Architecture | string | Target architecture | | OperatingSystem | string | Target operating system | +| RuntimeFlavor | string | Target runtime flavor | | RecommendedReaderVersion | uint32 | Incremented when an update to the latest contracts is recommended | -The contract implementation returns the architecture and operating system global values parsed as the -respective enum case-insensitively. If these globals are not available, the contract returns Unknown. +The contract implementation returns the architecture, operating system, and runtime flavor global +values parsed as the respective enum case-insensitively. If these globals are not available, the +contract returns Unknown. `Apple` covers all Apple platforms (macOS, iOS, tvOS, MacCatalyst) — i.e. any target where the runtime is compiled with `TARGET_APPLE` defined. It is distinct from `Unix` so that consumers which diff --git a/src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt index 344dc601110f3d..ac1a741eeb96ef 100644 --- a/src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/datadescriptor/CMakeLists.txt @@ -12,9 +12,15 @@ set(CMAKE_INCLUDE_CURRENT_DIR OFF) include(${CLR_DIR}/clrdatadescriptors.cmake) +if(CDAC_BUILD_TOOL_BINARY_PATH AND "${CLR_DOTNET_RID}" STREQUAL "") + message(FATAL_ERROR "CLR_DOTNET_RID is not set. Please ensure it is being set to the portable RID of the target platform by runtime.proj.") +endif() +configure_file(configure.h.in ${CMAKE_CURRENT_BINARY_DIR}/configure.h) + add_library(nativeaot_descriptor_interface INTERFACE) target_include_directories(nativeaot_descriptor_interface INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR}) + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(nativeaot_descriptor_interface INTERFACE nativeaot_runtime_includes) add_dependencies(nativeaot_descriptor_interface aot_eventing_headers) generate_data_descriptors( diff --git a/src/coreclr/nativeaot/Runtime/datadescriptor/configure.h.in b/src/coreclr/nativeaot/Runtime/datadescriptor/configure.h.in new file mode 100644 index 00000000000000..5b3a6e5069694e --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/datadescriptor/configure.h.in @@ -0,0 +1,6 @@ +#ifndef NATIVEAOT_RUNTIME_INFO_CONFIGURE_H_INCLUDED +#define NATIVEAOT_RUNTIME_INFO_CONFIGURE_H_INCLUDED + +#define RID_STRING @CLR_DOTNET_RID@ + +#endif // NATIVEAOT_RUNTIME_INFO_CONFIGURE_H_INCLUDED diff --git a/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h b/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h index 4b5b4e1824f413..948fded3e79f32 100644 --- a/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h +++ b/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.h @@ -16,6 +16,8 @@ #include "thread.h" #include "threadstore.h" +#include "configure.h" + #include #include diff --git a/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc b/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc index 365abce8061d29..f95aba6775292f 100644 --- a/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc +++ b/src/coreclr/nativeaot/Runtime/datadescriptor/datadescriptor.inc @@ -13,6 +13,17 @@ // 3. Update the contract implementation in src/native/managed/cdac/.../Contracts/.cs // 4. Update the mock descriptors and tests in src/native/managed/cdac/tests/. +// Increment this when making a change where we'd like to recommend users update their diagnostic tools. +// Tools can use this to display an advisory notice to users encouraging them to update. Changing +// this value on its own is not considered a breaking change. See the RuntimeInfo.md data contract for details. +// When incrementing this value, also implement the new functionality in the cDAC reader and update the +// GetCurrentReaderVersion() method on the IRuntimeInfo contract in +// src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeInfo_1.cs +// to match. +#ifndef CDAC_RECOMMENDED_READER_VERSION +#define CDAC_RECOMMENDED_READER_VERSION 1 +#endif + CDAC_BASELINE("empty") CDAC_TYPES_BEGIN() @@ -160,10 +171,59 @@ CDAC_GLOBAL(StressLogChunkSize, T_UINT32, STRESSLOG_CHUNK_SIZE) CDAC_GLOBAL(StressLogValidChunkSig, T_UINT32, 0xCFCFCFCF) CDAC_GLOBAL(StressLogMaxMessageSize, T_UINT64, (uint64_t)StressMsg::maxMsgSize) +#if defined(TARGET_BROWSER) +#ifdef Browser +#error Handle 'Browser' define +#endif // Browser +CDAC_GLOBAL_STRING(OperatingSystem, Browser) +#elif defined(TARGET_APPLE) +#ifdef Apple +#error Handle 'Apple' define +#endif // Apple +CDAC_GLOBAL_STRING(OperatingSystem, Apple) +#elif defined(TARGET_UNIX) +#ifdef Unix +#error Handle 'Unix' define +#endif // Unix +CDAC_GLOBAL_STRING(OperatingSystem, Unix) +#elif defined(TARGET_WINDOWS) +#ifdef Windows +#error Handle 'Windows' define +#endif // Windows +CDAC_GLOBAL_STRING(OperatingSystem, Windows) +#else +#error TARGET_{OS} define is not recognized by the cDAC. Update this switch and the enum values in IRuntimeInfo.cs +#endif + +#if defined(TARGET_X86) +CDAC_GLOBAL_STRING(Architecture, x86) +#elif defined(TARGET_AMD64) +CDAC_GLOBAL_STRING(Architecture, x64) +#elif defined(TARGET_ARM) +CDAC_GLOBAL_STRING(Architecture, arm) +#elif defined(TARGET_ARM64) +CDAC_GLOBAL_STRING(Architecture, arm64) +#elif defined(TARGET_LOONGARCH64) +CDAC_GLOBAL_STRING(Architecture, loongarch64) +#elif defined(TARGET_RISCV64) +CDAC_GLOBAL_STRING(Architecture, riscv64) +#elif defined(TARGET_WASM) +CDAC_GLOBAL_STRING(Architecture, wasm) +#else +#error TARGET_{ARCH} define is not recognized by the cDAC. Update this switch and the enum values in IRuntimeInfo.cs +#endif + +CDAC_GLOBAL_STRING(RuntimeFlavor, NativeAot) + +CDAC_GLOBAL_STRING(RID, RID_STRING) + +CDAC_GLOBAL(RecommendedReaderVersion, T_UINT32, CDAC_RECOMMENDED_READER_VERSION) + // Contracts: declare which contracts this runtime supports CDAC_GLOBAL_CONTRACT(Thread, n1) CDAC_GLOBAL_CONTRACT(Exception, c1) CDAC_GLOBAL_CONTRACT(RuntimeTypeSystem, n1) +CDAC_GLOBAL_CONTRACT(RuntimeInfo, c1) CDAC_GLOBAL_CONTRACT(StressLog, c2) // Managed type sub-descriptor: ILC emits a ContractDescriptor with managed type layouts diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index c0dbba1a0e6c19..8c6a829ca116b5 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1506,6 +1506,8 @@ CDAC_GLOBAL_STRING(Architecture, wasm) #error TARGET_{ARCH} define is not recognized by the cDAC. Update this switch and the enum values in IRuntimeInfo.cs #endif +CDAC_GLOBAL_STRING(RuntimeFlavor, Coreclr) + CDAC_GLOBAL_STRING(RID, RID_STRING) CDAC_GLOBAL(GCInfoVersion, T_UINT32, GCINFO_VERSION) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeInfo.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeInfo.cs index 0f2dfe0615bd52..8a9ac302ec9a3e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeInfo.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeInfo.cs @@ -30,11 +30,20 @@ public enum RuntimeInfoOperatingSystem : uint Apple, } +public enum RuntimeInfoRuntimeFlavor : uint +{ + Unknown = 0, + Coreclr, + Mono, + NativeAot, +} + public interface IRuntimeInfo : IContract { static string IContract.Name { get; } = nameof(RuntimeInfo); RuntimeInfoArchitecture GetTargetArchitecture() => throw new NotImplementedException(); RuntimeInfoOperatingSystem GetTargetOperatingSystem() => throw new NotImplementedException(); + RuntimeInfoRuntimeFlavor GetRuntimeFlavor() => throw new NotImplementedException(); uint GetCurrentReaderVersion() => throw new NotImplementedException(); uint GetRecommendedReaderVersion() => throw new NotImplementedException(); } 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 37f49930fce10c..c00719afdb2aa8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Constants.cs @@ -114,6 +114,7 @@ public static class Globals public const string Architecture = nameof(Architecture); public const string OperatingSystem = nameof(OperatingSystem); + public const string RuntimeFlavor = nameof(RuntimeFlavor); public const string GCInfoVersion = nameof(GCInfoVersion); public const string GCLowestAddress = nameof(GCLowestAddress); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeInfo_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeInfo_1.cs index fdc50b0f3fd5e0..1579cad4cb5025 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeInfo_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeInfo_1.cs @@ -5,16 +5,43 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; -internal struct RuntimeInfo_1 : IRuntimeInfo +internal sealed class RuntimeInfo_1 : IRuntimeInfo { - internal readonly Target _target; + private readonly Target _target; + + private RuntimeInfoArchitecture? _architecture; + private RuntimeInfoOperatingSystem? _operatingSystem; + private RuntimeInfoRuntimeFlavor? _runtimeFlavor; + private uint? _recommendedReaderVersion; public RuntimeInfo_1(Target target) { _target = target; } - readonly RuntimeInfoArchitecture IRuntimeInfo.GetTargetArchitecture() + public void Flush(FlushScope scope) + { + _architecture = null; + _operatingSystem = null; + _runtimeFlavor = null; + _recommendedReaderVersion = null; + } + + RuntimeInfoArchitecture IRuntimeInfo.GetTargetArchitecture() + => _architecture ??= ReadArchitecture(); + + RuntimeInfoOperatingSystem IRuntimeInfo.GetTargetOperatingSystem() + => _operatingSystem ??= ReadOperatingSystem(); + + RuntimeInfoRuntimeFlavor IRuntimeInfo.GetRuntimeFlavor() + => _runtimeFlavor ??= ReadRuntimeFlavor(); + + uint IRuntimeInfo.GetCurrentReaderVersion() => 1; + + uint IRuntimeInfo.GetRecommendedReaderVersion() + => _recommendedReaderVersion ??= ReadRecommendedReaderVersion(); + + private RuntimeInfoArchitecture ReadArchitecture() { if (_target.TryReadGlobalString(Constants.Globals.Architecture, out string? arch)) { @@ -27,7 +54,7 @@ readonly RuntimeInfoArchitecture IRuntimeInfo.GetTargetArchitecture() return RuntimeInfoArchitecture.Unknown; } - readonly RuntimeInfoOperatingSystem IRuntimeInfo.GetTargetOperatingSystem() + private RuntimeInfoOperatingSystem ReadOperatingSystem() { if (_target.TryReadGlobalString(Constants.Globals.OperatingSystem, out string? os)) { @@ -40,9 +67,20 @@ readonly RuntimeInfoOperatingSystem IRuntimeInfo.GetTargetOperatingSystem() return RuntimeInfoOperatingSystem.Unknown; } - readonly uint IRuntimeInfo.GetCurrentReaderVersion() => 1; + private RuntimeInfoRuntimeFlavor ReadRuntimeFlavor() + { + if (_target.TryReadGlobalString(Constants.Globals.RuntimeFlavor, out string? flavor)) + { + if (Enum.TryParse(flavor, ignoreCase: true, out RuntimeInfoRuntimeFlavor parsedFlavor)) + { + return parsedFlavor; + } + } + + return RuntimeInfoRuntimeFlavor.Unknown; + } - readonly uint IRuntimeInfo.GetRecommendedReaderVersion() + private uint ReadRecommendedReaderVersion() { _target.TryReadGlobal(Constants.Globals.RecommendedReaderVersion, out uint? runtimeVersion); return runtimeVersion ?? 0; diff --git a/src/native/managed/cdac/tests/DumpTests/RuntimeInfoDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/RuntimeInfoDumpTests.cs index ece4af019cd6e4..3c334a283468aa 100644 --- a/src/native/managed/cdac/tests/DumpTests/RuntimeInfoDumpTests.cs +++ b/src/native/managed/cdac/tests/DumpTests/RuntimeInfoDumpTests.cs @@ -61,4 +61,16 @@ public void RuntimeInfo_OperatingSystemMatchesDumpMetadata(TestConfiguration con Assert.Equal(expected, os); } + + [ConditionalTheory] + [MemberData(nameof(TestConfigurations))] + public void RuntimeInfo_RuntimeFlavorIsCoreclr(TestConfiguration config) + { + InitializeDumpTest(config); + + IRuntimeInfo runtimeInfo = Target.Contracts.RuntimeInfo; + RuntimeInfoRuntimeFlavor flavor = runtimeInfo.GetRuntimeFlavor(); + + Assert.Equal(RuntimeInfoRuntimeFlavor.Coreclr, flavor); + } } diff --git a/src/native/managed/cdac/tests/UnitTests/RuntimeInfoTests.cs b/src/native/managed/cdac/tests/UnitTests/RuntimeInfoTests.cs index 02e552eefa152b..1bdf5a7aae6005 100644 --- a/src/native/managed/cdac/tests/UnitTests/RuntimeInfoTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/RuntimeInfoTests.cs @@ -91,8 +91,118 @@ public void GetTargetOperatingSystemTest( Assert.Equal(expectedOS, actualArchitecture); } + public static IEnumerable StdArchAllRuntimeFlavors() + { + foreach(object[] arr in new MockTarget.StdArch()) + { + MockTarget.Architecture arch = (MockTarget.Architecture)arr[0]; + + foreach(RuntimeInfoRuntimeFlavor flavor in (RuntimeInfoRuntimeFlavor[])Enum.GetValues(typeof(RuntimeInfoRuntimeFlavor))) + { + // Skip Unknown flavor + if (flavor == RuntimeInfoRuntimeFlavor.Unknown) + continue; + + yield return new object[] { arch, flavor.ToString().ToLowerInvariant(), flavor }; + } + + yield return new object[] { arch, "notARuntimeFlavor", RuntimeInfoRuntimeFlavor.Unknown }; + } + } + + [Theory] + [MemberData(nameof(StdArchAllRuntimeFlavors))] + public void GetRuntimeFlavorTest( + MockTarget.Architecture arch, + string flavor, + RuntimeInfoRuntimeFlavor expectedFlavor) + { + Target target = CreateTarget(arch, [(Constants.Globals.RuntimeFlavor, flavor)]); + + IRuntimeInfo runtimeInfo = target.Contracts.RuntimeInfo; + var actualFlavor = runtimeInfo.GetRuntimeFlavor(); + Assert.Equal(expectedFlavor, actualFlavor); + } + + [Fact] + public void GetRuntimeFlavor_GlobalAbsent_ReturnsUnknown() + { + Target target = CreateTarget(DefaultArch, []); + Assert.Equal(RuntimeInfoRuntimeFlavor.Unknown, target.Contracts.RuntimeInfo.GetRuntimeFlavor()); + } + private static readonly MockTarget.Architecture DefaultArch = new MockTarget.Architecture { IsLittleEndian = true, Is64Bit = true }; + [Fact] + public void Values_AreCached_AndClearedOnFlush() + { + var target = new CountingTarget(DefaultArch); + IRuntimeInfo runtimeInfo = target.Contracts.RuntimeInfo; + + // First access reads each global once. + Assert.Equal(RuntimeInfoArchitecture.X64, runtimeInfo.GetTargetArchitecture()); + Assert.Equal(RuntimeInfoOperatingSystem.Windows, runtimeInfo.GetTargetOperatingSystem()); + Assert.Equal(RuntimeInfoRuntimeFlavor.Coreclr, runtimeInfo.GetRuntimeFlavor()); + Assert.Equal((uint)42, runtimeInfo.GetRecommendedReaderVersion()); + + int baselineStringReads = target.GlobalStringReadCount; + int baselineUintReads = target.GlobalReadCount; + + // Subsequent accesses must not re-read. + for (int i = 0; i < 3; i++) + { + _ = runtimeInfo.GetTargetArchitecture(); + _ = runtimeInfo.GetTargetOperatingSystem(); + _ = runtimeInfo.GetRuntimeFlavor(); + _ = runtimeInfo.GetRecommendedReaderVersion(); + } + Assert.Equal(baselineStringReads, target.GlobalStringReadCount); + Assert.Equal(baselineUintReads, target.GlobalReadCount); + + // Flush clears the cache: next accesses must re-read. + runtimeInfo.Flush(FlushScope.All); + _ = runtimeInfo.GetTargetArchitecture(); + _ = runtimeInfo.GetTargetOperatingSystem(); + _ = runtimeInfo.GetRuntimeFlavor(); + _ = runtimeInfo.GetRecommendedReaderVersion(); + Assert.True(target.GlobalStringReadCount > baselineStringReads); + Assert.True(target.GlobalReadCount > baselineUintReads); + } + + private sealed class CountingTarget : TestPlaceholderTarget + { + public int GlobalStringReadCount { get; private set; } + public int GlobalReadCount { get; private set; } + + public CountingTarget(MockTarget.Architecture arch) + : base( + arch, + static (ulong _, Span _) => 0, + globals: [(Constants.Globals.RecommendedReaderVersion, 42UL)], + globalStrings: + [ + (Constants.Globals.Architecture, "x64"), + (Constants.Globals.OperatingSystem, "windows"), + (Constants.Globals.RuntimeFlavor, "coreclr"), + ]) + { + SetupContractRegistry(registry => registry.Register("c1", t => new RuntimeInfo_1(t))) + .SetVersion("c1"); + } + + public override bool TryReadGlobalString(string name, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? value) + { + GlobalStringReadCount++; + return base.TryReadGlobalString(name, out value); + } + + public override bool TryReadGlobal(string name, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out T? value) + { + GlobalReadCount++; + return base.TryReadGlobal(name, out value); + } + } + [Fact] public void RecommendedReaderVersion_GlobalPresent_ReturnsValue() { From ddf61a5c65d33cfec63e26ff90d2a1e7c0e21dc5 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Wed, 17 Jun 2026 10:22:01 -0400 Subject: [PATCH 2/4] Address Copilot review feedback - Include Unknown in the GetRuntimeFlavor theory data so explicit "unknown" exercises Enum.TryParse round-trip. - Sync RuntimeInfo.md enum snippet with the actual IRuntimeInfo.cs enum names (Arm/RiscV64/Windows/etc.). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/design/datacontracts/RuntimeInfo.md | 10 +++++++--- .../managed/cdac/tests/UnitTests/RuntimeInfoTests.cs | 4 ---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/design/datacontracts/RuntimeInfo.md b/docs/design/datacontracts/RuntimeInfo.md index cc73bd77645193..bb1084e00e9d44 100644 --- a/docs/design/datacontracts/RuntimeInfo.md +++ b/docs/design/datacontracts/RuntimeInfo.md @@ -9,17 +9,21 @@ public enum RuntimeInfoArchitecture : uint { Unknown = 0, X86, - Arm32, X64, + Arm, Arm64, + Wasm, + S390x, LoongArch64, - RISCV, + Armv6, + Ppc64le, + RiscV64, } public enum RuntimeInfoOperatingSystem : uint { Unknown = 0, - Win, + Windows, Unix, Browser, Apple, diff --git a/src/native/managed/cdac/tests/UnitTests/RuntimeInfoTests.cs b/src/native/managed/cdac/tests/UnitTests/RuntimeInfoTests.cs index 1bdf5a7aae6005..8ac54d671afff8 100644 --- a/src/native/managed/cdac/tests/UnitTests/RuntimeInfoTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/RuntimeInfoTests.cs @@ -99,10 +99,6 @@ public static IEnumerable StdArchAllRuntimeFlavors() foreach(RuntimeInfoRuntimeFlavor flavor in (RuntimeInfoRuntimeFlavor[])Enum.GetValues(typeof(RuntimeInfoRuntimeFlavor))) { - // Skip Unknown flavor - if (flavor == RuntimeInfoRuntimeFlavor.Unknown) - continue; - yield return new object[] { arch, flavor.ToString().ToLowerInvariant(), flavor }; } From 49a268a5bd39855e1018f1802ebafbc46e9f538c Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Wed, 17 Jun 2026 12:39:31 -0400 Subject: [PATCH 3/4] Drop Mono from RuntimeInfoRuntimeFlavor Per review feedback: cDAC does not need to model Mono as a runtime flavor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/design/datacontracts/RuntimeInfo.md | 1 - .../Contracts/IRuntimeInfo.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/design/datacontracts/RuntimeInfo.md b/docs/design/datacontracts/RuntimeInfo.md index bb1084e00e9d44..539c2b90ebde0f 100644 --- a/docs/design/datacontracts/RuntimeInfo.md +++ b/docs/design/datacontracts/RuntimeInfo.md @@ -33,7 +33,6 @@ public enum RuntimeInfoRuntimeFlavor : uint { Unknown = 0, Coreclr, - Mono, NativeAot, } ``` diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeInfo.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeInfo.cs index 8a9ac302ec9a3e..3e4f7e3284f4c6 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeInfo.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeInfo.cs @@ -34,7 +34,6 @@ public enum RuntimeInfoRuntimeFlavor : uint { Unknown = 0, Coreclr, - Mono, NativeAot, } From 5396333a442a3f63d2de2c042d7d05aaddbff86e Mon Sep 17 00:00:00 2001 From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com> Date: Thu, 18 Jun 2026 09:41:44 -0400 Subject: [PATCH 4/4] Update docs/design/datacontracts/RuntimeInfo.md Co-authored-by: Noah Falk --- docs/design/datacontracts/RuntimeInfo.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/design/datacontracts/RuntimeInfo.md b/docs/design/datacontracts/RuntimeInfo.md index 539c2b90ebde0f..20ef3caea36500 100644 --- a/docs/design/datacontracts/RuntimeInfo.md +++ b/docs/design/datacontracts/RuntimeInfo.md @@ -45,7 +45,11 @@ RuntimeInfoArchitecture GetTargetArchitecture(); RuntimeInfoOperatingSystem GetTargetOperatingSystem(); // Gets the target's runtime flavor. If this information is not -// available returns Unknown. +// available returns Unknown. This is intended to be descriptive information for +// users and provides no guarantees how the underlying runtime works. Over time +// implementation details may change dramatically. For determining what features or +// invariants a given runtime implementation supports look at which contracts are +// implemented or call contract APIs that probe for specific capabilities. RuntimeInfoRuntimeFlavor GetRuntimeFlavor(); // Returns the runtime's RecommendedReaderVersion global. Returns 0 if the global is absent.