Skip to content

Commit

Permalink
first draft
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Charlamb committed Nov 18, 2024
1 parent 4087cc8 commit cbb0de3
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 29 deletions.
3 changes: 3 additions & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ CDAC_TYPE_END(CodeHeapListNode)

CDAC_TYPE_BEGIN(ILCodeVersioningState)
CDAC_TYPE_INDETERMINATE(ILCodeVersioningState)
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, FirstVersionNode, cdac_data<ILCodeVersioningState>::FirstVersionNode)
CDAC_TYPE_FIELD(ILCodeVersioningState, /*uint32*/, ActiveVersionKind, cdac_data<ILCodeVersioningState>::ActiveVersionKind)
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionNode, cdac_data<ILCodeVersioningState>::ActiveVersionNode)
CDAC_TYPE_FIELD(ILCodeVersioningState, /*pointer*/, ActiveVersionModule, cdac_data<ILCodeVersioningState>::ActiveVersionModule)
Expand All @@ -469,6 +470,8 @@ CDAC_TYPE_END(NativeCodeVersionNode)
CDAC_TYPE_BEGIN(ILCodeVersionNode)
CDAC_TYPE_INDETERMINATE(ILCodeVersionNode)
CDAC_TYPE_FIELD(ILCodeVersionNode, /*nuint*/, VersionId, cdac_data<ILCodeVersionNode>::VersionId)
CDAC_TYPE_FIELD(ILCodeVersionNode, /*pointer*/, Next, cdac_data<ILCodeVersionNode>::Next)
CDAC_TYPE_FIELD(ILCodeVersionNode, /*uint32*/, RejitState, cdac_data<ILCodeVersionNode>::RejitState)
CDAC_TYPE_END(ILCodeVersionNode)

CDAC_TYPE_BEGIN(ProfControlBlock)
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/vm/codeversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,8 @@ template<>
struct cdac_data<ILCodeVersionNode>
{
static constexpr size_t VersionId = offsetof(ILCodeVersionNode, m_rejitId);
static constexpr size_t Next = offsetof(ILCodeVersionNode, m_pNextILVersionNode);
static constexpr size_t RejitState = offsetof(ILCodeVersionNode, m_rejitState);
};

class ILCodeVersionCollection
Expand Down Expand Up @@ -543,6 +545,7 @@ class ILCodeVersioningState
template<>
struct cdac_data<ILCodeVersioningState>
{
static constexpr size_t FirstVersionNode = offsetof(ILCodeVersioningState, m_pFirstVersionNode);
static constexpr size_t ActiveVersionKind = offsetof(ILCodeVersioningState, m_activeVersion.m_storageKind);
static constexpr size_t ActiveVersionNode = offsetof(ILCodeVersioningState, m_activeVersion.m_pVersionNode);
static constexpr size_t ActiveVersionModule = offsetof(ILCodeVersioningState, m_activeVersion.m_synthetic.m_pModule);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

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

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

public virtual ILCodeVersionHandle GetActiveILCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException();

public virtual IEnumerable<ILCodeVersionHandle> GetILCodeVersions(TargetPointer methodDesc) => throw new NotImplementedException();

public virtual NativeCodeVersionHandle GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle) => throw new NotImplementedException();
}

internal struct ILCodeVersionHandle
{
internal readonly TargetPointer Module;
internal uint MethodDefinition;
internal readonly TargetPointer ILCodeVersionNode;
internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress)
{
if (module != TargetPointer.Null && ilCodeVersionNodeAddress != TargetPointer.Null)
throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null");

if (module != TargetPointer.Null && methodDef == 0)
throw new ArgumentException("MethodDefinition must be non-zero if Module is non-null");

Module = module;
MethodDefinition = methodDef;
ILCodeVersionNode = ilCodeVersionNodeAddress;
}
public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null);
public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null;
}

