Add a new GC handle and use it to simplify NativeAOT corelib #99512
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.
Problem
In the .NET runtime, particularly in its interop systems, it is common to attached some extra state
to an object. In CoreCLR, this data is often stored in the
SyncBlock
of an object. In NativeAOT, thisis often accomplished using a
ConditionalWeakTable
.A disadvantage of using
ConditionalWeakTable
compared to theSyncBlock
is the behavior aroundfinalization. The
SyncBlock
system hooks into the GC to detect when an object is collected and waits untilthat moment to schedule the deallocation of data associated with an object. When using a
ConditionalWeakTable
,the value in a table is queued for finalization as soon as the key is queued for finalization.
The NativeAOT corelib has to ensure that the key in the table has been fully collected and call
GC.ReRegisterForFinalize
to defer finialization if it has not. Failure to check for this conditionhas cause a couple of bugs in the past:
#86882
#99185
This PR's solution
With a small tweak, the dependant handle and the
ConditionalWeakTable
can make writing thesesorts of finalizers in the corelib easier. If the dependant handle always promotes its secondary
as long as the primary was a alive, the secondary object will not be put on the finalization queue
until the primary object has been fully collected. This PR implements a new type of GC handle with
this behavior called a "defer finalize dependant handle".
Use cases
This PR uses the handle in 4 places in the NativeAOT corelib:
an extra GC handle allocation per tracked object.
I've identified a couple places in CoreCLR where this handle could be used, but have not implemented
it in this PR:
Conceivably, functionality that currently is placed on the SyncBlock in CoreCLR could be moved to use
this new handle to manage the lifetime of data. This might allow for more sharing between CoreCLR
and NativeAOT. Longer term, the
SyncBlock
and its custom handle table could removed in favor of usingthis new GC handle.
Analysis
Here are some of the pros and cons I can think of. Please let me know if there are other considerations
or if there are any best practices to quantify the performance impact of a change like this.
Pros:
Cons:
TODO