Skip to content

Commit cbb0de3

Browse files
author
Max Charlamb
committed
first draft
1 parent 4087cc8 commit cbb0de3

File tree

10 files changed

+358
-29
lines changed

10 files changed

+358
-29
lines changed

src/coreclr/debug/runtimeinfo/datadescriptor.h

+3
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ CDAC_TYPE_END(CodeHeapListNode)
451451

452452
CDAC_TYPE_BEGIN(ILCodeVersioningState)
453453
CDAC_TYPE_INDETERMINATE(ILCodeVersioningState)
454+
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, FirstVersionNode, cdac_data<ILCodeVersioningState>::FirstVersionNode)
454455
CDAC_TYPE_FIELD(ILCodeVersioningState, /*uint32*/, ActiveVersionKind, cdac_data<ILCodeVersioningState>::ActiveVersionKind)
455456
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionNode, cdac_data<ILCodeVersioningState>::ActiveVersionNode)
456457
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionModule, cdac_data<ILCodeVersioningState>::ActiveVersionModule)
@@ -469,6 +470,8 @@ CDAC_TYPE_END(NativeCodeVersionNode)
469470
CDAC_TYPE_BEGIN(ILCodeVersionNode)
470471
CDAC_TYPE_INDETERMINATE(ILCodeVersionNode)
471472
CDAC_TYPE_FIELD(ILCodeVersionNode, /*nuint*/, VersionId, cdac_data<ILCodeVersionNode>::VersionId)
473+
CDAC_TYPE_FIELD(ILCodeVersionNode, /*pointer*/, Next, cdac_data<ILCodeVersionNode>::Next)
474+
CDAC_TYPE_FIELD(ILCodeVersionNode, /*uint32*/, RejitState, cdac_data<ILCodeVersionNode>::RejitState)
472475
CDAC_TYPE_END(ILCodeVersionNode)
473476

474477
CDAC_TYPE_BEGIN(ProfControlBlock)

src/coreclr/vm/codeversion.h

+3
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,8 @@ template<>
419419
struct cdac_data<ILCodeVersionNode>
420420
{
421421
static constexpr size_t VersionId = offsetof(ILCodeVersionNode, m_rejitId);
422+
static constexpr size_t Next = offsetof(ILCodeVersionNode, m_pNextILVersionNode);
423+
static constexpr size_t RejitState = offsetof(ILCodeVersionNode, m_rejitState);
422424
};
423425

424426
class ILCodeVersionCollection
@@ -543,6 +545,7 @@ class ILCodeVersioningState
543545
template<>
544546
struct cdac_data<ILCodeVersioningState>
545547
{
548+
static constexpr size_t FirstVersionNode = offsetof(ILCodeVersioningState, m_pFirstVersionNode);
546549
static constexpr size_t ActiveVersionKind = offsetof(ILCodeVersioningState, m_activeVersion.m_storageKind);
547550
static constexpr size_t ActiveVersionNode = offsetof(ILCodeVersioningState, m_activeVersion.m_pVersionNode);
548551
static constexpr size_t ActiveVersionModule = offsetof(ILCodeVersioningState, m_activeVersion.m_synthetic.m_pModule);

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ICodeVersions.cs

+27
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56

67
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
78

@@ -16,6 +17,32 @@ internal interface ICodeVersions : IContract
1617

1718
public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
1819

20+
public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException();
21+
22+
public virtual IEnumerable<ILCodeVersionHandle> GetILCodeVersions(TargetPointer methodDesc) => throw new NotImplementedException();
23+
24+
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException();
25+
}
26+
27+
internal struct ILCodeVersionHandle
28+
{
29+
internal readonly TargetPointer Module;
30+
internal uint MethodDefinition;
31+
internal readonly TargetPointer ILCodeVersionNode;
32+
internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress)
33+
{
34+
if (module != TargetPointer.Null && ilCodeVersionNodeAddress != TargetPointer.Null)
35+
throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null");
36+
37+
if (module != TargetPointer.Null && methodDef == 0)
38+
throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null");
39+
40+
Module = module;
41+
MethodDefinition = methodDef;
42+
ILCodeVersionNode = ilCodeVersionNodeAddress;
43+
}
44+
public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null);
45+
public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null;
1946
}
2047

2148
internal struct NativeCodeVersionHandle

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IReJIT.cs

+11
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,24 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56

