# Contract CodeVersions

This contract encapsulates support for [code versioning](../features/code-versioning.md) in the runtime.

## APIs of contract

```csharp
internal readonly struct ILCodeVersionHandle
{
    public static ILCodeVersionHandle Invalid;

    public bool IsValid;
}
```

```csharp
internal struct NativeCodeVersionHandle
{
    internal static NativeCodeVersionHandle Invalid;

    public bool Valid;
}
```

```csharp
public enum CodeVersionSource : uint
{
    Unknown,
    ReJIT,
    EnC,
}
```

```csharp
// Return a handle to the active version of the IL code for a given method descriptor
public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc);
// Return a handle to the IL code version representing the given native code version
public virtual ILCodeVersionHandle GetILCodeVersion(NativeCodeVersionHandle codeVersionHandle);
// Return all of the IL code versions for a given method descriptor
public virtual IEnumerable<ILCodeVersionHandle> GetILCodeVersions(TargetPointer methodDesc);

// Return all of the Native code versions for a given ILCodeVersion
public virtual IEnumerable<NativeCodeVersionHandle> GetNativeCodeVersions(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle);
// Return a handle to the version of the native code that includes the given instruction pointer
public virtual NativeCodeVersionHandle GetNativeCodeVersionForIP(TargetCodePointer ip);
// 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
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle);

// returns true if the given method descriptor supports multiple code versions
public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc);

// Return the instruction pointer corresponding to the start of the given native code version
public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle);

// Gets the GCStressCodeCopy pointer if available, otherwise returns TargetPointer.Null
public virtual TargetPointer GetGCStressCodeCopy(NativeCodeVersionHandle codeVersionHandle);

// Gets the IL address given a code version
public virtual TargetPointer GetIL(ILCodeVersionHandle ilCodeVersionHandle);

// Determines whether an IL code version has default IL
public virtual bool HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle);

// Gets the instrumented IL offset mapping for an IL code version, if any.
// Returns false when the version has no instrumented map.
public virtual bool TryGetInstrumentedILMap(ILCodeVersionHandle ilCodeVersionHandle, out uint mapEntryCount, out TargetPointer mapEntries);

// Gets the optimization tier for a native code version
public virtual OptimizationTier GetOptimizationTier(NativeCodeVersionHandle codeVersionHandle);

// Gets what produced an IL code version (ReJIT, EnC, or Unknown for the default version)
public virtual CodeVersionSource GetSource(ILCodeVersionHandle ilCodeVersionHandle);

// Gets the EnC version number of an IL code version
public virtual TargetNUInt GetEnCVersion(ILCodeVersionHandle ilCodeVersionHandle);
```

### Extension Methods
```csharp
// Return a handle to the active version of the native code for a given method descriptor
public static NativeCodeVersionHandle GetActiveNativeCodeVersion(this ICodeVersions, TargetPointer methodDesc);
```

## Version 1

See [code versioning](../features/code-versioning.md) for a general overview and the definitions of *synthetic* and *explicit* nodes.

<!-- BEGIN GENERATED: usage contract=CodeVersions version=c1 -->
### Data descriptors used

