From 4dddf46bc54883785e79076d4bfd125424f1177b Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sun, 26 Dec 2021 07:10:20 -0500 Subject: [PATCH] Mark Go override as SkipLocalsInit if possible It can have so many locals that zero-initing is measurable. --- .../gen/RegexGenerator.Emitter.cs | 12 +++++++++--- .../gen/RegexGenerator.cs | 2 +- .../RegexGeneratorParserTests.cs | 12 +++++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index cbe77998186a2d..b95387ba4eceed 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -41,7 +41,7 @@ public partial class RegexGenerator }; /// Generates the code for one regular expression class. - private static (string, ImmutableArray) EmitRegexType(RegexType regexClass) + private static (string, ImmutableArray) EmitRegexType(RegexType regexClass, Compilation compilation) { var sb = new StringBuilder(1024); var writer = new IndentedTextWriter(new StringWriter(sb)); @@ -82,7 +82,7 @@ private static (string, ImmutableArray) EmitRegexType(RegexType rege generatedName += ComputeStringHash(generatedName).ToString("X"); // Generate the regex type - ImmutableArray diagnostics = EmitRegexMethod(writer, regexClass.Method, generatedName); + ImmutableArray diagnostics = EmitRegexMethod(writer, regexClass.Method, generatedName, compilation); while (writer.Indent != 0) { @@ -149,7 +149,7 @@ static bool ExceedsMaxDepthForSimpleCodeGeneration(RegexNode node, int allowedDe } /// Generates the code for a regular expression method. - private static ImmutableArray EmitRegexMethod(IndentedTextWriter writer, RegexMethod rm, string id) + private static ImmutableArray EmitRegexMethod(IndentedTextWriter writer, RegexMethod rm, string id, Compilation compilation) { string patternExpression = Literal(rm.Pattern); string optionsExpression = Literal(rm.Options); @@ -174,6 +174,8 @@ private static ImmutableArray EmitRegexMethod(IndentedTextWriter wri return ImmutableArray.Create(Diagnostic.Create(DiagnosticDescriptors.LimitedSourceGeneration, rm.MethodSyntax.GetLocation())); } + bool allowUnsafe = compilation.Options is CSharpCompilationOptions { AllowUnsafe: true }; + writer.WriteLine($"new {id}();"); writer.WriteLine(); writer.WriteLine($" private {id}()"); @@ -231,6 +233,10 @@ private static ImmutableArray EmitRegexMethod(IndentedTextWriter wri writer.Indent -= 4; writer.WriteLine($" }}"); writer.WriteLine(); + if (allowUnsafe) + { + writer.WriteLine($" [global::System.Runtime.CompilerServices.SkipLocalsInit]"); + } writer.WriteLine($" protected override void Go()"); writer.WriteLine($" {{"); writer.Indent += 4; diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.cs index a459c8312c2639..558c613eae3a8f 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.cs @@ -49,7 +49,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { Debug.Assert(state.Item1 is not null); object? result = GetRegexTypeToEmit(state.Item2, state.Item1, cancellationToken); - return result is RegexType regexType ? EmitRegexType(regexType) : result; + return result is RegexType regexType ? EmitRegexType(regexType, state.Item2) : result; }) .Collect(); diff --git a/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Generators.Tests/RegexGeneratorParserTests.cs b/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Generators.Tests/RegexGeneratorParserTests.cs index 1e8523d2f73f4a..da7e19c820128e 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Generators.Tests/RegexGeneratorParserTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Generators.Tests/RegexGeneratorParserTests.cs @@ -297,8 +297,10 @@ partial class C ", compile: true)); } - [Fact] - public async Task Valid_ClassWithNamespace() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task Valid_ClassWithNamespace(bool allowUnsafe) { Assert.Empty(await RunGenerator(@" using System.Text.RegularExpressions; @@ -310,7 +312,7 @@ partial class C private static partial Regex Valid(); } } - ", compile: true)); + ", compile: true, allowUnsafe: allowUnsafe)); } [Fact] @@ -557,13 +559,13 @@ partial class C } private async Task> RunGenerator( - string code, bool compile = false, LanguageVersion langVersion = LanguageVersion.Preview, MetadataReference[]? additionalRefs = null, CancellationToken cancellationToken = default) + string code, bool compile = false, LanguageVersion langVersion = LanguageVersion.Preview, MetadataReference[]? additionalRefs = null, bool allowUnsafe = false, CancellationToken cancellationToken = default) { var proj = new AdhocWorkspace() .AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create())) .AddProject("RegexGeneratorTest", "RegexGeneratorTest.dll", "C#") .WithMetadataReferences(additionalRefs is not null ? s_refs.Concat(additionalRefs) : s_refs) - .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: allowUnsafe) .WithNullableContextOptions(NullableContextOptions.Enable)) .WithParseOptions(new CSharpParseOptions(langVersion)) .AddDocument("RegexGenerator.g.cs", SourceText.From(code, Encoding.UTF8)).Project;