Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Replace multi-loaderallocator hash implementation in MethodDescBackpatchInfo #22285

Merged

Conversation

davidwrighton
Copy link
Member

The multi-loaderallocator table for MethodDescs as used by MethodDescBackpatchInfo is both complex on shutdown (which is very difficult to test), somewhat memory inefficient, and not generalized for use for other similar needs. This change builds a new hashtable that utilizes the GC to handle lifetime, but is still useable from the portions of our codebase which need to use this data structure (and thus can't be written in managed code) See the comment in CrossLoaderAllocatorHash.h for details on how it works. It is expected that this will be used by this, by work adding support to the typesystem to track derived types, and by upcoming profiler api work (which has driven much of the complex size saving work, as it is expected that data structure will be large).

- Hashtable implementation for runtime use
- Implementation written in C++
- Data storage in managed heap memory
- Based on SHash design, but using managed memory

CrossLoaderAllocatorHash
- Hash for c++ Pointer to C++ pointer where the lifetimes are controlled by different loader allocators
 - Support for add/remove/visit all entries of 1 key/visit all entries/ remove all entries of 1 key
- Supports holding data which is unmanaged, but data items themselves can be of any size (key/value are templated types)
@davidwrighton
Copy link
Member Author

@davmason I've put this up for review as a WIP to get cross platform testing. I believe its functionally correct, but as its a complex mass of templates currently only tested on msvc, I expect to see new and interesting failures on clang. Let me know what you think of the available api surface, and if it will work for your scenario.

@davmason
Copy link
Member

@davidwrighton I plan to take a look later today

@davidwrighton
Copy link
Member Author

@janvorli I think I'd like you to take a look at this. This is a data structure that allows previously difficult cross loader allocator references to be kept.

@davmason davmason closed this Jan 31, 2019
@davmason davmason reopened this Jan 31, 2019
@davmason
Copy link
Member

Looks good from the API surface area point of view. I don't see any issues

- Adjust the Crst so that it can safely be used around code which allocates
- Required moving its use out from within the EESuspend logic used in reji
Copy link
Member

@janvorli janvorli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it looks good to me, my comments are mostly formal. I would also like to suggest to change the naming convention for members from _xxxx to m_xxxx for the sake of consistency with the rest of the runtime. That is the convention used in the whole runtime except for very few places.

@davidwrighton
Copy link
Member Author

@dotnet-bot test this please

- Use m_ instead of _
- Use m_gcHeapHash instead of _gcHeap to describe hashtable held in GC
memory
@davidwrighton davidwrighton changed the title [WIP] Replace multi-loaderallocator hash implementation in MethodDescBackpatchInfo Replace multi-loaderallocator hash implementation in MethodDescBackpatchInfo Feb 9, 2019
@davidwrighton
Copy link
Member Author

@davmason @kouvel Could you folks review this? Thanks

Copy link
Member

@kouvel kouvel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you haven't already, could you please check to make sure that vtable slots get backpatched as expected with tiering enabled, something like for the non-generic cases in https://github.com/dotnet/coreclr/blob/master/tests/src/baseservices/TieredCompilation/TieredVtableMethodTests.cs including the cross-loader-allocator ones?

@kouvel
Copy link
Member

kouvel commented Feb 13, 2019

From my understanding, the dependent handle in LAHashDependentHashTrackerObject causes the object to have the same lifetime as the LoaderAllocator without keeping the LoaderAllocator alive. So when the LoaderAllocator appears to be free, the dependent handle can also be invalidated.

If correct so far, from that point, does the finalizer of LAHashDependentHashTrackerObject need to run before the entry in the GCHeapHash appears to be deleted? And it looks like only after the dependent handle is noticed to be free (upon the next add or iterate), the value in the key/value store would be removed.

Wondering if there could be an issue where the LoaderAllocator is destroyed but memory from it is still referenced by the value in the key/value store. For example, for a backpatchable slot from a dispatch stub or a MethodTable from a dependent LoaderAllocator, is there a possibility that it would try to backpatch the slot after the LoaderAllocator or the VirtualCallStubManager is destroyed?

@davidwrighton
Copy link
Member Author

From my understanding, the dependent handle in LAHashDependentHashTrackerObject causes the object to have the same lifetime as the LoaderAllocator without keeping the LoaderAllocator alive. So when the LoaderAllocator appears to be free, the dependent handle can also be invalidated.
If correct so far, from that point, does the finalizer of LAHashDependentHashTrackerObject need to run before the entry in the GCHeapHash appears to be deleted? And it looks like only after the dependent handle is noticed to be free (upon the next add or iterate), the value in the key/value store would be removed.
Wondering if there could be an issue where the LoaderAllocator is destroyed but memory from it is still referenced by the value in the key/value store. For example, for a backpatchable slot from a dispatch stub or a MethodTable from a dependent LoaderAllocator, is there a possibility that it would try to backpatch the slot after the LoaderAllocator or the VirtualCallStubManager is destroyed?

No, this isn't an issue. The dependent handle loses its reference to the secondary when the secondary is actually unreachable (even from within a finalizer). The finalizer actually needs to be delayed until there cannot be an attempt to use the dependent handle to find an answer, hence the use of a GC handle with registered cleanup instead of a LoaderAllocator handle.

@@ -718,6 +719,8 @@ void TieredCompilationManager::ActivateCodeVersion(NativeCodeVersion nativeCodeV
// code version will activate then.
ILCodeVersion ilParent;
HRESULT hr = S_OK;
MethodDescBackpatchInfoTracker::ConditionalLockHolder lockHolder;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also pass in pMethod->MayHaveEntryPointSlotsToBackpatch() as a parameter

@kouvel
Copy link
Member

kouvel commented Feb 13, 2019

I see, makes sense

@davidwrighton
Copy link
Member Author

@dotnet-bot test Windows_NT x64 Checked CoreFX Tests

@davidwrighton
Copy link
Member Author

@dotnet-bot test Windows_NT x64 Checked Innerloop Build and Test

@davidwrighton davidwrighton merged commit 423d2a3 into dotnet:master Feb 15, 2019
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…tchInfo (dotnet/coreclr#22285)

* GCHeapHash
- Hashtable implementation for runtime use
- Implementation written in C++
- Data storage in managed heap memory
- Based on SHash design, but using managed memory

CrossLoaderAllocatorHash
- Hash for c++ Pointer to C++ pointer where the lifetimes are controlled by different loader allocators
 - Support for add/remove/visit all entries of 1 key/visit all entries/ remove all entries of 1 key
- Supports holding data which is unmanaged, but data items themselves can be of any size (key/value are templated types)

* Swap MethodDescBackpatchInfo to use the CrossLoaderAllocatorHash

* The MethodDescBackpatchCrst needs to be around an allocation
- Adjust the Crst so that it can safely be used around code which allocates
- Required moving its use out from within the EESuspend logic used in rejit


Commit migrated from dotnet/coreclr@423d2a3
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants