Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ad0172f
Hook up initial infrastructure for unmanaged-to-managed vtable stubs.
jkoritzinsky Oct 17, 2022
f571cd0
Make the signatures for the UnmanagedCallersOnly wrapper have the cor…
jkoritzinsky Nov 1, 2022
c2f2fdf
Fix signature and add runtime tests for unmanaged->managed
jkoritzinsky Nov 2, 2022
32f856c
Update incremental generation liveness test to be a theory and add an…
jkoritzinsky Nov 10, 2022
9a38bee
Change IMarshallingGenerator.AsNativeType to return a ManagedTypeInfo…
jkoritzinsky Nov 10, 2022
71fa346
Use MarshalDirection to provide a nice abstraction for determining wh…
jkoritzinsky Nov 10, 2022
8646adf
Implement unmanaged->managed exception handling spec and get compilat…
jkoritzinsky Nov 10, 2022
baf8a36
Initial PR feedback.
jkoritzinsky Nov 10, 2022
6bf9f2c
Merge branch 'main' of github.com:dotnet/runtime into vtable-unmanged…
jkoritzinsky Nov 11, 2022
6819628
Fix function pointer signature
jkoritzinsky Nov 14, 2022
972fd18
Emit a PopulateUnmanagedVirtualMethodTable wrapper function to fill t…
jkoritzinsky Nov 15, 2022
ddaa876
Add methods for providing virtual method table length.
jkoritzinsky Nov 16, 2022
ec57196
Merge branch 'main' of github.com:dotnet/runtime into vtable-unmanged…
jkoritzinsky Nov 21, 2022
7f05abb
PR feedback
jkoritzinsky Nov 21, 2022
4132fd9
Fix bad merge that lost the native-to-managed-this marshaller factory.
jkoritzinsky Nov 21, 2022
96ac635
Enhance docs for the error case
jkoritzinsky Nov 21, 2022
76ce3f5
Internalize the "fallback-to-fowarder" logic to BoundGenerators and h…
jkoritzinsky Nov 29, 2022
8d89495
Pass in the fallback generator to BoundGenerators
jkoritzinsky Nov 30, 2022
7c05d70
Change the BoundGenerators constructor to a factory method.
jkoritzinsky Dec 1, 2022
d4e71c4
Add lots of comments and docs
jkoritzinsky Dec 2, 2022
0a45772
Fix a few missing init properties
jkoritzinsky Dec 2, 2022
9879853
PR feedback and finish wiring up the exception marshallers to actuall…
jkoritzinsky Dec 6, 2022
b7d1ab3
Add diagnostics for ExceptionMarshalling and other misc PR feedback.
jkoritzinsky Dec 7, 2022
8e9e5ca
Allow setting ExceptionMarshallingCustomType without setting Exceptio…
jkoritzinsky Dec 8, 2022
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
Prev Previous commit
Next Next commit
Change the BoundGenerators constructor to a factory method.
  • Loading branch information
jkoritzinsky committed Dec 1, 2022
commit 7c05d70c9fcc2783740392cd68d754c8daebb773
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public JSExportCodeGenerator(
NativeToManagedStubCodeContext innerContext = new NativeToManagedStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier);
_context = new JSExportCodeContext(attributeData, innerContext);