| Data Descriptor | Field | Type | Meaning |
| --- | --- | --- | --- |
| `GCCoverageInfo` | `SavedCode` | `pointer` | Pointer to the GCCover saved code copy, if supported |
| `ILCodeVersioningState` | `ActiveVersionKind` | `uint32` | an ILCodeVersionKind value indicating which fields of the active version are value |
| `ILCodeVersioningState` | `ActiveVersionMethodDef` | `uint32` | if the active version is synthetic or unknown, the MethodDef token for the method |
| `ILCodeVersioningState` | `ActiveVersionModule` | `pointer` | if the active version is synthetic or unknown, the pointer to the Module that defines the method |
| `ILCodeVersioningState` | `ActiveVersionNode` | `pointer` | if the active version is explicit, the NativeCodeVersionNode for the active version |
| `ILCodeVersioningState` | `FirstVersionNode` | `pointer` | pointer to the first ILCodeVersionNode |
| `ILCodeVersionNode` | `EnCVersion` | `nuint` | for an EnC version, the EnC (edit) version number this node corresponds to |
| `ILCodeVersionNode` | `ILAddress` | `pointer` | Address of IL corresponding to ILCodeVersionNode |
| `ILCodeVersionNode` | `InstrumentedILMap` | `InstrumentedILOffsetMapping` | Embedded InstrumentedILOffsetMapping describing the instrumented IL offset mapping |
| `ILCodeVersionNode` | `Next` | `pointer` | Pointer to the next ILCodeVersionNode |
| `ILCodeVersionNode` | `Source` | `uint32` | a CodeVersionSource value indicating what produced this version (ReJIT, EnC, or unknown) |
| `ILCodeVersionNode` | `VersionId` | `nuint` | Unique IL code version ID of the IL code version node (used as a ReJIT ID when Source is ReJIT) |
| `InstrumentedILOffsetMapping` | `Count` | `uint32` | Number of instrumented IL offset map entries |
| `InstrumentedILOffsetMapping` | `Map` | `pointer` | Pointer to the array of instrumented IL offset map entries |
| `MethodDescVersioningState` | `Flags` | `uint8` | MethodDescVersioningStateFlags flags, see below |
| `MethodDescVersioningState` | `NativeCodeVersionNode` | `pointer` | code version node of this method desc, if active |
| `NativeCodeVersionNode` | `Flags` | `uint32` | NativeCodeVersionNodeFlags flags, see below |
| `NativeCodeVersionNode` | `GCCoverageInfo` | `pointer` | GCStress debug info, if supported |
| `NativeCodeVersionNode` | `ILVersionId` | `nuint` | ReJIT ID of the IL code version that is the parent of this native code version |
| `NativeCodeVersionNode` | `MethodDesc` | `pointer` | indicates a synthetic native code version node |
| `NativeCodeVersionNode` | `NativeCode` | `CodePointer` | indicates an explicit native code version node |
| `NativeCodeVersionNode` | `Next` | `pointer` | pointer to the next native code version |
| `NativeCodeVersionNode` | `OptimizationTier` | `uint32` | The optimization tier of this native code version |

### Global variables used

_None._

### Contracts used

| Contract Name |
| --- |
| `ExecutionManager` |
| `Loader` |
| `PlatformMetadata` |
| `RuntimeTypeSystem` |
<!-- END GENERATED: usage contract=CodeVersions version=c1 -->

The flag indicates that the default version of the code for a method desc is active:
```csharp
internal enum MethodDescVersioningStateFlags : byte
{
    IsDefaultVersionActiveChildFlag = 0x4
};
```

The flag indicates the native code version is active:
```csharp
internal enum NativeCodeVersionNodeFlags : uint
{
    IsActiveChild = 1
};
```

The value of the `ILCodeVersioningState::ActiveVersionKind` field is one of:
```csharp
private enum ILCodeVersionKind
{
    Unknown = 0,
    Explicit = 1, // means Node is set
    Synthetic = 2, // means Module and Token are set
}
```

### Contract Constants:

| Constant Name | Value | Description |
| --- | --- | --- |
| `CorDB_DEFAULT_ENC_FUNCTION_VERSION` | 1 | The EnC version number of the original (unedited) IL. The synthetic default IL code version, and any version not produced by EnC, is treated as having this version. |

Implementation of CodeVersionHandles