67
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
78

89
internal interface IReJIT : IContract
910
{
1011
static string IContract.Name { get; } = nameof(ReJIT);
1112
bool IsEnabled() => throw new NotImplementedException();
13+
14+
IEnumerable<TargetNUInt> GetRejitIds(TargetPointer methodDesc) => throw new NotImplementedException();
15+
16+
uint GetRejitState(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
17+
18+
TargetNUInt GetRejitId(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
19+
20+
uint GetRejitState(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
21+
22+
TargetNUInt GetRejitId(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
1223
}
1324

1425
internal readonly struct ReJIT : IReJIT

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/TargetNUInt.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,20 @@ namespace Microsoft.Diagnostics.DataContractReader;
77

88

99
[DebuggerDisplay("{Hex}")]
10-
public readonly struct TargetNUInt
10+
public readonly struct TargetNUInt : IEquatable<TargetNUInt>
1111
{
1212
public readonly ulong Value;
1313
public TargetNUInt(ulong value) => Value = value;
1414

1515
internal string Hex => $"0x{Value:x}";
16+
17+
public override bool Equals(object? obj) => obj is TargetNUInt other && Equals(other);
18+
19+
public bool Equals(TargetNUInt t) => Value == t.Value;
20+
21+
public override int GetHashCode() => Value.GetHashCode();
22+
23+
public static bool operator ==(TargetNUInt lhs, TargetNUInt rhs) => lhs.Equals(rhs);
24+
25+
public static bool operator !=(TargetNUInt lhs, TargetNUInt rhs) => !(lhs == rhs);
1626
}

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/CodeVersions_1.cs

+43-17
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Diagnostics;
7+
using System.Linq;
8+
using Microsoft.Diagnostics.DataContractReader.Data;
69

710
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
811

@@ -98,27 +101,51 @@ TargetCodePointer ICodeVersions.GetNativeCode(NativeCodeVersionHandle codeVersio
98101
}
99102
}
100103

101-
internal struct ILCodeVersionHandle
104+
ILCodeVersionHandle ICodeVersions.GetActiveILCodeVersion(TargetPointer methodDesc)
102105
{
103-
internal readonly TargetPointer Module;
104-
internal uint MethodDefinition;
105-
internal readonly TargetPointer ILCodeVersionNode;
106-
internal readonly uint RejitId;
106+
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
107+
MethodDescHandle md = rts.GetMethodDescHandle(methodDesc);
108+
TargetPointer mtAddr = rts.GetMethodTable(md);
109+
TypeHandle typeHandle = rts.GetTypeHandle(mtAddr);
110+
TargetPointer module = rts.GetModule(typeHandle);
111+
uint methodDefToken = rts.GetMethodToken(md);
112+
return FindActiveILCodeVersion(module, methodDefToken);
113+
}
107114

108-
internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress)
109-
{
110-
if (module != TargetPointer.Null && ilCodeVersionNodeAddress != TargetPointer.Null)
111-
throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null");
115+
IEnumerable<ILCodeVersionHandle> ICodeVersions.GetILCodeVersions(TargetPointer methodDesc)
116+
{
117+
// CodeVersionManager::GetILCodeVersions
118+
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
119+
MethodDescHandle md = rts.GetMethodDescHandle(methodDesc);
120+
TargetPointer mtAddr = rts.GetMethodTable(md);
121+
TypeHandle typeHandle = rts.GetTypeHandle(mtAddr);
122+
TargetPointer module = rts.GetModule(typeHandle);
123+
uint methodDefToken = rts.GetMethodToken(md);
124+
125+
ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module);
126+
TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState;
127+
TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _);
112128

113-
if (module != TargetPointer.Null && methodDef == 0)
114-
throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null");
129+
// always add the synthetic version
130+
yield return new ILCodeVersionHandle(module, methodDefToken, TargetPointer.Null);
115131

116-
Module = module;
117-
MethodDefinition = methodDef;
118-
ILCodeVersionNode = ilCodeVersionNodeAddress;
132+
// if explicit versions exist, iterate linked list and return them
133+
if (ilVersionStateAddress != TargetPointer.Null)
134+
{
135+
Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd<Data.ILCodeVersioningState>(ilVersionStateAddress);
136+
TargetPointer nodePointer = ilState.FirstVersionNode;
137+
while (nodePointer != TargetPointer.Null)
138+
{
139+
Data.ILCodeVersionNode current = _target.ProcessedData.GetOrAdd<Data.ILCodeVersionNode>(nodePointer);
140+
yield return new ILCodeVersionHandle(TargetPointer.Null, 0, nodePointer);
141+
nodePointer = current.Next;
142+
}
119143
}
120-
public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null);
121-
public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null;
144+
}
145+
146+
NativeCodeVersionHandle ICodeVersions.GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle)
147+
{
148+
return FindActiveNativeCodeVersion(ilCodeVersionHandle, methodDesc);
122149
}
123150

