Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/design/datacontracts/ExecutionManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ struct CodeBlockHandle
void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion);
// Gets the offset of the codeInfoHandle inside of the code block
TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle);
// Gets information about the EEJitManager: its address, code type, and head of the code heap list.
JitManagerInfo GetEEJitManagerInfo();

// Extension Methods (implemented in terms of other APIs)
bool IsFunclet(CodeBlockHandle codeInfoHandle);
Expand Down Expand Up @@ -70,6 +72,7 @@ Data descriptors used:
| `CodeHeapListNode` | `MapBase` | Start of the map - start address rounded down based on OS page size |
| `CodeHeapListNode` | `HeaderMap` | Bit array used to find the start of methods - relative to `MapBase` |
| `EEJitManager` | `StoreRichDebugInfo` | Boolean value determining if debug info associated with the JitManager contains rich info. |
| `EEJitManager` | `AllCodeHeaps` | Pointer to the head of the linked list of all code heaps managed by the EEJitManager. |
| `RealCodeHeader` | `MethodDesc` | Pointer to the corresponding `MethodDesc` |
| `RealCodeHeader` | `NumUnwindInfos` | Number of Unwind Infos |
| `RealCodeHeader` | `UnwindInfos` | Start address of Unwind Infos |
Expand Down Expand Up @@ -101,6 +104,7 @@ Global variables used:
| Global Name | Type | Purpose |
| --- | --- | --- |
| `ExecutionManagerCodeRangeMapAddress` | TargetPointer | Pointer to the global RangeSectionMap |
| `EEJitManagerAddress` | TargetPointer | Address of the global pointer to the EEJitManager instance (read a TargetPointer from this address to obtain the instance address) |
| `StubCodeBlockLast` | uint8 | Maximum sentinel code header value indentifying a stub code block |
| `HashMapSlotsPerBucket` | uint32 | Number of slots in each bucket of a `HashMap` |
| `HashMapValueMask` | uint64 | Bitmask used when storing values in a `HashMap` |
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/codeman.h
Original file line number Diff line number Diff line change
Expand Up @@ -2005,6 +2005,8 @@ class EECodeGenManager : public IJitManager
Crst m_CodeHeapLock;
ULONG m_iteratorCount;
bool m_storeRichDebugInfo;

friend struct ::cdac_data<EEJitManager>;
};

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -2263,6 +2265,7 @@ template<>
struct cdac_data<EEJitManager>
{
static constexpr size_t StoreRichDebugInfo = offsetof(EEJitManager, m_storeRichDebugInfo);
static constexpr size_t AllCodeHeaps = offsetof(EEJitManager, m_pAllCodeHeaps);
};


Expand Down Expand Up @@ -2580,6 +2583,7 @@ template<>
struct cdac_data<ExecutionManager>
{
static constexpr void* const CodeRangeMapAddress = (void*)&ExecutionManager::g_codeRangeMap.Data[0];
static constexpr PTR_EEJitManager* EEJitManagerPtr = &ExecutionManager::m_pEEJitManager;
};
#endif

Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ CDAC_TYPE_END(RangeSection)
CDAC_TYPE_BEGIN(EEJitManager)
CDAC_TYPE_INDETERMINATE(EEJitManager)
CDAC_TYPE_FIELD(EEJitManager, /*bool*/, StoreRichDebugInfo, cdac_data<EEJitManager>::StoreRichDebugInfo)
CDAC_TYPE_FIELD(EEJitManager, /*pointer*/, AllCodeHeaps, cdac_data<EEJitManager>::AllCodeHeaps)
CDAC_TYPE_END(EEJitManager)

CDAC_TYPE_BEGIN(RealCodeHeader)
Expand Down Expand Up @@ -1153,6 +1154,7 @@ CDAC_GLOBAL(StressLogMaxMessageSize, uint64, (uint64_t)StressMsg::maxMsgSize)
CDAC_GLOBAL(StressLogEnabled, uint8, 0)
#endif
CDAC_GLOBAL_POINTER(ExecutionManagerCodeRangeMapAddress, cdac_data<ExecutionManager>::CodeRangeMapAddress)
CDAC_GLOBAL_POINTER(EEJitManagerAddress, cdac_data<ExecutionManager>::EEJitManagerPtr)
CDAC_GLOBAL_POINTER(PlatformMetadata, &::g_cdacPlatformMetadata)
CDAC_GLOBAL_POINTER(ProfilerControlBlock, &::g_profControlBlock)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ public struct CodeBlockHandle
public CodeBlockHandle(TargetPointer address) => Address = address;
}

