dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.71k stars 3.98k forks source link

Use module initializer in syntax generator #62659

Open RikkiGibson opened 1 year ago

RikkiGibson commented 1 year ago

Currently the syntax generator produces a static constructor for each green node (internal) type. e.g.

https://raw.githubusercontent.com/dotnet/roslyn/main/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs

        static IdentifierNameSyntax()
        {
            ObjectBinder.RegisterTypeReader(typeof(IdentifierNameSyntax), r => new IdentifierNameSyntax(r));
        }

We identified that when a type has a static constructor, the runtime actually needs to insert a check each time the type is used to determine whether the static constructor needs to run or not. This negatively affects perf. This is why we added the module initializers feature, to enable use of a long-standing CLR feature in C#.

Maybe we should change the generator to produce a single module initializer which registers all these type readers up-front.

RikkiGibson commented 1 year ago

There are other common types such as DiagnosticInfo and SyntaxAnnotation which have static constructors in order to register here. Maybe we could also consider adding an internal attribute to such types (declared in "user code") then introducing a source generator which does the registration for them in a single module initializer.

Since source generators can't see each other's outputs you'd basically get a single module initializer for all the types in user code that need this, then another module initializer for each generator which produces types that need this.