From 856328c3903994f73c9b433445e9b21a76154886 Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Tue, 9 Apr 2024 23:30:37 +0200 Subject: [PATCH 1/7] Drop generic type constraints from Unsafe.BitCast --- src/coreclr/jit/importercalls.cpp | 9 +- .../src/System/MemoryExtensions.cs | 320 +++++++++--------- .../CompilerServices/RuntimeHelpers.cs | 3 + .../System/Runtime/CompilerServices/Unsafe.cs | 7 +- .../src/System/SpanHelpers.Packed.cs | 2 +- .../src/System/SpanHelpers.T.cs | 52 +-- .../System.Runtime/ref/System.Runtime.cs | 2 +- .../UnsafeTests.cs | 12 + 8 files changed, 217 insertions(+), 190 deletions(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 7fba06f2b7b3c..82ba1f02ba260 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -4717,6 +4717,13 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, ClassLayout* toLayout = nullptr; var_types toType = TypeHandleToVarType(toTypeHnd, &toLayout); + if (fromType == TYP_REF || info.compCompHnd->getBoxHelper(fromTypeHnd) == CORINFO_HELP_BOX_NULLABLE || + toType == TYP_REF || info.compCompHnd->getBoxHelper(toTypeHnd) == CORINFO_HELP_BOX_NULLABLE) + { + // Fallback to the software implementation to throw when the types don't fit "where T : struct" + return nullptr; + } + unsigned fromSize = fromLayout != nullptr ? fromLayout->GetSize() : genTypeSize(fromType); unsigned toSize = toLayout != nullptr ? toLayout->GetSize() : genTypeSize(toType); @@ -4729,8 +4736,6 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, return nullptr; } - assert((fromType != TYP_REF) && (toType != TYP_REF)); - GenTree* op1 = impPopStack().val; op1 = impImplicitR4orR8Cast(op1, fromType); diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index 83ea307fc8570..50a0d5b19d5ac 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -323,28 +323,28 @@ public static unsafe bool Contains(this Span span, T value) where T : IEqu { return SpanHelpers.ContainsValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.ContainsValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(int)) { return SpanHelpers.ContainsValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(long)) { return SpanHelpers.ContainsValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } } @@ -367,28 +367,28 @@ public static unsafe bool Contains(this ReadOnlySpan span, T value) where { return SpanHelpers.ContainsValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.ContainsValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(int)) { return SpanHelpers.ContainsValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(long)) { return SpanHelpers.ContainsValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } } @@ -623,25 +623,25 @@ public static unsafe int IndexOf(this Span span, T value) where T : IEquat if (sizeof(T) == sizeof(byte)) return SpanHelpers.IndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); if (sizeof(T) == sizeof(short)) return SpanHelpers.IndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); if (sizeof(T) == sizeof(int)) return SpanHelpers.IndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); if (sizeof(T) == sizeof(long)) return SpanHelpers.IndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } @@ -690,28 +690,28 @@ public static unsafe int LastIndexOf(this Span span, T value) where T : IE { return SpanHelpers.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(int)) { return SpanHelpers.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(long)) { return SpanHelpers.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } } @@ -826,28 +826,28 @@ public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(int)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(long)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } } @@ -873,16 +873,16 @@ public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value0 { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } } @@ -909,18 +909,18 @@ public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value0 { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } } @@ -937,20 +937,20 @@ private static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), - Unsafe.As(ref value3), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + Unsafe.BitCast(value3), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), - Unsafe.As(ref value3), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + Unsafe.BitCast(value3), span.Length); } } @@ -1135,28 +1135,28 @@ public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T va { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(int)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(long)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } } @@ -1182,16 +1182,16 @@ public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T va { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } } @@ -1218,18 +1218,18 @@ public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T va { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } } @@ -1246,20 +1246,20 @@ private static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T v { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), - Unsafe.As(ref value3), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + Unsafe.BitCast(value3), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), - Unsafe.As(ref value3), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), + Unsafe.BitCast(value3), span.Length); } } @@ -1399,8 +1399,8 @@ public static int IndexOfAnyInRange(this ReadOnlySpan span, T lowInclusive { return SpanHelpers.IndexOfAnyInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1408,8 +1408,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.IndexOfAnyInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1417,8 +1417,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.IndexOfAnyInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1426,8 +1426,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.IndexOfAnyInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } } @@ -1465,8 +1465,8 @@ public static int IndexOfAnyExceptInRange(this ReadOnlySpan span, T lowInc { return SpanHelpers.IndexOfAnyExceptInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1474,8 +1474,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.IndexOfAnyExceptInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1483,8 +1483,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.IndexOfAnyExceptInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1492,8 +1492,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.IndexOfAnyExceptInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } } @@ -1531,8 +1531,8 @@ public static int LastIndexOfAnyInRange(this ReadOnlySpan span, T lowInclu { return SpanHelpers.LastIndexOfAnyInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1540,8 +1540,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.LastIndexOfAnyInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1549,8 +1549,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.LastIndexOfAnyInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1558,8 +1558,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.LastIndexOfAnyInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } } @@ -1597,8 +1597,8 @@ public static int LastIndexOfAnyExceptInRange(this ReadOnlySpan span, T lo { return SpanHelpers.LastIndexOfAnyExceptInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1606,8 +1606,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.LastIndexOfAnyExceptInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1615,8 +1615,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.LastIndexOfAnyExceptInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } @@ -1624,8 +1624,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), { return SpanHelpers.LastIndexOfAnyExceptInRangeUnsignedNumber( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref lowInclusive), - Unsafe.As(ref highInclusive), + Unsafe.BitCast(lowInclusive), + Unsafe.BitCast(highInclusive), span.Length); } } @@ -1702,25 +1702,25 @@ public static unsafe int IndexOf(this ReadOnlySpan span, T value) where T if (sizeof(T) == sizeof(byte)) return SpanHelpers.IndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); if (sizeof(T) == sizeof(short)) return SpanHelpers.IndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); if (sizeof(T) == sizeof(int)) return SpanHelpers.IndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); if (sizeof(T) == sizeof(long)) return SpanHelpers.IndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } @@ -1769,28 +1769,28 @@ public static unsafe int LastIndexOf(this ReadOnlySpan span, T value) wher { return SpanHelpers.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(int)) { return SpanHelpers.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (sizeof(T) == sizeof(long)) { return SpanHelpers.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } } @@ -1844,16 +1844,16 @@ public static unsafe int IndexOfAny(this Span span, T value0, T value1) wh { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } } @@ -1877,18 +1877,18 @@ public static unsafe int IndexOfAny(this Span span, T value0, T value1, T { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } } @@ -1938,16 +1938,16 @@ public static unsafe int IndexOfAny(this ReadOnlySpan span, T value0, T va { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } } @@ -1971,18 +1971,18 @@ public static unsafe int IndexOfAny(this ReadOnlySpan span, T value0, T va { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } } @@ -2150,16 +2150,16 @@ public static unsafe int LastIndexOfAny(this Span span, T value0, T value1 { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } } @@ -2183,18 +2183,18 @@ public static unsafe int LastIndexOfAny(this Span span, T value0, T value1 { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } } @@ -2235,16 +2235,16 @@ public static unsafe int LastIndexOfAny(this ReadOnlySpan span, T value0, { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), span.Length); } } @@ -2268,18 +2268,18 @@ public static unsafe int LastIndexOfAny(this ReadOnlySpan span, T value0, { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value0), - Unsafe.As(ref value1), - Unsafe.As(ref value2), + Unsafe.BitCast(value0), + Unsafe.BitCast(value1), + Unsafe.BitCast(value2), span.Length); } } @@ -3382,8 +3382,8 @@ public static unsafe void Replace(this Span span, T oldValue, T newValue) SpanHelpers.ReplaceValueType( ref src, ref src, - Unsafe.As(ref oldValue), - Unsafe.As(ref newValue), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), length); return; } @@ -3394,8 +3394,8 @@ public static unsafe void Replace(this Span span, T oldValue, T newValue) SpanHelpers.ReplaceValueType( ref src, ref src, - Unsafe.As(ref oldValue), - Unsafe.As(ref newValue), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), length); return; } @@ -3405,8 +3405,8 @@ public static unsafe void Replace(this Span span, T oldValue, T newValue) SpanHelpers.ReplaceValueType( ref src, ref src, - Unsafe.As(ref oldValue), - Unsafe.As(ref newValue), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), length); return; } @@ -3416,8 +3416,8 @@ public static unsafe void Replace(this Span span, T oldValue, T newValue) SpanHelpers.ReplaceValueType( ref src, ref src, - Unsafe.As(ref oldValue), - Unsafe.As(ref newValue), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), length); return; } @@ -3469,8 +3469,8 @@ public static unsafe void Replace(this ReadOnlySpan source, Span destin SpanHelpers.ReplaceValueType( ref Unsafe.As(ref src), ref Unsafe.As(ref dst), - Unsafe.As(ref oldValue), - Unsafe.As(ref newValue), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), length); return; } @@ -3480,8 +3480,8 @@ ref Unsafe.As(ref dst), SpanHelpers.ReplaceValueType( ref Unsafe.As(ref src), ref Unsafe.As(ref dst), - Unsafe.As(ref oldValue), - Unsafe.As(ref newValue), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), length); return; } @@ -3490,8 +3490,8 @@ ref Unsafe.As(ref dst), SpanHelpers.ReplaceValueType( ref Unsafe.As(ref src), ref Unsafe.As(ref dst), - Unsafe.As(ref oldValue), - Unsafe.As(ref newValue), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), length); return; } @@ -3500,8 +3500,8 @@ ref Unsafe.As(ref dst), SpanHelpers.ReplaceValueType( ref Unsafe.As(ref src), ref Unsafe.As(ref dst), - Unsafe.As(ref oldValue), - Unsafe.As(ref newValue), + Unsafe.BitCast(oldValue), + Unsafe.BitCast(newValue), length); return; } @@ -3976,28 +3976,28 @@ public static int Count(this ReadOnlySpan span, T value) where T : IEquata { return SpanHelpers.CountValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (Unsafe.SizeOf() == sizeof(short)) { return SpanHelpers.CountValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (Unsafe.SizeOf() == sizeof(int)) { return SpanHelpers.CountValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } else if (Unsafe.SizeOf() == sizeof(long)) { return SpanHelpers.CountValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), - Unsafe.As(ref value), + Unsafe.BitCast(value), span.Length); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index d33471813491a..63471d9f91967 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -129,6 +129,9 @@ internal static bool IsPrimitiveType(this CorElementType et) [Intrinsic] internal static bool IsKnownConstant(char t) => false; + + [Intrinsic] + internal static bool IsKnownConstant(T t) where T : struct => false; #pragma warning restore IDE0060 } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs index 901d354cfc7c8..e59b30fd7633f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -242,15 +242,14 @@ public static bool AreSame([AllowNull] ref readonly T left, [AllowNull] ref r /// /// Reinterprets the given value of type as a value of type . /// - /// The size of and are not the same. + /// The sizes of and are not the same + /// or the type parameters are not s. [Intrinsic] [NonVersionable] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TTo BitCast(TFrom source) - where TFrom : struct - where TTo : struct { - if (sizeof(TFrom) != sizeof(TTo)) + if (sizeof(TFrom) != sizeof(TTo) || default(TFrom) is null || default(TTo) is null) { ThrowHelper.ThrowNotSupportedException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs index 99232b3a7f7d7..70d4e22acb5c9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Packed.cs @@ -27,7 +27,7 @@ public static unsafe bool CanUsePackedIndexOf(T value) Debug.Assert(RuntimeHelpers.IsBitwiseEquatable()); Debug.Assert(sizeof(T) == sizeof(ushort)); - return *(ushort*)&value - 1u < 254u; + return Unsafe.BitCast(value) - 1u < 254u; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs index 0bf32e6274402..9ef07d114da67 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Runtime.Intrinsics; #pragma warning disable 8500 // sizeof of managed types @@ -225,7 +224,7 @@ public static int IndexOf(ref T searchSpace, int searchSpaceLength, ref T val } // Adapted from IndexOf(...) - public static unsafe bool Contains(ref T searchSpace, T value, int length) where T : IEquatable? + public static bool Contains(ref T searchSpace, T value, int length) where T : IEquatable? { Debug.Assert(length >= 0); @@ -297,7 +296,7 @@ public static unsafe bool Contains(ref T searchSpace, T value, int length) wh return true; } - public static unsafe int IndexOf(ref T searchSpace, T value, int length) where T : IEquatable? + public static int IndexOf(ref T searchSpace, T value, int length) where T : IEquatable? { Debug.Assert(length >= 0); @@ -1304,11 +1303,11 @@ public static int SequenceCompareTo(ref T first, int firstLength, ref T secon } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static unsafe bool ContainsValueType(ref T searchSpace, T value, int length) where T : struct, INumber + internal static bool ContainsValueType(ref T searchSpace, T value, int length) where T : struct, INumber { if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(T) == typeof(short) && PackedSpanHelpers.CanUsePackedIndexOf(value)) { - return PackedSpanHelpers.Contains(ref Unsafe.As(ref searchSpace), *(short*)&value, length); + return PackedSpanHelpers.Contains(ref Unsafe.As(ref searchSpace), Unsafe.BitCast(value), length); } return NonPackedContainsValueType(ref searchSpace, value, length); @@ -1478,15 +1477,15 @@ internal static int IndexOfAnyExceptValueType(ref T searchSpace, T value, int => IndexOfValueType>(ref searchSpace, value, length); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe int IndexOfValueType(ref TValue searchSpace, TValue value, int length) + private static int IndexOfValueType(ref TValue searchSpace, TValue value, int length) where TValue : struct, INumber where TNegator : struct, INegator { if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(TValue) == typeof(short) && PackedSpanHelpers.CanUsePackedIndexOf(value)) { return typeof(TNegator) == typeof(DontNegate) - ? PackedSpanHelpers.IndexOf(ref Unsafe.As(ref searchSpace), *(char*)&value, length) - : PackedSpanHelpers.IndexOfAnyExcept(ref Unsafe.As(ref searchSpace), *(char*)&value, length); + ? PackedSpanHelpers.IndexOf(ref Unsafe.As(ref searchSpace), Unsafe.BitCast(value), length) + : PackedSpanHelpers.IndexOfAnyExcept(ref Unsafe.As(ref searchSpace), Unsafe.BitCast(value), length); } return NonPackedIndexOfValueType(ref searchSpace, value, length); @@ -1665,24 +1664,33 @@ internal static int IndexOfAnyExceptValueType(ref T searchSpace, T value0, T => IndexOfAnyValueType>(ref searchSpace, value0, value1, length); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe int IndexOfAnyValueType(ref TValue searchSpace, TValue value0, TValue value1, int length) + private static int IndexOfAnyValueType(ref TValue searchSpace, TValue value0, TValue value1, int length) where TValue : struct, INumber where TNegator : struct, INegator { if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(TValue) == typeof(short) && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1)) { - if ((*(char*)&value0 ^ *(char*)&value1) == 0x20) + char char0 = Unsafe.BitCast(value0); + char char1 = Unsafe.BitCast(value1); + + if (RuntimeHelpers.IsKnownConstant(value0) && RuntimeHelpers.IsKnownConstant(value1)) { - char lowerCase = (char)Math.Max(*(char*)&value0, *(char*)&value1); + // If the values differ only in the 0x20 bit, we can optimize the search by reducing the number of comparisons. + // This optimization only applies to a small subset of values and the throughput difference is not too significant. + // We avoid introducing per-call overhead for non-constant values by guarding this optimization behind RuntimeHelpers.IsKnownConstant. + if ((char0 ^ char1) == 0x20) + { + char lowerCase = (char)Math.Max(char0, char1); - return typeof(TNegator) == typeof(DontNegate) - ? PackedSpanHelpers.IndexOfAnyIgnoreCase(ref Unsafe.As(ref searchSpace), lowerCase, length) - : PackedSpanHelpers.IndexOfAnyExceptIgnoreCase(ref Unsafe.As(ref searchSpace), lowerCase, length); + return typeof(TNegator) == typeof(DontNegate) + ? PackedSpanHelpers.IndexOfAnyIgnoreCase(ref Unsafe.As(ref searchSpace), lowerCase, length) + : PackedSpanHelpers.IndexOfAnyExceptIgnoreCase(ref Unsafe.As(ref searchSpace), lowerCase, length); + } } return typeof(TNegator) == typeof(DontNegate) - ? PackedSpanHelpers.IndexOfAny(ref Unsafe.As(ref searchSpace), *(char*)&value0, *(char*)&value1, length) - : PackedSpanHelpers.IndexOfAnyExcept(ref Unsafe.As(ref searchSpace), *(char*)&value0, *(char*)&value1, length); + ? PackedSpanHelpers.IndexOfAny(ref Unsafe.As(ref searchSpace), char0, char1, length) + : PackedSpanHelpers.IndexOfAnyExcept(ref Unsafe.As(ref searchSpace), char0, char1, length); } return NonPackedIndexOfAnyValueType(ref searchSpace, value0, value1, length); @@ -1882,15 +1890,15 @@ internal static int IndexOfAnyExceptValueType(ref T searchSpace, T value0, T => IndexOfAnyValueType>(ref searchSpace, value0, value1, value2, length); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe int IndexOfAnyValueType(ref TValue searchSpace, TValue value0, TValue value1, TValue value2, int length) + private static int IndexOfAnyValueType(ref TValue searchSpace, TValue value0, TValue value1, TValue value2, int length) where TValue : struct, INumber where TNegator : struct, INegator { if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(TValue) == typeof(short) && PackedSpanHelpers.CanUsePackedIndexOf(value0) && PackedSpanHelpers.CanUsePackedIndexOf(value1) && PackedSpanHelpers.CanUsePackedIndexOf(value2)) { return typeof(TNegator) == typeof(DontNegate) - ? PackedSpanHelpers.IndexOfAny(ref Unsafe.As(ref searchSpace), *(char*)&value0, *(char*)&value1, *(char*)&value2, length) - : PackedSpanHelpers.IndexOfAnyExcept(ref Unsafe.As(ref searchSpace), *(char*)&value0, *(char*)&value1, *(char*)&value2, length); + ? PackedSpanHelpers.IndexOfAny(ref Unsafe.As(ref searchSpace), Unsafe.BitCast(value0), Unsafe.BitCast(value1), Unsafe.BitCast(value2), length) + : PackedSpanHelpers.IndexOfAnyExcept(ref Unsafe.As(ref searchSpace), Unsafe.BitCast(value0), Unsafe.BitCast(value1), Unsafe.BitCast(value2), length); } return NonPackedIndexOfAnyValueType(ref searchSpace, value0, value1, value2, length); @@ -3466,15 +3474,15 @@ internal static int IndexOfAnyExceptInRangeUnsignedNumber(ref T searchSpace, IndexOfAnyInRangeUnsignedNumber>(ref searchSpace, lowInclusive, highInclusive, length); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe int IndexOfAnyInRangeUnsignedNumber(ref T searchSpace, T lowInclusive, T highInclusive, int length) + private static int IndexOfAnyInRangeUnsignedNumber(ref T searchSpace, T lowInclusive, T highInclusive, int length) where T : struct, IUnsignedNumber, IComparisonOperators where TNegator : struct, INegator { if (PackedSpanHelpers.PackedIndexOfIsSupported && typeof(T) == typeof(ushort) && PackedSpanHelpers.CanUsePackedIndexOf(lowInclusive) && PackedSpanHelpers.CanUsePackedIndexOf(highInclusive) && highInclusive >= lowInclusive) { ref char charSearchSpace = ref Unsafe.As(ref searchSpace); - char charLowInclusive = *(char*)&lowInclusive; - char charRange = (char)(*(char*)&highInclusive - charLowInclusive); + char charLowInclusive = Unsafe.BitCast(lowInclusive); + char charRange = (char)(Unsafe.BitCast(highInclusive) - charLowInclusive); return typeof(TNegator) == typeof(DontNegate) ? PackedSpanHelpers.IndexOfAnyInRange(ref charSearchSpace, charLowInclusive, charRange, length) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index e8ef65ea31444..678afaefb5fa9 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -13299,7 +13299,7 @@ public static partial class Unsafe [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("o")] public static T? As(object? o) where T : class? { throw null; } public static ref TTo As(ref TFrom source) { throw null; } - public static TTo BitCast(TFrom source) where TFrom : struct where TTo : struct { throw null; } + public static TTo BitCast(TFrom source) { throw null; } public static System.IntPtr ByteOffset([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T origin, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T target) { throw null; } [System.CLSCompliantAttribute(false)] public static void CopyBlock(ref byte destination, ref readonly byte source, uint byteCount) { } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs index 955bc189b4331..70d55cd6f6985 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.CompilerServices.Unsafe.Tests/UnsafeTests.cs @@ -1166,6 +1166,18 @@ public static unsafe void BitCast() Assert.Throws(() => Unsafe.BitCast(5)); Assert.Throws(() => Unsafe.BitCast(5)); + // Conversion to/from a class should fail + + Assert.Throws(() => Unsafe.BitCast(string.Empty)); + Assert.Throws(() => Unsafe.BitCast(42)); + Assert.Throws(() => Unsafe.BitCast(string.Empty)); + + // Conversion to/from nullable value types should fail + + Assert.Throws(() => Unsafe.BitCast(42)); + Assert.Throws(() => Unsafe.BitCast(42)); + Assert.Throws(() => Unsafe.BitCast(42)); + // Conversion between floating-point and same sized integral should succeed Assert.Equal(0x8000_0000u, Unsafe.BitCast(-0.0f)); From bb52b2505e0887a2631f8b1e716be40b9f496c6a Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Sun, 14 Apr 2024 21:37:16 +0200 Subject: [PATCH 2/7] Add isNullableType to JIT interface --- src/coreclr/inc/corinfo.h | 5 + src/coreclr/inc/icorjitinfoimpl_generated.h | 3 + src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 1 + .../jit/ICorJitInfo_wrapper_generated.hpp | 9 + src/coreclr/jit/importercalls.cpp | 6 +- .../tools/Common/JitInterface/CorInfoImpl.cs | 12 ++ .../JitInterface/CorInfoImpl_generated.cs | 204 ++++++++++-------- .../ThunkGenerator/ThunkInput.txt | 1 + .../aot/jitinterface/jitinterface_generated.h | 10 + .../icorjitinfo_generated.cpp | 7 + .../icorjitinfo_generated.cpp | 6 + src/coreclr/vm/jitinterface.cpp | 25 +++ 13 files changed, 197 insertions(+), 102 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 35f7d2f0bdf86..ff82759f6aab6 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2709,6 +2709,11 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE cls ) = 0; + // Returns whether a class handle represents a Nullable type, if that can be statically determined. + virtual TypeCompareState isNullableType( + CORINFO_CLASS_HANDLE cls + ) = 0; + // Returns TypeCompareState::Must if cls is known to be an enum. // For enums with known exact type returns the underlying // type in underlyingType when the provided pointer is diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 2348162d94854..98b47dced2beb 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -344,6 +344,9 @@ bool isMoreSpecificType( bool isExactType( CORINFO_CLASS_HANDLE cls) override; +TypeCompareState isNullableType( + CORINFO_CLASS_HANDLE cls) override; + TypeCompareState isEnum( CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 0e9f6e2940bcb..743abdaff86ae 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 3c216494-65f8-49e2-b69a-7f272193bcc6 */ - 0x3c216494, - 0x65f8, - 0x49e2, - {0xb6, 0x9a, 0x7f, 0x27, 0x21, 0x93, 0xbc, 0xc6} +constexpr GUID JITEEVersionIdentifier = { /* 8f046bcb-ca5f-4692-9277-898b71cb7938 */ + 0x8f046bcb, + 0xca5f, + 0x4692, + {0x92, 0x77, 0x89, 0x8b, 0x71, 0xcb, 0x79, 0x38} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 30c499518e007..2e2573a911993 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -85,6 +85,7 @@ DEF_CLR_API(compareTypesForCast) DEF_CLR_API(compareTypesForEquality) DEF_CLR_API(isMoreSpecificType) DEF_CLR_API(isExactType) +DEF_CLR_API(isNullableType) DEF_CLR_API(isEnum) DEF_CLR_API(getParentType) DEF_CLR_API(getChildType) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 77af720739ece..85db2ec5efffa 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -804,6 +804,15 @@ bool WrapICorJitInfo::isExactType( return temp; } +TypeCompareState WrapICorJitInfo::isNullableType( + CORINFO_CLASS_HANDLE cls) +{ + API_ENTER(isNullableType); + TypeCompareState temp = wrapHnd->isNullableType(cls); + API_LEAVE(isNullableType); + return temp; +} + TypeCompareState WrapICorJitInfo::isEnum( CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 82ba1f02ba260..ccc7be5a7b6fa 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -4717,10 +4717,10 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, ClassLayout* toLayout = nullptr; var_types toType = TypeHandleToVarType(toTypeHnd, &toLayout); - if (fromType == TYP_REF || info.compCompHnd->getBoxHelper(fromTypeHnd) == CORINFO_HELP_BOX_NULLABLE || - toType == TYP_REF || info.compCompHnd->getBoxHelper(toTypeHnd) == CORINFO_HELP_BOX_NULLABLE) + if (fromType == TYP_REF || info.compCompHnd->isNullableType(fromTypeHnd) != TypeCompareState::MustNot || + toType == TYP_REF || info.compCompHnd->isNullableType(toTypeHnd) != TypeCompareState::MustNot) { - // Fallback to the software implementation to throw when the types don't fit "where T : struct" + // Fallback to the software implementation to throw when the types fail a "default(T) is not null" check. return nullptr; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 9366e1aa65b6d..a75318e7bcd18 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2941,6 +2941,18 @@ private bool isExactType(CORINFO_CLASS_STRUCT_* cls) return _compilation.IsEffectivelySealed(type); } + private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) + { + TypeDesc type = HandleToObject(cls); + + if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) + { + return TypeCompareState.May; + } + + return type.IsNullable ? TypeCompareState.Must : TypeCompareState.MustNot; + } + private TypeCompareState isEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) { Debug.Assert(cls != null); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 09ea54f989fde..481c22864356c 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1210,6 +1210,21 @@ private static byte _isExactType(IntPtr thisHandle, IntPtr* ppException, CORINFO } } + [UnmanagedCallersOnly] + private static TypeCompareState _isNullableType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) + { + var _this = GetThis(thisHandle); + try + { + return _this.isNullableType(cls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static TypeCompareState _isEnum(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) { @@ -2579,7 +2594,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 174); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 175); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2662,99 +2677,100 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[78] = (delegate* unmanaged)&_compareTypesForEquality; callbacks[79] = (delegate* unmanaged)&_isMoreSpecificType; callbacks[80] = (delegate* unmanaged)&_isExactType; - callbacks[81] = (delegate* unmanaged)&_isEnum; - callbacks[82] = (delegate* unmanaged)&_getParentType; - callbacks[83] = (delegate* unmanaged)&_getChildType; - callbacks[84] = (delegate* unmanaged)&_isSDArray; - callbacks[85] = (delegate* unmanaged)&_getArrayRank; - callbacks[86] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[87] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[88] = (delegate* unmanaged)&_canAccessClass; - callbacks[89] = (delegate* unmanaged)&_printFieldName; - callbacks[90] = (delegate* unmanaged)&_getFieldClass; - callbacks[91] = (delegate* unmanaged)&_getFieldType; - callbacks[92] = (delegate* unmanaged)&_getFieldOffset; - callbacks[93] = (delegate* unmanaged)&_getFieldInfo; - callbacks[94] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[95] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - callbacks[96] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; - callbacks[97] = (delegate* unmanaged)&_isFieldStatic; - callbacks[98] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[99] = (delegate* unmanaged)&_getBoundaries; - callbacks[100] = (delegate* unmanaged)&_setBoundaries; - callbacks[101] = (delegate* unmanaged)&_getVars; - callbacks[102] = (delegate* unmanaged)&_setVars; - callbacks[103] = (delegate* unmanaged)&_reportRichMappings; - callbacks[104] = (delegate* unmanaged)&_reportMetadata; - callbacks[105] = (delegate* unmanaged)&_allocateArray; - callbacks[106] = (delegate* unmanaged)&_freeArray; - callbacks[107] = (delegate* unmanaged)&_getArgNext; - callbacks[108] = (delegate* unmanaged)&_getArgType; - callbacks[109] = (delegate* unmanaged)&_getExactClasses; - callbacks[110] = (delegate* unmanaged)&_getArgClass; - callbacks[111] = (delegate* unmanaged)&_getHFAType; - callbacks[112] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[113] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[114] = (delegate* unmanaged)&_getEEInfo; - callbacks[115] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[116] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[117] = (delegate* unmanaged)&_printMethodName; - callbacks[118] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[119] = (delegate* unmanaged)&_getMethodHash; - callbacks[120] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[121] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[122] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[123] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; - callbacks[124] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[125] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[126] = (delegate* unmanaged)&_getHelperFtn; - callbacks[127] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[128] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[129] = (delegate* unmanaged)&_getMethodSync; - callbacks[130] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[131] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[132] = (delegate* unmanaged)&_embedClassHandle; - callbacks[133] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[134] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[135] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[136] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[137] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[138] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[139] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[140] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[141] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[142] = (delegate* unmanaged)&_getCallInfo; - callbacks[143] = (delegate* unmanaged)&_getClassDomainID; - callbacks[144] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[145] = (delegate* unmanaged)&_getObjectContent; - callbacks[146] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[147] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[148] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[149] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[150] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[151] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[152] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[153] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[154] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[155] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[156] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[157] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[158] = (delegate* unmanaged)&_allocMem; - callbacks[159] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[160] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[161] = (delegate* unmanaged)&_allocGCInfo; - callbacks[162] = (delegate* unmanaged)&_setEHcount; - callbacks[163] = (delegate* unmanaged)&_setEHinfo; - callbacks[164] = (delegate* unmanaged)&_logMsg; - callbacks[165] = (delegate* unmanaged)&_doAssert; - callbacks[166] = (delegate* unmanaged)&_reportFatalError; - callbacks[167] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[168] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[169] = (delegate* unmanaged)&_recordCallSite; - callbacks[170] = (delegate* unmanaged)&_recordRelocation; - callbacks[171] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[172] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[173] = (delegate* unmanaged)&_getJitFlags; + callbacks[81] = (delegate* unmanaged)&_isNullableType; + callbacks[82] = (delegate* unmanaged)&_isEnum; + callbacks[83] = (delegate* unmanaged)&_getParentType; + callbacks[84] = (delegate* unmanaged)&_getChildType; + callbacks[85] = (delegate* unmanaged)&_isSDArray; + callbacks[86] = (delegate* unmanaged)&_getArrayRank; + callbacks[87] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[88] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[89] = (delegate* unmanaged)&_canAccessClass; + callbacks[90] = (delegate* unmanaged)&_printFieldName; + callbacks[91] = (delegate* unmanaged)&_getFieldClass; + callbacks[92] = (delegate* unmanaged)&_getFieldType; + callbacks[93] = (delegate* unmanaged)&_getFieldOffset; + callbacks[94] = (delegate* unmanaged)&_getFieldInfo; + callbacks[95] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[96] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[97] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; + callbacks[98] = (delegate* unmanaged)&_isFieldStatic; + callbacks[99] = (delegate* unmanaged)&_getArrayOrStringLength; + callbacks[100] = (delegate* unmanaged)&_getBoundaries; + callbacks[101] = (delegate* unmanaged)&_setBoundaries; + callbacks[102] = (delegate* unmanaged)&_getVars; + callbacks[103] = (delegate* unmanaged)&_setVars; + callbacks[104] = (delegate* unmanaged)&_reportRichMappings; + callbacks[105] = (delegate* unmanaged)&_reportMetadata; + callbacks[106] = (delegate* unmanaged)&_allocateArray; + callbacks[107] = (delegate* unmanaged)&_freeArray; + callbacks[108] = (delegate* unmanaged)&_getArgNext; + callbacks[109] = (delegate* unmanaged)&_getArgType; + callbacks[110] = (delegate* unmanaged)&_getExactClasses; + callbacks[111] = (delegate* unmanaged)&_getArgClass; + callbacks[112] = (delegate* unmanaged)&_getHFAType; + callbacks[113] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[114] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[115] = (delegate* unmanaged)&_getEEInfo; + callbacks[116] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[117] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[118] = (delegate* unmanaged)&_printMethodName; + callbacks[119] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[120] = (delegate* unmanaged)&_getMethodHash; + callbacks[121] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[122] = (delegate* unmanaged)&_getSwiftLowering; + callbacks[123] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[124] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; + callbacks[125] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[126] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[127] = (delegate* unmanaged)&_getHelperFtn; + callbacks[128] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[129] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[130] = (delegate* unmanaged)&_getMethodSync; + callbacks[131] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[132] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[133] = (delegate* unmanaged)&_embedClassHandle; + callbacks[134] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[135] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[136] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[137] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[138] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[139] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[140] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[141] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[142] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[143] = (delegate* unmanaged)&_getCallInfo; + callbacks[144] = (delegate* unmanaged)&_getClassDomainID; + callbacks[145] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[146] = (delegate* unmanaged)&_getObjectContent; + callbacks[147] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[148] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[149] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[150] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[151] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[152] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[153] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[154] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[155] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[156] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[157] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[158] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[159] = (delegate* unmanaged)&_allocMem; + callbacks[160] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[161] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[162] = (delegate* unmanaged)&_allocGCInfo; + callbacks[163] = (delegate* unmanaged)&_setEHcount; + callbacks[164] = (delegate* unmanaged)&_setEHinfo; + callbacks[165] = (delegate* unmanaged)&_logMsg; + callbacks[166] = (delegate* unmanaged)&_doAssert; + callbacks[167] = (delegate* unmanaged)&_reportFatalError; + callbacks[168] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[169] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[170] = (delegate* unmanaged)&_recordCallSite; + callbacks[171] = (delegate* unmanaged)&_recordRelocation; + callbacks[172] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[173] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[174] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 8d6ecabaa77c5..86674ab2b5924 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -244,6 +244,7 @@ FUNCTIONS TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) bool isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) bool isExactType(CORINFO_CLASS_HANDLE cls) + TypeCompareState isNullableType(CORINFO_CLASS_HANDLE cls) TypeCompareState isEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) CORINFO_CLASS_HANDLE getParentType(CORINFO_CLASS_HANDLE cls) CorInfoType getChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 754394f16ee9e..db1d0a721d1f1 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -92,6 +92,7 @@ struct JitInterfaceCallbacks TypeCompareState (* compareTypesForEquality)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); bool (* isMoreSpecificType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); bool (* isExactType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); + TypeCompareState (* isNullableType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); TypeCompareState (* isEnum)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType); CORINFO_CLASS_HANDLE (* getParentType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); CorInfoType (* getChildType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet); @@ -992,6 +993,15 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual TypeCompareState isNullableType( + CORINFO_CLASS_HANDLE cls) +{ + CorInfoExceptionClass* pException = nullptr; + TypeCompareState temp = _callbacks->isNullableType(_thisHandle, &pException, cls); + if (pException != nullptr) throw pException; + return temp; +} + virtual TypeCompareState isEnum( CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index ef1b277e80533..eebb80ab6b9df 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -659,6 +659,13 @@ bool interceptor_ICJI::isExactType( return original_ICorJitInfo->isExactType(cls); } +TypeCompareState interceptor_ICJI::isNullableType( + CORINFO_CLASS_HANDLE cls) +{ + mcs->AddCall("isNullableType"); + return original_ICorJitInfo->isNullableType(cls); +} + TypeCompareState interceptor_ICJI::isEnum( CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 55aef65127347..6a2ca48d87cd7 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -578,6 +578,12 @@ bool interceptor_ICJI::isExactType( return original_ICorJitInfo->isExactType(cls); } +TypeCompareState interceptor_ICJI::isNullableType( + CORINFO_CLASS_HANDLE cls) +{ + return original_ICorJitInfo->isNullableType(cls); +} + TypeCompareState interceptor_ICJI::isEnum( CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c8ac3350b2e91..1e7ffc1ca5708 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -4658,6 +4658,31 @@ bool CEEInfo::isExactType(CORINFO_CLASS_HANDLE cls) return result; } +// Returns whether a class handle represents a Nullable type, if that can be statically determined. +TypeCompareState CEEInfo::isNullableType(CORINFO_CLASS_HANDLE cls) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + TypeHandle typeHandle = TypeHandle(); + + TypeCompareState result = TypeCompareState::May; + + JIT_TO_EE_TRANSITION(); + + if (typeHandle != TypeHandle(g_pCanonMethodTableClass)) + { + TypeHandle VMClsHnd(cls); + result = Nullable::IsNullableType(VMClsHnd) ? TypeCompareState::Must : TypeCompareState::MustNot; + } + + EE_TO_JIT_TRANSITION(); + return result; +} + /*********************************************************************/ // Returns TypeCompareState::Must if cls is known to be an enum. // For enums with known exact type returns the underlying From 1210d9a169ff4f67ab483499b0c980478014cc5b Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Sun, 14 Apr 2024 22:12:20 +0200 Subject: [PATCH 3/7] superpmi --- .../tools/superpmi/superpmi-shared/lwmlist.h | 1 + .../superpmi-shared/methodcontext.cpp | 22 +++++++++++++++++++ .../superpmi/superpmi-shared/methodcontext.h | 5 +++++ .../superpmi-shim-collector/icorjitinfo.cpp | 9 ++++++++ .../tools/superpmi/superpmi/icorjitinfo.cpp | 7 ++++++ 5 files changed, 44 insertions(+) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index c3445291eeb93..75c1ac1b6f52a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -158,6 +158,7 @@ LWM(PrintMethodName, DWORDLONG, Agnostic_PrintResult) LWM(IsValueClass, DWORDLONG, DWORD) LWM(IsMoreSpecificType, DLDL, DWORD) LWM(IsExactType, DWORDLONG, DWORD) +LWM(IsNullableType, DWORDLONG, DWORD) LWM(IsEnum, DWORDLONG, DLD) LWM(PInvokeMarshalingRequired, MethodOrSigInfoValue, DWORD) LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, ResolveTokenValue) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 7b0ddc8ded5ae..05ad1c23a6a2c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -5920,6 +5920,28 @@ bool MethodContext::repIsExactType(CORINFO_CLASS_HANDLE cls) return value != 0; } +void MethodContext::recIsNullableType(CORINFO_CLASS_HANDLE cls, TypeCompareState result) +{ + if (IsNullableType == nullptr) + IsNullableType = new LightWeightMap(); + + DWORDLONG key = CastHandle(cls); + DWORD value = (DWORD)result; + IsNullableType->Add(key, value); + DEBUG_REC(dmpIsNullableType(key, value)); +} +void MethodContext::dmpIsNullableType(DWORDLONG key, DWORD value) +{ + printf("IsNullableType key cls-%016" PRIX64 ", value res-%d", key, value); +} +TypeCompareState MethodContext::repIsNullableType(CORINFO_CLASS_HANDLE cls) +{ + DWORDLONG key = CastHandle(cls); + DWORD value = LookupByKeyOrMiss(IsNullableType, key, ": key %016" PRIX64 "", key); + DEBUG_REP(dmpIsNullableType(key, value)); + return (TypeCompareState)value; +} + void MethodContext::recIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE underlyingType, TypeCompareState result) { if (IsEnum == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index cf9c235ae987e..a530d2f58385b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -723,6 +723,10 @@ class MethodContext void dmpIsExactType(DWORDLONG key, DWORD value); bool repIsExactType(CORINFO_CLASS_HANDLE cls); + void recIsNullableType(CORINFO_CLASS_HANDLE cls, TypeCompareState result); + void dmpIsNullableType(DWORDLONG key, DWORD value); + TypeCompareState repIsNullableType(CORINFO_CLASS_HANDLE cls); + void recIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE underlyingType, TypeCompareState result); void dmpIsEnum(DWORDLONG key, DLD value); TypeCompareState repIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType); @@ -1165,6 +1169,7 @@ enum mcPackets Packet_NotifyMethodInfoUsage = 214, Packet_IsExactType = 215, Packet_GetSwiftLowering = 216, + Packet_IsNullableType = 217, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index d53002a42914b..d39379089794f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -914,6 +914,15 @@ bool interceptor_ICJI::isExactType(CORINFO_CLASS_HANDLE cls) return temp; } +// Returns whether a class handle represents a Nullable type, if that can be statically determined. +TypeCompareState interceptor_ICJI::isNullableType(CORINFO_CLASS_HANDLE cls) +{ + mc->cr->AddCall("isNullableType"); + TypeCompareState temp = original_ICorJitInfo->isNullableType(cls); + mc->recIsNullableType(cls, temp); + return temp; +} + // Returns TypeCompareState::Must if cls is known to be an enum. // For enums with known exact type returns the underlying // type in underlyingType when the provided pointer is diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index f23c8e12f8661..08814336a74b1 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -764,6 +764,13 @@ bool MyICJI::isExactType(CORINFO_CLASS_HANDLE cls) return jitInstance->mc->repIsExactType(cls); } +// Returns true if a class handle represents a Nullable type. +TypeCompareState MyICJI::isNullableType(CORINFO_CLASS_HANDLE cls) +{ + jitInstance->mc->cr->AddCall("isNullableType"); + return jitInstance->mc->repIsNullableType(cls); +} + // Returns TypeCompareState::Must if cls is known to be an enum. // For enums with known exact type returns the underlying // type in underlyingType when the provided pointer is From fbdf4e9db892f465fd8e8b0ffe32166c8df4d5bb Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Sun, 14 Apr 2024 22:35:42 +0200 Subject: [PATCH 4/7] Comment formatting --- src/coreclr/jit/importercalls.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index ccc7be5a7b6fa..44dbfc0b73ace 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -4720,7 +4720,8 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic, if (fromType == TYP_REF || info.compCompHnd->isNullableType(fromTypeHnd) != TypeCompareState::MustNot || toType == TYP_REF || info.compCompHnd->isNullableType(toTypeHnd) != TypeCompareState::MustNot) { - // Fallback to the software implementation to throw when the types fail a "default(T) is not null" check. + // Fallback to the software implementation to throw when the types fail a "default(T) is not null" + // check. return nullptr; } From 77f47d77e92a26b23b61ab9143c581811199813d Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Mon, 15 Apr 2024 13:06:22 +0200 Subject: [PATCH 5/7] Check IsGenericParameter instead of Canon --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index a75318e7bcd18..f1f98c25df2c1 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2945,7 +2945,7 @@ private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) { TypeDesc type = HandleToObject(cls); - if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) + if (type.IsGenericParameter) { return TypeCompareState.May; } From 11159310c0be391a8e59ed0ee7d31669bee9a755 Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Mon, 15 Apr 2024 13:27:31 +0200 Subject: [PATCH 6/7] Replace IsGenericParameter check with assert --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index f1f98c25df2c1..e9c624bb1ada5 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2944,11 +2944,7 @@ private bool isExactType(CORINFO_CLASS_STRUCT_* cls) private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) { TypeDesc type = HandleToObject(cls); - - if (type.IsGenericParameter) - { - return TypeCompareState.May; - } + Debug.Assert(!type.IsGenericParameter); return type.IsNullable ? TypeCompareState.Must : TypeCompareState.MustNot; } From 443c23a5b185b15cff023ecf859776e34b0f37ef Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Mon, 15 Apr 2024 13:34:58 +0200 Subject: [PATCH 7/7] Just kidding, remove it completely :D --- src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index e9c624bb1ada5..0e4be3a344baf 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2944,7 +2944,6 @@ private bool isExactType(CORINFO_CLASS_STRUCT_* cls) private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) { TypeDesc type = HandleToObject(cls); - Debug.Assert(!type.IsGenericParameter); return type.IsNullable ? TypeCompareState.Must : TypeCompareState.MustNot; }