Skip to content

JIT: import static readonly fields holding frozen objects as const handles - #76112

Merged
EgorBo merged 70 commits into
dotnet:mainfrom
EgorBo:frozen-static-readonly
Oct 10, 2022
Merged

JIT: import static readonly fields holding frozen objects as const handles#76112
EgorBo merged 70 commits into
dotnet:mainfrom
EgorBo:frozen-static-readonly

Conversation

@EgorBo

@EgorBoEgorBo commented Sep 24, 2022

Copy link
Copy Markdown
Member

JIT is able to fold static readonly fields to constants for primitive types. This PR extends that to handle such fields pointing to frozen objects, example:

// static readonly frozen stringstaticstringMyStr{get;}= "Hello";
// static readonly frozen TypestaticreadonlyTypes_type=typeof(int);// static readonly null (env var doesn't exist)staticreadonlystringMyConfig=Environment.GetEnvironmentVariable("NonExistingEnvVar");staticvoidFoo(){WriteLine(MyStr);WriteLine(s_type);WriteLine(MyConfig);}

Tier1 codegen diff for Foo:

; Assembly listing for method Foo()
; Tier-1 compilation
G_M14074_IG01: 4883EC28 sub rsp, 40
G_M14074_IG02: - 48B9C01EC0CB9E020000 mov rcx, 0x29ECBC01EC0 ; const ptr- 488B09 mov rcx, gword ptr [rcx]+ 48B9B017954DDA010000 mov rcx, 0x1DA4D9517B0 ; 'Hello'
FF15B9073800 call [System.Console:WriteLine(System.String)]
- 48B9C81EC0CB9E020000 mov rcx, 0x29ECBC01EC8 ; const ptr- 488B09 mov rcx, gword ptr [rcx]+ 48B9D017954DDA010000 mov rcx, 0x1DA4D9517D0 ; 'System.Int32'
FF158E073800 call [System.Console:WriteLine(System.Object)]
- 48B9D01E80DDBD010000 mov rcx, 0x1BDDD801ED0 ; data for ConsoleApp1.Program:MyConfig- 488B09 mov rcx, gword ptr [rcx]+ 33C9 xor rcx, rcx
FF155C871A00 call [ConsoleApp1.Program:WriteLine(System.Object)]
90 nop G_M14074_IG03: 4883C428 add rsp, 40
C3 ret 

UPD: Also, this PR helps NativeAOT:

see #76112 (comment) thread

Motivation

  1. static readonly Type .* = typeof pattern found 211 matches in dotnet/runtime (tests are not included)
    Example: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs#L15-L18
  2. static readonly string .* = "\w+"; found 119 results in dotnet/runtime (tests are not included)
  3. It's needed for future ideas, e.g. Array.Empty<T> as was suggested by @jkotas

Jit-diff (-f --pmi --cctors)