public struct JitManagerInfo
{
public TargetPointer ManagerAddress;
public uint CodeType;
public TargetPointer HeapListAddress;
}

public interface IExecutionManager : IContract
{
static string IContract.Name { get; } = nameof(ExecutionManager);
Expand All @@ -25,6 +32,7 @@ public interface IExecutionManager : IContract
// **Currently GetGCInfo only supports X86**
void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => throw new NotImplementedException();
TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => throw new NotImplementedException();
JitManagerInfo GetEEJitManagerInfo() => throw new NotImplementedException();
}

public readonly struct ExecutionManager : IExecutionManager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static class Globals
public const string DirectorySeparator = nameof(DirectorySeparator);

public const string ExecutionManagerCodeRangeMapAddress = nameof(ExecutionManagerCodeRangeMapAddress);
public const string EEJitManagerAddress = nameof(EEJitManagerAddress);
public const string StubCodeBlockLast = nameof(StubCodeBlockLast);
public const string DefaultADID = nameof(DefaultADID);
public const string StaticsPointerMask = nameof(StaticsPointerMask);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,4 +269,19 @@ TargetNUInt IExecutionManager.GetRelativeOffset(CodeBlockHandle codeInfoHandle)

return info.RelativeOffset;
}

JitManagerInfo IExecutionManager.GetEEJitManagerInfo()
{
TargetPointer eeJitManagerPtr = _target.ReadGlobalPointer(Constants.Globals.EEJitManagerAddress);
TargetPointer eeJitManagerAddr = _target.ReadPointer(eeJitManagerPtr);

Data.EEJitManager jitManager = _target.ProcessedData.GetOrAdd<Data.EEJitManager>(eeJitManagerAddr);

return new JitManagerInfo
{
ManagerAddress = eeJitManagerAddr,
CodeType = 0, // miManaged | miIL
HeapListAddress = jitManager.AllCodeHeaps,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ internal ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionM
public TargetPointer GetDebugInfo(CodeBlockHandle codeInfoHandle, out bool hasFlagByte) => _executionManagerCore.GetDebugInfo(codeInfoHandle, out hasFlagByte);
public void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => _executionManagerCore.GetGCInfo(codeInfoHandle, out gcInfo, out gcVersion);
public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle);
public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ internal ExecutionManager_2(Target target, Data.RangeSectionMap topRangeSectionM
public TargetPointer GetDebugInfo(CodeBlockHandle codeInfoHandle, out bool hasFlagByte) => _executionManagerCore.GetDebugInfo(codeInfoHandle, out hasFlagByte);
public void GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPointer gcInfo, out uint gcVersion) => _executionManagerCore.GetGCInfo(codeInfoHandle, out gcInfo, out gcVersion);
public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle);
public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo();
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ public EEJitManager(Target target, TargetPointer address)
Target.TypeInfo type = target.GetTypeInfo(DataType.EEJitManager);

StoreRichDebugInfo = target.Read<byte>(address + (ulong)type.Fields[nameof(StoreRichDebugInfo)].Offset) != 0;
AllCodeHeaps = target.ReadPointer(address + (ulong)type.Fields[nameof(AllCodeHeaps)].Offset);
}

public bool StoreRichDebugInfo { get; init; }
public TargetPointer AllCodeHeaps { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,13 @@ public struct DacpFieldDescData
public ClrDataAddress NextField;
};

public struct DacpJitManagerInfo
{
public ClrDataAddress managerAddr;
public uint codeType;
public ClrDataAddress ptrHeapList;
};

