-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Conversation
@dotnet-bot test Windows_NT x64 corefx_baseline Jit-diffs here are interesting (using checked to show off which generics got impacted, diffs are similar in release):
The huge decreases in the first method set comes about because the new interface method knows that |
👍 |
@omariom does this help? using System;
struct Wrap1<T> {}
struct Wrap2<T> {}
class C
{
static bool IsInt<T>()
{
return (typeof(T) == typeof(int));
}
static bool IsInt<T>(T t)
{
return (t.GetType() == typeof(int));
}
static bool IsString<T>()
{
return (typeof(T) == typeof(string));
}
static bool IsString<T>(T t)
{
return (t.GetType() == typeof(string));
}
static bool IsIntArray<T>()
{
return (typeof(T) == typeof(int[]));
}
static bool IsStringArray<T>()
{
return (typeof(T) == typeof(string[]));
}
static bool IsWrap1<T,U>()
{
return (typeof(U) == typeof(Wrap1<T>));
}
static bool IsWrap1<T,U>(U u)
{
return (u.GetType() == typeof(Wrap1<T>));
}
public static int Main()
{
// Fully optimized
bool c1 = IsInt<int>();
bool c2 = IsInt<string>();
bool c3 = IsString<int>();
// Partially optimized
bool c4 = IsString<string>();
// Not yet optimized (#14304)
bool d1 = IsInt<int>(3);
bool d2 = IsInt<string>("three");
bool d3 = IsString<int>(3);
bool d4 = IsString<string>("three");
// Partially optimized
// Note all these calls share one method body
bool e1 = IsIntArray<int[]>();
bool e2 = IsIntArray<string[]>();
bool e3 = IsStringArray<int[]>();
bool e4 = IsStringArray<string[]>();
// Fully optimized
bool f1 = IsWrap1<int, Wrap1<int>>();
bool f2 = IsWrap1<int, Wrap2<int>>();
// Not yet optimized (#14304)
bool f3 = IsWrap1<int, Wrap2<int>>(new Wrap2<int>());
bool f4 = IsWrap1<int, Wrap1<int>>(new Wrap1<int>());
bool pos = c1 & c4 & d1 & d4 & e1 & e4 & f1 & f4;
bool neg = c2 & c3 & d2 & d3 & e2 & e3 & f2 & f3;
return pos & !neg ? 100 : 0;
}
} |
OSX failure may be relevant, but looks odd, so will retry @dotnet-bot retest OSX10.12 x64 Checked Build and Test |
Hmm, can't trigger retest with edit. retrying my retry @dotnet-bot retest OSX10.12 x64 Checked Build and Test |
This is getting closer to being ready. Still need t work on SPMI and related changes and the desktop side updates. @jkotas could you look over the logic in the new jit interface method |
LGTM |
src/vm/jitinterface.cpp
Outdated
// be equal unless the type defs are the same | ||
if (hnd1.IsValueType() || hnd2.IsValueType()) | ||
{ | ||
if (!hnd1.AsMethodTable()->HasSameTypeDefAs(hnd2.AsMethodTable())) |
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.
There are "native value types" for which IsValueType() returns true, but they are not backed by MethodTable. You may want to check for !IsTypeDesc() before calling AsMethodTable() here.
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.
How about:
if ((hnd1.IsValueType() && !hnd1.IsNativeValueType())
|| (hnd2.IsValueType() && !hnd2.IsNativeValueType()))
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.
This can be still true if one of them is native value type -> AsMethodTable
won't work. It may be best to handle this by calling GetMethodTable
instead of AsMethodTable
. Something like:
if (hnd1.IsValueType() || hnd2.IsValueType())
{
if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
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.
So there are classes that aren't value types but are native value types? Interesting. Is there some simple way to create these kinds of classes?
Any extra complications on desktop? I need to implement at least part of this there...
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.
The situation that I was worried about does not actually need to involve native value types. For example: hnd1 is value type and hnd2 is array. if (hnd1.IsValueType() || hnd2.IsValueType())
will be true, and we would end up calling AsMethodTable on array TypeDesc.
So there are classes that aren't value types but are native value types?
All native value types are value types too.
src/vm/jitinterface.cpp
Outdated
TypeHandle canonHnd = TypeHandle(g_pCanonMethodTableClass); | ||
if ((hnd1 != canonHnd) && (hnd2 != canonHnd)) | ||
{ | ||
// Arrays... ? |
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.
This should work fine for arrays, I think.
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.
Thanks, removed the comment.
@briansull PTAL |
Note this changes the jit interface so will need desktop changes too. I will get working on those. |
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 Good
(with suggestions for better enum names)
{ | ||
MustNot = -1, // types are not equal | ||
May = 0, // types may be equal (must test at runtime) | ||
Must = 1, // type are equal |
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.
Another possibility here is:
Incongruent,
Unknown,
Congruent,
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.
In particular the usage of May
is confusing as it represents the lack of knowledge.
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 forgot to mention this when we were chatting offline: these names match the ones used a in similar .NetNative extension of the jit interface. So am going to keep them as is...
Arm legs look like they likely going to time out. Will retry them later. |
Work based on the plan outlined in #14305. Introduce a new unary node type GT_RUNTIMELOOKUP that wraps existing runtime lookup trees created in `impLookupToTree` and holds onto the handle that inspired the lookup. Note there are other importer paths that create lookups directly that we might also want to wrap, though wrapping is not a requirement for correctness. Keep this node type around through morph, then unwrap and just use the wrapped node after that.
The jit is now able to optimize some type equality checks in shared method instances where one or both of the types require runtime lookup, for instance comparing `T` to a value type, or comparing two different value types `V1<T>` and `V2<T>`. Add two new jit interface methods, one for testing for type equality and the other for type casting. These return Must/MustNot/Maybe results depending on whether or not the equality or cast can be resolved at jit time. Implement the equality check. Use this to enhance the type equality opts in the jit for both direct comparison and the checking done by unbox.any.
508b1bd
to
9fc2875
Compare
Latest update includes suggested fix for the type desc case. Also rebased and squashed down to two commits. |
Am going to retry the arm tests since the HW should be more or less idle now. @dotnet-bot retest Windows_NT arm Cross Checked Build and Test |
Am going to give up trying to get arm runs through; there's nothing arch-specific about this change. |
Handle some type equality cases we couldn't get previously, involving runtime lookups.
Not ready for merging just yet, but want to get some test exposure.