Skip to content

Commit 02dafce

Browse files
author
Max Charlamb
committed
add to contract docs
1 parent e3b3aaa commit 02dafce

File tree

14 files changed

+740
-51
lines changed

14 files changed

+740
-51
lines changed

docs/design/datacontracts/CodeVersions.md

+70-2
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

+82
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,20 @@ This contract encapsulates support for [ReJIT](../features/code-versioning.md) i
44

55
## APIs of contract
66

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

1123
## Version 1
@@ -14,6 +26,8 @@ Data descriptors used:
1426
| Data Descriptor Name | Field | Meaning |
1527
| --- | --- | --- |
1628
| ProfControlBlock | GlobalEventMask | an `ICorProfiler` `COR_PRF_MONITOR` value |
29+
| ILCodeVersionNode | VersionId | `ILCodeVersion` ReJIT id
30+
| ILCodeVersionNode | RejitState | a `RejitFlags` value |
1731

1832
Global variables used:
1933
| Global Name | Type | Purpose |
@@ -23,6 +37,7 @@ Global variables used:
2337
Contracts used:
2438
| Contract Name |
2539
| --- |
40+
| CodeVersions |
2641

2742
```csharp
2843
// see src/coreclr/inc/corprof.idl
@@ -32,6 +47,21 @@ private enum COR_PRF_MONITOR
3247
COR_PRF_ENABLE_REJIT = 0x00040000,
3348
}
3449

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

src/coreclr/debug/runtimeinfo/datadescriptor.h

+3
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

+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

+32-2
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,53 @@
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();
20+
1321
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException();
1422

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

1725
public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
1826

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

21-
internal struct NativeCodeVersionHandle
51+
internal readonly struct NativeCodeVersionHandle
2252
{
2353
// no public constructors
2454
internal readonly TargetPointer MethodDescAddress;

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

+14
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,27 @@
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();
24+
25+
IEnumerable<TargetNUInt> GetRejitIds(TargetPointer methodDesc) => throw new NotImplementedException();
1226
}
1327

1428
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
}

0 commit comments

Comments
 (0)