_marshallers = new BoundGenerators(argTypes, generatorFactory, _context, new EmptyJSGenerator());
foreach (var failure in _marshallers.GeneratorBindingFailures)
_marshallers = BoundGenerators.Create(argTypes, generatorFactory, _context, new EmptyJSGenerator(), out var bindingFailures);
foreach (var failure in bindingFailures)
{
marshallingNotSupportedCallback(failure.Info, failure.Exception);
}
Expand All @@ -50,7 +50,7 @@ public JSExportCodeGenerator(
// validate task + span mix
if (_marshallers.ManagedReturnMarshaller.TypeInfo.MarshallingAttributeInfo is JSMarshallingInfo(_, JSTaskTypeInfo))
{
BoundGenerator spanArg = _marshallers.AllMarshallers.FirstOrDefault(m => m.TypeInfo.MarshallingAttributeInfo is JSMarshallingInfo(_, JSSpanTypeInfo));
BoundGenerator spanArg = _marshallers.SignatureMarshallers.FirstOrDefault(m => m.TypeInfo.MarshallingAttributeInfo is JSMarshallingInfo(_, JSSpanTypeInfo));
if (spanArg != default)
{
marshallingNotSupportedCallback(spanArg.TypeInfo, new MarshallingNotSupportedException(spanArg.TypeInfo, _context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public JSImportCodeGenerator(
_signatureContext = signatureContext;
ManagedToNativeStubCodeContext innerContext = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier);
_context = new JSImportCodeContext(attributeData, innerContext);
_marshallers = new BoundGenerators(argTypes, generatorFactory, _context, new EmptyJSGenerator());
_marshallers = BoundGenerators.Create(argTypes, generatorFactory, _context, new EmptyJSGenerator(), out var bindingFailures);

foreach (var failure in _marshallers.GeneratorBindingFailures)
foreach (var failure in bindingFailures)
{
marshallingNotSupportedCallback(failure.Info, failure.Exception);
}
Expand All @@ -56,7 +56,7 @@ public JSImportCodeGenerator(
// validate task + span mix
if (_marshallers.ManagedReturnMarshaller.TypeInfo.MarshallingAttributeInfo is JSMarshallingInfo(_, JSTaskTypeInfo))
{
BoundGenerator spanArg = _marshallers.AllMarshallers.FirstOrDefault(m => m.TypeInfo.MarshallingAttributeInfo is JSMarshallingInfo(_, JSSpanTypeInfo));
BoundGenerator spanArg = _marshallers.SignatureMarshallers.FirstOrDefault(m => m.TypeInfo.MarshallingAttributeInfo is JSMarshallingInfo(_, JSSpanTypeInfo));
if (spanArg != default)
{
marshallingNotSupportedCallback(spanArg.TypeInfo, new MarshallingNotSupportedException(spanArg.TypeInfo, _context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ public ManagedToNativeVTableMethodGenerator(
}

_context = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier);
_marshallers = new BoundGenerators(argTypes, generatorFactory, _context, new Forwarder());
_marshallers = BoundGenerators.Create(argTypes, generatorFactory, _context, new Forwarder(), out var bindingFailures);

foreach (var failure in _marshallers.GeneratorBindingFailures)
foreach (var failure in bindingFailures)
{
marshallingNotSupportedCallback(failure.Info, failure.Exception);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public UnmanagedToManagedStubGenerator(
IMarshallingGeneratorFactory generatorFactory)
{
_context = new NativeToManagedStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier);
_marshallers = new BoundGenerators(argTypes, generatorFactory, _context, new Forwarder());
_marshallers = BoundGenerators.Create(argTypes, generatorFactory, _context, new Forwarder(), out var bindingFailures);

foreach (var failure in _marshallers.GeneratorBindingFailures)
foreach (var failure in bindingFailures)
{
marshallingNotSupportedCallback(failure.Info, failure.Exception);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo

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.
BoundGenerators generators = new(targetSignatureContext.ElementTypeInformation, new CallbackGeneratorFactory((info, context) =>
BoundGenerators generators = BoundGenerators.Create(targetSignatureContext.ElementTypeInformation, new CallbackGeneratorFactory((info, context) =>
{
if (s_unsupportedTypeNames.Contains(info.ManagedType.FullTypeName))
{
Expand All @@ -112,9 +112,9 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo
return forwarder;
}
return generatorFactoryKey.GeneratorFactory.Create(info, stubCodeContext);
}), stubCodeContext, forwarder);
}), stubCodeContext, forwarder, out var bindingFailures);

mayRequireAdditionalWork |= generators.GeneratorBindingFailures.Length > 0;
mayRequireAdditionalWork |= bindingFailures.Length > 0;

if (anyExplicitlyUnsupportedInfo)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ public PInvokeStubCodeGenerator(
}

_context = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier);
_marshallers = new BoundGenerators(argTypes, generatorFactory, _context, new Forwarder());
_marshallers = BoundGenerators.Create(argTypes, generatorFactory, _context, new Forwarder(), out var bindingFailures);

foreach (var failure in _marshallers.GeneratorBindingFailures)
foreach (var failure in bindingFailures)
{
marshallingNotSupportedCallback(failure.Info, failure.Exception);
}
Expand All @@ -83,7 +83,7 @@ public PInvokeStubCodeGenerator(

bool noMarshallingNeeded = true;

foreach (BoundGenerator generator in _marshallers.AllMarshallers)
foreach (BoundGenerator generator in _marshallers.SignatureMarshallers)
{
// Check if marshalling info and generator support the current target framework.
SupportsTargetFramework &= generator.TypeInfo.MarshallingAttributeInfo is not MissingSupportMarshallingInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,31 @@ namespace Microsoft.Interop
{
public readonly record struct BoundGenerator(TypePositionInfo TypeInfo, IMarshallingGenerator Generator);

public class BoundGenerators
public sealed class BoundGenerators
{
public BoundGenerators(ImmutableArray<TypePositionInfo> elementTypeInfo, IMarshallingGeneratorFactory generatorFactory, StubCodeContext context, IMarshallingGenerator fallbackGenerator)
private BoundGenerators() { }

public static BoundGenerators Create(ImmutableArray<TypePositionInfo> elementTypeInfo, IMarshallingGeneratorFactory generatorFactory, StubCodeContext context, IMarshallingGenerator fallbackGenerator, out ImmutableArray<(TypePositionInfo Info, MarshallingNotSupportedException Exception)> generatorBindingFailures)
{
ImmutableArray<BoundGenerator>.Builder allMarshallers = ImmutableArray.CreateBuilder<BoundGenerator>();
BoundGenerator defaultBoundGenerator = new BoundGenerator(new TypePositionInfo(SpecialTypeInfo.Void, NoMarshallingInfo.Instance), fallbackGenerator);
BoundGenerators result = new();

ImmutableArray<BoundGenerator>.Builder signatureMarshallers = ImmutableArray.CreateBuilder<BoundGenerator>();
ImmutableArray<BoundGenerator>.Builder nativeParamMarshallers = ImmutableArray.CreateBuilder<BoundGenerator>();
ImmutableArray<BoundGenerator>.Builder managedParamMarshallers = ImmutableArray.CreateBuilder<BoundGenerator>();
ImmutableArray<(TypePositionInfo Info, MarshallingNotSupportedException Exception)>.Builder bindingFailures = ImmutableArray.CreateBuilder<(TypePositionInfo, MarshallingNotSupportedException)>();
bool foundNativeRetMarshaller = false;
bool foundManagedRetMarshaller = false;
BoundGenerator managedReturnMarshaller = defaultBoundGenerator;
BoundGenerator nativeReturnMarshaller = defaultBoundGenerator;
BoundGenerator managedExceptionMarshaller = defaultBoundGenerator;
bool foundManagedReturnMarshaller = false;
bool foundNativeReturnMarshaller = false;
TypePositionInfo? managedExceptionInfo = null;
NativeReturnMarshaller = new(new TypePositionInfo(SpecialTypeInfo.Void, NoMarshallingInfo.Instance), fallbackGenerator);
ManagedReturnMarshaller = new(new TypePositionInfo(SpecialTypeInfo.Void, NoMarshallingInfo.Instance), fallbackGenerator);
ManagedExceptionMarshaller = new(new TypePositionInfo(SpecialTypeInfo.Void, NoMarshallingInfo.Instance), fallbackGenerator);

foreach (TypePositionInfo argType in elementTypeInfo)
{
if (argType.IsManagedExceptionPosition)
{
Debug.Assert(managedExceptionInfo is null);
Debug.Assert(managedExceptionInfo == null);
managedExceptionInfo = argType;
// The exception marshaller's selection might depend on the unmanaged type of the native return marshaller.
// Delay binding the generator until we've processed the native return marshaller.
Expand All @@ -44,18 +49,18 @@ public BoundGenerators(ImmutableArray<TypePositionInfo> elementTypeInfo, IMarsha

BoundGenerator generator = new BoundGenerator(argType, CreateGenerator(argType, generatorFactory));

allMarshallers.Add(generator);
signatureMarshallers.Add(generator);
if (argType.IsManagedReturnPosition)
{
Debug.Assert(!foundManagedRetMarshaller);
ManagedReturnMarshaller = generator;
foundManagedRetMarshaller = true;
Debug.Assert(!foundManagedReturnMarshaller);
managedReturnMarshaller = generator;
foundManagedReturnMarshaller = true;
}
if (argType.IsNativeReturnPosition)
{
Debug.Assert(!foundNativeRetMarshaller);
NativeReturnMarshaller = generator;
foundNativeRetMarshaller = true;
Debug.Assert(!foundNativeReturnMarshaller);
nativeReturnMarshaller = generator;
foundNativeReturnMarshaller = true;
}
if (!TypePositionInfo.IsSpecialIndex(argType.ManagedIndex))
{
Expand All @@ -71,9 +76,6 @@ public BoundGenerators(ImmutableArray<TypePositionInfo> elementTypeInfo, IMarsha
managedParamMarshallers.Sort(static (m1, m2) => m1.TypeInfo.ManagedIndex.CompareTo(m2.TypeInfo.ManagedIndex));
nativeParamMarshallers.Sort(static (m1, m2) => m1.TypeInfo.NativeIndex.CompareTo(m2.TypeInfo.NativeIndex));

NativeParameterMarshallers = nativeParamMarshallers.ToImmutable();
ManagedParameterMarshallers = managedParamMarshallers.ToImmutable();

// Now that we've processed all of the signature marshallers,
// we'll handle the special ones that might depend on them, like the exception marshaller.
if (managedExceptionInfo is not null)
Expand All @@ -82,46 +84,51 @@ public BoundGenerators(ImmutableArray<TypePositionInfo> elementTypeInfo, IMarsha
{
managedExceptionInfo = managedExceptionInfo with
{
MarshallingAttributeInfo = ComExceptionMarshalling.CreateSpecificMarshallingInfo(NativeReturnMarshaller.Generator.AsNativeType(NativeReturnMarshaller.TypeInfo))
MarshallingAttributeInfo = ComExceptionMarshalling.CreateSpecificMarshallingInfo(nativeReturnMarshaller.Generator.AsNativeType(nativeReturnMarshaller.TypeInfo))
};
}

IMarshallingGeneratorFactory exceptionHandlerFactory = new ExtendedInvariantsValidator(NativeReturnMarshaller.Generator.AsNativeType(NativeReturnMarshaller.TypeInfo), generatorFactory);
IMarshallingGeneratorFactory exceptionHandlerFactory = new ExtendedInvariantsValidator(nativeReturnMarshaller.Generator.AsNativeType(nativeReturnMarshaller.TypeInfo), generatorFactory);

// We explicitly don't include exceptionMarshaller in the allMarshallers collection
// We explicitly don't include exceptionMarshaller in the signatureMarshallers collection
// as it needs to be specially emitted.
ManagedExceptionMarshaller = new(managedExceptionInfo, CreateGenerator(managedExceptionInfo, generatorFactory));
managedExceptionMarshaller = new(managedExceptionInfo, CreateGenerator(managedExceptionInfo, generatorFactory));
}

// We are doing a topological sort of our marshallers to ensure that each parameter/return value's
// dependencies are unmarshalled before their dependents. This comes up in the case of contiguous
// collections, where the number of elements in a collection are provided via another parameter/return value.
// When using nested collections, the parameter that represents the number of elements of each element of the
// outer collection is another collection. As a result, there are two options on how to retrieve the size.
// Either we partially unmarshal the collection of counts while unmarshalling the collection of elements,
// or we unmarshal our parameters and return value in an order such that we can use the managed identifiers
// for our lengths.
// Here's an example signature where the dependency shows up:
//
// [LibraryImport(NativeExportsNE_Binary, EntryPoint = "transpose_matrix")]
// [return: MarshalUsing(CountElementName = "numColumns")]
// [return: MarshalUsing(CountElementName = "numRows", ElementIndirectionDepth = 1)]
// public static partial int[][] TransposeMatrix(
// int[][] matrix,
// [MarshalUsing(CountElementName="numColumns")] ref int[] numRows,
// int numColumns);
//
// In this scenario, we'd traditionally unmarshal the return value and then each parameter. However, since
// the return value has dependencies on numRows and numColumns and numRows has a dependency on numColumns,
// we want to unmarshal numColumns, then numRows, then the return value.
// A topological sort ensures we get this order correct.
AllMarshallers = MarshallerHelpers.GetTopologicallySortedElements(
allMarshallers,
static m => GetInfoIndex(m.TypeInfo),
static m => GetInfoDependencies(m.TypeInfo))
.ToImmutableArray();

GeneratorBindingFailures = bindingFailures.ToImmutable();
generatorBindingFailures = bindingFailures.ToImmutable();

return new BoundGenerators()
{
// We are doing a topological sort of our marshallers to ensure that each parameter/return value's
// dependencies are unmarshalled before their dependents. This comes up in the case of contiguous
// collections, where the number of elements in a collection are provided via another parameter/return value.
// When using nested collections, the parameter that represents the number of elements of each element of the
// outer collection is another collection. As a result, there are two options on how to retrieve the size.
// Either we partially unmarshal the collection of counts while unmarshalling the collection of elements,
// or we unmarshal our parameters and return value in an order such that we can use the managed identifiers
// for our lengths.
// Here's an example signature where the dependency shows up:
//
// [LibraryImport(NativeExportsNE_Binary, EntryPoint = "transpose_matrix")]
// [return: MarshalUsing(CountElementName = "numColumns")]
// [return: MarshalUsing(CountElementName = "numRows", ElementIndirectionDepth = 1)]
// public static partial int[][] TransposeMatrix(
// int[][] matrix,
// [MarshalUsing(CountElementName="numColumns")] ref int[] numRows,
// int numColumns);
//
// In this scenario, we'd traditionally unmarshal the return value and then each parameter. However, since
// the return value has dependencies on numRows and numColumns and numRows has a dependency on numColumns,
// we want to unmarshal numColumns, then numRows, then the return value.
// A topological sort ensures we get this order correct.
SignatureMarshallers = MarshallerHelpers.GetTopologicallySortedElements(
signatureMarshallers,
static m => GetInfoIndex(m.TypeInfo),
static m => GetInfoDependencies(m.TypeInfo))
.ToImmutableArray(),
NativeParameterMarshallers = nativeParamMarshallers.ToImmutable(),
ManagedParameterMarshallers = managedParamMarshallers.ToImmutable()
};

static IEnumerable<(bool IsManagedIndex, int Index)> GetInfoDependencies(TypePositionInfo info)
{
Expand Down Expand Up @@ -161,19 +168,17 @@ IMarshallingGenerator CreateGenerator(TypePositionInfo p, IMarshallingGeneratorF
}
}

public BoundGenerator ManagedReturnMarshaller { get; }

public BoundGenerator NativeReturnMarshaller { get; }
public BoundGenerator ManagedReturnMarshaller { get; private init; }

public BoundGenerator ManagedExceptionMarshaller { get; }
public BoundGenerator NativeReturnMarshaller { get; private init; }

public ImmutableArray<BoundGenerator> AllMarshallers { get; }
public BoundGenerator ManagedExceptionMarshaller { get; private init; }

public ImmutableArray<BoundGenerator> ManagedParameterMarshallers { get; }
public ImmutableArray<BoundGenerator> SignatureMarshallers { get; private init; }

public ImmutableArray<BoundGenerator> NativeParameterMarshallers { get; }
public ImmutableArray<BoundGenerator> ManagedParameterMarshallers { get; private init; }

public ImmutableArray<(TypePositionInfo Info, MarshallingNotSupportedException Exception)> GeneratorBindingFailures { get; }
public ImmutableArray<BoundGenerator> NativeParameterMarshallers { get; private init; }

public (ParameterListSyntax ParameterList, TypeSyntax ReturnType, AttributeListSyntax? ReturnTypeAttributes) GenerateTargetMethodSignatureData(StubCodeContext context)
{
Expand Down
Loading