Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't cache the Compilation object in steps in the interop source generators #76474

Merged
merged 4 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,22 @@ internal sealed class JSExportCodeGenerator : JSCodeGenerator
private readonly JSSignatureContext _signatureContext;

public JSExportCodeGenerator(
StubEnvironment environment,
TargetFramework targetFramework,
Version targetFrameworkVersion,
ImmutableArray<TypePositionInfo> argTypes,
JSExportData attributeData,
JSSignatureContext signatureContext,
Action<TypePositionInfo, MarshallingNotSupportedException> marshallingNotSupportedCallback,
IMarshallingGeneratorFactory generatorFactory)
{
_signatureContext = signatureContext;
ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnIdentifier);
ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier);
_context = new JSExportCodeContext(attributeData, innerContext);
_marshallers = new BoundGenerators(argTypes, CreateGenerator);
if (_marshallers.ManagedReturnMarshaller.Generator.UsesNativeIdentifier(_marshallers.ManagedReturnMarshaller.TypeInfo, null))
{
// If we need a different native return identifier, then recreate the context with the correct identifier before we generate any code.
innerContext = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnNativeIdentifier);
innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnNativeIdentifier);
_context = new JSExportCodeContext(attributeData, innerContext);
_marshallers = new BoundGenerators(argTypes, CreateGenerator);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,13 @@ namespace Microsoft.Interop.JavaScript
public sealed class JSExportGenerator : IIncrementalGenerator
{
internal sealed record IncrementalStubGenerationContext(
StubEnvironment Environment,
JSSignatureContext SignatureContext,
ContainingSyntaxContext ContainingSyntaxContext,
ContainingSyntax StubMethodSyntaxTemplate,
MethodSignatureDiagnosticLocations DiagnosticLocation,
JSExportData JSExportData,
MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> GeneratorFactoryKey,
ImmutableArray<Diagnostic> Diagnostics)
{
public bool Equals(IncrementalStubGenerationContext? other)
{
return other is not null
&& StubEnvironment.AreCompilationSettingsEqual(Environment, other.Environment)
&& SignatureContext.Equals(other.SignatureContext)
&& ContainingSyntaxContext.Equals(other.ContainingSyntaxContext)
&& StubMethodSyntaxTemplate.Equals(other.StubMethodSyntaxTemplate)
&& JSExportData.Equals(other.JSExportData)
&& DiagnosticLocation.Equals(DiagnosticLocation)
&& GeneratorFactoryKey.Equals(other.GeneratorFactoryKey)
&& Diagnostics.SequenceEqual(other.Diagnostics);
}

public override int GetHashCode()
{
throw new UnreachableException();
}
}
MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion, JSGeneratorOptions)> GeneratorFactoryKey,
SequenceEqualImmutableArray<Diagnostic> Diagnostics);

public static class StepNames
{
Expand Down Expand Up @@ -119,9 +99,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
static (data, ct) => CalculateStubInformation(data.Syntax, data.Symbol, data.Environment, data.Options, ct)
)
.WithTrackingName(StepNames.CalculateStubInformation)
.Combine(stubOptions)
.Select(
static (data, ct) => GenerateSource(data.Left, data.Right)
static (data, ct) => GenerateSource(data)
)
.WithComparer(Comparers.GeneratedSyntax)
.WithTrackingName(StepNames.GenerateSingleStub);
Expand Down Expand Up @@ -215,14 +194,13 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
var methodSyntaxTemplate = new ContainingSyntax(originalSyntax.Modifiers.StripTriviaFromTokens(), SyntaxKind.MethodDeclaration, originalSyntax.Identifier, originalSyntax.TypeParameterList);

return new IncrementalStubGenerationContext(
environment,
signatureContext,
containingTypeContext,
methodSyntaxTemplate,
new MethodSignatureDiagnosticLocations(originalSyntax),
jsExportData,
CreateGeneratorFactory(environment, options),
generatorDiagnostics.Diagnostics.ToImmutableArray());
new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()));
}

private static MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> CreateGeneratorFactory(StubEnvironment env, JSGeneratorOptions options)
Expand All @@ -232,14 +210,14 @@ private static IncrementalStubGenerationContext CalculateStubInformation(
}

