Skip to content

Commit 22dc50d

Browse files
authored
[cdac] Implement ExecutionManager.ReadyToRunJitManager.GetMethodInfo (minus handling of hot/cold lookup) (#109766)
Implement `ExecutionManager.ReadyToRunJitManager.GetMethodInfo` without handling of hot/cold lookup. This maps to `ReadyToRunJitManager::JitCodeToMethodInfo` in the runtime. Basic logic is: - Check if the address is in a thunk for `READYTORUN_HELPER_DelayLoad_MethodCall` - Find the runtime function entry corresponding to the address - Look up the `MethodDesc` for the entry point using the `ReadyToRunInfo`'s hash map Add tests for `ExecutionManager` for getting code blocks and method desc in R2R and for `HashMap` lookup functionality - Start using `Moq` - this change only uses it to mock `IPlatformMetadata`, but I think we should be able to use this instead some of the explicit subclasses we have for testing. - Simplify usage of `TestPlaceholderTarget` such that setting the reader delegate and data cache are not explicit operations - make its constructor take a reader delegate and always create a default data cache - Slight clean up of `ExecutionManagerTestBuilder` - make it more consistent with `MockDescriptors.*` - I think this should probably also be moved under `MockDescriptors`, but I didn't want to do that in this change (same with some helpers in other test classes, like PrecodeStubsTests) Manually validated with `!clrstack` and `!ip2md` in windbg that R2R functions now show up correctly (were `<unknown>` before this change).
1 parent 0cecd7d commit 22dc50d

38 files changed

+1405
-395
lines changed

docs/design/datacontracts/ExecutionManager.md

Lines changed: 112 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,57 @@ struct CodeBlockHandle
2828
## Version 1
2929

3030
The execution manager uses two data structures to map the entire target address space to native executable code.
31-
The range section map is used to partition the address space into large chunks which point to range section fragments. Each chunk is relatively large. If there is any executable code in the chunk, the chunk will contain one or more range section fragments that cover subsets of the chunk. Conversely if a massive method is JITed a single range section fragment may span multiple adjacent chunks.
31+
The [range section map](#rangesectionmap) is used to partition the address space into large chunks which point to range section fragments. Each chunk is relatively large. If there is any executable code in the chunk, the chunk will contain one or more range section fragments that cover subsets of the chunk. Conversely if a massive method is JITed a single range section fragment may span multiple adjacent chunks.
3232

33-
Within a range section fragment, a nibble map structure is used to map arbitrary IP addresses back to the start of the method (and to the code header which immediately preceeeds the entrypoint to the code).
33+
Within a range section fragment, a [nibble map](#nibblemap) structure is used to map arbitrary IP addresses back to the start of the method (and to the code header which immediately preceeeds the entrypoint to the code).
3434

3535
Data descriptors used:
3636
| Data Descriptor Name | Field | Meaning |
3737
| --- | --- | --- |
38-
| RangeSectionMap | TopLevelData | pointer to the outermost RangeSection |
39-
| RangeSectionFragment| ? | ? |
40-
| RangeSection | ? | ? |
41-
| RealCodeHeader | ? | ? |
42-
| HeapList | ? | ? |
43-
44-
38+
| `RangeSectionMap` | `TopLevelData` | Pointer to the outermost RangeSection |
39+
| `RangeSectionFragment`| `RangeBegin` | Begin address of the fragment |
40+
| `RangeSectionFragment`| `RangeEndOpen` | End address of the fragment |
41+
| `RangeSectionFragment`| `RangeSection` | Pointer to the corresponding `RangeSection` |
42+
| `RangeSectionFragment`| `Next` | Pointer to the next fragment |
43+
| `RangeSection` | `RangeBegin` | Begin address of the range section |
44+
| `RangeSection` | `RangeEndOpen` | End address of the range section |
45+
| `RangeSection` | `NextForDelete` | Pointer to next range section for deletion |
46+
| `RangeSection` | `JitManager` | Pointer to the JIT manager |
47+
| `RangeSection` | `Flags` | Flags for the range section |
48+
| `RangeSection` | `HeapList` | Pointer to the heap list |
49+
| `RangeSection` | `R2RModule` | ReadyToRun module |
50+
| `CodeHeapListNode` | `Next` | Next node |
51+
| `CodeHeapListNode` | `StartAddress` | Start address of the used portion of the code heap |
52+
| `CodeHeapListNode` | `EndAddress` | End address of the used portion of the code heap |
53+
| `CodeHeapListNode` | `MapBase` | Start of the map - start address rounded down based on OS page size |
54+
| `CodeHeapListNode` | `HeaderMap` | Bit array used to find the start of methods - relative to `MapBase` |
55+
| `RealCodeHeader` | `MethodDesc` | Pointer to the corresponding `MethodDesc` |
56+
| `Module` | `ReadyToRunInfo` | Pointer to the `ReadyToRunInfo` for the module |
57+
| `ReadyToRunInfo` | `CompositeInfo` | Pointer to composite R2R info - or itself for non-composite |
58+
| `ReadyToRunInfo` | `NumRuntimeFunctions` | Number of `RuntimeFunctions` |
59+
| `ReadyToRunInfo` | `RuntimeFunctions` | Pointer to an array of `RuntimeFunctions` |
60+
| `ReadyToRunInfo` | `DelayLoadMethodCallThunks` | Pointer to an `ImageDataDirectory` for the delay load method call thunks |
61+
| `ReadyToRunInfo` | `EntryPointToMethodDescMap` | `HashMap` of entry point addresses to `MethodDesc` pointers |
62+
| `ImageDataDirectory` | `VirtualAddress` | Virtual address of the image data directory |
63+
| `ImageDataDirectory` | `Size` | Size of the data |
64+
| `RuntimeFunction` | `BeginAddress` | Begin address of the function |
65+
| `HashMap` | `Buckets` | Pointer to the buckets of a `HashMap` |
66+
| `Bucket` | `Keys` | Array of keys of `HashMapSlotsPerBucket` length |
67+
| `Bucket` | `Values` | Array of values of `HashMapSlotsPerBucket` length |
4568

4669
Global variables used:
4770
| Global Name | Type | Purpose |
4871
| --- | --- | --- |
49-
| ExecutionManagerCodeRangeMapAddress | TargetPointer | Pointer to the global RangeSectionMap
50-
| StubCodeBlockLast | uint8 | Maximum sentinel code header value indentifying a stub code block
72+
| `ExecutionManagerCodeRangeMapAddress` | TargetPointer | Pointer to the global RangeSectionMap |
73+
| `StubCodeBlockLast` | uint8 | Maximum sentinel code header value indentifying a stub code block |
74+
| `HashMapSlotsPerBucket` | uint32 | Number of slots in each bucket of a `HashMap` |
75+
| `HashMapValueMask` | uint64 | Bitmask used when storing values in a `HashMap` |
76+
| `FeatureEHFunclets` | uint8 | 1 if EH funclets are enabled, 0 otherwise |
5177

5278
Contracts used:
5379
| Contract Name |
5480
| --- |
81+
| `PlatformMetadata` |
5582

5683
The bulk of the work is done by the `GetCodeBlockHandle` API that maps a code pointer to information about the containing jitted method.
5784

@@ -97,46 +124,93 @@ There are two `JitManager`s: the "EE JitManager" for jitted code and "R2R JitMan
97124
The EE JitManager `GetMethodInfo` implements the nibble map lookup, summarized below, followed by returning the `RealCodeHeader` data:
98125

99126
```csharp
100-
bool GetMethodInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out CodeBlock? info)
127+
bool GetMethodInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out CodeBlock? info)
128+
{
129+
TargetPointer start = FindMethodCode(rangeSection, jittedCodeAddress); // nibble map lookup
130+
if (start == TargetPointer.Null)
101131
{
102-
TargetPointer start = FindMethodCode(rangeSection, jittedCodeAddress); // nibble map lookup
103-
if (start == TargetPointer.Null)
104-
{
105-
return false;
106-
}
107-
TargetNUInt relativeOffset = jittedCodeAddress - start;
108-
int codeHeaderOffset = Target.PointerSize;
109-
TargetPointer codeHeaderIndirect = start - codeHeaderOffset;
110-
if (RangeSection.IsStubCodeBlock(Target, codeHeaderIndirect))
111-
{
112-
return false;
113-
}
114-
TargetPointer codeHeaderAddress = Target.ReadPointer(codeHeaderIndirect);
115-
Data.RealCodeHeader realCodeHeader = Target.ProcessedData.GetOrAdd<Data.RealCodeHeader>(codeHeaderAddress);
116-
info = new CodeBlock(jittedCodeAddress, codeHeaderOffset, relativeOffset, realCodeHeader, rangeSection.Data!.JitManager);
117-
return true;
132+
return false;
133+
}
134+
TargetNUInt relativeOffset = jittedCodeAddress - start;
135+
int codeHeaderOffset = Target.PointerSize;
136+
TargetPointer codeHeaderIndirect = start - codeHeaderOffset;
137+
if (RangeSection.IsStubCodeBlock(Target, codeHeaderIndirect))
138+
{
139+
return false;
140+
}
141+
TargetPointer codeHeaderAddress = Target.ReadPointer(codeHeaderIndirect);
142+
Data.RealCodeHeader realCodeHeader = Target.ProcessedData.GetOrAdd<Data.RealCodeHeader>(codeHeaderAddress);
143+
info = new CodeBlock(jittedCodeAddress, realCodeHeader.MethodDesc, relativeOffset, rangeSection.Data!.JitManager);
144+
return true;
145+
}
146+
```
147+
148+
The R2R JitManager `GetMethodInfo` finds the runtime function corresponding to an address and maps its entry point pack to a method:
149+
150+
```csharp
151+
bool GetMethodInfo(RangeSection rangeSection, TargetCodePointer jittedCodeAddress, [NotNullWhen(true)] out CodeBlock? info)
152+
{
153+
if (rangeSection.Data == null)
154+
throw new ArgumentException(nameof(rangeSection));
155+
156+
info = default;
157+
158+
TargetPointer r2rModule = Target.ReadPointer(/* range section address + RangeSection::R2RModule offset */);
159+
TargetPointer r2rInfo = Target.ReadPointer(r2rModule + /* Module::ReadyToRunInfo offset */);
160+
161+
// Check if address is in a thunk
162+
if (IsStubCodeBlockThunk(rangeSection.Data, r2rInfo, jittedCodeAddress))
163+
return false;
164+
165+
// Find the relative address that we are looking for
166+
TargetCodePointer code = /* code pointer from jittedCodeAddress using PlatformMetadata.GetCodePointerFlags */
167+
TargetPointer imageBase = Target.ReadPointer(/* range section address + RangeSection::RangeBegin offset */);
168+
TargetPointer relativeAddr = code - imageBase;
169+
170+
TargetPointer runtimeFunctions = Target.ReadPointer(r2rInfo + /* ReadyToRunInfo::RuntimeFunctions offset */);
171+
int index = // Iterate through runtimeFunctions and find index of function with relativeAddress
172+
if (index < 0)
173+
return false;
174+
175+
bool featureEHFunclets = Target.ReadGlobal<byte>(Constants.Globals.FeatureEHFunclets) != 0;
176+
if (featureEHFunclets)
177+
{
178+
// TODO: [cdac] Look up in hot/cold mapping lookup table and if the method is in the cold block,
179+
// get the index of the associated hot block.
118180
}
181+
182+
TargetPointer function = runtimeFunctions + (ulong)(index * /* size of RuntimeFunction */);
183+
184+
TargetPointer startAddress = imageBase + Target.Read<uint>(function + /* RuntimeFunction::BeginAddress offset */);
185+
TargetPointer entryPoint = /* code pointer from startAddress using PlatformMetadata.GetCodePointerFlags */
186+
187+
TargetPointer mapAddress = r2rInfo + /* ReadyToRunInfo::EntryPointToMethodDescMap offset */;
188+
TargetPointer methodDesc = /* look up entryPoint in HashMap at mapAddress */;
189+
190+
// TODO: [cdac] Handle method with cold code when computing relative offset
191+
TargetNUInt relativeOffset = new TargetNUInt(code - startAddress);
192+
193+
info = new CodeBlock(startAddress.Value, methodDesc, relativeOffset, rangeSection.Data!.JitManager);
194+
return true;
195+
}
119196
```
120197

121-
The `CodeBlock` encapsulates the `RealCodeHeader` data from the target runtime together with the start of the jitted method
198+
The `CodeBlock` encapsulates the `MethodDesc` data from the target runtime together with the start of the jitted method
122199

123200
```csharp
124201
class CodeBlock
125202
{
126203
private readonly int _codeHeaderOffset;
127204

128205
public TargetCodePointer StartAddress { get; }
129-
// note: this is the address of the pointer to the "real code header", you need to
130-
// dereference it to get the address of _codeHeaderData
131-
public TargetPointer CodeHeaderAddress => StartAddress - _codeHeaderOffset;
132-
private Data.RealCodeHeader _codeHeaderData;
206+
public TargetPointer MethodDesc { get; }
133207
public TargetPointer JitManagerAddress { get; }
134208
public TargetNUInt RelativeOffset { get; }
135-
public CodeBlock(TargetCodePointer startAddress, int codeHeaderOffset, TargetNUInt relativeOffset, Data.RealCodeHeader codeHeaderData, TargetPointer jitManagerAddress)
209+
210+
public CodeBlock(TargetCodePointer startAddress, TargetPointer methodDesc, TargetNUInt relativeOffset, TargetPointer jitManagerAddress)
136211
{
137-
_codeHeaderOffset = codeHeaderOffset;
138212
StartAddress = startAddress;
139-
_codeHeaderData = codeHeaderData;
213+
MethodDesc = methodDesc;
140214
RelativeOffset = relativeOffset;
141215
JitManagerAddress = jitManagerAddress;
142216
}
@@ -151,13 +225,13 @@ The remaining contract APIs extract fields of the `CodeBlock`:
151225
```csharp
152226
TargetPointer IExecutionManager.GetMethodDesc(CodeBlockHandle codeInfoHandle)
153227
{
154-
/* find EECodeBlock info for codeInfoHandle.Address*/
228+
/* find CodeBlock info for codeInfoHandle.Address*/
155229
return info.MethodDescAddress;
156230
}
157231

158232
TargetCodePointer IExecutionManager.GetStartAddress(CodeBlockHandle codeInfoHandle)
159233
{
160-
/* find EECodeBlock info for codeInfoHandle.Address*/
234+
/* find CodeBlock info for codeInfoHandle.Address*/
161235
return info.StartAddress;
162236
}
163237
```

src/coreclr/debug/runtimeinfo/datadescriptor.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ CDAC_TYPE_FIELD(Module, /*pointer*/, ThunkHeap, cdac_data<Module>::ThunkHeap)
227227
CDAC_TYPE_FIELD(Module, /*pointer*/, DynamicMetadata, cdac_data<Module>::DynamicMetadata)
228228
CDAC_TYPE_FIELD(Module, /*pointer*/, Path, cdac_data<Module>::Path)
229229
CDAC_TYPE_FIELD(Module, /*pointer*/, FileName, cdac_data<Module>::FileName)
230+
CDAC_TYPE_FIELD(Module, /*pointer*/, ReadyToRunInfo, cdac_data<Module>::ReadyToRunInfo)
230231

231232
CDAC_TYPE_FIELD(Module, /*pointer*/, FieldDefToDescMap, cdac_data<Module>::FieldDefToDescMap)
232233
CDAC_TYPE_FIELD(Module, /*pointer*/, ManifestModuleReferencesMap, cdac_data<Module>::ManifestModuleReferencesMap)
@@ -412,6 +413,37 @@ CDAC_TYPE_INDETERMINATE(FixupPrecodeData)
412413
CDAC_TYPE_FIELD(FixupPrecodeData, /*pointer*/, MethodDesc, offsetof(FixupPrecodeData, MethodDesc))
413414
CDAC_TYPE_END(FixupPrecodeData)
414415

416+
CDAC_TYPE_BEGIN(ReadyToRunInfo)
417+
CDAC_TYPE_INDETERMINATE(ReadyToRunInfo)
418+
CDAC_TYPE_FIELD(ReadyToRunInfo, /*pointer*/, CompositeInfo, cdac_data<ReadyToRunInfo>::CompositeInfo)
419+
CDAC_TYPE_FIELD(ReadyToRunInfo, /*uint32*/, NumRuntimeFunctions, cdac_data<ReadyToRunInfo>::NumRuntimeFunctions)
420+
CDAC_TYPE_FIELD(ReadyToRunInfo, /*pointer*/, RuntimeFunctions, cdac_data<ReadyToRunInfo>::RuntimeFunctions)
421+
CDAC_TYPE_FIELD(ReadyToRunInfo, /*pointer*/, DelayLoadMethodCallThunks, cdac_data<ReadyToRunInfo>::DelayLoadMethodCallThunks)
422+
CDAC_TYPE_FIELD(ReadyToRunInfo, /*HashMap*/, EntryPointToMethodDescMap, cdac_data<ReadyToRunInfo>::EntryPointToMethodDescMap)
423+
CDAC_TYPE_END(ReadyToRunInfo)
424+
425+
CDAC_TYPE_BEGIN(ImageDataDirectory)
426+
CDAC_TYPE_SIZE(sizeof(IMAGE_DATA_DIRECTORY))
427+
CDAC_TYPE_FIELD(ImageDataDirectory, /*uint32*/, VirtualAddress, offsetof(IMAGE_DATA_DIRECTORY, VirtualAddress))
428+
CDAC_TYPE_FIELD(ImageDataDirectory, /*uint32*/, Size, offsetof(IMAGE_DATA_DIRECTORY, Size))
429+
CDAC_TYPE_END(ImageDataDirectory)
430+
431+
CDAC_TYPE_BEGIN(RuntimeFunction)
432+
CDAC_TYPE_SIZE(sizeof(RUNTIME_FUNCTION))
433+
CDAC_TYPE_FIELD(RuntimeFunction, /*uint32*/, BeginAddress, offsetof(RUNTIME_FUNCTION, BeginAddress))
434+
CDAC_TYPE_END(RuntimeFunction)
435+
436+
CDAC_TYPE_BEGIN(HashMap)
437+
CDAC_TYPE_INDETERMINATE(HashMap)
438+
CDAC_TYPE_FIELD(HashMap, /*pointer*/, Buckets, cdac_data<HashMap>::Buckets)
439+
CDAC_TYPE_END(HashMap)
440+
441+
CDAC_TYPE_BEGIN(Bucket)
442+
CDAC_TYPE_SIZE(sizeof(Bucket))
443+
CDAC_TYPE_FIELD(Bucket, /*pointer*/, Keys, offsetof(Bucket, m_rgKeys))
444+
CDAC_TYPE_FIELD(Bucket, /*pointer*/, Values, offsetof(Bucket, m_rgValues))
445+
CDAC_TYPE_END(Bucket)
446+
415447
CDAC_TYPE_BEGIN(RangeSectionMap)
416448
CDAC_TYPE_INDETERMINATE(RangeSectionMap)
417449
CDAC_TYPE_FIELD(RangeSectionMap, /*pointer*/, TopLevelData, cdac_data<RangeSectionMap>::TopLevelData)
@@ -501,6 +533,8 @@ CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 1 | 1 << 1)
501533
#endif //TARGET_64BIT
502534
CDAC_GLOBAL(SOSBreakingChangeVersion, uint8, SOS_BREAKING_CHANGE_VERSION)
503535
CDAC_GLOBAL(DirectorySeparator, uint8, (uint8_t)DIRECTORY_SEPARATOR_CHAR_A)
536+
CDAC_GLOBAL(HashMapSlotsPerBucket, uint32, SLOTS_PER_BUCKET)
537+
CDAC_GLOBAL(HashMapValueMask, uint64, VALUE_MASK)
504538
CDAC_GLOBAL(MethodDescAlignment, uint64, MethodDesc::ALIGNMENT)
505539
CDAC_GLOBAL(ObjectHeaderSize, uint64, OBJHEADER_SIZE)
506540
CDAC_GLOBAL(SyncBlockValueToObjectOffset, uint16, OBJHEADER_SIZE - cdac_data<ObjHeader>::SyncBlockValue)

src/coreclr/vm/ceeload.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,7 @@ struct cdac_data<Module>
16491649
static constexpr size_t DynamicMetadata = offsetof(Module, m_pDynamicMetadata);
16501650
static constexpr size_t Path = offsetof(Module, m_path);
16511651
static constexpr size_t FileName = offsetof(Module, m_fileName);
1652+
static constexpr size_t ReadyToRunInfo = offsetof(Module, m_pReadyToRunInfo);
16521653

16531654
// Lookup map pointers
16541655
static constexpr size_t FieldDefToDescMap = offsetof(Module, m_FieldDefToDescMap);

src/coreclr/vm/codeman.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5888,8 +5888,6 @@ BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection,
58885888
// Save the raw entry
58895889
PTR_RUNTIME_FUNCTION RawFunctionEntry = pRuntimeFunctions + MethodIndex;
58905890

5891-
ULONG UMethodIndex = (ULONG)MethodIndex;
5892-
58935891
const int lookupIndex = HotColdMappingLookupTable::LookupMappingForMethod(pInfo, (ULONG)MethodIndex);
58945892
if ((lookupIndex != -1) && ((lookupIndex & 1) == 1))
58955893
{

src/coreclr/vm/codeman.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ Module Name:
2323
An IJitManager knows about which method bodies live in each RangeSection.
2424
It can handle methods of one given CodeType. It can map a method body to
2525
a MethodDesc. It knows where the GCInfo about the method lives.
26-
Today, we have three IJitManagers viz.
26+
Today, we have two IJitManagers:
2727
1. EEJitManager for JITcompiled code generated by clrjit.dll
28-
2. NativeImageJitManager for ngenned code.
29-
3. ReadyToRunJitManager for version resiliant ReadyToRun code
28+
2. ReadyToRunJitManager for version resiliant ReadyToRun code
3029
3130
An ICodeManager knows how to crack a specific format of GCInfo. There is
3231
a default format (handled by ExecutionManager::GetDefaultCodeManager())
@@ -73,7 +72,6 @@ class MethodDesc;
7372
class ICorJitCompiler;
7473
class IJitManager;
7574
class EEJitManager;
76-
class NativeImageJitManager;
7775
class ReadyToRunJitManager;
7876
class ExecutionManager;
7977
class Thread;
@@ -1657,7 +1655,6 @@ class HostCodeHeap;
16571655
typedef VPTR(class HostCodeHeap) PTR_HostCodeHeap;
16581656

16591657
typedef VPTR(class EEJitManager) PTR_EEJitManager;
1660-
typedef VPTR(class NativeImageJitManager) PTR_NativeImageJitManager;
16611658
typedef VPTR(class ReadyToRunJitManager) PTR_ReadyToRunJitManager;
16621659

16631660
struct JumpStubBlockHeader

src/coreclr/vm/hash.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ const DWORD g_rgPrimes[] = {
3434
};
3535
const SIZE_T g_rgNumPrimes = sizeof(g_rgPrimes) / sizeof(*g_rgPrimes);
3636

37-
const unsigned int SLOTS_PER_BUCKET = 4;
38-
3937
#ifndef DACCESS_COMPILE
4038

4139
void *PtrHashMap::operator new(size_t size, LoaderHeap *pHeap)

src/coreclr/vm/hash.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ typedef ULONG_PTR UPTR;
4646
class Bucket;
4747
class HashMap;
4848

49+
const unsigned int SLOTS_PER_BUCKET = 4;
50+
4951
//-------------------------------------------------------
5052
// class Bucket
5153
// used by hash table implementation
@@ -54,8 +56,8 @@ typedef DPTR(class Bucket) PTR_Bucket;
5456
class Bucket
5557
{
5658
public:
57-
UPTR m_rgKeys[4];
58-
UPTR m_rgValues[4];
59+
UPTR m_rgKeys[SLOTS_PER_BUCKET];
60+
UPTR m_rgValues[SLOTS_PER_BUCKET];
5961

6062
#define VALUE_MASK (sizeof(LPVOID) == 4 ? 0x7FFFFFFF : I64(0x7FFFFFFFFFFFFFFF))
6163

@@ -532,6 +534,14 @@ class HashMap
532534

533535
return m_cbInserts-m_cbDeletes;
534536
}
537+
538+
friend struct ::cdac_data<HashMap>;
539+
};
540+
541+
template<>
542+
struct cdac_data<HashMap>
543+
{
544+
static constexpr size_t Buckets = offsetof(HashMap, m_rgBuckets);
535545
};
536546

537547
//---------------------------------------------------------------------------------------

src/coreclr/vm/readytoruninfo.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class ReadyToRunCoreInfo
2828
PTR_PEImageLayout m_pLayout;
2929
PTR_READYTORUN_CORE_HEADER m_pCoreHeader;
3030
Volatile<bool> m_fForbidLoadILBodyFixups;
31-
31+
3232
public:
3333
ReadyToRunCoreInfo();
3434
ReadyToRunCoreInfo(PEImageLayout * pLayout, READYTORUN_CORE_HEADER * pCoreHeader);
@@ -123,7 +123,7 @@ class ReadyToRunInfo
123123
PTR_READYTORUN_IMPORT_SECTION m_pImportSections;
124124
DWORD m_nImportSections;
125125

126-
bool m_readyToRunCodeDisabled; // Is
126+
bool m_readyToRunCodeDisabled;
127127

128128
NativeFormat::NativeReader m_nativeReader;
129129
NativeFormat::NativeArray m_methodDefEntryPoints;
@@ -335,8 +335,20 @@ class ReadyToRunInfo
335335

336336
PTR_MethodDesc GetMethodDescForEntryPointInNativeImage(PCODE entryPoint);
337337
void SetMethodDescForEntryPointInNativeImage(PCODE entryPoint, PTR_MethodDesc methodDesc);
338-
338+
339339
PTR_ReadyToRunCoreInfo GetComponentInfo() { return dac_cast<PTR_ReadyToRunCoreInfo>(&m_component); }
340+
341+
friend struct ::cdac_data<ReadyToRunInfo>;
342+
};
343+
344+
template<>
345+
struct cdac_data<ReadyToRunInfo>
346+
{
347+
static constexpr size_t CompositeInfo = offsetof(ReadyToRunInfo, m_pCompositeInfo);
348+
static constexpr size_t NumRuntimeFunctions = offsetof(ReadyToRunInfo, m_nRuntimeFunctions);
349+
static constexpr size_t RuntimeFunctions = offsetof(ReadyToRunInfo, m_pRuntimeFunctions);
350+
static constexpr size_t DelayLoadMethodCallThunks = offsetof(ReadyToRunInfo, m_pSectionDelayLoadMethodCallThunks);
351+
static constexpr size_t EntryPointToMethodDescMap = offsetof(ReadyToRunInfo, m_entryPointToMethodDescMap);
340352
};
341353

342354
class DynamicHelpers

0 commit comments

Comments
 (0)