From 49cce7a9aa0f29893c266906a2520fa8273e94ca Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Mon, 18 Mar 2024 12:07:41 -0700 Subject: [PATCH 1/4] Improvements to performance of mono_wasm_get_assembly_exports --- .../gen/JSImportGenerator/JSExportGenerator.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs index ffe0fe6a0f995..8ada0d78672ed 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs @@ -241,8 +241,9 @@ private static NamespaceDeclarationSyntax GenerateRegSource( .WithModifiers(TokenList(new[] { Token(SyntaxKind.StaticKeyword) })) .WithBody(Block(registerStatements)); - // when we are running code generated by .NET8 on .NET7 runtime we need to auto initialize the assembly, because .NET7 doesn't call the registration from JS - // this also keeps the code protected from trimming + // HACK: protect the code from trimming by putting it behind a comparison we know + // will always evaluate to false at runtime, but the linker can't see through at + // build time. It seems there's no attribute to block trimming of a method? MemberDeclarationSyntax initializerMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier(selfInitName)) .WithAttributeLists(List(new[]{ AttributeList(SingletonSeparatedList(Attribute(IdentifierName(Constants.ModuleInitializerAttributeGlobal)))), @@ -253,8 +254,8 @@ private static NamespaceDeclarationSyntax GenerateRegSource( })) .WithBody(Block( IfStatement(BinaryExpression(SyntaxKind.EqualsExpression, - IdentifierName("Environment.Version.Major"), - LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(7))), + IdentifierName("System.Runtime.InteropServices.JavaScript.JSHost.GlobalThis"), + LiteralExpression(SyntaxKind.NullLiteralExpression)), Block(SingletonList( ExpressionStatement(InvocationExpression(IdentifierName(initializerName)))))))); From e47a08a7ae16c37c7c8eb265c641527918387d32 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Wed, 3 Apr 2024 13:56:26 -0700 Subject: [PATCH 2/4] Preserve register method using DynamicDependency --- .../gen/JSImportGenerator/Constants.cs | 1 + .../JSImportGenerator/JSExportGenerator.cs | 39 ++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Constants.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Constants.cs index 520eeba3ec4e8..a5475e27c70a4 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Constants.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Constants.cs @@ -17,6 +17,7 @@ internal static class Constants public const string ModuleInitializerAttributeGlobal = "global::System.Runtime.CompilerServices.ModuleInitializerAttribute"; public const string CompilerGeneratedAttributeGlobal = "global::System.Runtime.CompilerServices.CompilerGeneratedAttribute"; public const string DynamicDependencyAttributeGlobal = "global::System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute"; + public const string DynamicallyAccessedMemberTypesGlobal = "global::System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes"; public const string ThreadStaticGlobal = "global::System.ThreadStaticAttribute"; public const string TaskGlobal = "global::System.Threading.Tasks.Task"; public const string SpanGlobal = "global::System.Span"; diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs index 8ada0d78672ed..19a3d677c74cd 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs @@ -245,19 +245,40 @@ private static NamespaceDeclarationSyntax GenerateRegSource( // will always evaluate to false at runtime, but the linker can't see through at // build time. It seems there's no attribute to block trimming of a method? MemberDeclarationSyntax initializerMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier(selfInitName)) - .WithAttributeLists(List(new[]{ - AttributeList(SingletonSeparatedList(Attribute(IdentifierName(Constants.ModuleInitializerAttributeGlobal)))), - })) + .WithAttributeLists( + SingletonList( + AttributeList( + SeparatedList( + new SyntaxNodeOrToken[]{ + Attribute( + IdentifierName(Constants.ModuleInitializerAttributeGlobal)), + Token(SyntaxKind.CommaToken), + Attribute( + IdentifierName(Constants.DynamicDependencyAttributeGlobal)) + .WithArgumentList( + AttributeArgumentList( + SeparatedList( + new SyntaxNodeOrToken[]{ + AttributeArgument( + BinaryExpression( + SyntaxKind.BitwiseOrExpression, + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(Constants.DynamicallyAccessedMemberTypesGlobal), + IdentifierName("PublicMethods")), + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(Constants.DynamicallyAccessedMemberTypesGlobal), + IdentifierName("NonPublicMethods")))), + Token(SyntaxKind.CommaToken), + AttributeArgument( + TypeOfExpression( + IdentifierName(initializerClass)))})))})))) .WithModifiers(TokenList(new[] { Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.InternalKeyword) })) - .WithBody(Block( - IfStatement(BinaryExpression(SyntaxKind.EqualsExpression, - IdentifierName("System.Runtime.InteropServices.JavaScript.JSHost.GlobalThis"), - LiteralExpression(SyntaxKind.NullLiteralExpression)), - Block(SingletonList( - ExpressionStatement(InvocationExpression(IdentifierName(initializerName)))))))); + .WithBody(Block()); var ns = NamespaceDeclaration(IdentifierName(generatedNamespace)) .WithMembers( From 1401aa3a5f0a7e54a1aaa773134686d35e1a3738 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Wed, 3 Apr 2024 13:57:58 -0700 Subject: [PATCH 3/4] Fix comment --- .../gen/JSImportGenerator/JSExportGenerator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs index 19a3d677c74cd..95a327b1cc076 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs @@ -241,9 +241,7 @@ private static NamespaceDeclarationSyntax GenerateRegSource( .WithModifiers(TokenList(new[] { Token(SyntaxKind.StaticKeyword) })) .WithBody(Block(registerStatements)); - // HACK: protect the code from trimming by putting it behind a comparison we know - // will always evaluate to false at runtime, but the linker can't see through at - // build time. It seems there's no attribute to block trimming of a method? + // HACK: protect the code from trimming with DynamicDependency attached to a ModuleInitializer MemberDeclarationSyntax initializerMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier(selfInitName)) .WithAttributeLists( SingletonList( From 77f918b8d1f4924385f792a564b74a93645603a9 Mon Sep 17 00:00:00 2001 From: Katelyn Gadd Date: Thu, 4 Apr 2024 07:44:55 -0700 Subject: [PATCH 4/4] Address PR feedback --- .../gen/JSImportGenerator/JSExportGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs index 95a327b1cc076..ee7eb94cdd3e5 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs @@ -215,7 +215,7 @@ private static NamespaceDeclarationSyntax GenerateRegSource( const string generatedNamespace = "System.Runtime.InteropServices.JavaScript"; const string initializerClass = "__GeneratedInitializer"; const string initializerName = "__Register_"; - const string selfInitName = "__Net7SelfInit_"; + const string trimmingPreserveName = "__TrimmingPreserve_"; if (methods.IsEmpty) return NamespaceDeclaration(IdentifierName(generatedNamespace)); @@ -242,7 +242,7 @@ private static NamespaceDeclarationSyntax GenerateRegSource( .WithBody(Block(registerStatements)); // HACK: protect the code from trimming with DynamicDependency attached to a ModuleInitializer - MemberDeclarationSyntax initializerMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier(selfInitName)) + MemberDeclarationSyntax initializerMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier(trimmingPreserveName)) .WithAttributeLists( SingletonList( AttributeList(