Skip to content

Commit 1652dee

Browse files
mandel-macaqueGitHub Actions Autoformatter
andauthored
[RGen] Add factory method to generate the internal delegate for a trampoline. (#22813)
The delegate must use the name provided by the Nomenclator, have the first parameter as a IntPtr to the block and then all the other parameters from the delegate. The return type should be the same as the original parameter. --------- Co-authored-by: GitHub Actions Autoformatter <[email protected]>
1 parent 30ebb25 commit 1652dee

File tree

5 files changed

+475
-41
lines changed

5 files changed

+475
-41
lines changed

src/rgen/Microsoft.Macios.Generator/Emitters/BindingSyntaxFactory.Trampoline.cs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,91 @@ internal static ParameterSyntax GetTrampolineInvokeParameter (string trampolineN
161161
.NormalizeWhitespace ();
162162
}
163163

164+
/// <summary>
165+
///
166+
/// </summary>
167+
/// <param name="typeInfo"></param>
168+
/// <returns></returns>
169+
internal static TypeSyntax GetLowLevelType (in TypeInfo typeInfo)
170+
{
171+
#pragma warning disable format
172+
return typeInfo switch {
173+
// pointer parameter
174+
{ IsPointer: true } => typeInfo.GetIdentifierSyntax (),
175+
176+
// delegate parameter is a NativeHandle
177+
{ IsDelegate: true } => IntPtr,
178+
179+
// native enum, return the conversion expression to the native type
180+
{ IsNativeEnum: true} => IdentifierName(typeInfo.EnumUnderlyingType!.Value.GetKeyword ()),
181+
182+
// boolean, convert it to byte
183+
{ SpecialType: SpecialType.System_Boolean } => PredefinedType (Token(SyntaxKind.ByteKeyword)),
184+
185+
{ IsArray: true } => NativeHandle,
186+
187+
{ SpecialType: SpecialType.System_String } => NativeHandle,
188+
189+
{ IsProtocol: true } => NativeHandle,
190+
191+
// special types
192+
193+
// CoreMedia.CMSampleBuffer
194+
{ FullyQualifiedName: "CoreMedia.CMSampleBuffer" } => NativeHandle,
195+
196+
// AudioToolbox.AudioBuffers
197+
{ FullyQualifiedName: "AudioToolbox.AudioBuffers" } => NativeHandle,
198+
199+
// general NSObject/INativeObject, has to be after the special types otherwise the special types will
200+
// fall into the NSObject/INativeObject case
201+
202+
// same name, native handle
203+
{ IsNSObject: true } => NativeHandle,
204+
205+
// same name, native handle
206+
{ IsINativeObject: true } => NativeHandle,
207+
208+
// by default, we will use the parameter name as is and the type of the parameter
209+
_ => typeInfo.GetIdentifierSyntax (),
210+
};
211+
#pragma warning restore format
212+
}
213+
214+
/// <summary>
215+
/// Returns the needed data to build the parameter syntax for the native trampoline delegate.
216+
/// </summary>
217+
/// <param name="parameter">The parameter we want to generate for the lower invoke method.</param>
218+
/// <returns>The parameter syntax needed for the parameter.</returns>
219+
internal static ParameterSyntax GetTrampolineInvokeParameter (in DelegateParameter parameter)
220+
{
221+
// in the general case we will return the low level type conversion of the parameter type but we
222+
// need to handle in a special case those parameters that are passed by reference
223+
var parameterIdentifier = Identifier (parameter.Name);
224+
#pragma warning disable format
225+
(SyntaxToken ParameterName, TypeSyntax ParameterType) parameterInfo = parameter switch {
226+
// parameters that are passed by reference, depend on the type that is referenced
227+
{ IsByRef: true, Type.IsReferenceType: false, Type.IsNullable: true}
228+
=> (parameterIdentifier,
229+
PointerType (IdentifierName (parameter.Type.FullyQualifiedName))),
230+
231+
{ IsByRef: true, Type.SpecialType: SpecialType.System_Boolean}
232+
=> (parameterIdentifier,
233+
PointerType (PredefinedType (Token(SyntaxKind.ByteKeyword)))),
234+
235+
{ IsByRef: true, Type.IsReferenceType: true, Type.IsNullable: false}
236+
=> (parameterIdentifier,
237+
PointerType (NativeHandle)),
238+
239+
// by default, we will use the parameter name as is and the type of the parameter
240+
_ => (parameterIdentifier, GetLowLevelType (parameter.Type)),
241+
};
242+
#pragma warning restore format
243+
244+
return Parameter (parameterInfo.ParameterName)
245+
.WithType (parameterInfo.ParameterType)
246+
.NormalizeWhitespace ();
247+
}
248+
164249
/// <summary>
165250
/// Returns the argument syntax of a parameter to be used for the trampoliner to invoke a delegate.
166251
/// </summary>
@@ -533,4 +618,43 @@ internal static StatementSyntax CallTrampolineDelegate (in DelegateInfo delegate
533618
EqualsValueClause (invocation.WithLeadingTrivia (Space)).WithLeadingTrivia (Space))));
534619
return LocalDeclarationStatement (declaration);
535620
}
621+
622+
/// <summary>
623+
/// Return the delegate declaration for the trampoline delegate. The trampoline delegate is a delegate that
624+
/// takes as a first parameter a IntPtr that represents the block to be called. The rest of the parameters are
625+
/// the same as the original delegate.
626+
/// </summary>
627+
/// <param name="delegateTypeInfo">The delegate type information.</param>
628+
/// <param name="delegateName">The name of the delegate generated.</param>
629+
/// <returns>The syntax of the delegate.</returns>
630+
internal static SyntaxNode GetTrampolineDelegateDeclaration (in TypeInfo delegateTypeInfo, out string delegateName)
631+
{
632+
// generate a new delegate type with the addition of the IntPtr parameter for block
633+
var modifiers = TokenList (Token (SyntaxKind.UnsafeKeyword), Token (SyntaxKind.InternalKeyword));
634+
delegateName = Nomenclator.GetTrampolineClassName (delegateTypeInfo.Name, Nomenclator.TrampolineClassType.DelegateType);
635+
636+
// build the arguments for the delegate, but add a IntPtr parameter at the start of the list
637+
var parameterBucket = ImmutableArray.CreateBuilder<ParameterSyntax> (delegateTypeInfo.Delegate!.Parameters.Length + 1);
638+
// block parameter needed for the trampoline
639+
parameterBucket.Add (
640+
Parameter (Identifier (Nomenclator.GetTrampolineBlockParameterName ()))
641+
.WithType (IntPtr));
642+
// calculate the rest of the parameters
643+
foreach (var parameterInfo in delegateTypeInfo.Delegate!.Parameters) {
644+
// build the parameter
645+
parameterBucket.Add (GetTrampolineInvokeParameter (parameterInfo));
646+
}
647+
648+
var parametersSyntax = ParameterList (
649+
SeparatedList<ParameterSyntax> (
650+
parameterBucket.ToImmutableArray ().ToSyntaxNodeOrTokenArray ())).NormalizeWhitespace ();
651+
// delegate declaration
652+
var declaration = DelegateDeclaration (
653+
GetLowLevelType (delegateTypeInfo.Delegate!.ReturnType), // return the low level type, not the manged version
654+
Identifier (delegateName))
655+
.WithModifiers (modifiers).NormalizeWhitespace ()
656+
.WithParameterList (parametersSyntax.WithLeadingTrivia (Space));
657+
658+
return declaration;
659+
}
536660
}

