diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs index fb830859082c..b691227431fc 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features.Authentication; @@ -394,118 +395,122 @@ private void ExtraFeatureSet(Type key, object? value) TFeature? IFeatureCollection.Get() where TFeature : default { + // Using Unsafe.As for the cast due to https://github.com/dotnet/runtime/issues/49614 + // The type of TFeature is confirmed by the typeof() check and the As cast only accepts + // that type; however the Jit does not eliminate a regular cast in a shared generic. + TFeature? feature = default; if (typeof(TFeature) == typeof(IHttpRequestFeature)) { - feature = (TFeature?)_currentIHttpRequestFeature; + feature = Unsafe.As(ref _currentIHttpRequestFeature); } else if (typeof(TFeature) == typeof(IHttpRequestBodyDetectionFeature)) { - feature = (TFeature?)_currentIHttpRequestBodyDetectionFeature; + feature = Unsafe.As(ref _currentIHttpRequestBodyDetectionFeature); } else if (typeof(TFeature) == typeof(IHttpResponseFeature)) { - feature = (TFeature?)_currentIHttpResponseFeature; + feature = Unsafe.As(ref _currentIHttpResponseFeature); } else if (typeof(TFeature) == typeof(IHttpResponseBodyFeature)) { - feature = (TFeature?)_currentIHttpResponseBodyFeature; + feature = Unsafe.As(ref _currentIHttpResponseBodyFeature); } else if (typeof(TFeature) == typeof(IRequestBodyPipeFeature)) { - feature = (TFeature?)_currentIRequestBodyPipeFeature; + feature = Unsafe.As(ref _currentIRequestBodyPipeFeature); } else if (typeof(TFeature) == typeof(IHttpRequestIdentifierFeature)) { - feature = (TFeature?)_currentIHttpRequestIdentifierFeature; + feature = Unsafe.As(ref _currentIHttpRequestIdentifierFeature); } else if (typeof(TFeature) == typeof(IServiceProvidersFeature)) { - feature = (TFeature?)_currentIServiceProvidersFeature; + feature = Unsafe.As(ref _currentIServiceProvidersFeature); } else if (typeof(TFeature) == typeof(IHttpRequestLifetimeFeature)) { - feature = (TFeature?)_currentIHttpRequestLifetimeFeature; + feature = Unsafe.As(ref _currentIHttpRequestLifetimeFeature); } else if (typeof(TFeature) == typeof(IHttpConnectionFeature)) { - feature = (TFeature?)_currentIHttpConnectionFeature; + feature = Unsafe.As(ref _currentIHttpConnectionFeature); } else if (typeof(TFeature) == typeof(IRouteValuesFeature)) { - feature = (TFeature?)_currentIRouteValuesFeature; + feature = Unsafe.As(ref _currentIRouteValuesFeature); } else if (typeof(TFeature) == typeof(IEndpointFeature)) { - feature = (TFeature?)_currentIEndpointFeature; + feature = Unsafe.As(ref _currentIEndpointFeature); } else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature)) { - feature = (TFeature?)_currentIHttpAuthenticationFeature; + feature = Unsafe.As(ref _currentIHttpAuthenticationFeature); } else if (typeof(TFeature) == typeof(IHttpRequestTrailersFeature)) { - feature = (TFeature?)_currentIHttpRequestTrailersFeature; + feature = Unsafe.As(ref _currentIHttpRequestTrailersFeature); } else if (typeof(TFeature) == typeof(IQueryFeature)) { - feature = (TFeature?)_currentIQueryFeature; + feature = Unsafe.As(ref _currentIQueryFeature); } else if (typeof(TFeature) == typeof(IFormFeature)) { - feature = (TFeature?)_currentIFormFeature; + feature = Unsafe.As(ref _currentIFormFeature); } else if (typeof(TFeature) == typeof(IHttpUpgradeFeature)) { - feature = (TFeature?)_currentIHttpUpgradeFeature; + feature = Unsafe.As(ref _currentIHttpUpgradeFeature); } else if (typeof(TFeature) == typeof(IHttp2StreamIdFeature)) { - feature = (TFeature?)_currentIHttp2StreamIdFeature; + feature = Unsafe.As(ref _currentIHttp2StreamIdFeature); } else if (typeof(TFeature) == typeof(IHttpResponseTrailersFeature)) { - feature = (TFeature?)_currentIHttpResponseTrailersFeature; + feature = Unsafe.As(ref _currentIHttpResponseTrailersFeature); } else if (typeof(TFeature) == typeof(IResponseCookiesFeature)) { - feature = (TFeature?)_currentIResponseCookiesFeature; + feature = Unsafe.As(ref _currentIResponseCookiesFeature); } else if (typeof(TFeature) == typeof(IItemsFeature)) { - feature = (TFeature?)_currentIItemsFeature; + feature = Unsafe.As(ref _currentIItemsFeature); } else if (typeof(TFeature) == typeof(ITlsConnectionFeature)) { - feature = (TFeature?)_currentITlsConnectionFeature; + feature = Unsafe.As(ref _currentITlsConnectionFeature); } else if (typeof(TFeature) == typeof(IHttpWebSocketFeature)) { - feature = (TFeature?)_currentIHttpWebSocketFeature; + feature = Unsafe.As(ref _currentIHttpWebSocketFeature); } else if (typeof(TFeature) == typeof(ISessionFeature)) { - feature = (TFeature?)_currentISessionFeature; + feature = Unsafe.As(ref _currentISessionFeature); } else if (typeof(TFeature) == typeof(IHttpMaxRequestBodySizeFeature)) { - feature = (TFeature?)_currentIHttpMaxRequestBodySizeFeature; + feature = Unsafe.As(ref _currentIHttpMaxRequestBodySizeFeature); } else if (typeof(TFeature) == typeof(IHttpMinRequestBodyDataRateFeature)) { - feature = (TFeature?)_currentIHttpMinRequestBodyDataRateFeature; + feature = Unsafe.As(ref _currentIHttpMinRequestBodyDataRateFeature); } else if (typeof(TFeature) == typeof(IHttpMinResponseDataRateFeature)) { - feature = (TFeature?)_currentIHttpMinResponseDataRateFeature; + feature = Unsafe.As(ref _currentIHttpMinResponseDataRateFeature); } else if (typeof(TFeature) == typeof(IHttpBodyControlFeature)) { - feature = (TFeature?)_currentIHttpBodyControlFeature; + feature = Unsafe.As(ref _currentIHttpBodyControlFeature); } else if (typeof(TFeature) == typeof(IHttpResetFeature)) { - feature = (TFeature?)_currentIHttpResetFeature; + feature = Unsafe.As(ref _currentIHttpResetFeature); } else if (MaybeExtra != null) { diff --git a/src/Servers/Kestrel/shared/TransportConnection.Generated.cs b/src/Servers/Kestrel/shared/TransportConnection.Generated.cs index c53e20b5184b..c3e852715323 100644 --- a/src/Servers/Kestrel/shared/TransportConnection.Generated.cs +++ b/src/Servers/Kestrel/shared/TransportConnection.Generated.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Http.Features; @@ -164,26 +165,30 @@ private void ExtraFeatureSet(Type key, object? value) TFeature? IFeatureCollection.Get() where TFeature : default { + // Using Unsafe.As for the cast due to https://github.com/dotnet/runtime/issues/49614 + // The type of TFeature is confirmed by the typeof() check and the As cast only accepts + // that type; however the Jit does not eliminate a regular cast in a shared generic. + TFeature? feature = default; if (typeof(TFeature) == typeof(IConnectionIdFeature)) { - feature = (TFeature?)_currentIConnectionIdFeature; + feature = Unsafe.As(ref _currentIConnectionIdFeature); } else if (typeof(TFeature) == typeof(IConnectionTransportFeature)) { - feature = (TFeature?)_currentIConnectionTransportFeature; + feature = Unsafe.As(ref _currentIConnectionTransportFeature); } else if (typeof(TFeature) == typeof(IConnectionItemsFeature)) { - feature = (TFeature?)_currentIConnectionItemsFeature; + feature = Unsafe.As(ref _currentIConnectionItemsFeature); } else if (typeof(TFeature) == typeof(IMemoryPoolFeature)) { - feature = (TFeature?)_currentIMemoryPoolFeature; + feature = Unsafe.As(ref _currentIMemoryPoolFeature); } else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature)) { - feature = (TFeature?)_currentIConnectionLifetimeFeature; + feature = Unsafe.As(ref _currentIConnectionLifetimeFeature); } else if (MaybeExtra != null) { diff --git a/src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs b/src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs index 586ec1a0b5ea..da9c6e064252 100644 --- a/src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs +++ b/src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Http.Features; @@ -164,26 +165,30 @@ private void ExtraFeatureSet(Type key, object? value) TFeature? IFeatureCollection.Get() where TFeature : default { + // Using Unsafe.As for the cast due to https://github.com/dotnet/runtime/issues/49614 + // The type of TFeature is confirmed by the typeof() check and the As cast only accepts + // that type; however the Jit does not eliminate a regular cast in a shared generic. + TFeature? feature = default; if (typeof(TFeature) == typeof(IConnectionIdFeature)) { - feature = (TFeature?)_currentIConnectionIdFeature; + feature = Unsafe.As(ref _currentIConnectionIdFeature); } else if (typeof(TFeature) == typeof(IConnectionTransportFeature)) { - feature = (TFeature?)_currentIConnectionTransportFeature; + feature = Unsafe.As(ref _currentIConnectionTransportFeature); } else if (typeof(TFeature) == typeof(IConnectionItemsFeature)) { - feature = (TFeature?)_currentIConnectionItemsFeature; + feature = Unsafe.As(ref _currentIConnectionItemsFeature); } else if (typeof(TFeature) == typeof(IMemoryPoolFeature)) { - feature = (TFeature?)_currentIMemoryPoolFeature; + feature = Unsafe.As(ref _currentIMemoryPoolFeature); } else if (typeof(TFeature) == typeof(IConnectionLifetimeFeature)) { - feature = (TFeature?)_currentIConnectionLifetimeFeature; + feature = Unsafe.As(ref _currentIConnectionLifetimeFeature); } else if (MaybeExtra != null) { diff --git a/src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs b/src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs index a95ff2f769e2..918cf11e63b1 100644 --- a/src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs +++ b/src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs @@ -25,6 +25,7 @@ public static string GenerateFile(string namespaceName, string className, string using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; {extraUsings} #nullable enable @@ -144,10 +145,14 @@ private void ExtraFeatureSet(Type key, object? value) TFeature? IFeatureCollection.Get() where TFeature : default {{ + // Using Unsafe.As for the cast due to https://github.com/dotnet/runtime/issues/49614 + // The type of TFeature is confirmed by the typeof() check and the As cast only accepts + // that type; however the Jit does not eliminate a regular cast in a shared generic. + TFeature? feature = default;{Each(features, feature => $@" {(feature.Index != 0 ? "else " : "")}if (typeof(TFeature) == typeof({feature.Name})) {{ - feature = (TFeature?)_current{feature.Name}; + feature = Unsafe.As<{feature.Name}?, TFeature?>(ref _current{feature.Name}); }}")} else if (MaybeExtra != null) {{