예제 #1
0
 public IEnumerable <StatementSyntax> GenerateNotifyForSuccessfulInvokeStatements(TypePositionInfo info, StubCodeContext context) => _innerMarshaller.GenerateNotifyForSuccessfulInvokeStatements(info, context);
예제 #2
0
 public IEnumerable <StatementSyntax> GenerateNotifyForSuccessfulInvokeStatements(TypePositionInfo info, StubCodeContext context)
 {
     return(Array.Empty <StatementSyntax>());
 }
예제 #3
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))
                    }))))));
                }
            }
        }
예제 #4
0
 private bool IsPinningPathSupported(TypePositionInfo info, StubCodeContext context)
 {
     return(context.SingleFrameSpansNativeContext && _enablePinning && !info.IsByRef && !info.IsManagedReturnPosition);
 }
예제 #5
0
 public IMarshallingGenerator Create(
     TypePositionInfo info,
     StubCodeContext context)
 {
     throw new MarshallingNotSupportedException(info, context);
 }
예제 #6
0
 public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) => _inner.GetValueBoundaryBehavior(info, context);
예제 #7
0
 public TypeSyntax AsNativeType(TypePositionInfo info)
 {
     return(_manualMarshallingGenerator.AsNativeType(info));
 }
예제 #8
0
 public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => true;
 public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context)
 {
     return(info.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier);
 }
예제 #10
0
 public IEnumerable <StatementSyntax> GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) => Array.Empty <StatementSyntax>();
예제 #11
0
 public IEnumerable <StatementSyntax> GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) => Array.Empty <StatementSyntax>();
예제 #12
0
 public TypeSyntax AsNativeType(TypePositionInfo info) => _nativeTypeSyntax;
예제 #13
0
 public TypeSyntax AsNativeType(TypePositionInfo info)
 {
     return(_nativeTypeSyntax);
 }
예제 #14
0
 public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => _innerMarshaller.UsesNativeIdentifier(info, context);
예제 #15
0
 public virtual bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => _inner.UsesNativeIdentifier(info, context);
 public TypeSyntax AsNativeType(TypePositionInfo info)
 {
     return(_nativeTypeMarshaller.AsNativeType(info));
 }
예제 #17
0
 public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) => _inner.GetNativeSignatureBehavior(info);
 public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info)
 {
     return(info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType);
 }
예제 #19
0
 public virtual IEnumerable <ExpressionSyntax> GenerateBind(TypePositionInfo info, StubCodeContext context)
 {
     yield return(MarshalerTypeName(Type));
 }
 public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context)
 {
     return(_nativeTypeMarshaller.UsesNativeIdentifier(info, context));
 }
예제 #21
0
 public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info)
 {
     return(_manualMarshallingGenerator.GetNativeSignatureBehavior(info));
 }
예제 #22
0
 public ParameterSyntax AsParameter(TypePositionInfo info)
 {
     return(_manualMarshallingGenerator.AsParameter(info));
 }
예제 #23
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()));
            }
        }
예제 #24
0
 /// <summary>
 /// Get managed and native instance identifiers for the <paramref name="info"/>
 /// </summary>
 /// <param name="info">Object for which to get identifiers</param>
 /// <returns>Managed and native identifiers</returns>
 public virtual (string managed, string native) GetIdentifiers(TypePositionInfo info)
 {
     return(info.InstanceIdentifier, $"__{info.InstanceIdentifier.TrimStart('@')}{GeneratedNativeIdentifierSuffix}");
 }
예제 #25
0
 public IEnumerable <StatementSyntax> GeneratePinStatements(TypePositionInfo info, StubCodeContext context)
 {
     return(Array.Empty <StatementSyntax>());
 }
예제 #26
0
 public virtual string GetAdditionalIdentifier(TypePositionInfo info, string name)
 {
     return($"{GetIdentifiers(info).native}__{name}");
 }
예제 #27
0
 public TypeSyntax AsNativeType(TypePositionInfo info) => _innerMarshaller.AsNativeType(info);
예제 #28
0
 public ParameterSyntax AsParameter(TypePositionInfo info) => _inner.AsParameter(info);
