-
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
Extra copy of struct before return #38743
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
I can't speak for the JIT team, but it's possible that writing directly into the return value's storage address could be an incorrect optimization. Consider: public class MyClass
{
public Guid MyGuid;
}
MyClass o = new MyClass();
o.MyGuid = SomeMethod();
Guid SomeMethod()
{
// do something
if (rnd()) { return g; }
else { throw new Exception(); }
} If any portion of SomeMethod has a side effect that may result in the method throwing an exception or otherwise not returning, then the write to MyClass.SomeGuid should never have taken place at all, as the write is performed by SomeMethod's caller, not by SomeMethod itself. (In practice the write is performed by SomeMethod's epilog, which is indistinguishable from the write having been performed by the caller after method return. So the observed behavior is consistent with expectations.) |
CC @CarolEidt @sandreenko PTAL |
There are at least a few factors at play here:
Perhaps @AndyAyersMS has additional thoughts. |
It could be allocated on stack before the method call like an optimization for stackalloc. |
The .NET analogs of C++'s RVO and NRVO are indeed useful -- but not something the jit is able to do at present. Reverse struct copy-prop (#8887) will eventually allow the jit to construct some structs directly into the hidden return buffer. However, as @GrabYourPitchforks notes, on the |
As discussed above, the cases we can do this would be very limited. The return buffer can also alias other arguments in the managed calling convention which makes this even harder. I don't think there is much we would be able to do because of that. Will close this. |
There are cases we would still be able to do this, even in the face of there being potential aliasing/overlap between the return buffer and arguments. Reverse copy prop would probably need to handle this in some form anyway, so let's reopen this. |
I can explain my perplexity about this issue. |
@iSazonov It's not just about what is possible but also about what is going to be realistic in the framework of the JIT. The fact that the return buffer is allowed to alias global memory puts the JIT on territory that it generally handles very conservatively today. More powerful alias analysis is quite costly and I don't know how much we could get away with there. In your original example it is very unlikely we would be able to do anything without making the JIT's alias analysis more powerful. There are two main reasons: 1) Unlike C++, If the expression does not involve global memory then it becomes easier; so those are the cases where I think we would more easily be able to do something, and why I reopened it. E.g. it may be common that you just have |
Thanks for the clarification! I don't ask for the impossible. The main things I noted is (1) that there is undesirable (invisible) copying (2) that there are examples where we can help the compiler make the code better. |
Some methods don't have any throws and are self contained (especially post inlining); could the Jit write directly to the output buffer in these cases? |
Related issue #12219 |
Description
Looking Guid.NewGuid() implementation I prepared a simple test on CSharpLab site
It seems the method does extra struct copy before return (
g
variable is defined on stack and could be returned as is).I do not know whether this is an omission in the existing optimization, or a new optimization сould be added.
category:cq
theme:structs
skill-level:intermediate
cost:medium
impact:small
The text was updated successfully, but these errors were encountered: