private ExpressionSyntax CastToManagedIfNecessary(ExpressionSyntax expression)
        {
            // Skip the cast if the managed and unmanaged element types are the same
            if (_unmanagedElementType.IsEquivalentTo(_managedElementType))
            {
                return(expression);
            }

            // MemoryMarshal.Cast<<unmanagedElementType>, <elementType>>(<expression>)
            return(InvocationExpression(
                       MemberAccessExpression(
                           SyntaxKind.SimpleMemberAccessExpression,
                           ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal),
                           GenericName(
                               Identifier("Cast"),
                               TypeArgumentList(SeparatedList(
                                                    new[]
            {
                _unmanagedElementType,
                _managedElementType
            })))),
                       ArgumentList(SingletonSeparatedList(
                                        Argument(expression)))));
        }
Beispiel #2
0
        private IEnumerable <StatementSyntax> GeneratePinningPath(TypePositionInfo info, StubCodeContext context)
        {
            (string managedIdentifer, string nativeIdentifier) = context.GetIdentifiers(info);
            string byRefIdentifier = $"__byref_{managedIdentifer}";

            // The element type here is used only for refs/pointers. In the pointer array case, we use byte as the basic placeholder type,
            // since we can't use pointer types in generic type parameters.
            bool       isPointerArray   = info.ManagedType is SzArrayType arrayType && arrayType.ElementTypeInfo is PointerTypeInfo;
            TypeSyntax arrayElementType = isPointerArray ? PredefinedType(Token(SyntaxKind.ByteKeyword)) : _elementType;

            if (context.CurrentStage == StubCodeContext.Stage.Marshal)
            {
                // [COMPAT] We use explicit byref calculations here instead of just using a fixed statement
                // since a fixed statement converts a zero-length array to a null pointer.
                // Many native APIs, such as GDI+, ICU, etc. validate that an array parameter is non-null
                // even when the passed in array length is zero. To avoid breaking customers that want to move
                // to source-generated interop in subtle ways, we explicitly pass a reference to the 0-th element
                // of an array as long as it is non-null, matching the behavior of the built-in interop system
                // for single-dimensional zero-based arrays.

                // ref <elementType> <byRefIdentifier> = ref <managedIdentifer> == null ? ref *(<elementType>*)0 : ref MemoryMarshal.GetArrayDataReference(<managedIdentifer>);
                PrefixUnaryExpressionSyntax nullRef =
                    PrefixUnaryExpression(SyntaxKind.PointerIndirectionExpression,
                                          CastExpression(
                                              PointerType(arrayElementType),
                                              LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0))));

                InvocationExpressionSyntax getArrayDataReference =
                    InvocationExpression(
                        MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression,
                            ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal),
                            IdentifierName("GetArrayDataReference")),
                        ArgumentList(SingletonSeparatedList(
                                         Argument(IdentifierName(managedIdentifer)))));

                yield return(LocalDeclarationStatement(
                                 VariableDeclaration(
                                     RefType(arrayElementType))
                                 .WithVariables(SingletonSeparatedList(
                                                    VariableDeclarator(Identifier(byRefIdentifier))
                                                    .WithInitializer(EqualsValueClause(
                                                                         RefExpression(ParenthesizedExpression(
                                                                                           ConditionalExpression(
                                                                                               BinaryExpression(
                                                                                                   SyntaxKind.EqualsExpression,
                                                                                                   IdentifierName(managedIdentifer),
                                                                                                   LiteralExpression(
                                                                                                       SyntaxKind.NullLiteralExpression)),
                                                                                               RefExpression(nullRef),
                                                                                               RefExpression(getArrayDataReference))))))))));
            }
            if (context.CurrentStage == StubCodeContext.Stage.Pin)
            {
                TypeSyntax nativeType = AsNativeType(info);

                // We skip the Unsafe.As if the element type and native element type are equivalent (ignoring trivia differences)
                // &<byrefIdentifier>
                // or
                // &Unsafe.As<elementType, nativeElementType>(ref <byrefIdentifier>)
                TypeSyntax nativeElementType = nativeType is PointerTypeSyntax pointerType ? pointerType.ElementType : nativeType;
                var        initializer       = arrayElementType.IsEquivalentTo(nativeElementType, topLevel: true)
                    ? PrefixUnaryExpression(SyntaxKind.AddressOfExpression, IdentifierName(byRefIdentifier))
                    : PrefixUnaryExpression(SyntaxKind.AddressOfExpression,
                                            InvocationExpression(
                                                MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                       ParseTypeName(TypeNames.System_Runtime_CompilerServices_Unsafe),
                                                                       GenericName("As").AddTypeArgumentListArguments(
                                                                           arrayElementType,
                                                                           nativeElementType)))
                                            .AddArgumentListArguments(
                                                Argument(IdentifierName(byRefIdentifier))
                                                .WithRefKindKeyword(Token(SyntaxKind.RefKeyword))));

                // fixed (<nativeType> <nativeIdentifier> = <initializer>)
                yield return(FixedStatement(
                                 VariableDeclaration(nativeType, SingletonSeparatedList(
                                                         VariableDeclarator(nativeIdentifier)
                                                         .WithInitializer(EqualsValueClause(initializer)))),
                                 EmptyStatement()));
            }
        }
Beispiel #3
0
        //		internal static readonly AstNode wherePatternCase1 =
        //			new InvocationExpression(
        //				new MemberReferenceExpression(
        //					new InvocationExpression(
        //						new MemberReferenceExpression(new AnyNode("target"), "Where"),
        //						new LambdaExpression {
        //							Parameters = { PatternHelper.NamedParameter ("param1", PatternHelper.AnyType ("paramType", true), Pattern.AnyString) },
        //							Body = PatternHelper.OptionalParentheses (new IsExpression(new AnyNode("expr1"), new AnyNode("type")))
        //						}
        //					), "Select"),
        //				new LambdaExpression {
        //					Parameters = { PatternHelper.NamedParameter ("param2", PatternHelper.AnyType ("paramType", true), Pattern.AnyString) },
        //					Body = PatternHelper.OptionalParentheses (new AsExpression(PatternHelper.OptionalParentheses (new AnyNode("expr2")), new Backreference("type")))
        //				}
        //		);
        //
        //		internal static readonly AstNode wherePatternCase2 =
        //			new InvocationExpression(
        //				new MemberReferenceExpression(
        //					new InvocationExpression(
        //						new MemberReferenceExpression(new AnyNode("target"), "Where"),
        //						new LambdaExpression {
        //							Parameters = { PatternHelper.NamedParameter ("param1", PatternHelper.AnyType ("paramType", true), Pattern.AnyString) },
        //							Body = PatternHelper.OptionalParentheses (new IsExpression(PatternHelper.OptionalParentheses (new AnyNode("expr1")), new AnyNode("type")))
        //						}
        //					), "Select"),
        //				new LambdaExpression {
        //					Parameters = { PatternHelper.NamedParameter ("param2", PatternHelper.AnyType ("paramType", true), Pattern.AnyString) },
        //					Body = PatternHelper.OptionalParentheses (new CastExpression(new Backreference("type"), PatternHelper.OptionalParentheses (new AnyNode("expr2"))))
        //				}
        //		);
        static bool MatchWhereSelect(InvocationExpressionSyntax selectInvoke, out ExpressionSyntax target, out TypeSyntax type)
        {
            target = null;
            type   = null;

            if (selectInvoke.ArgumentList.Arguments.Count != 1)
            {
                return(false);
            }
            var anyInvokeBase = selectInvoke.Expression as MemberAccessExpressionSyntax;

            if (anyInvokeBase == null || anyInvokeBase.Name.Identifier.Text != "Select")
            {
                return(false);
            }
            var whereInvoke = anyInvokeBase.Expression as InvocationExpressionSyntax;

            if (whereInvoke == null || whereInvoke.ArgumentList.Arguments.Count != 1)
            {
                return(false);
            }
            var baseMember = whereInvoke.Expression as MemberAccessExpressionSyntax;

            if (baseMember == null || baseMember.Name.Identifier.Text != "Where")
            {
                return(false);
            }
            target = baseMember.Expression;

            ParameterSyntax  param1, param2;
            ExpressionSyntax expr1, expr2;

            if (!ExtractLambda(whereInvoke.ArgumentList.Arguments[0], out param1, out expr1))
            {
                return(false);
            }
            if (!ExtractLambda(selectInvoke.ArgumentList.Arguments[0], out param2, out expr2))
            {
                return(false);
            }
            if (!expr1.IsKind(SyntaxKind.IsExpression))
            {
                return(false);
            }
            type = (expr1 as BinaryExpressionSyntax)?.Right as TypeSyntax;
            if (type == null)
            {
                return(false);
            }
            if (expr2.IsKind(SyntaxKind.AsExpression))
            {
                if (!CompareNames(param2, (expr2 as BinaryExpressionSyntax).Left as IdentifierNameSyntax))
                {
                    return(false);
                }
                if (!type.IsEquivalentTo((expr2 as BinaryExpressionSyntax)?.Right))
                {
                    return(false);
                }
            }
            else if (expr2.IsKind(SyntaxKind.CastExpression))
            {
                if (!CompareNames(param2, (expr2 as CastExpressionSyntax)?.Expression.SkipParens() as IdentifierNameSyntax))
                {
                    return(false);
                }
                if (!type.IsEquivalentTo((expr2 as CastExpressionSyntax)?.Type))
                {
                    return(false);
                }
            }
            else
            {
                return(false);
            }

            if (!CompareNames(param1, (expr1 as BinaryExpressionSyntax)?.Left as IdentifierNameSyntax))
            {
                return(false);
            }


            return(target != null);
        }
Beispiel #4
0
        public IEnumerable <StatementSyntax> GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable <ArgumentSyntax> nativeTypeConstructorArguments)
        {
            if (!_shape.HasFlag(MarshallerShape.ToUnmanaged))
            {
                yield break;
            }

            (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);
            string numElementsIdentifier = 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))
            }))))));

            // <marshallerType>.GetUnmanagedValuesDestination(<nativeIdentifier>, <numElements>)
            ExpressionSyntax destination =
                InvocationExpression(
                    MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        _marshallerTypeSyntax,
                        IdentifierName(ShapeMemberNames.LinearCollection.Stateless.GetUnmanagedValuesDestination)),
                    ArgumentList(SeparatedList(new ArgumentSyntax[]
            {
                Argument(IdentifierName(nativeIdentifier)),
                Argument(IdentifierName(numElementsIdentifier)),
            })));

            if (!info.IsByRef && info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.Out)
            {
                // If the parameter is marshalled by-value [Out], then we don't marshal the contents of the collection.
                // We do clear the span, so that if the invoke target doesn't fill it, we aren't left with undefined content.
                // <marshallerType>.GetUnmanagedValuesDestination(<nativeIdentifier>, <numElements>).Clear();
                yield return(ExpressionStatement(
                                 InvocationExpression(
                                     MemberAccessExpression(
                                         SyntaxKind.SimpleMemberAccessExpression,
                                         destination,
                                         IdentifierName("Clear")))));

                yield break;
            }

            // Skip the cast if the managed and unmanaged element types are the same
            if (!_unmanagedElementType.IsEquivalentTo(_managedElementType))
            {
                // MemoryMarshal.Cast<<unmanagedElementType>, <managedElementType>>(<destination>)
                destination = InvocationExpression(
                    MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        ParseTypeName(TypeNames.System_Runtime_InteropServices_MemoryMarshal),
                        GenericName(
                            Identifier("Cast"))
                        .WithTypeArgumentList(
                            TypeArgumentList(
                                SeparatedList(
                                    new[]
                {
                    _unmanagedElementType,
                    _managedElementType
                })))),
                    ArgumentList(SingletonSeparatedList(
                                     Argument(destination))));
            }

            // <marshallerType>.GetManagedValuesSource(<managedIdentifer>).CopyTo(<destination>);
            yield return(ExpressionStatement(
                             InvocationExpression(
                                 MemberAccessExpression(
                                     SyntaxKind.SimpleMemberAccessExpression,
                                     InvocationExpression(
                                         MemberAccessExpression(
                                             SyntaxKind.SimpleMemberAccessExpression,
                                             _marshallerTypeSyntax,
                                             IdentifierName(ShapeMemberNames.LinearCollection.Stateless.GetManagedValuesSource)),
                                         ArgumentList(SingletonSeparatedList(
                                                          Argument(IdentifierName(managedIdentifier))))),
                                     IdentifierName("CopyTo")))
                             .AddArgumentListArguments(
                                 Argument(destination))));
        }
Beispiel #5
0
 public static bool IsVoid(this TypeSyntax type)
 {
     return(type.IsEquivalentTo(PredefinedType(VoidKeyword.ToToken()), false));
 }