internal struct NativeCodeVersionHandle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal interface IReJIT : IContract
{
static string IContract.Name { get; } = nameof(ReJIT);
bool IsEnabled() => throw new NotImplementedException();

IEnumerable<TargetNUInt> GetRejitIds(TargetPointer methodDesc) => throw new NotImplementedException();

uint GetRejitState(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();

TargetNUInt GetRejitId(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();

uint GetRejitState(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();

TargetNUInt GetRejitId(ILCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
}

internal readonly struct ReJIT : IReJIT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@ namespace Microsoft.Diagnostics.DataContractReader;


[DebuggerDisplay("{Hex}")]
public readonly struct TargetNUInt
public readonly struct TargetNUInt : IEquatable<TargetNUInt>
{
public readonly ulong Value;
public TargetNUInt(ulong value) => Value = value;

internal string Hex => $"0x{Value:x}";

public override bool Equals(object? obj) => obj is TargetNUInt other && Equals(other);

public bool Equals(TargetNUInt t) => Value == t.Value;

public override int GetHashCode() => Value.GetHashCode();

public static bool operator ==(TargetNUInt lhs, TargetNUInt rhs) => lhs.Equals(rhs);

public static bool operator !=(TargetNUInt lhs, TargetNUInt rhs) => !(lhs == rhs);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Diagnostics.DataContractReader.Data;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

Expand Down Expand Up @@ -98,27 +101,51 @@ TargetCodePointer ICodeVersions.GetNativeCode(NativeCodeVersionHandle codeVersio
}
}

internal struct ILCodeVersionHandle
ILCodeVersionHandle ICodeVersions.GetActiveILCodeVersion(TargetPointer methodDesc)
{
internal readonly TargetPointer Module;
internal uint MethodDefinition;
internal readonly TargetPointer ILCodeVersionNode;
internal readonly uint RejitId;
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
MethodDescHandle md = rts.GetMethodDescHandle(methodDesc);
TargetPointer mtAddr = rts.GetMethodTable(md);
TypeHandle typeHandle = rts.GetTypeHandle(mtAddr);
TargetPointer module = rts.GetModule(typeHandle);
uint methodDefToken = rts.GetMethodToken(md);
return FindActiveILCodeVersion(module, methodDefToken);
}

internal ILCodeVersionHandle(TargetPointer module, uint methodDef, TargetPointer ilCodeVersionNodeAddress)
{
if (module != TargetPointer.Null && ilCodeVersionNodeAddress != TargetPointer.Null)
throw new ArgumentException("Both MethodDesc and ILCodeVersionNode cannot be non-null");
IEnumerable<ILCodeVersionHandle> ICodeVersions.GetILCodeVersions(TargetPointer methodDesc)
{
// CodeVersionManager::GetILCodeVersions
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
MethodDescHandle md = rts.GetMethodDescHandle(methodDesc);
TargetPointer mtAddr = rts.GetMethodTable(md);
TypeHandle typeHandle = rts.GetTypeHandle(mtAddr);
TargetPointer module = rts.GetModule(typeHandle);
uint methodDefToken = rts.GetMethodToken(md);

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

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

Module = module;
MethodDefinition = methodDef;
ILCodeVersionNode = ilCodeVersionNodeAddress;
// 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;
}
}
public static ILCodeVersionHandle Invalid => new ILCodeVersionHandle(TargetPointer.Null, 0, TargetPointer.Null);
public bool IsValid => Module != TargetPointer.Null || ILCodeVersionNode != TargetPointer.Null;
}

NativeCodeVersionHandle ICodeVersions.GetActiveNativeCodeVersionForILCodeVersion(TargetPointer methodDesc, ILCodeVersionHandle ilCodeVersionHandle)
{
return FindActiveNativeCodeVersion(ilCodeVersionHandle, methodDesc);
}

[Flags]
Expand Down Expand Up @@ -263,5 +290,4 @@ private NativeCodeVersionHandle FindActiveNativeCodeVersion(ILCodeVersionHandle
&& ((NativeCodeVersionNodeFlags)codeVersion.Flags).HasFlag(NativeCodeVersionNodeFlags.IsActiveChild);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using Microsoft.Diagnostics.DataContractReader.Data;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

Expand All @@ -17,6 +19,22 @@ private enum COR_PRF_MONITOR
COR_PRF_ENABLE_REJIT = 0x00040000,
}


// see src/coreclr/vm/codeversion.h
[Flags]
private enum RejitFlags : uint
{
kStateRequested = 0x00000000,

kStateGettingReJITParameters = 0x00000001,

kStateActive = 0x00000002,

kStateMask = 0x0000000F,

kSuppressParams = 0x80000000
}

public ReJIT_1(Target target, Data.ProfControlBlock profControlBlock)
{
_target = target;
Expand All @@ -32,4 +50,108 @@ bool IReJIT.IsEnabled()
bool clrConfigEnabledReJIT = true;
return profEnabledReJIT || clrConfigEnabledReJIT;
}

IEnumerable<TargetNUInt> IReJIT.GetRejitIds(TargetPointer methodDesc)
{
ICodeVersions cv = _target.Contracts.CodeVersions;

IEnumerable<ILCodeVersionHandle> ilCodeVersions = cv.GetILCodeVersions(methodDesc);

foreach (ILCodeVersionHandle ilCodeVersionHandle in ilCodeVersions)
{
if (((IReJIT)this).GetRejitState(ilCodeVersionHandle) == (uint)RejitFlags.kStateActive)
{
yield return ((IReJIT)this).GetRejitId(ilCodeVersionHandle);
}
}
}

TargetNUInt IReJIT.GetRejitId(ILCodeVersionHandle ilCodeVersionHandle)
{
if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null)
{
// for non explicit ILCodeVersions, ReJITId is always 0
return new TargetNUInt(0);
}
ILCodeVersionNode ilCodeVersionNode = GetILCodeVersionNode(ilCodeVersionHandle);
return ilCodeVersionNode.VersionId;
}

uint IReJIT.GetRejitState(ILCodeVersionHandle ilCodeVersionHandle)
{
if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null)
{
// for non explicit ILCodeVersions, ReJITState is always kStateActive
return (uint)RejitFlags.kStateActive;
}
ILCodeVersionNode ilCodeVersionNode = GetILCodeVersionNode(ilCodeVersionHandle);
return ilCodeVersionNode.RejitState & (uint)RejitFlags.kStateMask;
}

uint IReJIT.GetRejitState(NativeCodeVersionHandle nativeCodeVersionHandle)
{
if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null)
{
// for non explicit ILCodeVersions, ReJITState is always kStateActive
return (uint)RejitFlags.kStateActive;
}
ILCodeVersionHandle ilCodeVersionHandle = GetILCodeVersionHandle(nativeCodeVersionHandle);
if (!ilCodeVersionHandle.IsValid)
{
throw new ArgumentException("Invalid NativeCodeVersionHandle");
}
return (uint)((IReJIT)this).GetRejitState(ilCodeVersionHandle);
}

TargetNUInt IReJIT.GetRejitId(NativeCodeVersionHandle nativeCodeVersionHandle)
{
if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null)
{
return new TargetNUInt(0);
}
NativeCodeVersionNode nativeCodeVersionNode = GetNativeCodeVersionNode(nativeCodeVersionHandle);
return nativeCodeVersionNode.ILVersionId;
}

private ILCodeVersionHandle GetILCodeVersionHandle(NativeCodeVersionHandle nativeCodeVersionHandle)
{
ICodeVersions cv = _target.Contracts.CodeVersions;

if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null)
{
throw new NotImplementedException("Synthetic NativeCodeVersion does not have a backing node.");
}
NativeCodeVersionNode nativeCodeVersionNode = GetNativeCodeVersionNode(nativeCodeVersionHandle);

IEnumerable<ILCodeVersionHandle> ilCodeVersions = cv.GetILCodeVersions(nativeCodeVersionNode.MethodDesc);
foreach (ILCodeVersionHandle ilCodeVersionHandle in ilCodeVersions)
{
if (nativeCodeVersionNode.ILVersionId.Value == ((IReJIT)this).GetRejitId(ilCodeVersionHandle).Value)
{
return ilCodeVersionHandle;
}
}

return ILCodeVersionHandle.Invalid;
}

private ILCodeVersionNode GetILCodeVersionNode(ILCodeVersionHandle ilCodeVersionHandle)
{
if (ilCodeVersionHandle.ILCodeVersionNode == TargetPointer.Null)
{
throw new NotImplementedException("Synthetic ILCodeVersion does not have a backing node.");
}

return _target.ProcessedData.GetOrAdd<ILCodeVersionNode>(ilCodeVersionHandle.ILCodeVersionNode);
}

private NativeCodeVersionNode GetNativeCodeVersionNode(NativeCodeVersionHandle nativeCodeVersionHandle)
{
if (nativeCodeVersionHandle.CodeVersionNodeAddress == TargetPointer.Null)
{
throw new NotImplementedException("Synthetic NativeCodeVersion does not have a backing node.");
}

return _target.ProcessedData.GetOrAdd<NativeCodeVersionNode>(nativeCodeVersionHandle.CodeVersionNodeAddress);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ public ILCodeVersionNode(Target target, TargetPointer address)
Target.TypeInfo type = target.GetTypeInfo(DataType.ILCodeVersionNode);

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

public TargetNUInt VersionId { get; init; }

public TargetPointer Next { get; init; }
public uint RejitState { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ public ILCodeVersioningState(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.ILCodeVersioningState);

FirstVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(FirstVersionNode)].Offset);
ActiveVersionKind = target.Read<uint>(address + (ulong)type.Fields[nameof(ActiveVersionKind)].Offset);
ActiveVersionNode = target.ReadPointer(address + (ulong)type.Fields[nameof(ActiveVersionNode)].Offset);
ActiveVersionModule = target.ReadPointer(address + (ulong)type.Fields[nameof(ActiveVersionModule)].Offset);
ActiveVersionMethodDef = target.Read<uint>(address + (ulong)type.Fields[nameof(ActiveVersionMethodDef)].Offset);
}

public TargetPointer FirstVersionNode { get; set; }
public uint ActiveVersionKind { get; set; }
public TargetPointer ActiveVersionNode { get; set; }
public TargetPointer ActiveVersionModule { get; set; }
Expand Down
Loading

0 comments on commit cbb0de3

Please sign in to comment.