runtime icon indicating copy to clipboard operation
runtime copied to clipboard

Allocate RuntimeType objects on Frozen Object Heap

Open EgorBo opened this issue 3 years ago • 19 comments
trafficstars

Follow up to https://github.com/dotnet/runtime/pull/49576 This PR allocates Type objects on the recently-added Frozen Segments so we can bake direct objects' addresses in JIT and avoid helper calls, e.g. for:

Type Test() => typeof(int);

Old codegen:

; Method Program:Test():System.Type:this
G_M50870_IG01: 
       4883EC28             sub      rsp, 40
G_M50870_IG02: 
       48B968BB53F5FB7F0000 mov      rcx, 0x7FFBF553BB68      ; System.Int32
       E81D94505F           call     CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
       90                   nop      
G_M50870_IG03: 
       4883C428             add      rsp, 40
       C3                   ret      
; Total bytes of code: 25

New codegen:

; Method Program:Test():System.Type:this
G_M50870_IG01: 
G_M50870_IG02:          
       48B8482A63DE29020000 mov      rax, 0x229DE632A48      ; System.Int32
G_M50870_IG03: 
       C3                   ret      
; Total bytes of code: 11

Jit-diffs (-f --pmi):

PMI CodeSize Diffs for System.Private.CoreLib.dll, framework assemblies for  default jit

Summary of Code Size diffs:
(Lower is better)

Total bytes of base: 64750613
Total bytes of diff: 64621503
Total bytes of delta: -129110 (-0.20 % of base)
Total relative delta: -715.51
    diff is an improvement.
    relative diff is an improvement.


Top file improvements (bytes):
      -14241 : System.Text.Json.dasm (-1.22% of base)
      -12215 : System.Private.Xml.dasm (-0.30% of base)
      -11900 : System.Linq.Queryable.dasm (-3.49% of base)
       -9901 : System.Private.CoreLib.dasm (-0.17% of base)
       -7878 : System.Linq.Expressions.dasm (-0.90% of base)
       -6757 : System.Data.Common.dasm (-0.39% of base)
       -6516 : System.Private.DataContractSerialization.dasm (-0.71% of base)
       -4883 : System.ComponentModel.TypeConverter.dasm (-1.59% of base)
       -4275 : Newtonsoft.Json.dasm (-0.44% of base)
       -3175 : System.ComponentModel.Composition.dasm (-0.86% of base)
       -2984 : Microsoft.CodeAnalysis.VisualBasic.dasm (-0.04% of base)
       -2625 : Microsoft.CSharp.dasm (-0.61% of base)
       -2537 : System.DirectoryServices.dasm (-0.54% of base)
       -2418 : FSharp.Core.dasm (-0.06% of base)
       -2219 : System.DirectoryServices.AccountManagement.dasm (-0.52% of base)
       -1961 : Microsoft.CodeAnalysis.CSharp.dasm (-0.04% of base)
       -1539 : System.Data.OleDb.dasm (-0.45% of base)
       -1387 : System.Drawing.Common.dasm (-0.24% of base)
       -1309 : xunit.execution.dotnet.dasm (-0.47% of base)
       -1196 : Microsoft.VisualBasic.Core.dasm (-0.22% of base)

173 total files with Code Size differences (173 improved, 0 regressed), 101 unchanged.

