-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Faster null checks #21736
Faster null checks #21736
Conversation
| return false; | ||
| } | ||
|
|
||
| if (left is Type type1) |
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.
Should this rather call left.Equals(right) instead of this manual dispatch?
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.
Looks like Type is the only particularly special one where operator == is an external call and its .Equals test is a ReferenceEquals; so maybe have to manually dispatch for Type?
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.
operator== is external call on Type just so the JIT can recognize it as intrinsic. It is from the days when the method had to be FCall in order to be recognized as intrinsic.
It should be fine to just call Equals for Type as well.
src/System.Private.CoreLib/shared/System/Reflection/MethodBase.cs
Outdated
Show resolved
Hide resolved
|
Nice! Have you done anything to find these automatically - should we do the same cleanup in other repos too? |
I'd like to say I have... that would, sound good 😅 |
|
Going to go all in on this |
This construct does not look anything like a null check. |
|
cc @stephentoub Do you have an opinion about doing this globally and about the pattern to use for the "is not null" case? |
gfoidl
left a comment
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.
Not all changes are necessary, as the code gets less readable and the C# compiler emits the same code. See the two examples I've commented.
For the initial motivation with MethodInfo there is a difference, notably by casting to object and then performing the null-check instead of the (not inlined) method call.
| try | ||
| { | ||
| if (path == null) | ||
| if (path is null) |
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 here actually a difference as Roslyn generates the same code for both?
BTW: here I would use string.IsNullOrEmpty for this and the following check.
| _currentlyLoading.Add(key); // Push | ||
|
|
||
| if (ResourceManager == null) | ||
| if (ResourceManager is null) |
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 here actually a difference as Roslyn generates the same code for both?
Though I find this version more readable / nicer 😉.
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.
Can either pick consistency or ease of changing 4k+ call sites 😄
Early commits I was only picking a specific set of classes; doing it for the all == null and != null checks is either much slower or more broad brush (or would need time to write a tool)
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.
That's right 😉
!(obj is null) vs. obj != null the latter is more readable.
obj is null vs obj == null I find both very readable.
So it's hard to find a good balance between consistency and readability, as for MethodInfo and the like the is-variant has to be taken perf-wise -- or adapt the compiler(s) to emit efficient code for the null-comparison.
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.
Was a discussion (on twitter) about a less fugly is not null check for C#; most popular variants seemed to be x !is null and x is !null
Don't know if there is a formal C# proposal though
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.
VB's leading the way here by already having IsNot Nothing 😉
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.
Too many channels to follow 😃 Thanks for the link!
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.
formal proposal
It's there: dotnet/csharplang#27. Someone suggested aint operator as well. 😄
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 think this is the current proposal that would end up landing the 'not' pattern: dotnet/csharplang#1350
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.
For checking not null specifically, there's also the syntax that falls out from Property Patterns: if (foo is {}), though I will concede that it's not quite as readable as if (foo is not null), but the outcome is the exact same.
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.
if (foo is object) also works, but undid that in e4389b0 as it wasn't very clear
|
@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test |
|
@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test (Jit - TieredCompilation=0) |
If we're going to do it, we should do it everywhere / globally, across coreclr/corert/corefx, for both the is and is not cases. For is not, we should go with The other option would be to never use |
|
To improve the common use of right-sided null If we trim most of the class public static bool operator== (MyClass left, MyClass right)
=> (right is null) ? (left is null) : right.Equals(left);Then it drops under the |
So would the whole perf benefit of this change come from doing just this? |
Just checking |
|
just 2 cents - i'd rather see compiler improved to support this |
Works even better; every call evaporates even the non null tests #21765 |
| if (v == null) | ||
| if (!(value is MulticastDelegate v)) | ||
| return this; | ||
| if (v._invocationList as object[] == null) |
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.
Why is == null used here?
| if (argumentType is null) | ||
| throw new ArgumentNullException(nameof(argumentType)); | ||
|
|
||
| m_value = (value == null) ? null : CanonicalizeValue(value); |
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.
Should is be used here?
operator ==(MethodInfo left, MethodInfo right)was showing up in traces, ~40% of them from== nullchecksThis changes the null checks against (most)
MemberInfoderived classes in coreclr to be anis nullfast null check and related changes; rather than calling through to their operator overloads to test for null.Mostly effects class types that overload the
operator==andoperator!=as these methods are then used fornull.Pre
Post