src/rgen/Microsoft.Macios.Generator/Extensions/ArgumentSyntaxExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Microsoft.Macios.Generator.Extensions;
1111

1212
static class ArgumentSyntaxExtensions {
1313

14-
public static SyntaxNodeOrToken [] ToSyntaxNodeOrTokenArray (this ImmutableArray<ArgumentSyntax> arguments)
14+
public static SyntaxNodeOrToken [] ToSyntaxNodeOrTokenArray<T> (this ImmutableArray<T> arguments) where T : CSharpSyntaxNode
1515
{
1616
// the size of the array is simple to calculate, we need space for all parameters
1717
// and for a comma for each parameter except for the last one

src/rgen/Microsoft.Macios.Generator/Formatters/ParameterFormatter.cs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.Macios.Generator.DataModel;
88
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
99
using ParameterDataModel = Microsoft.Macios.Generator.DataModel.Parameter;
10+
using TypeInfo = Microsoft.Macios.Generator.DataModel.TypeInfo;
1011

1112
namespace Microsoft.Macios.Generator.Formatters;
1213

@@ -35,24 +36,6 @@ public static ParameterListSyntax GetParameterList (this in ImmutableArray<Param
3536

3637
return ParameterList (SeparatedList<ParameterSyntax> (nodes)).NormalizeWhitespace ();
3738
}
38-
static TypeSyntax GetIdentifierSyntax (this in ParameterDataModel parameter)
39-
{
40-
if (parameter.Type.IsArray) {
41-
// could be a params array or simply an array
42-
var arrayType = ArrayType (IdentifierName (parameter.Type.FullyQualifiedName))
43-
.WithRankSpecifiers (SingletonList (
44-
ArrayRankSpecifier (
45-
SingletonSeparatedList<ExpressionSyntax> (OmittedArraySizeExpression ()))));
46-
return parameter.Type.IsNullable
47-
? NullableType (arrayType)
48-
: arrayType;
49-
}
50-
51-
// dealing with a non-array type
52-
return parameter.Type.IsNullable
53-
? NullableType (IdentifierName (parameter.Type.FullyQualifiedName))
54-
: IdentifierName (parameter.Type.FullyQualifiedName);
55-
}
5639

5740
public static ParameterSyntax ToDeclaration (this in ParameterDataModel parameter)
5841
{
@@ -89,7 +72,7 @@ public static ParameterSyntax ToDeclaration (this in ParameterDataModel paramete
8972
// }
9073
var syntax = Parameter (Identifier (parameter.Name))
9174
.WithModifiers (modifiers)
92-
.WithType (parameter.GetIdentifierSyntax ());
75+
.WithType (parameter.Type.GetIdentifierSyntax ());
9376

9477
return syntax.NormalizeWhitespace ();
9578
}

src/rgen/Microsoft.Macios.Generator/Nomenclator.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,11 @@ public static string GetTrampolineClassName (string trampolineName, TrampolineCl
166166
/// </summary>
167167
/// <returns>The name of the variable used to store delegates in trampolines.</returns>
168168
public static string GetTrampolineDelegateVariableName () => "del";
169+
170+
/// <summary>
171+
/// Return the name of the trampoline block parameter. This is the name of the parameter that will be containing the
172+
/// IntPtr to the trampoline block.
173+
/// </summary>
174+
/// <returns>The name to be used in the delegate.</returns>
175+
public static string GetTrampolineBlockParameterName () => "block";
169176
}

0 commit comments

Comments
 (0)