Top method regressions (bytes):
         122 (13.22% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[System.Numerics.Vector`1[float]](System.Object):System.Numerics.Vector`1[float]
         115 (13.92% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[int](System.Object):int
         115 (13.69% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[long](System.Object):long
         115 (13.45% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[short](System.Object):short
         115 (13.67% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[ubyte](System.Object):ubyte
         112 (11.62% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[double](System.Object):double
          99 (11.22% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[System.Nullable`1[int]](System.Object):System.Nullable`1[int]
          89 ( 5.45% of base) : System.Composition.TypedParts.dasm - System.Composition.TypedParts.ActivationFeatures.PropertyInjectionFeature:RewriteActivator(System.Reflection.TypeInfo,System.Composition.Hosting.Core.CompositeActivator,System.Collections.Generic.IDictionary`2[System.String,System.Object],System.Collections.Generic.IEnumerable`1[System.Composition.Hosting.Core.CompositionDependency]):System.Composition.Hosting.Core.CompositeActivator:this
          69 ( 8.18% of base) : System.Private.CoreLib.dasm - AdjustmentRule:.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext):this
          68 ( 2.52% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.LightCompiler:CompileLiftedLogicalBinaryExpression(System.Linq.Expressions.BinaryExpression,bool):this
          62 ( 9.67% of base) : System.Data.Odbc.dasm - System.Data.Common.ADP:UnsafeCreateTimer(System.Threading.TimerCallback,System.Object,int,int):System.Threading.Timer
          59 ( 1.45% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationWriterCodeGen:WriteValue(System.Object):this
          58 ( 6.39% of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter:transBinOp(Microsoft.FSharp.Core.FSharpFunc`2[System.Type,bool],Microsoft.FSharp.Quotations.FSharpExpr,ConvEnv,bool,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,bool,Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`3[System.Linq.Expressions.Expression,System.Linq.Expressions.Expression,System.Reflection.MethodInfo],System.Linq.Expressions.BinaryExpression],System.RuntimeMethodHandle):System.Linq.Expressions.Expression
          56 ( 2.79% of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.RuntimeHelpers.Adapters:ConvImmutableTypeToMutableType(ConversionDescription,System.Type):System.Type
          55 ( 3.91% of base) : System.Private.CoreLib.dasm - System.Enum:TryParse[double](System.ReadOnlySpan`1[ushort],bool,bool,byref):bool
          55 ( 3.88% of base) : System.Private.CoreLib.dasm - System.Enum:TryParse[System.Numerics.Vector`1[float]](System.ReadOnlySpan`1[ushort],bool,bool,byref):bool
          54 ( 5.99% of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter:transShiftOp(Microsoft.FSharp.Quotations.FSharpExpr,ConvEnv,bool,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,bool,Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`3[System.Linq.Expressions.Expression,System.Linq.Expressions.Expression,System.Reflection.MethodInfo],System.Linq.Expressions.BinaryExpression],System.RuntimeMethodHandle):System.Linq.Expressions.Expression
          54 ( 4.81% of base) : System.Private.CoreLib.dasm - System.Decimal:.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext):this
          54 ( 4.26% of base) : System.Private.CoreLib.dasm - System.Enum:TryParse[long](System.ReadOnlySpan`1[ushort],bool,bool,byref):bool
          54 ( 4.30% of base) : System.Private.CoreLib.dasm - System.Enum:TryParse[ubyte](System.ReadOnlySpan`1[ushort],bool,bool,byref):bool

Top method improvements (bytes):
       -2328 (-26.68% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.SyntaxFactory:GetNodeTypes():System.Collections.Generic.IEnumerable`1[System.Object]
       -1496 (-26.69% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory:GetNodeTypes():System.Collections.Generic.IEnumerable`1[System.Type]
        -933 (-12.13% of base) : System.Data.Common.dasm - System.Data.DataTable:DeserializeTableSchema(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext,bool):this
        -714 (-12.83% of base) : System.Data.Common.dasm - System.Data.DataTable:SerializeTableSchema(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext,bool):this
        -480 (-5.29% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationReaderILGen:WriteLiteralStructMethod(System.Xml.Serialization.StructMapping):this
        -462 (-7.88% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationReaderILGen:WriteElement(System.String,System.String,System.String,System.Xml.Serialization.ElementAccessor,System.Xml.Serialization.ChoiceIdentifierAccessor,System.String,bool,bool,int,int):this
        -395 (-5.99% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationWriterILGen:WriteStructMethod(System.Xml.Serialization.StructMapping):this
        -360 (-6.65% of base) : System.ComponentModel.TypeConverter.dasm - <>c:<get_IntrinsicTypeConverters>b__24_0():System.Collections.Generic.Dictionary`2[System.Object,IntrinsicTypeConverterData]:this
        -343 (-17.03% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.Converters.IEnumerableConverterFactory:CreateConverter(System.Type,System.Text.Json.JsonSerializerOptions):System.Text.Json.Serialization.JsonConverter:this
        -326 (-5.34% of base) : System.Private.DataContractSerialization.dasm - DataContractCriticalHelper:TryCreateBuiltInDataContract(System.String,System.String,byref):bool
        -305 (-6.14% of base) : System.Data.Common.dasm - System.Data.DataTableReader:GetSchemaTableFromDataTable(System.Data.DataTable):System.Data.DataTable
        -287 (-47.52% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Compiler.DelegateHelpers:GetFuncType(System.Type[]):System.Type
        -276 (-46.78% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Compiler.DelegateHelpers:GetActionType(System.Type[]):System.Type
        -264 (-11.64% of base) : System.Private.DataContractSerialization.dasm - DataContractCriticalHelper:GetBuiltInDataContract(System.String):System.Runtime.Serialization.DataContracts.DataContract
        -262 (-5.19% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationWriterILGen:WriteMember(System.Xml.Serialization.SourceInfo,System.Xml.Serialization.AttributeAccessor,System.Xml.Serialization.TypeDesc,System.String):this
        -240 (-6.39% of base) : System.Private.Xml.dasm - System.Xml.Serialization.SchemaGraph:Depends(System.Xml.Schema.XmlSchemaObject,System.Collections.ArrayList):this
        -233 (-6.52% of base) : Microsoft.CSharp.dasm - Microsoft.CSharp.RuntimeBinder.ComInterop.ComInvokeBinder:GenerateTryBlock():System.Linq.Expressions.Expression:this
        -232 (-6.14% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationWriterILGen:WriteEnumMethod(System.Xml.Serialization.EnumMapping):this
        -228 (-5.30% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationWriterILGen:WriteEnumAndArrayTypes():this
        -227 (-5.05% of base) : System.Private.Xml.dasm - System.Xml.Serialization.ReflectionAwareCodeGen:WriteTypeInfo(System.Xml.Serialization.TypeScope,System.Xml.Serialization.TypeDesc,System.Type):System.String:this

Top method regressions (percentages):
          35 (14.11% of base) : FSharp.Core.dasm - Microsoft.FSharp.Text.StructuredPrintfImpl.Display:isSetOrMapType(System.Type):bool
         115 (13.92% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[int](System.Object):int
         115 (13.69% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[long](System.Object):long
         115 (13.67% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[ubyte](System.Object):ubyte
         115 (13.45% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[short](System.Object):short
         122 (13.22% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[System.Numerics.Vector`1[float]](System.Object):System.Numerics.Vector`1[float]
          11 (11.83% of base) : System.Composition.Hosting.dasm - System.Composition.Hosting.Util.MethodInfoExtensions:CreateStaticDelegate[System.Numerics.Vector`1[float]](System.Reflection.MethodInfo):System.Numerics.Vector`1[float]
         112 (11.62% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[double](System.Object):double
          99 (11.22% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[System.Nullable`1[int]](System.Object):System.Nullable`1[int]
          62 ( 9.67% of base) : System.Data.Odbc.dasm - System.Data.Common.ADP:UnsafeCreateTimer(System.Threading.TimerCallback,System.Object,int,int):System.Threading.Timer
          44 ( 9.17% of base) : Microsoft.Extensions.DependencyInjection.Abstractions.dasm - Microsoft.Extensions.DependencyInjection.ActivatorUtilities:CreateFactory(System.Type,System.Type[]):Microsoft.Extensions.DependencyInjection.ObjectFactory
          69 ( 8.18% of base) : System.Private.CoreLib.dasm - AdjustmentRule:.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext):this
          51 ( 7.92% of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter:transBoolOpNoWitness(Microsoft.FSharp.Core.FSharpFunc`2[System.Type,bool],ConvEnv,bool,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,bool,Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`4[System.Linq.Expressions.Expression,System.Linq.Expressions.Expression,bool,System.Reflection.MethodInfo],System.Linq.Expressions.BinaryExpression],System.Reflection.MethodInfo):System.Linq.Expressions.Expression
          40 ( 7.60% of base) : System.Composition.TypedParts.dasm - System.Composition.TypedParts.Discovery.DiscoveredPropertyExport:GetExportDescriptor(System.Composition.Hosting.Core.CompositeActivator):System.Composition.Hosting.Core.ExportDescriptor:this
          42 ( 7.24% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateMethodCall[System.__Canon](System.Reflection.MethodBase):Newtonsoft.Json.Utilities.MethodCall`2[System.__Canon,System.__Canon]:this
          48 ( 6.69% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[double](System.Reflection.FieldInfo):System.Action`2[double,System.Object]:this
          48 ( 6.69% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[int](System.Reflection.FieldInfo):System.Action`2[int,System.Object]:this
          48 ( 6.69% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[long](System.Reflection.FieldInfo):System.Action`2[long,System.Object]:this
          48 ( 6.69% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[short](System.Reflection.FieldInfo):System.Action`2[short,System.Object]:this
          48 ( 6.69% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[System.Nullable`1[int]](System.Reflection.FieldInfo):System.Action`2[System.Nullable`1[int],System.Object]:this

Top method improvements (percentages):
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[double]()
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[int]()
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[long]()
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[short]()
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[ubyte]()
         -40 (-71.43% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Expression:IfThenElse(System.Linq.Expressions.Expression,System.Linq.Expressions.Expression,System.Linq.Expressions.Expression):System.Linq.Expressions.ConditionalExpression
         -23 (-62.16% of base) : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.TypeHandle:TypeHandleOf[double]():System.Runtime.CompilerServices.TypeHandle
         -23 (-62.16% of base) : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.TypeHandle:TypeHandleOf[int]():System.Runtime.CompilerServices.TypeHandle
         -23 (-62.16% of base) : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.TypeHandle:TypeHandleOf[long]():System.Runtime.CompilerServices.TypeHandle
         -23 (-62.16% of base) : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.TypeHandle:TypeHandleOf[short]():System.Runtime.CompilerServices.TypeHandle
         -23 (-62.16% of base) : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.TypeHandle:TypeHandleOf[System.Nullable`1[int]]():System.Runtime.CompilerServices.TypeHandle
         -23 (-62.16% of base) : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.TypeHandle:TypeHandleOf[System.Numerics.Vector`1[float]]():System.Runtime.CompilerServices.TypeHandle
         -23 (-62.16% of base) : System.Private.CoreLib.dasm - System.Runtime.CompilerServices.TypeHandle:TypeHandleOf[ubyte]():System.Runtime.CompilerServices.TypeHandle
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[double](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[int](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[long](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[short](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[System.Nullable`1[int]](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[System.Numerics.Vector`1[float]](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[ubyte](long)

7846 total methods with Code Size differences (7511 improved, 335 regressed), 383629 unchanged.

Size regressions look to be CSE-related, e.g. https://www.diffchecker.com/eOr1LIyf E.g. previously call CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE could share its const argument with other places where we only need type handle (like in this diff)

Notes: In JIT I do the optimization in morph because a lot of other optimizations here and there (mostly in importer) rely on typeof() being a helper call so it's simpler for now, will try to perform a sort of clean up later - current change is minimalistic and doesn't produce regressions.

Closes https://github.com/dotnet/runtime/issues/49429

EgorBo avatar Sep 13 '22 23:09 EgorBo

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

Issue Details

Follow up to https://github.com/dotnet/runtime/pull/49576 This PR allocates Type objects on the recently-added Frozen Segments so we can bake direct objects' addresses in JIT and avoid helper calls, e.g. for:

Type Test() => typeof(int);

Old codegen:

; Method Program:Test():System.Type:this
G_M50870_IG01: 
       4883EC28             sub      rsp, 40
G_M50870_IG02: 
       48B968BB53F5FB7F0000 mov      rcx, 0x7FFBF553BB68      ; System.Int32
       E81D94505F           call     CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE
       90                   nop      
G_M50870_IG03: 
       4883C428             add      rsp, 40
       C3                   ret      
; Total bytes of code: 25

New codegen:

; Method Program:Test():System.Type:this
G_M50870_IG01: 
G_M50870_IG02:          
       48B8482A63DE29020000 mov      rax, 0x229DE632A48      ; Type handle
G_M50870_IG03: 
       C3                   ret      
; Total bytes of code: 11

Jit-diffs (-f --pmi):

Total bytes of base: 64641078
Total bytes of diff: 64511525
Total bytes of delta: -129553 (-0.20 % of base)
Total relative delta: -714.65
    diff is an improvement.
    relative diff is an improvement.


Top file improvements (bytes):
      -14248 : System.Text.Json.dasm (-1.22% of base)
      -12304 : System.Private.Xml.dasm (-0.30% of base)
      -11900 : System.Linq.Queryable.dasm (-3.49% of base)
       -9846 : System.Private.CoreLib.dasm (-0.17% of base)
       -7846 : System.Linq.Expressions.dasm (-0.90% of base)
       -6967 : System.Data.Common.dasm (-0.41% of base)
       -6519 : System.Private.DataContractSerialization.dasm (-0.71% of base)
       -4769 : System.ComponentModel.TypeConverter.dasm (-1.55% of base)
       -4491 : Newtonsoft.Json.dasm (-0.47% of base)
       -3168 : System.ComponentModel.Composition.dasm (-0.85% of base)
       -2984 : Microsoft.CodeAnalysis.VisualBasic.dasm (-0.04% of base)
       -2951 : FSharp.Core.dasm (-0.07% of base)
       -2662 : Microsoft.CSharp.dasm (-0.62% of base)
       -2537 : System.DirectoryServices.dasm (-0.54% of base)
       -2219 : System.DirectoryServices.AccountManagement.dasm (-0.52% of base)

173 total files with Code Size differences (173 improved, 0 regressed), 101 unchanged.

Top method regressions (bytes):
         122 (13.22% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[System.Numerics.Vector`1[float]](System.Object):System.Numerics.Vector`1[float]
         115 (13.92% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[int](System.Object):int
         115 (13.69% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[long](System.Object):long
         115 (13.45% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[short](System.Object):short
         115 (13.67% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[ubyte](System.Object):ubyte
         112 (11.62% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[double](System.Object):double
          99 (11.22% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[System.Nullable`1[int]](System.Object):System.Nullable`1[int]
          89 ( 5.45% of base) : System.Composition.TypedParts.dasm - System.Composition.TypedParts.ActivationFeatures.PropertyInjectionFeature:RewriteActivator(System.Reflection.TypeInfo,System.Composition.Hosting.Core.CompositeActivator,System.Collections.Generic.IDictionary`2[System.String,System.Object],System.Collections.Generic.IEnumerable`1[System.Composition.Hosting.Core.CompositionDependency]):System.Composition.Hosting.Core.CompositeActivator:this
          69 ( 8.18% of base) : System.Private.CoreLib.dasm - AdjustmentRule:.ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext):this
          68 ( 2.52% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.LightCompiler:CompileLiftedLogicalBinaryExpression(System.Linq.Expressions.BinaryExpression,bool):this
          62 ( 8.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[double](System.Reflection.FieldInfo):System.Action`2[double,System.Object]:this
          62 ( 8.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[int](System.Reflection.FieldInfo):System.Action`2[int,System.Object]:this
          62 ( 8.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[long](System.Reflection.FieldInfo):System.Action`2[long,System.Object]:this
          62 ( 8.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[short](System.Reflection.FieldInfo):System.Action`2[short,System.Object]:this
          62 ( 8.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[System.Nullable`1[int]](System.Reflection.FieldInfo):System.Action`2[System.Nullable`1[int],System.Object]:this

Top method improvements (bytes):
       -2328 (-26.68% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.SyntaxFactory:GetNodeTypes():System.Collections.Generic.IEnumerable`1[System.Object]
       -1496 (-26.69% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxFactory:GetNodeTypes():System.Collections.Generic.IEnumerable`1[System.Type]
        -933 (-12.13% of base) : System.Data.Common.dasm - System.Data.DataTable:DeserializeTableSchema(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext,bool):this
        -714 (-12.83% of base) : System.Data.Common.dasm - System.Data.DataTable:SerializeTableSchema(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext,bool):this
        -575 (-2.59% of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter:ConvExprToLinqInContext(ConvEnv,Microsoft.FSharp.Quotations.FSharpExpr):System.Linq.Expressions.Expression
        -480 (-5.29% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationReaderILGen:WriteLiteralStructMethod(System.Xml.Serialization.StructMapping):this
        -462 (-7.88% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationReaderILGen:WriteElement(System.String,System.String,System.String,System.Xml.Serialization.ElementAccessor,System.Xml.Serialization.ChoiceIdentifierAccessor,System.String,bool,bool,int,int):this
        -395 (-5.99% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationWriterILGen:WriteStructMethod(System.Xml.Serialization.StructMapping):this
        -343 (-17.03% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.Converters.IEnumerableConverterFactory:CreateConverter(System.Type,System.Text.Json.JsonSerializerOptions):System.Text.Json.Serialization.JsonConverter:this
        -326 (-5.34% of base) : System.Private.DataContractSerialization.dasm - DataContractCriticalHelper:TryCreateBuiltInDataContract(System.String,System.String,byref):bool
        -305 (-6.14% of base) : System.Data.Common.dasm - System.Data.DataTableReader:GetSchemaTableFromDataTable(System.Data.DataTable):System.Data.DataTable
        -287 (-47.52% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Compiler.DelegateHelpers:GetFuncType(<unnamed>):System.Type
        -276 (-46.78% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Compiler.DelegateHelpers:GetActionType(<unnamed>):System.Type
        -270 (-5.35% of base) : System.Private.Xml.dasm - System.Xml.Serialization.XmlSerializationWriterILGen:WriteMember(System.Xml.Serialization.SourceInfo,System.Xml.Serialization.AttributeAccessor,System.Xml.Serialization.TypeDesc,System.String):this
        -264 (-11.64% of base) : System.Private.DataContractSerialization.dasm - DataContractCriticalHelper:GetBuiltInDataContract(System.String):System.Runtime.Serialization.DataContracts.DataContract

Top method regressions (percentages):
          35 (14.11% of base) : FSharp.Core.dasm - Microsoft.FSharp.Text.StructuredPrintfImpl.Display:isSetOrMapType(System.Type):bool
         115 (13.92% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[int](System.Object):int
         115 (13.69% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[long](System.Object):long
         115 (13.67% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[ubyte](System.Object):ubyte
         115 (13.45% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[short](System.Object):short
         122 (13.22% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[System.Numerics.Vector`1[float]](System.Object):System.Numerics.Vector`1[float]
          58 (12.08% of base) : Microsoft.Extensions.DependencyInjection.Abstractions.dasm - Microsoft.Extensions.DependencyInjection.ActivatorUtilities:CreateFactory(System.Type,<unnamed>):Microsoft.Extensions.DependencyInjection.ObjectFactory
          11 (11.83% of base) : System.Composition.Hosting.dasm - System.Composition.Hosting.Util.MethodInfoExtensions:CreateStaticDelegate[System.Numerics.Vector`1[float]](System.Reflection.MethodInfo):System.Numerics.Vector`1[float]
         112 (11.62% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[double](System.Object):double
          99 (11.22% of base) : Microsoft.VisualBasic.Core.dasm - Microsoft.VisualBasic.CompilerServices.Conversions:ToGenericParameter[System.Nullable`1[int]](System.Object):System.Nullable`1[int]
          54 (10.27% of base) : System.Composition.TypedParts.dasm - System.Composition.TypedParts.Discovery.DiscoveredPropertyExport:GetExportDescriptor(System.Composition.Hosting.Core.CompositeActivator):System.Composition.Hosting.Core.ExportDescriptor:this
          48 ( 9.62% of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter:transBinOp(Microsoft.FSharp.Quotations.FSharpExpr,ConvEnv,bool,Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr],bool,Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[System.Linq.Expressions.Expression,System.Linq.Expressions.Expression],System.Linq.Expressions.BinaryExpression]):System.Linq.Expressions.Expression
          62 ( 8.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[double](System.Reflection.FieldInfo):System.Action`2[double,System.Object]:this
          62 ( 8.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[int](System.Reflection.FieldInfo):System.Action`2[int,System.Object]:this
          62 ( 8.65% of base) : Newtonsoft.Json.dasm - Newtonsoft.Json.Utilities.ExpressionReflectionDelegateFactory:CreateSet[long](System.Reflection.FieldInfo):System.Action`2[long,System.Object]:this

Top method improvements (percentages):
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[double]()
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[int]()
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[long]()
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[short]()
          -8 (-88.89% of base) : System.Diagnostics.DiagnosticSource.dasm - System.Diagnostics.Metrics.Instrument:ValidateTypeParameter[ubyte]()
         -40 (-71.43% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Expression:IfThenElse(System.Linq.Expressions.Expression,System.Linq.Expressions.Expression,System.Linq.Expressions.Expression):System.Linq.Expressions.ConditionalExpression
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[double](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[int](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[long](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[short](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[System.Nullable`1[int]](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[System.Numerics.Vector`1[float]](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.Runtime.InteropServices.Marshal:DestroyStructure[ubyte](long)
         -24 (-61.54% of base) : System.Private.CoreLib.dasm - System.RuntimeType:IsCOMObjectImpl():bool:this
         -34 (-60.71% of base) : System.Private.DataContractSerialization.dasm - System.Runtime.Serialization.DataContracts.CharDataContract:.ctor(System.Xml.XmlDictionaryString,System.Xml.XmlDictionaryString):this

7830 total methods with Code Size differences (7524 improved, 306 regressed), 383145 unchanged.

Size regressions look to be CSE-related, e.g. https://www.diffchecker.com/lDHsFUcP

Notes: In JIT I do the optimization in morph because a lot of stuff here and there rely on typeof() being a helper call so it's simpler for now, will try to perform a sort of clean up later - current change is minimalistic and doesn't produce regressions.

Author: EgorBo
Assignees: EgorBo
Labels:

area-CodeGen-coreclr

Milestone: -

ghost avatar Sep 13 '22 23:09 ghost

Seems to be passing CI tests (SPMI failures are due to JIT-EE change), @jkotas when you have time could you review the vm side?

EgorBo avatar Sep 14 '22 14:09 EgorBo

CI failures are weird, e.g. https://helixre107v0xdeko0k025g8.blob.core.windows.net/dotnet-runtime-refs-pull-75573-merge-3616944558404cd193/System.Linq.Queryable.Tests/1/console.13d74af2.log?helixlogtype=result had no luck trying to reproduce any, going to kick off a single gc stress job - maybe it will help to find a repro.

EgorBo avatar Sep 18 '22 01:09 EgorBo

/azp run Fuzzlyn

EgorBo avatar Sep 18 '22 01:09 EgorBo

Azure Pipelines successfully started running 1 pipeline(s).

azure-pipelines[bot] avatar Sep 18 '22 01:09 azure-pipelines[bot]

/azp run runtime-coreclr gcstress0x3-gcstress0xc

EgorBo avatar Sep 18 '22 03:09 EgorBo

Azure Pipelines successfully started running 1 pipeline(s).

azure-pipelines[bot] avatar Sep 18 '22 03:09 azure-pipelines[bot]

Ok, gcstress=0xc didn't find anything, and it doesn't look like it's a codegen issue (I disabled the jit optimization) Reproduces for me locally (not every run) for src\libraries\System.Formats.Asn1\tests built with Debug.

Judging by

System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array

it feels like it's related to type co(ntra)variance. Investigating..

Or it's a race condition since it doesn't repro when I ask xunit to run tests without parallelism 🤔

EgorBo avatar Sep 18 '22 14:09 EgorBo

@jkotas Anything else needed from VM side? It seems to be passing all tests (spmi jobs are failing due to JIT-EE guid change), I'll kick off (gently this time) a few outerloop pipelines to make sure. There are a few things I'd love to address separately later:

  1. Do the same for TypeDesc (diffs are pretty small from it though)
  2. Wire it up in NativeAOT (or can leave it for anyone interested)
  3. PublishObjectAndNotify problem from https://github.com/dotnet/runtime/pull/49576#issuecomment-1250248951

EgorBo avatar Sep 18 '22 18:09 EgorBo

https://github.com/icsharpcode/AvaloniaILSpy - when I run this average-size client app it allocates 12153 objects on the frozen segments (total size is 604kb). Going to check other apps/web services

EgorBo avatar Sep 18 '22 18:09 EgorBo

Do the same for TypeDesc (diffs are pretty small from it though)

I think it would be a good idea to address this as part of this PR. (I expect that you will want to move some the code that you are adding here around.)

The rest can wait for separate PR.

jkotas avatar Sep 18 '22 18:09 jkotas

Do the same for TypeDesc (diffs are pretty small from it though)

I think it would be a good idea to address this as part of this PR. (I expect that you will want to move some the code that you are adding here around.)

The rest can wait for separate PR.

Ok, pushed the change for ParamTypeDesc/TypeVarTypeDesc. The only thing I am not sure is the fact they all share the same lock. From the other hand, FrozenObjectHeapManager has its own lock they all will hit anyway if I create 3 different lock objects

EgorBo avatar Sep 18 '22 19:09 EgorBo

Ah, oops forgot to update the logic to extract OBJECTREF from the field for both

EgorBo avatar Sep 18 '22 20:09 EgorBo

/azp run runtime-coreclr outerloop

EgorBo avatar Sep 18 '22 22:09 EgorBo

Azure Pipelines successfully started running 1 pipeline(s).

azure-pipelines[bot] avatar Sep 18 '22 22:09 azure-pipelines[bot]

/azp run runtime-coreclr jitstressregs

EgorBo avatar Sep 19 '22 02:09 EgorBo

Azure Pipelines successfully started running 1 pipeline(s).

azure-pipelines[bot] avatar Sep 19 '22 02:09 azure-pipelines[bot]

Wire it up in NativeAOT (or can leave it for anyone interested)

We'll need to do some work on the reflection stack first - there's no unique RuntimeType type we could preallocate (NativeAOT has like half a dozen RuntimeType descendants), and it has GC-pointer fields (no-no in frozen segments). Having a single RuntimeType is our plan. It's just not there yet.

MichalStrehovsky avatar Sep 19 '22 10:09 MichalStrehovsky

@jakobbotsch @AndyAyersMS PTAL JIT side, like @jakobbotsch suggested I introduced a separate flag GTF_ICON_OBJ_HDL for both frozen strings and frozen RuntimeType objects. GTF_ICON_STR_HDL is kept for non-frozen string literals (e.g. too large or in unloadable context). Also, removed dangerous eeGetCPString and replaced it with JIT-EE calls (tested with SPMI)

Also note that I do the optimization in Morph (fgMorphCall) and not earlier because a lot of code in JIT expects call helper(handle) for optimizations during import/inlining - that's how I avoided regressions and minimized changes in JIT, will do a clean up at some point.

PS: this PR passed outerloop, jitstress and gcstress pipelines

EgorBo avatar Sep 19 '22 15:09 EgorBo

Current codegen for JIT_GetRuntimeType:

image

one less branch but + and rdx, 0FFFFFFFFFFFFFFFEh so presumably it's faster. The fast-return block is still too far but looks like MSVC just wants to have a single epilogue, I do hope it will change with native PGO 🙄

EgorBo avatar Sep 21 '22 00:09 EgorBo

Btw, for generics we can probably inline a fast path in jit, e.g. for:

[MethodImpl(MethodImplOptions.NoInlining)]
static Type Foo<T>() => typeof(T);

for __Canon version we currently emit:

       488B4938             mov      rcx, qword ptr [rcx+38H]
       488B09               mov      rcx, qword ptr [rcx]
       E84BD8505F           call     CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE

while we can inline the m_Exposed & 1 check if it's worth the effort

EgorBo avatar Sep 21 '22 00:09 EgorBo

The fast-return block is still too far but looks like MSVC just wants to have a single epilogue, I do hope it will change with native PGO

It won't. It is impossible for the C++ compiler to prove that handle - 1 is non-zero so it has to produce the redundant check.

I think there is a reason why the signature of LoaderAllocator::GetHandleValueFast is bool (handle, objectref*) and not objectref (handle). If you change the signature of TypeHandle::GetManagedClassObjectFromHandleFast to be bool (handle, objectref*), you should be able to get rid of the manual inlining and the redundant check.

jkotas avatar Sep 21 '22 00:09 jkotas

@jkotas thanks!! now it's clear why the initial shape was like that. I had to also play with GetManagedClassObjectFromHandleFast because it didn't want to inline.

The new codegen is perfect:

image

EgorBo avatar Sep 21 '22 01:09 EgorBo

VM changes LGTM. Thanks!

Thanks for patience and great help! Learned so many cool tricks and VM internals! 🙂 Btw, a quick prototype for a managed JIT_GetRuntimeType: https://github.com/EgorBo/runtime-1/commit/ef7a46583145b9917865dc1eb1cc85ccc041588e we can enable inlining for CastHelpers and get faster typeof for generics (if it shows any benefit). Although, some other helpers might benefit from inlining (especially on really hot paths with PGO) too.

@jakobbotsch does the jit part look good in this PR?

EgorBo avatar Sep 21 '22 02:09 EgorBo

/azp run runtime-coreclr outerloop, gcstress0x3-gcstress0xc

EgorBo avatar Sep 21 '22 02:09 EgorBo

Azure Pipelines successfully started running 1 pipeline(s).

azure-pipelines[bot] avatar Sep 21 '22 02:09 azure-pipelines[bot]

Btw, a quick prototype for a managed JIT_GetRuntimeType: https://github.com/EgorBo/runtime-1/commit/ef7a46583145b9917865dc1eb1cc85ccc041588e

We will get to this eventually. I think we need to do more cleanup of the runtime structures to make this sort of optimizations interesting and easy to maintain. For example, the writeable data indirection is useless. It should be inlined into Methodtable.

jkotas avatar Sep 21 '22 02:09 jkotas

Looks like this can be merged now, two Pri0 failures are from https://github.com/dotnet/runtime/pull/75952, SPMI ones are due to JIT-EE guid change (we still don't know how to avoid triggering those when both JIT and JIT-EE guid are changed in YML)

I plan to look into the profiler/diag issues raised in the other PR for FOH, and test this and the string literals on OSS (and, hopefully, some 1st parties) projects to get a better understanding how many objects make it to FOH.

Then we might look into making static objects (at least those without GC fields inside) also FOH-based

EgorBo avatar Sep 22 '22 14:09 EgorBo

Then we might look into making static objects (at least those without GC fields inside) also FOH-based

How do you plan to do that? I do not think it is feasible without AOT step (or without doing expensive work when JITing static constructors - I do not expect we would want to do that).

jkotas avatar Sep 22 '22 15:09 jkotas

Can we do it for static field boxes (the ones created for non-primitives)? Today, JIT needs to create

ADD byref
  IND  ref
    CNS <object slot addr>
  CNS 8

for all such accesses, I believe. We could potentially create direct pointer to the boxed contents.

jakobbotsch avatar Sep 22 '22 15:09 jakobbotsch