public IEnumerable <StatementSyntax> GenerateNotifyForSuccessfulInvokeStatements(TypePositionInfo info, StubCodeContext context) => _innerMarshaller.GenerateNotifyForSuccessfulInvokeStatements(info, context);
public IEnumerable <StatementSyntax> GenerateNotifyForSuccessfulInvokeStatements(TypePositionInfo info, StubCodeContext context) { return(Array.Empty <StatementSyntax>()); }
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)) })))))); } } }
private bool IsPinningPathSupported(TypePositionInfo info, StubCodeContext context) { return(context.SingleFrameSpansNativeContext && _enablePinning && !info.IsByRef && !info.IsManagedReturnPosition); }
public IMarshallingGenerator Create( TypePositionInfo info, StubCodeContext context) { throw new MarshallingNotSupportedException(info, context); }
public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) => _inner.GetValueBoundaryBehavior(info, context);
public TypeSyntax AsNativeType(TypePositionInfo info) { return(_manualMarshallingGenerator.AsNativeType(info)); }
public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => true;
public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) { return(info.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier); }
public IEnumerable <StatementSyntax> GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) => Array.Empty <StatementSyntax>();
public IEnumerable <StatementSyntax> GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) => Array.Empty <StatementSyntax>();
public TypeSyntax AsNativeType(TypePositionInfo info) => _nativeTypeSyntax;
public TypeSyntax AsNativeType(TypePositionInfo info) { return(_nativeTypeSyntax); }
public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => _innerMarshaller.UsesNativeIdentifier(info, context);
public virtual bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => _inner.UsesNativeIdentifier(info, context);
public TypeSyntax AsNativeType(TypePositionInfo info) { return(_nativeTypeMarshaller.AsNativeType(info)); }
public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) => _inner.GetNativeSignatureBehavior(info);
public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { return(info.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType); }
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)); }
public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) { return(_manualMarshallingGenerator.GetNativeSignatureBehavior(info)); }
public ParameterSyntax AsParameter(TypePositionInfo info) { return(_manualMarshallingGenerator.AsParameter(info)); }
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())); } }
/// <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}"); }
public IEnumerable <StatementSyntax> GeneratePinStatements(TypePositionInfo info, StubCodeContext context) { return(Array.Empty <StatementSyntax>()); }
public virtual string GetAdditionalIdentifier(TypePositionInfo info, string name) { return($"{GetIdentifiers(info).native}__{name}"); }
public TypeSyntax AsNativeType(TypePositionInfo info) => _innerMarshaller.AsNativeType(info);
public ParameterSyntax AsParameter(TypePositionInfo info) => _inner.AsParameter(info);
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))); }