Skip to content

Change the PerfMap crst into an UNSAFE_ANYMODE crst#129021

Open
davidwrighton wants to merge 5 commits into
dotnet:mainfrom
davidwrighton:PerfMapUNSAFE_ANYMODECrst
Open

Change the PerfMap crst into an UNSAFE_ANYMODE crst#129021
davidwrighton wants to merge 5 commits into
dotnet:mainfrom
davidwrighton:PerfMapUNSAFE_ANYMODECrst

Conversation

@davidwrighton
Copy link
Copy Markdown
Member

And make sure all logic run under the crst is safe for running in such a place

Also, add logic to handle some simple cases where moving to preemptive is fairly simple. Notably, the VirtualCallStub logic needed these fixes.

@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts CoreCLR’s perfmap logging synchronization to avoid GC-mode toggle deadlocks by switching the PerfMap lock to CRST_UNSAFE_ANYMODE, and updates VSD (virtual call stub) stub-generation paths to safely enter preemptive mode where needed when perfmap logging is enabled.

Changes:

  • Switch PerfMap’s s_csPerfMap to CRST_UNSAFE_ANYMODE to avoid deadlock cycles involving GC-mode toggles during lock acquisition.
  • Update VirtualCallStubManager stub-generation call sites to temporarily enter preemptive GC mode when perfmap logging is enabled, and reinitialize hash probers after mode transitions.
  • Add a non-FEATURE_PERFMAP stub PerfMap implementation in perfmap.h so call sites can compile without #ifdef FEATURE_PERFMAP wrappers.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/coreclr/vm/virtualcallstub.cpp Wrap specific stub-generation paths in GCX_MAYBE_PREEMP when perfmap is enabled, and reset probers after potential invalidation.
src/coreclr/vm/perfmap.h Add a stub PerfMap class for builds where FEATURE_PERFMAP is not defined.
src/coreclr/vm/perfmap.cpp Initialize the PerfMap lock as CRST_UNSAFE_ANYMODE and slightly reduce time holding the lock in LogPreCompiledMethod.

Comment thread src/coreclr/vm/perfmap.h
Comment on lines +27 to +34
static bool IsEnabled()
{
#ifdef DEBUG
return true;
#else
return false;
#endif
}
Comment thread src/coreclr/vm/perfmap.h
Comment thread src/coreclr/vm/virtualcallstub.cpp
Comment thread src/coreclr/vm/virtualcallstub.cpp
Comment thread src/coreclr/vm/perfmap.cpp Outdated
Comment thread src/coreclr/vm/perfmap.h
Comment thread src/coreclr/vm/virtualcallstub.cpp
Copilot AI review requested due to automatic review settings June 5, 2026 22:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread src/coreclr/vm/perfmap.cpp
Comment thread src/coreclr/vm/perfmap.cpp
name.Append(W("[PreJit-cold]"));
}

CrstHolder ch(&(s_csPerfMap));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this just optimization making the lock narrower or its functionally important that the if() above is no longer covered by the lock?

Comment thread src/coreclr/vm/perfmap.h
static bool IsEnabled()
{
#ifdef DEBUG
return true;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why true here? When FEATURE_PERFMAP isn't defined I wouldn't expect this to return true.

{
LookupHolder *pLookupHolder = GenerateLookupStub(addrOfResolver, token.To_SIZE_T());
LookupHolder *pLookupHolder;
bool reenteredCooperativeGCMode = PerfMap::IsEnabled();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm probably not understanding something. I thought the purpose of the ANYMODE Crst is so that we would not do a coop->preemp->coop transition but the code and naming here sounds like we will do those transitions?

LIMITED_METHOD_CONTRACT;
CONTRACTL
{
MODE_PREEMPTIVE;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
MODE_PREEMPTIVE;
THROWS;
MODE_PREEMPTIVE;

Match the dummy implementation

@@ -404,7 +422,7 @@
{
LIMITED_METHOD_CONTRACT;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
LIMITED_METHOD_CONTRACT;
CONTRACTL
{
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;

Comment on lines 311 to 312
LIMITED_METHOD_CONTRACT;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants