Example #1
0
        public IEnumerable <StatementSyntax> GenerateGuaranteedUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
        {
            if (!_shape.HasFlag(MarshallerShape.GuaranteedUnmarshal))
            {
                yield break;
            }

            (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);
            string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);

            yield return(ExpressionStatement(
                             AssignmentExpression(
                                 SyntaxKind.SimpleAssignmentExpression,
                                 IdentifierName(numElementsIdentifier),
                                 _numElementsExpression)));

            // <managedIdentifier> = <marshallerType>.AllocateContainerForManagedElementsFinally(<nativeIdentifier>, <numElements>);
            yield return(ExpressionStatement(
                             AssignmentExpression(
                                 SyntaxKind.SimpleAssignmentExpression,
                                 IdentifierName(managedIdentifier),
                                 InvocationExpression(
                                     MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                            _marshallerTypeSyntax,
                                                            IdentifierName(ShapeMemberNames.LinearCollection.Stateless.AllocateContainerForManagedElementsFinally)),
                                     ArgumentList(SeparatedList(new ArgumentSyntax[]
            {
                Argument(IdentifierName(nativeIdentifier)),
                Argument(IdentifierName(numElementsIdentifier))
            }))))));
        }
        public IEnumerable <StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
        {
            if (!_shape.HasFlag(MarshallerShape.ToManaged))
            {
                yield break;
            }

            if (!info.IsByRef && info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out))
            {
                yield return(GenerateByValueOutUnmarshalStatement(info, context));
            }
            else
            {
                // int <numElements> = <numElementExpression>
                string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);
                yield return(LocalDeclarationStatement(
                                 VariableDeclaration(
                                     PredefinedType(Token(SyntaxKind.IntKeyword)),
                                     SingletonSeparatedList(
                                         VariableDeclarator(numElementsIdentifier)
                                         .WithInitializer(EqualsValueClause(_numElementsExpression))))));

                yield return(GenerateUnmarshalStatement(info, context));
            }

            foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, context))
            {
                yield return(statement);
            }
        }
Example #3
0
        public StatementSyntax GenerateUnmarshalStatement(TypePositionInfo info, StubCodeContext context)
        {
            string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context);
            string nativeSpanIdentifier  = MarshallerHelpers.GetNativeSpanIdentifier(info, context);
            string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);

            // ReadOnlySpan<TUnmanagedElement> <nativeSpan> = <GetUnmanagedValuesSource>
            // Span<T> <managedSpan> = <GetManagedValuesDestination>
            // << unmarshal contents >>
            return(Block(
                       LocalDeclarationStatement(VariableDeclaration(
                                                     GenericName(
                                                         Identifier(TypeNames.System_ReadOnlySpan),
                                                         TypeArgumentList(SingletonSeparatedList(_unmanagedElementType))),
                                                     SingletonSeparatedList(
                                                         VariableDeclarator(
                                                             Identifier(nativeSpanIdentifier))
                                                         .WithInitializer(EqualsValueClause(
                                                                              GetUnmanagedValuesSource(info, context)))))),
                       LocalDeclarationStatement(VariableDeclaration(
                                                     GenericName(
                                                         Identifier(TypeNames.System_Span),
                                                         TypeArgumentList(SingletonSeparatedList(_elementInfo.ManagedType.Syntax))),
                                                     SingletonSeparatedList(
                                                         VariableDeclarator(
                                                             Identifier(managedSpanIdentifier))
                                                         .WithInitializer(EqualsValueClause(
                                                                              GetManagedValuesDestination(info, context)))))),
                       GenerateContentsMarshallingStatement(
                           info,
                           context,
                           IdentifierName(numElementsIdentifier),
                           StubCodeContext.Stage.UnmarshalCapture,
                           StubCodeContext.Stage.Unmarshal)));
        }
Example #4
0
 public IEnumerable <StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context)
 {
     yield return(MarshallerHelpers.Declare(
                      _marshallerTypeSyntax,
                      context.GetAdditionalIdentifier(info, MarshallerIdentifier),
                      ImplicitObjectCreationExpression(ArgumentList(), initializer: null)));
 }
        public IEnumerable <StatementSyntax> GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context)
        {
            if (MarshallerHelpers.CanUseCallerAllocatedBuffer(info, context))
            {
                return(GenerateCallerAllocatedBufferMarshalStatements());
            }

            return(_innerMarshaller.GenerateMarshalStatements(info, context));

            IEnumerable <StatementSyntax> GenerateCallerAllocatedBufferMarshalStatements()
            {
                // TODO: Update once we can consume the scoped keword. We should be able to simplify this once we get that API.
                string stackPtrIdentifier = context.GetAdditionalIdentifier(info, "stackptr");

                // <bufferElementType>* <managedIdentifier>__stackptr = stackalloc <bufferElementType>[<_bufferSize>];
                yield return(LocalDeclarationStatement(
                                 VariableDeclaration(
                                     PointerType(_bufferElementType),
                                     SingletonSeparatedList(
                                         VariableDeclarator(stackPtrIdentifier)
                                         .WithInitializer(EqualsValueClause(
                                                              StackAllocArrayCreationExpression(
                                                                  ArrayType(
                                                                      _bufferElementType,
                                                                      SingletonList(ArrayRankSpecifier(SingletonSeparatedList <ExpressionSyntax>(
                                                                                                           MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                                                                                  _marshallerType,
                                                                                                                                  IdentifierName(ShapeMemberNames.BufferSize))
                                                                                                           )))))))))));


                (string managedIdentifier, _) = context.GetIdentifiers(info);

                // <marshaller>.FromManaged(<managedIdentifier>, new Span<bufferElementType>(<stackPtrIdentifier>, <marshallerType>.BufferSize));
                yield return(ExpressionStatement(
                                 InvocationExpression(
                                     MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                            IdentifierName(context.GetAdditionalIdentifier(info, StatefulValueMarshalling.MarshallerIdentifier)),
                                                            IdentifierName(ShapeMemberNames.Value.Stateful.FromManaged)),
                                     ArgumentList(SeparatedList(
                                                      new[]
                {
                    Argument(IdentifierName(managedIdentifier)),
                    Argument(
                        ObjectCreationExpression(
                            GenericName(Identifier(TypeNames.System_Span),
                                        TypeArgumentList(SingletonSeparatedList(
                                                             _bufferElementType))))
                        .WithArgumentList(
                            ArgumentList(SeparatedList(new ArgumentSyntax[]
                    {
                        Argument(IdentifierName(stackPtrIdentifier)),
                        Argument(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                        _marshallerType,
                                                        IdentifierName(ShapeMemberNames.BufferSize)))
                    }))))
                })))));
            }
        }
Example #6
0
 public IEnumerable <StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context)
 {
     yield return(LocalDeclarationStatement(
                      VariableDeclaration(
                          PredefinedType(Token(SyntaxKind.IntKeyword)),
                          SingletonSeparatedList(
                              VariableDeclarator(MarshallerHelpers.GetNumElementsIdentifier(info, context))))));
 }
Example #7
0
 static IEnumerable <int> GetInfoDependencies(TypePositionInfo info)
 {
     // A parameter without a managed index cannot have any dependencies.
     if (info.ManagedIndex == TypePositionInfo.UnsetIndex)
     {
         return(Array.Empty <int>());
     }
     return(MarshallerHelpers.GetDependentElementsOfMarshallingInfo(info.MarshallingAttributeInfo)
            .Select(static info => GetInfoIndex(info)).ToImmutableArray());
Example #8
0
        public IEnumerable <StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
        {
            (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);
            string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);

            if (!info.IsByRef && info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out))
            {
                // <numElements> = <GetManagedValuesSource.Length;
                yield return(ExpressionStatement(
                                 AssignmentExpression(
                                     SyntaxKind.SimpleAssignmentExpression,
                                     IdentifierName(numElementsIdentifier),
                                     MemberAccessExpression(
                                         SyntaxKind.SimpleMemberAccessExpression,
                                         GetManagedValuesSource(info, context),
                                         IdentifierName("Length")))));

                yield return(GenerateByValueOutUnmarshalStatement(info, context));
            }

            if (!_shape.HasFlag(MarshallerShape.ToManaged))
            {
                yield break;
            }
            else
            {
                // <numElements> = <numElementsExpression>;
                yield return(ExpressionStatement(
                                 AssignmentExpression(
                                     SyntaxKind.SimpleAssignmentExpression,
                                     IdentifierName(numElementsIdentifier),
                                     _numElementsExpression)));

                // <managedIdentifier> = <marshallerType>.AllocateContainerForManagedElements(<nativeIdentifier>, <numElements>);
                yield return(ExpressionStatement(
                                 AssignmentExpression(
                                     SyntaxKind.SimpleAssignmentExpression,
                                     IdentifierName(managedIdentifier),
                                     InvocationExpression(
                                         MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                _marshallerTypeSyntax,
                                                                IdentifierName(ShapeMemberNames.LinearCollection.Stateless.AllocateContainerForManagedElements)),
                                         ArgumentList(SeparatedList(new ArgumentSyntax[]
                {
                    Argument(IdentifierName(nativeIdentifier)),
                    Argument(IdentifierName(numElementsIdentifier))
                }))))));

                // ReadOnlySpan<TUnmanagedElement> <nativeSpan> = <marshallerType>.GetUnmanagedValuesSource(<nativeIdentifier>, <numElements>)
                // Span<T> <managedSpan> = <marshallerType>.GetManagedValuesDestination(<managedIdentifier>)
                // << unmarshal contents >>
                yield return(GenerateUnmarshalStatement(info, context));
            }
        }
Example #9
0
        protected StatementSyntax GenerateContentsMarshallingStatement(
            TypePositionInfo info,
            StubCodeContext context,
            ExpressionSyntax lengthExpression,
            params StubCodeContext.Stage[] stagesToGeneratePerElement)
        {
            string managedSpanIdentifier  = MarshallerHelpers.GetManagedSpanIdentifier(info, context);
            string nativeSpanIdentifier   = MarshallerHelpers.GetNativeSpanIdentifier(info, context);
            var    elementSetupSubContext = new LinearCollectionElementMarshallingCodeContext(
                StubCodeContext.Stage.Setup,
                managedSpanIdentifier,
                nativeSpanIdentifier,
                context);

            TypePositionInfo localElementInfo = _elementInfo with
            {
                InstanceIdentifier = info.InstanceIdentifier,
                RefKind            = info.IsByRef ? info.RefKind : info.ByValueContentsMarshalKind.GetRefKindForByValueContentsKind(),
                ManagedIndex       = info.ManagedIndex,
                NativeIndex        = info.NativeIndex
            };

            List <StatementSyntax> elementStatements = new();

            foreach (StubCodeContext.Stage stage in stagesToGeneratePerElement)
            {
                var elementSubContext = elementSetupSubContext with {
                    CurrentStage = stage
                };
                elementStatements.AddRange(_elementMarshaller.Generate(localElementInfo, elementSubContext));
            }

            if (elementStatements.Any())
            {
                StatementSyntax marshallingStatement = Block(
                    List(_elementMarshaller.Generate(localElementInfo, elementSetupSubContext)
                         .Concat(elementStatements)));

                if (_elementMarshaller.AsNativeType(_elementInfo) is PointerTypeSyntax elementNativeType)
                {
                    PointerNativeTypeAssignmentRewriter rewriter = new(elementSetupSubContext.GetIdentifiers(localElementInfo).native, elementNativeType);
                    marshallingStatement = (StatementSyntax)rewriter.Visit(marshallingStatement);
                }

                // Iterate through the elements of the native collection to marshal them
                return(MarshallerHelpers.GetForLoop(lengthExpression, elementSetupSubContext.IndexerIdentifier)
                       .WithStatement(marshallingStatement));
            }

            return(EmptyStatement());
        }
        protected override InvocationExpressionSyntax GetManagedValuesDestination(TypePositionInfo info, StubCodeContext context)
        {
            string marshaller            = StatefulValueMarshalling.GetMarshallerIdentifier(info, context);
            string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);

            // <marshaller>.GetManagedValuesDestination(<numElements>)
            return(InvocationExpression(
                       MemberAccessExpression(
                           SyntaxKind.SimpleMemberAccessExpression,
                           IdentifierName(marshaller),
                           IdentifierName(ShapeMemberNames.LinearCollection.Stateless.GetManagedValuesDestination)),
                       ArgumentList(SingletonSeparatedList(
                                        Argument(IdentifierName(numElementsIdentifier))))));
        }
        public IEnumerable <StatementSyntax> GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context)
        {
            string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);

            if (!info.IsByRef && info.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out))
            {
                // int <numElements> = <GetManagedValuesSource>.Length;
                yield return(LocalDeclarationStatement(
                                 VariableDeclaration(
                                     PredefinedType(Token(SyntaxKind.IntKeyword)),
                                     SingletonSeparatedList(
                                         VariableDeclarator(numElementsIdentifier)
                                         .WithInitializer(EqualsValueClause(
                                                              MemberAccessExpression(
                                                                  SyntaxKind.SimpleMemberAccessExpression,
                                                                  GetManagedValuesSource(info, context),
                                                                  IdentifierName("Length"))))))));

                yield return(GenerateByValueOutUnmarshalStatement(info, context));
            }

            if (!_shape.HasFlag(MarshallerShape.ToManaged))
            {
                yield break;
            }
            else
            {
                // int <numElements> = <numElementsExpression>;
                yield return(LocalDeclarationStatement(
                                 VariableDeclaration(
                                     PredefinedType(Token(SyntaxKind.IntKeyword)),
                                     SingletonSeparatedList(
                                         VariableDeclarator(numElementsIdentifier)
                                         .WithInitializer(EqualsValueClause(_numElementsExpression))))));

                // ReadOnlySpan<TUnmanagedElement> <nativeSpan> = <marshaller>.GetUnmanagedValuesSource(<nativeIdentifier>, <numElements>)
                // Span<T> <managedSpan> = <marshaller>.GetManagedValuesDestination(<managedIdentifier>)
                // << unmarshal contents >>
                yield return(GenerateUnmarshalStatement(info, context));
            }

            foreach (StatementSyntax statement in _innerMarshaller.GenerateUnmarshalStatements(info, context))
            {
                yield return(statement);
            }
        }
        public IEnumerable <StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context)
        {
            // <marshaller> = new();
            LocalDeclarationStatementSyntax declaration = MarshallerHelpers.Declare(
                _marshallerType.Syntax,
                context.GetAdditionalIdentifier(info, MarshallerIdentifier),
                ImplicitObjectCreationExpression(ArgumentList(), initializer: null));

            // For byref-like marshaller types, we'll mark them as scoped.
            // Byref-like types can capture references, so by default the compiler has to worry that
            // they could enable those references to escape the current stack frame.
            // In particular, this can interact poorly with the caller-allocated-buffer marshalling
            // support and make the simple `marshaller.FromManaged(managed, stackalloc X[i])` expression
            // illegal. Mark the marshaller type as scoped so the compiler knows that it won't escape.
            if (_marshallerType is ValueTypeInfo {
                IsByRefLike : true
            })
Example #13
0
        protected override InvocationExpressionSyntax GetUnmanagedValuesSource(TypePositionInfo info, StubCodeContext context)
        {
            string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);
            string nativeIdentifier      = context.GetIdentifiers(info).native;

            // <marshallerType>.GetUnmanagedValuesSource(<nativeIdentifier>, <numElements>)
            return(InvocationExpression(
                       MemberAccessExpression(
                           SyntaxKind.SimpleMemberAccessExpression,
                           _marshallerTypeSyntax,
                           IdentifierName(ShapeMemberNames.LinearCollection.Stateless.GetUnmanagedValuesSource)),
                       ArgumentList(SeparatedList(new ArgumentSyntax[]
            {
                Argument(IdentifierName(nativeIdentifier)),
                Argument(IdentifierName(numElementsIdentifier))
            }))));
        }
Example #14
0
        public IEnumerable <StatementSyntax> GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context)
        {
            if (!_shape.HasFlag(MarshallerShape.ToUnmanaged) && !_shape.HasFlag(MarshallerShape.CallerAllocatedBuffer))
            {
                yield break;
            }

            if (_shape.HasFlag(MarshallerShape.ToUnmanaged) &&
                !(_shape.HasFlag(MarshallerShape.CallerAllocatedBuffer) &&
                  MarshallerHelpers.CanUseCallerAllocatedBuffer(info, context)))
            {
                (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);
                string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);

                // <nativeIdentifier> = <marshallerType>.AllocateContainerForUnmanagedElements(<managedIdentifier>, out <numElements>);
                yield return(ExpressionStatement(
                                 AssignmentExpression(
                                     SyntaxKind.SimpleAssignmentExpression,
                                     IdentifierName(nativeIdentifier),
                                     InvocationExpression(
                                         MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                _marshallerTypeSyntax,
                                                                IdentifierName(ShapeMemberNames.LinearCollection.Stateless.AllocateContainerForUnmanagedElements)),
                                         ArgumentList(SeparatedList(new ArgumentSyntax[]
                {
                    Argument(IdentifierName(managedIdentifier)),
                    Argument(IdentifierName(numElementsIdentifier))
                    .WithRefOrOutKeyword(Token(SyntaxKind.OutKeyword))
                }))))));
            }

            if (!info.IsByRef && info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.Out)
            {
                yield return(GenerateByValueOutMarshalStatement(info, context));
            }
            else
            {
                yield return(GenerateMarshalStatement(info, context));
            }
        }
        /// <summary>
        /// Generate the method body of the p/invoke stub.
        /// </summary>
        /// <param name="dllImportName">Name of the target DllImport function to invoke</param>
        /// <returns>Method body of the p/invoke stub</returns>
        /// <remarks>
        /// The generated code assumes it will be in an unsafe context.
        /// </remarks>
        public BlockSyntax GeneratePInvokeBody(string dllImportName)
        {
            GeneratedStatements statements    = GeneratedStatements.Create(_marshallers, _context, IdentifierName(dllImportName));
            bool shouldInitializeVariables    = !statements.GuaranteedUnmarshal.IsEmpty || !statements.Cleanup.IsEmpty;
            VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForManagedToNative(_marshallers, _context, shouldInitializeVariables);

            var setupStatements = new List <StatementSyntax>();

            if (_setLastError)
            {
                // Declare variable for last error
                setupStatements.Add(MarshallerHelpers.Declare(
                                        PredefinedType(Token(SyntaxKind.IntKeyword)),
                                        LastErrorIdentifier,
                                        initializeToDefault: false));
            }

            if (!statements.GuaranteedUnmarshal.IsEmpty)
            {
                setupStatements.Add(MarshallerHelpers.Declare(PredefinedType(Token(SyntaxKind.BoolKeyword)), InvokeSucceededIdentifier, initializeToDefault: true));
            }

            setupStatements.AddRange(declarations.Initializations);
            setupStatements.AddRange(declarations.Variables);
            setupStatements.AddRange(statements.Setup);

            var tryStatements = new List <StatementSyntax>();

            tryStatements.AddRange(statements.Marshal);

            BlockSyntax fixedBlock = Block(statements.PinnedMarshal);

            if (_setLastError)
            {
                StatementSyntax clearLastError = MarshallerHelpers.CreateClearLastSystemErrorStatement(SuccessErrorCode);

                StatementSyntax getLastError = MarshallerHelpers.CreateGetLastSystemErrorStatement(LastErrorIdentifier);

                fixedBlock = fixedBlock.AddStatements(clearLastError, statements.InvokeStatement, getLastError);
            }
            else
            {
                fixedBlock = fixedBlock.AddStatements(statements.InvokeStatement);
            }
            tryStatements.Add(statements.Pin.NestFixedStatements(fixedBlock));
            // <invokeSucceeded> = true;
            if (!statements.GuaranteedUnmarshal.IsEmpty)
            {
                tryStatements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                                                                           IdentifierName(InvokeSucceededIdentifier),
                                                                           LiteralExpression(SyntaxKind.TrueLiteralExpression))));
            }

            tryStatements.AddRange(statements.NotifyForSuccessfulInvoke);
            tryStatements.AddRange(statements.Unmarshal);

            List <StatementSyntax> allStatements     = setupStatements;
            List <StatementSyntax> finallyStatements = new List <StatementSyntax>();

            if (!statements.GuaranteedUnmarshal.IsEmpty)
            {
                finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal)));
            }

            finallyStatements.AddRange(statements.Cleanup);
            if (finallyStatements.Count > 0)
            {
                // Add try-finally block if there are any statements in the finally block
                allStatements.Add(
                    TryStatement(Block(tryStatements), default, FinallyClause(Block(finallyStatements))));
Example #16
0
        public IEnumerable <StatementSyntax> GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context)
        {
            if (MarshallerHelpers.CanUseCallerAllocatedBuffer(info, context))
            {
                return(GenerateCallerAllocatedBufferMarshalStatements());
            }

            return(_innerMarshaller.GenerateMarshalStatements(info, context));

            IEnumerable <StatementSyntax> GenerateCallerAllocatedBufferMarshalStatements()
            {
                string bufferIdentifier = context.GetAdditionalIdentifier(info, "buffer");

                // Span<bufferElementType> <bufferIdentifier> = stackalloc <bufferElementType>[<marshallerType>.BufferSize];
                yield return(LocalDeclarationStatement(
                                 VariableDeclaration(
                                     GenericName(
                                         Identifier(TypeNames.System_Span),
                                         TypeArgumentList(
                                             SingletonSeparatedList(_bufferElementType))),
                                     SingletonSeparatedList(
                                         VariableDeclarator(bufferIdentifier)
                                         .WithInitializer(EqualsValueClause(
                                                              StackAllocArrayCreationExpression(
                                                                  ArrayType(
                                                                      _bufferElementType,
                                                                      SingletonList(ArrayRankSpecifier(SingletonSeparatedList <ExpressionSyntax>(
                                                                                                           MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                                                                                  _marshallerType,
                                                                                                                                  IdentifierName(ShapeMemberNames.BufferSize))
                                                                                                           )))))))))));

                (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);

                if (_isLinearCollectionMarshalling)
                {
                    string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);

                    // <nativeIdentifier> = <marshallerType>.AllocateContainerForUnmanagedElements(<managedIdentifier>, <bufferIdentifier>, out <numElements>);
                    yield return(ExpressionStatement(
                                     AssignmentExpression(
                                         SyntaxKind.SimpleAssignmentExpression,
                                         IdentifierName(nativeIdentifier),
                                         InvocationExpression(
                                             MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                    _marshallerType,
                                                                    IdentifierName(ShapeMemberNames.LinearCollection.Stateless.AllocateContainerForUnmanagedElements)),
                                             ArgumentList(SeparatedList(new ArgumentSyntax[]
                    {
                        Argument(IdentifierName(managedIdentifier)),
                        Argument(IdentifierName(bufferIdentifier)),
                        Argument(IdentifierName(numElementsIdentifier))
                        .WithRefOrOutKeyword(Token(SyntaxKind.OutKeyword))
                    }))))));

                    // Linear collections have additional marshalling required using the inner marshaller
                    foreach (StatementSyntax statement in _innerMarshaller.GenerateMarshalStatements(info, context))
                    {
                        yield return(statement);
                    }
                }
                else
                {
                    // <nativeIdentifier> = <marshallerType>.ConvertToUnmanaged(<managedIdentifier>, <nativeIdentifier>__buffer);
                    yield return(ExpressionStatement(
                                     AssignmentExpression(
                                         SyntaxKind.SimpleAssignmentExpression,
                                         IdentifierName(nativeIdentifier),
                                         InvocationExpression(
                                             MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                    _marshallerType,
                                                                    IdentifierName(ShapeMemberNames.Value.Stateless.ConvertToUnmanaged)),
                                             ArgumentList(SeparatedList(new ArgumentSyntax[]
                    {
                        Argument(IdentifierName(managedIdentifier)),
                        Argument(IdentifierName(bufferIdentifier))
                    }))))));
                }
            }
        }
Example #17
0
        protected StatementSyntax GenerateByValueOutUnmarshalStatement(TypePositionInfo info, StubCodeContext context)
        {
            // Use ManagedSource and NativeDestination spans for by-value marshalling since we're just marshalling back the contents,
            // not the array itself.
            // This code is ugly since we're now enforcing readonly safety with ReadOnlySpan for all other scenarios,
            // but this is an uncommon case so we don't want to design the API around enabling just it.
            string numElementsIdentifier = MarshallerHelpers.GetNumElementsIdentifier(info, context);
            string managedSpanIdentifier = MarshallerHelpers.GetManagedSpanIdentifier(info, context);

            // Span<TElement> <managedSpan> = MemoryMarshal.CreateSpan(ref Unsafe.AsRef(in <GetManagedValuesSource>.GetPinnableReference(), <numElements>));
            LocalDeclarationStatementSyntax managedValuesDeclaration = LocalDeclarationStatement(VariableDeclaration(
                                                                                                     GenericName(
                                                                                                         Identifier(TypeNames.System_Span),
                                                                                                         TypeArgumentList(
                                                                                                             SingletonSeparatedList(_elementInfo.ManagedType.Syntax))
                                                                                                         ),
                                                                                                     SingletonSeparatedList(VariableDeclarator(managedSpanIdentifier).WithInitializer(EqualsValueClause(
                                                                                                                                                                                          InvocationExpression(
                                                                                                                                                                                              MemberAccessExpression(
                                                                                                                                                                                                  SyntaxKind.SimpleMemberAccessExpression,
                                                                                                                                                                                                  ParseName(TypeNames.System_Runtime_InteropServices_MemoryMarshal),
                                                                                                                                                                                                  IdentifierName("CreateSpan")))
                                                                                                                                                                                          .WithArgumentList(
                                                                                                                                                                                              ArgumentList(
                                                                                                                                                                                                  SeparatedList(
                                                                                                                                                                                                      new[]
            {
                Argument(
                    InvocationExpression(
                        MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                               ParseName(TypeNames.System_Runtime_CompilerServices_Unsafe),
                                               IdentifierName("AsRef")),
                        ArgumentList(SingletonSeparatedList(
                                         Argument(
                                             InvocationExpression(
                                                 MemberAccessExpression(
                                                     SyntaxKind.SimpleMemberAccessExpression,
                                                     GetManagedValuesSource(info, context),
                                                     IdentifierName("GetPinnableReference")),
                                                 ArgumentList()))
                                         .WithRefKindKeyword(
                                             Token(SyntaxKind.InKeyword))))))
                .WithRefKindKeyword(
                    Token(SyntaxKind.RefKeyword)),
                Argument(
                    IdentifierName(numElementsIdentifier))
            }))))))));

            // Span<TUnmanagedElement> <nativeSpan> = <GetUnmanagedValuesDestination>
            string nativeSpanIdentifier = MarshallerHelpers.GetNativeSpanIdentifier(info, context);
            LocalDeclarationStatementSyntax unmanagedValuesDeclaration = LocalDeclarationStatement(VariableDeclaration(
                                                                                                       GenericName(
                                                                                                           Identifier(TypeNames.System_Span),
                                                                                                           TypeArgumentList(SingletonSeparatedList(_unmanagedElementType))),
                                                                                                       SingletonSeparatedList(
                                                                                                           VariableDeclarator(
                                                                                                               Identifier(nativeSpanIdentifier))
                                                                                                           .WithInitializer(EqualsValueClause(
                                                                                                                                GetUnmanagedValuesDestination(info, context))))));

            return(Block(
                       managedValuesDeclaration,
                       unmanagedValuesDeclaration,
                       GenerateContentsMarshallingStatement(
                           info,
                           context,
                           IdentifierName(numElementsIdentifier),
                           StubCodeContext.Stage.UnmarshalCapture,
                           StubCodeContext.Stage.Unmarshal)));
        }