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

Update GetPinnableReference() usage in multi-step custom type marshalling #61539

Conversation

jkoritzinsky
Copy link
Member

@jkoritzinsky jkoritzinsky commented Nov 13, 2021

Change GetPinnableReference() on a marshaller type to be used as a side effect when marshalling in all cases when a fixed() statement is usable.

Use the Value property getter to get the value to pass to native in all cases.

Update our marshallers and tests to follow this design update. Also do some code cleanup along the way.

Fixes dotnet/runtimelab#1653 in two ways:

  1. Enables writing marshallers in C# source that can effectively solve that issue now that GetPinnableReference can return a value that needs to be pinned that is not equal to the value that is passed to native code.
  2. Directly fixes that issue by preserving the statements within a fixed() statement returned in the Pin stage (was required to implement 1.).

…ling

Change GetPinnableReference() on a marshaller type to be used as a side effect when marshalling in all cases when a fixed() statement is usable.

Use the Value property getter to get the value to pass to native in all cases.

Update our marshallers and tests to follow this design update.
@jkoritzinsky jkoritzinsky added area-System.Runtime.InteropServices source-generator Indicates an issue with a source generator feature labels Nov 13, 2021
@jkoritzinsky jkoritzinsky added this to the 7.0.0 milestone Nov 13, 2021
@AaronRobinsonMSFT AaronRobinsonMSFT changed the title Update GetPinnableReference() usage in multi-step custom tyep marshalling Update GetPinnableReference() usage in multi-step custom type marshalling Nov 13, 2021
@elinor-fung
Copy link
Member

Do you have a good before/after example for the generated code?

@jkoritzinsky
Copy link
Member Author

jkoritzinsky commented Nov 16, 2021

Before:

namespace DllImportGenerator.IntegrationTests
{
    partial class NativeExportsNE
    {
        public unsafe partial class Arrays
        {
            [System.Runtime.CompilerServices.SkipLocalsInitAttribute]
            public static partial int SumInArray(in int[] values, int numValues)
            {
                int __retVal;
                //
                // Setup
                //
                global::System.Runtime.InteropServices.GeneratedMarshalling.ArrayMarshaller<int> __values_gen_native__marshaller = default;
                try
                {
                    //
                    // Marshal
                    //
                    byte* __values_gen_native__marshaller__stackptr = stackalloc byte[global::System.Runtime.InteropServices.GeneratedMarshalling.ArrayMarshaller<int>.StackBufferSize];
                    __values_gen_native__marshaller = new(values, new System.Span<byte>(__values_gen_native__marshaller__stackptr, global::System.Runtime.InteropServices.GeneratedMarshalling.ArrayMarshaller<int>.StackBufferSize), sizeof(int));
                    __values_gen_native__marshaller.ManagedValues.CopyTo(System.Runtime.InteropServices.MemoryMarshal.Cast<byte, int>(__values_gen_native__marshaller.NativeValueStorage));
                    fixed (byte* __values_gen_native = &__values_gen_native__marshaller.GetPinnableReference())
                        __retVal = __PInvoke__(&__values_gen_native, numValues);
                }
                finally
                {
                    //
                    // Cleanup
                    //
                    __values_gen_native__marshaller.FreeNative();
                }

                return __retVal;
                //
                // Local P/Invoke
                //
                [System.Runtime.InteropServices.DllImportAttribute("Microsoft.Interop.Tests.NativeExportsNE", EntryPoint = "sum_int_array_ref")]
                extern static unsafe int __PInvoke__(byte** values, int numValues);
            }
        }
    }
}

After:

namespace DllImportGenerator.IntegrationTests
{
    partial class NativeExportsNE
    {
        public unsafe partial class Arrays
        {
            [System.Runtime.CompilerServices.SkipLocalsInitAttribute]
            public static partial int SumInArray(in int[] values, int numValues)
            {
                byte* __values_gen_native = default;
                int __retVal;
                //
                // Setup
                //
                global::System.Runtime.InteropServices.GeneratedMarshalling.ArrayMarshaller<int> __values_gen_native__marshaller = default;
                try
                {
                    //
                    // Marshal
                    //
                    byte* __values_gen_native__marshaller__stackptr = stackalloc byte[global::System.Runtime.InteropServices.GeneratedMarshalling.ArrayMarshaller<int>.StackBufferSize];
                    __values_gen_native__marshaller = new(values, new System.Span<byte>(__values_gen_native__marshaller__stackptr, global::System.Runtime.InteropServices.GeneratedMarshalling.ArrayMarshaller<int>.StackBufferSize), sizeof(int));
                    __values_gen_native__marshaller.ManagedValues.CopyTo(System.Runtime.InteropServices.MemoryMarshal.Cast<byte, int>(__values_gen_native__marshaller.NativeValueStorage));
                    fixed (byte* __values_gen_native__ignored = __values_gen_native__marshaller)
                    {
                        __values_gen_native = __values_gen_native__marshaller.Value;
                        {
                            __retVal = __PInvoke__(&__values_gen_native, numValues);
                        }
                    }
                }
                finally
                {
                    //
                    // Cleanup
                    //
                    __values_gen_native__marshaller.FreeNative();
                }

                return __retVal;
                //
                // Local P/Invoke
                //
                [System.Runtime.InteropServices.DllImportAttribute("Microsoft.Interop.Tests.NativeExportsNE", EntryPoint = "sum_int_array_ref")]
                extern static unsafe int __PInvoke__(byte** values, int numValues);
            }
        }
    }
}

@jkoritzinsky jkoritzinsky force-pushed the getpinnablereference-struct-marshalling-design-update branch from 893bc61 to d66549a Compare November 16, 2021 21:37
… now that we're using spans internally for storage in all cases.
@jkoritzinsky jkoritzinsky force-pushed the getpinnablereference-struct-marshalling-design-update branch from 7e610c5 to ada0693 Compare November 17, 2021 19:15
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Runtime.InteropServices NO-SQUASH The PR should not be squashed source-generator Indicates an issue with a source generator feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pin stage only accepts FixedStatementSyntaxes
3 participants