private static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateSource(
IncrementalStubGenerationContext incrementalContext,
JSGeneratorOptions options)
IncrementalStubGenerationContext incrementalContext)
{
var diagnostics = new GeneratorDiagnostics();

// Generate stub code
var stubGenerator = new JSExportCodeGenerator(
incrementalContext.Environment,
incrementalContext.GeneratorFactoryKey.Key.TargetFramework,
incrementalContext.GeneratorFactoryKey.Key.TargetFrameworkVersion,
incrementalContext.SignatureContext.SignatureContext.ElementTypeInformation,
incrementalContext.JSExportData,
incrementalContext.SignatureContext,
Expand All @@ -252,7 +230,7 @@ private static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateSou
BlockSyntax wrapper = stubGenerator.GenerateJSExportBody();
BlockSyntax registration = stubGenerator.GenerateJSExportRegistration();

return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, incrementalContext.ContainingSyntaxContext, wrapper, registration), incrementalContext.Diagnostics.AddRange(diagnostics.Diagnostics));
return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, incrementalContext.ContainingSyntaxContext, wrapper, registration), incrementalContext.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
}

private static bool ShouldVisitNode(SyntaxNode syntaxNode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,22 @@ internal sealed class JSImportCodeGenerator : JSCodeGenerator
private readonly JSSignatureContext _signatureContext;

public JSImportCodeGenerator(
StubEnvironment environment,
TargetFramework targetFramework,
Version targetFrameworkVersion,
ImmutableArray<TypePositionInfo> argTypes,
JSImportData attributeData,
JSSignatureContext signatureContext,
Action<TypePositionInfo, MarshallingNotSupportedException> marshallingNotSupportedCallback,
IMarshallingGeneratorFactory generatorFactory)
{
_signatureContext = signatureContext;
ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnIdentifier);
ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier);
_context = new JSImportCodeContext(attributeData, innerContext);
_marshallers = new BoundGenerators(argTypes, CreateGenerator);
if (_marshallers.ManagedReturnMarshaller.Generator.UsesNativeIdentifier(_marshallers.ManagedReturnMarshaller.TypeInfo, null))
{
// If we need a different native return identifier, then recreate the context with the correct identifier before we generate any code.
innerContext = new ManagedToNativeStubCodeContext(environment, ReturnIdentifier, ReturnNativeIdentifier);
innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnNativeIdentifier);
_context = new JSImportCodeContext(attributeData, innerContext);
_marshallers = new BoundGenerators(argTypes, CreateGenerator);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -22,33 +19,13 @@ namespace Microsoft.Interop.JavaScript
public sealed class JSImportGenerator : IIncrementalGenerator
{
internal sealed record IncrementalStubGenerationContext(
StubEnvironment Environment,
JSSignatureContext SignatureContext,
ContainingSyntaxContext ContainingSyntaxContext,
ContainingSyntax StubMethodSyntaxTemplate,
MethodSignatureDiagnosticLocations DiagnosticLocation,
JSImportData JSImportData,
MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> GeneratorFactoryKey,
ImmutableArray<Diagnostic> Diagnostics)
{
public bool Equals(IncrementalStubGenerationContext? other)
{
return other is not null
&& StubEnvironment.AreCompilationSettingsEqual(Environment, other.Environment)
&& SignatureContext.Equals(other.SignatureContext)
&& ContainingSyntaxContext.Equals(other.ContainingSyntaxContext)
&& StubMethodSyntaxTemplate.Equals(other.StubMethodSyntaxTemplate)
&& JSImportData.Equals(other.JSImportData)
&& DiagnosticLocation.Equals(DiagnosticLocation)
&& GeneratorFactoryKey.Equals(other.GeneratorFactoryKey)
&& Diagnostics.SequenceEqual(other.Diagnostics);
}

public override int GetHashCode()
{
throw new UnreachableException();
}
}
MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion, JSGeneratorOptions)> GeneratorFactoryKey,
SequenceEqualImmutableArray<Diagnostic> Diagnostics);

public static class StepNames
{
Expand Down Expand Up @@ -228,14 +205,13 @@ private static IncrementalStubGenerationContext CalculateStubInformation(

var methodSyntaxTemplate = new ContainingSyntax(originalSyntax.Modifiers.StripTriviaFromTokens(), SyntaxKind.MethodDeclaration, originalSyntax.Identifier, originalSyntax.TypeParameterList);
return new IncrementalStubGenerationContext(
environment,
signatureContext,
containingTypeContext,
methodSyntaxTemplate,
new MethodSignatureDiagnosticLocations(originalSyntax),
jsImportData,
CreateGeneratorFactory(environment, options),
generatorDiagnostics.Diagnostics.ToImmutableArray());
new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()));
}

