-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Avoid unnecessary allocations of jump stubs #116944
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
Conversation
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.
Pull Request Overview
This PR adds checks to prevent additional jump stub allocations once an overflow condition is detected, deferring to a full retry instead of creating more stubs.
- Introduces
m_fJumpStubOverflow
guard in the Rel32 path to forcedelta = 0
- Adds a similar overflow check in the Rel28 stub allocation path, declaring
jumpStubAddr
and conditionally skipping stub creation
Comments suppressed due to low confidence (1)
src/coreclr/vm/jitinterface.cpp:11788
- The new overflow path for Rel28 stub allocation isn't covered by existing tests. Consider adding a unit or integration test that sets
m_fJumpStubOverflow
and verifies no additional jump stubs are allocated.
TADDR jumpStubAddr;
false); | ||
TADDR jumpStubAddr; | ||
|
||
if (m_fJumpStubOverflow) |
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.
In the Rel28 stub allocation path, the branch for m_fJumpStubOverflow
sets jumpStubAddr = 0
but does not reset delta
. This could lead to an invalid relocation calculation using jumpStubAddr = 0
. Consider assigning delta = 0
here or skipping the rest of the relocation logic to match the behavior in the Rel32 branch.
Copilot uses AI. Check for mistakes.
// Do not attempt to allocate more jump stubs. We are going to throw away the code and retry anyway. | ||
delta = 0; |
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.
Is my understanding of what happens in the test correct?
- We have a first JIT attempt that sets
m_fAllowRel32 = false
- The second JIT attempt fails to allocate a jump stub and sets
m_fJumpStubOverflow = false
- The third try allocates a new code heap without any address range constraints and puts everything in there
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.
Or is 1 and 2 happening during the same attempt? And the slowness of the compilation was because of needing to find 284k jump stubs, which all go into the ReserveWithinRange
path that can be quite slow?
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.
It is 3 step process in the worst-case scenario on x64 like what's exercised by this test. It is 2 step process on arm64 (there is no allowRel32 on arm64.)
It may be possible to make it 2 step process in the worst case on x64 as well if the JIT passed more reloc details to the EE. I do not think we care enough about the extremely large methods like this one to make it better.
The second JIT attempt fails to allocate a jump stub and sets m_fJumpStubOverflow = false
Right.
The third try allocates a new code heap without any address range constraints and puts everything in there
The third allocates a code heap with enough spare space for jump stubs that we may need. Jump stubs are allocated in the same code heap as regular code and we always try to find space for jump stubs in the existing code heaps first.
Fixes #116748