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; } }
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(); }
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; } }
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(); }