-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Add GC support for external memory handles #133986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jkoritzinsky
wants to merge
21
commits into
dotnet:main
Choose a base branch
from
jkoritzinsky:external-roots
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,022
−320
Open
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
729548e
Add external memory handle concept
jkoritzinsky 2d88679
Add diagnostic support
jkoritzinsky 7858949
Move to separate contract to break contract cycles
jkoritzinsky 6567d36
Additional cleanup
jkoritzinsky 5b17d8e
Protect byref-like func-eval results
jkoritzinsky 7857802
Exclude byref-like return values from strong-handle creation
jkoritzinsky dda7b25
Remove Unordered flag from CrstExternalMemoryHandle
jkoritzinsky 47e9afc
Move ExternalMemoryHandle list to a process-wide static
jkoritzinsky 767e3ae
Use CrstStatic for ExternalMemoryHandle::s_crst
jkoritzinsky a04e25e
Remove comment on ExternalMemoryHandle static list
jkoritzinsky c86127a
Skip external memory handle scan during concurrent BGC mark
jkoritzinsky 6c084d9
Take s_crst during ExternalMemoryHandle::Cleanup
jkoritzinsky 0c0117f
Cleanup condition and make the comment reasonable.
jkoritzinsky ea46337
Remove early-return
jkoritzinsky 1c4f353
Move ExternalMemoryHandle init to EEStartupHelper; clean up includes
jkoritzinsky 1916159
Fix condition and extract helper to gcheaputilities.h
jkoritzinsky 3738cac
Fix byref scanning to not assume we're in the context of the last thr…
jkoritzinsky 043f8ae
Order external memory handle before output parameters
jkoritzinsky 1c29ca4
Share byreflike field scanning with CallingConvention contract and ad…
jkoritzinsky d73a900
Strengthen cDAC inline array stress coverage
jkoritzinsky 2525097
Update InlineArrayByRefLike description in README
jkoritzinsky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| # ExternalMemoryHandles contract | ||
|
|
||
| The ExternalMemoryHandles contract scans memory registered with the runtime as containing managed | ||
| references outside the GC heap and managed stacks. | ||
|
|
||
| ## APIs of contract | ||
|
|
||
| ``` csharp | ||
| sealed class ExternalMemoryHandleRootData | ||
| { | ||
| bool IsInteriorPointer { get; init; } | ||
| TargetPointer Address { get; init; } | ||
| TargetPointer Object { get; init; } | ||
| } | ||
| ``` | ||
|
|
||
| ``` csharp | ||
| IReadOnlyList<ExternalMemoryHandleRootData> GetRoots(bool resolveInteriorPointers); | ||
| ``` | ||
|
|
||
| ## Version 1 | ||
|
|
||
| <!-- BEGIN GENERATED: usage contract=ExternalMemoryHandles version=c1 --> | ||
| ### Data descriptors used | ||
|
|
||
| | Data Descriptor | Field | Type | Meaning | | ||
| | --- | --- | --- | --- | | ||
| | `Array` | `m_NumComponents` | `uint32` | Number of items in the array | | ||
| | `ExternalMemoryHandle` | `GCFlags` | `uint32` | Non-zero if the handle's memory holds a direct object pointer (interior/GC_CALL_INTERIOR root) rather than the address of an object reference slot | | ||
| | `ExternalMemoryHandle` | `Memory` | `pointer` | Pointer to the external memory tracked by this handle | | ||
| | `ExternalMemoryHandle` | `MethodTable` | `pointer` | Pointer to the MethodTable describing the type of the tracked memory | | ||
| | `ExternalMemoryHandle` | `Next` | `pointer` | Pointer to the next ExternalMemoryHandle in the process-wide list | | ||
| | `Object` | `m_pMethTab` | `pointer` | Method table for the object | | ||
| | `String` | `m_StringLength` | `uint32` | Length of the string in UTF-16 characters | | ||
|
|
||
| ### Global variables used | ||
|
|
||
| | Global | Type | Meaning | | ||
| | --- | --- | --- | | ||
| | `ExternalMemoryHandles` | `pointer` | Address of the global pointer to the head of the process-wide external memory handle list (read a TargetPointer from this address to obtain the head ExternalMemoryHandle, or null if the list is empty) | | ||
| | `ObjectToMethodTableUnmask` | `uint8` | Bits to clear when converting an object header value to a method table address | | ||
|
|
||
| ### Contracts used | ||
|
|
||
| | Contract Name | | ||
| | --- | | ||
| | `GC` | | ||
| | `RuntimeTypeSystem` | | ||
| <!-- END GENERATED: usage contract=ExternalMemoryHandles version=c1 --> | ||
|
|
||
| Each returned root identifies either an ordinary object-reference slot through `Address`, or an | ||
| interior root through `IsInteriorPointer` and `Object`. When `resolveInteriorPointers` is true, | ||
| `Object` is the containing managed object; null, invalid, or unresolvable interior pointers are | ||
| omitted. When it is false, `Object` is the raw pointer read from `Address`. | ||
|
|
||
| For reference-type handles, a zero `GCFlags` value produces an ordinary root at the handle's | ||
| `Memory` address and a non-zero value produces an interior root. For value-type handles, the | ||
| implementation reports ordinary object-reference fields described by the type's GCDesc and | ||
| recursively finds `ELEMENT_TYPE_BYREF` fields in byref-like value types, including every element of | ||
| an inline array. GCDesc offsets are adjusted from boxed-object layout to the unboxed external-memory | ||
| layout. | ||
|
|
||
| ``` csharp | ||
| IReadOnlyList<ExternalMemoryHandleRootData> IExternalMemoryHandles.GetRoots(bool resolveInteriorPointers) | ||
| { | ||
| TargetPointer headPointer = // read the ExternalMemoryHandles global | ||
| TargetPointer current = // read a pointer from headPointer | ||
|
|
||
| HashSet<TargetPointer> visited = []; | ||
| List<ExternalMemoryHandleRootData> roots = []; | ||
| while (current != TargetPointer.Null) | ||
| { | ||
| if (!visited.Add(current)) | ||
| throw new InvalidOperationException(); | ||
|
|
||
| ExternalMemoryHandle handle = // read ExternalMemoryHandle object starting at current | ||
| TypeHandle type = // get the RuntimeTypeSystem handle for handle.MethodTable | ||
| if (type.IsValueType) | ||
| { | ||
| // Add GCDesc object-reference slots and recursively discovered byref-like interior roots. | ||
| } | ||
| else if (handle.GCFlags != 0) | ||
| { | ||
| // Read the pointer from handle.Memory and optionally resolve it to its containing object. | ||
| } | ||
| else | ||
| { | ||
| roots.Add(new ExternalMemoryHandleRootData { Address = handle.Memory }); | ||
| } | ||
| current = handle.Next; | ||
| } | ||
| return roots; | ||
| } | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does this use
m_StringLength?