Comments (3)
Some more info:
Both SharpLab and ILSpy decompile Cmp2 and Cmp4 to something like this:
// renamed 'reference' to 'refT_a'
// renamed 'val' to 'valT_0'
public bool Cmp4 (T a, int i) {
ref T refT_a = ref a;
T valT_0 = default (T);
if (valT_0 == null) {
valT_0 = refT_a;
refT_a = ref valT_0;
}
return refT_a.Equals (A[i]);
}
Both SharpLab and ILSpy show the follwing IL code (ILSpy adds the C# code as comments before the corresponding IL code):
.method private hidebysig
instance bool CmpVal4 (
!T a,
uint32 i
) cil managed
{
// Method begins at RVA 0x2b48
// Header size: 12
// Code size: 60 (0x3c)
.maxstack 3
.locals init (
[0] !T,
[1] bool
)
// {
IL_0000: nop
// ref T reference = ref a;
IL_0001: ldarga.s a
// (no C# code)
IL_0003: ldloca.s 0
// T val = default(T);
IL_0005: initobj !T
// if (val == null)
IL_000b: ldloc.0
// (no C# code)
IL_000c: box !T
IL_0011: brtrue.s IL_001b
// val = reference;
IL_0013: ldobj !T
IL_0018: stloc.0
// reference = ref val;
IL_0019: ldloca.s 0
// return reference.Equals(Nodes[i].Value);
IL_001b: ldarg.0
IL_001c: ldfld !0[] class C`1<!T>::A
IL_0021: ldarg.2
IL_0022: ldelem !T
IL_0027: constrained. !T
IL_002d: callvirt instance bool class [System.Runtime]System.IEquatable`1<!T>::Equals(!0)
IL_0032: stloc.1
IL_0033: br.s IL_0035
IL_0035: ldloc.1
IL_0036: ret
} // end of method C`1::Cmp4
As far as I understand,
- a local variable 'valT_0' is generated
- 'valT_0' is cleared
- then 'valT_0' gets boxed, before it is compared to 'null'
I have no clue about the purpose of all that.
from roslyn.
Even more info:
When T is constrained to struct, all 4 Cmp funcs do not box.
When T is constrained to class, all 4 Cmp funcs do box.
So, when T is not constrained to struct or class,
- either boxing is missing in Cmp1/Cmp3 ?
- (x)or it is not needed in Cmp2/Cmp4 ?
At the time when the JITter compiles the IL code to assembler code, it will be known whether T is class or struct.
If T is struct:
public bool Cmp4 (T a, int i) {
ref T refT_a = ref a;
T valT_0 = default (T);
if (valT_0 == null) {
valT_0 = refT_a;
refT_a = ref valT_0;
}
return refT_a.Equals (A[i]);
}
From MS docs here :
Unbounded type parameters
Type parameters that have no constraints, [...] are called unbounded type parameters. [...]
You can compare them to null. If an unbounded parameter is compared to null, the comparison always returns false if the type argument is a value type.
In that case, 'valT_0 == null' is always false, and the then clause can be eliminated ..
public bool Cmp4 (T a, int i) {
ref T refT_a = ref a;
T valT_0 = default (T);
if (valT_0 == null) { }
return refT_a.Equals (A[i]);
}
.. which allows to eliminate the condition 'valT_0 == null' as well as the statement 'T valT_0 = default (T);' ..
public bool Cmp4 (T a, int i) {
ref T refT_a = ref a;
return refT_a.Equals (A[i]);
}
.. so the boxing is eliminated in the JITter ?
However, if T is class:
public bool Cmp4 (T a, int i) {
ref T refT_a = ref a;
T valT_0 = default (T);
if (valT_0 == null) {
valT_0 = refT_a;
refT_a = ref valT_0;
}
return refT_a.Equals (A[i]);
}
In that case, 'valT_0 == null' is always true, so the code can be reduced to ..
public bool Cmp4 (T a, int i) {
ref T refT_a = ref a;
T valT_0 = refT_a; // = 'T valT_0 = a;'
refT_a = ref valT_0;
return refT_a.Equals (A[i]);
}
.. which can be further reduced to ..
public bool Cmp4 (T a, int i) {
ref T refT_a = ref a;
return refT_a.Equals (A[i]);
}
.. so, again, the boxing is eliminated in the JITter ?
from roslyn.
When constrained as class, box !T
is actually an upcast, casting from T
to object
.
box
followed by br
is a well known pattern of the JIT:
https://github.com/dotnet/runtime/blob/84b33395057737db3ea342a5151feb6b90c1b6f6/src/coreclr/jit/importer.cpp#L2905-L2929
It will always be folded to true
if T
is not a nullable value type.
The compiler seems messed up when blending the gap between value type and reference type. I can't see any semantical difference of side effect of Cmp2
and Cmp3
.
When constrained to class
, the call is using with box !T
and unconstrained callvirt
. When constrained to struct
, the call is using constrained !T callvirt
without box
.
from roslyn.
Related Issues (20)
- Intellisense References not showing correctly when using a Primary-Constructor
- EnC: Report warning when Main method is updated
- [Automated] PRs inserted in VS build main-34914.66
- CallerInfo attributes are emitted to metadata even when they are ignored in source HOT 3
- CallerArgumentExpression attributes on partial method parameters look at the implemention rather than definition parameter names HOT 6
- Nullable attributes don't modify indexer parameter initial nullable state
- Colorization flickers when scrolling through a file
- Implicit conversion method prioritized over type declaration when using "Go to definition" on invalid constructor
- [Automated] PRs inserted in VS build main-34915.83
- [Question] Will there be a way to get XAML completions or diagnostics with Roslyn? HOT 2
- Record structs with InlineArray attribute compares only by the first value. HOT 6
- IDE1006 "Naming rule violation" is not triggered in all async cases
- Code that compiled using SDK 8.0.250 fails to compile when using SDK 8.0.300 with error CS0121 HOT 3
- All analyzers from assembly Microsoft.CodeAnalysis.CodeStyle.Fixes failed to load: Unable to load one or more of the requested types. Method not found: 'Boolean Microsoft.CodeAnalysis.IParameterSymbol.get_IsParamsArray()'. HOT 5
- Nullable decimal comparison bug in dotnet 8.0.5 (SDK 8.0.300) HOT 6
- ENC attributes are generated in different orders for different runtimes
- Obsoleted parameterless constructors can be used as generic arguments with no warnings HOT 1
- Interface implementation option not available for classes HOT 1
- Auto formatting C# code with list assignments does not indent correctly
- Expose Hot Reload functionality for third-party tools
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from roslyn.