-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
JIT: handle interaction of OSR, PGO, and tail calls #62263
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -536,10 +536,10 @@ void Compiler::fgReplaceSwitchJumpTarget(BasicBlock* blockSwitch, BasicBlock* ne | |
// Notes: | ||
// 1. Only branches are changed: BBJ_ALWAYS, the non-fallthrough path of BBJ_COND, BBJ_SWITCH, etc. | ||
// We ignore other block types. | ||
// 2. Only the first target found is updated. If there are multiple ways for a block | ||
// to reach 'oldTarget' (e.g., multiple arms of a switch), only the first one found is changed. | ||
// 2. All branch targets found are updated. If there are multiple ways for a block | ||
// to reach 'oldTarget' (e.g., multiple arms of a switch), all of them are changed. | ||
// 3. The predecessor lists are not changed. | ||
// 4. The switch table "unique successor" cache is invalidated. | ||
// 4. If any switch table entry was updated, the switch table "unique successor" cache is invalidated. | ||
// | ||
// This function is most useful early, before the full predecessor lists have been computed. | ||
// | ||
|
@@ -569,20 +569,26 @@ void Compiler::fgReplaceJumpTarget(BasicBlock* block, BasicBlock* newTarget, Bas | |
break; | ||
|
||
case BBJ_SWITCH: | ||
unsigned jumpCnt; | ||
jumpCnt = block->bbJumpSwt->bbsCount; | ||
BasicBlock** jumpTab; | ||
jumpTab = block->bbJumpSwt->bbsDstTab; | ||
{ | ||
unsigned const jumpCnt = block->bbJumpSwt->bbsCount; | ||
BasicBlock** const jumpTab = block->bbJumpSwt->bbsDstTab; | ||
bool changed = false; | ||
|
||
for (unsigned i = 0; i < jumpCnt; i++) | ||
{ | ||
if (jumpTab[i] == oldTarget) | ||
{ | ||
jumpTab[i] = newTarget; | ||
break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAICT, this is safe and won't cause diffs. However, the header comment specifically says:
so that should be updated. One caller, fgNormalizeEHCase2() specifically expects the old behavior:
but it's ok, because subsequent calls will just do nothing. Unrelated, I also note the comment says:
Although we don't call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, let me update this documentation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added the invalidation and updated the comments. |
||
changed = true; | ||
} | ||
} | ||
|
||
if (changed) | ||
{ | ||
InvalidateUniqueSwitchSuccMap(); | ||
} | ||
break; | ||
} | ||
|
||
default: | ||
assert(!"Block doesn't have a valid bbJumpKind!!!!"); | ||
|
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.
I assume you meant
BB has successor
?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.
No -- it marks blocks that come after tail calls.
Maybe a picture will help? Here's a fragment of an OSR method flow graph before we add instrumentation. We want to count how often
R
is executed, but we can't put probes inR
because it is marked withBBF_TAILCALL_SUCCESSOR
-- it needs to remain empty since the tail call preds won't executeR
.Also pictured are some non-tail call blocks
A
andB
that conditionally share the return, and an OSR-unreachable blockZ
. And the blue edge is a fall-through edge.A
has degenerate flow, which is rare, but possible.To handle this we need to put copies of
R
's probes in the tail call blocks, and create an intermediary block that all the other preds flow through to get toR
. So we end up with 3 separate copies of R's pgo probe that collectively give us the right count forR
, andR
remains empty so the tail calls work as expected.We also take pains not to instrument
Z
, since there are debug checks that verify that un-imported blocks remain empty and can be removed. And we take pains not to double-countA
.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.
Oh, yeah it makes sense now for me, thanks for detailed response 🙂 not going to mark it as resolved to keep it.