From cbb0de3290a4bd13c16f3fc3ef9dc41b7cc3e550 Mon Sep 17 00:00:00 2001 From: Max Charlamb Date: Mon, 18 Nov 2024 15:07:35 -0500 Subject: [PATCH] first draft --- .../debug/runtimeinfo/datadescriptor.h | 3 + src/coreclr/vm/codeversion.h | 3 + .../Contracts/ICodeVersions.cs | 27 ++++ .../Contracts/IReJIT.cs | 11 ++ .../TargetNUInt.cs | 12 +- .../Contracts/CodeVersions_1.cs | 60 +++++--- .../Contracts/ReJIT_1.cs | 122 +++++++++++++++ .../Data/ILCodeVersionNode.cs | 5 + .../Data/ILCodeVersioningState.cs | 2 + .../cdacreader/src/Legacy/SOSDacImpl.cs | 142 ++++++++++++++++-- 10 files changed, 358 insertions(+), 29 deletions(-) diff --git a/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/coreclr/debug/runtimeinfo/datadescriptor.h index 1bc05369a38719..096b64da7ab52e 100644 --- a/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -451,6 +451,7 @@ CDAC_TYPE_END(CodeHeapListNode) CDAC_TYPE_BEGIN(ILCodeVersioningState) CDAC_TYPE_INDETERMINATE(ILCodeVersioningState) +CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, FirstVersionNode, cdac_data::FirstVersionNode) CDAC_TYPE_FIELD(ILCodeVersioningState, /*uint32*/, ActiveVersionKind, cdac_data::ActiveVersionKind) CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionNode, cdac_data::ActiveVersionNode) CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionModule, cdac_data::ActiveVersionModule) @@ -469,6 +470,8 @@ CDAC_TYPE_END(NativeCodeVersionNode) CDAC_TYPE_BEGIN(ILCodeVersionNode) CDAC_TYPE_INDETERMINATE(ILCodeVersionNode) CDAC_TYPE_FIELD(ILCodeVersionNode, /*nuint*/, VersionId, cdac_data::VersionId) +CDAC_TYPE_FIELD(ILCodeVersionNode, /*pointer*/, Next, cdac_data::Next) +CDAC_TYPE_FIELD(ILCodeVersionNode, /*uint32*/, RejitState, cdac_data::RejitState) CDAC_TYPE_END(ILCodeVersionNode) CDAC_TYPE_BEGIN(ProfControlBlock) diff --git a/src/coreclr/vm/codeversion.h b/src/coreclr/vm/codeversion.h index 55f3407ca0a555..bddad32caddf42 100644 --- a/src/coreclr/vm/codeversion.h +++ b/src/coreclr/vm/codeversion.h @@ -419,6 +419,8 @@ template<> struct cdac_data { static constexpr size_t VersionId = offsetof(ILCodeVersionNode, m_rejitId); + static constexpr size_t Next = offsetof(ILCodeVersionNode, m_pNextILVersionNode); + static constexpr size_t RejitState = offsetof(ILCodeVersionNode, m_rejitState); }; class ILCodeVersionCollection @@ -543,6 +545,7 @@ class ILCodeVersioningState template<> struct cdac_data { + static constexpr size_t FirstVersionNode = offsetof(ILCodeVersioningState, m_pFirstVersionNode); static constexpr size_t ActiveVersionKind = offsetof(ILCodeVersioningState, m_activeVersion.m_storageKind); static constexpr size_t ActiveVersionNode = offsetof(ILCodeVersioningState, m_activeVersion.m_pVersionNode); static constexpr size_t ActiveVersionModule = offsetof(ILCodeVersioningState, m_activeVersion.m_synthetic.m_pModule); diff --git a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs index bddba2cdc27875..6bbdc67f6c777d 100644 --- a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs +++ b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -16,6 +17,32 @@ internal interface ICodeVersions : IContract public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException(); + + public virtual IEnumerable GetILCodeVersions(TargetPointer methodDesc) => throw new NotImplementedException(); + + public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException(); +} + +internal struct ILCodeVersionHandle +{ + internal readonly TargetPointer Module; + internal uint MethodDefinition; + internal readonly TargetPointer ILCodeVersionNode; + internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress) + { + if (module != TargetPointer.Null && ilCodeVersionNodeAddress != TargetPointer.Null) + throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null"); + + if (module != TargetPointer.Null && methodDef == 0) + throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null"); + + Module = module; + MethodDefinition = methodDef; + ILCodeVersionNode = ilCodeVersionNodeAddress; + } + public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null); + public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; } internal struct NativeCodeVersionHandle diff --git a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs index 6bb9f4e0f0f176..b6864dc275529a 100644 --- a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs +++ b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -9,6 +10,16 @@ internal interface IReJIT : IContract { static string IContract.Name { get; } = nameof(ReJIT); bool IsEnabled() => throw new NotImplementedException(); + + IEnumerable GetRejitIds(TargetPointer methodDesc) => throw new NotImplementedException(); + + uint GetRejitState(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + + TargetNUInt GetRejitId(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + + uint GetRejitState(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); + + TargetNUInt GetRejitId(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException(); } internal readonly struct ReJIT : IReJIT diff --git a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/TargetNUInt.cs b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/TargetNUInt.cs index 8a565225ba8311..3072c484edb2ee 100644 --- a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/TargetNUInt.cs +++ b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/TargetNUInt.cs @@ -7,10 +7,20 @@ namespace Microsoft.Diagnostics.DataContractReader; [DebuggerDisplay("{Hex}")] -public readonly struct TargetNUInt +public readonly struct TargetNUInt : IEquatable { public readonly ulong Value; public TargetNUInt(ulong value) => Value = value; internal string Hex => $"0x{Value:x}"; + + public override bool Equals(object? obj) => obj is TargetNUInt other && Equals(other); + + public bool Equals(TargetNUInt t) => Value == t.Value; + + public override int GetHashCode() => Value.GetHashCode(); + + public static bool operator ==(TargetNUInt lhs, TargetNUInt rhs) => lhs.Equals(rhs); + + public static bool operator !=(TargetNUInt lhs, TargetNUInt rhs) => !(lhs == rhs); } diff --git a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs index 37086698d95e08..2bf8337b214c7a 100644 --- a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs +++ b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs @@ -2,7 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -98,27 +101,51 @@ TargetCodePointer ICodeVersions.GetNativeCode(NativeCodeVersionHandle codeVersio } } - internal struct ILCodeVersionHandle + ILCodeVersionHandle ICodeVersions.GetActiveILCodeVersion(TargetPointer methodDesc) { - internal readonly TargetPointer Module; - internal uint MethodDefinition; - internal readonly TargetPointer ILCodeVersionNode; - internal readonly uint RejitId; + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); + TargetPointer mtAddr = rts.GetMethodTable(md); + TypeHandle typeHandle = rts.GetTypeHandle(mtAddr); + TargetPointer module = rts.GetModule(typeHandle); + uint methodDefToken = rts.GetMethodToken(md); + return FindActiveILCodeVersion(module, methodDefToken); + } - internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress) - { - if (module != TargetPointer.Null && ilCodeVersionNodeAddress != TargetPointer.Null) - throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null"); + IEnumerable ICodeVersions.GetILCodeVersions(TargetPointer methodDesc) + { + // CodeVersionManager::GetILCodeVersions + IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + MethodDescHandle md = rts.GetMethodDescHandle(methodDesc); + TargetPointer mtAddr = rts.GetMethodTable(md); + TypeHandle typeHandle = rts.GetTypeHandle(mtAddr); + TargetPointer module = rts.GetModule(typeHandle); + uint methodDefToken = rts.GetMethodToken(md); + + ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module); + TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState; + TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _); - if (module != TargetPointer.Null && methodDef == 0) - throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null"); + // always add the synthetic version + yield return new ILCodeVersionHandle(module, methodDefToken, TargetPointer.Null); - Module = module; - MethodDefinition = methodDef; - ILCodeVersionNode = ilCodeVersionNodeAddress; + // if explicit versions exist, iterate linked list and return them + if (ilVersionStateAddress != TargetPointer.Null) + { + Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd(ilVersionStateAddress); + TargetPointer nodePointer = ilState.FirstVersionNode; + while (nodePointer != TargetPointer.Null) + { + Data.ILCodeVersionNode current = _target.ProcessedData.GetOrAdd(nodePointer); + yield return new ILCodeVersionHandle(TargetPointer.Null, 0, nodePointer); + nodePointer = current.Next; + } } - public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null); - public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null; + } + + NativeCodeVersionHandle ICodeVersions.GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle) + { + return FindActiveNativeCodeVersion(ilCodeVersionHandle, methodDesc); } [Flags] @@ -263,5 +290,4 @@ private NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle && ((NativeCodeVersionNodeFlags)codeVersion.Flags).HasFlag(NativeCodeVersionNodeFlags.IsActiveChild); }); } - } diff --git a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs index d5bcd98bd4b432..ecf7104d547be7 100644 --- a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs +++ b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts; @@ -17,6 +19,22 @@ private enum COR_PRF_MONITOR COR_PRF_ENABLE_REJIT = 0x00040000, } + + // see src/coreclr/vm/codeversion.h + [Flags] + private enum RejitFlags : uint + { + kStateRequested = 0x00000000, + + kStateGettingReJITParameters = 0x00000001, + + kStateActive = 0x00000002, + + kStateMask = 0x0000000F, + + kSuppressParams = 0x80000000 + } + public ReJIT_1(Target target, Data.ProfControlBlock profControlBlock) { _target = target; @@ -32,4 +50,108 @@ bool IReJIT.IsEnabled() bool clrConfigEnabledReJIT = true; return profEnabledReJIT || clrConfigEnabledReJIT; } + + IEnumerable IReJIT.GetRejitIds(TargetPointer methodDesc) + { + ICodeVersions cv = _target.Contracts.CodeVersions; + + IEnumerable ilCodeVersions = cv.GetILCodeVersions(methodDesc); + + foreach (ILCodeVersionHandle ilCodeVersionHandle in ilCodeVersions) + { + if (((IReJIT)this).GetRejitState(ilCodeVersionHandle) == (uint)RejitFlags.kStateActive) + { + yield return ((IReJIT)this).GetRejitId(ilCodeVersionHandle); + } + } + } + + TargetNUInt IReJIT.GetRejitId(ILCodeVersionHandle ilCodeVersionHandle) + { + if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null) + { + // for non explicit ILCodeVersions, ReJITId is always 0 + return new TargetNUInt(0); + } + ILCodeVersionNode ilCodeVersionNode = GetILCodeVersionNode(ilCodeVersionHandle); + return ilCodeVersionNode.VersionId; + } + + uint IReJIT.GetRejitState(ILCodeVersionHandle ilCodeVersionHandle) + { + if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null) + { + // for non explicit ILCodeVersions, ReJITState is always kStateActive + return (uint)RejitFlags.kStateActive; + } + ILCodeVersionNode ilCodeVersionNode = GetILCodeVersionNode(ilCodeVersionHandle); + return ilCodeVersionNode.RejitState & (uint)RejitFlags.kStateMask; + } + + uint IReJIT.GetRejitState(NativeCodeVersionHandle nativeCodeVersionHandle) + { + if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null) + { + // for non explicit ILCodeVersions, ReJITState is always kStateActive + return (uint)RejitFlags.kStateActive; + } + ILCodeVersionHandle ilCodeVersionHandle = GetILCodeVersionHandle(nativeCodeVersionHandle); + if (!ilCodeVersionHandle.IsValid) + { + throw new ArgumentException("Invalid NativeCodeVersionHandle"); + } + return (uint)((IReJIT)this).GetRejitState(ilCodeVersionHandle); + } + + TargetNUInt IReJIT.GetRejitId(NativeCodeVersionHandle nativeCodeVersionHandle) + { + if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null) + { + return new TargetNUInt(0); + } + NativeCodeVersionNode nativeCodeVersionNode = GetNativeCodeVersionNode(nativeCodeVersionHandle); + return nativeCodeVersionNode.ILVersionId; + } + + private ILCodeVersionHandle GetILCodeVersionHandle(NativeCodeVersionHandle nativeCodeVersionHandle) + { + ICodeVersions cv = _target.Contracts.CodeVersions; + + if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null) + { + throw new NotImplementedException("Synthetic NativeCodeVersion does not have a backing node."); + } + NativeCodeVersionNode nativeCodeVersionNode = GetNativeCodeVersionNode(nativeCodeVersionHandle); + + IEnumerable ilCodeVersions = cv.GetILCodeVersions(nativeCodeVersionNode.MethodDesc); + foreach (ILCodeVersionHandle ilCodeVersionHandle in ilCodeVersions) + { + if (nativeCodeVersionNode.ILVersionId.Value == ((IReJIT)this).GetRejitId(ilCodeVersionHandle).Value) + { + return ilCodeVersionHandle; + } + } + + return ILCodeVersionHandle.Invalid; + } + + private ILCodeVersionNode GetILCodeVersionNode(ILCodeVersionHandle ilCodeVersionHandle) + { + if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null) + { + throw new NotImplementedException("Synthetic ILCodeVersion does not have a backing node."); + } + + return _target.ProcessedData.GetOrAdd(ilCodeVersionHandle.ILCodeVersionNode); + } + + private NativeCodeVersionNode GetNativeCodeVersionNode(NativeCodeVersionHandle nativeCodeVersionHandle) + { + if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null) + { + throw new NotImplementedException("Synthetic NativeCodeVersion does not have a backing node."); + } + + return _target.ProcessedData.GetOrAdd(nativeCodeVersionHandle.CodeVersionNodeAddress); + } } diff --git a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersionNode.cs b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersionNode.cs index fbc7183c6688e2..b954b9186b9a6b 100644 --- a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersionNode.cs +++ b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersionNode.cs @@ -13,7 +13,12 @@ public ILCodeVersionNode(Target target, TargetPointer address) Target.TypeInfo type = target.GetTypeInfo(DataType.ILCodeVersionNode); VersionId = target.ReadNUInt(address + (ulong)type.Fields[nameof(VersionId)].Offset); + Next = target.ReadPointer(address + (ulong)type.Fields[nameof(Next)].Offset); + RejitState = target.Read(address + (ulong)type.Fields[nameof(RejitState)].Offset); } public TargetNUInt VersionId { get; init; } + + public TargetPointer Next { get; init; } + public uint RejitState { get; init; } } diff --git a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersioningState.cs b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersioningState.cs index 92a214d910f6d2..a37e93ed9637e8 100644 --- a/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersioningState.cs +++ b/src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersioningState.cs @@ -12,12 +12,14 @@ public ILCodeVersioningState(Target target, TargetPointer address) { Target.TypeInfo type = target.GetTypeInfo(DataType.ILCodeVersioningState); + FirstVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(FirstVersionNode)].Offset); ActiveVersionKind = target.Read(address + (ulong)type.Fields[nameof(ActiveVersionKind)].Offset); ActiveVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(ActiveVersionNode)].Offset); ActiveVersionModule = target.ReadPointer(address + (ulong)type.Fields[nameof(ActiveVersionModule)].Offset); ActiveVersionMethodDef = target.Read(address + (ulong)type.Fields[nameof(ActiveVersionMethodDef)].Offset); } + public TargetPointer FirstVersionNode { get; set; } public uint ActiveVersionKind { get; set; } public TargetPointer ActiveVersionNode { get; set; } public TargetPointer ActiveVersionModule { get; set; } diff --git a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs index dce6b1bf9d0b2f..6599fa37c4dd90 100644 --- a/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdacreader/src/Legacy/SOSDacImpl.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; using System.Text; @@ -194,13 +196,10 @@ int ISOSDacInterface.GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDes int hr = HResults.E_NOTIMPL; try { - if (cRevertedRejitVersions != 0) - { - throw new NotImplementedException(); // TODO[cdac]: rejit - } Contracts.IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; Contracts.MethodDescHandle methodDescHandle = rtsContract.GetMethodDescHandle(methodDesc); Contracts.ICodeVersions nativeCodeContract = _target.Contracts.CodeVersions; + Contracts.IReJIT rejitContract = _target.Contracts.ReJIT; if (rgRevertedRejitData != null) { @@ -257,10 +256,92 @@ int ISOSDacInterface.GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDes data->ModulePtr = rtsContract.GetModule(typeHandle); // TODO[cdac]: everything in the ReJIT TRY/CATCH in GetMethodDescDataImpl in request.cpp - if (pcNeededRevertedRejitData != null) + try { + if (activeNativeCodeVersion is null || !activeNativeCodeVersion.Value.Valid) + { + activeNativeCodeVersion = nativeCodeContract.GetActiveNativeCodeVersion(new TargetPointer(methodDesc)); + } + + if (activeNativeCodeVersion is null || !activeNativeCodeVersion.Value.Valid) + { + throw new InvalidOperationException("No active native code version found"); + } + + // Active ReJitInfo + CopyNativeCodeVersionToReJitData( + activeNativeCodeVersion.Value, + activeNativeCodeVersion.Value, + &data->rejitDataCurrent); + + // Requested ReJitInfo + Debug.Assert(data->rejitDataRequested.rejitID == 0); + if (ip != 0 && requestedNativeCodeVersion.Valid) + { + CopyNativeCodeVersionToReJitData( + requestedNativeCodeVersion, + activeNativeCodeVersion.Value, + &data->rejitDataRequested); + } + + // Total number of jitted rejit versions + int cJittedRejitVersions = rejitContract.GetRejitIds(methodDescHandle.Address).Count(); + data->cJittedRejitVersions = (uint)cJittedRejitVersions; + + // Reverted ReJitInfos + if (rgRevertedRejitData == null) + { + // No reverted rejit versions will be returned, but maybe caller wants a + // count of all versions + if (pcNeededRevertedRejitData != null) + { + *pcNeededRevertedRejitData = data->cJittedRejitVersions; + } + } + else + { + // Caller wants some reverted rejit versions. Gather reverted rejit version data to return + + // Prepare array to populate with rejitids. "+ 1" because GetReJITIDs + // returns all available rejitids, including the rejitid for the one non-reverted + // current version. + List reJitIds = rejitContract.GetRejitIds(methodDescHandle.Address).ToList(); + + // Go through rejitids. For each reverted one, populate a entry in rgRevertedRejitData + uint iRejitDataReverted = 0; + ILCodeVersionHandle activeVersion = nativeCodeContract.GetActiveILCodeVersion(methodDesc); + TargetNUInt activeVersionId = rejitContract.GetRejitId(activeVersion); + for (uint i = 0; (i < reJitIds.Count) && (iRejitDataReverted < cRevertedRejitVersions); i++) + { + ILCodeVersionHandle ilCodeVersion = nativeCodeContract.GetILCodeVersions(methodDesc) + .FirstOrDefault(ilcode => rejitContract.GetRejitId(ilcode) == reJitIds[(int)i], + ILCodeVersionHandle.Invalid); + - throw new NotImplementedException(); // TODO[cdac]: rejit stuff + if (!ilCodeVersion.IsValid || rejitContract.GetRejitId(ilCodeVersion) == activeVersionId) + { + continue; + } + + NativeCodeVersionHandle activeRejitChild = nativeCodeContract.GetActiveNativeCodeVersionForILCodeVersion(methodDesc, ilCodeVersion); + CopyNativeCodeVersionToReJitData( + activeRejitChild, + activeNativeCodeVersion.Value, + &rgRevertedRejitData[iRejitDataReverted]); + + iRejitDataReverted++; + } + // pcNeededRevertedRejitData != NULL as per condition at top of function (cuz rgRevertedRejitData != + // NULL). + *pcNeededRevertedRejitData = iRejitDataReverted; + } + } + catch (global::System.Exception) + { + if (pcNeededRevertedRejitData != null) + { + *pcNeededRevertedRejitData = 0; + } } #if false // TODO[cdac]: HAVE_GCCOVER @@ -297,7 +378,7 @@ int ISOSDacInterface.GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDes rgRevertedRejitDataLocal = new DacpReJitData[cRevertedRejitVersions]; } uint cNeededRevertedRejitDataLocal = 0; - uint *pcNeededRevertedRejitDataLocal = null; + uint* pcNeededRevertedRejitDataLocal = null; if (pcNeededRevertedRejitData != null) { pcNeededRevertedRejitDataLocal = &cNeededRevertedRejitDataLocal; @@ -321,12 +402,22 @@ int ISOSDacInterface.GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDes Debug.Assert(data->GCStressCodeCopy == dataLocal.GCStressCodeCopy); Debug.Assert(data->managedDynamicMethodObject == dataLocal.managedDynamicMethodObject); Debug.Assert(data->requestedIP == dataLocal.requestedIP); - // TODO[cdac]: cdacreader always returns 0 currently - Debug.Assert(data->cJittedRejitVersions == 0 || data->cJittedRejitVersions == dataLocal.cJittedRejitVersions); - // TODO[cdac]: compare rejitDataCurrent and rejitDataRequested, too + Debug.Assert(data->cJittedRejitVersions == dataLocal.cJittedRejitVersions); + + // rejitDataCurrent + Debug.Assert(data->rejitDataCurrent.rejitID == dataLocal.rejitDataCurrent.rejitID); + Debug.Assert(data->rejitDataCurrent.NativeCodeAddr == dataLocal.rejitDataCurrent.NativeCodeAddr); + Debug.Assert(data->rejitDataCurrent.flags == dataLocal.rejitDataCurrent.flags); + + // rejitDataRequested + Debug.Assert(data->rejitDataRequested.rejitID == dataLocal.rejitDataRequested.rejitID); + Debug.Assert(data->rejitDataRequested.NativeCodeAddr == dataLocal.rejitDataRequested.NativeCodeAddr); + Debug.Assert(data->rejitDataRequested.flags == dataLocal.rejitDataRequested.flags); + + // rgRevertedRejitData if (rgRevertedRejitData != null && rgRevertedRejitDataLocal != null) { - Debug.Assert (cNeededRevertedRejitDataLocal == *pcNeededRevertedRejitData); + Debug.Assert(cNeededRevertedRejitDataLocal == *pcNeededRevertedRejitData); for (ulong i = 0; i < cNeededRevertedRejitDataLocal; i++) { Debug.Assert(rgRevertedRejitData[i].rejitID == rgRevertedRejitDataLocal[i].rejitID); @@ -343,6 +434,35 @@ int ISOSDacInterface.GetMethodDescData(ulong methodDesc, ulong ip, DacpMethodDes return hr; } + private void CopyNativeCodeVersionToReJitData( + NativeCodeVersionHandle nativeCodeVersion, + NativeCodeVersionHandle activeNativeCodeVersion, + DacpReJitData* pReJitData) + { + ICodeVersions cv = _target.Contracts.CodeVersions; + IReJIT rejit = _target.Contracts.ReJIT; + + pReJitData->rejitID = rejit.GetRejitId(nativeCodeVersion).Value; + pReJitData->NativeCodeAddr = cv.GetNativeCode(nativeCodeVersion); + + if (nativeCodeVersion.CodeVersionNodeAddress != activeNativeCodeVersion.CodeVersionNodeAddress || + nativeCodeVersion.MethodDescAddress != activeNativeCodeVersion.MethodDescAddress) + { + pReJitData->flags = DacpReJitData.Flags.kReverted; + } + else + { + pReJitData->flags = rejit.GetRejitState(nativeCodeVersion) switch + { + // kStateRequested + 0x00000000u => DacpReJitData.Flags.kRequested, + // kStateActive + 0x00000002u => DacpReJitData.Flags.kActive, + _ => throw new InvalidOperationException("Unknown SharedRejitInfo state. cDAC should be updated to understand this new state."), + }; + } + } + int ISOSDacInterface.GetMethodDescFromToken(ulong moduleAddr, uint token, ulong* methodDesc) => _legacyImpl is not null ? _legacyImpl.GetMethodDescFromToken(moduleAddr, token, methodDesc) : HResults.E_NOTIMPL; int ISOSDacInterface.GetMethodDescName(ulong methodDesc, uint count, char* name, uint* pNeeded)