private static MarshallingGeneratorFactoryKey<(TargetFramework, Version, JSGeneratorOptions)> CreateGeneratorFactory(StubEnvironment env, JSGeneratorOptions options)
Expand All @@ -253,7 +229,8 @@ private static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateSou

// Generate stub code
var stubGenerator = new JSImportCodeGenerator(
incrementalContext.Environment,
incrementalContext.GeneratorFactoryKey.Key.TargetFramework,
incrementalContext.GeneratorFactoryKey.Key.TargetFrameworkVersion,
incrementalContext.SignatureContext.SignatureContext.ElementTypeInformation,
incrementalContext.JSImportData,
incrementalContext.SignatureContext,
Expand All @@ -265,7 +242,7 @@ private static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateSou

BlockSyntax code = stubGenerator.GenerateJSImportBody();

return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, incrementalContext.ContainingSyntaxContext, code), incrementalContext.Diagnostics.AddRange(diagnostics.Diagnostics));
return (PrintGeneratedSource(incrementalContext.StubMethodSyntaxTemplate, incrementalContext.SignatureContext, incrementalContext.ContainingSyntaxContext, code), incrementalContext.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
}

private static bool ShouldVisitNode(SyntaxNode syntaxNode)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;

namespace Microsoft.Interop
{
internal static class ComInterfaceGeneratorHelpers
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
{
public static MarshallingGeneratorFactoryKey<(TargetFramework, Version)> CreateGeneratorFactory(StubEnvironment env)
{
IMarshallingGeneratorFactory generatorFactory;

// If we're in a "supported" scenario, then emit a diagnostic as our final fallback.
generatorFactory = new UnsupportedMarshallingFactory();

generatorFactory = new NoMarshallingInfoErrorMarshallingFactory(generatorFactory);

// The presence of System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute is tied to TFM,
// so we use TFM in the generator factory key instead of the Compilation as the compilation changes on every keystroke.
IAssemblySymbol coreLibraryAssembly = env.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly;
ITypeSymbol? disabledRuntimeMarshallingAttributeType = coreLibraryAssembly.GetTypeByMetadataName(TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute);
bool runtimeMarshallingDisabled = disabledRuntimeMarshallingAttributeType is not null
&& env.Compilation.Assembly.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, disabledRuntimeMarshallingAttributeType));

// Since the char type can go into the P/Invoke signature here, we can only use it when
// runtime marshalling is disabled.
generatorFactory = new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: runtimeMarshallingDisabled);

InteropGenerationOptions interopGenerationOptions = new(UseMarshalType: true);
generatorFactory = new MarshalAsMarshallingGeneratorFactory(interopGenerationOptions, generatorFactory);

IMarshallingGeneratorFactory elementFactory = new AttributedMarshallingModelGeneratorFactory(
// Since the char type in an array will not be part of the P/Invoke signature, we can
// use the regular blittable marshaller in all cases.
new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true),
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ElementIn, MarshalMode.ElementRef, MarshalMode.ElementOut));
// We don't need to include the later generator factories for collection elements
// as the later generator factories only apply to parameters.
generatorFactory = new AttributedMarshallingModelGeneratorFactory(
generatorFactory,
elementFactory,
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ManagedToUnmanagedIn, MarshalMode.ManagedToUnmanagedRef, MarshalMode.ManagedToUnmanagedOut));

generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory);

return MarshallingGeneratorFactoryKey.Create((env.TargetFramework, env.TargetFrameworkVersion), generatorFactory);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo
bool mayRequireAdditionalWork = diagnostics.AnyDiagnostics;
bool anyExplicitlyUnsupportedInfo = false;

var stubCodeContext = new ManagedToNativeStubCodeContext(env, "return", "nativeReturn");
var stubCodeContext = new ManagedToNativeStubCodeContext(env.TargetFramework, env.TargetFrameworkVersion, "return", "nativeReturn");

var forwarder = new Forwarder();
// We don't actually need the bound generators. We just need them to be attempted to be bound to determine if the generator will be able to bind them.
Expand Down
Loading