예제 #29
0
 public IEnumerable <StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) => _innerMarshaller.GenerateSetupStatements(info, context);
        protected IEnumerable <StatementSyntax> GenerateConditionalAllocationSyntax(
            TypePositionInfo info,
            StubCodeContext context,
            int stackallocMaxSize)
        {
            (_, string nativeIdentifier) = context.GetIdentifiers(info);

            string allocationMarkerIdentifier = GetAllocationMarkerIdentifier(info, context);
            string byteLenIdentifier          = GetByteLengthIdentifier(info, context);
            string stackAllocPtrIdentifier    = GetStackAllocIdentifier(info, context);
            // <native> = <allocationExpression>;
            ExpressionStatementSyntax allocationStatement = ExpressionStatement(
                AssignmentExpression(
                    SyntaxKind.SimpleAssignmentExpression,
                    IdentifierName(nativeIdentifier),
                    GenerateAllocationExpression(info, context, Identifier(byteLenIdentifier), out bool allocationRequiresByteLength)));

            // int <byteLenIdentifier> = <byteLengthExpression>;
            LocalDeclarationStatementSyntax byteLenAssignment = LocalDeclarationStatement(
                VariableDeclaration(
                    PredefinedType(Token(SyntaxKind.IntKeyword)),
                    SingletonSeparatedList(
                        VariableDeclarator(byteLenIdentifier)
                        .WithInitializer(EqualsValueClause(
                                             GenerateByteLengthCalculationExpression(info, context))))));

            if (!UsesConditionalStackAlloc(info, context))
            {
                List <StatementSyntax> statements = new List <StatementSyntax>();
                if (allocationRequiresByteLength)
                {
                    statements.Add(byteLenAssignment);
                }
                statements.Add(allocationStatement);
                yield return(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                                                                      IdentifierName(nativeIdentifier),
                                                                      LiteralExpression(SyntaxKind.NullLiteralExpression))));

                yield return(IfStatement(
                                 GenerateNullCheckExpression(info, context),
                                 Block(statements)));

                yield break;
            }

            // Code block for stackalloc if number of bytes is below threshold size
            BlockSyntax marshalOnStack = Block(
                // byte* <stackAllocPtr> = stackalloc byte[<byteLen>];
                LocalDeclarationStatement(
                    VariableDeclaration(
                        PointerType(PredefinedType(Token(SyntaxKind.ByteKeyword))),
                        SingletonSeparatedList(
                            VariableDeclarator(stackAllocPtrIdentifier)
                            .WithInitializer(EqualsValueClause(
                                                 StackAllocArrayCreationExpression(
                                                     ArrayType(
                                                         PredefinedType(Token(SyntaxKind.ByteKeyword)),
                                                         SingletonList(
                                                             ArrayRankSpecifier(SingletonSeparatedList <ExpressionSyntax>(
                                                                                    IdentifierName(byteLenIdentifier))))))))))),
                GenerateStackallocOnlyValueMarshalling(info, context, Identifier(byteLenIdentifier), Identifier(stackAllocPtrIdentifier)),
                // <nativeIdentifier> = <stackAllocPtr>;
                ExpressionStatement(
                    AssignmentExpression(
                        SyntaxKind.SimpleAssignmentExpression,
                        IdentifierName(nativeIdentifier),
                        CastExpression(
                            AsNativeType(info),
                            IdentifierName(stackAllocPtrIdentifier)))));

            //   if (<byteLen> > <StackAllocBytesThreshold>)
            //   {
            //       <allocationStatement>;
            //       <allocationMarker> = true;
            //   }
            //   else
            //   {
            //       byte* <stackAllocPtr> = stackalloc byte[<byteLen>];
            //       <marshalValueOnStackStatement>;
            //       <native> = (<nativeType>)<stackAllocPtr>;
            //   }
            IfStatementSyntax allocBlock = IfStatement(
                BinaryExpression(
                    SyntaxKind.GreaterThanExpression,
                    IdentifierName(byteLenIdentifier),
                    LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(stackallocMaxSize))),
                Block(
                    allocationStatement,
                    ExpressionStatement(
                        AssignmentExpression(
                            SyntaxKind.SimpleAssignmentExpression,
                            IdentifierName(allocationMarkerIdentifier),
                            LiteralExpression(SyntaxKind.TrueLiteralExpression)))),
                ElseClause(marshalOnStack));

            yield return(IfStatement(
                             GenerateNullCheckExpression(info, context),
                             Block(byteLenAssignment, allocBlock)));
        }