124151
[Flags]
@@ -263,5 +290,4 @@ private NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle
263290
&& ((NativeCodeVersionNodeFlags)codeVersion.Flags).HasFlag(NativeCodeVersionNodeFlags.IsActiveChild);
264291
});
265292
}
266-
267293
}

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ReJIT_1.cs

+122
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
6+
using Microsoft.Diagnostics.DataContractReader.Data;
57

68
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
79

@@ -17,6 +19,22 @@ private enum COR_PRF_MONITOR
1719
COR_PRF_ENABLE_REJIT = 0x00040000,
1820
}
1921

22+
23+
// see src/coreclr/vm/codeversion.h
24+
[Flags]
25+
private enum RejitFlags : uint
26+
{
27+
kStateRequested = 0x00000000,
28+
29+
kStateGettingReJITParameters = 0x00000001,
30+
31+
kStateActive = 0x00000002,
32+
33+
kStateMask = 0x0000000F,
34+
35+
kSuppressParams = 0x80000000
36+
}
37+
2038
public ReJIT_1(Target target, Data.ProfControlBlock profControlBlock)
2139
{
2240
_target = target;
@@ -32,4 +50,108 @@ bool IReJIT.IsEnabled()
3250
bool clrConfigEnabledReJIT = true;
3351
return profEnabledReJIT || clrConfigEnabledReJIT;
3452
}
53+
54+
IEnumerable<TargetNUInt> IReJIT.GetRejitIds(TargetPointer methodDesc)
55+
{
56+
ICodeVersions cv = _target.Contracts.CodeVersions;
57+
58+
IEnumerable<ILCodeVersionHandle> ilCodeVersions = cv.GetILCodeVersions(methodDesc);
59+
60+
foreach (ILCodeVersionHandle ilCodeVersionHandle in ilCodeVersions)
61+
{
62+
if (((IReJIT)this).GetRejitState(ilCodeVersionHandle) == (uint)RejitFlags.kStateActive)
63+
{
64+
yield return ((IReJIT)this).GetRejitId(ilCodeVersionHandle);
65+
}
66+
}
67+
}
68+
69+
TargetNUInt IReJIT.GetRejitId(ILCodeVersionHandle ilCodeVersionHandle)
70+
{
71+
if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null)
72+
{
73+
// for non explicit ILCodeVersions, ReJITId is always 0
74+
return new TargetNUInt(0);
75+
}
76+
ILCodeVersionNode ilCodeVersionNode = GetILCodeVersionNode(ilCodeVersionHandle);
77+
return ilCodeVersionNode.VersionId;
78+
}
79+
80+
uint IReJIT.GetRejitState(ILCodeVersionHandle ilCodeVersionHandle)
81+
{
82+
if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null)
83+
{
84+
// for non explicit ILCodeVersions, ReJITState is always kStateActive
85+
return (uint)RejitFlags.kStateActive;
86+
}
87+
ILCodeVersionNode ilCodeVersionNode = GetILCodeVersionNode(ilCodeVersionHandle);
88+
return ilCodeVersionNode.RejitState & (uint)RejitFlags.kStateMask;
89+
}
90+
91+
uint IReJIT.GetRejitState(NativeCodeVersionHandle nativeCodeVersionHandle)
92+
{
93+
if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null)
94+
{
95+
// for non explicit ILCodeVersions, ReJITState is always kStateActive
96+
return (uint)RejitFlags.kStateActive;
97+
}
98+
ILCodeVersionHandle ilCodeVersionHandle = GetILCodeVersionHandle(nativeCodeVersionHandle);
99+
if (!ilCodeVersionHandle.IsValid)
100+
{
101+
throw new ArgumentException("Invalid NativeCodeVersionHandle");
102+
}
103+
return (uint)((IReJIT)this).GetRejitState(ilCodeVersionHandle);
104+
}
105+
106+
TargetNUInt IReJIT.GetRejitId(NativeCodeVersionHandle nativeCodeVersionHandle)
107+
{
108+
if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null)
109+
{
110+
return new TargetNUInt(0);
111+
}
112+
NativeCodeVersionNode nativeCodeVersionNode = GetNativeCodeVersionNode(nativeCodeVersionHandle);
113+
return nativeCodeVersionNode.ILVersionId;
114+
}
115+
116+
private ILCodeVersionHandle GetILCodeVersionHandle(NativeCodeVersionHandle nativeCodeVersionHandle)
117+
{
118+
ICodeVersions cv = _target.Contracts.CodeVersions;
119+
120+
if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null)
121+
{
122+
throw new NotImplementedException("Synthetic NativeCodeVersion does not have a backing node.");
123+
}
124+
NativeCodeVersionNode nativeCodeVersionNode = GetNativeCodeVersionNode(nativeCodeVersionHandle);
125+
126+
IEnumerable<ILCodeVersionHandle> ilCodeVersions = cv.GetILCodeVersions(nativeCodeVersionNode.MethodDesc);
127+
foreach (ILCodeVersionHandle ilCodeVersionHandle in ilCodeVersions)
128+
{
129+
if (nativeCodeVersionNode.ILVersionId.Value == ((IReJIT)this).GetRejitId(ilCodeVersionHandle).Value)
130+
{
131+
return ilCodeVersionHandle;
132+
}
133+
}
134+
135+
return ILCodeVersionHandle.Invalid;
136+
}
137+
138+
private ILCodeVersionNode GetILCodeVersionNode(ILCodeVersionHandle ilCodeVersionHandle)
139+
{
140+
if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null)
141+
{
142+
throw new NotImplementedException("Synthetic ILCodeVersion does not have a backing node.");
143+
}
144+
145+
return _target.ProcessedData.GetOrAdd<ILCodeVersionNode>(ilCodeVersionHandle.ILCodeVersionNode);
146+
}
147+
148+
private NativeCodeVersionNode GetNativeCodeVersionNode(NativeCodeVersionHandle nativeCodeVersionHandle)
149+
{
150+
if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null)
151+
{
152+
throw new NotImplementedException("Synthetic NativeCodeVersion does not have a backing node.");
153+
}
154+
155+
return _target.ProcessedData.GetOrAdd<NativeCodeVersionNode>(nativeCodeVersionHandle.CodeVersionNodeAddress);
156+
}
35157
}

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersionNode.cs