Total bytes of base: 63732878
Total bytes of diff: 63700726
Total bytes of delta: -32152 (-0.05 % of base)
Total relative delta: -62.29
diff is an improvement.
relative diff is an improvement.
Total byte diff includes -54 bytes from reconciling methods
Base had 3 unique methods, 54 unique bytes
Diff had 0 unique methods, 0 unique bytes
Top file regressions (bytes):
3160 : Newtonsoft.Json.dasm (0.33% of base)
715 : Microsoft.CSharp.dasm (0.17% of base)
456 : Microsoft.CodeAnalysis.CSharp.dasm (0.01% of base)
419 : System.Private.Uri.dasm (0.48% of base)
239 : System.IO.Packaging.dasm (0.26% of base)
205 : xunit.execution.dotnet.dasm (0.07% of base)
155 : Microsoft.Diagnostics.Tools.RuntimeClient.dasm (1.40% of base)
68 : System.Linq.Expressions.dasm (0.01% of base)
54 : Microsoft.CodeAnalysis.dasm (0.00% of base)
40 : System.Threading.RateLimiting.dasm (0.02% of base)
37 : Microsoft.Extensions.Configuration.Abstractions.dasm (0.86% of base)
32 : tieringtest.dasm (0.45% of base)
27 : System.Drawing.Common.dasm (0.00% of base)
16 : System.ComponentModel.Composition.dasm (0.00% of base)
16 : runincontext.dasm (0.11% of base)
8 : System.DirectoryServices.Protocols.dasm (0.01% of base)
8 : System.Net.Http.dasm (0.00% of base)
8 : Microsoft.Extensions.Http.dasm (0.02% of base)
8 : System.Runtime.Caching.dasm (0.01% of base)
Top file improvements (bytes):
-35586 : Microsoft.Diagnostics.Tracing.TraceEvent.dasm (-0.94% of base)
-576 : Microsoft.Diagnostics.FastSerialization.dasm (-0.24% of base)
-374 : System.Private.Xml.dasm (-0.01% of base)
-286 : System.Private.CoreLib.dasm (-0.00% of base)
-183 : System.Private.DataContractSerialization.dasm (-0.02% of base)
-176 : xunit.runner.utility.netcoreapp10.dasm (-0.08% of base)
-81 : System.Data.OleDb.dasm (-0.03% of base)
-80 : System.Runtime.Serialization.Formatters.dasm (-0.08% of base)
-76 : System.Data.Odbc.dasm (-0.03% of base)
-74 : Microsoft.Extensions.Options.dasm (-0.26% of base)
-72 : Microsoft.CodeAnalysis.VisualBasic.dasm (-0.00% of base)
-51 : System.ComponentModel.Annotations.dasm (-0.11% of base)
-48 : Microsoft.Extensions.Hosting.Abstractions.dasm (-0.50% of base)
-45 : System.DirectoryServices.AccountManagement.dasm (-0.01% of base)
-32 : Newtonsoft.Json.Bson.dasm (-0.03% of base)
-24 : FSharp.Core.dasm (-0.00% of base)
-17 : System.Text.Json.dasm (-0.00% of base)
-9 : System.Private.Xml.Linq.dasm (-0.00% of base)
-9 : System.Runtime.Serialization.Schema.dasm (-0.02% of base)
-6 : System.Configuration.ConfigurationManager.dasm (-0.00% of base)
-6 : System.Net.Primitives.dasm (-0.01% of base)
-6 : System.Data.Common.dasm (-0.00% of base)
-3 : xunit.console.dasm (-0.00% of base)
-3 : Microsoft.Extensions.DependencyModel.dasm (-0.00% of base)
43 total files with Code Size differences (24 improved, 19 regressed), 231 unchanged.
Top method regressions (bytes):
425 (123.19% of base) : System.Private.Uri.dasm - System.UriBuilder:.ctor(System.String):this
342 (170.15% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:RemoveDelegates(System.Func`2[System.Delegate,bool]):this
242 (27.66% of base) : System.IO.Packaging.dasm - System.IO.Packaging.PackUriHelper:Create(System.Uri,System.Uri,System.String):System.Uri
228 (140.74% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.ErrorFacts:GetDescription(int):Microsoft.CodeAnalysis.LocalizableResourceString
228 (140.74% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.ErrorFacts:GetTitle(int):Microsoft.CodeAnalysis.LocalizableResourceString
199 (13.71% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextReader:ParseValue():bool:this
198 (18.80% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[ushort],System.Threading.CancellationToken):System.Threading.Tasks.Task:this (2 methods)
195 (330.51% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:Invoke(System.Object[]):System.Object:this
195 (39.47% of base) : xunit.execution.dotnet.dasm - Xunit.ExecutionHelper:get_PlatformSuffix():System.String
183 (22.10% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[ushort],System.Threading.CancellationToken):System.Threading.Tasks.Task:this (2 methods)
134 (22.22% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[System.Decimal],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
123 (20.60% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[ulong],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
120 (800.00% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:get_Empty():bool:this
114 (23.27% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[ulong],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
114 (30.89% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[System.DateTimeOffset],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
114 (31.40% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[System.Guid],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
107 (24.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[System.Decimal],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
96 (20.00% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[bool],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
96 (16.78% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[byte],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
96 (17.05% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[int],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
96 (16.81% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[short],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
96 (16.90% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[ubyte],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
96 (17.11% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[uint],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
93 (16.85% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[long],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
90 (24.52% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[bool],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
88 (20.66% of base) : Microsoft.Diagnostics.Tools.RuntimeClient.dasm - Microsoft.Diagnostics.Tools.RuntimeClient.EventPipeClient:ListAvailablePorts():System.Collections.Generic.IEnumerable`1[int]
87 (19.04% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[byte],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
87 (19.08% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[int],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
87 (19.04% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[short],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
87 (19.04% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[ubyte],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
Top method improvements (bytes):
-16117 (-16.63% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.ApplicationServerTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-1660 (-14.19% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.AspNet.AspNetTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-1360 (-4.23% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.KernelTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-611 (-2.88% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.ClrTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-292 (-21.73% of base) : System.Private.CoreLib.dasm - System.Reflection.RuntimeParameterInfo:GetDefaultValueInternal(bool):System.Object:this
-170 (-4.44% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.Clr.ClrRundownTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-149 (-0.72% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.ClrPrivateTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-129 (-16.80% of base) : xunit.runner.utility.netcoreapp10.dasm - Xunit.DiaSession:GetNavigationData(System.String,System.String,System.String):Xunit.DiaNavigationData:this
-127 (-8.61% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.JSDumpHeapTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-80 (-3.62% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.SymbolTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-63 (-2.88% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.Kernel.HeapTraceProviderTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-63 (-2.91% of base) : System.Private.DataContractSerialization.dasm - System.Runtime.Serialization.XmlReaderDelegator:ReadExtensionData(System.Type):System.Runtime.Serialization.IDataNode:this
-61 (-16.62% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:RemoveDelegate(System.Delegate,bool):this
-48 (-2.81% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.Kernel.ThreadPoolTraceEventParser:EnumerateTemplates(System.Func`3[System.String,System.String,int],System.Action`1[Microsoft.Diagnostics.Tracing.TraceEvent]):this
-47 (-37.01% of base) : xunit.runner.utility.netcoreapp10.dasm - Xunit.DiaSession:.ctor(System.String):this
-45 (-11.31% of base) : System.Runtime.Serialization.Formatters.dasm - System.Runtime.Serialization.Formatters.Binary.Converter:InitArrayTypeA()
-45 (-11.31% of base) : System.Runtime.Serialization.Formatters.dasm - System.Runtime.Serialization.Formatters.Binary.Converter:InitTypeA()
-42 (-4.40% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxNode:GetSerializationData():System.Collections.Generic.IEnumerable`1[System.Object]
-37 (-100.00% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:PublishNewWrappers(DelegateWrapper[],DelegateWrapper[]):bool:this (1 base, 0 diff methods)
-33 (-2.37% of base) : System.Private.DataContractSerialization.dasm - System.Runtime.Serialization.Json.XmlObjectSerializerReadContextComplexJson:ReadNumericalPrimitiveExtensionDataValue(System.Runtime.Serialization.XmlReaderDelegator):System.Runtime.Serialization.IDataNode
-30 (-2.63% of base) : Microsoft.CodeAnalysis.dasm - FileStream:.cctor()
-27 (-0.84% of base) : System.Data.OleDb.dasm - System.Data.OleDb.OleDbMetaDataFactory:.ctor(System.IO.Stream,System.String,System.String,System.Data.OleDb.SchemaSupport[]):this
-23 (-88.46% of base) : System.DirectoryServices.AccountManagement.dasm - System.DirectoryServices.AccountManagement.GlobalConfig:get_DebugLogFile():System.String
-23 (-0.93% of base) : System.Private.Xml.dasm - System.Xml.Schema.XmlMiscConverter:ChangeType(System.Object,System.Type,System.Xml.IXmlNamespaceResolver):System.Object:this
-22 (-88.00% of base) : System.DirectoryServices.AccountManagement.dasm - System.DirectoryServices.AccountManagement.GlobalConfig:get_DebugLevel():int
-21 (-0.92% of base) : System.Data.Odbc.dasm - System.Data.Odbc.OdbcMetaDataFactory:.ctor(System.IO.Stream,System.String,System.String,System.Data.Odbc.OdbcConnection):this
-21 (-2.32% of base) : System.Data.Odbc.dasm - System.Data.Odbc.OdbcMetaDataFactory:PrepareCollection(System.String,System.String[],System.Data.Common.DbConnection):System.Data.DataTable:this
-19 (-6.51% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.KernelTraceEventParser:add_DiskIOFlushBuffers(System.Action`1[Microsoft.Diagnostics.Tracing.Parsers.Kernel.DiskIOFlushBuffersTraceData]):this
-19 (-6.51% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.KernelTraceEventParser:add_DiskIOFlushInit(System.Action`1[Microsoft.Diagnostics.Tracing.Parsers.Kernel.DiskIOInitTraceData]):this
-19 (-6.51% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.KernelTraceEventParser:add_DiskIORead(System.Action`1[Microsoft.Diagnostics.Tracing.Parsers.Kernel.DiskIOTraceData]):this
Top method regressions (percentages):
120 (800.00% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:get_Empty():bool:this
195 (330.51% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:Invoke(System.Object[]):System.Object:this
342 (170.15% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:RemoveDelegates(System.Func`2[System.Delegate,bool]):this
228 (140.74% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.ErrorFacts:GetDescription(int):Microsoft.CodeAnalysis.LocalizableResourceString
228 (140.74% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.ErrorFacts:GetTitle(int):Microsoft.CodeAnalysis.LocalizableResourceString
425 (123.19% of base) : System.Private.Uri.dasm - System.UriBuilder:.ctor(System.String):this
53 (73.61% of base) : Microsoft.Extensions.Configuration.Abstractions.dasm - Microsoft.Extensions.Configuration.ConfigurationPath:Combine(System.String[]):System.String
32 (50.79% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:.ctor(int):this
79 (46.75% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteNullAsync(System.Threading.CancellationToken):System.Threading.Tasks.Task:this
78 (39.59% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[System.DateTime],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
78 (39.59% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[System.TimeSpan],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
195 (39.47% of base) : xunit.execution.dotnet.dasm - Xunit.ExecutionHelper:get_PlatformSuffix():System.String
81 (38.21% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[System.Guid],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
8 (38.10% of base) : System.Private.CoreLib.dasm - System.Diagnostics.Stopwatch:GetElapsedTime(long,long):System.TimeSpan
78 (36.79% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[System.DateTimeOffset],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
114 (31.40% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[System.Guid],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
114 (30.89% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[System.DateTimeOffset],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
78 (30.23% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteNullAsync(System.Threading.CancellationToken):System.Threading.Tasks.Task:this
32 (28.83% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsSink:AddMethod(int):System.Runtime.InteropServices.ComEventsMethod:this
242 (27.66% of base) : System.IO.Packaging.dasm - System.IO.Packaging.PackUriHelper:Create(System.Uri,System.Uri,System.String):System.Uri
78 (25.41% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[System.DateTime],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
78 (25.41% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[System.TimeSpan],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
107 (24.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[System.Decimal],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
84 (24.56% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:AddDelegate(System.Delegate,bool):this
90 (24.52% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[bool],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
114 (23.27% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[ulong],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
134 (22.22% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[System.Decimal],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
183 (22.10% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:DoWriteValueAsync(System.Nullable`1[ushort],System.Threading.CancellationToken):System.Threading.Tasks.Task:this (2 methods)
88 (20.66% of base) : Microsoft.Diagnostics.Tools.RuntimeClient.dasm - Microsoft.Diagnostics.Tools.RuntimeClient.EventPipeClient:ListAvailablePorts():System.Collections.Generic.IEnumerable`1[int]
123 (20.60% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.JsonTextWriter:WriteValueAsync(System.Nullable`1[ulong],System.Threading.CancellationToken):System.Threading.Tasks.Task:this
Top method improvements (percentages):
-1 (-100.00% of base) : Microsoft.CSharp.dasm - <>c__DisplayClass12_0:.ctor():this (1 base, 0 diff methods)
-16 (-100.00% of base) : Microsoft.CSharp.dasm - <>c__DisplayClass12_0:<RemoveDelegates>b__0(DelegateWrapper):bool:this (1 base, 0 diff methods)
-37 (-100.00% of base) : Microsoft.CSharp.dasm - System.Runtime.InteropServices.ComEventsMethod:PublishNewWrappers(DelegateWrapper[],DelegateWrapper[]):bool:this (1 base, 0 diff methods)
-23 (-88.46% of base) : System.DirectoryServices.AccountManagement.dasm - System.DirectoryServices.AccountManagement.GlobalConfig:get_DebugLogFile():System.String
-22 (-88.00% of base) : System.DirectoryServices.AccountManagement.dasm - System.DirectoryServices.AccountManagement.GlobalConfig:get_DebugLevel():int
-47 (-37.01% of base) : xunit.runner.utility.netcoreapp10.dasm - Xunit.DiaSession:.ctor(System.String):this
-9 (-31.03% of base) : System.Private.CoreLib.dasm - System.RuntimeType:GetCustomAttributes(bool):System.Object[]:this
-292 (-21.73% of base) : System.Private.CoreLib.dasm - System.Reflection.RuntimeParameterInfo:GetDefaultValueInternal(bool):System.Object:this
-3 (-21.43% of base) : Microsoft.CodeAnalysis.dasm - HexPropertyMetadataNamedArgument:get_ArgumentName():System.String:this
-3 (-21.43% of base) : xunit.console.dasm - Internal.Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment:get_OperatingSystem():System.String
-3 (-21.43% of base) : xunit.console.dasm - Internal.Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment:get_RuntimeArchitecture():System.String
-3 (-21.43% of base) : Microsoft.CodeAnalysis.dasm - Microsoft.CodeAnalysis.CodeGen.PermissionSetFileReadException:get_PropertyName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tools.RuntimeClient.dasm - Microsoft.Diagnostics.Tools.RuntimeClient.DiagnosticsIpc.IpcClient:get_DiagnosticsPortPattern():System.String
-3 (-21.43% of base) : Microsoft.Diagnostics.Tools.RuntimeClient.dasm - Microsoft.Diagnostics.Tools.RuntimeClient.DiagnosticsIpc.IpcClient:get_IpcRootPath():System.String
-3 (-21.43% of base) : Microsoft.Diagnostics.Tools.RuntimeClient.dasm - Microsoft.Diagnostics.Tools.RuntimeClient.EventPipeClient:get_DiagnosticsPortPattern():System.String
-3 (-21.43% of base) : Microsoft.Diagnostics.Tools.RuntimeClient.dasm - Microsoft.Diagnostics.Tools.RuntimeClient.EventPipeClient:get_IpcRootPath():System.String
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.AutomatedAnalysis.StackTypes:get_CPU():System.String
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.ApplicationServerTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.AspNet.AspNetTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.Clr.ClrRundownTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.Clr.ClrStressTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.ClrPrivateTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.ClrTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.FrameworkEventSourceTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.JScriptTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.JSDumpHeapTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.Kernel.CritSecTraceProviderTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.Kernel.HeapTraceProviderTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.Kernel.ThreadPoolTraceEventParser:GetProviderName():System.String:this
-3 (-21.43% of base) : Microsoft.Diagnostics.Tracing.TraceEvent.dasm - Microsoft.Diagnostics.Tracing.Parsers.KernelTraceEventParser:GetProviderName():System.String:this
2259 total methods with Code Size differences (2153 improved, 106 regressed), 389393 unchanged.

Regressions seem to be CSE related e.g. https://www.diffchecker.com/E3PieJCB + changed inlining decisions due to changes in gtGetClassHandle

PR is verbose due to JIT-EE update, the actual changes are fairly small.

@ghostghost added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Sep 24, 2022
@ghostghost assigned EgorBoSep 24, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

JIT is able to fold static readonly fields to constants for primitive types. This PR extends that on frozen objects, example:

staticstringMyStr{get;}= "Hello";
staticreadonlyTypes_type=typeof(int);staticvoidFoo(){Console.WriteLine(MyStr);Console.WriteLine(s_type);}

Tier1 codegen diff for Foo:

; Assembly listing for method Foo()
; Tier-1 compilation
G_M14074_IG01: 4883EC28 sub rsp, 40
G_M14074_IG02: - 48B9C01EC0CB9E020000 mov rcx, 0x29ECBC01EC0 ; const ptr- 488B09 mov rcx, gword ptr [rcx]+ 48B9B017954DDA010000 mov rcx, 0x1DA4D9517B0 ; 'Hello'
FF15B9073800 call [System.Console:WriteLine(System.String)]
- 48B9C81EC0CB9E020000 mov rcx, 0x29ECBC01EC8 ; const ptr- 488B09 mov rcx, gword ptr [rcx]+ 48B9D017954DDA010000 mov rcx, 0x1DA4D9517D0 ; 'System.Int32'
FF158E073800 call [System.Console:WriteLine(System.Object)]
90 nop G_M14074_IG03: 4883C428 add rsp, 40
C3 ret 

Motivation

  1. static readonly Type .* = typeof pattern found 211 matches in dotnet/runtime (tests are not included)
    Example: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.Cache.cs#L15-L18
  2. It's needed for future ideas, e.g. Array.Empty<T> as was suggested by @jkotas

Jit-diff

PR is verbose due to JIT-EE update, the actual changes are fairly small.

Author:EgorBo
Assignees:EgorBo
Labels:

area-CodeGen-coreclr

Milestone:-

Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated
Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated
Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated
@jkotas

Copy link
Copy Markdown
Member

BTW: Storing frozen objects does not require write barrier. For example:

string[] a = new string[1];
a[0] = "Hello"; // no GC write barrier needed if "Hello" is frozen object

Does this optimization happen already? If not, we just need to skip the write barrier for frozen icon handles, similar how we skip them for nulls.

Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated
Comment threadsrc/coreclr/jit/importer.cpp Outdated
@EgorBo

Copy link
Copy Markdown
MemberAuthor

BTW: Storing frozen objects does not require write barrier. For example:

string[] a = new string[1];
a[0] = "Hello"; // no GC write barrier needed if "Hello" is frozen object

Does this optimization happen already? If not, we just need to skip the write barrier for frozen icon handles, similar how we skip them for nulls.

Good point! Do you mind if I do it separately, I also wanted to e.g. check if it's worth optimizing pinning against frozen objects, etc. Separate commits also help to triage perf improvements/regressions

@jkotas

Copy link
Copy Markdown
Member

Good point! Do you mind if I do it separately

Yes, it is fine to do it separately.

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
Comment threadsrc/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp
Comment threadsrc/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Outdated
Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated
Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM otherwise. Thank you!

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Comment threadsrc/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Outdated
Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated
Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated
Comment threadsrc/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Outdated
…pl.RyuJit.cs
Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Comment threadsrc/coreclr/vm/jitinterface.cpp Outdated
@EgorBo

Copy link
Copy Markdown
MemberAuthor

Looks like IsThreadStatic check should be preserved on VM side, jit doesn't know that info in advance it seems, there is CORINFO_FIELD_STATIC_TLS but that, presumably, for native TLS

@jkotas

Copy link
Copy Markdown
Member

Looks like IsThreadStatic check should be preserved on VM side, jit doesn't know that info in advance it seems, there is CORINFO_FIELD_STATIC_TLS but that, presumably, for native TLS

Sounds reasonable.

@EgorBoEgorBo closed this Oct 9, 2022
@EgorBoEgorBo reopened this Oct 9, 2022
@EgorBo

Copy link
Copy Markdown
MemberAuthor

CI is green except SPMI jobs (JIT-EE change), going to merge

@EgorBo
EgorBo merged commit 12caa8f into dotnet:mainOct 10, 2022
@ghostghost locked as resolved and limited conversation to collaborators Nov 10, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@EgorBo@jkotas@jakobbotsch@VSadov@MichalStrehovsky@SingleAccretion