From 87157cd4e1b307f27e67d3bd4cb66296e7f9ea76 Mon Sep 17 00:00:00 2001 From: Juan Hoyos <19413848+hoyosjs@users.noreply.github.com> Date: Fri, 12 May 2023 15:02:15 -0700 Subject: [PATCH 01/11] Update debugging-runtime.md to mention nativeprereqs (#86174) --- docs/workflow/debugging/coreclr/debugging-runtime.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/workflow/debugging/coreclr/debugging-runtime.md b/docs/workflow/debugging/coreclr/debugging-runtime.md index 74a742fb51e4c..10b63a185559c 100644 --- a/docs/workflow/debugging/coreclr/debugging-runtime.md +++ b/docs/workflow/debugging/coreclr/debugging-runtime.md @@ -41,6 +41,7 @@ If for some reason `System.Private.CoreLib.dll` is missing, you can rebuild it w Visual Studio's capabilities as a full IDE provide a lot of help making the runtime debugging more amiable. +0. Run `.\build.cmd clr.nativeprereqs -a -c `. This will build some of the tools requiremented for the native build. This step only needs to be run once as long you don't clean the `artifacts` directory. 1. Open the CoreCLR solution _(coreclr.sln)_ in Visual Studio. * _Method 1_: Use the build scripts to open the solution: 1. Run `.\build.cmd -vs coreclr.sln -a -c `. This will create and launch the CoreCLR solution in VS for the specified architecture and configuration. By default, this will be `x64 Debug`. From 6023c870e60ef45b704d2b6e850dce9e14d8d9a5 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 12 May 2023 15:49:29 -0700 Subject: [PATCH 02/11] Fix the test build error (#86176) Remove outputtype=exe, mark test as [Fact] --------- Co-authored-by: Mark Plesko --- src/tests/JIT/opt/SSA/MemorySsa.cs | 4 +++- src/tests/JIT/opt/SSA/MemorySsa.csproj | 3 --- src/tests/issues.targets | 3 +++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/tests/JIT/opt/SSA/MemorySsa.cs b/src/tests/JIT/opt/SSA/MemorySsa.cs index 9d2d46f3e2528..db67163a3352f 100644 --- a/src/tests/JIT/opt/SSA/MemorySsa.cs +++ b/src/tests/JIT/opt/SSA/MemorySsa.cs @@ -3,12 +3,14 @@ using System; using System.Runtime.CompilerServices; +using Xunit; public class MemorySsaTests { private static int _intStatic; - public static int Main() + [Fact] + public static int TestEntryPoint() { return ProblemWithHandlerPhis(new int[0]) ? 101 : 100; } diff --git a/src/tests/JIT/opt/SSA/MemorySsa.csproj b/src/tests/JIT/opt/SSA/MemorySsa.csproj index f3e1cbd44b404..501217e4d8689 100644 --- a/src/tests/JIT/opt/SSA/MemorySsa.csproj +++ b/src/tests/JIT/opt/SSA/MemorySsa.csproj @@ -1,7 +1,4 @@ - - Exe - None True diff --git a/src/tests/issues.targets b/src/tests/issues.targets index cfbfbd3175701..f2796be7a7d07 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -17,6 +17,9 @@ https://github.com/dotnet/runtime/issues/80184 + + https://github.com/dotnet/runtime/issues/86112 + From 604ac43f25a8f438cd212290afb5c18afeb4793c Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Sat, 13 May 2023 01:53:06 +0200 Subject: [PATCH 03/11] Avoid NRE in networking EventSources (#86171) --- .../src/System/Net/Http/HttpTelemetry.AnyOS.cs | 6 +++--- .../src/System/Net/NameResolutionTelemetry.cs | 2 +- .../src/System/Net/Security/NetSecurityTelemetry.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.AnyOS.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.AnyOS.cs index a3609e4909e96..e8f6e91218da9 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.AnyOS.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.AnyOS.cs @@ -23,21 +23,21 @@ internal sealed partial class HttpTelemetry [NonEvent] public void Http11RequestLeftQueue(double timeOnQueueMilliseconds) { - _http11RequestsQueueDurationCounter!.WriteMetric(timeOnQueueMilliseconds); + _http11RequestsQueueDurationCounter?.WriteMetric(timeOnQueueMilliseconds); RequestLeftQueue(timeOnQueueMilliseconds, versionMajor: 1, versionMinor: 1); } [NonEvent] public void Http20RequestLeftQueue(double timeOnQueueMilliseconds) { - _http20RequestsQueueDurationCounter!.WriteMetric(timeOnQueueMilliseconds); + _http20RequestsQueueDurationCounter?.WriteMetric(timeOnQueueMilliseconds); RequestLeftQueue(timeOnQueueMilliseconds, versionMajor: 2, versionMinor: 0); } [NonEvent] public void Http30RequestLeftQueue(double timeOnQueueMilliseconds) { - _http30RequestsQueueDurationCounter!.WriteMetric(timeOnQueueMilliseconds); + _http30RequestsQueueDurationCounter?.WriteMetric(timeOnQueueMilliseconds); RequestLeftQueue(timeOnQueueMilliseconds, versionMajor: 3, versionMinor: 0); } diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs index 5ef75348e8027..eef4b0af8a869 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionTelemetry.cs @@ -101,7 +101,7 @@ public void AfterResolution(long startingTimestamp, bool successful) { Interlocked.Decrement(ref _currentLookups); - _lookupsDuration!.WriteMetric(Stopwatch.GetElapsedTime(startingTimestamp).TotalMilliseconds); + _lookupsDuration?.WriteMetric(Stopwatch.GetElapsedTime(startingTimestamp).TotalMilliseconds); if (IsEnabled(EventLevel.Informational, EventKeywords.None)) { diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/NetSecurityTelemetry.cs b/src/libraries/System.Net.Security/src/System/Net/Security/NetSecurityTelemetry.cs index a6d89f11b8d21..a1d79aee0e259 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/NetSecurityTelemetry.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/NetSecurityTelemetry.cs @@ -209,7 +209,7 @@ public void HandshakeCompleted(SslProtocols protocol, long startingTimestamp, bo double duration = Stopwatch.GetElapsedTime(startingTimestamp).TotalMilliseconds; handshakeDurationCounter?.WriteMetric(duration); - _handshakeDurationCounter!.WriteMetric(duration); + _handshakeDurationCounter?.WriteMetric(duration); HandshakeStop(protocol); } From b677265bd1a846c6ce48184735d46682d0f5d7d7 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Fri, 12 May 2023 21:45:00 -0400 Subject: [PATCH 04/11] [wasm] InstallWorkloadFromArtifacts: remove unnecessary workaround (#86191) Prompted by WBT failing with: ``` /Users/ankj/dev/r2/eng/testing/workloads-testing.targets(191,5): error : Could not find IncludedWorkloadManifests.txt in /Users/ankj/dev/r2/artifacts/bin/dotnet-none/ ``` .. which seems to been renamed to `KnownWorkloadManifests.txt`. --- .../InstallWorkloadFromArtifacts.cs | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs b/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs index 9d16bf5d10b01..b64b853feffec 100644 --- a/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs +++ b/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs @@ -65,7 +65,6 @@ public override bool Execute() throw new LogAsErrorException($"Cannot find {nameof(LocalNuGetsPath)}={LocalNuGetsPath} . " + "Set it to the Shipping packages directory in artifacts."); - ExecuteHackForRenamedManifest(); if (!InstallAllManifests()) return false; @@ -177,29 +176,6 @@ private bool ExecuteInternal(InstallWorkloadRequest req) return !Log.HasLoggedErrors; } - private void ExecuteHackForRenamedManifest() - { - // HACK - Because the microsoft.net.workload.mono.toolchain is being renamed to microsoft.net.workload.mono.toolchain.current - // but the sdk doesn't have the change yet. - string? txtPath = Directory.EnumerateFiles(Path.Combine(SdkWithNoWorkloadInstalledPath, "sdk"), "IncludedWorkloadManifests.txt", - new EnumerationOptions { RecurseSubdirectories = true, MaxRecursionDepth = 2}) - .FirstOrDefault(); - if (txtPath is null) - throw new LogAsErrorException($"Could not find IncludedWorkloadManifests.txt in {SdkWithNoWorkloadInstalledPath}"); - - string stampPath = Path.Combine(Path.GetDirectoryName(txtPath)!, ".stamp"); - if (File.Exists(stampPath)) - return; - - var lines = File.ReadAllLines(txtPath) - .Select(line => line == "microsoft.net.workload.mono.toolchain" - ? "microsoft.net.workload.mono.toolchain.current" - : line); - File.WriteAllLines(txtPath, lines); - - File.WriteAllText(stampPath, ""); - } - private bool InstallAllManifests() { var allManifestPkgs = Directory.EnumerateFiles(LocalNuGetsPath, "*Manifest*nupkg"); From 9200155a2fcc5b9caa1c4a0010eda74d61a28e00 Mon Sep 17 00:00:00 2001 From: Nickolas McDonald <43690021+n77y@users.noreply.github.com> Date: Fri, 12 May 2023 21:49:08 -0400 Subject: [PATCH 05/11] Remove static modifiers from ThreadPool events in NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs (#85563) * remove static modifiers remove static modifiers from lines: - 156 - 191 in: src\libraries\System.Private.CoreLib\src\System\Threading\NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs * Update NativeRuntimeEventSourceTest.cs * Test NativeRuntimeEventSourceTest.cs * Remove static modifiers --- ...ntSource.PortableThreadPool.NativeSinks.cs | 4 +- .../NativeRuntimeEventSourceTest.cs | 290 +++++++++++++----- 2 files changed, 215 insertions(+), 79 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs index 76e67f5da79fd..3e9cb4e3e3d68 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs @@ -153,7 +153,7 @@ public unsafe void ThreadPoolWorkerThreadAdjustmentStats( } [Event(63, Level = EventLevel.Verbose, Message = Messages.IOEnqueue, Task = Tasks.ThreadPool, Opcode = Opcodes.IOEnqueue, Version = 0, Keywords = Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword)] - private static unsafe void ThreadPoolIOEnqueue( + private unsafe void ThreadPoolIOEnqueue( IntPtr NativeOverlapped, IntPtr Overlapped, bool MultiDequeues, @@ -188,7 +188,7 @@ public void ThreadPoolIOEnqueue(RegisteredWaitHandle registeredWaitHandle) } [Event(64, Level = EventLevel.Verbose, Message = Messages.IO, Task = Tasks.ThreadPool, Opcode = Opcodes.IODequeue, Version = 0, Keywords = Keywords.ThreadingKeyword | Keywords.ThreadTransferKeyword)] - private static unsafe void ThreadPoolIODequeue( + private unsafe void ThreadPoolIODequeue( IntPtr NativeOverlapped, IntPtr Overlapped, ushort ClrInstanceID = DefaultClrInstanceId) diff --git a/src/tests/tracing/runtimeeventsource/NativeRuntimeEventSourceTest.cs b/src/tests/tracing/runtimeeventsource/NativeRuntimeEventSourceTest.cs index 6322f16e6d004..e1f8d5558683f 100644 --- a/src/tests/tracing/runtimeeventsource/NativeRuntimeEventSourceTest.cs +++ b/src/tests/tracing/runtimeeventsource/NativeRuntimeEventSourceTest.cs @@ -10,58 +10,83 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Tracing.Tests.Common; using System.Collections.Concurrent; +using System.ComponentModel; +using System.Collections; +using System.Collections.Generic; +using System.Text; namespace Tracing.Tests { public sealed class NativeRuntimeEventSourceTest { - static int Main() + private static int Main() { - SimpleEventListener.EnableKeywords = (EventKeywords)0; - using (SimpleEventListener noEventsListener = new SimpleEventListener("NoEvents")) + // Create deaf listener + Listener.Level = EventLevel.Critical; + Listener.EnableKeywords = EventKeywords.None; + using (Listener noEventsListener = new("NoEvents")) { - // Create an EventListener. - SimpleEventListener.EnableKeywords = (EventKeywords)0x4c14fccbd; - using (SimpleEventListener listener = new SimpleEventListener("Simple")) + using (NativeOverlappedClass nativeOverlappedClass = new()) { - // Trigger the allocator task. - Task.Run(new Action(Allocator)); + // Create an EventListener. + Listener.Level = EventLevel.Verbose; + const EventKeywords EventKeywordThreading = (EventKeywords)65536; + Listener.EnableKeywords = (EventKeywords)0x4c14fccbd | EventKeywordThreading; - // If on Windows, attempt some Overlapped IO (triggers ThreadPool events) - if (OperatingSystem.IsWindows()) + // Check for events e.g. ThreadPoolIODequeue = 64 + // At least some of these events can be found in "src\libraries\System.Private.CoreLib\src\System\Threading\NativeRuntimeEventSource.PortableThreadPool.NativeSinks.cs" + Listener.TargetEventIds(63, 64, 65); + + using (Listener listener = new()) { + // Trigger the allocator task. + Task.Run(() => + { + while (true) + { + for (int i = 0; i < 1000; i++) + { + GC.KeepAlive(new object()); + } + + Thread.Sleep(10); + } + }); + + // If on Windows, attempt some Overlapped IO (triggers ThreadPool events) DoOverlappedIO(); - } - // Generate some GC events. - GC.Collect(2, GCCollectionMode.Forced); + // Trigger EventId 63 and 64 + nativeOverlappedClass.ThreadPoolQueue(); - Stopwatch sw = Stopwatch.StartNew(); - - while (sw.Elapsed <= TimeSpan.FromMinutes(1)) - { - Thread.Sleep(100); + // Generate some GC events. + GC.Collect(2, GCCollectionMode.Forced); - if ((OperatingSystem.IsWindows() && listener.SeenProvidersAndEvents.Contains("Microsoft-Windows-DotNETRuntime/EVENTID(65)")) - || (!OperatingSystem.IsWindows() && listener.EventCount > 0)) + Stopwatch sw = Stopwatch.StartNew(); + + while (sw.Elapsed <= TimeSpan.FromMinutes(1d / 12d)) { - break; + Thread.Sleep(100); + + if ((listener.EventsLeft <= 0) || (!OperatingSystem.IsWindows() && listener.EventCount > 0)) + { + break; + } } - } - // Ensure that we've seen some events. - foreach (string s in listener.SeenProvidersAndEvents) - { - Console.WriteLine(s); - } + Assert2.True("listener.EventCount > 0", listener.EventCount > 0); - Assert.True("listener.EventCount > 0", listener.EventCount > 0); - - if (OperatingSystem.IsWindows()) - { - Assert.True("Saw the ThreadPoolIOPack event", listener.SeenProvidersAndEvents.Contains("Microsoft-Windows-DotNETRuntime/EVENTID(65)")); + if (OperatingSystem.IsWindows()) + { + StringBuilder stringBuilder = new(); + foreach (var e in listener.GetFailedTargetEvents()) + { + stringBuilder.Append((stringBuilder.Length > 0) ? ", " : ""); + stringBuilder.Append(e.Key); + } + Assert2.True($"At least one of the EventIds ({stringBuilder}) where heard.", stringBuilder.Length < 1); + } } } @@ -69,88 +94,199 @@ static int Main() GC.Collect(2, GCCollectionMode.Forced); // Ensure that we've seen no events. - Assert.True("noEventsListener.EventCount == 0", noEventsListener.EventCount == 0); + Assert2.True("noEventsListener.EventCount == 0", noEventsListener.EventCount == 0); } return 100; } - private static void Allocator() + private static unsafe void DoOverlappedIO() { - while (true) + if (!OperatingSystem.IsWindows()) { - for(int i=0; i<1000; i++) - { - GC.KeepAlive(new object()); - } - - Thread.Sleep(10); + return; } - } - - private static unsafe void DoOverlappedIO() - { Console.WriteLine("DOOVERLAPPEDIO"); Overlapped overlapped = new(); NativeOverlapped* pOverlap = overlapped.Pack(null, null); Overlapped.Free(pOverlap); } + + private static class Assert2 + { + public static void True(string name, bool condition) + { + if (!condition) + { + throw new Exception( + string.Format("Condition '{0}' is not true", name)); + } + } + } } - internal sealed class SimpleEventListener : EventListener + internal sealed unsafe class NativeOverlappedClass : IDisposable { - public ConcurrentBag SeenProvidersAndEvents { get; private set; } = new(); - private string m_name; + private bool disposedValue; + private readonly NativeOverlapped* nativeOverlapped; - // Keep track of the set of keywords to be enabled. - public static EventKeywords EnableKeywords + public NativeOverlappedClass() { - get; - set; + if (OperatingSystem.IsWindows()) + { + nativeOverlapped = new Overlapped().Pack(null, null); + } } - public SimpleEventListener(string name) + public bool ThreadPoolQueue() { - m_name = name; + return OperatingSystem.IsWindows() && ThreadPool.UnsafeQueueNativeOverlapped(nativeOverlapped); } - public int EventCount { get; private set; } = 0; - - protected override void OnEventSourceCreated(EventSource eventSource) + private void Dispose(bool disposing) { - if (eventSource.Name.Equals("Microsoft-Windows-DotNETRuntime")) + if (!disposedValue) { - if (EnableKeywords != 0) + if (disposing) { - // Enable events. - EnableEvents(eventSource, EventLevel.Verbose, EnableKeywords); + // TODO: dispose managed state (managed objects) } - else + + if (OperatingSystem.IsWindows()) { - // Enable the provider, but not any keywords, so we should get no events as long as no rundown occurs. - EnableEvents(eventSource, EventLevel.Critical, EnableKeywords); + Overlapped.Free(nativeOverlapped); } + + disposedValue = true; } } - protected override void OnEventWritten(EventWrittenEventArgs eventData) + ~NativeOverlappedClass() { - Console.WriteLine($"[{m_name}] ThreadID = {eventData.OSThreadId} ID = {eventData.EventId} Name = {eventData.EventName}"); - Console.WriteLine($"TimeStamp: {eventData.TimeStamp.ToLocalTime()}"); - Console.WriteLine($"LocalTime: {DateTime.Now}"); - Console.WriteLine($"Difference: {DateTime.UtcNow - eventData.TimeStamp}"); - Assert.True("eventData.TimeStamp <= DateTime.UtcNow", eventData.TimeStamp <= DateTime.UtcNow); - for (int i = 0; i < eventData.Payload.Count; i++) + Dispose(disposing: false); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } + + internal sealed class Listener : EventListener + { + public static string EventSourceName = "Microsoft-Windows-DotNETRuntime"; + public static EventLevel Level = EventLevel.Verbose; + public static EventKeywords EnableKeywords = EventKeywords.All; + + public int EventCount { get; private set; } = 0; + public int EventsLeft { get; private set; } = 0; + + private static readonly ConcurrentBag targetEventIds = new(); + private static readonly (string, string) defaultEventSourceNameName = ("Failed to listen", "Was not heard or didn't fire"); + + private readonly string name = ""; + private readonly ConcurrentDictionary eventIdSourceNameNames = new(); + + public Listener(string name = nameof(Listener)) + { + this.name = $"({name}) "; + } + + public static void TargetEventIds(params int[] ids) + { + targetEventIds.Clear(); + + foreach (int id in ids) + { + targetEventIds.Add(id); + } + } + public IEnumerable> GetFailedTargetEvents() + { + foreach (KeyValuePair e in eventIdSourceNameNames) + { + if (e.Value == defaultEventSourceNameName) + { + yield return e; + } + } + } + public override void Dispose() + { + base.Dispose(); + + foreach (KeyValuePair e in eventIdSourceNameNames) { - string payloadString = eventData.Payload[i] != null ? eventData.Payload[i].ToString() : string.Empty; - Console.WriteLine($"\tName = \"{eventData.PayloadNames[i]}\" Value = \"{payloadString}\""); + WriteLine(e); } - Console.WriteLine("\n"); - SeenProvidersAndEvents.Add($"{eventData.EventSource.Name}"); - SeenProvidersAndEvents.Add($"{eventData.EventSource.Name}/EVENTID({eventData.EventId})"); + WriteLine("\n"); + } + + protected override void OnEventSourceCreated(EventSource eventSource) + { + if ((eventSource.Name == EventSourceName) && eventIdSourceNameNames.IsEmpty) + { + foreach (var targetEventId in targetEventIds) + { + eventIdSourceNameNames[targetEventId] = defaultEventSourceNameName; + } + EventsLeft = eventIdSourceNameNames.Count; + EnableEvents(eventSource, Level, EnableKeywords); + } + } + protected override void OnEventWritten(EventWrittenEventArgs eventWrittenEventArgs) + { EventCount++; + + KeyValuePair e = new( + eventWrittenEventArgs.EventId, + (eventWrittenEventArgs.EventSource.Name, eventWrittenEventArgs.EventName ?? "")); + + EventsLeft -= (eventIdSourceNameNames.TryGetValue(e.Key, out (string, string) value) && value == defaultEventSourceNameName) ? 1 : 0; + eventIdSourceNameNames[e.Key] = e.Value; + + WriteLine(e); + + WriteLine($"OSThreadId = {eventWrittenEventArgs.OSThreadId}", ConsoleColor.Yellow); + + WriteLine($"TimeStamp: {eventWrittenEventArgs.TimeStamp.ToLocalTime()}"); + WriteLine($"local time: {DateTime.Now}"); + WriteLine($"Difference: {DateTime.UtcNow - eventWrittenEventArgs.TimeStamp}"); + + for (int i = 0; (i < eventWrittenEventArgs.PayloadNames?.Count) && (i < eventWrittenEventArgs.Payload?.Count); i++) + { + WriteLine($"{eventWrittenEventArgs.PayloadNames[i]} = {eventWrittenEventArgs.Payload[i]}", ConsoleColor.Magenta); + } + + WriteLine("\n"); + } + + private void Write(object? o = null, ConsoleColor? consoleColor = null) + { + ConsoleColor foregroundColor = Console.ForegroundColor; + + if (o is KeyValuePair e) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.Write(name); + + Console.ForegroundColor = (e.Value != defaultEventSourceNameName) ? ConsoleColor.Green : ConsoleColor.Red; + } + else if (consoleColor != null) + { + Console.ForegroundColor = (ConsoleColor)consoleColor; + } + Console.Write(o); + + Console.ForegroundColor = foregroundColor; + } + private void WriteLine(object? o = null, ConsoleColor? consoleColor = null) + { + Write(o, consoleColor); + Console.WriteLine(); } } } From d08c807ba6c148164041bb8f0d0156687ab3898f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 12 May 2023 19:36:22 -0700 Subject: [PATCH 06/11] [JIT]: Inline TLS field access for GC type (#85619) * Add CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED * Working prototype * Rename ThreadStaticBlock to NonGCThreadStaticBlock * Add GCThreadStaticBlock * fix linux build * Restrict the optimization to non-generics * Update the guid * Add canOptimizeHelper check * Rename and related methods from typeIDMap to NonGCTypeID * Introduce GCTypeIDMap and getGCThreadLocalFieldInfo() * Use GCThreadLocalFieldInfo() * fix the bug about gc tracking * resolve merge conflicts * remove the commented code * add comment * Unify some of the non-gc/gc methods * fix missing methods * update the comments * Track gc for derefernce of object handle * fix the superpmi methods * review feedback --- src/coreclr/inc/corinfo.h | 8 +- src/coreclr/inc/icorjitinfoimpl_generated.h | 6 +- src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/inc/jithelpers.h | 3 +- .../jit/ICorJitInfo_wrapper_generated.hpp | 10 +- src/coreclr/jit/compiler.h | 1 - src/coreclr/jit/compiler.hpp | 1 + src/coreclr/jit/ee_il_dll.hpp | 6 - src/coreclr/jit/flowgraph.cpp | 7 +- src/coreclr/jit/helperexpansion.cpp | 54 ++++++--- src/coreclr/jit/importer.cpp | 10 +- src/coreclr/jit/utils.cpp | 1 + src/coreclr/jit/valuenum.cpp | 3 + src/coreclr/jit/valuenumfuncs.h | 1 + .../Common/JitInterface/CorInfoHelpFunc.cs | 1 + .../tools/Common/JitInterface/CorInfoImpl.cs | 4 +- .../JitInterface/CorInfoImpl_generated.cs | 12 +- .../tools/Common/JitInterface/CorInfoTypes.cs | 1 + .../ThunkGenerator/ThunkInput.txt | 4 +- .../aot/jitinterface/jitinterface_generated.h | 14 ++- .../tools/superpmi/superpmi-shared/agnostic.h | 1 + .../tools/superpmi/superpmi-shared/lwmlist.h | 2 +- .../superpmi-shared/methodcontext.cpp | 58 +++++---- .../superpmi/superpmi-shared/methodcontext.h | 10 +- .../superpmi-shim-collector/icorjitinfo.cpp | 12 +- .../icorjitinfo_generated.cpp | 10 +- .../icorjitinfo_generated.cpp | 10 +- .../tools/superpmi/superpmi/icorjitinfo.cpp | 8 +- src/coreclr/vm/appdomain.cpp | 36 +++++- src/coreclr/vm/appdomain.hpp | 13 +- src/coreclr/vm/jithelpers.cpp | 111 +++++++++++++++--- src/coreclr/vm/jitinterface.cpp | 52 ++++++-- src/coreclr/vm/methodtable.h | 1 + src/coreclr/vm/methodtable.inl | 26 ++++ 34 files changed, 362 insertions(+), 145 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 50c0d348bd0f3..3208abe82bdd3 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -548,6 +548,7 @@ enum CorInfoHelpFunc CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, + CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, /* Debugger */ @@ -1731,6 +1732,7 @@ struct CORINFO_THREAD_STATIC_BLOCKS_INFO uint32_t offsetOfThreadLocalStoragePointer; uint32_t offsetOfMaxThreadStaticBlocks; uint32_t offsetOfThreadStaticBlocks; + uint32_t offsetOfGCDataPointer; }; //---------------------------------------------------------------------------- @@ -2733,11 +2735,13 @@ class ICorStaticInfo CORINFO_FIELD_INFO *pResult ) = 0; + // Returns the index against which the field's thread static block in stored in TLS. virtual uint32_t getThreadLocalFieldInfo ( - CORINFO_FIELD_HANDLE field) = 0; + CORINFO_FIELD_HANDLE field, bool isGCType) = 0; + // Returns the thread static block information like offsets, etc. from current TLS. virtual void getThreadLocalStaticBlocksInfo ( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) = 0; + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) = 0; // Returns true iff "fldHnd" represents a static field. virtual bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) = 0; diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index ad73b66da0966..f3d93194df258 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -411,10 +411,12 @@ void getFieldInfo( CORINFO_FIELD_INFO* pResult) override; uint32_t getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field) override; + CORINFO_FIELD_HANDLE field, + bool isGCtype) override; void getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) override; + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, + bool isGCType) override; bool isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 6e5df744de35a..f38a8f6139acf 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 50246073-be42-4227-b9e1-edc585672820 */ - 0x50246073, - 0xbe42, - 0x4227, - {0xb9, 0xe1, 0xed, 0xc5, 0x85, 0x67, 0x28, 0x20} +constexpr GUID JITEEVersionIdentifier = { /* f63c2964-bae9-448f-baaf-9c9f2d4292f2 */ + 0xf63c2964, + 0xbae9, + 0x448f, + {0xba, 0xaf, 0x9c, 0x9f, 0x2d, 0x42, 0x92, 0xf2} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 1d498c3589347..1913a428da942 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -203,8 +203,9 @@ JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, JIT_GetSharedNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetSharedGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, JIT_GetSharedNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedNonGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedNonGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY) // Debugger diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 990d8cabce1a2..da369eda01a37 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -972,19 +972,21 @@ void WrapICorJitInfo::getFieldInfo( } uint32_t WrapICorJitInfo::getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field) + CORINFO_FIELD_HANDLE field, + bool isGCtype) { API_ENTER(getThreadLocalFieldInfo); - uint32_t temp = wrapHnd->getThreadLocalFieldInfo(field); + uint32_t temp = wrapHnd->getThreadLocalFieldInfo(field, isGCtype); API_LEAVE(getThreadLocalFieldInfo); return temp; } void WrapICorJitInfo::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, + bool isGCType) { API_ENTER(getThreadLocalStaticBlocksInfo); - wrapHnd->getThreadLocalStaticBlocksInfo(pInfo); + wrapHnd->getThreadLocalStaticBlocksInfo(pInfo, isGCType); API_LEAVE(getThreadLocalStaticBlocksInfo); } diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index c03192ec9eac9..3b777c5b36a7c 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7818,7 +7818,6 @@ class Compiler void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); - uint32_t eeGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); // Get the flags diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index acd41345799c9..83f90d4be5fd7 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3518,6 +3518,7 @@ inline bool Compiler::IsSharedStaticHelper(GenTree* tree) helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE || helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE || helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR || + helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED || helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR || helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED || helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS || diff --git a/src/coreclr/jit/ee_il_dll.hpp b/src/coreclr/jit/ee_il_dll.hpp index 162d5479dff49..cfdc1f87c680e 100644 --- a/src/coreclr/jit/ee_il_dll.hpp +++ b/src/coreclr/jit/ee_il_dll.hpp @@ -44,12 +44,6 @@ void Compiler::eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, info.compCompHnd->getFieldInfo(pResolvedToken, info.compMethodHnd, accessFlags, pResult); } -FORCEINLINE -uint32_t Compiler::eeGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) -{ - return info.compCompHnd->getThreadLocalFieldInfo(field); -} - /***************************************************************************** * * VOS info, method sigs, etc diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index a88e3c89800e5..cce98db9bc503 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -698,7 +698,8 @@ bool Compiler::fgIsCommaThrow(GenTree* tree, bool forFolding /* = false */) // cls - The class handle // helper - The helper function // typeIndex - The static block type index. Used only for -// CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED to cache +// CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED or +// CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED to cache // the static block in an array at index typeIndex. // // Return Value: @@ -715,6 +716,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo switch (helper) { case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: bNeedClassID = false; FALLTHROUGH; @@ -795,7 +797,8 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg); } - else if (helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) + else if ((helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) || + (helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED)) { result = gtNewHelperCallNode(helper, type, gtNewIconNode(typeIndex)); result->SetExpTLSFieldAccess(); diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index e920e769e9c32..fc71feb0090d8 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -410,7 +410,8 @@ bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock** pBlock, Statement* stm //------------------------------------------------------------------------------ // fgExpandThreadLocalAccess: Inline the CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED -// helper. See fgExpandThreadLocalAccessForCall for details. +// or CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED helper. See +// fgExpandThreadLocalAccessForCall for details. // // Returns: // PhaseStatus indicating what, if anything, was changed. @@ -446,7 +447,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() //------------------------------------------------------------------------------ // fgExpandThreadLocalAccessForCall : Expand the CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED -// that access fields marked with [ThreadLocal]. +// or CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, that access fields marked with [ThreadLocal]. // // Arguments: // pBlock - Block containing the helper call to expand. If expansion is performed, @@ -483,20 +484,31 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* assert(!"Unsupported scenario of optimizing TLS access on Arm32"); #endif + JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(call), block->bbNum); + DISPTREE(call); + JITDUMP("\n"); + bool isGCThreadStatic = + eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; + CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; - info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); - JITDUMP("getThreadLocalStaticBlocksInfo\n:"); + info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo, isGCThreadStatic); + + uint32_t offsetOfMaxThreadStaticBlocksVal = 0; + uint32_t offsetOfThreadStaticBlocksVal = 0; + + JITDUMP("getThreadLocalStaticBlocksInfo (%s)\n:", isGCThreadStatic ? "GC" : "Non-GC"); + offsetOfMaxThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks; + offsetOfThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfThreadStaticBlocks; + JITDUMP("tlsIndex= %u\n", (ssize_t)threadStaticBlocksInfo.tlsIndex.addr); - JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks); JITDUMP("offsetOfThreadLocalStoragePointer= %u\n", threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer); - JITDUMP("offsetOfThreadStaticBlocks= %u\n", threadStaticBlocksInfo.offsetOfThreadStaticBlocks); + JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", offsetOfMaxThreadStaticBlocksVal); + JITDUMP("offsetOfThreadStaticBlocks= %u\n", offsetOfThreadStaticBlocksVal); + JITDUMP("offsetOfGCDataPointer= %u\n", threadStaticBlocksInfo.offsetOfGCDataPointer); assert(threadStaticBlocksInfo.tlsIndex.accessType == IAT_VALUE); - assert(eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); - - JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(call), block->bbNum); - DISPTREE(call); - JITDUMP("\n"); + assert((eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) || + (eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED)); call->ClearExpTLSFieldAccess(); assert(call->gtArgs.CountArgs() == 1); @@ -508,6 +520,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* DebugInfo debugInfo = stmt->GetDebugInfo(); block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); *pBlock = block; + var_types callType = call->TypeGet(); assert(prevBb != nullptr && block != nullptr); // Block ops inserted by the split need to be morphed here since we are after morph. @@ -523,8 +536,8 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) unsigned threadStaticBlockLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - lvaTable[threadStaticBlockLclNum].lvType = TYP_I_IMPL; - threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, call->TypeGet()); + lvaTable[threadStaticBlockLclNum].lvType = callType; + threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, callType); *callUse = gtClone(threadStaticBlockLcl); @@ -564,8 +577,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* GenTree* tlsLclValueUse = gtNewLclVarNode(tlsLclNum); // Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]" - GenTree* offsetOfMaxThreadStaticBlocks = - gtNewIconNode(threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); + GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(offsetOfMaxThreadStaticBlocksVal, TYP_I_IMPL); GenTree* maxThreadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse), offsetOfMaxThreadStaticBlocks); GenTree* maxThreadStaticBlocksValue = @@ -577,7 +589,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" - GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadStaticBlocksInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); + GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(offsetOfThreadStaticBlocksVal, TYP_I_IMPL); GenTree* threadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse), offsetOfThreadStaticBlocks); GenTree* threadStaticBlocksValue = @@ -642,6 +654,16 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* fgNewBBFromTreeAfter(BBJ_ALWAYS, threadStaticBlockNullCondBB, fallbackValueDef, debugInfo, true); // fastPathBb + if (isGCThreadStatic) + { + // Need to add extra indirection to access the data pointer. + + threadStaticBlockBaseLclValueUse = gtNewIndir(callType, threadStaticBlockBaseLclValueUse, GTF_IND_NONFAULTING); + threadStaticBlockBaseLclValueUse = + gtNewOperNode(GT_ADD, callType, threadStaticBlockBaseLclValueUse, + gtNewIconNode(threadStaticBlocksInfo.offsetOfGCDataPointer, TYP_I_IMPL)); + } + GenTree* fastPathValueDef = gtNewStoreLclVarNode(threadStaticBlockLclNum, gtCloneExpr(threadStaticBlockBaseLclValueUse)); BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, fallbackBb, fastPathValueDef, debugInfo, true); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 2834cf78ab34e..22c25523f41dd 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3963,7 +3963,15 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT case CORINFO_FIELD_STATIC_TLS_MANAGED: - typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField); + if (pFieldInfo->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) + { + typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, false); + } + else + { + assert(pFieldInfo->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); + typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, true); + } FALLTHROUGH; case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 12d520b14c44c..fb8266240ad74 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1476,6 +1476,7 @@ void HelperCallProperties::init() case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index b41e7cd5c2216..14be1b160a04c 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -12228,6 +12228,9 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR: vnf = VNF_GetsharedGcthreadstaticBaseNoctor; break; + case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + vnf = VNF_GetsharedGcthreadstaticBaseNoctorOptimized; + break; case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: vnf = VNF_GetsharedNongcthreadstaticBaseNoctor; break; diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index df804121eb98a..1c6c72bb87fa0 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -125,6 +125,7 @@ ValueNumFuncDef(GetgenericsNongcthreadstaticBase, 1, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true) +ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctorOptimized, 1, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 1, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index 06bc0f6363a09..0693f3c1b69f1 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -187,6 +187,7 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 5c90ea273df43..2a16f1102fec0 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2859,7 +2859,7 @@ private nuint printFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint buf } #pragma warning disable CA1822 // Mark members as static - private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* fld) + private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* fld, bool isGCType) #pragma warning restore CA1822 // Mark members as static { // Implemented for JIT only for now. @@ -2868,7 +2868,7 @@ private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* fld) } #pragma warning disable CA1822 // Mark members as static - private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) #pragma warning restore CA1822 // Mark members as static { // Implemented for JIT only for now. diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index ccfdf88b8797e..772a97e0cfb82 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1465,12 +1465,12 @@ private static void _getFieldInfo(IntPtr thisHandle, IntPtr* ppException, CORINF } [UnmanagedCallersOnly] - private static uint _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field) + private static uint _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte isGCtype) { var _this = GetThis(thisHandle); try { - return _this.getThreadLocalFieldInfo(field); + return _this.getThreadLocalFieldInfo(field, isGCtype != 0); } catch (Exception ex) { @@ -1480,12 +1480,12 @@ private static uint _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppExcept } [UnmanagedCallersOnly] - private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, byte isGCType) { var _this = GetThis(thisHandle); try { - _this.getThreadLocalStaticBlocksInfo(pInfo); + _this.getThreadLocalStaticBlocksInfo(pInfo, isGCType != 0); } catch (Exception ex) { @@ -2757,8 +2757,8 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[95] = (delegate* unmanaged)&_getFieldType; callbacks[96] = (delegate* unmanaged)&_getFieldOffset; callbacks[97] = (delegate* unmanaged)&_getFieldInfo; - callbacks[98] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[99] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[98] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[99] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; callbacks[100] = (delegate* unmanaged)&_isFieldStatic; callbacks[101] = (delegate* unmanaged)&_getArrayOrStringLength; callbacks[102] = (delegate* unmanaged)&_getBoundaries; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 18c24222c4fdf..71d8cd105dc60 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1154,6 +1154,7 @@ public unsafe struct CORINFO_THREAD_STATIC_BLOCKS_INFO public uint offsetOfThreadLocalStoragePointer; public CORINFO_CONST_LOOKUP offsetOfMaxThreadStaticBlocks; public CORINFO_CONST_LOOKUP offsetOfThreadStaticBlocks; + public CORINFO_CONST_LOOKUP offsetOfGCDataPointer; }; // System V struct passing diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 327255bd7eb58..89d87da12f848 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -257,8 +257,8 @@ FUNCTIONS CorInfoType getFieldType(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType, CORINFO_CLASS_HANDLE memberParent) unsigned getFieldOffset(CORINFO_FIELD_HANDLE field) void getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) - uint32_t getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) - void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + uint32_t getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isGCtype) + void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) int getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd) void getBoundaries(CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index ec15c56b293aa..56fb164b35956 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -109,8 +109,8 @@ struct JitInterfaceCallbacks CorInfoType (* getFieldType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType, CORINFO_CLASS_HANDLE memberParent); unsigned (* getFieldOffset)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field); void (* getFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); - uint32_t (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field); - void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); + uint32_t (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, bool isGCtype); + void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType); bool (* isFieldStatic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd); int (* getArrayOrStringLength)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE objHnd); void (* getBoundaries)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries); @@ -1165,19 +1165,21 @@ class JitInterfaceWrapper : public ICorJitInfo } virtual uint32_t getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field) + CORINFO_FIELD_HANDLE field, + bool isGCtype) { CorInfoExceptionClass* pException = nullptr; - uint32_t temp = _callbacks->getThreadLocalFieldInfo(_thisHandle, &pException, field); + uint32_t temp = _callbacks->getThreadLocalFieldInfo(_thisHandle, &pException, field, isGCtype); if (pException != nullptr) throw pException; return temp; } virtual void getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, + bool isGCType) { CorInfoExceptionClass* pException = nullptr; - _callbacks->getThreadLocalStaticBlocksInfo(_thisHandle, &pException, pInfo); + _callbacks->getThreadLocalStaticBlocksInfo(_thisHandle, &pException, pInfo, isGCType); if (pException != nullptr) throw pException; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index c717ea0631c8d..0783fa52962a4 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -522,6 +522,7 @@ struct Agnostic_GetThreadLocalStaticBlocksInfo UINT offsetOfThreadLocalStoragePointer; UINT offsetOfMaxThreadStaticBlocks; UINT offsetOfThreadStaticBlocks; + UINT offsetOfGCDataPointer; }; struct Agnostic_GetThreadLocalFieldInfo diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 615072268280b..9ea8c6ada013c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -38,7 +38,7 @@ LWM(EmbedFieldHandle, DWORDLONG, DLDL) LWM(EmbedGenericHandle, Agnostic_EmbedGenericHandle, Agnostic_CORINFO_GENERICHANDLE_RESULT) LWM(EmbedMethodHandle, DWORDLONG, DLDL) LWM(EmbedModuleHandle, DWORDLONG, DLDL) -LWM(GetThreadLocalFieldInfo, DWORDLONG, DWORD) +LWM(GetThreadLocalFieldInfo, DLD, DWORD) LWM(GetThreadLocalStaticBlocksInfo, DWORD, Agnostic_GetThreadLocalStaticBlocksInfo) DENSELWM(EmptyStringLiteral, DLD) DENSELWM(ErrorList, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 83e298408bcea..aa491393c414b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3601,34 +3601,39 @@ void MethodContext::repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, } } -void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, uint32_t result) +void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType, uint32_t result) { if (GetThreadLocalFieldInfo == nullptr) - GetThreadLocalFieldInfo = new LightWeightMap(); + GetThreadLocalFieldInfo = new LightWeightMap(); - DWORDLONG key = 0; - - key = CastHandle(field); + DLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(field); + key.B = isGCType ? 0 : 1; GetThreadLocalFieldInfo->Add(key, result); DEBUG_REC(dmpGetThreadLocalFieldInfo(key, result)); } -void MethodContext::dmpGetThreadLocalFieldInfo(DWORDLONG key, DWORD value) +void MethodContext::dmpGetThreadLocalFieldInfo(DLD key, DWORD value) { - printf("GetThreadLocalFieldInfo key hnd-%016" PRIX64 ", result-%u", key, value); + printf("GetThreadLocalFieldInfo key hnd-%016" PRIX64 ",gctype-%d result-%u", key.A, key.B, value); } -uint32_t MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) +uint32_t MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType) { - DWORDLONG key = CastHandle(field); - DWORD value = LookupByKeyOrMiss(GetThreadLocalFieldInfo, key, ": key %016" PRIX64 "", key); + DLD key; + ZeroMemory(&key, sizeof(key)); + + key.A = CastHandle(field); + key.B = isGCType ? 0 : 1; + DWORD value = LookupByKeyOrMiss(GetThreadLocalFieldInfo, key, ": key hnd-%016" PRIX64 ", gctype-%u", key.A, key.B); DEBUG_REP(dmpGetThreadLocalFieldInfo(key, value)); return value; } -void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) { if (GetThreadLocalStaticBlocksInfo == nullptr) GetThreadLocalStaticBlocksInfo = new LightWeightMap(); @@ -3641,31 +3646,36 @@ void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC value.offsetOfMaxThreadStaticBlocks = pInfo->offsetOfMaxThreadStaticBlocks; value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; value.offsetOfThreadStaticBlocks = pInfo->offsetOfThreadStaticBlocks; + value.offsetOfGCDataPointer = pInfo->offsetOfGCDataPointer; // This data is same for entire process, so just add it against key '0'. - GetThreadLocalStaticBlocksInfo->Add(0, value); - DEBUG_REC(dmpGetThreadLocalStaticBlocksInfo(0, value)); + DWORD key = isGCType ? 0 : 1; + GetThreadLocalStaticBlocksInfo->Add(key, value); + DEBUG_REC(dmpGetThreadLocalStaticBlocksInfo(key, value)); } void MethodContext::dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value) { - printf("GetThreadLocalStaticBlocksInfo key 0, value tlsIndex-%016" PRIX64 - ", offsetOfMaxThreadStaticBlocks-%u, offsetOfThreadLocalStoragePointer-%u, offsetOfThreadStaticBlocks-%u", - value.tlsIndex.handle, value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadLocalStoragePointer, - value.offsetOfThreadStaticBlocks); + printf("GetThreadLocalStaticBlocksInfo key %u, value tlsIndex-%016" PRIX64 + ", offsetOfThreadLocalStoragePointer-%u, offsetOfMaxThreadStaticBlocks-%u" + ", offsetOfThreadStaticBlocks-%u offsetOfGCDataPointer-%u", + key, value.tlsIndex.handle, value.offsetOfThreadLocalStoragePointer, + value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadStaticBlocks, value.offsetOfGCDataPointer); } -void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) { - Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, 0, ": key %u", 0); + int key = isGCType ? 0 : 1; + Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, key, ": key %u", key); - DEBUG_REP(dmpGetThreadLocalStaticBlocksInfo(0, value)); + DEBUG_REP(dmpGetThreadLocalStaticBlocksInfo(key, value)); - pInfo->tlsIndex.accessType = (InfoAccessType)value.tlsIndex.accessType; - pInfo->tlsIndex.addr = (void*)value.tlsIndex.handle; - pInfo->offsetOfMaxThreadStaticBlocks = value.offsetOfMaxThreadStaticBlocks; + pInfo->tlsIndex.accessType = (InfoAccessType)value.tlsIndex.accessType; + pInfo->tlsIndex.addr = (void*)value.tlsIndex.handle; + pInfo->offsetOfMaxThreadStaticBlocks = value.offsetOfMaxThreadStaticBlocks; pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; - pInfo->offsetOfThreadStaticBlocks = value.offsetOfThreadStaticBlocks; + pInfo->offsetOfThreadStaticBlocks = value.offsetOfThreadStaticBlocks; + pInfo->offsetOfGCDataPointer = value.offsetOfGCDataPointer; } void MethodContext::recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 23f77fed33825..e6dacd31f2a3c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -485,13 +485,13 @@ class MethodContext CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); - void recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, uint32_t result); - void dmpGetThreadLocalFieldInfo(DWORDLONG key, DWORD value); - uint32_t repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); + void recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType, uint32_t result); + void dmpGetThreadLocalFieldInfo(DLD key, DWORD value); + uint32_t repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType); - void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); + void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType); void dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value); - void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); + void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType); void recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, CORINFO_METHOD_HANDLE result); void dmpEmbedMethodHandle(DWORDLONG key, DLDL value); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 132cb3b3556ab..c746be1fe5bd6 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1096,19 +1096,19 @@ void interceptor_ICJI::getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, mc->recGetFieldInfo(pResolvedToken, callerHandle, flags, pResult); } -uint32_t interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) +uint32_t interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType) { mc->cr->AddCall("getThreadLocalFieldInfo"); - uint32_t result = original_ICorJitInfo->getThreadLocalFieldInfo(field); - mc->recGetThreadLocalFieldInfo(field, result); + uint32_t result = original_ICorJitInfo->getThreadLocalFieldInfo(field, isGCType); + mc->recGetThreadLocalFieldInfo(field, isGCType, result); return result; } -void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) { mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); - mc->recGetThreadLocalStaticBlocksInfo(pInfo); + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType); + mc->recGetThreadLocalStaticBlocksInfo(pInfo, isGCType); } // Returns true iff "fldHnd" represents a static field. diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 33746daa479e4..6d301f516f60b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -794,17 +794,19 @@ void interceptor_ICJI::getFieldInfo( } uint32_t interceptor_ICJI::getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field) + CORINFO_FIELD_HANDLE field, + bool isGCtype) { mcs->AddCall("getThreadLocalFieldInfo"); - return original_ICorJitInfo->getThreadLocalFieldInfo(field); + return original_ICorJitInfo->getThreadLocalFieldInfo(field, isGCtype); } void interceptor_ICJI::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, + bool isGCType) { mcs->AddCall("getThreadLocalStaticBlocksInfo"); - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType); } bool interceptor_ICJI::isFieldStatic( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 78179769f31d4..7dd611b5283dc 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -696,15 +696,17 @@ void interceptor_ICJI::getFieldInfo( } uint32_t interceptor_ICJI::getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field) + CORINFO_FIELD_HANDLE field, + bool isGCtype) { - return original_ICorJitInfo->getThreadLocalFieldInfo(field); + return original_ICorJitInfo->getThreadLocalFieldInfo(field, isGCtype); } void interceptor_ICJI::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, + bool isGCType) { - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType); } bool interceptor_ICJI::isFieldStatic( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 3fdd37cb879ed..16d52438b6c40 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -917,16 +917,16 @@ void MyICJI::getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, jitInstance->mc->repGetFieldInfo(pResolvedToken, callerHandle, flags, pResult); } -uint32_t MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) +uint32_t MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType) { jitInstance->mc->cr->AddCall("getThreadLocalFieldInfo"); - return jitInstance->mc->repGetThreadLocalFieldInfo(field); + return jitInstance->mc->repGetThreadLocalFieldInfo(field, isGCType); } -void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) { jitInstance->mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); - jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo); + jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo, isGCType); } // Returns true iff "fldHnd" represents a static field. diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 144e8ac0ac841..d7210892f2ae5 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -670,7 +670,8 @@ void BaseDomain::InitThreadStaticBlockTypeMap() { STANDARD_VM_CONTRACT; - m_threadStaticBlockTypeIDMap.Init(); + m_NonGCThreadStaticBlockTypeIDMap.Init(); + m_GCThreadStaticBlockTypeIDMap.Init(); } #endif // HOST_WINDOWS @@ -4680,7 +4681,7 @@ PTR_MethodTable BaseDomain::LookupType(UINT32 id) { #ifdef HOST_WINDOWS //------------------------------------------------------------------------ -UINT32 BaseDomain::GetThreadStaticTypeIndex(PTR_MethodTable pMT) +UINT32 BaseDomain::GetNonGCThreadStaticTypeIndex(PTR_MethodTable pMT) { CONTRACTL { THROWS; @@ -4688,18 +4689,43 @@ UINT32 BaseDomain::GetThreadStaticTypeIndex(PTR_MethodTable pMT) PRECONDITION(pMT->GetDomain() == this); } CONTRACTL_END; - return m_threadStaticBlockTypeIDMap.GetTypeID(pMT, false); + return m_NonGCThreadStaticBlockTypeIDMap.GetTypeID(pMT, false); } //------------------------------------------------------------------------ -PTR_MethodTable BaseDomain::LookupThreadStaticBlockType(UINT32 id) { +PTR_MethodTable BaseDomain::LookupNonGCThreadStaticBlockType(UINT32 id) { CONTRACTL { NOTHROW; WRAPPER(GC_TRIGGERS); CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS); } CONTRACTL_END; - PTR_MethodTable pMT = m_threadStaticBlockTypeIDMap.LookupType(id); + PTR_MethodTable pMT = m_NonGCThreadStaticBlockTypeIDMap.LookupType(id); + + CONSISTENCY_CHECK(CheckPointer(pMT)); + return pMT; +} +//------------------------------------------------------------------------ +UINT32 BaseDomain::GetGCThreadStaticTypeIndex(PTR_MethodTable pMT) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + PRECONDITION(pMT->GetDomain() == this); + } CONTRACTL_END; + + return m_GCThreadStaticBlockTypeIDMap.GetTypeID(pMT, false); +} + +//------------------------------------------------------------------------ +PTR_MethodTable BaseDomain::LookupGCThreadStaticBlockType(UINT32 id) { + CONTRACTL { + NOTHROW; + WRAPPER(GC_TRIGGERS); + CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS); + } CONTRACTL_END; + + PTR_MethodTable pMT = m_GCThreadStaticBlockTypeIDMap.LookupType(id); CONSISTENCY_CHECK(CheckPointer(pMT)); return pMT; diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 15c1f119ca7d3..ab928ca5975ab 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1223,9 +1223,10 @@ class BaseDomain #ifdef HOST_WINDOWS // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. - // During execution corresponding thread static data blocks are stored in `t_threadStaticBlocks` - // array at the `typeIndex`. - TypeIDMap m_threadStaticBlockTypeIDMap; + // During execution corresponding thread static data blocks are stored in `t_NonGCThreadStaticBlocks` + // and `t_GCThreadStaticBlocks` array at the `typeIndex`. + TypeIDMap m_NonGCThreadStaticBlockTypeIDMap; + TypeIDMap m_GCThreadStaticBlockTypeIDMap; #endif // HOST_WINDOWS @@ -1234,9 +1235,11 @@ class BaseDomain #ifdef HOST_WINDOWS void InitThreadStaticBlockTypeMap(); - UINT32 GetThreadStaticTypeIndex(PTR_MethodTable pMT); + UINT32 GetNonGCThreadStaticTypeIndex(PTR_MethodTable pMT); + UINT32 GetGCThreadStaticTypeIndex(PTR_MethodTable pMT); - PTR_MethodTable LookupThreadStaticBlockType(UINT32 id); + PTR_MethodTable LookupNonGCThreadStaticBlockType(UINT32 id); + PTR_MethodTable LookupGCThreadStaticBlockType(UINT32 id); #endif UINT32 GetTypeID(PTR_MethodTable pMT); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 084281763c010..d4ce2c9aa69ac 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1779,13 +1779,23 @@ HCIMPLEND #ifdef _MSC_VER -__declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks; -__declspec(selectany) __declspec(thread) uint32_t t_threadStaticBlocksSize; -__declspec(selectany) __declspec(thread) void** t_threadStaticBlocks; +__declspec(selectany) __declspec(thread) uint32_t t_NonGCMaxThreadStaticBlocks; +__declspec(selectany) __declspec(thread) uint32_t t_GCMaxThreadStaticBlocks; + +__declspec(selectany) __declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize; +__declspec(selectany) __declspec(thread) uint32_t t_GCThreadStaticBlocksSize; + +__declspec(selectany) __declspec(thread) void** t_NonGCThreadStaticBlocks; +__declspec(selectany) __declspec(thread) void** t_GCThreadStaticBlocks; #else -EXTERN_C __thread uint32_t t_maxThreadStaticBlocks; -EXTERN_C __thread uint32_t t_threadStaticBlocksSize; -EXTERN_C __thread void** t_threadStaticBlocks; +EXTERN_C __thread uint32_t t_NonGCMaxThreadStaticBlocks; +EXTERN_C __thread uint32_t t_GCMaxThreadStaticBlocks; + +EXTERN_C __thread uint32_t t_NonGCThreadStaticBlocksSize; +EXTERN_C __thread uint32_t t_GCThreadStaticBlocksSize; + +EXTERN_C __thread void** t_NonGCThreadStaticBlocks; +EXTERN_C __thread void** t_GCThreadStaticBlocks; #endif // *** This helper corresponds to both CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE and @@ -1835,7 +1845,7 @@ HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIn HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame - MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupThreadStaticBlockType(staticBlockIndex); + MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupNonGCThreadStaticBlockType(staticBlockIndex); _ASSERTE(!pMT->HasGenericsStaticsInfo()); // Get the TLM @@ -1849,30 +1859,30 @@ HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIn staticBlock = (void*) pMT->GetNonGCThreadStaticsBasePointer(); CONSISTENCY_CHECK(staticBlock != NULL); - if (t_threadStaticBlocksSize <= staticBlockIndex) + if (t_NonGCThreadStaticBlocksSize <= staticBlockIndex) { - UINT32 newThreadStaticBlocksSize = max(2 * t_threadStaticBlocksSize, staticBlockIndex + 1); + UINT32 newThreadStaticBlocksSize = max(2 * t_NonGCThreadStaticBlocksSize, staticBlockIndex + 1); void** newThreadStaticBlocks = (void**) new PTR_BYTE[newThreadStaticBlocksSize * sizeof(PTR_BYTE)]; - memset(newThreadStaticBlocks + t_threadStaticBlocksSize, 0, (newThreadStaticBlocksSize - t_threadStaticBlocksSize) * sizeof(PTR_BYTE)); + memset(newThreadStaticBlocks + t_NonGCThreadStaticBlocksSize, 0, (newThreadStaticBlocksSize - t_NonGCThreadStaticBlocksSize) * sizeof(PTR_BYTE)); - if (t_threadStaticBlocksSize > 0) + if (t_NonGCThreadStaticBlocksSize > 0) { - memcpy(newThreadStaticBlocks, t_threadStaticBlocks, t_threadStaticBlocksSize * sizeof(PTR_BYTE)); - delete t_threadStaticBlocks; + memcpy(newThreadStaticBlocks, t_NonGCThreadStaticBlocks, t_NonGCThreadStaticBlocksSize * sizeof(PTR_BYTE)); + delete t_NonGCThreadStaticBlocks; } - t_threadStaticBlocksSize = newThreadStaticBlocksSize; - t_threadStaticBlocks = newThreadStaticBlocks; + t_NonGCThreadStaticBlocksSize = newThreadStaticBlocksSize; + t_NonGCThreadStaticBlocks = newThreadStaticBlocks; } - void* currentEntry = t_threadStaticBlocks[staticBlockIndex]; + void* currentEntry = t_NonGCThreadStaticBlocks[staticBlockIndex]; // We could be coming here 2nd time after running the ctor when we try to get the static block. // In such case, just avoid adding the same entry. if (currentEntry != staticBlock) { _ASSERTE(currentEntry == nullptr); - t_threadStaticBlocks[staticBlockIndex] = staticBlock; - t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); + t_NonGCThreadStaticBlocks[staticBlockIndex] = staticBlock; + t_NonGCMaxThreadStaticBlocks = max(t_NonGCMaxThreadStaticBlocks, staticBlockIndex); } HELPER_METHOD_FRAME_END(); #else @@ -1920,6 +1930,71 @@ HCIMPL2(void*, JIT_GetSharedGCThreadStaticBase, DomainLocalModule *pDomainLocalM HCIMPLEND #include +// *** This helper corresponds CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED. +// Even though we always check if the class constructor has been run, we have a separate +// helper ID for the "no ctor" version because it allows the JIT to do some reordering that +// otherwise wouldn't be possible. +HCIMPL1(void*, JIT_GetSharedGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) +{ + void* staticBlock = nullptr; + +#ifdef HOST_WINDOWS + FCALL_CONTRACT; + + HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame + + MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupGCThreadStaticBlockType(staticBlockIndex); + _ASSERTE(!pMT->HasGenericsStaticsInfo()); + + // Get the TLM + ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT); + _ASSERTE(pThreadLocalModule != NULL); + + // Check if the class constructor needs to be run + pThreadLocalModule->CheckRunClassInitThrowing(pMT); + + // Lookup the GC statics base handle and cache it + staticBlock = (void*) pMT->GetGCThreadStaticsBaseHandle(); + CONSISTENCY_CHECK(staticBlock != NULL); + + if (t_GCThreadStaticBlocksSize <= staticBlockIndex) + { + UINT32 newThreadStaticBlocksSize = max(2 * t_GCThreadStaticBlocksSize, staticBlockIndex + 1); + void** newThreadStaticBlocks = (void**) new PTR_BYTE[newThreadStaticBlocksSize * sizeof(PTR_BYTE)]; + memset(newThreadStaticBlocks + t_GCThreadStaticBlocksSize, 0, (newThreadStaticBlocksSize - t_GCThreadStaticBlocksSize) * sizeof(PTR_BYTE)); + + if (t_GCThreadStaticBlocksSize > 0) + { + memcpy(newThreadStaticBlocks, t_GCThreadStaticBlocks, t_GCThreadStaticBlocksSize * sizeof(PTR_BYTE)); + delete t_GCThreadStaticBlocks; + } + + t_GCThreadStaticBlocksSize = newThreadStaticBlocksSize; + t_GCThreadStaticBlocks = newThreadStaticBlocks; + } + + void* currentEntry = t_GCThreadStaticBlocks[staticBlockIndex]; + // We could be coming here 2nd time after running the ctor when we try to get the static block. + // In such case, just avoid adding the same entry. + if (currentEntry != staticBlock) + { + _ASSERTE(currentEntry == nullptr); + t_GCThreadStaticBlocks[staticBlockIndex] = staticBlock; + t_GCMaxThreadStaticBlocks = max(t_GCMaxThreadStaticBlocks, staticBlockIndex); + } + + // Get the data pointer of static block + staticBlock = (void*) pMT->GetGCThreadStaticsBasePointer(); + + HELPER_METHOD_FRAME_END(); +#else + _ASSERTE(!"JIT_GetSharedGCThreadStaticBaseOptimized not supported on non-windows."); +#endif // HOST_WINDOWS + + return staticBlock; +} +HCIMPLEND + // *** This helper corresponds to CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS #include diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ae9d45fd28e2f..85d904b566cdd 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -70,8 +70,11 @@ EXTERN_C uint32_t _tls_index; #endif #ifdef _MSC_VER -__declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks; -__declspec(selectany) __declspec(thread) void** t_threadStaticBlocks; +__declspec(selectany) __declspec(thread) uint32_t t_NonGCMaxThreadStaticBlocks; +__declspec(selectany) __declspec(thread) uint32_t t_GCMaxThreadStaticBlocks; + +__declspec(selectany) __declspec(thread) void** t_NonGCThreadStaticBlocks; +__declspec(selectany) __declspec(thread) void** t_GCThreadStaticBlocks; #else EXTERN_C __thread uint32_t t_maxThreadStaticBlocks; EXTERN_C __thread void** t_threadStaticBlocks; @@ -1570,16 +1573,20 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, #ifdef HOST_WINDOWS #ifndef TARGET_ARM - bool canOptimizeHelper = (pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) || - (pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE); // For windows, we convert the TLS access to the optimized helper where we will store // the static blocks in TLS directly and access them via inline code. - if (canOptimizeHelper && ((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() < ELEMENT_TYPE_STRING))) + if ((pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) || + (pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE)) { fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; - pResult->helper = CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; } + else if ((pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR) || + (pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE)) + { + fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; + pResult->helper = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; + } #endif // !TARGET_ARM #endif // HOST_WINDOWS } @@ -1768,7 +1775,7 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, #ifdef HOST_WINDOWS /*********************************************************************/ -uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) +uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isGCType) { CONTRACTL { THROWS; @@ -1783,7 +1790,14 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) FieldDesc* fieldDesc = (FieldDesc*)field; _ASSERTE(fieldDesc->IsThreadStatic()); - typeIndex = AppDomain::GetCurrentDomain()->GetThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable()); + if (isGCType) + { + typeIndex = AppDomain::GetCurrentDomain()->GetGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable()); + } + else + { + typeIndex = AppDomain::GetCurrentDomain()->GetNonGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable()); + } assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID); @@ -1792,7 +1806,7 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) } /*********************************************************************/ -void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) { CONTRACTL { NOTHROW; @@ -1806,13 +1820,24 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo->tlsIndex.accessType = IAT_VALUE; pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); - pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); - pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); + if (isGCType) + { + pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_GCThreadStaticBlocks); + pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_GCMaxThreadStaticBlocks); + } + else + { + pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_NonGCThreadStaticBlocks); + pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_NonGCMaxThreadStaticBlocks); + } + + pInfo->offsetOfGCDataPointer = static_cast(PtrArray::GetDataOffset()); JIT_TO_EE_TRANSITION_LEAF(); } #else -uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) + +uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isGCType) { CONTRACTL { NOTHROW; @@ -1823,7 +1848,7 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) return 0; } -void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) { CONTRACTL { NOTHROW; @@ -1838,6 +1863,7 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo->offsetOfThreadLocalStoragePointer = 0; pInfo->offsetOfThreadStaticBlocks = 0; pInfo->offsetOfMaxThreadStaticBlocks = 0; + pInfo->offsetOfGCDataPointer = 0; JIT_TO_EE_TRANSITION_LEAF(); } diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index acffd1b6141c7..634e05177c8a3 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2285,6 +2285,7 @@ class MethodTable inline PTR_BYTE GetGCStaticsBasePointer(); inline PTR_BYTE GetNonGCThreadStaticsBasePointer(); inline PTR_BYTE GetGCThreadStaticsBasePointer(); + inline PTR_BYTE GetGCThreadStaticsBaseHandle(); #endif //!DACCESS_COMPILE inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread); diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index 55d0015f86790..3a11158e097d0 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1157,6 +1157,32 @@ inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer() return pTLM->GetNonGCStaticsBasePointer(this); } +//========================================================================================== +inline PTR_BYTE MethodTable::GetGCThreadStaticsBaseHandle() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + // Get the current thread + PTR_Thread pThread = dac_cast(GetThread()); + + // Get the current module's ModuleIndex + ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); + + PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); + + PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); + if (pTLM == NULL) + return NULL; + + return dac_cast(pTLM->GetPrecomputedGCStaticsBaseHandle()); +} + //========================================================================================== inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer() { From ff65075a1f79f4a76146321f725cc950d66c3d04 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 13 May 2023 02:35:24 -0400 Subject: [PATCH 07/11] Remove char[] allocation from TarHeader (#86201) --- .../System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs index e51129631fc6d..f72a69d5dcc13 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.cs @@ -120,7 +120,7 @@ internal void InitializeExtendedAttributesWithExisting(IEnumerable kvp = enumerator.Current; - int index = kvp.Key.IndexOfAny(new char[] { '=', '\n' }); + int index = kvp.Key.AsSpan().IndexOfAny('=', '\n'); if (index >= 0) { throw new ArgumentException(SR.Format(SR.TarExtAttrDisallowedKeyChar, kvp.Key, kvp.Key[index] == '\n' ? "\\n" : kvp.Key[index])); From aa38055cca67d9ece504cef2adc8a19f0cb2ec8e Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sat, 13 May 2023 07:42:33 -0700 Subject: [PATCH 08/11] JIT: do early block merging in more cases (#86157) OSR and PGO both rely on the fact that the early flowgraph the JIT builds is the same flowgraph as the one seen in a previous JIT complation of that method, since there is metadata (patchpoint offset, pgo schema) that refers to the flowgraph. Previous work here (#85860) didn't ensure this for enough cases. In particular if Tier0 does not do early block merging, but OSR does, it's possible for the OSR entry point to fall within a merged block range, which the JIT is not prepared to handle. This lead to the asserts seen in #86125. The fix is to enable early block merging unless we're truly in a minopts or debug codegen mode (previous to this Tier0 would not merge unless it also was instrumenting; now it will always merge). An alternative fix would be to find the block containing the OSR entry IL offset, scan its statements, and split the block at the right spot, but that seemed more involved. Fixes #86125. --- src/coreclr/jit/compiler.h | 16 ++++++++++++---- src/coreclr/jit/fgbasic.cpp | 4 ++-- src/coreclr/jit/importer.cpp | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 3b777c5b36a7c..9dd385f6596c5 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9393,11 +9393,19 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX return IsInstrumented() && jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT); } - bool CanBeInstrumentedOrIsOptimized() const + bool DoEarlyBlockMerging() const { - return IsInstrumented() || (jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0) && - jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR_IF_LOOPS)) || - jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT); + if (jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC) || jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_CODE)) + { + return false; + } + + if (jitFlags->IsSet(JitFlags::JIT_FLAG_MIN_OPT) && !jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0)) + { + return false; + } + + return true; } // true if we should use the PINVOKE_{BEGIN,END} helpers instead of generating diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 0e009919acbd4..61f2c846edfac 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -1840,7 +1840,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed if ((jmpDist == 0) && (opcode == CEE_LEAVE || opcode == CEE_LEAVE_S || opcode == CEE_BR || opcode == CEE_BR_S) && - opts.CanBeInstrumentedOrIsOptimized()) + opts.DoEarlyBlockMerging()) { break; /* NOP */ } @@ -2989,7 +2989,7 @@ unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, F jmpDist = (sz == 1) ? getI1LittleEndian(codeAddr) : getI4LittleEndian(codeAddr); - if ((jmpDist == 0) && (opcode == CEE_BR || opcode == CEE_BR_S) && opts.CanBeInstrumentedOrIsOptimized()) + if ((jmpDist == 0) && (opcode == CEE_BR || opcode == CEE_BR_S) && opts.DoEarlyBlockMerging()) { continue; /* NOP */ } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 22c25523f41dd..14866e1e171fb 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -7420,7 +7420,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CEE_BR_S: jmpDist = (sz == 1) ? getI1LittleEndian(codeAddr) : getI4LittleEndian(codeAddr); - if ((jmpDist == 0) && opts.CanBeInstrumentedOrIsOptimized()) + if ((jmpDist == 0) && opts.DoEarlyBlockMerging()) { break; /* NOP */ } From c7008d3c1a27d5e5720372843b6751926bdf7f20 Mon Sep 17 00:00:00 2001 From: RaymondHuy Date: Sun, 14 May 2023 08:47:19 +0700 Subject: [PATCH 09/11] Add ImmutableArray.Contains overload that accepts an IEqualityComparer (#86210) --- .../ref/System.Collections.Immutable.cs | 1 + .../Collections/Immutable/ImmutableArray_1.cs | 14 ++++++++++++++ .../tests/ImmutableArrayTest.cs | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs index aef043fd8a090..a9d74045f1546 100644 --- a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs +++ b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs @@ -265,6 +265,7 @@ public static System.Collections.Immutable.ImmutableArray< > CastUp(System.Collections.Immutable.ImmutableArray items) where TDerived : class?, T { throw null; } public System.Collections.Immutable.ImmutableArray Clear() { throw null; } public bool Contains(T item) { throw null; } + public bool Contains(T item, System.Collections.Generic.IEqualityComparer? equalityComparer) { throw null; } public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length) { } public void CopyTo(T[] destination) { } public void CopyTo(T[] destination, int destinationIndex) { } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs index 780a43ca5be63..6c9fdb1341cba 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs @@ -280,6 +280,20 @@ public bool Contains(T item) return this.IndexOf(item) >= 0; } + /// + /// Determines whether the specified item exists in the array. + /// + /// The item to search for. + /// + /// The equality comparer to use in the search. + /// If null, is used. + /// + /// true if an equal value was found in the array; false otherwise. + public bool Contains(T item, IEqualityComparer? equalityComparer) + { + return this.IndexOf(item, equalityComparer) >= 0; + } + /// /// Returns a new array with the specified value inserted at the specified position. /// diff --git a/src/libraries/System.Collections.Immutable/tests/ImmutableArrayTest.cs b/src/libraries/System.Collections.Immutable/tests/ImmutableArrayTest.cs index 84fdb53e78302..bc7f7df4761bb 100644 --- a/src/libraries/System.Collections.Immutable/tests/ImmutableArrayTest.cs +++ b/src/libraries/System.Collections.Immutable/tests/ImmutableArrayTest.cs @@ -810,6 +810,24 @@ public void ContainsInt32(IEnumerable source) Assert.False(((ICollection)array).Contains(notContained)); } + [Fact] + public void ContainsDivisibleEqualityComparer() + { + ImmutableArray array = ImmutableArray.Create(1, 4, 3); + var divisibleComparer = new DelegateEqualityComparer(equals: (x, y) => x % y == 0); + Assert.True(array.Contains(2, divisibleComparer)); + + array = ImmutableArray.Create(1, 5, 3); + Assert.False(array.Contains(2, divisibleComparer)); + } + + [Fact] + public void ContainsDefaultEqualityComparer() + { + ImmutableArray array = ImmutableArray.Create(1, 2, 3); + Assert.True(array.Contains(2, null)); + } + [Theory] [MemberData(nameof(ContainsNullData))] public void ContainsNull(IEnumerable source) where T : class From f107b63fca1bd617a106e3cc7e86b337151bff79 Mon Sep 17 00:00:00 2001 From: yowl Date: Sun, 14 May 2023 00:56:01 -0500 Subject: [PATCH 10/11] For Wasi build on windows, do not set CLR_CMAKE_TARGET_WIN32 (#86208) Co-authored-by: Jan Kotas --- eng/native/configureplatform.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index 192e3a302974a..2c477097dd0c0 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -461,10 +461,12 @@ if(CLR_CMAKE_TARGET_UNIX) else() clr_unknown_arch() endif() -else() - set(CLR_CMAKE_TARGET_WIN32 1) endif(CLR_CMAKE_TARGET_UNIX) +if(CLR_CMAKE_TARGET_OS STREQUAL windows) + set(CLR_CMAKE_TARGET_WIN32 1) +endif() + # check if host & target os/arch combination are valid if (NOT (CLR_CMAKE_TARGET_OS STREQUAL CLR_CMAKE_HOST_OS) AND NOT CLR_CMAKE_TARGET_WASI) if(NOT (CLR_CMAKE_HOST_OS STREQUAL windows)) From 9dd59af3aee2f403e63887afef50d98022a2e575 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Mon, 15 May 2023 03:30:23 +0800 Subject: [PATCH 11/11] Update Base64StringAttribute.cs (#86221) --- .../DataAnnotations/Base64StringAttribute.cs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Base64StringAttribute.cs b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Base64StringAttribute.cs index bb67765914a51..490e6d74b7cc5 100644 --- a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Base64StringAttribute.cs +++ b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Base64StringAttribute.cs @@ -1,7 +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 System.Buffers; +using System.Buffers.Text; namespace System.ComponentModel.DataAnnotations { @@ -45,20 +45,7 @@ public override bool IsValid(object? value) return false; } - byte[]? rentedBuffer = null; - Span destinationBuffer = valueAsString.Length < 256 - ? stackalloc byte[256] - : rentedBuffer = ArrayPool.Shared.Rent(valueAsString.Length); - - bool result = Convert.TryFromBase64String(valueAsString, destinationBuffer, out int bytesWritten); - - if (rentedBuffer != null) - { - destinationBuffer.Slice(0, bytesWritten).Clear(); - ArrayPool.Shared.Return(rentedBuffer); - } - - return result; + return Base64.IsValid(valueAsString); } } }