+5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ public ILCodeVersionNode(Target target, TargetPointer address)
1313
Target.TypeInfo type = target.GetTypeInfo(DataType.ILCodeVersionNode);
1414

1515
VersionId = target.ReadNUInt(address + (ulong)type.Fields[nameof(VersionId)].Offset);
16+
Next = target.ReadPointer(address + (ulong)type.Fields[nameof(Next)].Offset);
17+
RejitState = target.Read<uint>(address + (ulong)type.Fields[nameof(RejitState)].Offset);
1618
}
1719

1820
public TargetNUInt VersionId { get; init; }
21+
22+
public TargetPointer Next { get; init; }
23+
public uint RejitState { get; init; }
1924
}

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Data/ILCodeVersioningState.cs

+2
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ public ILCodeVersioningState(Target target, TargetPointer address)
1212
{
1313
Target.TypeInfo type = target.GetTypeInfo(DataType.ILCodeVersioningState);
1414

15+
FirstVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(FirstVersionNode)].Offset);
1516
ActiveVersionKind = target.Read<uint>(address + (ulong)type.Fields[nameof(ActiveVersionKind)].Offset);
1617
ActiveVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(ActiveVersionNode)].Offset);
1718
ActiveVersionModule = target.ReadPointer(address + (ulong)type.Fields[nameof(ActiveVersionModule)].Offset);
1819
ActiveVersionMethodDef = target.Read<uint>(address + (ulong)type.Fields[nameof(ActiveVersionMethodDef)].Offset);
1920
}
2021

22+
public TargetPointer FirstVersionNode { get; set; }
2123
public uint ActiveVersionKind { get; set; }
2224
public TargetPointer ActiveVersionNode { get; set; }
2325
public TargetPointer ActiveVersionModule { get; set; }

0 commit comments

Comments
 (0)