From e24179e775a2666dd4b7e0154f95305308c6a400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Fri, 19 Jan 2024 09:35:16 +0100 Subject: [PATCH 01/33] [release/8.0-staging] [browser] Use whole assembly name when looking for already loaded assemblies (#97144) --- .../Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs | 4 ++++ .../TestAppScenarios/LazyLoadingTests.cs | 2 +- src/mono/wasm/runtime/lazyLoading.ts | 2 +- src/mono/wasm/runtime/loader/assets.ts | 2 +- .../WasmBasicTestApp/{ => App}/AppSettingsTest.cs | 0 .../WasmBasicTestApp/{ => App}/Common/Program.cs | 0 .../WasmBasicTestApp/{ => App}/Common/TestOutput.cs | 0 .../WasmBasicTestApp/{ => App}/LazyLoadingTest.cs | 3 +-- .../{ => App}/LibraryInitializerTest.cs | 0 .../{ => App}/Properties/AssemblyInfo.cs | 0 .../{ => App}/SatelliteAssembliesTest.cs | 0 .../{ => App}/WasmBasicTestApp.csproj | 6 +++++- .../{ => App}/runtimeconfig.template.json | 0 .../WasmBasicTestApp/{ => App}/words.es-ES.resx | 0 .../testassets/WasmBasicTestApp/{ => App}/words.resx | 0 .../{ => App}/wwwroot/WasmBasicTestApp.lib.module.js | 0 .../{ => App}/wwwroot/appsettings.Development.json | 0 .../{ => App}/wwwroot/appsettings.Production.json | 0 .../{ => App}/wwwroot/appsettings.json | 0 .../WasmBasicTestApp/{ => App}/wwwroot/index.html | 0 .../WasmBasicTestApp/{ => App}/wwwroot/main.js | 2 +- .../wasm/testassets/WasmBasicTestApp/Library/Json.cs | 11 +++++++++++ .../testassets/WasmBasicTestApp/Library/Json.csproj | 8 ++++++++ 23 files changed, 33 insertions(+), 7 deletions(-) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/AppSettingsTest.cs (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/Common/Program.cs (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/Common/TestOutput.cs (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/LazyLoadingTest.cs (91%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/LibraryInitializerTest.cs (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/Properties/AssemblyInfo.cs (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/SatelliteAssembliesTest.cs (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/WasmBasicTestApp.csproj (70%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/runtimeconfig.template.json (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/words.es-ES.resx (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/words.resx (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/wwwroot/WasmBasicTestApp.lib.module.js (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/wwwroot/appsettings.Development.json (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/wwwroot/appsettings.Production.json (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/wwwroot/appsettings.json (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/wwwroot/index.html (100%) rename src/mono/wasm/testassets/WasmBasicTestApp/{ => App}/wwwroot/main.js (97%) create mode 100644 src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.cs create mode 100644 src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.csproj diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs index 444d70228b08fa..dc6fb9b490e7f3 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs @@ -30,6 +30,10 @@ protected void CopyTestAsset(string assetName, string generatedProjectNamePrefix LogPath = Path.Combine(s_buildEnv.LogRootPath, Id); Utils.DirectoryCopy(Path.Combine(BuildEnvironment.TestAssetsPath, assetName), Path.Combine(_projectDir!)); + + // WasmBasicTestApp consists of App + Library projects + if (assetName == "WasmBasicTestApp") + _projectDir = Path.Combine(_projectDir!, "App"); } protected void BuildProject(string configuration) diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs index d2219e9f9e50da..8f37a47e18860a 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs @@ -42,6 +42,6 @@ public async Task FailOnMissingLazyAssembly() BrowserQueryString: new Dictionary { ["loadRequiredAssembly"] = "false" }, ExpectedExitCode: 1 )); - Assert.True(result.ConsoleOutput.Any(m => m.Contains("Could not load file or assembly") && m.Contains("System.Text.Json")), "The lazy loading test didn't emit expected error message"); + Assert.True(result.ConsoleOutput.Any(m => m.Contains("Could not load file or assembly") && m.Contains("Json")), "The lazy loading test didn't emit expected error message"); } } diff --git a/src/mono/wasm/runtime/lazyLoading.ts b/src/mono/wasm/runtime/lazyLoading.ts index 59c153a9d62365..55bcfd67101e8c 100644 --- a/src/mono/wasm/runtime/lazyLoading.ts +++ b/src/mono/wasm/runtime/lazyLoading.ts @@ -21,7 +21,7 @@ export async function loadLazyAssembly(assemblyNameToLoad: string): Promise f.includes(assemblyNameToLoad))) { + if (loaderHelpers.loadedAssemblies.includes(assemblyNameToLoad)) { return false; } diff --git a/src/mono/wasm/runtime/loader/assets.ts b/src/mono/wasm/runtime/loader/assets.ts index 02e05b1f8a9622..8730988193ffd0 100644 --- a/src/mono/wasm/runtime/loader/assets.ts +++ b/src/mono/wasm/runtime/loader/assets.ts @@ -598,7 +598,7 @@ function download_resource(asset: AssetEntryInternal): LoadingResource { totalResources.add(asset.name!); response.response.then(() => { if (asset.behavior == "assembly") { - loaderHelpers.loadedAssemblies.push(asset.resolvedUrl!); + loaderHelpers.loadedAssemblies.push(asset.name); } resourcesLoaded++; diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/AppSettingsTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/AppSettingsTest.cs similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/AppSettingsTest.cs rename to src/mono/wasm/testassets/WasmBasicTestApp/App/AppSettingsTest.cs diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/Common/Program.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/Common/Program.cs similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/Common/Program.cs rename to src/mono/wasm/testassets/WasmBasicTestApp/App/Common/Program.cs diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/Common/TestOutput.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/Common/TestOutput.cs similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/Common/TestOutput.cs rename to src/mono/wasm/testassets/WasmBasicTestApp/App/Common/TestOutput.cs diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/LazyLoadingTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/LazyLoadingTest.cs similarity index 91% rename from src/mono/wasm/testassets/WasmBasicTestApp/LazyLoadingTest.cs rename to src/mono/wasm/testassets/WasmBasicTestApp/App/LazyLoadingTest.cs index 0d68b1216816c3..5aba6b1ee48a0f 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/LazyLoadingTest.cs +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/LazyLoadingTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Library; using System; using System.Text.Json; using System.Runtime.InteropServices.JavaScript; @@ -15,6 +16,4 @@ public static void Run() var text = JsonSerializer.Serialize(new Person("John", "Doe")); TestOutput.WriteLine(text); } - - public record Person(string FirstName, string LastName); } diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/LibraryInitializerTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/LibraryInitializerTest.cs similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/LibraryInitializerTest.cs rename to src/mono/wasm/testassets/WasmBasicTestApp/App/LibraryInitializerTest.cs diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/Properties/AssemblyInfo.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/Properties/AssemblyInfo.cs similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/Properties/AssemblyInfo.cs rename to src/mono/wasm/testassets/WasmBasicTestApp/App/Properties/AssemblyInfo.cs diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/SatelliteAssembliesTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/SatelliteAssembliesTest.cs similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/SatelliteAssembliesTest.cs rename to src/mono/wasm/testassets/WasmBasicTestApp/App/SatelliteAssembliesTest.cs diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/WasmBasicTestApp.csproj b/src/mono/wasm/testassets/WasmBasicTestApp/App/WasmBasicTestApp.csproj similarity index 70% rename from src/mono/wasm/testassets/WasmBasicTestApp/WasmBasicTestApp.csproj rename to src/mono/wasm/testassets/WasmBasicTestApp/App/WasmBasicTestApp.csproj index 761ac6354ce861..a3b9364d4fce80 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/WasmBasicTestApp.csproj +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/WasmBasicTestApp.csproj @@ -8,6 +8,10 @@ - + + + + + diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/runtimeconfig.template.json b/src/mono/wasm/testassets/WasmBasicTestApp/App/runtimeconfig.template.json similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/runtimeconfig.template.json rename to src/mono/wasm/testassets/WasmBasicTestApp/App/runtimeconfig.template.json diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/words.es-ES.resx b/src/mono/wasm/testassets/WasmBasicTestApp/App/words.es-ES.resx similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/words.es-ES.resx rename to src/mono/wasm/testassets/WasmBasicTestApp/App/words.es-ES.resx diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/words.resx b/src/mono/wasm/testassets/WasmBasicTestApp/App/words.resx similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/words.resx rename to src/mono/wasm/testassets/WasmBasicTestApp/App/words.resx diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/WasmBasicTestApp.lib.module.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/WasmBasicTestApp.lib.module.js similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/WasmBasicTestApp.lib.module.js rename to src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/WasmBasicTestApp.lib.module.js diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/appsettings.Development.json b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/appsettings.Development.json similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/appsettings.Development.json rename to src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/appsettings.Development.json diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/appsettings.Production.json b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/appsettings.Production.json similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/appsettings.Production.json rename to src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/appsettings.Production.json diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/appsettings.json b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/appsettings.json similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/appsettings.json rename to src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/appsettings.json diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/index.html b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/index.html similarity index 100% rename from src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/index.html rename to src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/index.html diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/main.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js similarity index 97% rename from src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/main.js rename to src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js index 8d537cbdfb4041..076f37a62a6d87 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/wwwroot/main.js +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js @@ -79,7 +79,7 @@ try { break; case "LazyLoadingTest": if (params.get("loadRequiredAssembly") !== "false") { - await INTERNAL.loadLazyAssembly(`System.Text.Json${assemblyExtension}`); + await INTERNAL.loadLazyAssembly(`Json${assemblyExtension}`); } exports.LazyLoadingTest.Run(); exit(0); diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.cs b/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.cs new file mode 100644 index 00000000000000..cd496b96a3fc9e --- /dev/null +++ b/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.cs @@ -0,0 +1,11 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Library; + +public record Person(string FirstName, string LastName); + +[JsonSerializable(typeof(Person))] +public partial class PersonJsonSerializerContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.csproj b/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.csproj new file mode 100644 index 00000000000000..87c4a405521efe --- /dev/null +++ b/src/mono/wasm/testassets/WasmBasicTestApp/Library/Json.csproj @@ -0,0 +1,8 @@ + + + + net8.0 + Library + true + + From 5e9e29f6bb2e76f24bb80e72d39813ee6d3909a1 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Tue, 23 Jan 2024 15:50:09 +0100 Subject: [PATCH 02/33] [release/8.0][browser] BrowserWebSocket.ReceiveAsync after server initiated close (#97002) --- .../Net/WebSockets/WebSocketValidate.cs | 11 ++- .../Handlers/EchoWebSocketHandler.cs | 17 +++- .../BrowserWebSockets/BrowserWebSocket.cs | 87 ++++++++++++------- .../tests/CloseTest.cs | 81 ++++++++++++++--- .../tests/SendReceiveTest.cs | 2 +- src/mono/wasm/runtime/web-socket.ts | 68 ++++++++++++--- 6 files changed, 205 insertions(+), 61 deletions(-) diff --git a/src/libraries/Common/src/System/Net/WebSockets/WebSocketValidate.cs b/src/libraries/Common/src/System/Net/WebSockets/WebSocketValidate.cs index 7c97c082d26f89..e087677be4608e 100644 --- a/src/libraries/Common/src/System/Net/WebSockets/WebSocketValidate.cs +++ b/src/libraries/Common/src/System/Net/WebSockets/WebSocketValidate.cs @@ -23,10 +23,15 @@ internal static partial class WebSocketValidate internal const int MaxDeflateWindowBits = 15; internal const int MaxControlFramePayloadLength = 123; +#if TARGET_BROWSER + private const int ValidCloseStatusCodesFrom = 3000; + private const int ValidCloseStatusCodesTo = 4999; +#else private const int CloseStatusCodeAbort = 1006; private const int CloseStatusCodeFailedTLSHandshake = 1015; private const int InvalidCloseStatusCodesFrom = 0; private const int InvalidCloseStatusCodesTo = 999; +#endif // [0x21, 0x7E] except separators "()<>@,;:\\\"/[]?={} ". private static readonly SearchValues s_validSubprotocolChars = @@ -84,11 +89,15 @@ internal static void ValidateCloseStatus(WebSocketCloseStatus closeStatus, strin } int closeStatusCode = (int)closeStatus; - +#if TARGET_BROWSER + // as defined in https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code + if (closeStatus != WebSocketCloseStatus.NormalClosure && (closeStatusCode < ValidCloseStatusCodesFrom || closeStatusCode > ValidCloseStatusCodesTo)) +#else if ((closeStatusCode >= InvalidCloseStatusCodesFrom && closeStatusCode <= InvalidCloseStatusCodesTo) || closeStatusCode == CloseStatusCodeAbort || closeStatusCode == CloseStatusCodeFailedTLSHandshake) +#endif { // CloseStatus 1006 means Aborted - this will never appear on the wire and is reflected by calling WebSocket.Abort throw new ArgumentException(SR.Format(SR.net_WebSockets_InvalidCloseStatusCode, diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Handlers/EchoWebSocketHandler.cs b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Handlers/EchoWebSocketHandler.cs index f4e5562600015d..8304f2d1156072 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Handlers/EchoWebSocketHandler.cs +++ b/src/libraries/Common/tests/System/Net/Prerequisites/NetCoreServer/Handlers/EchoWebSocketHandler.cs @@ -24,11 +24,11 @@ public static async Task InvokeAsync(HttpContext context) if (context.Request.QueryString.HasValue && context.Request.QueryString.Value.Contains("delay10sec")) { - Thread.Sleep(10000); + await Task.Delay(10000); } else if (context.Request.QueryString.HasValue && context.Request.QueryString.Value.Contains("delay20sec")) { - Thread.Sleep(20000); + await Task.Delay(20000); } try @@ -124,14 +124,15 @@ await socket.CloseAsync( } bool sendMessage = false; + string receivedMessage = null; if (receiveResult.MessageType == WebSocketMessageType.Text) { - string receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, offset); + receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, offset); if (receivedMessage == ".close") { await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, receivedMessage, CancellationToken.None); } - if (receivedMessage == ".shutdown") + else if (receivedMessage == ".shutdown") { await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, receivedMessage, CancellationToken.None); } @@ -161,6 +162,14 @@ await socket.SendAsync( !replyWithPartialMessages, CancellationToken.None); } + if (receivedMessage == ".closeafter") + { + await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, receivedMessage, CancellationToken.None); + } + else if (receivedMessage == ".shutdownafter") + { + await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, receivedMessage, CancellationToken.None); + } } } } diff --git a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs index 121fa8595c65d5..879d45ca0da57c 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs +++ b/src/libraries/System.Net.WebSockets.Client/src/System/Net/WebSockets/BrowserWebSockets/BrowserWebSocket.cs @@ -24,6 +24,8 @@ internal sealed class BrowserWebSocket : WebSocket private WebSocketState _state; private bool _disposed; private bool _aborted; + private bool _closeReceived; + private bool _closeSent; private int[] responseStatus = new int[3]; private MemoryHandle? responseStatusHandle; @@ -37,7 +39,7 @@ public override WebSocketState State lock (_thisLock) { #endif - if (_innerWebSocket == null || _disposed || (_state != WebSocketState.Connecting && _state != WebSocketState.Open && _state != WebSocketState.CloseSent)) + if (_innerWebSocket == null || _disposed || _state == WebSocketState.Aborted || _state == WebSocketState.Closed) { return _state; } @@ -46,15 +48,9 @@ public override WebSocketState State #endif #if FEATURE_WASM_THREADS - return FastState = _innerWebSocket!.SynchronizationContext.Send(static (BrowserWebSocket self) => - { - lock (self._thisLock) - { - return GetReadyState(self._innerWebSocket!); - } //lock - }, this); + return _innerWebSocket!.SynchronizationContext.Send(GetReadyState, this); #else - return FastState = GetReadyState(_innerWebSocket!); + return GetReadyState(this); #endif } } @@ -148,7 +144,7 @@ public override Task SendAsync(ArraySegment buffer, WebSocketMessageType m ThrowIfDisposed(); // fast check of previous _state instead of GetReadyState(), the readyState would be validated on JS side - if (FastState != WebSocketState.Open) + if (FastState != WebSocketState.Open && FastState != WebSocketState.CloseReceived) { throw new InvalidOperationException(SR.net_WebSockets_NotConnected); } @@ -240,7 +236,7 @@ public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string? { throw new WebSocketException(WebSocketError.InvalidState, SR.Format(SR.net_WebSockets_InvalidState, state, "Connecting, Open, CloseSent, Aborted")); } - if(state != WebSocketState.Open && state != WebSocketState.Connecting && state != WebSocketState.Aborted) + if (state == WebSocketState.CloseSent) { return Task.CompletedTask; } @@ -280,10 +276,6 @@ public override Task CloseAsync(WebSocketCloseStatus closeStatus, string? status { throw new WebSocketException(WebSocketError.InvalidState, SR.Format(SR.net_WebSockets_InvalidState, state, "Connecting, Open, CloseSent, Aborted")); } - if (state != WebSocketState.Open && state != WebSocketState.Connecting && state != WebSocketState.Aborted && state != WebSocketState.CloseSent) - { - return Task.CompletedTask; - } #if FEATURE_WASM_THREADS promise = CloseAsyncCore(closeStatus, statusDescription, state != WebSocketState.Aborted, cancellationToken); @@ -387,12 +379,13 @@ private void CreateCore(Uri uri, List? requestedSubProtocols) string[]? subProtocols = requestedSubProtocols?.ToArray(); var onClose = (int code, string reason) => { - _closeStatus = (WebSocketCloseStatus)code; - _closeStatusDescription = reason; #if FEATURE_WASM_THREADS lock (_thisLock) { #endif + _closeStatus = (WebSocketCloseStatus)code; + _closeStatusDescription = reason; + _closeReceived = true; WebSocketState state = State; if (state == WebSocketState.Connecting || state == WebSocketState.Open || state == WebSocketState.CloseSent) { @@ -545,6 +538,8 @@ private static WebSocketReceiveResult ConvertResponse(BrowserWebSocket self) WebSocketMessageType messageType = (WebSocketMessageType)self.responseStatus[typeIndex]; if (messageType == WebSocketMessageType.Close) { + self._closeReceived = true; + self.FastState = self._closeSent ? WebSocketState.Closed : WebSocketState.CloseReceived; return new WebSocketReceiveResult(self.responseStatus[countIndex], messageType, self.responseStatus[endIndex] != 0, self.CloseStatus, self.CloseStatusDescription); } return new WebSocketReceiveResult(self.responseStatus[countIndex], messageType, self.responseStatus[endIndex] != 0); @@ -552,8 +547,12 @@ private static WebSocketReceiveResult ConvertResponse(BrowserWebSocket self) private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, string? statusDescription, bool waitForCloseReceived, CancellationToken cancellationToken) { - _closeStatus = closeStatus; - _closeStatusDescription = statusDescription; + if (!_closeReceived) + { + _closeStatus = closeStatus; + _closeStatusDescription = statusDescription; + } + _closeSent = true; var closeTask = BrowserInterop.WebSocketClose(_innerWebSocket!, (int)closeStatus, statusDescription, waitForCloseReceived) ?? Task.CompletedTask; await CancelationHelper(closeTask, cancellationToken, FastState).ConfigureAwait(true); @@ -562,6 +561,10 @@ private async Task CloseAsyncCore(WebSocketCloseStatus closeStatus, string? stat lock (_thisLock) { #endif + if (waitForCloseReceived) + { + _closeReceived = true; + } var state = State; if (state == WebSocketState.Open || state == WebSocketState.Connecting || state == WebSocketState.CloseSent) { @@ -614,18 +617,42 @@ private async Task CancelationHelper(Task jsTask, CancellationToken cancellation } } - private static WebSocketState GetReadyState(JSObject innerWebSocket) + private static WebSocketState GetReadyState(BrowserWebSocket self) { - var readyState = BrowserInterop.GetReadyState(innerWebSocket); - // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState - return readyState switch - { - 0 => WebSocketState.Connecting, // 0 (CONNECTING) - 1 => WebSocketState.Open, // 1 (OPEN) - 2 => WebSocketState.CloseSent, // 2 (CLOSING) - 3 => WebSocketState.Closed, // 3 (CLOSED) - _ => WebSocketState.None - }; +#if FEATURE_WASM_THREADS + lock (self._thisLock) + { +#endif + var readyState = BrowserInterop.GetReadyState(self._innerWebSocket); + // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState + var st = readyState switch + { + 0 => WebSocketState.Connecting, // 0 (CONNECTING) + 1 => WebSocketState.Open, // 1 (OPEN) + 2 => WebSocketState.CloseSent, // 2 (CLOSING) + 3 => WebSocketState.Closed, // 3 (CLOSED) + _ => WebSocketState.None + }; + if (st == WebSocketState.Closed || st == WebSocketState.CloseSent) + { + if (self._closeReceived && self._closeSent) + { + st = WebSocketState.Closed; + } + else if (self._closeReceived && !self._closeSent) + { + st = WebSocketState.CloseReceived; + } + else if (!self._closeReceived && self._closeSent) + { + st = WebSocketState.CloseSent; + } + } + self.FastState = st; + return st; +#if FEATURE_WASM_THREADS + } //lock +#endif } #endregion diff --git a/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs index 9e33810098f7da..6f1e6faa490192 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs @@ -33,12 +33,12 @@ public class CloseTest : ClientWebSocketTestBase public CloseTest(ITestOutputHelper output) : base(output) { } - [ActiveIssue("/~https://github.com/dotnet/runtime/issues/28957")] + [ActiveIssue("/~https://github.com/dotnet/runtime/issues/28957", typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServersAndBoolean))] public async Task CloseAsync_ServerInitiatedClose_Success(Uri server, bool useCloseOutputAsync) { - const string closeWebSocketMetaCommand = ".close"; + const string shutdownWebSocketMetaCommand = ".shutdown"; using (ClientWebSocket cws = await GetConnectedWebSocket(server, TimeOutMilliseconds, _output)) { @@ -46,7 +46,7 @@ public async Task CloseAsync_ServerInitiatedClose_Success(Uri server, bool useCl _output.WriteLine("SendAsync starting."); await cws.SendAsync( - WebSocketData.GetBufferFromText(closeWebSocketMetaCommand), + WebSocketData.GetBufferFromText(shutdownWebSocketMetaCommand), WebSocketMessageType.Text, true, cts.Token); @@ -59,26 +59,27 @@ await cws.SendAsync( // Verify received server-initiated close message. Assert.Equal(WebSocketCloseStatus.NormalClosure, recvResult.CloseStatus); - Assert.Equal(closeWebSocketMetaCommand, recvResult.CloseStatusDescription); + Assert.Equal(shutdownWebSocketMetaCommand, recvResult.CloseStatusDescription); Assert.Equal(WebSocketMessageType.Close, recvResult.MessageType); // Verify current websocket state as CloseReceived which indicates only partial close. Assert.Equal(WebSocketState.CloseReceived, cws.State); Assert.Equal(WebSocketCloseStatus.NormalClosure, cws.CloseStatus); - Assert.Equal(closeWebSocketMetaCommand, cws.CloseStatusDescription); + Assert.Equal(shutdownWebSocketMetaCommand, cws.CloseStatusDescription); // Send back close message to acknowledge server-initiated close. _output.WriteLine("Close starting."); + var closeStatus = PlatformDetection.IsNotBrowser ? WebSocketCloseStatus.InvalidMessageType : (WebSocketCloseStatus)3210; await (useCloseOutputAsync ? - cws.CloseOutputAsync(WebSocketCloseStatus.InvalidMessageType, string.Empty, cts.Token) : - cws.CloseAsync(WebSocketCloseStatus.InvalidMessageType, string.Empty, cts.Token)); + cws.CloseOutputAsync(closeStatus, string.Empty, cts.Token) : + cws.CloseAsync(closeStatus, string.Empty, cts.Token)); _output.WriteLine("Close done."); Assert.Equal(WebSocketState.Closed, cws.State); // Verify that there is no follow-up echo close message back from the server by // making sure the close code and message are the same as from the first server close message. Assert.Equal(WebSocketCloseStatus.NormalClosure, cws.CloseStatus); - Assert.Equal(closeWebSocketMetaCommand, cws.CloseStatusDescription); + Assert.Equal(shutdownWebSocketMetaCommand, cws.CloseStatusDescription); } } @@ -233,8 +234,7 @@ public async Task CloseOutputAsync_ClientInitiated_CanReceive_CanClose(Uri serve { var cts = new CancellationTokenSource(TimeOutMilliseconds); - // See issue for Browser websocket differences /~https://github.com/dotnet/runtime/issues/45538 - var closeStatus = PlatformDetection.IsBrowser ? WebSocketCloseStatus.NormalClosure : WebSocketCloseStatus.InvalidPayloadData; + var closeStatus = PlatformDetection.IsNotBrowser ? WebSocketCloseStatus.InvalidPayloadData : (WebSocketCloseStatus)3210; string closeDescription = "CloseOutputAsync_Client_InvalidPayloadData"; await cws.SendAsync(WebSocketData.GetBufferFromText(message), WebSocketMessageType.Text, true, cts.Token); @@ -262,7 +262,64 @@ public async Task CloseOutputAsync_ClientInitiated_CanReceive_CanClose(Uri serve } } - [ActiveIssue("/~https://github.com/dotnet/runtime/issues/28957")] + [ActiveIssue("/~https://github.com/dotnet/runtime/issues/28957", typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] + [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))] + public async Task CloseOutputAsync_ServerInitiated_CanReceive(Uri server) + { + string message = "Hello WebSockets!"; + var expectedCloseStatus = WebSocketCloseStatus.NormalClosure; + var expectedCloseDescription = ".shutdownafter"; + + using (ClientWebSocket cws = await GetConnectedWebSocket(server, TimeOutMilliseconds, _output)) + { + var cts = new CancellationTokenSource(TimeOutMilliseconds); + + await cws.SendAsync( + WebSocketData.GetBufferFromText(expectedCloseDescription), + WebSocketMessageType.Text, + true, + cts.Token); + + // Should be able to receive the message echoed by the server. + var recvBuffer = new byte[100]; + var segmentRecv = new ArraySegment(recvBuffer); + WebSocketReceiveResult recvResult = await cws.ReceiveAsync(segmentRecv, cts.Token); + Assert.Equal(expectedCloseDescription.Length, recvResult.Count); + segmentRecv = new ArraySegment(segmentRecv.Array, 0, recvResult.Count); + Assert.Equal(expectedCloseDescription, WebSocketData.GetTextFromBuffer(segmentRecv)); + Assert.Null(recvResult.CloseStatus); + Assert.Null(recvResult.CloseStatusDescription); + + // Should be able to receive a shutdown message. + segmentRecv = new ArraySegment(recvBuffer); + recvResult = await cws.ReceiveAsync(segmentRecv, cts.Token); + Assert.Equal(0, recvResult.Count); + Assert.Equal(expectedCloseStatus, recvResult.CloseStatus); + Assert.Equal(expectedCloseDescription, recvResult.CloseStatusDescription); + + // Verify WebSocket state + Assert.Equal(expectedCloseStatus, cws.CloseStatus); + Assert.Equal(expectedCloseDescription, cws.CloseStatusDescription); + + Assert.Equal(WebSocketState.CloseReceived, cws.State); + + // Should be able to send. + await cws.SendAsync(WebSocketData.GetBufferFromText(message), WebSocketMessageType.Text, true, cts.Token); + + // Cannot change the close status/description with the final close. + var closeStatus = PlatformDetection.IsNotBrowser ? WebSocketCloseStatus.InvalidPayloadData : (WebSocketCloseStatus)3210; + var closeDescription = "CloseOutputAsync_Client_Description"; + + await cws.CloseAsync(closeStatus, closeDescription, cts.Token); + + Assert.Equal(expectedCloseStatus, cws.CloseStatus); + Assert.Equal(expectedCloseDescription, cws.CloseStatusDescription); + Assert.Equal(WebSocketState.Closed, cws.State); + } + } + + [ActiveIssue("/~https://github.com/dotnet/runtime/issues/28957", typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))] public async Task CloseOutputAsync_ServerInitiated_CanSend(Uri server) @@ -299,7 +356,7 @@ await cws.SendAsync( await cws.SendAsync(WebSocketData.GetBufferFromText(message), WebSocketMessageType.Text, true, cts.Token); // Cannot change the close status/description with the final close. - var closeStatus = WebSocketCloseStatus.InvalidPayloadData; + var closeStatus = PlatformDetection.IsNotBrowser ? WebSocketCloseStatus.InvalidPayloadData : (WebSocketCloseStatus)3210; var closeDescription = "CloseOutputAsync_Client_Description"; await cws.CloseAsync(closeStatus, closeDescription, cts.Token); diff --git a/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs index 18694fcd97a1a9..f45ed7fd9c14ca 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs @@ -249,7 +249,7 @@ public async Task SendAsync_MultipleOutstandingSendOperations_Throws(Uri server) [OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))] [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))] // This will also pass when no exception is thrown. Current implementation doesn't throw. - [ActiveIssue("/~https://github.com/dotnet/runtime/issues/83517", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser))] + [ActiveIssue("/~https://github.com/dotnet/runtime/issues/83517", typeof(PlatformDetection), nameof(PlatformDetection.IsNodeJS))] public async Task ReceiveAsync_MultipleOutstandingReceiveOperations_Throws(Uri server) { using (ClientWebSocket cws = await GetConnectedWebSocket(server, TimeOutMilliseconds, _output)) diff --git a/src/mono/wasm/runtime/web-socket.ts b/src/mono/wasm/runtime/web-socket.ts index 7469d27cd7501e..5cf400aca536a9 100644 --- a/src/mono/wasm/runtime/web-socket.ts +++ b/src/mono/wasm/runtime/web-socket.ts @@ -5,7 +5,7 @@ import MonoWasmThreads from "consts:monoWasmThreads"; import { prevent_timer_throttling } from "./scheduling"; import { Queue } from "./queue"; -import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, createPromiseController, mono_assert } from "./globals"; +import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, createPromiseController, loaderHelpers, mono_assert } from "./globals"; import { setI32, localHeapViewU8 } from "./memory"; import { VoidPtr } from "./types/emscripten"; import { PromiseController } from "./types/internal"; @@ -19,12 +19,15 @@ const wasm_ws_pending_send_buffer_type = Symbol.for("wasm ws_pending_send_buffer const wasm_ws_pending_receive_event_queue = Symbol.for("wasm ws_pending_receive_event_queue"); const wasm_ws_pending_receive_promise_queue = Symbol.for("wasm ws_pending_receive_promise_queue"); const wasm_ws_pending_open_promise = Symbol.for("wasm ws_pending_open_promise"); +const wasm_ws_pending_open_promise_used = Symbol.for("wasm wasm_ws_pending_open_promise_used"); const wasm_ws_pending_close_promises = Symbol.for("wasm ws_pending_close_promises"); const wasm_ws_pending_send_promises = Symbol.for("wasm ws_pending_send_promises"); const wasm_ws_is_aborted = Symbol.for("wasm ws_is_aborted"); const wasm_ws_on_closed = Symbol.for("wasm ws_on_closed"); +const wasm_ws_close_sent = Symbol.for("wasm wasm_ws_close_sent"); +const wasm_ws_close_received = Symbol.for("wasm wasm_ws_close_received"); const wasm_ws_receive_status_ptr = Symbol.for("wasm ws_receive_status_ptr"); -let mono_wasm_web_socket_close_warning = false; + const ws_send_buffer_blocking_threshold = 65536; const emptyBuffer = new Uint8Array(); @@ -58,18 +61,22 @@ export function ws_wasm_create(uri: string, sub_protocols: string[] | null, rece ws.binaryType = "arraybuffer"; const local_on_open = () => { if (ws[wasm_ws_is_aborted]) return; + if (loaderHelpers.is_exited()) return; open_promise_control.resolve(ws); prevent_timer_throttling(); }; const local_on_message = (ev: MessageEvent) => { if (ws[wasm_ws_is_aborted]) return; + if (loaderHelpers.is_exited()) return; _mono_wasm_web_socket_on_message(ws, ev); prevent_timer_throttling(); }; const local_on_close = (ev: CloseEvent) => { ws.removeEventListener("message", local_on_message); if (ws[wasm_ws_is_aborted]) return; + if (loaderHelpers.is_exited()) return; + ws[wasm_ws_close_received] = true; onClosed(ev.code, ev.reason); // this reject would not do anything if there was already "open" before it. @@ -93,6 +100,7 @@ export function ws_wasm_create(uri: string, sub_protocols: string[] | null, rece }; const local_on_error = (ev: any) => { if (ws[wasm_ws_is_aborted]) return; + if (loaderHelpers.is_exited()) return; ws.removeEventListener("message", local_on_message); const error = new Error(ev.message || "WebSocket error"); mono_log_warn("WebSocket error", error); @@ -116,12 +124,23 @@ export function ws_wasm_create(uri: string, sub_protocols: string[] | null, rece export function ws_wasm_open(ws: WebSocketExtension): Promise | null { mono_assert(!!ws, "ERR17: expected ws instance"); const open_promise_control = ws[wasm_ws_pending_open_promise]; + ws[wasm_ws_pending_open_promise_used] = true; return open_promise_control.promise; } export function ws_wasm_send(ws: WebSocketExtension, buffer_ptr: VoidPtr, buffer_length: number, message_type: number, end_of_message: boolean): Promise | null { mono_assert(!!ws, "ERR17: expected ws instance"); + if (ws[wasm_ws_is_aborted] || ws[wasm_ws_close_sent]) { + return Promise.reject(new Error("InvalidState: The WebSocket is not connected.")); + } + + if (ws.readyState === WebSocket.CLOSED) { + // this is server initiated close but not partial close + // because CloseOutputAsync_ServerInitiated_CanSend expectations, we don't fail here + return null; + } + const buffer_view = new Uint8Array(localHeapViewU8().buffer, buffer_ptr, buffer_length); const whole_buffer = _mono_wasm_web_socket_send_buffering(ws, buffer_view, message_type, end_of_message); @@ -135,14 +154,18 @@ export function ws_wasm_send(ws: WebSocketExtension, buffer_ptr: VoidPtr, buffer export function ws_wasm_receive(ws: WebSocketExtension, buffer_ptr: VoidPtr, buffer_length: number): Promise | null { mono_assert(!!ws, "ERR18: expected ws instance"); + // we can't quickly return if wasm_ws_close_received==true, because there could be pending messages + if (ws[wasm_ws_is_aborted]) { + const receive_status_ptr = ws[wasm_ws_receive_status_ptr]; + setI32(receive_status_ptr, 0); // count + setI32(receive_status_ptr + 4, 2); // type:close + setI32(receive_status_ptr + 8, 1);// end_of_message: true + return null; + } + const receive_event_queue = ws[wasm_ws_pending_receive_event_queue]; const receive_promise_queue = ws[wasm_ws_pending_receive_promise_queue]; - const readyState = ws.readyState; - if (readyState != WebSocket.OPEN && readyState != WebSocket.CLOSING) { - throw new Error(`InvalidState: ${readyState} The WebSocket is not connected.`); - } - if (receive_event_queue.getLength()) { mono_assert(receive_promise_queue.getLength() == 0, "ERR20: Invalid WS state"); @@ -151,6 +174,16 @@ export function ws_wasm_receive(ws: WebSocketExtension, buffer_ptr: VoidPtr, buf return null; } + + const readyState = ws.readyState; + if (readyState == WebSocket.CLOSED) { + const receive_status_ptr = ws[wasm_ws_receive_status_ptr]; + setI32(receive_status_ptr, 0); // count + setI32(receive_status_ptr + 4, 2); // type:close + setI32(receive_status_ptr + 8, 1);// end_of_message: true + return null; + } + const { promise, promise_control } = createPromiseController(); const receive_promise_control = promise_control as ReceivePromiseControl; receive_promise_control.buffer_ptr = buffer_ptr; @@ -163,10 +196,11 @@ export function ws_wasm_receive(ws: WebSocketExtension, buffer_ptr: VoidPtr, buf export function ws_wasm_close(ws: WebSocketExtension, code: number, reason: string | null, wait_for_close_received: boolean): Promise | null { mono_assert(!!ws, "ERR19: expected ws instance"); - if (ws.readyState == WebSocket.CLOSED) { + if (ws[wasm_ws_is_aborted] || ws[wasm_ws_close_sent] || ws.readyState == WebSocket.CLOSED) { return null; } + ws[wasm_ws_close_sent] = true; if (wait_for_close_received) { const { promise, promise_control } = createPromiseController(); ws[wasm_ws_pending_close_promises].push(promise_control); @@ -179,10 +213,6 @@ export function ws_wasm_close(ws: WebSocketExtension, code: number, reason: stri return promise; } else { - if (!mono_wasm_web_socket_close_warning) { - mono_wasm_web_socket_close_warning = true; - mono_log_warn("WARNING: Web browsers do not support closing the output side of a WebSocket. CloseOutputAsync has closed the socket and discarded any incoming messages."); - } if (typeof reason === "string") { ws.close(code, reason); } else { @@ -195,6 +225,10 @@ export function ws_wasm_close(ws: WebSocketExtension, code: number, reason: stri export function ws_wasm_abort(ws: WebSocketExtension): void { mono_assert(!!ws, "ERR18: expected ws instance"); + if (ws[wasm_ws_is_aborted] || ws[wasm_ws_close_sent]) { + return; + } + ws[wasm_ws_is_aborted] = true; reject_promises(ws, new Error("OperationCanceledException")); @@ -211,7 +245,12 @@ export function ws_wasm_abort(ws: WebSocketExtension): void { function reject_promises(ws: WebSocketExtension, error: Error) { const open_promise_control = ws[wasm_ws_pending_open_promise]; - if (open_promise_control) { + const open_promise_used = ws[wasm_ws_pending_open_promise_used]; + + // when `open_promise_used` is false, we should not reject it, + // because it would be unhandled rejection. Nobody is subscribed yet. + // The subscription comes on the next call, which is `ws_wasm_open`, but cancelation/abort could happen in the meantime. + if (open_promise_control && open_promise_used) { open_promise_control.reject(error); } for (const close_promise_control of ws[wasm_ws_pending_close_promises]) { @@ -399,10 +438,13 @@ type WebSocketExtension = WebSocket & { [wasm_ws_pending_receive_event_queue]: Queue; [wasm_ws_pending_receive_promise_queue]: Queue; [wasm_ws_pending_open_promise]: PromiseController + [wasm_ws_pending_open_promise_used]: boolean [wasm_ws_pending_send_promises]: PromiseController[] [wasm_ws_pending_close_promises]: PromiseController[] [wasm_ws_is_aborted]: boolean [wasm_ws_on_closed]: IDisposable + [wasm_ws_close_received]: boolean + [wasm_ws_close_sent]: boolean [wasm_ws_receive_status_ptr]: VoidPtr [wasm_ws_pending_send_buffer_offset]: number [wasm_ws_pending_send_buffer_type]: number From fe443a9f8fdbb19cdb6a955a65c4b700d261ef3d Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Wed, 24 Jan 2024 15:47:46 -0300 Subject: [PATCH 03/33] [release/8.0][mono][debugger] Debugger improvements on .net8 (#97160) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [mono][hotreload] Generate seq_points if we don't have pdb information from HotReload (#93039) * Generating seq_points if we don't have pdb information from HotReload * Apply suggestions from code review Co-authored-by: Aleksey Kliger (λgeek) * Addressing @lambdageek comments --------- Co-authored-by: Aleksey Kliger (λgeek) * Fix CMD_OBJECT_REF_GET_VALUES_BY_FIELD_TOKEN behavior (#93363) * [mono] Simplify of OffsetToStringData as it's done on coreclr (#93987) * Change implementation of OffsetToStringData as it's done on coreclr * Fix comment * Remove more comments * completely remove the comments * Update RuntimeHelpers.Mono.cs * Addressing comments * Addressing @lambdageek comment. * [mono] Trying to fix performance regression. (#94358) * Trying to fix performance regression. * Fix performance issue * [mono][debugger] Improve debugger features (#94066) * Creating new messages, changing some olds, and fixing when jit_end is called while running a invoke_method * Fix compilation error * Fix compilation * Applying suggestions from @lambdageek and adding more changes. * Addressing @lambdageek suggestions. * Addressing @lambdageek comment * Addressing @lambdageek comments * adding mono_component_api to function added. * Bump protocol version to check if we are in correct version that has all the things to make icordebug work. (#97161) --------- Co-authored-by: Aleksey Kliger (λgeek) --- .../CompilerServices/RuntimeHelpers.Mono.cs | 6 +- .../src/System/String.Mono.cs | 6 + src/mono/mono/component/debugger-agent.c | 193 ++++++++++++------ src/mono/mono/component/debugger-engine.c | 28 ++- src/mono/mono/component/debugger-engine.h | 2 + src/mono/mono/component/debugger-protocol.h | 8 +- src/mono/mono/metadata/class-internals.h | 2 +- src/mono/mono/metadata/debug-internals.h | 2 + src/mono/mono/metadata/icall.c | 11 +- src/mono/mono/metadata/mono-debug.c | 15 ++ src/mono/mono/metadata/object-internals.h | 3 + src/mono/mono/metadata/object.c | 14 ++ src/mono/mono/mini/interp/transform.c | 21 +- src/mono/mono/mini/intrinsics.c | 5 +- 14 files changed, 229 insertions(+), 87 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs index 8fa80262e4903c..1564b301210bf2 100644 --- a/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs @@ -30,11 +30,7 @@ public static void InitializeArray(Array array, RuntimeFieldHandle fldHandle) } [Obsolete("OffsetToStringData has been deprecated. Use string.GetPinnableReference() instead.")] - public static int OffsetToStringData - { - [Intrinsic] - get => OffsetToStringData; - } + public static int OffsetToStringData => string.OFFSET_TO_STRING; [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern int InternalGetHashCode(object? o); diff --git a/src/mono/System.Private.CoreLib/src/System/String.Mono.cs b/src/mono/System.Private.CoreLib/src/System/String.Mono.cs index 35e2aef4f2fbbf..7314504aff9a22 100644 --- a/src/mono/System.Private.CoreLib/src/System/String.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/String.Mono.cs @@ -30,6 +30,12 @@ public static string IsInterned(string str) [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern string InternalIntern(string str); +#if TARGET_64BIT + internal const int OFFSET_TO_STRING = 20; +#else + internal const int OFFSET_TO_STRING = 12; +#endif + // TODO: Should be pointing to Buffer instead #region Runtime method-to-ir dependencies diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index 1e8e27686a287e..7cc565cbf5ffd2 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -3812,7 +3812,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx default: g_assert_not_reached (); } -#ifdef HOST_WASI + #ifdef HOST_WASI resumed_from_wasi = FALSE; while (suspend_policy != SUSPEND_POLICY_NONE && !resumed_from_wasi) { @@ -4147,7 +4147,14 @@ jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) dbg_unlock (); if (assembly) { - process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, assembly); + DebuggerTlsData *tls; + tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); + if (tls->invoke == NULL) { + process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, assembly); + } else { + assembly_load(prof, assembly); //send later + break; + } } else { break; } @@ -5068,20 +5075,16 @@ buffer_add_info_for_null_value (Buffer* buf, MonoType* t, MonoDomain* domain) { buffer_add_byte (buf, t->type); switch (t->type) { - case MONO_TYPE_CLASS: - case MONO_TYPE_STRING: - buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t)); - break; - case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: - buffer_add_byte (buf, m_class_get_byval_arg (m_class_get_element_class (mono_class_from_mono_type_internal (t)))->type); - buffer_add_int (buf, m_class_get_rank (mono_class_from_mono_type_internal (t))); - if (m_class_get_byval_arg (m_class_get_element_class (mono_class_from_mono_type_internal (t)))->type == MONO_TYPE_CLASS) - buffer_add_typeid (buf, domain, m_class_get_element_class (mono_class_from_mono_type_internal (t))); - buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t)); - break; - default: - buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t)); + case MONO_TYPE_SZARRAY: + case MONO_TYPE_ARRAY: + buffer_add_byte (buf, m_class_get_byval_arg (m_class_get_element_class (mono_class_from_mono_type_internal (t)))->type); + buffer_add_int (buf, m_class_get_rank (mono_class_from_mono_type_internal (t))); + if (m_class_get_byval_arg (m_class_get_element_class (mono_class_from_mono_type_internal (t)))->type == MONO_TYPE_CLASS) + buffer_add_typeid (buf, domain, m_class_get_element_class (mono_class_from_mono_type_internal (t))); + buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t)); + break; + default: + buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t)); } } /* @@ -5098,6 +5101,9 @@ buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain, MonoObject *obj; gboolean boxed_vtype = FALSE; + if (CHECK_ICORDBG (TRUE)) + buffer_add_byte (buf, !!m_type_is_byref (t)); + if (m_type_is_byref (t)) { if (!(*(void**)addr)) { /* This can happen with compiler generated locals */ @@ -5298,6 +5304,8 @@ buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain, if (mono_vtype_get_field_addr (addr, f) == addr && mono_class_from_mono_type_internal (t) == mono_class_from_mono_type_internal (f->type) && !boxed_vtype) //to avoid infinite recursion { gssize val = *(gssize*)addr; + if (CHECK_ICORDBG (TRUE)) + buffer_add_byte (buf, !!m_type_is_byref (f->type)); buffer_add_byte (buf, MONO_TYPE_PTR); buffer_add_long (buf, val); if (CHECK_PROTOCOL_VERSION(2, 46)) @@ -7097,6 +7105,8 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) minor_version = decode_int (p, &p, end); if (p < end) using_icordbg = decode_byte (p, &p, end); + if (using_icordbg) + mono_de_set_using_icordbg (); protocol_version_set = TRUE; PRINT_DEBUG_MSG (1, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION, MINOR_VERSION, major_version, minor_version); break; @@ -7120,7 +7130,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf) wait_for_suspend (); break; case CMD_VM_RESUME: -#ifndef HOST_WASI + #ifndef HOST_WASI if (suspend_count == 0) { if (agent_config.defer && !agent_config.suspend) // Workaround for issue in debugger-libs when running in defer attach mode. @@ -7708,7 +7718,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (req->event_kind == EVENT_KIND_BREAKPOINT) { g_assert (method); - + req->info = mono_de_set_breakpoint (method, location, req, error); if (!is_ok (error)) { g_free (req); @@ -7945,6 +7955,42 @@ domain_commands (int command, guint8 *p, guint8 *end, Buffer *buf) buffer_add_objid (buf, o); break; } + case MDBGPROT_CMD_APPDOMAIN_GET_ARRAY_OR_POINTER_TYPE: { + MonoClass *klass; + domain = decode_domainid (p, &p, end, NULL, &err); + MonoTypeEnum type = decode_int (p, &p, end); + klass = decode_typeid (p, &p, end, NULL, &err); + int rank = decode_int (p, &p, end); + if (type == MONO_TYPE_SZARRAY || type == MONO_TYPE_ARRAY) + klass = mono_class_create_array (klass, rank); + else + return ERR_INVALID_ARGUMENT; + buffer_add_typeid (buf, domain, klass); + break; + } + + case MDBGPROT_CMD_APPDOMAIN_CREATE_ARRAY: { + ERROR_DECL (error); + MonoClass *klass; + MonoArray *arr; + domain = decode_domainid (p, &p, end, NULL, &err); + klass = decode_typeid (p, &p, end, NULL, &err); + int rank = decode_int (p, &p, end); + uintptr_t *lengths = g_newa (uintptr_t, rank); + intptr_t *lower_bounds = g_newa (intptr_t, rank); + for (int i = 0 ; i < rank; i++) + { + lengths [i] = decode_int (p, &p, end); + } + for (int i = 0 ; i < rank; i++) + { + lower_bounds [i] = decode_int (p, &p, end); + } + arr = mono_array_new_full_checked (klass, lengths, lower_bounds, error); + buffer_add_objid (buf, (MonoObject*) arr); + break; + } + default: return ERR_NOT_IMPLEMENTED; } @@ -8287,6 +8333,21 @@ field_commands (int command, guint8 *p, guint8 *end, Buffer *buf) } break; } + case MDBGPROT_CMD_FIELD_GET_TOKEN_AND_TYPE: { + MonoClassField *f = decode_fieldid (p, &p, end, &domain, &err); + if (G_UNLIKELY (!f->type)) { + ERROR_DECL(field_error); + mono_field_resolve_type (f, field_error); + mono_error_cleanup (field_error); + if (!f->type) + return ERR_INVALID_OBJECT; + } + buffer_add_int (buf, mono_class_get_field_token (f)); + buffer_add_byte(buf, GINT_TO_UINT8(m_class_is_valuetype (mono_class_from_mono_type_internal (f->type)))); + buffer_add_int (buf, f->type->type); + buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (f->type)); + break; + } default: return ERR_NOT_IMPLEMENTED; } @@ -8476,6 +8537,19 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint buffer_add_int (buf, 0); } } + if (CHECK_ICORDBG (TRUE)) + { + if (type->type == MONO_TYPE_FNPTR) + { + buffer_add_int (buf, 1 + type->data.method->param_count); + buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (type->data.method->ret)); + for (int j = 0; j < type->data.method->param_count; ++j) { + buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (type->data.method->params[j])); + } + } else { + buffer_add_int (buf, 0); + } + } break; } case CMD_TYPE_GET_METHODS: { @@ -8890,44 +8964,9 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint buffer_add_objid (buf, obj); if (CHECK_ICORDBG (TRUE)) { - buffer_add_byte(buf, m_class_is_valuetype (klass)); - if (m_class_is_valuetype (klass)) - { - int nfields = 0; - gpointer iter = NULL; - while ((f = mono_class_get_fields_internal (klass, &iter))) { - if (G_UNLIKELY (!f->type)) { - ERROR_DECL(field_error); - mono_field_resolve_type (f, field_error); - mono_error_cleanup (field_error); - if (!f->type) - continue; - } - if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) - continue; - if (mono_field_is_deleted (f)) - continue; - nfields ++; - } - buffer_add_int (buf, nfields); - - iter = NULL; - while ((f = mono_class_get_fields_internal (klass, &iter))) { - if (G_UNLIKELY (!f->type)) { - ERROR_DECL(field_error); - mono_field_resolve_type (f, field_error); - mono_error_cleanup (field_error); - if (!f->type) - continue; - } - if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) - continue; - if (mono_field_is_deleted (f)) - continue; - buffer_add_int (buf, mono_class_get_field_token (f)); - buffer_add_byte (buf, f->type->type); - } - } + buffer_add_byte(buf, GINT_TO_UINT8(m_class_is_valuetype (klass))); + buffer_add_int (buf, m_class_get_byval_arg (klass)->type); + buffer_add_typeid (buf, domain, klass); } break; } @@ -9007,6 +9046,33 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint buffer_add_byte (buf, m_class_get_rank (klass)); break; } + case MDBGPROT_CMD_TYPE_GET_FIELD_RVA: + { + gpointer iter = NULL; + int field_token = decode_int (p, &p, end); + while ((f = mono_class_get_fields_internal (klass, &iter))) { + if (mono_class_get_field_token (f) == field_token) + { + if (G_UNLIKELY (!f->type)) { + ERROR_DECL(field_error); + mono_field_resolve_type (f, field_error); + mono_error_cleanup (field_error); + if (!f->type) + continue; + } + if (f->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) + { + gint32 count = 0; + const char* arr = mono_get_span_data_from_field (f, f->type, f->type, &count); + m_dbgprot_buffer_add_byte_array (buf, (uint8_t *)arr, count); + err = ERR_NONE; + goto exit; + } + } + } + m_dbgprot_buffer_add_int (buf, 0); + break; + } default: err = ERR_NOT_IMPLEMENTED; goto exit; @@ -10186,7 +10252,7 @@ array_commands (int command, guint8 *p, guint8 *end, Buffer *buf) MonoTypeEnum type = m_class_get_byval_arg (m_class_get_element_class (arr->obj.vtable->klass))->type; buffer_add_byte(buf, type); buffer_add_int (buf, m_class_get_rank (arr->obj.vtable->klass)); - if (type == MONO_TYPE_CLASS || type == MONO_TYPE_GENERICINST || type == MONO_TYPE_OBJECT) + if (type == MONO_TYPE_CLASS || type == MONO_TYPE_GENERICINST || type == MONO_TYPE_OBJECT || (CHECK_ICORDBG (TRUE) && (type == MONO_TYPE_VALUETYPE || type == MONO_TYPE_PTR))) { buffer_add_typeid (buf, arr->obj.vtable->domain, m_class_get_element_class (arr->obj.vtable->klass)); if (CHECK_ICORDBG (TRUE)) @@ -10385,13 +10451,20 @@ object_commands (int command, guint8 *p, guint8 *end, Buffer *buf) case CMD_OBJECT_REF_GET_VALUES_BY_FIELD_TOKEN: { len = 1; i = 0; - MonoClass* klass = decode_typeid (p, &p, end, NULL, &err); + int class_token = decode_int (p, &p, end); int field_token = decode_int (p, &p, end); gpointer iter = NULL; - while ((f = mono_class_get_fields_internal (klass, &iter))) { - if (mono_class_get_field_token (f) == field_token) + for (k = obj_type; k; k = m_class_get_parent (k)) { + if (m_class_get_type_token (k) == class_token) { + break; + } + } + + while ((f = mono_class_get_fields_internal (k, &iter))) { + if (mono_class_get_field_token (f) == field_token) { goto get_field_value; + } } goto invalid_fieldid; } diff --git a/src/mono/mono/component/debugger-engine.c b/src/mono/mono/component/debugger-engine.c index 02f7eb090f6aec..5ec3e68b62aee4 100644 --- a/src/mono/mono/component/debugger-engine.c +++ b/src/mono/mono/component/debugger-engine.c @@ -35,6 +35,7 @@ static DebuggerEngineCallbacks rt_callbacks; static int log_level; static FILE *log_file; +static bool using_icordbg = FALSE; /* * Locking @@ -160,6 +161,19 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo } } + if (!it_has_sp && using_icordbg) + { + mono_seq_point_iterator_init (&it, seq_points); + while (mono_seq_point_iterator_next (&it)) { + if (it.seq_point.il_offset != METHOD_ENTRY_IL_OFFSET && + it.seq_point.il_offset != METHOD_EXIT_IL_OFFSET && + it.seq_point.il_offset > bp->il_offset) { + it_has_sp = TRUE; + break; + } + } + } + if (!it_has_sp) { char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%ld", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset); @@ -581,10 +595,10 @@ ss_req_cleanup (void) void mono_de_start_single_stepping (void) { - int val = mono_atomic_inc_i32 (&ss_count); + int val = mono_atomic_inc_i32 (&ss_count); if (val == 1) { -#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED + #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED mono_arch_start_single_stepping (); #endif mini_get_interp_callbacks_api ()->start_single_stepping (); @@ -594,10 +608,10 @@ mono_de_start_single_stepping (void) void mono_de_stop_single_stepping (void) { - int val = mono_atomic_dec_i32 (&ss_count); + int val = mono_atomic_dec_i32 (&ss_count); if (val == 0) { -#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED + #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED mono_arch_stop_single_stepping (); #endif mini_get_interp_callbacks_api ()->stop_single_stepping (); @@ -1534,6 +1548,12 @@ mono_de_set_log_level (int level, FILE *file) log_file = file; } +void +mono_de_set_using_icordbg () +{ + using_icordbg = TRUE; +} + /* * mono_de_init: * diff --git a/src/mono/mono/component/debugger-engine.h b/src/mono/mono/component/debugger-engine.h index b0f6c5ca729b38..d3c9b0696be5d1 100644 --- a/src/mono/mono/component/debugger-engine.h +++ b/src/mono/mono/component/debugger-engine.h @@ -345,6 +345,8 @@ mono_debugger_get_thread_state (DebuggerTlsData *ref); void mono_de_cleanup (void); void mono_de_set_log_level (int level, FILE *file); +void mono_de_set_using_icordbg (void); + //locking - we expose the lock object from the debugging engine to ensure we keep the same locking semantics of sdb. void mono_de_lock (void); void mono_de_unlock (void); diff --git a/src/mono/mono/component/debugger-protocol.h b/src/mono/mono/component/debugger-protocol.h index 9fe3c690c93e72..5948cef59c2c1a 100644 --- a/src/mono/mono/component/debugger-protocol.h +++ b/src/mono/mono/component/debugger-protocol.h @@ -11,7 +11,7 @@ */ #define MAJOR_VERSION 2 -#define MINOR_VERSION 65 +#define MINOR_VERSION 66 typedef enum { MDBGPROT_CMD_COMPOSITE = 100 @@ -132,6 +132,8 @@ typedef enum { MDBGPROT_CMD_APPDOMAIN_GET_CORLIB = 6, MDBGPROT_CMD_APPDOMAIN_CREATE_BOXED_VALUE = 7, MDBGPROT_CMD_APPDOMAIN_CREATE_BYTE_ARRAY = 8, + MDBGPROT_CMD_APPDOMAIN_GET_ARRAY_OR_POINTER_TYPE = 9, + MDBGPROT_CMD_APPDOMAIN_CREATE_ARRAY = 10 } MdbgProtCmdAppDomain; typedef enum { @@ -162,6 +164,7 @@ typedef enum { typedef enum { MDBGPROT_CMD_FIELD_GET_INFO = 1, + MDBGPROT_CMD_FIELD_GET_TOKEN_AND_TYPE = 2 } MdbgProtCmdField; typedef enum { @@ -215,7 +218,8 @@ typedef enum { MDBGPROT_CMD_TYPE_BIND_GENERIC_PARAMETERS = 24, MDBGPROT_CMD_TYPE_ELEMENT_TYPE = 25, MDBGPROT_CMD_TYPE_RANK = 26, - MDBGPROT_CMD_TYPE_SET_VALUES_BY_FIELD_TOKEN = 27 + MDBGPROT_CMD_TYPE_SET_VALUES_BY_FIELD_TOKEN = 27, + MDBGPROT_CMD_TYPE_GET_FIELD_RVA = 28 } MdbgProtCmdType; typedef enum { diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 3b758b2acf6658..7a6a8ddc0080aa 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -1450,7 +1450,7 @@ mono_class_get_object_finalize_slot (void); MonoMethod * mono_class_get_default_finalize_method (void); -const char * +MONO_COMPONENT_API const char * mono_field_get_rva (MonoClassField *field, int swizzle); MONO_COMPONENT_API void diff --git a/src/mono/mono/metadata/debug-internals.h b/src/mono/mono/metadata/debug-internals.h index e08b767b4c3748..e03c2cffb9f35d 100644 --- a/src/mono/mono/metadata/debug-internals.h +++ b/src/mono/mono/metadata/debug-internals.h @@ -112,4 +112,6 @@ mono_debug_lookup_source_location_by_il (MonoMethod *method, guint32 il_offset, MONO_COMPONENT_API char* mono_debug_image_get_sourcelink (MonoImage *image); +mono_bool +mono_debug_generate_enc_seq_points_without_debug_info (MonoDebugMethodInfo *minfo); #endif /* __DEBUG_INTERNALS_H__ */ diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index f3ef9b74f26c65..2f612be9859985 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -989,16 +989,7 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetSpanDataFrom (MonoCl mono_error_set_argument (error, "array", "Cannot initialize array of non-primitive type"); return NULL; } - - int swizzle = 1; - int align; -#if G_BYTE_ORDER != G_LITTLE_ENDIAN - swizzle = mono_type_size (type, &align); -#endif - - int dummy; - *count = mono_type_size (field_type, &dummy)/mono_type_size (type, &align); - return (gpointer)mono_field_get_rva (field_handle, swizzle); + return mono_get_span_data_from_field (field_handle, field_type, type, count); } void diff --git a/src/mono/mono/metadata/mono-debug.c b/src/mono/mono/metadata/mono-debug.c index e49089b3e4652c..392581889def56 100644 --- a/src/mono/mono/metadata/mono-debug.c +++ b/src/mono/mono/metadata/mono-debug.c @@ -1149,6 +1149,21 @@ mono_debug_enabled (void) return mono_debug_format != MONO_DEBUG_FORMAT_NONE; } + +//Returns true if the method has updates but doesn't have ppdb information then we should generate the seq points using the coreclr rules +mono_bool +mono_debug_generate_enc_seq_points_without_debug_info (MonoDebugMethodInfo *minfo) +{ + MonoImage* img = m_class_get_image (minfo->method->klass); + if (G_UNLIKELY (img->has_updates)) { + guint32 idx = mono_metadata_token_index (minfo->method->token); + MonoDebugInformationEnc *mdie = (MonoDebugInformationEnc *) mono_metadata_update_get_updated_method_ppdb (img, idx); + if (mdie == NULL) + return TRUE; + } + return FALSE; +} + void mono_debug_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points) { diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 2f62c2530e8e46..1909411c7d03ef 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -2161,4 +2161,7 @@ mono_method_get_unmanaged_wrapper_ftnptr_internal (MonoMethod *method, gboolean void mono_runtime_run_startup_hooks (void); +MONO_COMPONENT_API gpointer +mono_get_span_data_from_field (MonoClassField *field_handle, MonoType *field_type, MonoType *target_type, gint32 *count); + #endif /* __MONO_OBJECT_INTERNALS_H__ */ diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index a99369f8bfce5f..36be06dca981d0 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -8178,6 +8178,20 @@ mono_runtime_run_startup_hooks (void) mono_error_raise_exception_deprecated (error); } +gpointer +mono_get_span_data_from_field (MonoClassField *field_handle, MonoType *field_type, MonoType *target_type, gint32 *count) +{ + int swizzle = 1; + int align; +#if G_BYTE_ORDER != G_LITTLE_ENDIAN + swizzle = mono_type_size (target_type, &align); +#endif + + int dummy; + *count = mono_type_size (field_type, &dummy)/mono_type_size (target_type, &align); + return (gpointer)mono_field_get_rva (field_handle, swizzle); +} + #if NEVER_DEFINED /* * The following section is purely to declare prototypes and diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 67034e9c59c81c..06396bc063fbcf 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -4786,6 +4786,19 @@ is_ip_protected (MonoMethodHeader *header, int offset) return FALSE; } +static gboolean +should_insert_seq_point (TransformData *td) +{ + //following the CoreCLR's algorithm for adding the sequence points + if ((*td->ip == CEE_NOP) || + (*td->ip == CEE_CALLVIRT) || + (*td->ip == CEE_CALLI) || + (*td->ip == CEE_CALL) || + (GPTRDIFF_TO_INT (td->sp - td->stack) == 0)) + return TRUE; + return FALSE; +} + static gboolean generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error) { @@ -4817,6 +4830,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, gboolean save_last_error = FALSE; gboolean link_bblocks = TRUE; gboolean inlining = td->method != method; + gboolean generate_enc_seq_points_without_debug_info = FALSE; InterpBasicBlock *exit_bb = NULL; original_bb = bb = mono_basic_block_split (method, error, header); @@ -4863,6 +4877,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, int n_il_offsets; mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets); + if (n_il_offsets == 0) + generate_enc_seq_points_without_debug_info = mono_debug_generate_enc_seq_points_without_debug_info (minfo); // FIXME: Free seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0); sym_seq_points = TRUE; @@ -5092,6 +5108,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, WRITE64_INS (td->last_ins, 0, &counter); } + if (G_UNLIKELY (generate_enc_seq_points_without_debug_info) && should_insert_seq_point (td)) + last_seq_point = interp_add_ins (td, MINT_SDB_SEQ_POINT); + switch (*td->ip) { case CEE_NOP: /* lose it */ @@ -5361,7 +5380,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (!interp_transform_call (td, method, NULL, generic_context, constrained_class, readonly, error, TRUE, save_last_error, tailcall)) goto exit; - if (need_seq_point) { + if (need_seq_point && !generate_enc_seq_points_without_debug_info) { // check if it is a nested call and remove the MONO_INST_NONEMPTY_STACK of the last breakpoint, only for non native methods if (!(method->flags & METHOD_IMPL_ATTRIBUTE_NATIVE)) { if (emitted_funccall_seq_point) { diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index ef77b7dc89f2ee..eca90a0e6abbf9 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -934,10 +934,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } else return NULL; } else if (cmethod->klass == runtime_helpers_class) { - if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) { - EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars)); - return ins; - } else if (!strcmp (cmethod->name, "GetRawData")) { + if (!strcmp (cmethod->name, "GetRawData")) { int dreg = alloc_preg (cfg); EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, args [0]->dreg, MONO_ABI_SIZEOF (MonoObject)); return ins; From d7a411899645fd5385b4c0efea4e0ec02f6b9ade Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:36:11 -0800 Subject: [PATCH 04/33] [release/8.0-staging] Add additionalSize for the DisableOptData (#97479) * add additionalSize for the DisableOptData * adding STRESS_LOG --------- Co-authored-by: Mikelle --- src/coreclr/debug/shared/dbgtransportsession.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/debug/shared/dbgtransportsession.cpp b/src/coreclr/debug/shared/dbgtransportsession.cpp index fa8b06618362d9..8b8ca6203c9571 100644 --- a/src/coreclr/debug/shared/dbgtransportsession.cpp +++ b/src/coreclr/debug/shared/dbgtransportsession.cpp @@ -2499,9 +2499,11 @@ DWORD DbgTransportSession::GetEventSize(DebuggerIPCEvent *pEvent) break; case DB_IPCE_DISABLE_OPTS: + cbAdditionalSize = sizeof(pEvent->DisableOptData); + break; default: - printf("Unknown debugger event type: 0x%x\n", (pEvent->type & DB_IPCE_TYPE_MASK)); + STRESS_LOG1(LF_CORDB, LL_INFO1000, "Unknown debugger event type: 0x%x\n", (pEvent->type & DB_IPCE_TYPE_MASK)); _ASSERTE(!"Unknown debugger event type"); } From 1901707289706ad9ffdc00be86e2b73bd9aa4898 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:46:38 +0100 Subject: [PATCH 05/33] [release/8.0-staging] Bump to new Ubuntu 22.04 queue for PPC64 (#97555) * Bump to new Ubuntu 22.04 queue for PPC64 * ActiveIssue for PPC64 generally, not limited to Ubuntu 20.04 This test errors out on the new 22.04 queue as well, it is not 20.04 specific --------- Co-authored-by: Jo Shields --- eng/pipelines/libraries/helix-queues-setup.yml | 2 +- .../tests/FunctionalTests/MsQuicPlatformDetectionTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index dd80cdc85095ad..5b37825df0867d 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -87,7 +87,7 @@ jobs: # Linux PPC64le - ${{ if eq(parameters.platform, 'linux_ppc64le') }}: - - Ubuntu.2004.PPC64le.Experimental.Open + - Ubuntu.2204.PPC64le.Experimental.Open # OSX arm64 - ${{ if eq(parameters.platform, 'osx_arm64') }}: diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicPlatformDetectionTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicPlatformDetectionTests.cs index 8dd026596c77fc..16f267fc719535 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicPlatformDetectionTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/MsQuicPlatformDetectionTests.cs @@ -57,7 +57,7 @@ public async Task SupportedLinuxPlatformsWithMsQuic_IsSupportedIsTrue() } [ActiveIssue("/~https://github.com/dotnet/runtime/issues/82154", typeof(PlatformDetection), nameof(PlatformDetection.IsRaspbian10), nameof(PlatformDetection.IsArmv6Process), nameof(PlatformDetection.IsInContainer))] - [ActiveIssue("/~https://github.com/dotnet/runtime/issues/82154", typeof(PlatformDetection), nameof(PlatformDetection.IsUbuntu2004), nameof(PlatformDetection.IsPpc64leProcess))] + [ActiveIssue("/~https://github.com/dotnet/runtime/issues/82154", typeof(PlatformDetection), nameof(PlatformDetection.IsPpc64leProcess))] [ActiveIssue("/~https://github.com/dotnet/runtime/issues/82154", typeof(PlatformDetection), nameof(PlatformDetection.IsUbuntu2004), nameof(PlatformDetection.IsS390xProcess))] [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsInHelix))] [PlatformSpecific(TestPlatforms.Linux)] From b54886b4b7e4b8617b1710459efc3a75b8c24235 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:30:40 -0800 Subject: [PATCH 06/33] [release/8.0-staging] Fix compilation error with generic type attributes (#97717) * Fix compilation error with generic type attributes Strip generic type parameter attributes from partial classes emitted by the logging source generated to avoid CS0579 errors from duplicate attributes. Fixes #97498. * Update comment Update comment as suggested by code review. * Verify type parameters retained Verify that attributes on generic type parameters are not lost. * Add package authoring --------- Co-authored-by: martincostello Co-authored-by: Tarek Mahmoud Sayed --- .../gen/LoggerMessageGenerator.Parser.cs | 27 ++++++++++++- ...oft.Extensions.Logging.Abstractions.csproj | 2 + ...thGenericTypesWithAttributes.generated.txt | 24 ++++++++++++ .../LoggerMessageGeneratorEmitterTests.cs | 36 +++++++++++++++++- .../LoggerMessageGeneratorParserTests.cs | 38 +++++++++++++++++++ .../TestClasses/NestedClassTestsExtensions.cs | 29 ++++++++++++++ 6 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithNestedClassWithGenericTypesWithAttributes.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs index 038b71bef0759b..1bc6ff6c323873 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs @@ -536,7 +536,7 @@ potentialNamespaceParent is not NamespaceDeclarationSyntax { Keyword = classDec.Keyword.ValueText, Namespace = nspace, - Name = classDec.Identifier.ToString() + classDec.TypeParameterList, + Name = GenerateClassName(classDec), ParentClass = null, }; @@ -554,7 +554,7 @@ static bool IsAllowedKind(SyntaxKind kind) => { Keyword = parentLoggerClass.Keyword.ValueText, Namespace = nspace, - Name = parentLoggerClass.Identifier.ToString() + parentLoggerClass.TypeParameterList, + Name = GenerateClassName(parentLoggerClass), ParentClass = null, }; @@ -601,6 +601,29 @@ static bool IsAllowedKind(SyntaxKind kind) => return results; } + private static string GenerateClassName(TypeDeclarationSyntax typeDeclaration) + { + if (typeDeclaration.TypeParameterList != null && + typeDeclaration.TypeParameterList.Parameters.Count != 0) + { + // The source generator produces a partial class that the compiler merges with the original + // class definition in the user code. If the user applies attributes to the generic types + // of the class, it is necessary to remove these attribute annotations from the generated + // code. Failure to do so may result in a compilation error (CS0579: Duplicate attribute). + for (int i = 0; i < typeDeclaration.TypeParameterList.Parameters.Count; i++) + { + TypeParameterSyntax parameter = typeDeclaration.TypeParameterList.Parameters[i]; + + if (parameter.AttributeLists.Count > 0) + { + typeDeclaration = typeDeclaration.ReplaceNode(parameter, parameter.WithAttributeLists([])); + } + } + } + + return typeDeclaration.Identifier.ToString() + typeDeclaration.TypeParameterList; + } + private (string? loggerField, bool multipleLoggerFields) FindLoggerField(SemanticModel sm, TypeDeclarationSyntax classDec, ITypeSymbol loggerSymbol) { string? loggerField = null; diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj index 085cade3966b96..052e5b9e0c0f60 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj @@ -5,6 +5,8 @@ true true true + true + 1 Logging abstractions for Microsoft.Extensions.Logging. Commonly Used Types: diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithNestedClassWithGenericTypesWithAttributes.generated.txt b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithNestedClassWithGenericTypesWithAttributes.generated.txt new file mode 100644 index 00000000000000..c7ddd086fcf27e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/Baselines/TestWithNestedClassWithGenericTypesWithAttributes.generated.txt @@ -0,0 +1,24 @@ +// +#nullable enable + +namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses +{ + partial class GenericTypeWithAttribute + { + partial class Log + { + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + private static readonly global::System.Action __M0Callback = + global::Microsoft.Extensions.Logging.LoggerMessage.Define(global::Microsoft.Extensions.Logging.LogLevel.Debug, new global::Microsoft.Extensions.Logging.EventId(42, nameof(M0)), "a = {a}; b = {b}; c = {c}", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true }); + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "%VERSION%")] + public static partial void M0(global::Microsoft.Extensions.Logging.ILogger logger, A a, B b, C c) + { + if (logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Debug)) + { + __M0Callback(logger, a, b, c, null); + } + } + } + } +} \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorEmitterTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorEmitterTests.cs index b1d767536653f5..30cf036fdd8606 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorEmitterTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorEmitterTests.cs @@ -3,8 +3,8 @@ using System; using System.IO; +using System.Reflection; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Text; using SourceGenerators.Tests; using Xunit; @@ -163,6 +163,40 @@ internal static partial class TestWithDefaultValues } #endif + [Fact] + public async Task TestBaseline_TestWithNestedClassWithGenericTypesWithAttributes_Success() + { + string testSourceCode = @" +namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses +{ + public partial class GenericTypeWithAttribute<[Foo] A, [Bar] B, C> + { + public void M0(A a, B b, C c, ILogger logger) => Log.M0(logger, a, b, c); + private static partial class Log<[Foo] D> + { + [LoggerMessage(EventId = 42, Level = LogLevel.Debug, Message = ""a = {a}; b = {b}; c = {c}"")] + public static partial void M0(ILogger logger, A a, B b, C c); + } + } + + [AttributeUsage(AttributeTargets.GenericParameter)] + public sealed class FooAttribute : Attribute { } + [AttributeUsage(AttributeTargets.GenericParameter)] + public sealed class BarAttribute : Attribute { } +}"; + await VerifyAgainstBaselineUsingFile("TestWithNestedClassWithGenericTypesWithAttributes.generated.txt", testSourceCode); + } + + [Fact] + public void GenericTypeParameterAttributesAreRetained() + { + var type = typeof(TestClasses.NestedClassWithGenericTypesWithAttributesTestsExtensions<,,>).GetTypeInfo(); + + Assert.Equal(3, type.GenericTypeParameters.Length); + Assert.NotNull(type.GenericTypeParameters[0].GetCustomAttribute()); + Assert.NotNull(type.GenericTypeParameters[1].GetCustomAttribute()); + } + private async Task VerifyAgainstBaselineUsingFile(string filename, string testSourceCode) { string baseline = LineEndingsHelper.Normalize(await File.ReadAllTextAsync(Path.Combine("Baselines", filename)).ConfigureAwait(false)); diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs index dc677e81cfc4a0..d0d5fc30af573f 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs @@ -359,6 +359,44 @@ public partial class Nested Assert.Empty(diagnostics); } + [Fact] + public async Task NestedTypeWithGenericParameterOK() + { + IReadOnlyList diagnostics = await RunGenerator(@" + partial class C + { + public partial class Nested + { + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + static partial void M1(ILogger logger); + } + } + "); + + Assert.Empty(diagnostics); + } + + [Fact] + public async Task NestedTypeWithGenericParameterWithAttributeOK() + { + IReadOnlyList diagnostics = await RunGenerator(@" + using System; + using System.Diagnostics.CodeAnalysis; + partial class C<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T> + { + public partial class Nested<[MarkerAttribute] U> + { + [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"")] + static partial void M1(ILogger logger); + } + } + [AttributeUsage(AttributeTargets.GenericParameter)] + class MarkerAttribute : Attribute { } + "); + + Assert.Empty(diagnostics); + } + #if ROSLYN4_0_OR_GREATER [Fact] public async Task FileScopedNamespaceOK() diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/TestClasses/NestedClassTestsExtensions.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/TestClasses/NestedClassTestsExtensions.cs index ba6b87f6d5308a..ea8cde78d566df 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/TestClasses/NestedClassTestsExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/TestClasses/NestedClassTestsExtensions.cs @@ -3,8 +3,20 @@ namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses { + using System; using NamespaceForABC; + public partial class NestedClassWithNoTypeConstraintTestsExtensions + { + public void M7(ILogger logger) => Log.M7(logger); + + private static partial class Log + { + [LoggerMessage(EventId = 7, Level = LogLevel.Debug, Message = "M7")] + public static partial void M7(ILogger logger); + } + } + internal static partial class NestedClassTestsExtensions where T : ABC { internal static partial class NestedMiddleParentClass @@ -61,6 +73,23 @@ internal static partial class Logger } } } + + public partial class NestedClassWithGenericTypesWithAttributesTestsExtensions<[Foo] A, [Bar] B, C> + { + public void M13(A a, B b, C c, ILogger logger) => Log.M13(logger, a, b, c); + + private static partial class Log<[Foo] D> + { + [LoggerMessage(EventId = 13, Level = LogLevel.Debug, Message = "M13: A = {a}; B = {b}; C = {c}")] + public static partial void M13(ILogger logger, A a, B b, C c); + } + } + + [AttributeUsage(AttributeTargets.GenericParameter)] + public sealed class FooAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.GenericParameter)] + public sealed class BarAttribute : Attribute { } } namespace NamespaceForABC From e6d8079d09491f4779a28e22f6b1702e9d98fe56 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 09:03:20 -0800 Subject: [PATCH 07/33] Remove use of NewHolder as field. (#97843) Co-authored-by: Aaron R Robinson --- src/coreclr/vm/syncblk.cpp | 4 ++++ src/coreclr/vm/syncblk.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/syncblk.cpp b/src/coreclr/vm/syncblk.cpp index bd235093b2d9c9..d0743994b7a86c 100644 --- a/src/coreclr/vm/syncblk.cpp +++ b/src/coreclr/vm/syncblk.cpp @@ -69,6 +69,10 @@ InteropSyncBlockInfo::~InteropSyncBlockInfo() CONTRACTL_END; FreeUMEntryThunk(); + +#if defined(FEATURE_COMWRAPPERS) + delete m_managedObjectComWrapperMap; +#endif // FEATURE_COMWRAPPERS } #ifndef TARGET_UNIX diff --git a/src/coreclr/vm/syncblk.h b/src/coreclr/vm/syncblk.h index 7fba11541532ff..c5464e73f24bb8 100644 --- a/src/coreclr/vm/syncblk.h +++ b/src/coreclr/vm/syncblk.h @@ -826,7 +826,7 @@ class InteropSyncBlockInfo if (m_managedObjectComWrapperMap == NULL) { NewHolder map = new ManagedObjectComWrapperByIdMap(); - if (InterlockedCompareExchangeT((ManagedObjectComWrapperByIdMap**)&m_managedObjectComWrapperMap, (ManagedObjectComWrapperByIdMap *)map, NULL) == NULL) + if (InterlockedCompareExchangeT(&m_managedObjectComWrapperMap, (ManagedObjectComWrapperByIdMap *)map, NULL) == NULL) { map.SuppressRelease(); } @@ -917,7 +917,7 @@ class InteropSyncBlockInfo void* m_externalComObjectContext; CrstExplicitInit m_managedObjectComWrapperLock; - NewHolder m_managedObjectComWrapperMap; + ManagedObjectComWrapperByIdMap* m_managedObjectComWrapperMap; #endif // FEATURE_COMWRAPPERS #ifdef FEATURE_OBJCMARSHAL From b0025c75590df174971f4c69c26a7380849c634d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:01:01 -0800 Subject: [PATCH 08/33] [release/8.0-staging] Update dependencies from dotnet/runtime-assets (#97212) * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 * Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240118.2 Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24060.2 -> To Version 8.0.0-beta.24068.2 --------- Co-authored-by: dotnet-maestro[bot] --- NuGet.config | 3 +++ eng/Version.Details.xml | 56 ++++++++++++++++++++--------------------- eng/Versions.props | 28 ++++++++++----------- 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/NuGet.config b/NuGet.config index 76ed5a30293c3a..12fa8c8879cdb6 100644 --- a/NuGet.config +++ b/NuGet.config @@ -10,6 +10,9 @@ + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 95c24b9f3675f5..d9219e152c7cad 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -185,57 +185,57 @@ /~https://github.com/dotnet/arcade 61ae141d2bf3534619265c8f691fd55dc3e75147 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 /~https://github.com/dotnet/llvm-project @@ -358,9 +358,9 @@ /~https://github.com/dotnet/hotreload-utils 3b7da338c73b31b943c5512dcf0e2f6dd75f601c - + /~https://github.com/dotnet/runtime-assets - 3b165c269b12cc194f48fde6a1a7694bece8931b + 15009138ff960446092497b67a13cc3dc00445f7 /~https://github.com/dotnet/roslyn diff --git a/eng/Versions.props b/eng/Versions.props index 55ce55ada067df..90ba26b4c2823c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -143,20 +143,20 @@ 4.5.0 8.0.0-rc.1.23406.6 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 - 8.0.0-beta.24060.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 + 8.0.0-beta.24068.2 1.0.0-prerelease.23566.3 1.0.0-prerelease.23566.3 From d8042d4384ca9ce5a6118a1bd87c6073a5f1052f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:01:39 -0800 Subject: [PATCH 09/33] Update dependencies from /~https://github.com/dotnet/hotreload-utils build 20240122.2 (#97322) Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 8.0.0-alpha.0.24060.1 -> To Version 8.0.0-alpha.0.24072.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d9219e152c7cad..1e47771d2b3a7c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -354,9 +354,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 67613417f5e1af250e6ddfba79f8f2885d8e90fb - + /~https://github.com/dotnet/hotreload-utils - 3b7da338c73b31b943c5512dcf0e2f6dd75f601c + bc857c64c5c5f1fc73048261e8f471c3310224d2 /~https://github.com/dotnet/runtime-assets diff --git a/eng/Versions.props b/eng/Versions.props index 90ba26b4c2823c..907392a3ee011d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -186,7 +186,7 @@ 8.0.0-prerelease.24060.1 8.0.0-prerelease.24060.1 8.0.0-prerelease.24060.1 - 8.0.0-alpha.0.24060.1 + 8.0.0-alpha.0.24072.2 2.4.2 1.0.0 2.4.5 From c2415d7e96f1bbc8864a2bbb7035fbcac2eb5100 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Thu, 8 Feb 2024 09:46:07 +0000 Subject: [PATCH 10/33] [release/8.0] Fix STJ SG regression in handling of property names that are reserved keywords. (#98082) * Fix #98050. (#98058) * bump servicing version --- .../gen/JsonSourceGenerator.Emitter.cs | 2 +- .../src/System.Text.Json.csproj | 2 +- .../JsonSourceGeneratorTests.cs | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index 90575721c507d7..692f90741b0373 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -798,7 +798,7 @@ private void GenerateFastPathFuncForObject(SourceWriter writer, ContextGeneratio if (defaultCheckType != DefaultCheckType.None) { // Use temporary variable to evaluate property value only once - string localVariableName = $"__value_{propertyGenSpec.NameSpecifiedInSourceCode}"; + string localVariableName = $"__value_{propertyGenSpec.NameSpecifiedInSourceCode.TrimStart('@')}"; writer.WriteLine($"{propertyGenSpec.PropertyType.FullyQualifiedName} {localVariableName} = {objectExpr}.{propertyGenSpec.NameSpecifiedInSourceCode};"); propValueExpr = localVariableName; } diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 29409f7f886293..9c492f0c6e0348 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -9,7 +9,7 @@ true true true - 2 + 3 Provides high-performance and low-allocating types that serialize objects to JavaScript Object Notation (JSON) text and deserialize JSON text to objects, with UTF-8 support built-in. Also provides types to read and write JSON text encoded as UTF-8, and to create an in-memory document object model (DOM), that is read-only, for random access of the JSON elements within a structured view of the data. The System.Text.Json library is built-in as part of the shared framework in .NET Runtime. The package can be installed when you need to use it in other target frameworks. diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs index ce27630b6ab692..332f718ce3ff49 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs @@ -737,5 +737,32 @@ public class MyClass Compilation compilation = CompilationHelper.CreateCompilation(source, parseOptions: CompilationHelper.CreateParseOptions(languageVersion)); CompilationHelper.RunJsonSourceGenerator(compilation); } + + [Fact] + public void FastPathWithReservedKeywordPropertyNames_CompilesSuccessfully() + { + // Regression test for /~https://github.com/dotnet/runtime/issues/98050 + + string source = """ + using System.Text.Json.Serialization; + + public class Model + { + public string type { get; set; } + public string alias { get; set; } + public string @class { get; set; } + public string @struct { get; set; } + } + + [JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] + [JsonSerializable(typeof(Model))] + internal partial class ModelContext : JsonSerializerContext + { + } + """; + + Compilation compilation = CompilationHelper.CreateCompilation(source); + CompilationHelper.RunJsonSourceGenerator(compilation); + } } } From 2663ba64a5a75eabb467da29fc9fad68393efdb5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 14:31:55 -0800 Subject: [PATCH 11/33] Update SystemDataSqlClientVersion from 4.8.5 -> 4.8.6 for component governance warning. (#97882) Co-authored-by: Parker Bibus --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index 907392a3ee011d..c50a1008b5f25f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -126,7 +126,7 @@ 4.5.1 7.0.0 5.0.0 - 4.8.5 + 4.8.6 8.0.0 5.0.0 4.5.5 From d62ff0ba2487e15b0d62ecadb7471019682b61d0 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Thu, 8 Feb 2024 15:11:29 -0800 Subject: [PATCH 12/33] Disable jiterpreter_do_jit_call to address issues with disabling Wasm EH on 8.0. (#98051) --- src/mono/mono/mini/interp/interp.c | 13 ------------- src/mono/mono/mini/interp/jiterpreter.c | 15 ++------------- src/mono/mono/mini/interp/jiterpreter.h | 6 ------ 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 6fb6bdd582d29d..c7d47719714de1 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -2726,21 +2726,8 @@ do_jit_call (ThreadContext *context, stackval *ret_sp, stackval *sp, InterpFrame interp_push_lmf (&ext, frame); if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) { -#if JITERPRETER_ENABLE_SPECIALIZED_JIT_CALL - /* - * invoke jit_call_cb via a single indirect function call that dispatches to - * either a specialized JS implementation or a specialized WASM EH version - * see jiterpreter-jit-call.ts and do-jit-call.wat - * NOTE: the first argument must ALWAYS be jit_call_cb for the specialization. - * the actual implementation cannot verify this at runtime, so get it right - * this is faster than mono_llvm_cpp_catch_exception by avoiding the use of - * emscripten invoke_vi to find and invoke jit_call_cb indirectly - */ - jiterpreter_do_jit_call(jit_call_cb, &cb_data, &thrown); -#else /* Catch the exception thrown by the native code using a try-catch */ mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown); -#endif } else { jit_call_cb (&cb_data); } diff --git a/src/mono/mono/mini/interp/jiterpreter.c b/src/mono/mono/mini/interp/jiterpreter.c index d3deb54f825659..82930e5737ac9c 100644 --- a/src/mono/mono/mini/interp/jiterpreter.c +++ b/src/mono/mono/mini/interp/jiterpreter.c @@ -53,10 +53,6 @@ void jiterp_preserve_module (void); static gint32 jiterpreter_abort_counts[MINT_LASTOP + 1] = { 0 }; static int64_t jiterp_trace_bailout_counts[256] = { 0 }; -// This function pointer is used by interp.c to invoke jit_call_cb for exception handling purposes -// See jiterpreter-jit-call.ts mono_jiterp_do_jit_call_indirect -WasmDoJitCall jiterpreter_do_jit_call = mono_jiterp_do_jit_call_indirect; - // We disable this diagnostic because EMSCRIPTEN_KEEPALIVE makes it a false alarm, the keepalive // functions are being used externally. Having a bunch of prototypes is pointless since these // functions are not consumed by C anywhere else @@ -951,15 +947,8 @@ mono_jiterp_get_options_as_json () EMSCRIPTEN_KEEPALIVE void mono_jiterp_update_jit_call_dispatcher (WasmDoJitCall dispatcher) { - // If we received a 0 dispatcher that means the TS side failed to compile - // any kind of dispatcher - this likely indicates that content security policy - // blocked the use of Module.addFunction - if (!dispatcher) - dispatcher = (WasmDoJitCall)mono_llvm_cpp_catch_exception; - else if (((int)(void*)dispatcher)==-1) - dispatcher = mono_jiterp_do_jit_call_indirect; - - jiterpreter_do_jit_call = dispatcher; + // Disabled in 8.0 to address issues when building with Wasm EH disabled. + // This system is entirely gone in 9.0. -kg } EMSCRIPTEN_KEEPALIVE int diff --git a/src/mono/mono/mini/interp/jiterpreter.h b/src/mono/mono/mini/interp/jiterpreter.h index 2f4d9a632a664b..a1b4cfd8e59570 100644 --- a/src/mono/mono/mini/interp/jiterpreter.h +++ b/src/mono/mono/mini/interp/jiterpreter.h @@ -5,12 +5,8 @@ #ifdef DISABLE_THREADS #define JITERPRETER_ENABLE_JIT_CALL_TRAMPOLINES 1 -// enables specialized mono_llvm_cpp_catch_exception replacement (see jiterpreter-jit-call.ts) -// works even if the jiterpreter is otherwise disabled. -#define JITERPRETER_ENABLE_SPECIALIZED_JIT_CALL 1 #else #define JITERPRETER_ENABLE_JIT_CALL_TRAMPOLINES 0 -#define JITERPRETER_ENABLE_SPECIALIZED_JIT_CALL 0 #endif // DISABLE_THREADS // mono_interp_tier_prepare_jiterpreter will return these special values if it doesn't @@ -149,8 +145,6 @@ mono_jiterp_monitor_trace (const guint16 *ip, void *frame, void *locals); #endif // __MONO_MINI_INTERPRETER_INTERNALS_H__ -extern WasmDoJitCall jiterpreter_do_jit_call; - #endif // HOST_BROWSER #endif // __MONO_MINI_JITERPRETER_H__ From 53c1d13c3a4f9fdf368bbff950da39ec71396525 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:25:45 -0600 Subject: [PATCH 13/33] Fixes exception while debugging on Chrome as IDE (#97871) Co-authored-by: Thays Grazia --- src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index bbf199f0e79b63..d072301f84259c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -1591,7 +1591,8 @@ internal virtual async Task OnSourceFileAdded(SessionId sessionId, SourceFile so await SendEvent(sessionId, "Debugger.scriptParsed", scriptSource, token); if (!resolveBreakpoints) return; - foreach (var req in context.BreakpointRequests.Values) + var breakpointRequests = context.BreakpointRequests.Values.ToList(); //this can be changed while we are looping it and cause an exception + foreach (var req in breakpointRequests) { if (req.TryResolve(source)) { From ea2b2e86419f2879c38f80a940b7d9f81209e7b5 Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Thu, 8 Feb 2024 23:28:50 -0300 Subject: [PATCH 14/33] Backport #97418 (#97568) --- src/mono/mono/component/debugger-agent.c | 59 ++++++++++-- .../BrowserDebugProxy/JObjectValueCreator.cs | 95 ++++++++++++++++++- .../BrowserDebugProxy/ValueTypeClass.cs | 20 +++- .../EvaluateOnCallFrame2Tests.cs | 23 +++++ .../debugger-test/debugger-evaluate-test.cs | 46 +++++++++ 5 files changed, 230 insertions(+), 13 deletions(-) diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index 7cc565cbf5ffd2..c9199635d15d59 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -5477,6 +5477,52 @@ decode_fixed_size_array_internal (MonoType *t, int type, MonoDomain *domain, gui return err; } +static int +decode_fixed_size_array_compute_size_internal (MonoType *t, int type, MonoDomain *domain, guint8 *buf, guint8 **endbuf, guint8 *limit) +{ + int ret = 0; + int fixedSizeLen = 1; + int newType = MONO_TYPE_END; + if (CHECK_PROTOCOL_VERSION (2, 53)) { + newType = decode_byte (buf, &buf, limit); + fixedSizeLen = decode_int (buf, &buf, limit); + //t->type = newType; + } + for (int i = 0 ; i < fixedSizeLen; i++) { + switch (newType) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + decode_int (buf, &buf, limit); + ret += sizeof(guint8); + break; + case MONO_TYPE_CHAR: + decode_int (buf, &buf, limit); + ret += sizeof(gunichar2); + break; + case MONO_TYPE_I2: + case MONO_TYPE_U2: + decode_int (buf, &buf, limit); + ret += sizeof(guint16); + break; + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_R4: + decode_int (buf, &buf, limit); + ret += sizeof(guint32); + break; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R8: + decode_long (buf, &buf, limit); + ret += sizeof(guint64); + break; + } + } + *endbuf = buf; + return ret; +} + static int decode_vtype_compute_size (MonoType *t, MonoDomain *domain, gpointer void_buf, guint8 **endbuf, guint8 *limit, gboolean from_by_ref_value_type) { @@ -5540,7 +5586,6 @@ decode_value_compute_size (MonoType *t, int type, MonoDomain *domain, guint8 *bu if (type == 0) type = decode_byte (buf, &buf, limit); int ret = 0; - ErrorCode err; if (type != t->type && !MONO_TYPE_IS_REFERENCE (t) && !(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) && !(type == VALUE_TYPE_ID_FIXED_ARRAY) && @@ -5555,7 +5600,7 @@ decode_value_compute_size (MonoType *t, int type, MonoDomain *domain, guint8 *bu goto end; } if (type == VALUE_TYPE_ID_FIXED_ARRAY && t->type != MONO_TYPE_VALUETYPE) { - //decode_fixed_size_array_internal (t, type, domain, addr, buf, endbuf, limit, check_field_datatype); + ret += decode_fixed_size_array_compute_size_internal (t, type, domain, buf, &buf, limit); goto end; } switch (t->type) { @@ -5626,13 +5671,6 @@ decode_value_compute_size (MonoType *t, int type, MonoDomain *domain, guint8 *bu decode_int (buf, &buf, limit); //not used } } else if (type == MONO_TYPE_VALUETYPE) { - MonoDomain *d; - decode_byte (buf, &buf, limit); - if (CHECK_PROTOCOL_VERSION(2, 61)) - decode_byte (buf, &buf, limit); //ignore is boxed - if (CHECK_PROTOCOL_VERSION(2, 65)) - decode_int (buf, &buf, limit); //ignore inline array - decode_typeid (buf, &buf, limit, &d, &err); ret += decode_vtype_compute_size (NULL, domain, buf, &buf, limit, from_by_ref_value_type); } else { goto end; @@ -5678,7 +5716,8 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, return ERR_INVALID_ARGUMENT; } if (type == VALUE_TYPE_ID_FIXED_ARRAY && t->type != MONO_TYPE_VALUETYPE) { - decode_fixed_size_array_internal (t, type, domain, addr, buf, endbuf, limit, check_field_datatype); + decode_fixed_size_array_internal (t, type, domain, addr, buf, &buf, limit, check_field_datatype); + *endbuf = buf; return ERR_NONE; } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs index 4231ac31967fa9..722c5a4aac3660 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/JObjectValueCreator.cs @@ -104,7 +104,6 @@ public async Task ReadAsVariableValue( case ElementType.U: case ElementType.Void: case (ElementType)ValueTypeId.VType: - case (ElementType)ValueTypeId.FixedArray: ret = Create(value: "void", type: "void", description: "void"); break; case ElementType.Boolean: @@ -419,4 +418,98 @@ private async Task ReadAsArray(MonoBinaryReader retDebuggerCmdReader, C objectId: "dotnet:array:" + objectId, subtype: length.Rank == 1 ? "array" : null); } + + public async Task CreateFixedArrayElement(MonoBinaryReader retDebuggerCmdReader, ElementType etype, string name, CancellationToken token) + { + JObject ret = null; + switch (etype) + { + case ElementType.I: + case ElementType.U: + case ElementType.Void: + case (ElementType)ValueTypeId.VType: + ret = Create(value: "void", type: "void", description: "void"); + break; + case ElementType.Boolean: + { + var value = retDebuggerCmdReader.ReadInt32(); + ret = CreateFromPrimitiveType(value == 1); + break; + } + case ElementType.I1: + { + var value = retDebuggerCmdReader.ReadSByte(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.I2: + case ElementType.I4: + { + var value = retDebuggerCmdReader.ReadInt32(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.U1: + { + var value = retDebuggerCmdReader.ReadUByte(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.U2: + { + var value = retDebuggerCmdReader.ReadUShort(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.U4: + { + var value = retDebuggerCmdReader.ReadUInt32(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.R4: + { + float value = retDebuggerCmdReader.ReadSingle(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.Char: + { + var value = retDebuggerCmdReader.ReadInt32(); + ret = CreateJObjectForChar(value); + break; + } + case ElementType.I8: + { + long value = retDebuggerCmdReader.ReadInt64(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.U8: + { + ulong value = retDebuggerCmdReader.ReadUInt64(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.R8: + { + double value = retDebuggerCmdReader.ReadDouble(); + ret = CreateJObjectForNumber(value); + break; + } + case ElementType.FnPtr: + case ElementType.Ptr: + { + ret = await ReadAsPtrValue(etype, retDebuggerCmdReader, name, token); + break; + } + default: + { + _logger.LogDebug($"Could not evaluate CreateFixedArrayElement invalid type {etype}"); + break; + } + } + ret["name"] = name; + return ret; + } } diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs index 59bc7b580ead93..85050d584f4279 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/ValueTypeClass.cs @@ -83,8 +83,24 @@ public static async Task CreateFromReader( && !f.Attributes.HasFlag(FieldAttributes.Static)); foreach (var field in writableFields) { - lastWritableFieldValue = await sdbAgent.ValueCreator.ReadAsVariableValue(cmdReader, field.Name, token, isOwn: true, field.TypeId, forDebuggerDisplayAttribute: false); - fields.Add(GetFieldWithMetadata(field, lastWritableFieldValue, isStatic: false)); + //check if it's fixed size array and behave as a inline array + ElementType etype = (ElementType)cmdReader.ReadByte(); + if (etype == (ElementType)ValueTypeId.FixedArray && writableFields.Count() == 1) + { + ElementType elementType = (ElementType)cmdReader.ReadByte(); + var arraySize = cmdReader.ReadInt32(); + inlineArray = new(arraySize + 1); + for (int i = 0; i < arraySize; i++) + { + inlineArray.Add(await sdbAgent.ValueCreator.CreateFixedArrayElement(cmdReader, elementType, $"{i}", token)); + } + } + else + { + cmdReader.BaseStream.Position-=sizeof(byte); + lastWritableFieldValue = await sdbAgent.ValueCreator.ReadAsVariableValue(cmdReader, field.Name, token, isOwn: true, field.TypeId, forDebuggerDisplayAttribute: false); + fields.Add(GetFieldWithMetadata(field, lastWritableFieldValue, isStatic: false)); + } } if (inlineArraySize > 0) { diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrame2Tests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrame2Tests.cs index b1a79b28ceeefe..ed034d91468665 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrame2Tests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrame2Tests.cs @@ -749,5 +749,28 @@ await EvaluateOnCallFrameAndCheck(id, ("f[f.numArray[f.numList[0]], f.numArray[f.numArray[i]]]", TNumber("4")) ); }); + + [Fact] + public async Task EvaluateValueTypeWithFixedArrayAndMoreFields() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateValueTypeWithFixedArray", "run", 3, "DebuggerTests.EvaluateValueTypeWithFixedArray.run", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateValueTypeWithFixedArray:run'); })", + wait_for_event_fn: async (pause_location) => + { + await RuntimeEvaluateAndCheck( + ("myVar.MyMethod()", TNumber(13)), + ("myVar.myIntArray[0]", TNumber(1)), + ("myVar.myIntArray[1]", TNumber(2)), + ("myVar.myCharArray[2]", TChar('a'))); + }); + + [Fact] + public async Task EvaluateValueTypeWithObjectValueType() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateValueTypeWithObjectValueType", "run", 3, "DebuggerTests.EvaluateValueTypeWithObjectValueType.run", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateValueTypeWithObjectValueType:run'); })", + wait_for_event_fn: async (pause_location) => + { + await RuntimeEvaluateAndCheck( + ("myVar.MyMethod()", TNumber(10))); + }); } } diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs index e46177ecc925b5..4f36197af79b42 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs @@ -2182,4 +2182,50 @@ public static void run() Console.WriteLine(dt); } } + public unsafe struct EvaluateValueTypeWithFixedArray + { + private fixed int myIntArray[4]; + private fixed char myCharArray[3]; + double myDouble; + public EvaluateValueTypeWithFixedArray() + { + myDouble = 10; + myIntArray[0] = 1; + myIntArray[1] = 2; + myCharArray[2] = 'a'; + } + public int MyMethod() + { + Console.WriteLine(myDouble); + return myIntArray[0] + myIntArray[1] + (int)myDouble; + } + public static void run() + { + var myVar = new EvaluateValueTypeWithFixedArray(); + Console.WriteLine("pause here"); + myVar.MyMethod(); + } + } + + public struct EvaluateValueTypeWithObjectValueType + { + private object myObject; + double myDouble; + public EvaluateValueTypeWithObjectValueType() + { + myObject = new int(); + myDouble = 10; + } + public int MyMethod() + { + Console.WriteLine(myDouble); + return (int)myObject + (int)myDouble; + } + public static void run() + { + var myVar = new EvaluateValueTypeWithObjectValueType(); + Console.WriteLine("pause here"); + myVar.MyMethod(); + } + } } \ No newline at end of file From 279fe234c7dda7faaaa693644f7de4e029e77c29 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 10:42:06 -0800 Subject: [PATCH 15/33] Update dependencies from /~https://github.com/dotnet/runtime-assets build 20240208.4 (#98224) Microsoft.DotNet.CilStrip.Sources , System.ComponentModel.TypeConverter.TestData , System.Data.Common.TestData , System.Drawing.Common.TestData , System.Formats.Tar.TestData , System.IO.Compression.TestData , System.IO.Packaging.TestData , System.Net.TestData , System.Private.Runtime.UnicodeData , System.Runtime.Numerics.TestData , System.Runtime.TimeZoneData , System.Security.Cryptography.X509Certificates.TestData , System.Text.RegularExpressions.TestData , System.Windows.Extensions.TestData From Version 8.0.0-beta.24068.2 -> To Version 8.0.0-beta.24108.4 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 56 ++++++++++++++++++++--------------------- eng/Versions.props | 28 ++++++++++----------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1e47771d2b3a7c..04a7792f12c29a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -185,57 +185,57 @@ /~https://github.com/dotnet/arcade 61ae141d2bf3534619265c8f691fd55dc3e75147 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 /~https://github.com/dotnet/llvm-project @@ -358,9 +358,9 @@ /~https://github.com/dotnet/hotreload-utils bc857c64c5c5f1fc73048261e8f471c3310224d2 - + /~https://github.com/dotnet/runtime-assets - 15009138ff960446092497b67a13cc3dc00445f7 + ca6c46012f68934198ce0d303196c3ae179230f5 /~https://github.com/dotnet/roslyn diff --git a/eng/Versions.props b/eng/Versions.props index c50a1008b5f25f..05d877f78822fa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -143,20 +143,20 @@ 4.5.0 8.0.0-rc.1.23406.6 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 - 8.0.0-beta.24068.2 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 + 8.0.0-beta.24108.4 1.0.0-prerelease.23566.3 1.0.0-prerelease.23566.3 From eded9a50a7ba49dfb371d5d3a0eb0845b9339a69 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 12:01:13 -0800 Subject: [PATCH 16/33] [release/8.0-staging] Ensure that the Create(Dot(...)) optimization doesn't kick in for Vector2 pre SSE4.1 (#97074) * Ensure that the Create(Dot(...)) optimization doesn't kick in for Vector2 pre SSE4.1 * Make sure to use #if defined(...) * Add missing using * Fix a type in the test --------- Co-authored-by: Tanner Gooding --- src/coreclr/jit/morph.cpp | 10 +++++ .../JitBlue/Runtime_96939/Runtime_96939.cs | 38 +++++++++++++++++++ .../Runtime_96939/Runtime_96939.csproj | 10 +++++ 3 files changed, 58 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_96939/Runtime_96939.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_96939/Runtime_96939.csproj diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 3deada8eec085b..b20cd585882b87 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -10724,6 +10724,16 @@ GenTree* Compiler::fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node) break; } +#if defined(TARGET_XARCH) + if ((node->GetSimdSize() == 8) && !compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + // When SSE4.1 isn't supported then Vector2 only needs a single horizontal add + // which means the result isn't broadcast across the entire vector and we can't + // optimize + break; + } +#endif // TARGET_XARCH + GenTree* op1 = node->Op(1); GenTree* sqrt = nullptr; GenTree* toScalar = nullptr; diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_96939/Runtime_96939.cs b/src/tests/JIT/Regression/JitBlue/Runtime_96939/Runtime_96939.cs new file mode 100644 index 00000000000000..ac26af680eea80 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_96939/Runtime_96939.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using Xunit; + +public static class Runtime_96939 +{ + [Fact] + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static void Problem() + { + Assert.Equal(new Vector2(13), TestVector2(new Vector2(2, 3))); + Assert.Equal(new Vector3(29), TestVector3(new Vector3(2, 3, 4))); + Assert.Equal(new Vector4(54), TestVector4(new Vector4(2, 3, 4, 5))); + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + public static Vector2 TestVector2(Vector2 value) + { + return Vector2.Dot(value, value) * new Vector2(1, 1); + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + public static Vector3 TestVector3(Vector3 value) + { + return Vector3.Dot(value, value) * new Vector3(1, 1, 1); + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + public static Vector4 TestVector4(Vector4 value) + { + return Vector4.Dot(value, value) * new Vector4(1, 1, 1, 1); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_96939/Runtime_96939.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_96939/Runtime_96939.csproj new file mode 100644 index 00000000000000..596f2374a8fb3b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_96939/Runtime_96939.csproj @@ -0,0 +1,10 @@ + + + True + None + true + + + + + From a143568343ac8956caf9f64264af877e2cf288e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 12:01:23 -0800 Subject: [PATCH 17/33] Don't clean up thread list on shutdown (#97188) Co-authored-by: David Mason --- src/native/eventpipe/ep-thread.c | 13 ------------- src/native/eventpipe/ep-thread.h | 3 --- src/native/eventpipe/ep.c | 15 --------------- 3 files changed, 31 deletions(-) diff --git a/src/native/eventpipe/ep-thread.c b/src/native/eventpipe/ep-thread.c index 93c87d4b8b4965..b720bf592d0c4d 100644 --- a/src/native/eventpipe/ep-thread.c +++ b/src/native/eventpipe/ep-thread.c @@ -93,19 +93,6 @@ ep_thread_init (void) EP_UNREACHABLE ("Failed to allocate threads list."); } -void -ep_thread_fini (void) -{ - // If threads are still included in list (depending on runtime shutdown order), - // don't clean up since TLS destructor migh callback freeing items, no new - // threads should however not be added to list at this stage. - if (dn_list_empty (_ep_threads)) { - dn_list_free (_ep_threads); - _ep_threads = NULL; - ep_rt_spin_lock_free (&_ep_threads_lock); - } -} - bool ep_thread_register (EventPipeThread *thread) { diff --git a/src/native/eventpipe/ep-thread.h b/src/native/eventpipe/ep-thread.h index c3f8fd7cd71a74..44c683b52d57f8 100644 --- a/src/native/eventpipe/ep-thread.h +++ b/src/native/eventpipe/ep-thread.h @@ -92,9 +92,6 @@ ep_thread_release (EventPipeThread *thread); void ep_thread_init (void); -void -ep_thread_fini (void); - bool ep_thread_register (EventPipeThread *thread); diff --git a/src/native/eventpipe/ep.c b/src/native/eventpipe/ep.c index d007702dde463f..34c84e874458aa 100644 --- a/src/native/eventpipe/ep.c +++ b/src/native/eventpipe/ep.c @@ -1453,21 +1453,6 @@ ep_shutdown (void) dn_vector_free (_ep_deferred_disable_session_ids); _ep_deferred_disable_session_ids = NULL; - ep_thread_fini (); - - // dotnet/coreclr: issue 24850: EventPipe shutdown race conditions - // Deallocating providers/events here might cause AV if a WriteEvent - // was to occur. Thus, we are not doing this cleanup. - - /*EP_LOCK_ENTER (section1) - ep_sample_profiler_shutdown (); - EP_LOCK_EXIT (section1)*/ - - // // Remove EventPipeEventSource first since it tries to use the data structures that we remove below. - // // We need to do this after disabling sessions since those try to write to EventPipeEventSource. - // ep_event_source_fini (ep_event_source_get ()); - // ep_config_shutdown (ep_config_get ()); - ep_on_exit: ep_requires_lock_not_held (); ep_rt_shutdown (); From 2767a15a0817dd9858a3cc90ac3aa44f37e8e7da Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Fri, 9 Feb 2024 22:01:52 +0200 Subject: [PATCH 18/33] [mono][interp] Fix inlining of ldarga (#97650) When inlining a method, all arguments are first copied to new vars. Ldarga is going to be applied on these copies. We were loading the address of the wrong var due to typo. --- src/mono/mono/mini/interp/transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 06396bc063fbcf..0d5ef5380de266 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -8018,7 +8018,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } else { int loc_n = arg_locals [n]; interp_add_ins (td, MINT_LDLOCA_S); - interp_ins_set_sreg (td->last_ins, n); + interp_ins_set_sreg (td->last_ins, loc_n); td->locals [loc_n].indirects++; } push_simple_type (td, STACK_TYPE_MP); From ef1b0d681999223ad6ecd493fbc02792346861f3 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Fri, 9 Feb 2024 15:02:02 -0500 Subject: [PATCH 19/33] [release/8.0-staging] [mono][jit] Fix passing of byref arguments in mono_gsharedvt_constrained_call (). (#97721) (#97850) Fixes /~https://github.com/dotnet/runtime/issues/97625. Co-authored-by: Larry Ewing --- src/mono/mono/mini/jit-icalls.c | 3 ++- .../JitBlue/Runtime_97625/Runtime_97625.cs | 23 +++++++++++++++++++ .../Runtime_97625/Runtime_97625.csproj | 8 +++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_97625/Runtime_97625.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_97625/Runtime_97625.csproj diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c index 628d18abe35cfd..24ec1b65dcf566 100644 --- a/src/mono/mono/mini/jit-icalls.c +++ b/src/mono/mono/mini/jit-icalls.c @@ -1482,7 +1482,8 @@ mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *kl g_assert (fsig->param_count < 16); memcpy (new_args, args, fsig->param_count * sizeof (gpointer)); for (int i = 0; i < fsig->param_count; ++i) { - if (deref_args [i]) + // If the argument is not a vtype or nullable, deref it + if (deref_args [i] && (deref_args [i] != MONO_GSHAREDVT_BOX_TYPE_VTYPE && deref_args [i] != MONO_GSHAREDVT_BOX_TYPE_NULLABLE)) new_args [i] = *(gpointer*)new_args [i]; } args = new_args; diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_97625/Runtime_97625.cs b/src/tests/JIT/Regression/JitBlue/Runtime_97625/Runtime_97625.cs new file mode 100644 index 00000000000000..2a2ad6b87873a1 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_97625/Runtime_97625.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +public static class Runtime_97625 +{ + public class CustomModel + { + public decimal Cost { get; set; } + } + + [Fact] + public static int Test() + { + List models = new List(); + models.Add(new CustomModel { Cost = 1 }); + return models.Average (x => x.Cost) == 1 ? 100 : -1; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_97625/Runtime_97625.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_97625/Runtime_97625.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_97625/Runtime_97625.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From 4b040aa6f0ed16c9c75e02e9d71a22b2afe49383 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 9 Feb 2024 12:02:11 -0800 Subject: [PATCH 20/33] Stop trying to format HOST_RUNTIME_CONTRACT property with locale settings (#97891) --- src/native/corehost/hostpolicy/deps_resolver.cpp | 3 ++- src/native/corehost/hostpolicy/hostpolicy_context.cpp | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/native/corehost/hostpolicy/deps_resolver.cpp b/src/native/corehost/hostpolicy/deps_resolver.cpp index beedcef62cd06b..66d44f0c17dae0 100644 --- a/src/native/corehost/hostpolicy/deps_resolver.cpp +++ b/src/native/corehost/hostpolicy/deps_resolver.cpp @@ -280,7 +280,8 @@ bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::str for (const auto& config : m_probes) { - trace::verbose(_X(" Using probe config: %s"), config.as_str().c_str()); + if (trace::is_enabled()) + trace::verbose(_X(" Using probe config: %s"), config.as_str().c_str()); if (config.is_servicing() && !entry.is_serviceable) { diff --git a/src/native/corehost/hostpolicy/hostpolicy_context.cpp b/src/native/corehost/hostpolicy/hostpolicy_context.cpp index f8d220d8130e07..1ceb961f8df367 100644 --- a/src/native/corehost/hostpolicy/hostpolicy_context.cpp +++ b/src/native/corehost/hostpolicy/hostpolicy_context.cpp @@ -378,9 +378,9 @@ int hostpolicy_context_t::initialize(const hostpolicy_init_t &hostpolicy_init, c } host_contract.get_runtime_property = &get_runtime_property; - pal::stringstream_t ptr_stream; - ptr_stream << "0x" << std::hex << (size_t)(&host_contract); - if (!coreclr_properties.add(_STRINGIFY(HOST_PROPERTY_RUNTIME_CONTRACT), ptr_stream.str().c_str())) + pal::char_t buffer[STRING_LENGTH("0xffffffffffffffff")]; + pal::snwprintf(buffer, ARRAY_SIZE(buffer), _X("0x%zx"), (size_t)(&host_contract)); + if (!coreclr_properties.add(_STRINGIFY(HOST_PROPERTY_RUNTIME_CONTRACT), buffer)) { log_duplicate_property_error(_STRINGIFY(HOST_PROPERTY_RUNTIME_CONTRACT)); return StatusCode::LibHostDuplicateProperty; From 6cd0eddba867045259663f3c83b9567eb7dc3b46 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 9 Feb 2024 12:02:38 -0800 Subject: [PATCH 21/33] Backport of Handle open types to appear in interface maps (#97733) to release/8.0-staging (#98182) - Reflection IsAssignableFrom api - As well as constraint checking --- src/coreclr/vm/methodtable.cpp | 13 +-- src/coreclr/vm/methodtable.h | 15 +++- src/coreclr/vm/methodtable.inl | 3 +- src/coreclr/vm/methodtablebuilder.cpp | 5 ++ .../CuriouslyRecurringThroughInterface.cs | 85 ++++++++++++++++++- 5 files changed, 107 insertions(+), 14 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 688bf29079e08d..76aab1f8b2d312 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -1433,7 +1433,7 @@ BOOL MethodTable::CanCastToInterface(MethodTable *pTargetMT, TypeHandlePairList if (CanCastByVarianceToInterfaceOrDelegate(pTargetMT, pVisited)) return TRUE; - if (pTargetMT->IsSpecialMarkerTypeForGenericCasting()) + if (pTargetMT->IsSpecialMarkerTypeForGenericCasting() && !GetWriteableData()->MayHaveOpenInterfacesInInterfaceMap()) return FALSE; // The special marker types cannot be cast to (at this time, they are the open generic types, so they are however, valid input to this method). InterfaceMapIterator it = IterateInterfaceMap(); @@ -1470,7 +1470,7 @@ BOOL MethodTable::CanCastByVarianceToInterfaceOrDelegate(MethodTable *pTargetMT, // Shortcut for generic approx type scenario if (pMTInterfaceMapOwner != NULL && - !pMTInterfaceMapOwner->ContainsGenericVariables() && + !pMTInterfaceMapOwner->GetWriteableData()->MayHaveOpenInterfacesInInterfaceMap() && IsSpecialMarkerTypeForGenericCasting() && GetTypeDefRid() == pTargetMT->GetTypeDefRid() && GetModule() == pTargetMT->GetModule() && @@ -1497,7 +1497,7 @@ BOOL MethodTable::CanCastByVarianceToInterfaceOrDelegate(MethodTable *pTargetMT, for (DWORD i = 0; i < inst.GetNumArgs(); i++) { TypeHandle thArg = inst[i]; - if (IsSpecialMarkerTypeForGenericCasting() && pMTInterfaceMapOwner && !pMTInterfaceMapOwner->ContainsGenericVariables()) + if (IsSpecialMarkerTypeForGenericCasting() && pMTInterfaceMapOwner && !pMTInterfaceMapOwner->GetWriteableData()->MayHaveOpenInterfacesInInterfaceMap()) { thArg = pMTInterfaceMapOwner; } @@ -1957,7 +1957,7 @@ NOINLINE BOOL MethodTable::ImplementsInterface(MethodTable *pInterface) { WRAPPER_NO_CONTRACT; - if (pInterface->IsSpecialMarkerTypeForGenericCasting()) + if (pInterface->IsSpecialMarkerTypeForGenericCasting() && !GetWriteableData()->MayHaveOpenInterfacesInInterfaceMap()) return FALSE; // The special marker types cannot be cast to (at this time, they are the open generic types, so they are however, valid input to this method). return ImplementsInterfaceInline(pInterface); @@ -1974,7 +1974,7 @@ BOOL MethodTable::ImplementsEquivalentInterface(MethodTable *pInterface) } CONTRACTL_END; - if (pInterface->IsSpecialMarkerTypeForGenericCasting()) + if (pInterface->IsSpecialMarkerTypeForGenericCasting() && !GetWriteableData()->MayHaveOpenInterfacesInInterfaceMap()) return FALSE; // The special marker types cannot be cast to (at this time, they are the open generic types, so they are however, valid input to this method). // look for exact match first (optimize for success) @@ -9568,12 +9568,13 @@ PTR_MethodTable MethodTable::InterfaceMapIterator::GetInterface(MethodTable* pMT GC_TRIGGERS; THROWS; PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); + PRECONDITION(CheckPointer(pMTOwner)); POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; MethodTable *pResult = m_pMap->GetMethodTable(); - if (pResult->IsSpecialMarkerTypeForGenericCasting() && !pMTOwner->ContainsGenericVariables()) + if (pResult->IsSpecialMarkerTypeForGenericCasting() && !pMTOwner->GetWriteableData()->MayHaveOpenInterfacesInInterfaceMap()) { TypeHandle ownerAsInst[MaxGenericParametersForSpecialMarkerType]; for (DWORD i = 0; i < MaxGenericParametersForSpecialMarkerType; i++) diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 69f16bec6ebdd4..f30fd7190f93c5 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -302,7 +302,7 @@ struct MethodTableWriteableData enum_flag_IsNotFullyLoaded = 0x00000040, enum_flag_DependenciesLoaded = 0x00000080, // class and all dependencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED - // enum_unused = 0x00000100, + enum_flag_MayHaveOpenInterfaceInInterfaceMap = 0x00000100, enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x00000200, // Is any field type or sub field type overrode Equals or GetHashCode enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x00000400, // Whether we have checked the overridden Equals or GetHashCode @@ -393,6 +393,17 @@ struct MethodTableWriteableData m_dwFlags &= ~(MethodTableWriteableData::enum_flag_HasApproxParent); } + + inline void SetMayHaveOpenInterfacesInInterfaceMap() + { + LIMITED_METHOD_CONTRACT; + InterlockedOr((LONG*)&m_dwFlags, MethodTableWriteableData::enum_flag_MayHaveOpenInterfaceInInterfaceMap); + } + + inline bool MayHaveOpenInterfacesInInterfaceMap() const + { + return !!(m_dwFlags & MethodTableWriteableData::enum_flag_MayHaveOpenInterfaceInInterfaceMap); + } }; // struct MethodTableWriteableData typedef DPTR(MethodTableWriteableData) PTR_MethodTableWriteableData; @@ -1970,7 +1981,7 @@ class MethodTable if (pCurrentMethodTable->HasSameTypeDefAs(pMT) && pMT->HasInstantiation() && pCurrentMethodTable->IsSpecialMarkerTypeForGenericCasting() && - !pMTOwner->ContainsGenericVariables() && + !pMTOwner->GetWriteableData()->MayHaveOpenInterfacesInInterfaceMap() && pMT->GetInstantiation().ContainsAllOneType(pMTOwner)) { exactMatch = true; diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 777080c7590179..f8b62de3e35d44 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1395,7 +1395,6 @@ FORCEINLINE BOOL MethodTable::ImplementsInterfaceInline(MethodTable *pInterface) NOTHROW; GC_NOTRIGGER; PRECONDITION(pInterface->IsInterface()); // class we are looking up should be an interface - PRECONDITION(!pInterface->IsSpecialMarkerTypeForGenericCasting()); } CONTRACTL_END; @@ -1428,7 +1427,7 @@ FORCEINLINE BOOL MethodTable::ImplementsInterfaceInline(MethodTable *pInterface) while (--numInterfaces); // Second scan, looking for the curiously recurring generic scenario - if (pInterface->HasInstantiation() && !ContainsGenericVariables() && pInterface->GetInstantiation().ContainsAllOneType(this)) + if (pInterface->HasInstantiation() && !GetWriteableData()->MayHaveOpenInterfacesInInterfaceMap() && pInterface->GetInstantiation().ContainsAllOneType(this)) { numInterfaces = GetNumInterfaces(); pInfo = GetInterfaceMap(); diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 47024106985eee..76ac3e7601768c 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -9341,6 +9341,10 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT) // to represent a type instantiated over its own generic variables, and the special marker type is currently the open type // and we make this case distinguishable by simply disallowing the optimization in those cases. bool retryWithExactInterfaces = !pMT->IsValueType() || pMT->IsSharedByGenericInstantiations() || pMT->ContainsGenericVariables(); + if (retryWithExactInterfaces) + { + pMT->GetWriteableDataForWrite()->SetMayHaveOpenInterfacesInInterfaceMap(); + } DWORD nAssigned = 0; do @@ -9407,6 +9411,7 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT) if (retry) { + pMT->GetWriteableDataForWrite()->SetMayHaveOpenInterfacesInInterfaceMap(); retryWithExactInterfaces = true; } } while (retry); diff --git a/src/tests/Loader/classloader/generics/Instantiation/Positive/CuriouslyRecurringThroughInterface.cs b/src/tests/Loader/classloader/generics/Instantiation/Positive/CuriouslyRecurringThroughInterface.cs index 0a091e138a876b..e74a23632c7b9a 100644 --- a/src/tests/Loader/classloader/generics/Instantiation/Positive/CuriouslyRecurringThroughInterface.cs +++ b/src/tests/Loader/classloader/generics/Instantiation/Positive/CuriouslyRecurringThroughInterface.cs @@ -1,3 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; + namespace CuriouslyRecurringPatternThroughInterface { interface IGeneric @@ -10,14 +16,85 @@ class CuriouslyRecurringThroughInterface : { } - class Program + class BaseClassWhereAImplementsB where A : B {} + interface ICuriouslyRecurring2 : IGeneric> + { + } + class DerivedCuriouslyRecurringThroughInterface : BaseClassWhereAImplementsB,ICuriouslyRecurring2>, ICuriouslyRecurring2 + { + } + + public class Program { static object _o; - static int Main() + + public static int Main() + { + TestIfCuriouslyRecurringInterfaceCanBeLoaded(); + TestIfCuriouslyRecurringInterfaceCanCast(); + TestIfCuriouslyRecurringInterfaceCanBeUsedAsConstraint(); + TestIfCuriouslyRecurringInterfaceCanBeUsedAsConstraintWorker(); + return 100; // Failures cause exceptions + } + + public static void TestIfCuriouslyRecurringInterfaceCanBeLoaded() { + Console.WriteLine("TestIfCuriouslyRecurringInterfaceCanBeLoaded"); + // Test that the a generic using a variant of the curiously recurring pattern involving an interface can be loaded. _o = typeof(CuriouslyRecurringThroughInterface); - return 100; + Console.WriteLine("Found type: {0}", _o); + Console.WriteLine("Curiously recurring interface: {0}", typeof(ICuriouslyRecurring<>)); + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetGenericArguments()[0]: {0}", typeof(ICuriouslyRecurring<>).GetGenericArguments()[0]); + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces().Length: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces().Length); + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0]: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0]); + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments().Length: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments().Length); + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0]: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0]); + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetGenericArguments()[0]: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetGenericArguments()[0]); + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetGenericArguments()[0]==typeof(ICuriouslyRecurring<>).GetGenericArguments()[0]: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetGenericArguments()[0]==typeof(ICuriouslyRecurring<>).GetGenericArguments()[0]); + if (!(typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetGenericArguments()[0]==typeof(ICuriouslyRecurring<>).GetGenericArguments()[0])) + { + throw new Exception("Fail checking for condition that should be true - 2"); + } + + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces().Length: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces().Length); + + // On CoreCLR this gets the Open type, which isn't really correct, but it has been that way for a very long time + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0]: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0]); + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0]==typeof(ICuriouslyRecurring<>): {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0]==typeof(ICuriouslyRecurring<>)); + + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0].GetGenericTypeDefinition()==typeof(ICuriouslyRecurring<>): {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0].GetGenericTypeDefinition()==typeof(ICuriouslyRecurring<>)); + + Console.WriteLine("typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0].GetGenericArguments()[0]==typeof(ICuriouslyRecurring<>)GetGenericArguments()[0]: {0}", typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0].GetGenericArguments()[0]==typeof(ICuriouslyRecurring<>).GetGenericArguments()[0]); + if (!(typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0].GetInterfaces()[0].GetGenericArguments()[0]==typeof(ICuriouslyRecurring<>).GetGenericArguments()[0])) + { + throw new Exception("Fail checking for condition that should be true - 2"); + } + } + + public static void TestIfCuriouslyRecurringInterfaceCanCast() + { + Console.WriteLine("TestIfCuriouslyRecurringInterfaceCanCast"); + Console.WriteLine("typeof(ICuriouslyRecurring<>).MakeGenericType(typeof(ICuriouslyRecurring<>).GetGenericArguments()[0]).IsAssignableFrom(typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0]): {0}", typeof(ICuriouslyRecurring<>).MakeGenericType(typeof(ICuriouslyRecurring<>).GetGenericArguments()[0]).IsAssignableFrom(typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0])); + if (!(typeof(ICuriouslyRecurring<>).MakeGenericType(typeof(ICuriouslyRecurring<>).GetGenericArguments()[0]).IsAssignableFrom(typeof(ICuriouslyRecurring<>).GetInterfaces()[0].GetGenericArguments()[0]))) + { + throw new Exception("Fail"); + } + } + + public static void TestIfCuriouslyRecurringInterfaceCanBeUsedAsConstraint() + { + Console.WriteLine("TestIfCuriouslyRecurringInterfaceCanBeUsedAsConstraint"); + TestIfCuriouslyRecurringInterfaceCanBeUsedAsConstraintWorker(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void TestIfCuriouslyRecurringInterfaceCanBeUsedAsConstraintWorker() + { + // Test that the a generic using a variant of the curiously recurring pattern involving an interface and constraint can be loaded. + // This test is just like TestIfCuriouslyRecurringInterfaceCanBeLoaded, except that it is structured so that we perform a cast via a constraint at type load time + _o = typeof(DerivedCuriouslyRecurringThroughInterface); + Console.WriteLine("Found type: {0}", _o); } } -} \ No newline at end of file +} From c804f58a6e594202c711a25281c80249e16079c2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Feb 2024 12:24:41 -0800 Subject: [PATCH 22/33] [release/8.0-staging] Move a lock to protect m_pDynamicStaticsInfo (#97352) * Move a lock to protect m_pDynamicStaticsInfo * apply feedback * cast to LONG * Fix access to m_pDynamicStaticsInfo (#97353) - Remove race condition where it is possible that an updated dynamic statics info pointer is published without ensuring that the data is also considered written. - Use VolatileLoadWithoutBarrier at the read site (where locks are not taken) to ensure that there are no difficult to examine reads of this pointer. --------- Co-authored-by: Hyungju Lee Co-authored-by: David Wrighton --- src/coreclr/vm/ceeload.cpp | 30 +++++++++++++----------------- src/coreclr/vm/ceeload.inl | 2 +- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 709ec1e5042984..f6e1cf37e4ebb5 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -1550,29 +1550,25 @@ DWORD Module::AllocateDynamicEntry(MethodTable *pMT) } CONTRACTL_END; - DWORD newId = InterlockedExchangeAdd((LONG*)&m_cDynamicEntries, 1); + CrstHolder ch(&m_Crst); + DWORD newId = (LONG)m_cDynamicEntries++; - if (newId >= VolatileLoad(&m_maxDynamicEntries)) + if (newId >= m_maxDynamicEntries) { - CrstHolder ch(&m_Crst); - - if (newId >= m_maxDynamicEntries) + SIZE_T maxDynamicEntries = max(16, m_maxDynamicEntries); + while (maxDynamicEntries <= newId) { - SIZE_T maxDynamicEntries = max(16, m_maxDynamicEntries); - while (maxDynamicEntries <= newId) - { - maxDynamicEntries *= 2; - } + maxDynamicEntries *= 2; + } - DynamicStaticsInfo* pNewDynamicStaticsInfo = (DynamicStaticsInfo*) - (void*)GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(DynamicStaticsInfo)) * S_SIZE_T(maxDynamicEntries)); + DynamicStaticsInfo* pNewDynamicStaticsInfo = (DynamicStaticsInfo*) + (void*)GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(DynamicStaticsInfo)) * S_SIZE_T(maxDynamicEntries)); - if (m_pDynamicStaticsInfo) - memcpy(pNewDynamicStaticsInfo, m_pDynamicStaticsInfo, sizeof(DynamicStaticsInfo) * m_maxDynamicEntries); + if (m_pDynamicStaticsInfo) + memcpy(pNewDynamicStaticsInfo, m_pDynamicStaticsInfo, sizeof(DynamicStaticsInfo) * m_maxDynamicEntries); - m_pDynamicStaticsInfo = pNewDynamicStaticsInfo; - VolatileStore(&m_maxDynamicEntries, maxDynamicEntries); - } + VolatileStore(&m_pDynamicStaticsInfo, pNewDynamicStaticsInfo); + m_maxDynamicEntries = maxDynamicEntries; } m_pDynamicStaticsInfo[newId].pEnclosingMT = pMT; diff --git a/src/coreclr/vm/ceeload.inl b/src/coreclr/vm/ceeload.inl index 8cd5189791b8c0..10bc879927a166 100644 --- a/src/coreclr/vm/ceeload.inl +++ b/src/coreclr/vm/ceeload.inl @@ -463,7 +463,7 @@ inline MethodTable* Module::GetDynamicClassMT(DWORD dynamicClassID) { LIMITED_METHOD_CONTRACT; _ASSERTE(m_cDynamicEntries > dynamicClassID); - return m_pDynamicStaticsInfo[dynamicClassID].pEnclosingMT; + return VolatileLoadWithoutBarrier(&m_pDynamicStaticsInfo)[dynamicClassID].pEnclosingMT; } #ifdef FEATURE_CODE_VERSIONING From f4075f3df6bc17138b591f99a151def41a7aa907 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 10 Feb 2024 09:32:52 -0800 Subject: [PATCH 23/33] Ensure that constant folding for SIMD shifts on xarch follow the correct behavior on overshift (#98001) (#98066) * Ensure that constant folding for SIMD shifts on xarch follow the correct behavior on overshift * Ensure we test Sse2.IsSupported --- src/coreclr/jit/hwintrinsicxarch.cpp | 2 +- src/coreclr/jit/simd.h | 54 ++++++++++++- src/coreclr/jit/valuenum.cpp | 75 +++++++++++++++++++ .../JitBlue/Runtime_93698/Runtime_93698.cs | 49 ++++++++++++ .../Runtime_93698/Runtime_93698.csproj | 8 ++ 5 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.csproj diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 065999982a87a9..3c8410a47ae353 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -924,7 +924,7 @@ GenTree* Compiler::impNonConstFallback(NamedIntrinsic intrinsic, var_types simdT GenTree* op2 = impPopStack().val; GenTree* op1 = impSIMDPopStack(); - GenTree* tmpOp = gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, op2, CORINFO_TYPE_INT, 16); + GenTree* tmpOp = gtNewSimdCreateScalarNode(TYP_SIMD16, op2, CORINFO_TYPE_INT, 16); return gtNewSimdHWIntrinsicNode(simdType, op1, tmpOp, intrinsic, simdBaseJitType, genTypeSize(simdType)); } diff --git a/src/coreclr/jit/simd.h b/src/coreclr/jit/simd.h index 478b0a1af4f4a3..9e8781714dbc41 100644 --- a/src/coreclr/jit/simd.h +++ b/src/coreclr/jit/simd.h @@ -453,7 +453,23 @@ void EvaluateUnarySimd(genTreeOps oper, bool scalar, var_types baseType, TSimd* template TBase EvaluateBinaryScalarRSZ(TBase arg0, TBase arg1) { - return arg0 >> (arg1 & ((sizeof(TBase) * 8) - 1)); +#if defined(TARGET_XARCH) + if ((arg1 < 0) || (arg1 >= (sizeof(TBase) * 8))) + { + // For SIMD, xarch allows overshifting and treats + // it as zeroing. So ensure we do the same here. + // + // The xplat APIs ensure the shiftAmount is masked + // to be within range, so we can't hit this for them. + + return static_cast(0); + } +#else + // Other platforms enforce masking in their encoding + assert((arg1 >= 0) && (arg1 < (sizeof(TBase) * 8))); +#endif + + return arg0 >> arg1; } template <> @@ -513,7 +529,22 @@ TBase EvaluateBinaryScalarSpecialized(genTreeOps oper, TBase arg0, TBase arg1) case GT_LSH: { - return arg0 << (arg1 & ((sizeof(TBase) * 8) - 1)); +#if defined(TARGET_XARCH) + if ((arg1 < 0) || (arg1 >= (sizeof(TBase) * 8))) + { + // For SIMD, xarch allows overshifting and treats + // it as zeroing. So ensure we do the same here. + // + // The xplat APIs ensure the shiftAmount is masked + // to be within range, so we can't hit this for them. + + return static_cast(0); + } +#else + // Other platforms enforce masking in their encoding + assert((arg1 >= 0) && (arg1 < (sizeof(TBase) * 8))); +#endif + return arg0 << arg1; } case GT_OR: @@ -535,7 +566,24 @@ TBase EvaluateBinaryScalarSpecialized(genTreeOps oper, TBase arg0, TBase arg1) case GT_RSH: { - return arg0 >> (arg1 & ((sizeof(TBase) * 8) - 1)); +#if defined(TARGET_XARCH) + if ((arg1 < 0) || (arg1 >= (sizeof(TBase) * 8))) + { + // For SIMD, xarch allows overshifting and treats + // it as propagating the sign bit (returning Zero + // or AllBitsSet). So ensure we do the same here. + // + // The xplat APIs ensure the shiftAmount is masked + // to be within range, so we can't hit this for them. + + arg0 >>= ((sizeof(TBase) * 8) - 1); + arg1 = static_cast(1); + } +#else + // Other platforms enforce masking in their encoding + assert((arg1 >= 0) && (arg1 < (sizeof(TBase) * 8))); +#endif + return arg0 >> arg1; } case GT_RSZ: diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 6943c3c5e07e26..259305a6aac7b1 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -7518,6 +7518,31 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type, case NI_AVX512BW_ShiftLeftLogical: #endif { +#ifdef TARGET_XARCH + if (TypeOfVN(arg1VN) == TYP_SIMD16) + { + // The xarch shift instructions support taking the shift amount as + // a simd16, in which case they take the shift amount from the lower + // 64-bits. + + uint64_t shiftAmount = GetConstantSimd16(arg1VN).u64[0]; + + if (genTypeSize(baseType) != 8) + { + if (shiftAmount > INT_MAX) + { + // Ensure we don't lose track the the amount is an overshift + shiftAmount = -1; + } + arg1VN = VNForIntCon(static_cast(shiftAmount)); + } + else + { + arg1VN = VNForLongCon(static_cast(shiftAmount)); + } + } +#endif // TARGET_XARCH + return EvaluateBinarySimd(this, GT_LSH, /* scalar */ false, type, baseType, arg0VN, arg1VN); } @@ -7531,6 +7556,31 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type, case NI_AVX512BW_ShiftRightArithmetic: #endif { +#ifdef TARGET_XARCH + if (TypeOfVN(arg1VN) == TYP_SIMD16) + { + // The xarch shift instructions support taking the shift amount as + // a simd16, in which case they take the shift amount from the lower + // 64-bits. + + uint64_t shiftAmount = GetConstantSimd16(arg1VN).u64[0]; + + if (genTypeSize(baseType) != 8) + { + if (shiftAmount > INT_MAX) + { + // Ensure we don't lose track the the amount is an overshift + shiftAmount = -1; + } + arg1VN = VNForIntCon(static_cast(shiftAmount)); + } + else + { + arg1VN = VNForLongCon(static_cast(shiftAmount)); + } + } +#endif // TARGET_XARCH + return EvaluateBinarySimd(this, GT_RSH, /* scalar */ false, type, baseType, arg0VN, arg1VN); } @@ -7543,6 +7593,31 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type, case NI_AVX512BW_ShiftRightLogical: #endif { +#ifdef TARGET_XARCH + if (TypeOfVN(arg1VN) == TYP_SIMD16) + { + // The xarch shift instructions support taking the shift amount as + // a simd16, in which case they take the shift amount from the lower + // 64-bits. + + uint64_t shiftAmount = GetConstantSimd16(arg1VN).u64[0]; + + if (genTypeSize(baseType) != 8) + { + if (shiftAmount > INT_MAX) + { + // Ensure we don't lose track the the amount is an overshift + shiftAmount = -1; + } + arg1VN = VNForIntCon(static_cast(shiftAmount)); + } + else + { + arg1VN = VNForLongCon(static_cast(shiftAmount)); + } + } +#endif // TARGET_XARCH + return EvaluateBinarySimd(this, GT_RSZ, /* scalar */ false, type, baseType, arg0VN, arg1VN); } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.cs b/src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.cs new file mode 100644 index 00000000000000..012387e9c656bc --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using Xunit; + +public static class Runtime_93698 +{ + [Fact] + public static void TestShiftLeftLogicalOvershift() + { + if (Sse2.IsSupported) + { + var result1 = Sse2.ShiftLeftLogical(Vector128.Create(-1, +2, -3, +4), 32); + Assert.Equal(Vector128.Zero, result1); + + var result2 = Sse2.ShiftLeftLogical(Vector128.Create(-5, +6, -7, +8), Vector128.Create(0, 32, 0, 0)); + Assert.Equal(Vector128.Zero, result2); + } + } + + [Fact] + public static void TestShiftRightLogicalOvershift() + { + if (Sse2.IsSupported) + { + var result1 = Sse2.ShiftRightLogical(Vector128.Create(-1, +2, -3, +4), 32); + Assert.Equal(Vector128.Zero, result1); + + var result2 = Sse2.ShiftRightLogical(Vector128.Create(-5, +6, -7, +8), Vector128.Create(0, 32, 0, 0)); + Assert.Equal(Vector128.Zero, result2); + } + } + + [Fact] + public static void TestShiftRightArithmeticOvershift() + { + if (Sse2.IsSupported) + { + var result1 = Sse2.ShiftRightArithmetic(Vector128.Create(-1, +2, -3, +4), 32); + Assert.Equal(Vector128.Create(-1, 0, -1, 0), result1); + + var result2 = Sse2.ShiftRightArithmetic(Vector128.Create(-5, +6, -7, +8), Vector128.Create(0, 32, 0, 0)); + Assert.Equal(Vector128.Create(-1, 0, -1, 0), result2); + } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_93698/Runtime_93698.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From d45a5762713620f859f6f671cd39cdccc0bb1497 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 10 Feb 2024 18:33:08 +0100 Subject: [PATCH 24/33] [release/8.0-staging] Ensure that the various `Max*Number` and `Min*Number` APIs optimize correctly (#98159) * Ensure that the various `Max*Number` and `Min*Number` APIs optimize correctly * Don't mark the test methods as AO * Add a missing using statement to the test --------- Co-authored-by: Tanner Gooding --- src/coreclr/jit/importercalls.cpp | 3 +- .../JitBlue/Runtime_98068/Runtime_98068.cs | 753 ++++++++++++++++++ .../Runtime_98068/Runtime_98068.csproj | 8 + 3 files changed, 763 insertions(+), 1 deletion(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_98068/Runtime_98068.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_98068/Runtime_98068.csproj diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index fc2d2376541445..e0c5cbb94e4733 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -8290,7 +8290,8 @@ GenTree* Compiler::impMinMaxIntrinsic(CORINFO_METHOD_HANDLE method, if (isNumber) { - std::swap(op1, op2); + // Swap the operands so that the cnsNode is op1, this prevents + // the unknown value (which could be NaN) from being selected. retNode->AsHWIntrinsic()->Op(1) = op2; retNode->AsHWIntrinsic()->Op(2) = op1; diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_98068/Runtime_98068.cs b/src/tests/JIT/Regression/JitBlue/Runtime_98068/Runtime_98068.cs new file mode 100644 index 00000000000000..26efaba4fd2d05 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_98068/Runtime_98068.cs @@ -0,0 +1,753 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public static class Runtime_98068 +{ + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestMax() + { + // Double + + Assert.Equal(Max(double.NaN, +1.0), Max_Value_One(double.NaN)); + Assert.Equal(Max(double.NaN, +0.0), Max_Value_Zero(double.NaN)); + Assert.Equal(Max(double.NaN, -0.0), Max_Value_NegZero(double.NaN)); + + Assert.Equal(Max(+1.0, double.NaN), Max_Value_NaN(+1.0)); + Assert.Equal(Max(+0.0, double.NaN), Max_Value_NaN(+0.0)); + Assert.Equal(Max(-0.0, double.NaN), Max_Value_NaN(-0.0)); + + // Single + + Assert.Equal(Max(float.NaN, +1.0f), Max_Value_One(float.NaN)); + Assert.Equal(Max(float.NaN, +0.0f), Max_Value_Zero(float.NaN)); + Assert.Equal(Max(float.NaN, -0.0f), Max_Value_NegZero(float.NaN)); + + Assert.Equal(Max(+1.0f, float.NaN), Max_Value_NaN(+1.0f)); + Assert.Equal(Max(+0.0f, float.NaN), Max_Value_NaN(+0.0f)); + Assert.Equal(Max(-0.0f, float.NaN), Max_Value_NaN(-0.0f)); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestMaxMagnitude() + { + // Double + + Assert.Equal(MaxMagnitude(double.NaN, +1.0), MaxMagnitude_Value_One(double.NaN)); + Assert.Equal(MaxMagnitude(double.NaN, +0.0), MaxMagnitude_Value_Zero(double.NaN)); + Assert.Equal(MaxMagnitude(double.NaN, -0.0), MaxMagnitude_Value_NegZero(double.NaN)); + + Assert.Equal(MaxMagnitude(+1.0, double.NaN), MaxMagnitude_Value_NaN(+1.0)); + Assert.Equal(MaxMagnitude(+0.0, double.NaN), MaxMagnitude_Value_NaN(+0.0)); + Assert.Equal(MaxMagnitude(-0.0, double.NaN), MaxMagnitude_Value_NaN(-0.0)); + + // Single + + Assert.Equal(MaxMagnitude(float.NaN, +1.0f), MaxMagnitude_Value_One(float.NaN)); + Assert.Equal(MaxMagnitude(float.NaN, +0.0f), MaxMagnitude_Value_Zero(float.NaN)); + Assert.Equal(MaxMagnitude(float.NaN, -0.0f), MaxMagnitude_Value_NegZero(float.NaN)); + + Assert.Equal(MaxMagnitude(+1.0f, float.NaN), MaxMagnitude_Value_NaN(+1.0f)); + Assert.Equal(MaxMagnitude(+0.0f, float.NaN), MaxMagnitude_Value_NaN(+0.0f)); + Assert.Equal(MaxMagnitude(-0.0f, float.NaN), MaxMagnitude_Value_NaN(-0.0f)); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestMaxMagnitudeNumber() + { + // Double + + Assert.Equal(MaxMagnitudeNumber(double.NaN, +1.0), MaxMagnitudeNumber_Value_One(double.NaN)); + Assert.Equal(MaxMagnitudeNumber(double.NaN, +0.0), MaxMagnitudeNumber_Value_Zero(double.NaN)); + Assert.Equal(MaxMagnitudeNumber(double.NaN, -0.0), MaxMagnitudeNumber_Value_NegZero(double.NaN)); + + Assert.Equal(MaxMagnitudeNumber(+1.0, double.NaN), MaxMagnitudeNumber_Value_NaN(+1.0)); + Assert.Equal(MaxMagnitudeNumber(+0.0, double.NaN), MaxMagnitudeNumber_Value_NaN(+0.0)); + Assert.Equal(MaxMagnitudeNumber(-0.0, double.NaN), MaxMagnitudeNumber_Value_NaN(-0.0)); + + // Single + + Assert.Equal(MaxMagnitudeNumber(float.NaN, +1.0f), MaxMagnitudeNumber_Value_One(float.NaN)); + Assert.Equal(MaxMagnitudeNumber(float.NaN, +0.0f), MaxMagnitudeNumber_Value_Zero(float.NaN)); + Assert.Equal(MaxMagnitudeNumber(float.NaN, -0.0f), MaxMagnitudeNumber_Value_NegZero(float.NaN)); + + Assert.Equal(MaxMagnitudeNumber(+1.0f, float.NaN), MaxMagnitudeNumber_Value_NaN(+1.0f)); + Assert.Equal(MaxMagnitudeNumber(+0.0f, float.NaN), MaxMagnitudeNumber_Value_NaN(+0.0f)); + Assert.Equal(MaxMagnitudeNumber(-0.0f, float.NaN), MaxMagnitudeNumber_Value_NaN(-0.0f)); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestMaxNumber() + { + // Double + + Assert.Equal(MaxNumber(double.NaN, +1.0), MaxNumber_Value_One(double.NaN)); + Assert.Equal(MaxNumber(double.NaN, +0.0), MaxNumber_Value_Zero(double.NaN)); + Assert.Equal(MaxNumber(double.NaN, -0.0), MaxNumber_Value_NegZero(double.NaN)); + + Assert.Equal(MaxNumber(+1.0, double.NaN), MaxNumber_Value_NaN(+1.0)); + Assert.Equal(MaxNumber(+0.0, double.NaN), MaxNumber_Value_NaN(+0.0)); + Assert.Equal(MaxNumber(-0.0, double.NaN), MaxNumber_Value_NaN(-0.0)); + + // Single + + Assert.Equal(MaxNumber(float.NaN, +1.0f), MaxNumber_Value_One(float.NaN)); + Assert.Equal(MaxNumber(float.NaN, +0.0f), MaxNumber_Value_Zero(float.NaN)); + Assert.Equal(MaxNumber(float.NaN, -0.0f), MaxNumber_Value_NegZero(float.NaN)); + + Assert.Equal(MaxNumber(+1.0f, float.NaN), MaxNumber_Value_NaN(+1.0f)); + Assert.Equal(MaxNumber(+0.0f, float.NaN), MaxNumber_Value_NaN(+0.0f)); + Assert.Equal(MaxNumber(-0.0f, float.NaN), MaxNumber_Value_NaN(-0.0f)); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestMin() + { + // Double + + Assert.Equal(Min(double.NaN, +1.0), Min_Value_One(double.NaN)); + Assert.Equal(Min(double.NaN, +0.0), Min_Value_Zero(double.NaN)); + Assert.Equal(Min(double.NaN, -0.0), Min_Value_NegZero(double.NaN)); + + Assert.Equal(Min(+1.0, double.NaN), Min_Value_NaN(+1.0)); + Assert.Equal(Min(+0.0, double.NaN), Min_Value_NaN(+0.0)); + Assert.Equal(Min(-0.0, double.NaN), Min_Value_NaN(-0.0)); + + // Single + + Assert.Equal(Min(float.NaN, +1.0f), Min_Value_One(float.NaN)); + Assert.Equal(Min(float.NaN, +0.0f), Min_Value_Zero(float.NaN)); + Assert.Equal(Min(float.NaN, -0.0f), Min_Value_NegZero(float.NaN)); + + Assert.Equal(Min(+1.0f, float.NaN), Min_Value_NaN(+1.0f)); + Assert.Equal(Min(+0.0f, float.NaN), Min_Value_NaN(+0.0f)); + Assert.Equal(Min(-0.0f, float.NaN), Min_Value_NaN(-0.0f)); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestMinMagnitude() + { + // Double + + Assert.Equal(MinMagnitude(double.NaN, +1.0), MinMagnitude_Value_One(double.NaN)); + Assert.Equal(MinMagnitude(double.NaN, +0.0), MinMagnitude_Value_Zero(double.NaN)); + Assert.Equal(MinMagnitude(double.NaN, -0.0), MinMagnitude_Value_NegZero(double.NaN)); + + Assert.Equal(MinMagnitude(+1.0, double.NaN), MinMagnitude_Value_NaN(+1.0)); + Assert.Equal(MinMagnitude(+0.0, double.NaN), MinMagnitude_Value_NaN(+0.0)); + Assert.Equal(MinMagnitude(-0.0, double.NaN), MinMagnitude_Value_NaN(-0.0)); + + // Single + + Assert.Equal(MinMagnitude(float.NaN, +1.0f), MinMagnitude_Value_One(float.NaN)); + Assert.Equal(MinMagnitude(float.NaN, +0.0f), MinMagnitude_Value_Zero(float.NaN)); + Assert.Equal(MinMagnitude(float.NaN, -0.0f), MinMagnitude_Value_NegZero(float.NaN)); + + Assert.Equal(MinMagnitude(+1.0f, float.NaN), MinMagnitude_Value_NaN(+1.0f)); + Assert.Equal(MinMagnitude(+0.0f, float.NaN), MinMagnitude_Value_NaN(+0.0f)); + Assert.Equal(MinMagnitude(-0.0f, float.NaN), MinMagnitude_Value_NaN(-0.0f)); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestMinMagnitudeNumber() + { + // Double + + Assert.Equal(MinMagnitudeNumber(double.NaN, +1.0), MinMagnitudeNumber_Value_One(double.NaN)); + Assert.Equal(MinMagnitudeNumber(double.NaN, +0.0), MinMagnitudeNumber_Value_Zero(double.NaN)); + Assert.Equal(MinMagnitudeNumber(double.NaN, -0.0), MinMagnitudeNumber_Value_NegZero(double.NaN)); + + Assert.Equal(MinMagnitudeNumber(+1.0, double.NaN), MinMagnitudeNumber_Value_NaN(+1.0)); + Assert.Equal(MinMagnitudeNumber(+0.0, double.NaN), MinMagnitudeNumber_Value_NaN(+0.0)); + Assert.Equal(MinMagnitudeNumber(-0.0, double.NaN), MinMagnitudeNumber_Value_NaN(-0.0)); + + // Single + + Assert.Equal(MinMagnitudeNumber(float.NaN, +1.0f), MinMagnitudeNumber_Value_One(float.NaN)); + Assert.Equal(MinMagnitudeNumber(float.NaN, +0.0f), MinMagnitudeNumber_Value_Zero(float.NaN)); + Assert.Equal(MinMagnitudeNumber(float.NaN, -0.0f), MinMagnitudeNumber_Value_NegZero(float.NaN)); + + Assert.Equal(MinMagnitudeNumber(+1.0f, float.NaN), MinMagnitudeNumber_Value_NaN(+1.0f)); + Assert.Equal(MinMagnitudeNumber(+0.0f, float.NaN), MinMagnitudeNumber_Value_NaN(+0.0f)); + Assert.Equal(MinMagnitudeNumber(-0.0f, float.NaN), MinMagnitudeNumber_Value_NaN(-0.0f)); + } + + [Fact] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestMinNumber() + { + // Double + + Assert.Equal(MinNumber(double.NaN, +1.0), MinNumber_Value_One(double.NaN)); + Assert.Equal(MinNumber(double.NaN, +0.0), MinNumber_Value_Zero(double.NaN)); + Assert.Equal(MinNumber(double.NaN, -0.0), MinNumber_Value_NegZero(double.NaN)); + + Assert.Equal(MinNumber(+1.0, double.NaN), MinNumber_Value_NaN(+1.0)); + Assert.Equal(MinNumber(+0.0, double.NaN), MinNumber_Value_NaN(+0.0)); + Assert.Equal(MinNumber(-0.0, double.NaN), MinNumber_Value_NaN(-0.0)); + + // Single + + Assert.Equal(MinNumber(float.NaN, +1.0f), MinNumber_Value_One(float.NaN)); + Assert.Equal(MinNumber(float.NaN, +0.0f), MinNumber_Value_Zero(float.NaN)); + Assert.Equal(MinNumber(float.NaN, -0.0f), MinNumber_Value_NegZero(float.NaN)); + + Assert.Equal(MinNumber(+1.0f, float.NaN), MinNumber_Value_NaN(+1.0f)); + Assert.Equal(MinNumber(+0.0f, float.NaN), MinNumber_Value_NaN(+0.0f)); + Assert.Equal(MinNumber(-0.0f, float.NaN), MinNumber_Value_NaN(-0.0f)); + } + + // + // Max.Double + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double Max(double left, double right) + { + return double.Max(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static double Max_Value_One(double value) + { + return double.Max(value, +1.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double Max_Value_NaN(double value) + { + return double.Max(value, double.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double Max_Value_NegZero(double value) + { + return double.Max(value, -0.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double Max_Value_Zero(double value) + { + return double.Max(value, +0.0); + } + + // + // Max.Single + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Max(float left, float right) + { + return float.Max(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static float Max_Value_One(float value) + { + return float.Max(value, +1.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Max_Value_NaN(float value) + { + return float.Max(value, float.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Max_Value_NegZero(float value) + { + return float.Max(value, -0.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Max_Value_Zero(float value) + { + return float.Max(value, +0.0f); + } + + // + // MaxMagnitude.Double + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxMagnitude(double left, double right) + { + return double.MaxMagnitude(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static double MaxMagnitude_Value_One(double value) + { + return double.MaxMagnitude(value, +1.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxMagnitude_Value_NaN(double value) + { + return double.MaxMagnitude(value, double.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxMagnitude_Value_NegZero(double value) + { + return double.MaxMagnitude(value, -0.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxMagnitude_Value_Zero(double value) + { + return double.MaxMagnitude(value, +0.0); + } + + // + // MaxMagnitude.Single + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxMagnitude(float left, float right) + { + return float.MaxMagnitude(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static float MaxMagnitude_Value_One(float value) + { + return float.MaxMagnitude(value, +1.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxMagnitude_Value_NaN(float value) + { + return float.MaxMagnitude(value, float.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxMagnitude_Value_NegZero(float value) + { + return float.MaxMagnitude(value, -0.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxMagnitude_Value_Zero(float value) + { + return float.MaxMagnitude(value, +0.0f); + } + + // + // MaxMagnitudeNumber.Double + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxMagnitudeNumber(double left, double right) + { + return double.MaxMagnitudeNumber(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static double MaxMagnitudeNumber_Value_One(double value) + { + return double.MaxMagnitudeNumber(value, +1.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxMagnitudeNumber_Value_NaN(double value) + { + return double.MaxMagnitudeNumber(value, double.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxMagnitudeNumber_Value_NegZero(double value) + { + return double.MaxMagnitudeNumber(value, -0.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxMagnitudeNumber_Value_Zero(double value) + { + return double.MaxMagnitudeNumber(value, +0.0); + } + + // + // MaxMagnitudeNumber.Single + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxMagnitudeNumber(float left, float right) + { + return float.MaxMagnitudeNumber(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static float MaxMagnitudeNumber_Value_One(float value) + { + return float.MaxMagnitudeNumber(value, +1.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxMagnitudeNumber_Value_NaN(float value) + { + return float.MaxMagnitudeNumber(value, float.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxMagnitudeNumber_Value_NegZero(float value) + { + return float.MaxMagnitudeNumber(value, -0.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxMagnitudeNumber_Value_Zero(float value) + { + return float.MaxMagnitudeNumber(value, +0.0f); + } + + // + // MaxNumber.Double + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxNumber(double left, double right) + { + return double.MaxNumber(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static double MaxNumber_Value_One(double value) + { + return double.MaxNumber(value, +1.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxNumber_Value_NaN(double value) + { + return double.MaxNumber(value, double.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxNumber_Value_NegZero(double value) + { + return double.MaxNumber(value, -0.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MaxNumber_Value_Zero(double value) + { + return double.MaxNumber(value, +0.0); + } + + // + // MaxNumber.Single + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxNumber(float left, float right) + { + return float.MaxNumber(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static float MaxNumber_Value_One(float value) + { + return float.MaxNumber(value, +1.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxNumber_Value_NaN(float value) + { + return float.MaxNumber(value, float.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxNumber_Value_NegZero(float value) + { + return float.MaxNumber(value, -0.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MaxNumber_Value_Zero(float value) + { + return float.MaxNumber(value, +0.0f); + } + + // + // Min.Double + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double Min(double left, double right) + { + return double.Min(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static double Min_Value_One(double value) + { + return double.Min(value, +1.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double Min_Value_NaN(double value) + { + return double.Min(value, double.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double Min_Value_NegZero(double value) + { + return double.Min(value, -0.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double Min_Value_Zero(double value) + { + return double.Min(value, +0.0); + } + + // + // Min.Single + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Min(float left, float right) + { + return float.Min(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static float Min_Value_One(float value) + { + return float.Min(value, +1.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Min_Value_NaN(float value) + { + return float.Min(value, float.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Min_Value_NegZero(float value) + { + return float.Min(value, -0.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float Min_Value_Zero(float value) + { + return float.Min(value, +0.0f); + } + + // + // MinMagnitude.Double + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinMagnitude(double left, double right) + { + return double.MinMagnitude(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static double MinMagnitude_Value_One(double value) + { + return double.MinMagnitude(value, +1.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinMagnitude_Value_NaN(double value) + { + return double.MinMagnitude(value, double.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinMagnitude_Value_NegZero(double value) + { + return double.MinMagnitude(value, -0.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinMagnitude_Value_Zero(double value) + { + return double.MinMagnitude(value, +0.0); + } + + // + // MinMagnitude.Single + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinMagnitude(float left, float right) + { + return float.MinMagnitude(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static float MinMagnitude_Value_One(float value) + { + return float.MinMagnitude(value, +1.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinMagnitude_Value_NaN(float value) + { + return float.MinMagnitude(value, float.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinMagnitude_Value_NegZero(float value) + { + return float.MinMagnitude(value, -0.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinMagnitude_Value_Zero(float value) + { + return float.MinMagnitude(value, +0.0f); + } + + // + // MinMagnitudeNumber.Double + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinMagnitudeNumber(double left, double right) + { + return double.MinMagnitudeNumber(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static double MinMagnitudeNumber_Value_One(double value) + { + return double.MinMagnitudeNumber(value, +1.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinMagnitudeNumber_Value_NaN(double value) + { + return double.MinMagnitudeNumber(value, double.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinMagnitudeNumber_Value_NegZero(double value) + { + return double.MinMagnitudeNumber(value, -0.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinMagnitudeNumber_Value_Zero(double value) + { + return double.MinMagnitudeNumber(value, +0.0); + } + + // + // MinMagnitudeNumber.Single + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinMagnitudeNumber(float left, float right) + { + return float.MinMagnitudeNumber(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static float MinMagnitudeNumber_Value_One(float value) + { + return float.MinMagnitudeNumber(value, +1.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinMagnitudeNumber_Value_NaN(float value) + { + return float.MinMagnitudeNumber(value, float.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinMagnitudeNumber_Value_NegZero(float value) + { + return float.MinMagnitudeNumber(value, -0.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinMagnitudeNumber_Value_Zero(float value) + { + return float.MinMagnitudeNumber(value, +0.0f); + } + + // + // MinNumber.Double + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinNumber(double left, double right) + { + return double.MinNumber(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static double MinNumber_Value_One(double value) + { + return double.MinNumber(value, +1.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinNumber_Value_NaN(double value) + { + return double.MinNumber(value, double.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinNumber_Value_NegZero(double value) + { + return double.MinNumber(value, -0.0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static double MinNumber_Value_Zero(double value) + { + return double.MinNumber(value, +0.0); + } + + // + // MinNumber.Single + // + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinNumber(float left, float right) + { + return float.MinNumber(left, right); + } + + [MethodImpl(MethodImplOptions.NoInlining| MethodImplOptions.AggressiveOptimization)] + public static float MinNumber_Value_One(float value) + { + return float.MinNumber(value, +1.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinNumber_Value_NaN(float value) + { + return float.MinNumber(value, float.NaN); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinNumber_Value_NegZero(float value) + { + return float.MinNumber(value, -0.0f); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static float MinNumber_Value_Zero(float value) + { + return float.MinNumber(value, +0.0f); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_98068/Runtime_98068.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_98068/Runtime_98068.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_98068/Runtime_98068.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From ff4e048ecabcac608e2cd10281efc3f043b7c6fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 11 Feb 2024 15:46:22 -0800 Subject: [PATCH 25/33] Define installer-owned directories (#98241) Co-authored-by: Nikola Milosavljevic --- .../Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props | 1 + 1 file changed, 1 insertion(+) diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props index 6907e829c384f3..b9af46ba7258bf 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props @@ -61,6 +61,7 @@ + From 2190e9be7e942f8037cd7318527086805a305150 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Mon, 12 Feb 2024 09:26:16 +0100 Subject: [PATCH 26/33] Fix Windows implementation of NegotiateAuthenticationPal.GetMIC (#98031) --- .../src/System/Net/NegotiateAuthenticationPal.Windows.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs index 07e8dea22baa9c..6a136c4a1c59df 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs @@ -566,7 +566,7 @@ public override unsafe void GetMIC(ReadOnlySpan message, IBufferWriter signatureBuffer = signature.GetSpan(sizes.cbSecurityTrailer); + Span signatureBuffer = signature.GetSpan(sizes.cbMaxSignature); fixed (byte* messagePtr = message) fixed (byte* signaturePtr = signatureBuffer) @@ -577,7 +577,7 @@ public override unsafe void GetMIC(ReadOnlySpan message, IBufferWriterBufferType = SecurityBufferType.SECBUFFER_TOKEN; tokenBuffer->pvBuffer = (IntPtr)signaturePtr; - tokenBuffer->cbBuffer = sizes.cbSecurityTrailer; + tokenBuffer->cbBuffer = sizes.cbMaxSignature; dataBuffer->BufferType = SecurityBufferType.SECBUFFER_DATA; dataBuffer->pvBuffer = (IntPtr)messagePtr; dataBuffer->cbBuffer = message.Length; @@ -597,7 +597,7 @@ public override unsafe void GetMIC(ReadOnlySpan message, IBufferWritercbBuffer); } } finally From dedae5e0a7cdeb2b86243d3fe48268b7b5e065ed Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Mon, 12 Feb 2024 17:59:08 +0100 Subject: [PATCH 27/33] [release/8.0-staging] Fix constant folding for arm64 MultiplyByScalar operations involving Vector2.One (#98150) MultiplyByScalar on ARM64 should not be handled by the same path as other multiplications since it has different behavior. --- src/coreclr/jit/valuenum.cpp | 32 +++++++++++++++++-- .../JitBlue/Runtime_93876/Runtime_93876.cs | 25 +++++++++++++++ .../Runtime_93876/Runtime_93876.csproj | 8 +++++ 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_93876/Runtime_93876.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_93876/Runtime_93876.csproj diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 259305a6aac7b1..fa60633afbc233 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -7809,10 +7809,38 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type, } #ifdef TARGET_ARM64 - case NI_AdvSimd_Multiply: case NI_AdvSimd_MultiplyByScalar: - case NI_AdvSimd_Arm64_Multiply: case NI_AdvSimd_Arm64_MultiplyByScalar: + { + if (!varTypeIsFloating(baseType)) + { + // Handle `x * 0 == 0` and `0 * x == 0` + // Not safe for floating-point when x == -0.0, NaN, +Inf, -Inf + ValueNum zeroVN = VNZeroForType(TypeOfVN(cnsVN)); + + if (cnsVN == zeroVN) + { + return VNZeroForType(type); + } + } + + assert((TypeOfVN(arg0VN) == type) && (TypeOfVN(arg1VN) == TYP_SIMD8)); + + // Handle x * 1 => x, but only if the scalar RHS is <1, ...>. + if (IsVNConstant(arg1VN)) + { + if (EvaluateSimdGetElement(this, TYP_SIMD8, baseType, arg1VN, 0) == VNOneForType(baseType)) + { + return arg0VN; + } + } + break; + } +#endif + +#ifdef TARGET_ARM64 + case NI_AdvSimd_Multiply: + case NI_AdvSimd_Arm64_Multiply: #else case NI_SSE_Multiply: case NI_SSE2_Multiply: diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_93876/Runtime_93876.cs b/src/tests/JIT/Regression/JitBlue/Runtime_93876/Runtime_93876.cs new file mode 100644 index 00000000000000..760cd04a594e3e --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_93876/Runtime_93876.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Numerics; +using Xunit; + +public static class Runtime_93876 +{ + [Fact] + public static void Problem() + { + Vector4 v = Mul(0, 1); + Assert.Equal(Vector4.One, v); + Vector64 v64 = Mul64(0, 1); + Assert.Equal(Vector64.One, v64); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector4 Mul(float a, float b) => Vector4.Multiply(a + b, Vector4.One); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector64 Mul64(float a, float b) => Vector64.Multiply(a + b, Vector64.One); +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_93876/Runtime_93876.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_93876/Runtime_93876.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_93876/Runtime_93876.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From bb540a87535a1d51828eed38d0f04998e1fb8f55 Mon Sep 17 00:00:00 2001 From: Vladimir Sadov Date: Mon, 12 Feb 2024 07:05:42 -1000 Subject: [PATCH 28/33] [NativeAOT][8.0] Use ld_classic in ILC build and in build integration (#97856) * use ld_classic in ILC build and in build integration * PR feedback * Maybe fix the build for non-apple * Update src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets PR feedback Co-authored-by: Jan Kotas --------- Co-authored-by: Jan Kotas --- .../Microsoft.NETCore.Native.Unix.targets | 13 +++++++++++++ src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets index 71acdacdadd10a..c9ae3083cf5cd4 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets @@ -166,6 +166,19 @@ The .NET Foundation licenses this file to you under the MIT license. + + + + + + + <_XcodeVersion>$([System.Text.RegularExpressions.Regex]::Match($(_XcodeVersionString), '[1-9]\d*')) + + + + + + <_CommandProbe>command -v <_CommandProbe Condition="$([MSBuild]::IsOSPlatform('Windows'))">where /Q diff --git a/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj b/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj index 7122c81034ff31..7c25444f209c33 100644 --- a/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj @@ -70,6 +70,19 @@ + + + + + + + <_XcodeVersion>$([System.Text.RegularExpressions.Regex]::Match($(_XcodeVersionString), '[1-9]\d*')) + + + + + + $(_CC_LDFLAGS.SubString(0, $(_CC_LDFLAGS.IndexOf(';')))) <_LDFLAGS>$(_CC_LDFLAGS.SubString($([MSBuild]::Add($(_CC_LDFLAGS.IndexOf(';')), 1)))) From ba68cf1d1091526397a2c655ff931f6678d1262f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 14:35:43 -0300 Subject: [PATCH 29/33] Fix side effect of only not sending assembly_load while invoking methods. (#98254) Co-authored-by: Thays Grazia --- src/mono/mono/component/debugger-agent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index c9199635d15d59..80918c38876824 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -4149,7 +4149,7 @@ jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) if (assembly) { DebuggerTlsData *tls; tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); - if (tls->invoke == NULL) { + if (!CHECK_ICORDBG (TRUE) || tls->invoke == NULL) { process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, assembly); } else { assembly_load(prof, assembly); //send later From 6dec8dd10ca45d925fb3577be9cfd44a4822b7fc Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Mon, 12 Feb 2024 09:47:17 -0800 Subject: [PATCH 30/33] Fix polluted CompareState when comparing element types in a signature (#98249) We were propagating state from each type in the method signature to the comparisons for the next type. This resulted in type equivalence checks being disabled for any parameters that came after a generic parameter. --- src/coreclr/vm/siginfo.cpp | 12 +-- .../typeequivalence/contracts/Types.cs | 6 ++ .../typeequivalence/impl/Impls.cs | 12 +++ .../typeequivalence/simple/Simple.cs | 87 ++++++++++--------- 4 files changed, 68 insertions(+), 49 deletions(-) diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index eb35f3a372538f..3342a27178f50c 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -4204,8 +4204,6 @@ MetaSig::CompareTypeDefsUnderSubstitutions( SigPointer inst1 = pSubst1->GetInst(); SigPointer inst2 = pSubst2->GetInst(); - TokenPairList visited { pVisited }; - CompareState state{ &visited }; for (DWORD i = 0; i < pTypeDef1->GetNumGenericArgs(); i++) { PCCOR_SIGNATURE startInst1 = inst1.GetPtr(); @@ -4214,6 +4212,8 @@ MetaSig::CompareTypeDefsUnderSubstitutions( PCCOR_SIGNATURE startInst2 = inst2.GetPtr(); IfFailThrow(inst2.SkipExactlyOne()); PCCOR_SIGNATURE endInst2ptr = inst2.GetPtr(); + TokenPairList visited{ pVisited }; + CompareState state{ &visited }; if (!CompareElementType( startInst1, startInst2, @@ -4382,8 +4382,6 @@ MetaSig::CompareMethodSigs( IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &ArgCount1)); IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &ArgCount2)); - TokenPairList visited{ pVisited }; - if (ArgCount1 != ArgCount2) { if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_VARARG) @@ -4405,7 +4403,6 @@ MetaSig::CompareMethodSigs( // to correctly handle overloads, where there are a number of varargs methods // to pick from, like m1(int,...) and m2(int,int,...), etc. - CompareState state{ &visited }; // <= because we want to include a check of the return value! for (i = 0; i <= ArgCount1; i++) { @@ -4437,6 +4434,8 @@ MetaSig::CompareMethodSigs( else { // We are in bounds on both sides. Compare the element. + TokenPairList visited{ pVisited }; + CompareState state{ &visited }; if (!CompareElementType( pSig1, pSig2, @@ -4461,7 +4460,6 @@ MetaSig::CompareMethodSigs( } // do return type as well - CompareState state{ &visited }; for (i = 0; i <= ArgCount1; i++) { if (i == 0 && skipReturnTypeSig) @@ -4476,6 +4474,8 @@ MetaSig::CompareMethodSigs( } else { + TokenPairList visited{ pVisited }; + CompareState state{ &visited }; if (!CompareElementType( pSig1, pSig2, diff --git a/src/tests/baseservices/typeequivalence/contracts/Types.cs b/src/tests/baseservices/typeequivalence/contracts/Types.cs index a9fc0270a1bdd0..539e83318fc506 100644 --- a/src/tests/baseservices/typeequivalence/contracts/Types.cs +++ b/src/tests/baseservices/typeequivalence/contracts/Types.cs @@ -61,6 +61,12 @@ public interface ISparseType int MultiplyBy20(int a); } + [Guid("BD752276-52DF-4CD1-8C62-49D202F15C8D")] + public struct TestValueType + { + public int Field; + } + // // Below types are used in type punning tests and shouldn't be used anywhere else. // diff --git a/src/tests/baseservices/typeequivalence/impl/Impls.cs b/src/tests/baseservices/typeequivalence/impl/Impls.cs index dd0ce12eec9baa..55117a68236175 100644 --- a/src/tests/baseservices/typeequivalence/impl/Impls.cs +++ b/src/tests/baseservices/typeequivalence/impl/Impls.cs @@ -130,3 +130,15 @@ public static int GetField_3(OnlyLoadOnce_3 s) return s.Field; } } + +public static class MethodCall +{ + // Include a generic type in the method signature before the type using type equivalence to ensure that + // processing of the generic type does not affect subsequent type processing during signature comparison. + public static System.Collections.Generic.List InterfaceAfterGeneric(IEmptyType t) => null; + public static System.Collections.Generic.List ValueTypeAfterGeneric(TestValueType t) => null; + + // Generic type after the type using type equivalence should also not affect processing. + public static void InterfaceBeforeGeneric(IEmptyType t, System.Collections.Generic.List l) { } + public static void ValueTypeBeforeGeneric(TestValueType t, System.Collections.Generic.List l) { } +} diff --git a/src/tests/baseservices/typeequivalence/simple/Simple.cs b/src/tests/baseservices/typeequivalence/simple/Simple.cs index 7595199a120e16..24e1c9684c70d4 100644 --- a/src/tests/baseservices/typeequivalence/simple/Simple.cs +++ b/src/tests/baseservices/typeequivalence/simple/Simple.cs @@ -17,6 +17,7 @@ public struct EquivalentValueType public int A; } +[PlatformSpecific(TestPlatforms.Windows)] public class Simple { private class EmptyType2 : IEmptyType @@ -30,7 +31,8 @@ public static object Create() } } - private static void InterfaceTypesFromDifferentAssembliesAreEquivalent() + [Fact] + public static void InterfaceTypesFromDifferentAssembliesAreEquivalent() { Console.WriteLine($"{nameof(InterfaceTypesFromDifferentAssembliesAreEquivalent)}"); var inAsm = EmptyType.Create(); @@ -44,9 +46,10 @@ void AreNotSameObject(IEmptyType a, IEmptyType b) } } - private static void ValidateTypeInstanceEquality() + [Fact] + public static void TypeInstanceEquality() { - Console.WriteLine($"{nameof(ValidateTypeInstanceEquality)}"); + Console.WriteLine($"{nameof(TypeInstanceEquality)}"); var inAsm = EmptyType.Create(); var otherAsm = EmptyType2.Create(); @@ -110,7 +113,8 @@ public override string ScaleString(string s) } } - private static void InterfaceTypesMethodOperations() + [Fact] + public static void InterfaceTypesMethodOperations() { Console.WriteLine($"{nameof(InterfaceTypesMethodOperations)}"); @@ -141,7 +145,8 @@ private static void InterfaceTypesMethodOperations() } } - private static void CallSparseInterface() + [Fact] + public static void CallSparseInterface() { Console.WriteLine($"{nameof(CallSparseInterface)}"); @@ -156,9 +161,10 @@ private static void CallSparseInterface() Assert.Equal(input * 18, sparseType.MultiplyBy18(input)); } - private static void TestArrayEquivalence() + [Fact] + public static void ArrayEquivalence() { - Console.WriteLine($"{nameof(TestArrayEquivalence)}"); + Console.WriteLine($"{nameof(ArrayEquivalence)}"); var inAsm = EmptyType.Create(); var otherAsm = EmptyType2.Create(); @@ -173,9 +179,10 @@ private static void TestArrayEquivalence() Assert.False(inAsmInterfaceType.MakeArrayType(1).IsEquivalentTo(otherAsmInterfaceType.MakeArrayType(2))); } - private static void TestByRefEquivalence() + [Fact] + public static void ByRefEquivalence() { - Console.WriteLine($"{nameof(TestByRefEquivalence)}"); + Console.WriteLine($"{nameof(ByRefEquivalence)}"); var inAsm = EmptyType.Create(); var otherAsm = EmptyType2.Create(); @@ -197,9 +204,10 @@ public void Method(V input) } } - private static void TestGenericClassNonEquivalence() + [Fact] + public static void GenericClassNonEquivalence() { - Console.WriteLine($"{nameof(TestGenericClassNonEquivalence)}"); + Console.WriteLine($"{nameof(GenericClassNonEquivalence)}"); var inAsm = EmptyType.Create(); var otherAsm = EmptyType2.Create(); @@ -209,9 +217,10 @@ private static void TestGenericClassNonEquivalence() Assert.False(typeof(Generic<>).MakeGenericType(inAsmInterfaceType).IsEquivalentTo(typeof(Generic<>).MakeGenericType(otherAsmInterfaceType))); } - private static void TestGenericInterfaceEquivalence() + [Fact] + public static void GenericInterfaceEquivalence() { - Console.WriteLine($"{nameof(TestGenericInterfaceEquivalence)}"); + Console.WriteLine($"{nameof(GenericInterfaceEquivalence)}"); var inAsm = EmptyType.Create(); var otherAsm = EmptyType2.Create(); @@ -221,9 +230,10 @@ private static void TestGenericInterfaceEquivalence() Assert.True(typeof(IGeneric<>).MakeGenericType(inAsmInterfaceType).IsEquivalentTo(typeof(IGeneric<>).MakeGenericType(otherAsmInterfaceType))); } - private static unsafe void TestTypeEquivalenceWithTypePunning() + [Fact] + public static unsafe void TypeEquivalenceWithTypePunning() { - Console.WriteLine($"{nameof(TestTypeEquivalenceWithTypePunning)}"); + Console.WriteLine($"{nameof(TypeEquivalenceWithTypePunning)}"); { Console.WriteLine($"-- GetFunctionPointer()"); @@ -260,10 +270,11 @@ private static unsafe void TestTypeEquivalenceWithTypePunning() } } + [Fact] [MethodImpl (MethodImplOptions.NoInlining)] - private static void TestLoadingValueTypesWithMethod() + public static void LoadValueTypesWithMethod() { - Console.WriteLine($"{nameof(TestLoadingValueTypesWithMethod)}"); + Console.WriteLine($"{nameof(LoadValueTypesWithMethod)}"); Console.WriteLine($"-- {typeof(ValueTypeWithStaticMethod).Name}"); Assert.Throws(() => LoadInvalidType()); } @@ -274,7 +285,8 @@ private static void LoadInvalidType() Console.WriteLine($"-- {typeof(ValueTypeWithInstanceMethod).Name}"); } - private static void TestCastsOptimizations() + [Fact] + public static void CastsOptimizations() { string otherTypeName = $"{typeof(EquivalentValueType).FullName},{typeof(EmptyType).Assembly.GetName().Name}"; Type otherEquivalentValueType = Type.GetType(otherTypeName); @@ -285,32 +297,21 @@ private static void TestCastsOptimizations() EquivalentValueType inst = (EquivalentValueType)otherEquivalentValueTypeInstance; } - public static int Main() + [Fact] + public static void MethodCallSignature() { - if (!OperatingSystem.IsWindows()) - { - return 100; - } - try - { - InterfaceTypesFromDifferentAssembliesAreEquivalent(); - ValidateTypeInstanceEquality(); - InterfaceTypesMethodOperations(); - CallSparseInterface(); - TestByRefEquivalence(); - TestArrayEquivalence(); - TestGenericClassNonEquivalence(); - TestGenericInterfaceEquivalence(); - TestTypeEquivalenceWithTypePunning(); - TestLoadingValueTypesWithMethod(); - TestCastsOptimizations(); - } - catch (Exception e) - { - Console.WriteLine($"Test Failure: {e}"); - return 101; - } + Console.WriteLine($"{nameof(MethodCallSignature)}"); + + Console.WriteLine($"-- {nameof(MethodCall.InterfaceAfterGeneric)}"); + MethodCall.InterfaceAfterGeneric((IEmptyType)EmptyType2.Create()); + + Console.WriteLine($"-- {nameof(MethodCall.ValueTypeAfterGeneric)}"); + MethodCall.ValueTypeAfterGeneric(new TestValueType()); + + Console.WriteLine($"-- {nameof(MethodCall.InterfaceBeforeGeneric)}"); + MethodCall.InterfaceBeforeGeneric((IEmptyType)EmptyType2.Create(), null); - return 100; + Console.WriteLine($"-- {nameof(MethodCall.ValueTypeBeforeGeneric)}"); + MethodCall.ValueTypeBeforeGeneric(new TestValueType(), null); } } From 95988727574bd17962fa2d7e54525446835a9ebb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 09:57:32 -0800 Subject: [PATCH 31/33] [release/8.0-staging] Update dependencies from dotnet/emsdk (#97405) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update dependencies from /~https://github.com/dotnet/emsdk build 20240123.1 Microsoft.SourceBuild.Intermediate.emsdk , Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100 From Version 8.0.2-servicing.24062.1 -> To Version 8.0.2-servicing.24073.1 * Update dependencies from /~https://github.com/dotnet/emsdk build 20240208.3 Microsoft.SourceBuild.Intermediate.emsdk , Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100 From Version 8.0.2-servicing.24062.1 -> To Version 8.0.3-servicing.24108.3 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- NuGet.config | 5 +---- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/NuGet.config b/NuGet.config index 12fa8c8879cdb6..a681bc250bc9ed 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,10 +9,7 @@ - - - - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 04a7792f12c29a..4e522812e23bc7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -90,13 +90,13 @@ 45dd3a73dd5b64b010c4251303b3664bb30df029 - + /~https://github.com/dotnet/emsdk - 2fc2ffd960930318f33fcaa690cbdbc55d72f52d + 9a29abdd764a4de0f253ed368871877a47725247 - + /~https://github.com/dotnet/emsdk - 2fc2ffd960930318f33fcaa690cbdbc55d72f52d + 9a29abdd764a4de0f253ed368871877a47725247 diff --git a/eng/Versions.props b/eng/Versions.props index 05d877f78822fa..8b755c5895c9db 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -240,7 +240,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.2 + 8.0.3 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100Version) 1.1.87-gba258badda From 11ae42ba5af1bec15e7ab7c11529d5e006f253a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:33:17 -0500 Subject: [PATCH 32/33] [release/8.0-staging] Fix regex lazy loop handling of backtracking state at max iteration limit (#97927) * Fix regex lazy loop handling of backtracking state at max iteration limit Upon entering a lazy loop, state is pushed onto the backtracking stack if the lazy loop might be backtracked into. That state is then dutifully popped off when unwinding the loop due to failure to match. However, if the loop successfully matches its maximum number of times but still fails because of a failure after the lazy loop, the state still needs to be popped off the stack, but isn't. This fixes that. * Add a few more test variations --------- Co-authored-by: Stephen Toub --- .../gen/RegexGenerator.Emitter.cs | 12 +++++++++ .../Text/RegularExpressions/RegexCompiler.cs | 26 +++++++++++++++++-- .../FunctionalTests/Regex.Match.Tests.cs | 5 ++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index 19488703f07f7e..efe4f0e40b4390 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -3770,6 +3770,17 @@ void EmitLazy(RegexNode node) using (clause) { + // We're backtracking, which could either be to something prior to the lazy loop or to something + // inside of the lazy loop. If it's to something inside of the lazy loop, then either the loop + // will eventually succeed or we'll eventually end up unwinding back through the iterations all + // the way back to the loop not matching at all, in which case the state we first pushed on at the + // beginning of the !isAtomic section will get popped off. But if here we're instead going to jump + // to something prior to the lazy loop, then we need to pop off that state here. + if (doneLabel == originalDoneLabel) + { + EmitAdd(writer, "stackpos", -entriesPerIteration); + } + if (iterationMayBeEmpty) { // If we saw empty, it must have been in the most recent iteration, as we wouldn't have @@ -3777,6 +3788,7 @@ void EmitLazy(RegexNode node) // false prior to backtracking / undoing that iteration. writer.WriteLine($"{sawEmpty} = 0; // false"); } + Goto(doneLabel); } } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs index 20ccc3afefcca6..fb710b26788732 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs @@ -4075,6 +4075,8 @@ void EmitLazy(RegexNode node) // Determine where to branch, either back to the lazy loop body to add an additional iteration, // or to the last backtracking label. + Label jumpToDone = DefineLabel(); + if (iterationMayBeEmpty) { // if (sawEmpty != 0) @@ -4093,7 +4095,7 @@ void EmitLazy(RegexNode node) Ldc(0); Stloc(sawEmpty!); - BrFar(doneLabel); + Br(jumpToDone); MarkLabel(sawEmptyZero); } @@ -4102,12 +4104,32 @@ void EmitLazy(RegexNode node) // if (iterationCount >= maxIterations) goto doneLabel; Ldloc(iterationCount); Ldc(maxIterations); - BgeFar(doneLabel); + Bge(jumpToDone); } // goto body; BrFar(body); + MarkLabel(jumpToDone); + + // We're backtracking, which could either be to something prior to the lazy loop or to something + // inside of the lazy loop. If it's to something inside of the lazy loop, then either the loop + // will eventually succeed or we'll eventually end up unwinding back through the iterations all + // the way back to the loop not matching at all, in which case the state we first pushed on at the + // beginning of the !isAtomic section will get popped off. But if here we're instead going to jump + // to something prior to the lazy loop, then we need to pop off that state here. + if (doneLabel == originalDoneLabel) + { + // stackpos -= entriesPerIteration; + Ldloc(stackpos); + Ldc(entriesPerIteration); + Sub(); + Stloc(stackpos); + } + + // goto done; + BrFar(doneLabel); + doneLabel = backtrack; MarkLabel(skipBacktrack); } diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs index 43bd39f8f36779..d09f45ac2064c4 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs @@ -2374,6 +2374,11 @@ public static IEnumerable AllMatches_TestData() yield return new object[] { engine, "^(?:aaa|aa){1,5}?$", RegexOptions.None, "aaaaaaaa", new (int, int, string)[] { (0, 8, "aaaaaaaa") } }; yield return new object[] { engine, "^(?:aaa|aa){4}$", RegexOptions.None, "aaaaaaaa", new (int, int, string)[] { (0, 8, "aaaaaaaa") } }; yield return new object[] { engine, "^(?:aaa|aa){4}?$", RegexOptions.None, "aaaaaaaa", new (int, int, string)[] { (0, 8, "aaaaaaaa") } }; + yield return new object[] { engine, "^((?:(xx?,xx?)|xx?,xx?>xx?,xx?)-?(x)??){1,2}$", RegexOptions.None, "xx,xx>xx,xx", new (int, int, string)[] { (0, 11, "xx,xx>xx,xx") } }; + yield return new object[] { engine, "^((?:(xx?,xx?)|xx?,xx?>xx?,xx?)-?(x*)??){1,2}$", RegexOptions.None, "xx,xx>xx,xx", new (int, int, string)[] { (0, 11, "xx,xx>xx,xx") } }; + yield return new object[] { engine, "^((?:(xx?,xx?)|xx?,xx?>xx?,xx?)-?(x+)??){1,2}$", RegexOptions.None, "xx,xx>xx,xx", new (int, int, string)[] { (0, 11, "xx,xx>xx,xx") } }; + yield return new object[] { engine, "^((?:(x(x?),x(x?))|xx?,(x(x?)>x(x?)),(x((x))?))-?(x+?)??){1,2}$", RegexOptions.None, "xx,xx>xx,xx", new (int, int, string)[] { (0, 11, "xx,xx>xx,xx") } }; + yield return new object[] { engine, "^(?:x|(x)??){2}$", RegexOptions.None, "x>", null }; // Mostly empty matches using unusual regexes consisting mostly of anchors only yield return new object[] { engine, "^", RegexOptions.None, "", new (int, int, string)[] { (0, 0, "") } }; From b7fda9f36c2cd2a8cde7afdd4dd9670a6e9397d6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:16:33 -0800 Subject: [PATCH 33/33] Add ca-certificates to Mariner 2.0 deps (#98267) Co-authored-by: Nikola Milosavljevic --- .../dotnet-runtime-deps/dotnet-runtime-deps-cm.2.proj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-cm.2.proj b/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-cm.2.proj index 52b410239d3be7..76315c4255ec16 100644 --- a/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-cm.2.proj +++ b/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-cm.2.proj @@ -5,6 +5,6 @@ - +