```csharp
private readonly struct ILCodeVersionHandle
{
    public readonly TargetPointer Module;
    public readonly uint MethodDefinition;
    public readonly TargetPointer ILCodeVersionNode;
    private ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress)
    {
        Module = module;
        MethodDefinition = methodDef;
        ILCodeVersionNode = ilCodeVersionNodeAddress;
    }

    // for more information on Explicit/Synthetic code versions see docs/design/features/code-versioning.md
    public static ILCodeVersionHandle CreateExplicit(TargetPointer ilCodeVersionNodeAddress) =>
        // create handle from node address
    public static ILCodeVersionHandle CreateSynthetic(TargetPointer module, uint methodDef) =>
        // create handle from module and methodDef

    public static ILCodeVersionHandle Invalid { get; } = // everything is null

    public bool IsValid => // either module or node addr is non nulls

    public bool IsExplicit => ILCodeVersionNode != TargetPointer.Null;
}
```

```csharp
private readonly struct NativeCodeVersionHandle
{
    public readonly TargetPointer MethodDescAddress;
    public readonly TargetPointer CodeVersionNodeAddress;
    private NativeCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer codeVersionNodeAddress)
    {
        MethodDescAddress = methodDescAddress;
        CodeVersionNodeAddress = codeVersionNodeAddress;
    }

    // for more information on Explicit/Synthetic code versions see docs/design/features/code-versioning.md
    public static NativeCodeVersionHandle CreateExplicit(TargetPointer codeVersionNodeAddress) =>
        // create handle from node address
    public static NativeCodeVersionHandle CreateSynthetic(TargetPointer methodDescAddress) =>
        // create handle from method desc

    public static NativeCodeVersionHandle Invalid { get; } = // all is null

    public bool Valid => // either method desc or node address is non null

    public bool IsExplicit => CodeVersionNodeAddress != TargetPointer.Null;
}
```

### Finding active ILCodeVersion for a method
```csharp
public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc);
```
1. Check if the method has an `ILCodeVersioningState`.
2. If the method does not have an `ILCodeVersioningState`, the synthetic ILCodeVersion must be active. Return the synthetic ILCodeVersion for the method.
3. Otherwise, read the active ILCodeVersion off of the `ILCodeVersioningState`.

### Finding ILCodeVersion from a NativeCodeVersion
```csharp
public virtual ILCodeVersionHandle GetILCodeVersion(NativeCodeVersionHandle nativeCodeVersionHandle);
```
1. If `nativeCodeVersionHandle` is invalid, return an invalid `ILCodeVersionHandle`.
2. If `nativeCodeVersionHandle` is synthetic, the corresponding ILCodeVersion must also be synthetic; return the synthetic ILCodeVersion for the method.
3. Search the linked list of ILCodeVersions for one with the matching ILVersionId. Return the ILCodeVersion if found. Otherwise return invalid.

### Finding all of the ILCodeVersions for a method
```csharp
IEnumerable<ILCodeVersionHandle> ICodeVersions.GetILCodeVersions(TargetPointer methodDesc)
{
    // CodeVersionManager::GetILCodeVersions
    GetModuleAndMethodDesc(methodDesc, out TargetPointer module, out uint methodDefToken);

    ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandleFromModulePtr(module);
    TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(
        moduleHandle,
        ModuleLookupMapKind.MethodDefToILCodeVersioningState,
        methodDefToken,
        out var _);

    // always add the synthetic version
    yield return new ILCodeVersionHandle(module, methodDefToken, TargetPointer.Null);

    // if explicit versions exist, iterate linked list and return them
    if (ilVersionStateAddress != TargetPointer.Null)
    {
        Data.ILCodeVersioningState ilState = _target.ProcessedData.GetOrAdd<Data.ILCodeVersioningState>(ilVersionStateAddress);
        TargetPointer nodePointer = ilState.FirstVersionNode;
        while (nodePointer != TargetPointer.Null)
        {
            Data.ILCodeVersionNode current = _target.ProcessedData.GetOrAdd<Data.ILCodeVersionNode>(nodePointer);
            yield return new ILCodeVersionHandle(TargetPointer.Null, 0, nodePointer);
            nodePointer = current.Next;
        }
    }
}
```

### Finding the start of a specific native code version

