@@ -4,39 +4,48 @@ This contract encapsulates support for [code versioning](../features/code-versio
4
4
5
5
## APIs of contract
6
6
7
+ ``` csharp
8
+ internal readonly struct ILCodeVersionHandle
9
+ {
10
+ public static ILCodeVersionHandle Invalid ;
11
+
12
+ public bool IsValid ;
13
+ }
14
+ ```
15
+
7
16
``` csharp
8
17
internal struct NativeCodeVersionHandle
9
18
{
10
- // no public constructors
11
- internal readonly TargetPointer MethodDescAddress ;
12
- internal readonly TargetPointer CodeVersionNodeAddress ;
13
- internal NativeCodeVersionHandle (TargetPointer methodDescAddress , TargetPointer codeVersionNodeAddress )
14
- {
15
- if (methodDescAddress != TargetPointer .Null && codeVersionNodeAddress != TargetPointer .Null )
16
- {
17
- throw new ArgumentException (" Only one of methodDescAddress and codeVersionNodeAddress can be non-null" );
18
- }
19
- MethodDescAddress = methodDescAddress ;
20
- CodeVersionNodeAddress = codeVersionNodeAddress ;
21
- }
19
+ internal static NativeCodeVersionHandle Invalid ;
22
20
23
- internal static NativeCodeVersionHandle Invalid => new (TargetPointer .Null , TargetPointer .Null );
24
- public bool Valid => MethodDescAddress != TargetPointer .Null || CodeVersionNodeAddress != TargetPointer .Null ;
21
+ public bool Valid ;
25
22
}
26
23
```
27
24
28
25
``` csharp
26
+ // Return a handle to the active version of the IL code for a given method descriptor
27
+ public virtual ILCodeVersionHandle GetActiveILCodeVersion (TargetPointer methodDesc );
28
+ // Return a handle to the IL code version representing the given native code version
29
+ public virtual ILCodeVersionHandle GetILCodeVersion (NativeCodeVersionHandle codeVersionHandle );
30
+ // Return all of the IL code versions for a given method descriptor
31
+ public virtual IEnumerable < ILCodeVersionHandle > GetILCodeVersions (TargetPointer methodDesc );
32
+
29
33
// Return a handle to the version of the native code that includes the given instruction pointer
30
34
public virtual NativeCodeVersionHandle GetNativeCodeVersionForIP (TargetCodePointer ip );
31
- // Return a handle to the active version of the native code for a given method descriptor
32
- public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion (TargetPointer methodDesc );
35
+ // 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
36
+ public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion (TargetPointer methodDesc , ILCodeVersionHandle ilCodeVersionHandle );
33
37
34
38
// returns true if the given method descriptor supports multiple code versions
35
39
public virtual bool CodeVersionManagerSupportsMethod (TargetPointer methodDesc );
36
40
37
41
// Return the instruction pointer corresponding to the start of the given native code version
38
42
public virtual TargetCodePointer GetNativeCode (NativeCodeVersionHandle codeVersionHandle );
39
43
```
44
+ ### Extension Methods
45
+ ``` csharp
46
+ // Return a handle to the active version of the native code for a given method descriptor
47
+ public static NativeCodeVersionHandle GetActiveNativeCodeVersion (this ICodeVersions , TargetPointer methodDesc );
48
+ ```
40
49
41
50
## Version 1
42
51
@@ -52,11 +61,13 @@ Data descriptors used:
52
61
| NativeCodeVersionNode | NativeCode | indicates an explicit native code version node |
53
62
| NativeCodeVersionNode | Flags | ` NativeCodeVersionNodeFlags ` flags, see below |
54
63
| NativeCodeVersionNode | VersionId | Version ID corresponding to the parent IL code version |
64
+ | ILCodeVersioningState | FirstVersionNode | pointer to the first ` ILCodeVersionNode ` |
55
65
| ILCodeVersioningState | ActiveVersionKind | an ` ILCodeVersionKind ` value indicating which fields of the active version are value |
56
66
| ILCodeVersioningState | ActiveVersionNode | if the active version is explicit, the NativeCodeVersionNode for the active version |
57
67
| ILCodeVersioningState | ActiveVersionModule | if the active version is synthetic or unknown, the pointer to the Module that defines the method |
58
68
| ILCodeVersioningState | ActiveVersionMethodDef | if the active version is synthetic or unknown, the MethodDef token for the method |
59
69
| ILCodeVersionNode | VersionId | Version ID of the node |
70
+ | ILCodeVersionNode | Next | Pointer to the next ` ILCodeVersionNode ` |
60
71
61
72
The flag indicates that the default version of the code for a method desc is active:
62
73
``` csharp
@@ -93,6 +104,51 @@ Contracts used:
93
104
| Loader |
94
105
| RuntimeTypeSystem |
95
106
107
+ ### Finding active ILCodeVersion for a method
108
+ ``` csharp
109
+ public virtual ILCodeVersionHandle GetActiveILCodeVersion (TargetPointer methodDesc );
110
+ ```
111
+ 1 . Check if the method has an ` ILCodeVersioningState ` .
112
+ 2 . If the method does not have an ` ILCodeVersioningState ` , the synthetic ILCodeVersion must be active. Return the synthetic ILCodeVersion for the method.
113
+ 3 . Otherwise, read the active ILCodeVersion off of the ` ILCodeVersioningState ` .
114
+
115
+ ### Finding ILCodeVersion from a NativeCodeVersion
116
+ ``` csharp
117
+ public virtual ILCodeVersionHandle GetILCodeVersion (NativeCodeVersionHandle nativeCodeVersionHandle );
118
+ ```
119
+ 1 . If ` nativeCodeVersionHandle ` is invalid, return an invalid ` ILCodeVersionHandle ` .
120
+ 2 . If ` nativeCodeVersionHandle ` is synthetic, the corresponding ILCodeVersion must also be synthetic; return the synthetic ILCodeVersion for the method.
121
+ 3 . Search the linked list of ILCodeVersions for one with the matching ILVersionId. Return the ILCodeVersion if found. Otherwise return invalid.
122
+
123
+ ### Finding all of the ILCodeVersions for a method
124
+ ``` csharp
125
+ IEnumerable < ILCodeVersionHandle > ICodeVersions .GetILCodeVersions (TargetPointer methodDesc )
126
+ {
127
+ // CodeVersionManager::GetILCodeVersions
128
+ GetModuleAndMethodDesc (methodDesc , out TargetPointer module , out uint methodDefToken );
129
+
130
+ ModuleHandle moduleHandle = _target .Contracts .Loader .GetModuleHandle (module );
131
+ TargetPointer ilCodeVersionTable = _target .Contracts .Loader .GetLookupTables (moduleHandle ).MethodDefToILCodeVersioningState ;
132
+ TargetPointer ilVersionStateAddress = _target .Contracts .Loader .GetModuleLookupMapElement (ilCodeVersionTable , methodDefToken , out var _ );
133
+
134
+ // always add the synthetic version
135
+ yield return new ILCodeVersionHandle (module , methodDefToken , TargetPointer .Null );
136
+
137
+ // if explicit versions exist, iterate linked list and return them
138
+ if (ilVersionStateAddress != TargetPointer .Null )
139
+ {
140
+ Data .ILCodeVersioningState ilState = _target .ProcessedData .GetOrAdd <Data .ILCodeVersioningState >(ilVersionStateAddress );
141
+ TargetPointer nodePointer = ilState .FirstVersionNode ;
142
+ while (nodePointer != TargetPointer .Null )
143
+ {
144
+ Data .ILCodeVersionNode current = _target .ProcessedData .GetOrAdd <Data .ILCodeVersionNode >(nodePointer );
145
+ yield return new ILCodeVersionHandle (TargetPointer .Null , 0 , nodePointer );
146
+ nodePointer = current .Next ;
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
96
152
### Finding the start of a specific native code version
97
153
98
154
``` csharp
@@ -113,7 +169,7 @@ NativeCodeVersionHandle ICodeVersions.GetNativeCodeVersionForIP(TargetCodePointe
113
169
MethodDescHandle md = rts .GetMethodDescHandle (methodDescAddress );
114
170
if (! rts .IsVersionable (md ))
115
171
{
116
- return new NativeCodeVersionHandle (methodDescAddress , codeVersionNodeAddress : TargetPointer . Null );
172
+ return NativeCodeVersion . OfSynthetic (methodDescAddress );
117
173
}
118
174
else
119
175
{
@@ -128,7 +184,7 @@ NativeCodeVersionHandle GetSpecificNativeCodeVersion(MethodDescHandle md, Target
128
184
TargetCodePointer firstNativeCode = rts .GetNativeCode (md );
129
185
if (firstNativeCode == startAddress )
130
186
{
131
- NativeCodeVersionHandle first = new NativeCodeVersionHandle (md .Address , TargetPointer . Null );
187
+ NativeCodeVersionHandle first = NativeCodeVersionHandle . OfSynthetic (md .Address );
132
188
return first ;
133
189
}
134
190
@@ -154,114 +210,23 @@ NativeCodeVersionHandle FindFirstCodeVersion(IRuntimeTypeSystem rts, MethodDescH
154
210
Data .NativeCodeVersionNode current = _target .ProcessedData .GetOrAdd <Data .NativeCodeVersionNode >(currentAddress );
155
211
if (predicate (current ))
156
212
{
157
- return new NativeCodeVersionHandle ( methodDescAddress : TargetPointer . Null , currentAddress );
213
+ return NativeCodeVersionHandle . OfExplicit ( currentAddress );
158
214
}
159
215
currentAddress = current .Next ;
160
216
}
161
217
return NativeCodeVersionHandle .Invalid ;
162
218
}
163
219
```
164
220
165
- ### Finding the active native code version of a method descriptor
166
-
221
+ ### Finding the active native code version of an ILCodeVersion for a method descriptor
167
222
``` csharp
168
- NativeCodeVersionHandle ICodeVersions .GetActiveNativeCodeVersion (TargetPointer methodDesc )
169
- {
170
- IRuntimeTypeSystem rts = _target .Contracts .RuntimeTypeSystem ;
171
- MethodDescHandle md = rts .GetMethodDescHandle (methodDesc );
172
- TargetPointer mtAddr = rts .GetMethodTable (md );
173
- TypeHandle typeHandle = rts .GetTypeHandle (mtAddr );
174
- TargetPointer module = rts .GetModule (typeHandle );
175
- uint methodDefToken = rts .GetMethodToken (md );
176
- ILCodeVersionHandle methodDefActiveVersion = FindActiveILCodeVersion (module , methodDefToken );
177
- if (! methodDefActiveVersion .IsValid )
178
- {
179
- return NativeCodeVersionHandle .Invalid ;
180
- }
181
- return FindActiveNativeCodeVersion (methodDefActiveVersion , methodDesc );
182
- }
183
-
184
- ILCodeVersionHandle ILCodeVersionHandleFromState (Data .ILCodeVersioningState ilState )
185
- {
186
- switch ((ILCodeVersionKind )ilState .ActiveVersionKind )
187
- {
188
- case ILCodeVersionKind .Explicit :
189
- return new ILCodeVersionHandle (module : TargetPointer .Null , methodDef : 0 , ilState .ActiveVersionNode );
190
- case ILCodeVersionKind .Synthetic :
191
- case ILCodeVersionKind .Unknown :
192
- return new ILCodeVersionHandle (ilState .ActiveVersionModule , ilState .ActiveVersionMethodDef , TargetPointer .Null );
193
- default :
194
- throw new InvalidOperationException ($" Unknown ILCodeVersionKind {ilState .ActiveVersionKind }" );
195
- }
196
- }
197
-
198
- ILCodeVersionHandle FindActiveILCodeVersion (TargetPointer module , uint methodDefinition )
199
- {
200
- ModuleHandle moduleHandle = _target .Contracts .Loader .GetModuleHandle (module );
201
- TargetPointer ilCodeVersionTable = _target .Contracts .Loader .GetLookupTables (moduleHandle ).MethodDefToILCodeVersioningState ;
202
- TargetPointer ilVersionStateAddress = _target .Contracts .Loader .GetModuleLookupMapElement (ilCodeVersionTable , methodDefinition , out var _ );
203
- if (ilVersionStateAddress == TargetPointer .Null )
204
- {
205
- return new ILCodeVersionHandle (module , methodDefinition , TargetPointer .Null );
206
- }
207
- Data .ILCodeVersioningState ilState = _target .ProcessedData .GetOrAdd <Data .ILCodeVersioningState >(ilVersionStateAddress );
208
- return ILCodeVersionHandleFromState (ilState );
209
- }
210
-
211
- bool IsActiveNativeCodeVersion (NativeCodeVersionHandle nativeCodeVersion )
212
- {
213
- if (nativeCodeVersion .MethodDescAddress != TargetPointer .Null )
214
- {
215
- MethodDescHandle md = _target .Contracts .RuntimeTypeSystem .GetMethodDescHandle (nativeCodeVersion .MethodDescAddress );
216
- TargetPointer versioningStateAddress = _target .Contracts .RuntimeTypeSystem .GetMethodDescVersioningState (md );
217
- if (versioningStateAddress == TargetPointer .Null )
218
- {
219
- return true ;
220
- }
221
- Data .MethodDescVersioningState versioningState = _target .ProcessedData .GetOrAdd <Data .MethodDescVersioningState >(versioningStateAddress );
222
- MethodDescVersioningStateFlags flags = (MethodDescVersioningStateFlags )versioningState .Flags ;
223
- return flags .HasFlag (MethodDescVersioningStateFlags .IsDefaultVersionActiveChildFlag );
224
- }
225
- else if (nativeCodeVersion .CodeVersionNodeAddress != TargetPointer .Null )
226
- {
227
- uint flags = _target .Read <uint >(nativeCodeVersion .CodeVersionNodeAddress + /* NativeCodVersionNode::Flags offset*/ )
228
- return ((NativeCodeVersionNodeFlags )flags ).HasFlag (NativeCodeVersionNodeFlags .IsActiveChild );
229
- }
230
- else
231
- {
232
- throw new ArgumentException (" Invalid NativeCodeVersionHandle" );
233
- }
234
- }
235
-
236
- NativeCodeVersionHandle FindActiveNativeCodeVersion (ILCodeVersionHandle methodDefActiveVersion , TargetPointer methodDescAddress )
237
- {
238
- TargetNUInt ? ilVersionId = default ;
239
- if (methodDefActiveVersion .Module != TargetPointer .Null )
240
- {
241
- NativeCodeVersionHandle provisionalHandle = new NativeCodeVersionHandle (methodDescAddress : methodDescAddress , codeVersionNodeAddress : TargetPointer .Null );
242
- if (IsActiveNativeCodeVersion (provisionalHandle ))
243
- {
244
- return provisionalHandle ;
245
- }
246
- }
247
- else
248
- {
249
- // Get the explicit IL code version
250
- Debug .Assert (methodDefActiveVersion .ILCodeVersionNode != TargetPointer .Null );
251
- ilVersionId = _target .ReadNUint (methodDefActiveVersion .ILCodeVersionNode + /* ILCodeVersionNode::VersionId offset */ );
252
- }
253
-
254
- // Iterate through versioning state nodes and return the active one, matching any IL code version
255
- Contracts .IRuntimeTypeSystem rts = _target .Contracts .RuntimeTypeSystem ;
256
- MethodDescHandle md = rts .GetMethodDescHandle (methodDescAddress );
257
- return FindFirstCodeVersion (rts , md , (codeVersion ) =>
258
- {
259
- return (! ilVersionId .HasValue || ilVersionId .Value .Value == codeVersion .ILVersionId .Value )
260
- && ((NativeCodeVersionNodeFlags )codeVersion .Flags ).HasFlag (NativeCodeVersionNodeFlags .IsActiveChild );
261
- });
262
- }
223
+ public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion (TargetPointer methodDesc , ILCodeVersionHandle ilCodeVersionHandle );
263
224
```
264
225
226
+ 1 . If ` ilCodeVersionHandle ` is invalid, return invalid.
227
+ 2 . If ` ilCodeVersionHandle ` is synthetic, the active native code version could be synthetic. Check if the method's synthetic NativeCodeVersion is active. If it is, return that NativeCodeVersion.
228
+ 3 . Search the linked list of NativeCodeVersions for one with the active flag and the relevent ILVersionId. If found return that node. Otherwise return invalid.
229
+
265
230
### Determining whether a method descriptor supports code versioning
266
231
267
232
``` csharp
0 commit comments