예제 #1
0
        public static void InjectMiddleware(ref IMarshalContext ctx, Action next)
        {
            var context     = ctx;
            var injectDatas = ctx.MethodSymbol.GetAttributes().Where(
                x => SymbolEqualityComparer.Default.Equals(x.AttributeClass, context.Compilation.GetTypeByMetadataName(typeof(InjectAttribute).FullName))
                );

            foreach (var injectData in injectDatas)
            {
                var injectPoint = (SilkTouchStage)injectData.ConstructorArguments[0].Value !;
                var code        = (string)injectData.ConstructorArguments[1].Value !;
                ctx.AddSideEffectToStage(injectPoint, ctx => {
                    if (injectPoint == SilkTouchStage.End)
                    {
                        var substitutions = _substitutionRegex.Match(code);
                        if (substitutions.Success)
                        {
                            var codeBuilder  = new StringBuilder();
                            var start        = 0;
                            string?resultStr = null;
                            Dictionary <string, string>?pValues = null;
                            while (substitutions.Success)
                            {
                                string?substitution = null;
                                if (substitutions.Groups["result"].Success)
                                {
                                    if (ctx.ResultVariable.HasValue)
                                    {
                                        // Cache for multiple-substitution
                                        if (resultStr is null)
                                        {
                                            resultStr = ParenthesizedExpression(ctx.ResolveVariable(ctx.ResultVariable.Value).Value)
                                                        .NormalizeWhitespace()
                                                        .ToFullString();
                                        }
                                        substitution = resultStr;
                                    }
                                }
                                else
                                {
                                    var parameterName = substitutions.Groups["pname"].Value;

                                    // Create parameter lookup dictionary first time we see the substitution.
                                    if (pValues is null)
                                    {
                                        pValues = ctx.MethodSymbol.Parameters
                                                  .Select((p, i) => (
                                                              Name: p.Name,
                                                              Value: ParenthesizedExpression(ctx.ResolveVariable(ctx.ParameterVariables[i]).Value)
                                                              .NormalizeWhitespace()
                                                              .ToFullString()))
                                                  .ToDictionary(t => t.Name, t => t.Value);
                                    }

                                    if (pValues.TryGetValue(parameterName, out
                                                            var value))
                                    {
                                        substitution = value;
                                    }
                                }
예제 #2
0
        public static void SpanMarshaller(ref IMarshalContext ctx, Action next)
        {
            bool[] b = new bool[ctx.ParameterVariables.Length];

            for (var index = 0; index < ctx.ParameterVariables.Length; index++)
            {
                if (!(ctx.LoadTypes[index] is INamedTypeSymbol named))
                {
                    continue;
                }

                if (!named.IsGenericType)
                {
                    continue;
                }

                if (!SymbolEqualityComparer.Default.Equals(named.OriginalDefinition, ctx.Compilation.GetTypeByMetadataName("System.Span`1")))
                {
                    continue;
                }

                b[index] = true;
            }

            var oldParameterIds = ctx.ParameterVariables.ToArray();

            for (var index = 0; index < ctx.ParameterVariables.Length; index++)
            {
                // in this loop, update all types & expressions

                var shouldPin = b[index];
                if (!shouldPin)
                {
                    continue;
                }

                var loadType = ctx.LoadTypes[index];
                loadType             = ctx.Compilation.CreatePointerTypeSymbol((loadType as INamedTypeSymbol) !.TypeArguments[0]);
                ctx.LoadTypes[index] = loadType;

                var(id, name) = ctx.DeclareSpecialVariableNoInlining(loadType, false);
                ctx.SetParameterToVariable(index, id);
                var l   = ctx.LoadTypes[index].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                var old = ctx.ResolveVariable(oldParameterIds[index]);
                ctx.BeginBlock((x, ctx) => FixedStatement
                               (
                                   VariableDeclaration
                                   (
                                       IdentifierName(l),
                                       SingletonSeparatedList
                                           (VariableDeclarator(Identifier(name), null, EqualsValueClause(old.Value)))
                                   ), x
                               ));
            }

            next();
        }
예제 #3
0
        public static void DelegateMarshaller(ref IMarshalContext ctx, Action next)
        {
            for (var index = 0; index < ctx.ParameterVariables.Length; index++)
            {
                var options = ctx.ParameterMarshalOptions[index];

                if (ctx.LoadTypes[index].TypeKind != TypeKind.Delegate)
                {
                    continue;
                }

                ctx.LoadTypes[index] = ctx.Compilation.GetSpecialType(SpecialType.System_IntPtr);
                var id = ctx.DeclareVariable(ctx.LoadTypes[index]);
                var parameterVariable = ctx.ResolveVariable(ctx.ParameterVariables[index]);
                ctx.SetVariable
                (
                    id, ctx => ConditionalExpression
                    (
                        BinaryExpression
                        (
                            SyntaxKind.EqualsExpression, parameterVariable.Value,
                            LiteralExpression(SyntaxKind.NullLiteralExpression)
                        ),
                        MemberAccessExpression
                        (
                            SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nameof(IntPtr)),
                            IdentifierName(nameof(IntPtr.Zero))
                        ), InvocationExpression
                            ( // System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer<T>(ResultName)
                            MemberAccessExpression
                            (
                                SyntaxKind.SimpleMemberAccessExpression,
                                MemberAccessExpression
                                (
                                    SyntaxKind.SimpleMemberAccessExpression,
                                    MemberAccessExpression
                                    (
                                        SyntaxKind.SimpleMemberAccessExpression,
                                        MemberAccessExpression
                                        (
                                            SyntaxKind.SimpleMemberAccessExpression, IdentifierName("System"),
                                            IdentifierName("Runtime")
                                        ), IdentifierName("InteropServices")
                                    ), IdentifierName("Marshal")
                                ), IdentifierName("GetFunctionPointerForDelegate")
                            ), ArgumentList(SingletonSeparatedList(Argument(parameterVariable.Value)))
                            )
                    )
                );
                ctx.SetParameterToVariable(index, id);
            }

            int resultLocalId     = default;
            var processReturn     = ctx.ReturnLoadType.TypeKind == TypeKind.Delegate;
            var oldReturnLoadType = ctx.ReturnLoadType;

            if (processReturn)
            {
                resultLocalId      = ctx.DeclareVariable(ctx.ReturnLoadType);
                ctx.ReturnLoadType = ctx.Compilation.GetSpecialType(SpecialType.System_IntPtr);
            }

            next();

            if (processReturn)
            {
                var resultVariable = ctx.ResolveVariable(ctx.ResultVariable.Value);
                ctx.SetVariable
                (
                    resultLocalId, ctx => ConditionalExpression
                    (
                        BinaryExpression
                        (
                            SyntaxKind.EqualsExpression, resultVariable.Value,
                            MemberAccessExpression
                            (
                                SyntaxKind.SimpleMemberAccessExpression, IdentifierName("IntPtr"),
                                IdentifierName("Zero")
                            )
                        ), LiteralExpression(SyntaxKind.NullLiteralExpression), InvocationExpression
                            ( // System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer<T>(ResultName)
                            MemberAccessExpression
                            (
                                SyntaxKind.SimpleMemberAccessExpression,
                                MemberAccessExpression
                                (
                                    SyntaxKind.SimpleMemberAccessExpression,
                                    MemberAccessExpression
                                    (
                                        SyntaxKind.SimpleMemberAccessExpression,
                                        MemberAccessExpression
                                        (
                                            SyntaxKind.SimpleMemberAccessExpression, IdentifierName("System"),
                                            IdentifierName("Runtime")
                                        ), IdentifierName("InteropServices")
                                    ), IdentifierName("Marshal")
                                ),
                                GenericName
                                (
                                    Identifier("GetDelegateForFunctionPointer"),
                                    TypeArgumentList
                                    (
                                        SingletonSeparatedList
                                        (
                                            (TypeSyntax)IdentifierName
                                            (
                                                oldReturnLoadType.ToDisplayString
                                                    (SymbolDisplayFormat.FullyQualifiedFormat)
                                            )
                                        )
                                    )
                                )
                            ),
                            ArgumentList
                                (SingletonSeparatedList(Argument(resultVariable.Value)))
                            )
                    )
                );
                ctx.ResultVariable = resultLocalId;
            }
        }
예제 #4
0
        public static void PinObjectMarshaller(ref IMarshalContext ctx, Action next)
        {
            for (var index = 0; index < ctx.ParameterVariables.Length; index++)
            {
                if (!ctx.TryGetAttribute(index, "Silk.NET.Core.Native.PinObjectAttribute", out var data))
                {
                    continue;
                }

                var     gcSlot = ctx.AllocateGcSlot();
                PinMode pinMode;
                if (data.ConstructorArguments.Length < 1)
                {
                    pinMode = PinMode.Persist;
                }
                else
                {
                    pinMode = (PinMode)(data.ConstructorArguments[0].Value ?? PinMode.Persist);
                }

                var name = pinMode switch
                {
                    PinMode.Persist => "Pin",
                    PinMode.UntilNextCall => "PinUntilNextCall",
                    _ => throw new Exception()
                };

                var parameterVariable = ctx.ResolveVariable(ctx.ParameterVariables[index]);
                ctx.AddSideEffect
                (
                    ctx => ExpressionStatement
                    (
                        InvocationExpression
                        (
                            MemberAccessExpression
                                (SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName(name)),
                            ArgumentList
                            (
                                SeparatedList
                                (
                                    new[]
                {
                    Argument(parameterVariable.Value),
                    Argument
                        (LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(gcSlot)))
                }
                                )
                            )
                        )
                    )
                );
            }

            next();

            if (!ctx.ReturnsVoid && ctx.TryGetAttribute
                    (ctx.LoadTypes.Length - 1, "Silk.NET.Core.Native.PinObjectAttribute", out var resultData))
            {
                var gcSlot = ctx.AllocateGcSlot();

                PinMode pinMode;
                if (resultData.ConstructorArguments.Length < 1)
                {
                    pinMode = PinMode.Persist;
                }
                else
                {
                    pinMode = (PinMode)(resultData.ConstructorArguments[0].Value ?? PinMode.Persist);
                }

                var name = pinMode switch
                {
                    PinMode.Persist => "Pin",
                    PinMode.UntilNextCall => "PinUntilNextCall",
                    _ => throw new Exception()
                };

                var resultVariable = ctx.ResolveVariable(ctx.ResultVariable.Value);
                ctx.AddSideEffect
                (
                    ctx => ExpressionStatement
                    (
                        InvocationExpression
                        (
                            MemberAccessExpression
                                (SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName(name)),
                            ArgumentList
                            (
                                SeparatedList
                                (
                                    new[]
                {
                    Argument(resultVariable.Value),
                    Argument
                        (LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(gcSlot)))
                }
                                )
                            )
                        )
                    )
                );
            }
        }
    }
        public static void GenericPointerMarshaller(ref IMarshalContext ctx, Action next)
        {
            for (int i = 0; i < ctx.LoadTypes.Length - 1; i++)
            {
                var lt = ctx.LoadTypes[i];
                if (lt is IPointerTypeSymbol pts)
                {
                    if (pts.PointedAtType is ITypeParameterSymbol tps)
                    {
                        var id = ctx.DeclareVariable
                                 (
                            ctx.Compilation.CreatePointerTypeSymbol
                                (ctx.Compilation.GetSpecialType(SpecialType.System_Void))
                                 );
                        var baseId = ctx.ParameterVariables[i];
                        ctx.SetVariable(id, ctx => CastExpression(IdentifierName("void*"), ctx.ResolveVariable(baseId).Value));
                        ctx.SetParameterToVariable(i, id);
                    }
                }
            }

            next();
        }