예제 #1
0
        private static void ProcessMethod
        (
            GeneratorExecutionContext sourceContext,
            MarshalBuilder rootMarshalBuilder,
            CallingConvention callingConvention,
            Dictionary <int, string> entryPoints,
            string entryPoint,
            bool classIsSealed,
            bool generateSeal,
            bool generateVTable,
            int slot,
            Compilation compilation,
            IMethodSymbol symbol,
            MethodDeclarationSyntax declaration,
            List <MemberDeclarationSyntax> newMembers,
            ref int gcCount,
            List <EntryPoint> processedEntrypoints,
            string generatedVTableName
        )
        {
            void BuildLoadInvoke(ref IMarshalContext ctx, Action next)
            {
                ctx.TransitionTo(SilkTouchStage.PreLoad);

                // this is terminal, we never call next

                var parameters = ctx.ResolveAllLoadParameters();

                var fPtrType = FunctionPointerType
                               (
                    FunctionPointerCallingConvention
                    (
                        Token(SyntaxKind.UnmanagedKeyword),
                        FunctionPointerUnmanagedCallingConventionList
                        (
                            SingletonSeparatedList
                            (
                                FunctionPointerUnmanagedCallingConvention
                                    (Identifier(GetCallingConvention(callingConvention)))
                            )
                        )
                    ),
                    FunctionPointerParameterList
                    (
                        SeparatedList
                        (
                            ctx.LoadTypes.Select
                            (
                                x => FunctionPointerParameter
                                    (IdentifierName(x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)))
                            )
                        )
                    )
                               );

                entryPoints[ctx.Slot] = entryPoint;
                processedEntrypoints.Add
                (
                    new EntryPoint
                    (
                        entryPoint, ctx.Slot, callingConvention,
                        ctx.LoadTypes.Select
                        (
                            x => (TypeSyntax)IdentifierName
                                (x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
                        )
                        .ToArray(),
                        symbol
                    )
                );

                ExpressionSyntax loadCallTarget;

                if ((classIsSealed || generateSeal) && generateVTable)
                {
                    loadCallTarget = MemberAccessExpression
                                     (
                        SyntaxKind.SimpleMemberAccessExpression,
                        ParenthesizedExpression
                        (
                            BinaryExpression
                            (
                                SyntaxKind.AsExpression, IdentifierName("CurrentVTable"), IdentifierName(generatedVTableName)
                            )
                        ), IdentifierName("Load")
                                     );
                }
                else
                {
                    loadCallTarget = IdentifierName("Load");
                }

                // build load + invocation
                Func <IMarshalContext, ExpressionSyntax> expression = ctx => InvocationExpression
                                                                      (
                    ParenthesizedExpression
                    (
                        CastExpression
                        (
                            fPtrType, InvocationExpression
                            (
                                loadCallTarget, ArgumentList
                                (
                                    SeparatedList
                                    (
                                        new[]
                {
                    Argument
                        (LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(ctx.Slot))),
                    Argument
                        (LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(entryPoint)))
                }
                                    )
                                )
                            )
                        )
                    ), ArgumentList(SeparatedList(parameters.Select(x => Argument(x.Value))))
                                                                      );

                if (ctx.ReturnsVoid)
                {
                    var exp = expression(ctx); // this forces evaluation of everything until this point.
                    ctx.AddSideEffect(ctx => ExpressionStatement(exp));
                    ctx.ResultVariable = null;
                }
                else
                {
                    var id = ctx.DeclareVariable(ctx.ReturnLoadType, false);
                    ctx.ResultVariable = id;
                    ctx.SetVariable(id, expression);
                    _ = ctx.ResolveVariable(id).Value; // force evaluation of ret
                }

                ctx.CurrentResultType = ctx.ReturnLoadType;
                ctx.TransitionTo(SilkTouchStage.PostLoad);
            }

            try
            {
                var marshalBuilder = rootMarshalBuilder.Clone();

                marshalBuilder.Use(BuildLoadInvoke);

                var context = new MarshalContext(compilation, symbol, slot);

                marshalBuilder.Run(context);

                var block = context.BuildFinalBlock();

                gcCount += context.GCCount;

                if (declaration.Modifiers.All(x => x.Text != "unsafe"))
                {
                    // this is not done as a middleware to allow middleware to prepend any variable declaration, even if it's unsafe
                    block = Block(UnsafeStatement(Token(SyntaxKind.UnsafeKeyword), block));
                }

                var method = declaration.WithBody
                                 (block)
                             .WithAttributeLists(default)