[GeneratedComInterface]
[Guid("436f00f2-b42a-4b9f-870c-e73db66ae930")]
public unsafe partial interface ISOSDacInterface
Expand Down Expand Up @@ -480,7 +487,7 @@ public unsafe partial interface ISOSDacInterface
[PreserveSig]
int GetCodeHeaderData(ClrDataAddress ip, /*struct DacpCodeHeaderData*/ void* data);
[PreserveSig]
int GetJitManagerList(uint count, /*struct DacpJitManagerInfo*/ void* managers, uint* pNeeded);
int GetJitManagerList(uint count, DacpJitManagerInfo* managers, uint* pNeeded);
[PreserveSig]
int GetJitHelperFunctionName(ClrDataAddress ip, uint count, byte* name, uint* pNeeded);
[PreserveSig]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1537,8 +1537,60 @@ int ISOSDacInterface.GetILForModule(ClrDataAddress moduleAddr, int rva, ClrDataA
}
int ISOSDacInterface.GetJitHelperFunctionName(ClrDataAddress ip, uint count, byte* name, uint* pNeeded)
=> _legacyImpl is not null ? _legacyImpl.GetJitHelperFunctionName(ip, count, name, pNeeded) : HResults.E_NOTIMPL;
int ISOSDacInterface.GetJitManagerList(uint count, void* managers, uint* pNeeded)
=> _legacyImpl is not null ? _legacyImpl.GetJitManagerList(count, managers, pNeeded) : HResults.E_NOTIMPL;
int ISOSDacInterface.GetJitManagerList(uint count, DacpJitManagerInfo* managers, uint* pNeeded)
{
int hr = HResults.S_OK;
try
{
if (managers is not null)
{
if (count >= 1)
{
*managers = default;
Contracts.JitManagerInfo jitManagerInfo = _target.Contracts.ExecutionManager.GetEEJitManagerInfo();
managers->managerAddr = jitManagerInfo.ManagerAddress.ToClrDataAddress(_target);
managers->codeType = jitManagerInfo.CodeType;
managers->ptrHeapList = jitManagerInfo.HeapListAddress.ToClrDataAddress(_target);
}
}
else if (pNeeded is not null)
{
*pNeeded = 1;
}
}
catch (System.Exception ex)
{
hr = ex.HResult;
}
#if DEBUG
if (_legacyImpl is not null)
{
if (managers is not null)
{
DacpJitManagerInfo managerLocal = default;
int hrLocal = _legacyImpl.GetJitManagerList(count, &managerLocal, null);
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
if (hr == HResults.S_OK && count >= 1)
{
Debug.Assert(managers->managerAddr == managerLocal.managerAddr);
Debug.Assert(managers->codeType == managerLocal.codeType);
Debug.Assert(managers->ptrHeapList == managerLocal.ptrHeapList);
}
}
else
{
uint neededLocal;
int hrLocal = _legacyImpl.GetJitManagerList(0, null, &neededLocal);
Debug.Assert(hrLocal == hr, $"cDAC: {hr:x}, DAC: {hrLocal:x}");
if (hr == HResults.S_OK && pNeeded is not null)
{
Debug.Assert(*pNeeded == neededLocal);
}
}
}
#endif
return hr;
}

private bool IsJumpRel64(TargetPointer pThunk)
=> 0x48 == _target.Read<byte>(pThunk) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,40 @@ public void GetUnwindInfoBaseAddress_R2R_ManyRuntimeFunction(int version, MockTa
Assert.Equal(new TargetPointer(codeRangeStart), actualBaseAddress);
}

[Theory]
[MemberData(nameof(StdArchAllVersions))]
public void GetEEJitManagerInfo_ReturnsManagerAddress(int version, MockTarget.Architecture arch)
{
MockDescriptors.ExecutionManager emBuilder = new(version, arch, MockDescriptors.ExecutionManager.DefaultAllocationRange);
var target = CreateTarget(emBuilder);

var em = target.Contracts.ExecutionManager;
Assert.NotNull(em);

JitManagerInfo info = em.GetEEJitManagerInfo();
Assert.Equal(emBuilder.EEJitManagerAddress, info.ManagerAddress);
Assert.Equal(0u, info.CodeType);
Assert.Equal(TargetPointer.Null, info.HeapListAddress);
}

[Theory]
[MemberData(nameof(StdArchAllVersions))]
public void GetEEJitManagerInfo_WithCodeHeaps(int version, MockTarget.Architecture arch)
{
TargetPointer expectedHeapList = new(0x0099_aa00);

MockDescriptors.ExecutionManager emBuilder = new(version, arch, MockDescriptors.ExecutionManager.DefaultAllocationRange, allCodeHeaps: expectedHeapList);
var target = CreateTarget(emBuilder);

var em = target.Contracts.ExecutionManager;
Assert.NotNull(em);

JitManagerInfo info = em.GetEEJitManagerInfo();
Assert.Equal(emBuilder.EEJitManagerAddress, info.ManagerAddress);
Assert.Equal(0u, info.CodeType);
Assert.Equal(expectedHeapList, info.HeapListAddress);
}

