diff options
author | Sven Boemer <sbomer@gmail.com> | 2022-08-18 01:50:53 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-18 01:50:53 +0300 |
commit | bc1f05f234bf70219687c255587e79439de9d6ee (patch) | |
tree | b1b654b9cdb9836d73df1bd2effbef5d334c585e | |
parent | c42e3cb42f354b13cd0414d0a4a1729146042583 (diff) |
Don't track current field of state machines (#2979)
There was a performance problem where we were tracking all
possible returned values throughout the method, since we were
treating them the same as hoisted locals. I'm sure it's still
possible to come up with testcases that show bad performance (for
example assigning many arrays to a hoisted local in the same
iterator), but this should at least fix the immediate issue
encountered in runtime.
5 files changed, 34 insertions, 15 deletions
diff --git a/src/linker/Linker.Dataflow/CompilerGeneratedNames.cs b/src/linker/Linker.Dataflow/CompilerGeneratedNames.cs index 46e6c9764..afdb716f5 100644 --- a/src/linker/Linker.Dataflow/CompilerGeneratedNames.cs +++ b/src/linker/Linker.Dataflow/CompilerGeneratedNames.cs @@ -34,6 +34,19 @@ namespace Mono.Linker.Dataflow return typeName.Length > i + 1 && typeName[i + 1] == 'd'; } + internal static bool IsStateMachineCurrentField (string fieldName) + { + if (!IsGeneratedMemberName (fieldName)) + return false; + + int i = fieldName.LastIndexOf ('>'); + if (i == -1) + return false; + + // Current field is <>2__current + return fieldName.Length > i + 1 && fieldName[i + 1] == '2'; + } + internal static bool IsGeneratedType (string name) => IsStateMachineType (name) || IsLambdaDisplayClass (name); internal static bool IsLambdaOrLocalFunction (string methodName) => IsLambdaMethod (methodName) || IsLocalFunction (methodName); diff --git a/src/linker/Linker.Dataflow/CompilerGeneratedState.cs b/src/linker/Linker.Dataflow/CompilerGeneratedState.cs index 3213f49fd..3033cef70 100644 --- a/src/linker/Linker.Dataflow/CompilerGeneratedState.cs +++ b/src/linker/Linker.Dataflow/CompilerGeneratedState.cs @@ -55,10 +55,16 @@ namespace Mono.Linker.Dataflow public static bool IsHoistedLocal (FieldDefinition field) { - // Treat all fields on compiler-generated types as hoisted locals. - // This avoids depending on the name mangling scheme for hoisted locals. - var declaringTypeName = field.DeclaringType.Name; - return CompilerGeneratedNames.IsLambdaDisplayClass (declaringTypeName) || CompilerGeneratedNames.IsStateMachineType (declaringTypeName); + if (CompilerGeneratedNames.IsLambdaDisplayClass (field.DeclaringType.Name)) + return true; + + if (CompilerGeneratedNames.IsStateMachineType (field.DeclaringType.Name)) { + // Don't track the "current" field which is used for state machine return values, + // because this can be expensive to track. + return !CompilerGeneratedNames.IsStateMachineCurrentField (field.Name); + } + + return false; } // "Nested function" refers to lambdas and local functions. diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs index 53032ae72..90b2c53bf 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeDataflow.cs @@ -210,8 +210,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow FlowParameterAcrossYieldReturn (); FlowUnannotatedParameterAcrossYieldReturn (); FlowAcrossYieldReturnWithBackwardsBranch (); - - foreach (var o in ReturnManyObjects ()); + + foreach (var o in ReturnManyObjects ()) ; } } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ILVerifier.cs b/test/Mono.Linker.Tests/TestCasesRunner/ILVerifier.cs index bf935cc22..d9d4b8a43 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ILVerifier.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ILVerifier.cs @@ -14,13 +14,13 @@ using Mono.Linker.Tests.Extensions; #nullable enable namespace Mono.Linker.Tests.TestCasesRunner { - class ILVerifier : ILVerify.IResolver + sealed class ILVerifier : ILVerify.IResolver { - Verifier _verifier; - NPath _assemblyFolder; - NPath _frameworkFolder; - Dictionary<string, PEReader> _assemblyCache; - AssemblyLoadContext _alc; + readonly Verifier _verifier; + readonly NPath _assemblyFolder; + readonly NPath _frameworkFolder; + readonly Dictionary<string, PEReader> _assemblyCache; + readonly AssemblyLoadContext _alc; public IEnumerable<VerificationResult> Results { get; private set; } @@ -123,7 +123,7 @@ namespace Mono.Linker.Tests.TestCasesRunner PEReader? ILVerify.IResolver.ResolveModule (AssemblyName referencingModule, string fileName) => Resolve (Path.GetFileNameWithoutExtension (fileName)); - public string GetErrorMessage (VerificationResult result) + public static string GetErrorMessage (VerificationResult result) { return $"IL Verification error:\n{result.Message}"; } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index ccb76575f..4a7de6de6 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -55,7 +55,7 @@ namespace Mono.Linker.Tests.TestCasesRunner foreach (var result in verifier.Results) { if (result.Code == ILVerify.VerifierError.None) continue; - Assert.Fail (verifier.GetErrorMessage (result)); + Assert.Fail (ILVerifier.GetErrorMessage (result)); } } @@ -1122,7 +1122,7 @@ namespace Mono.Linker.Tests.TestCasesRunner return false; } - static IEnumerable<CustomAttribute> GetCustomAttributes (ICustomAttributeProvider caProvider, string attributeName ) + static IEnumerable<CustomAttribute> GetCustomAttributes (ICustomAttributeProvider caProvider, string attributeName) { if (caProvider is AssemblyDefinition assembly && assembly.EntryPoint != null) return assembly.EntryPoint.DeclaringType.CustomAttributes |