-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[mini] publish global patches after JitInfo has been added #16589
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
Merged
Conversation
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
Fixes mono#14080 Consider the following example: ```csharp static void CommonCallTarget () { } static void TailA () { tailcall CommonCallTarget (); } static void TailB () { tailcall CommonCallTarget (); } ``` Since `TailA` and `TailB` are tailcalling into `CommonCallTarget`, the resolution at patch-time is a bit tricky, that is, since it's a jump-like instruction the patching machinery won't know where it was called from. That's why we maintain a global hashtable `jump_target_hash` where each jump-site is signed up to be patched. At patch-time we know the target method (in the example `CommonCallTarget`), but since we don't know where we are coming from, we will just apply all patches for that target. This works since ages, so why did it crash on arm64 sometimes? When the patching happens, we check if the displacement between jump-site and target fits into it (24bit). If not, which happens not very often, we have to allocate a _thunk_: https://github.com/mono/mono/blob/36296ce291f8a7b19de3eccb7a32c7e4ed9df8f2/mono/mini/mini-arm64.c#L928-L942 So instead of jumping to the target directly, we'll branch to the thunk. This is a little trampoline that loads the full address of the target and then finally branches to it. This one will live close-by the jump-site, because during compilation we will reserve specifically for that scenario some space after the generated code. For this, however, we need the JitInfo of the jump-site. And that's where the origin of the race is. Let's say: * Thread A compiles `TailA`, and then jumps into it. Thus one patch point is in the `jump_target_hash`. * Now Thread B compiles `TailB`, registers the patch point but has _not_ yet registered its JitInfo. * Then Thread A continues, does the tailcall into `CommonCallTarget`, enters the patching machinery, which sees two patches. Now assume when applying the patch for `TailB` the displacement is too large, thus it tries to allocate a thunk but can't find the relevant JitInfo for it that it needs to emit the thunk. So it crashes as reported in mono#14080 As far as I can tell this only affects ARM64, ARM and PPC.
vargaz
approved these changes
Aug 30, 2019
Contributor
Author
|
@monojenkins build failed |
Contributor
Author
|
@monojenkins squash |
Member
|
@monojenkins backport 2019-08 |
ManickaP
pushed a commit
to ManickaP/runtime
that referenced
this pull request
Jan 20, 2020
…#16589) [mini] publish global patches after JitInfo has been added Fixes mono/mono#14080 Consider the following example: ```csharp static void CommonCallTarget () { } static void TailA () { tailcall CommonCallTarget (); } static void TailB () { tailcall CommonCallTarget (); } ``` Since `TailA` and `TailB` are tailcalling into `CommonCallTarget`, the resolution at patch-time is a bit tricky, that is, since it's a jump-like instruction the patching machinery won't know where it was called from. That's why we maintain a global hashtable `jump_target_hash` where each jump-site is signed up to be patched. At patch-time we know the target method (in the example `CommonCallTarget`), but since we don't know where we are coming from, we will just apply all patches for that target. This works since ages, so why did it crash on arm64 sometimes? When the patching happens, we check if the displacement between jump-site and target fits into it (24bit). If not, which happens not very often, we have to allocate a _thunk_: https://github.com/mono/mono/blob/mono/mono@36296ce291f8a7b19de3eccb7a32c7e4ed9df8f2/mono/mini/mini-arm64.c#L928-L942 So instead of jumping to the target directly, we'll branch to the thunk. This is a little trampoline that loads the full address of the target and then finally branches to it. This one will live close-by the jump-site, because during compilation we will reserve specifically for that scenario some space after the generated code. For this, however, we need the JitInfo of the jump-site. And that's where the origin of the race is. Let's say: * Thread A compiles `TailA`, and then jumps into it. Thus one patch point is in the `jump_target_hash`. * Now Thread B compiles `TailB`, registers the patch point but has _not_ yet registered its JitInfo. * Then Thread A continues, does the tailcall into `CommonCallTarget`, enters the patching machinery, which sees two patches. Now assume when applying the patch for `TailB` the displacement is too large, thus it tries to allocate a thunk but can't find the relevant JitInfo for it that it needs to emit the thunk. So it crashes as reported in mono/mono#14080 As far as I can tell this only affects ARM64, ARM and PPC. <!-- Thank you for your Pull Request! If you are new to contributing to Mono, please try to do your best at conforming to our coding guidelines http://www.mono-project.com/community/contributing/coding-guidelines/ but don't worry if you get something wrong. One of the project members will help you to get things landed. Does your pull request fix any of the existing issues? Please use the following format: Fixes #issue-number --> Commit migrated from mono/mono@06e63b3
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Fixes #14080
Consider the following example:
Since
TailAandTailBare tailcalling intoCommonCallTarget, the resolution at patch-time is a bit tricky, that is, since it's a jump-like instruction the patching machinery won't know where it was called from. That's why we maintain a global hashtablejump_target_hashwhere each jump-site is signed up to be patched. At patch-time we know the target method (in the exampleCommonCallTarget), but since we don't know where we are coming from, we will just apply all patches for that target.This works since ages, so why did it crash on arm64 sometimes?
When the patching happens, we check if the displacement between jump-site and target fits into it (24bit). If not, which happens not very often, we have to allocate a thunk:
mono/mono/mini/mini-arm64.c
Lines 928 to 942 in 36296ce
So instead of jumping to the target directly, we'll branch to the thunk. This is a little trampoline that loads the full address of the target and then finally branches to it. This one will live close-by the jump-site, because during compilation we will reserve specifically for that scenario some space after the generated code. For this, however, we need the JitInfo of the jump-site. And that's where the origin of the race is. Let's say:
TailA, and then jumps into it. Thus one patch point is in thejump_target_hash.TailB, registers the patch point but has not yet registered its JitInfo.CommonCallTarget, enters the patching machinery, which sees two patches. Now assume when applying the patch forTailBthe displacement is too large, thus it tries to allocate a thunk but can't find the relevant JitInfo for it that it needs to emit the thunk. So it crashes as reported in condition 'ji' not met, with 'dynamic' and multithreading #14080As far as I can tell this only affects ARM64, ARM and PPC.