Skip to content

Commit d4de7c9

Browse files
author
Max Charlamb
committed
add rejit support to GetMethodDescData
1 parent 09b30a4 commit d4de7c9

File tree

18 files changed

+1007
-70
lines changed

18 files changed

+1007
-70
lines changed

docs/design/datacontracts/CodeVersions.md

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,29 @@ This contract encapsulates support for [code versioning](../features/code-versio
44

55
## APIs of contract
66

7+
```csharp
8+
internal readonly struct ILCodeVersionHandle
9+
{
10+
internal readonly TargetPointer Module;
11+
internal readonly uint MethodDefinition;
12+
internal readonly TargetPointer ILCodeVersionNode;
13+
internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress)
14+
{
15+
if (module != TargetPointer.Null && ilCodeVersionNodeAddress != TargetPointer.Null)
16+
throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null");
17+
18+
if (module != TargetPointer.Null && methodDef == 0)
19+
throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null");
20+
21+
Module = module;
22+
MethodDefinition = methodDef;
23+
ILCodeVersionNode = ilCodeVersionNodeAddress;
24+
}
25+
public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null);
26+
public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null;
27+
}
28+
```
29+
730
```csharp
831
internal struct NativeCodeVersionHandle
932
{
@@ -26,10 +49,19 @@ internal struct NativeCodeVersionHandle
2649
```
2750

2851
```csharp
52+
// Return a handle to the active version of the IL code for a given method descriptor
53+
public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc);
54+
// Return a handle to the IL code version representing the given native code version
55+
public virtual ILCodeVersionHandle GetILCodeVersion(NativeCodeVersionHandle codeVersionHandle);
56+
// Return all of the IL code versions for a given method descriptor
57+
public virtual IEnumerable<ILCodeVersionHandle> GetILCodeVersions(TargetPointer methodDesc);
58+
2959
// Return a handle to the version of the native code that includes the given instruction pointer
3060
public virtual NativeCodeVersionHandle GetNativeCodeVersionForIP(TargetCodePointer ip);
3161
// Return a handle to the active version of the native code for a given method descriptor
3262
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc);
63+
// Return a handle to the active version of the native code for a given method descriptor and IL code version. The IL code version and method descriptor must represent the same method
64+
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle);
3365

3466
// returns true if the given method descriptor supports multiple code versions
3567
public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc);
@@ -52,11 +84,13 @@ Data descriptors used:
5284
| NativeCodeVersionNode | NativeCode | indicates an explicit native code version node |
5385
| NativeCodeVersionNode | Flags | `NativeCodeVersionNodeFlags` flags, see below |
5486
| NativeCodeVersionNode | VersionId | Version ID corresponding to the parent IL code version |
87+
| ILCodeVersioningState | FirstVersionNode | pointer to the first `ILCodeVersionNode` |
5588
| ILCodeVersioningState | ActiveVersionKind | an `ILCodeVersionKind` value indicating which fields of the active version are value |
5689
| ILCodeVersioningState | ActiveVersionNode | if the active version is explicit, the NativeCodeVersionNode for the active version |
5790
| ILCodeVersioningState | ActiveVersionModule | if the active version is synthetic or unknown, the pointer to the Module that defines the method |
5891
| ILCodeVersioningState | ActiveVersionMethodDef | if the active version is synthetic or unknown, the MethodDef token for the method |
5992
| ILCodeVersionNode | VersionId | Version ID of the node |
93+
| ILCodeVersionNode | Next | Pointer to the next `ILCodeVersionNode`|
6094

6195
The flag indicates that the default version of the code for a method desc is active:
6296
```csharp
@@ -93,6 +127,40 @@ Contracts used:
93127
| Loader |
94128
| RuntimeTypeSystem |
95129

130+
### Finding all of the ILCodeVersions for a method
131+
```csharp
132+
IEnumerable<ILCodeVersionHandle> ICodeVersions.GetILCodeVersions(TargetPointer methodDesc)
133+
{
134+
// CodeVersionManager::GetILCodeVersions
135+
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
136+
MethodDescHandle md = rts.GetMethodDescHandle(methodDesc);
137+
TargetPointer mtAddr = rts.GetMethodTable(md);
138+
TypeHandle typeHandle = rts.GetTypeHandle(mtAddr);
139+
TargetPointer module = rts.GetModule(typeHandle);
140+
uint methodDefToken = rts.GetMethodToken(md);
141+
142+
ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module);
143+
TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState;
144+
TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _);
145+
146+
// always add the synthetic version
147+
yield return new ILCodeVersionHandle(module, methodDefToken, TargetPointer.Null);
148+
149+
// if explicit versions exist, iterate linked list and return them
150+
if (ilVersionStateAddress != TargetPointer.Null)
151+
{
152+
Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd<Data.ILCodeVersioningState>(ilVersionStateAddress);
153+
TargetPointer nodePointer = ilState.FirstVersionNode;
154+
while (nodePointer != TargetPointer.Null)
155+
{
156+
Data.ILCodeVersionNode current = _target.ProcessedData.GetOrAdd<Data.ILCodeVersionNode>(nodePointer);
157+
yield return new ILCodeVersionHandle(TargetPointer.Null, 0, nodePointer);
158+
nodePointer = current.Next;
159+
}
160+
}
161+
}
162+
```
163+
96164
### Finding the start of a specific native code version
97165

98166
```csharp
@@ -235,7 +303,7 @@ bool IsActiveNativeCodeVersion(NativeCodeVersionHandle nativeCodeVersion)
235303

236304
NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDefActiveVersion, TargetPointer methodDescAddress)
237305
{
238-
TargetNUInt? ilVersionId = default;
306+
TargetNUInt ilVersionId = GetId(ilcodeVersion);
239307
if (methodDefActiveVersion.Module != TargetPointer.Null)
240308
{
241309
NativeCodeVersionHandle provisionalHandle = new NativeCodeVersionHandle(methodDescAddress: methodDescAddress, codeVersionNodeAddress: TargetPointer.Null);
@@ -256,7 +324,7 @@ NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle methodDe
256324
MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress);
257325
return FindFirstCodeVersion(rts, md, (codeVersion) =>
258326
{
259-
return (!ilVersionId.HasValue || ilVersionId.Value.Value == codeVersion.ILVersionId.Value)
327+
return (ilVersionId == codeVersion.ILVersionId)
260328
&& ((NativeCodeVersionNodeFlags)codeVersion.Flags).HasFlag(NativeCodeVersionNodeFlags.IsActiveChild);
261329
});
262330
}

docs/design/datacontracts/ReJIT.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,22 @@ This contract encapsulates support for [ReJIT](../features/code-versioning.md) i
44

55
## APIs of contract
66

7+
```csharp
8+
public enum RejitState
9+
{
10+
Requested,
11+
Active
12+
}
13+
```
14+
715
```csharp
816
bool IsEnabled();
17+
18+
RejitState GetRejitState(ILCodeVersionHandle codeVersionHandle);
19+
20+
TargetNUInt GetRejitId(ILCodeVersionHandle codeVersionHandle);
21+
22+
IEnumerable<TargetNUInt> GetRejitIds(TargetPointer methodDesc)
923
```
1024

1125
## Version 1
@@ -14,6 +28,8 @@ Data descriptors used:
1428
| Data Descriptor Name | Field | Meaning |
1529
| --- | --- | --- |
1630
| ProfControlBlock | GlobalEventMask | an `ICorProfiler` `COR_PRF_MONITOR` value |
31+
| ILCodeVersionNode | VersionId | `ILCodeVersion` ReJIT id
32+
| ILCodeVersionNode | RejitState | a `RejitFlags` value |
1733

1834
Global variables used:
1935
| Global Name | Type | Purpose |
@@ -23,6 +39,7 @@ Global variables used:
2339
Contracts used:
2440
| Contract Name |
2541
| --- |
42+
| CodeVersions |
2643

2744
```csharp
2845
// see src/coreclr/inc/corprof.idl
@@ -32,6 +49,21 @@ private enum COR_PRF_MONITOR
3249
COR_PRF_ENABLE_REJIT = 0x00040000,
3350
}
3451

52+
// see src/coreclr/vm/codeversion.h
53+
[Flags]
54+
public enum RejitFlags : uint
55+
{
56+
kStateRequested = 0x00000000,
57+
58+
kStateGettingReJITParameters = 0x00000001,
59+
60+
kStateActive = 0x00000002,
61+
62+
kStateMask = 0x0000000F,
63+
64+
kSuppressParams = 0x80000000
65+
}
66+
3567
bool IsEnabled()
3668
{
3769
TargetPointer address = target.ReadGlobalPointer("ProfilerControlBlock");
@@ -40,4 +72,56 @@ bool IsEnabled()
4072
bool clrConfigEnabledReJit = /* host process does not have environment variable DOTNET_ProfAPI_ReJitOnAttach set to 0 */;
4173
return profEnabledReJIT || clrConfigEnabledReJIT;
4274
}
75+
76+
RejitState GetRejitState(ILCodeVersionHandle codeVersion)
77+
{
78+
// ILCodeVersion::GetRejitState
79+
if (codeVersion is not explicit)
80+
{
81+
// for non explicit ILCodeVersions, ReJITState is always kStateActive
82+
return RejitState.Active;
83+
}
84+
else
85+
{
86+
// ILCodeVersionNode::GetRejitState
87+
ILCodeVersionNode codeVersionNode = AsNode(codeVersion);
88+
return ((RejitFlags)ilCodeVersionNode.RejitState & RejitFlags.kStateMask) switch
89+
{
90+
RejitFlags.kStateRequested => RejitState.Requested,
91+
RejitFlags.kStateActive => RejitState.Active,
92+
_ => throw new NotImplementedException($"Unknown ReJIT state: {ilCodeVersionNode.RejitState}"),
93+
};
94+
}
95+
}
96+
97+
TargetNUInt GetRejitId(ILCodeVersionHandle codeVersion)
98+
{
99+
// ILCodeVersion::GetVersionId
100+
if (codeVersion is not explicit)
101+
{
102+
// for non explicit ILCodeVersions, ReJITId is always 0
103+
return new TargetNUInt(0);
104+
}
105+
else
106+
{
107+
// ILCodeVersionNode::GetVersionId
108+
ILCodeVersionNode codeVersionNode = AsNode(codeVersion);
109+
return codeVersionNode.VersionId;
110+
}
111+
}
112+
113+
IEnumerable<TargetNUInt> GetRejitIds(TargetPointer methodDesc)
114+
{
115+
// ReJitManager::GetReJITIDs
116+
ICodeVersions cv = _target.Contracts.CodeVersions;
117+
IEnumerable<ILCodeVersionHandle> ilCodeVersions = cv.GetILCodeVersions(methodDesc);
118+
119+
foreach (ILCodeVersionHandle ilCodeVersionHandle in ilCodeVersions)
120+
{
121+
if (GetRejitState(ilCodeVersionHandle) == RejitState.Active)
122+
{
123+
yield return GetRejitId(ilCodeVersionHandle);
124+
}
125+
}
126+
}
43127
```

src/coreclr/debug/runtimeinfo/datadescriptor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ CDAC_TYPE_END(CodeHeapListNode)
483483

484484
CDAC_TYPE_BEGIN(ILCodeVersioningState)
485485
CDAC_TYPE_INDETERMINATE(ILCodeVersioningState)
486+
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, FirstVersionNode, cdac_data<ILCodeVersioningState>::FirstVersionNode)
486487
CDAC_TYPE_FIELD(ILCodeVersioningState, /*uint32*/, ActiveVersionKind, cdac_data<ILCodeVersioningState>::ActiveVersionKind)
487488
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionNode, cdac_data<ILCodeVersioningState>::ActiveVersionNode)
488489
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionModule, cdac_data<ILCodeVersioningState>::ActiveVersionModule)
@@ -501,6 +502,8 @@ CDAC_TYPE_END(NativeCodeVersionNode)
501502
CDAC_TYPE_BEGIN(ILCodeVersionNode)
502503
CDAC_TYPE_INDETERMINATE(ILCodeVersionNode)
503504
CDAC_TYPE_FIELD(ILCodeVersionNode, /*nuint*/, VersionId, cdac_data<ILCodeVersionNode>::VersionId)
505+
CDAC_TYPE_FIELD(ILCodeVersionNode, /*pointer*/, Next, cdac_data<ILCodeVersionNode>::Next)
506+
CDAC_TYPE_FIELD(ILCodeVersionNode, /*uint32*/, RejitState, cdac_data<ILCodeVersionNode>::RejitState)
504507
CDAC_TYPE_END(ILCodeVersionNode)
505508

506509
CDAC_TYPE_BEGIN(ProfControlBlock)

src/coreclr/vm/codeversion.h

Lines changed: 3 additions & 0 deletions
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);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.Diagnostics.DataContractReader.Contracts.Extensions;
5+
6+
internal static class ICodeVersionsExtensions
7+
{
8+
internal static NativeCodeVersionHandle GetActiveNativeCodeVersion(this ICodeVersions cv, TargetPointer methodDesc)
9+
{
10+
ILCodeVersionHandle iLCodeVersionHandle = cv.GetActiveILCodeVersion(methodDesc);
11+
return cv.GetActiveNativeCodeVersionForILCodeVersion(methodDesc, iLCodeVersionHandle);
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Generic;
5+
6+
namespace Microsoft.Diagnostics.DataContractReader.Contracts.Extensions;
7+
8+
internal static class IReJITExtensions
9+
{
10+
public static IEnumerable<TargetNUInt> GetRejitIds(this IReJIT rejit, Target target, TargetPointer methodDesc)
11+
{
12+
ICodeVersions cv = target.Contracts.CodeVersions;
13+
14+
IEnumerable<ILCodeVersionHandle> ilCodeVersions = cv.GetILCodeVersions(methodDesc);
15+
16+
foreach (ILCodeVersionHandle ilCodeVersionHandle in ilCodeVersions)
17+
{
18+
if (rejit.GetRejitState(ilCodeVersionHandle) == RejitState.Active)
19+
{
20+
yield return rejit.GetRejitId(ilCodeVersionHandle);
21+
}
22+
}
23+
}
24+
}

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

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,51 @@
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 ICodeVersions : IContract
910
{
1011
static string IContract.Name { get; } = nameof(CodeVersions);
1112

13+
public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException();
14+
15+
public virtual ILCodeVersionHandle GetILCodeVersion(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
16+
17+
public virtual IEnumerable<ILCodeVersionHandle> GetILCodeVersions(TargetPointer methodDesc) => throw new NotImplementedException();
18+
1219
public virtual NativeCodeVersionHandle GetNativeCodeVersionForIP(TargetCodePointer ip) => throw new NotImplementedException();
13-
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException();
1420

15-
public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException();
21+
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException();
1622

1723
public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
1824

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

21-
internal struct NativeCodeVersionHandle
49+
internal readonly struct NativeCodeVersionHandle
2250
{
2351
// no public constructors
2452
internal readonly TargetPointer MethodDescAddress;

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,25 @@
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

9+
public enum RejitState
10+
{
11+
Requested,
12+
Active
13+
}
14+
815
internal interface IReJIT : IContract
916
{
1017
static string IContract.Name { get; } = nameof(ReJIT);
18+
1119
bool IsEnabled() => throw new NotImplementedException();
20+
21+
RejitState GetRejitState(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
22+
23+
TargetNUInt GetRejitId(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
1224
}
1325

1426
internal readonly struct ReJIT : IReJIT

0 commit comments

Comments
 (0)