public static IEnumerable<object[]> StdArchAllVersions()
{
const int highestVersion = 2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,16 @@ public static RangeSectionMapTestBuilder CreateRangeSection(MockTarget.Architect
]
};

private static readonly MockDescriptors.TypeFields EEJitManagerFields = new()
{
DataType = DataType.EEJitManager,
Fields =
[
new(nameof(Data.EEJitManager.StoreRichDebugInfo), DataType.uint8),
new(nameof(Data.EEJitManager.AllCodeHeaps), DataType.pointer),
]
};

internal int Version { get; }

internal MockMemorySpace.Builder Builder { get; }
Expand All @@ -269,11 +279,13 @@ public static RangeSectionMapTestBuilder CreateRangeSection(MockTarget.Architect
private readonly MockMemorySpace.BumpAllocator _nibbleMapAllocator;
private readonly MockMemorySpace.BumpAllocator _allocator;

internal ExecutionManager(int version, MockTarget.Architecture arch, AllocationRange allocationRange)
: this(version, new MockMemorySpace.Builder(new TargetTestHelpers(arch)), allocationRange)
internal TargetPointer EEJitManagerAddress { get; }

internal ExecutionManager(int version, MockTarget.Architecture arch, AllocationRange allocationRange, TargetPointer allCodeHeaps = default)
: this(version, new MockMemorySpace.Builder(new TargetTestHelpers(arch)), allocationRange, allCodeHeaps)
{ }

internal ExecutionManager(int version, MockMemorySpace.Builder builder, AllocationRange allocationRange)
internal ExecutionManager(int version, MockMemorySpace.Builder builder, AllocationRange allocationRange, TargetPointer allCodeHeaps = default)
{
Version = version;
Builder = builder;
Expand All @@ -292,14 +304,30 @@ internal ExecutionManager(int version, MockMemorySpace.Builder builder, Allocati
RealCodeHeaderFields,
ReadyToRunInfoFields(Builder.TargetTestHelpers),
MockDescriptors.ModuleFields,
EEJitManagerFields,
]).Concat(MockDescriptors.HashMap.GetTypes(Builder.TargetTestHelpers))
.Concat(_rfBuilder.Types)
.ToDictionary();

// Allocate and populate the EEJitManager instance
var jitManagerTypeInfo = Types[DataType.EEJitManager];
MockMemorySpace.HeapFragment eeJitManagerFragment = _allocator.Allocate(jitManagerTypeInfo.Size.Value, "EEJitManager");
Builder.AddHeapFragment(eeJitManagerFragment);
EEJitManagerAddress = eeJitManagerFragment.Address;
int pointerSize = Builder.TargetTestHelpers.PointerSize;
Span<byte> jmData = Builder.BorrowAddressRange(eeJitManagerFragment.Address, (int)jitManagerTypeInfo.Size.Value);
Builder.TargetTestHelpers.WritePointer(jmData.Slice(jitManagerTypeInfo.Fields[nameof(Data.EEJitManager.AllCodeHeaps)].Offset, pointerSize), allCodeHeaps);

// Allocate the global pointer that holds the EEJitManager address
MockMemorySpace.HeapFragment eeJitManagerGlobalPointer = _allocator.Allocate((ulong)pointerSize, "EEJitManagerGlobalPointer");
Builder.AddHeapFragment(eeJitManagerGlobalPointer);
Builder.TargetTestHelpers.WritePointer(eeJitManagerGlobalPointer.Data, EEJitManagerAddress);

Globals =
[
(nameof(Constants.Globals.ExecutionManagerCodeRangeMapAddress), ExecutionManagerCodeRangeMapAddress),
(nameof(Constants.Globals.StubCodeBlockLast), 0x0Fu),
(nameof(Constants.Globals.EEJitManagerAddress), eeJitManagerGlobalPointer.Address),
];
Globals = Globals
.Concat(MockDescriptors.HashMap.GetGlobals(Builder.TargetTestHelpers))
Expand Down
Loading