-
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
Transform indirect calls to direct ones in the importer #85197
Conversation
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsImports indirect calls as direct ones when the target method is known. Only handles addresses from ldftn as the VM has no way to verify pointers from static readonly fields and crashes on invalid ones. The helpers currently contain a small dead path that I'll soon use when extending the code to also handle delegates. Opening as a draft so that the code can be reviewed while I finish the tests. Fixes #44610
|
34909e2
to
34e4195
Compare
Some thoughts:
|
9ad26ef
to
bf44b09
Compare
Imports indirect calls as direct ones when the target method is known. Only handles addresses from ldftn as the VM has no way to verify pointers from static readonly fields and crashes on invalid ones. The helpers currently contain a small dead path that I'll soon use when extending the code to also handle delegates. Opening as a draft so that the code can be reviewed while I finish the tests. Fixes dotnet#44610
bf44b09
to
050ec5b
Compare
I'll be unable to respond to reviews for a few weeks, I've asked @thatbakamono to apply any feedback though. |
}; | ||
|
||
GenTree* valueNode = findValue(impStmtList); | ||
BasicBlock* bb = fgFirstBB; |
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'm still ambivalent about this non-local searching.
Seems like we could have cases where we are able to do this transformation in Tier0-instr but not in a subsequent OSR, because OSR doesn't have the same fgFirstBB
.
I suppose one fix is not to do this transformation in Tier0-instr (though removing the need to have a method probe is appealing)... but only if we can then always do the same in a subsequent rejit.
/*------------------------------------------------------------------------- | ||
* First create the call node | ||
*/ | ||
// run transformations when instrumenting to not pollute PGO data |
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'm not sure what you mean by this?
Are you saying if can optimize calli->call here when instrumenting we won't need a method probe? See my note above about whether this is an effective strategy given OSR.
GenTree* fptr = impStackTop().val; | ||
if (fptr->OperIs(GT_LCL_VAR)) | ||
{ | ||
JITDUMP("impImportCall trying to import calli as call - trying to substitute LCL_VAR\n"); |
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.
Would be nice to know in the dump which local var...
|
||
if (valueNode != nullptr && valueNode->OperIs(GT_LCL_VAR)) | ||
{ | ||
return impGetNodeFromLocal(valueNode); |
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.
Seems like this could get tripped up if there is a chain of local assignments where one of them is initialized later than it is used, eg
t0 = t1;
t1 = <fnptr>;
calli t0;
The chained search should start from where the previous search left off.
CORINFO_CLASS_HANDLE targetClass = info.compCompHnd->getMethodClass(replacementMethod); | ||
info.compCompHnd->getMethodSig(replacementMethod, &methodSig, targetClass); | ||
|
||
if (methodSig.hasImplicitThis() && targetThis == TYP_UNDEF) |
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.
Isn't targetThis
always TYP_UNDEF
at this point?
CORINFO_METHOD_HANDLE replacementMethod = nullptr; | ||
GenTree* newThis = nullptr; | ||
var_types oldThis = TYP_UNDEF; | ||
var_types targetThis = TYP_UNDEF; |
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 would rename these to be a bit more descriptive, eg oldThisTyp
.
Also move the declaration/definition down closer to where they're used.
} | ||
} | ||
|
||
if (valueNode != nullptr && valueNode->OperIs(GT_LCL_VAR)) |
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.
Add a jit dump here to track the progress of chaining back through other locals.
var_types sourceThis, | ||
var_types targetThis) | ||
{ | ||
assert(sourceSig->hasImplicitThis() || sourceThis == TYP_UNDEF); |
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.
Seems like sourceThis
is always TYP_UNDEF
and targetThis
is never TYP_VOID
?
I can't tell if you are trying to future-proof this method and have it handle cases it currently won't be asked to handle, or if this is a vestige of some earlier version.
Since there is currently just one caller perhaps scope this down to just the cases you'll actually see, and assert if anything else comes along?
// | ||
bool Compiler::impCanSubstituteSig(CORINFO_SIG_INFO* sourceSig, | ||
CORINFO_SIG_INFO* targetSig, | ||
var_types sourceThis, |
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.
As above, sourceThisTyp
and targetThisType
?
Would be good to settle on one pair of adjectives to describe the two options here: one of original/new, old/net, source/target.
@@ -1622,6 +1708,138 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN | |||
#endif // FEATURE_MULTIREG_RET | |||
} | |||
|
|||
//----------------------------------------------------------------------------------- | |||
// impCanSubstituteSig: Checks whether it's safe to replace a call with another one. |
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 wonder if we're better off implementing this entirely on the VM side of the interface; there's quite a bit of back and forth across the interface here, and the VM may already have something like this that you can just call (though maybe not for "jit sigs")... ?
Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it. |
@MichalPetryka plans to work on this soon. |
Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it. |
Imports indirect calls as direct ones when the target method is known.
Only handles addresses from ldftn as the VM has no way to verify pointers from static readonly fields and crashes on invalid ones.
The helpers currently contain a small dead path that I'll soon use when extending the code to also handle delegates.
Opening as a draft so that the code can be reviewed while I finish the tests.
Fixes #44610