```csharp
NativeCodeVersionHandle ICodeVersions.GetNativeCodeVersionForIP(TargetCodePointer ip)
{
    Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager;
    EECodeInfoHandle? info = executionManager.GetEECodeInfoHandle(ip);
    if (!info.HasValue)
    {
        return NativeCodeVersionHandle.Invalid;
    }
    TargetPointer methodDescAddress = executionManager.GetMethodDesc(info.Value);
    if (methodDescAddress == TargetPointer.Null)
    {
        return NativeCodeVersionHandle.Invalid;
    }
    IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
    MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress);
    if (!rts.IsVersionable(md))
    {
        return NativeCodeVersion.OfSynthetic(methodDescAddress);
    }
    else
    {
        TargetCodePointer startAddress = executionManager.GetStartAddress(info.Value);
        return GetSpecificNativeCodeVersion(md, startAddress);
    }
}

NativeCodeVersionHandle GetSpecificNativeCodeVersion(MethodDescHandle md, TargetCodePointer startAddress)
{
    // "Initial" stage of NativeCodeVersionIterator::Next() with a null m_ilCodeFilter
    TargetCodePointer firstNativeCode = rts.GetNativeCode(md);
    if (firstNativeCode == startAddress)
    {
        NativeCodeVersionHandle first = NativeCodeVersionHandle.OfSynthetic(md.Address);
        return first;
    }

    return FindNativeCodeVersionNodes(rts, md, (codeVersion) =>
    {
        return codeVersion.MethodDesc == md.Address && codeVersion.NativeCode == startAddress;
    }).FirstOrDefault(NativeCodeVersionHandle.Invalid);
}

IEnumerable<NativeCodeVersionHandle> FindNativeCodeVersionNodes(IRuntimeTypeSystem rts, MethodDescHandle md, Func<Data.NativeCodeVersionNode, bool> predicate)
{
    // ImplicitCodeVersion stage of NativeCodeVersionIterator::Next()
    TargetPointer versioningStateAddr = rts.GetMethodDescVersioningState(md);
    if (versioningStateAddr == TargetPointer.Null)
        yield break;

    Data.MethodDescVersioningState versioningState = _target.ProcessedData.GetOrAdd<Data.MethodDescVersioningState>(versioningStateAddr);

    // LinkedList stage of NativeCodeVersion::Next, heavily inlined
    TargetPointer currentAddress = versioningState.NativeCodeVersionNode;
    while (currentAddress != TargetPointer.Null)
    {
        Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd<Data.NativeCodeVersionNode>(currentAddress);
        if (predicate(current))
        {
            yield return NativeCodeVersionHandle.OfExplicit(currentAddress);
        }
        currentAddress = current.Next;
    }
    yield break;
}
```

### Finding all of the native code versions of an ILCodeVersion for a method descriptor

```csharp
IEnumerable<NativeCodeVersionHandle> ICodeVersions.GetNativeCodeVersions(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle)
{
    if (!ilCodeVersionHandle.IsValid)
        yield break;

    if (!ilCodeVersionHandle.IsExplicit)
    {
        // if the ILCodeVersion is synthetic, then yield the synthetic NativeCodeVersion
        NativeCodeVersionHandle provisionalHandle = NativeCodeVersionHandle.CreateSynthetic(methodDesc);
        yield return provisionalHandle;
    }

    // Iterate through versioning state nodes and return the active one, matching any IL code version
    Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
    MethodDescHandle md = rts.GetMethodDescHandle(methodDesc);
    TargetNUInt ilVersionId = GetId(ilCodeVersionHandle);
    IEnumerable<NativeCodeVersionHandle> nativeCodeVersions = FindNativeCodeVersionNodes(
        rts,
        md,
        (codeVersion) => ilVersionId == codeVersion.ILVersionId);
    foreach (NativeCodeVersionHandle nativeCodeVersion in nativeCodeVersions)
    {
        yield return nativeCodeVersion;
    }
}
```


### Finding the active native code version of an ILCodeVersion for a method descriptor
```csharp
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle);
```

1. If `ilCodeVersionHandle` is invalid, return invalid.
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.
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.

### Determining whether a method descriptor supports code versioning

```csharp
bool ICodeVersions.CodeVersionManagerSupportsMethod(TargetPointer methodDescAddress)
{
    IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
    MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress);
    if (rts.IsDynamicMethod(md))
        return false;
    if (rts.IsCollectibleMethod(md))
        return false;
    return true;
}
```

### Finding GCStress Code Copy
```csharp
public virtual TargetPointer GetGCStressCodeCopy(NativeCodeVersionHandle codeVersionHandle);
```

1. If `codeVersionHandle` is synthetic, use the `IRuntimeTypeSystem` to find the GCStressCodeCopy.
2. If `codeVersionHandle` is explicit, read the `NativeCodeVersionNode` for the `GCCoverageInfo` pointer. This value only exists in some builds. If the value doesn't exist or is a nullptr, return `TargetPointer.Null`. Otherwise return the `SavedCode` pointer from the `GCCoverageInfo` struct.

### Finding IL address for method
```csharp
TargetPointer ICodeVersions.GetIL(ILCodeVersionHandle ilCodeVersionHandle, TargetPointer methodDescPtr)
{
    TargetPointer ilAddress = default;
    if (ilCodeVersionHandle.IsExplicit)
    {
        ilAddress = target.ReadPointer(ilCodeVersionHandle.ILCodeVersionNode + /* ILCodeVersionNode::ILAddress offset */)
    }

    // For the default code version we always fetch the globally stored default IL for a method
    // See src/coreclr/vm/codeversion.cpp for more detailed implementation comments.

    if (ilAddress == TargetPointer.Null)
    {
        // Synthetic ILCodeVersion, get the IL from the module and method def

        ILoader loader = _target.Contracts.Loader;
        ModuleHandle moduleHandle = loader.GetModuleHandleFromModulePtr(ilCodeVersionHandle.Module);
        ilAddress = loader.GetILHeader(moduleHandle, ilCodeVersionHandle.MethodDefinition);
    }

    return ilAddress;
}
```

### Do we have default IL
```csharp
bool ICodeVersions.HasDefaultIL(ILCodeVersionHandle ilCodeVersionHandle)
{
    return ilCodeVersionHandle.IsExplicit ? AsNode(ilCodeVersionHandle).ILAddress == TargetPointer.Null : true;
}
```

### Getting what produced an IL code version

```csharp
CodeVersionSource ICodeVersions.GetSource(ILCodeVersionHandle ilCodeVersionHandle)
{
    if (!ilCodeVersionHandle.IsExplicit)
        return CodeVersionSource.Unknown;
    return // node Source
}
```

### Getting the EnC version of an IL code version

```csharp
TargetNUInt ICodeVersions.GetEnCVersion(ILCodeVersionHandle ilCodeVersionHandle)
{
    if (!ilCodeVersionHandle.IsExplicit)
        return new TargetNUInt(CorDB_DEFAULT_ENC_FUNCTION_VERSION);
    return AsNode(ilCodeVersionHandle).EnCVersion;
}
```

### Getting the instrumented IL offset mapping
```csharp
bool ICodeVersions.TryGetInstrumentedILMap(ILCodeVersionHandle ilCodeVersionHandle, out uint mapEntryCount, out TargetPointer mapEntries)
{
    mapEntryCount = 0;
    mapEntries = TargetPointer.Null;

    // Synthetic IL code versions have no backing node and therefore no instrumented map.
    if (!ilCodeVersionHandle.IsExplicit)
        return false;

    TargetPointer mappingAddress = ilCodeVersionHandle.ILCodeVersionNode + /* ILCodeVersionNode::InstrumentedILMap offset */;
    mapEntryCount = target.Read<uint>(mappingAddress + /* InstrumentedILOffsetMapping::Count offset */);
    mapEntries = target.ReadPointer(mappingAddress + /* InstrumentedILOffsetMapping::Map offset */);
    return true;
}
```
