You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[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).
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.
32
32
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).
34
34
35
35
Data descriptors used:
36
36
| Data Descriptor Name | Field | Meaning |
37
37
| --- | --- | --- |
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 |
45
68
46
69
Global variables used:
47
70
| Global Name | Type | Purpose |
48
71
| --- | --- | --- |
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 |
51
77
52
78
Contracts used:
53
79
| Contract Name |
54
80
| --- |
81
+
|`PlatformMetadata`|
55
82
56
83
The bulk of the work is done by the `GetCodeBlockHandle` API that maps a code pointer to information about the containing jitted method.
57
84
@@ -97,46 +124,93 @@ There are two `JitManager`s: the "EE JitManager" for jitted code and "R2R JitMan
97
124
The EE JitManager `GetMethodInfo` implements the nibble map lookup, summarized below, followed by returning the `RealCodeHeader` data:
0 commit comments