Skip to content

Commit 2ad8a0e

Browse files
mandel-macaqueCopilotGitHub Actions Autoformatter
authored
[RGen] Remove all the Nullable<TypeInfo> boxing that happens in the generator (#23428)
This reduces the number of boxed structs in the generator which will reduce the use of the heap and move all the instances of the struct to have no heap references. --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: GitHub Actions Autoformatter <[email protected]>
1 parent ba23fc7 commit 2ad8a0e

File tree

11 files changed

+93
-43
lines changed

11 files changed

+93
-43
lines changed

src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
<Compile Include="../Microsoft.Macios.Generator/Attributes/UnsupportedOSPlatformData.cs" >
7373
<Link>Generator/Attributes/UnsupportedOSPlatformData.cs</Link>
7474
</Compile>
75+
<Compile Include="../Microsoft.Macios.Generator/DataModel/StructState.cs" >
76+
<Link>DataModel/StructState.cs</Link>
77+
</Compile>
7578
<Compile Include="../Microsoft.Macios.Generator/DataModel/AttributeCodeChange.cs" >
7679
<Link>DataModel/AttributeCodeChange.cs</Link>
7780
</Compile>

src/rgen/Microsoft.Macios.Generator/Attributes/BindFromData.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ namespace Microsoft.Macios.Generator.Attributes;
1111
readonly struct BindFromData : IEquatable<BindFromData> {
1212

1313
public TypeInfo Type { get; }
14-
public TypeInfo? OriginalType { get; }
14+
public TypeInfo OriginalType { get; } = TypeInfo.Default;
1515

1616
public BindFromData (TypeInfo type)
1717
{
1818
Type = type;
1919
}
2020

21-
public BindFromData (TypeInfo type, TypeInfo? originalType)
21+
public BindFromData (TypeInfo type, TypeInfo originalType)
2222
{
2323
Type = type;
2424
OriginalType = originalType;
@@ -31,7 +31,7 @@ public static bool TryParse (AttributeData attributeData,
3131
data = null;
3232
var count = attributeData.ConstructorArguments.Length;
3333
TypeInfo type;
34-
TypeInfo? originalType = null;
34+
TypeInfo originalType = TypeInfo.Default;
3535

3636
switch (count) {
3737
case 1:
@@ -68,7 +68,7 @@ public static bool TryParse (AttributeData attributeData,
6868
public bool Equals (BindFromData other)
6969
{
7070
return Type.FullyQualifiedName == other.Type.FullyQualifiedName
71-
&& OriginalType?.FullyQualifiedName == other.OriginalType?.FullyQualifiedName;
71+
&& OriginalType.FullyQualifiedName == other.OriginalType.FullyQualifiedName;
7272
}
7373

7474
/// <inheritdoc />
@@ -95,6 +95,7 @@ public override int GetHashCode ()
9595

9696
public override string ToString ()
9797
{
98-
return $"{{ Type: '{Type.FullyQualifiedName}', OriginalType: '{OriginalType?.FullyQualifiedName ?? "null"}' }}";
98+
var originalType = OriginalType.IsNullOrDefault ? "null" : OriginalType.FullyQualifiedName;
99+
return $"{{ Type: '{Type.FullyQualifiedName}', OriginalType: '{originalType}' }}";
99100
}
100101
}

src/rgen/Microsoft.Macios.Generator/Attributes/BindingTypeData.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public override string ToString ()
152152
/// <summary>
153153
/// The type that the category extends.
154154
/// </summary>
155-
public TypeInfo? CategoryType { get; init; } = null;
155+
public TypeInfo CategoryType { get; init; } = TypeInfo.Default;
156156

157157
/// <summary>
158158
/// Initializes a new instance of the <see cref="BindingTypeData{T}"/> struct.
@@ -188,9 +188,9 @@ public BindingTypeData (string? name, T? flags)
188188
/// Initializes a new instance of the <see cref="BindingTypeData"/> struct for a category.
189189
/// </summary>
190190
/// <param name="categoryType">The type that the category extends.</param>
191-
public BindingTypeData (TypeInfo? categoryType)
191+
public BindingTypeData (TypeInfo categoryType)
192192
{
193-
Name = categoryType?.Name;
193+
Name = categoryType.IsNullOrDefault ? null : categoryType.Name;
194194
CategoryType = categoryType;
195195
}
196196

@@ -199,9 +199,9 @@ public BindingTypeData (TypeInfo? categoryType)
199199
/// </summary>
200200
/// <param name="categoryType">The type that the category extends.</param>
201201
/// <param name="flags">The configuration flags.</param>
202-
public BindingTypeData (TypeInfo? categoryType, T? flags)
202+
public BindingTypeData (TypeInfo categoryType, T? flags)
203203
{
204-
Name = categoryType?.Name;
204+
Name = categoryType.IsNullOrDefault ? null : categoryType.Name;
205205
CategoryType = categoryType;
206206
Flags = flags;
207207
}
@@ -220,7 +220,7 @@ public static bool TryParse (AttributeData attributeData,
220220
string? name = null;
221221
T? flags = default;
222222
// category related data
223-
TypeInfo? categoryType = null;
223+
TypeInfo categoryType = TypeInfo.Default;
224224

225225
// check if we have a category type, we can do that by checking the type of the flag
226226
var isCategory = typeof (T) == typeof (ObjCBindings.Category);
@@ -235,7 +235,7 @@ public static bool TryParse (AttributeData attributeData,
235235
var value = attributeData.ConstructorArguments [0].Value;
236236
if (isCategory && value is INamedTypeSymbol typeSymbol) {
237237
categoryType = new (typeSymbol);
238-
name = categoryType.Value.Name;
238+
name = categoryType.Name;
239239
} else if (!isCategory && value is string str) {
240240
name = str;
241241
} else if (value is not null) {
@@ -245,7 +245,7 @@ public static bool TryParse (AttributeData attributeData,
245245
case 2:
246246
if (isCategory) {
247247
categoryType = new ((INamedTypeSymbol) attributeData.ConstructorArguments [0].Value!);
248-
name = categoryType.Value.Name;
248+
name = categoryType.Name;
249249
} else {
250250
// we have the name and the config flags present
251251
name = (string?) attributeData.ConstructorArguments [0].Value!;
@@ -317,7 +317,7 @@ static BindingTypeData<T> CreateClassBindingData (T? flags, string? name, string
317317
/// <param name="flags">The configuration flags.</param>
318318
/// <param name="categoryType">The type that the category extends.</param>
319319
/// <returns>A new instance of <see cref="BindingTypeData{T}"/>.</returns>
320-
static BindingTypeData<T> CreateCategoryBindingData (T? flags, TypeInfo? categoryType)
320+
static BindingTypeData<T> CreateCategoryBindingData (T? flags, TypeInfo categoryType)
321321
{
322322
return flags is not null
323323
? new (categoryType, flags)
@@ -387,10 +387,10 @@ static bool TryExtractClassNamedParameters (AttributeData attributeData,
387387
/// <param name="flags">The configuration flags.</param>
388388
/// <param name="categoryType">The type that the category extends.</param>
389389
/// <returns>True if the data was parsed.</returns>
390-
static bool TryExtractCategoryNamedParameters (AttributeData attributeData, out string? name, ref T? flags, out TypeInfo? categoryType)
390+
static bool TryExtractCategoryNamedParameters (AttributeData attributeData, out string? name, ref T? flags, out TypeInfo categoryType)
391391
{
392392
name = null;
393-
categoryType = null;
393+
categoryType = TypeInfo.Default;
394394
foreach (var (paramName, value) in attributeData.NamedArguments) {
395395
switch (paramName) {
396396
case "Name":
@@ -460,6 +460,7 @@ public override int GetHashCode ()
460460
/// <inheritdoc />
461461
public override string ToString ()
462462
{
463-
return $"{{ Name: '{Name}', CategoryType: '{CategoryType?.ToString () ?? "null"}', Flags: '{Flags}' }}";
463+
var category = CategoryType.IsNullOrDefault ? "null" : CategoryType.FullyQualifiedName;
464+
return $"{{ Name: '{Name}', CategoryType: '{category}', Flags: '{Flags}' }}";
464465
}
465466
}

src/rgen/Microsoft.Macios.Generator/Attributes/ExportData.cs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ namespace Microsoft.Macios.Generator.Attributes;
5858
/// <summary>
5959
/// The type of the result for an async method.
6060
/// </summary>
61-
public TypeInfo? ResultType { get; init; }
61+
public TypeInfo ResultType { get; init; } = TypeInfo.Default;
6262

6363
/// <summary>
6464
/// The name of the generated async method.
@@ -78,7 +78,7 @@ namespace Microsoft.Macios.Generator.Attributes;
7878
/// <summary>
7979
/// The type of the strong delegate for a weak delegate property.
8080
/// </summary>
81-
public TypeInfo? StrongDelegateType { get; init; }
81+
public TypeInfo StrongDelegateType { get; init; } = TypeInfo.Default;
8282

8383
/// <summary>
8484
/// The name of the strong delegate for a weak delegate property.
@@ -88,7 +88,7 @@ namespace Microsoft.Macios.Generator.Attributes;
8888
/// <summary>
8989
/// The type of the dictionary key class for strong dictionary properties.
9090
/// </summary>
91-
public TypeInfo? StrongDictionaryKeyClass { get; init; }
91+
public TypeInfo StrongDictionaryKeyClass { get; init; } = TypeInfo.Default;
9292

9393
public ExportData () { }
9494

@@ -130,15 +130,15 @@ public static bool TryParse (AttributeData attributeData,
130130
string? nativeSuffix = null;
131131
string? library = null;
132132
// async related data
133-
TypeInfo? resultType = null;
133+
TypeInfo resultType = TypeInfo.Default;
134134
string? methodName = null;
135135
string? resultTypeName = null;
136136
string? postNonResultSnippet = null;
137137
// weak delegate related data
138-
TypeInfo? strongDelegateType = null;
138+
TypeInfo strongDelegateType = TypeInfo.Default;
139139
string? strongDelegateName = null;
140140
// strong dictionary related data
141-
TypeInfo? strongDictionaryKeyClass = null;
141+
TypeInfo strongDictionaryKeyClass = TypeInfo.Default;
142142

143143
switch (count) {
144144
case 1:
@@ -257,15 +257,15 @@ public static bool TryParse (AttributeData attributeData,
257257
NativeSuffix = nativeSuffix,
258258
Library = library,
259259
// set the data for async methods only if the flags are set
260-
ResultType = isAsync ? resultType : null,
260+
ResultType = isAsync ? resultType : TypeInfo.Default,
261261
MethodName = isAsync ? methodName : null,
262262
ResultTypeName = isAsync ? resultTypeName : null,
263263
PostNonResultSnippet = isAsync ? postNonResultSnippet : null,
264264
// we set the data for the weak delegate only if the flags are set
265-
StrongDelegateType = isWeakDelegate ? strongDelegateType : null,
265+
StrongDelegateType = isWeakDelegate ? strongDelegateType : TypeInfo.Default,
266266
StrongDelegateName = isWeakDelegate ? strongDelegateName : null,
267267
// we set the data for the strong dictionary only if the flags are set
268-
StrongDictionaryKeyClass = isStrongDictionaryProperty ? strongDictionaryKeyClass : null,
268+
StrongDictionaryKeyClass = isStrongDictionaryProperty ? strongDictionaryKeyClass : TypeInfo.Default,
269269
};
270270
return true;
271271
}
@@ -334,6 +334,10 @@ public override int GetHashCode ()
334334
/// <inheritdoc />
335335
public override string ToString ()
336336
{
337+
var resultTypeName = ResultType.IsNullOrDefault ? "null" : ResultType.FullyQualifiedName;
338+
var strongDelegateTypeName = StrongDelegateType.IsNullOrDefault ? "null" : StrongDelegateType.FullyQualifiedName;
339+
var strongDictionaryKeyClassName = StrongDictionaryKeyClass.IsNullOrDefault ? "null" : StrongDictionaryKeyClass.FullyQualifiedName;
340+
337341
var sb = new StringBuilder ("{ Type: '");
338342
sb.Append (typeof (T).FullName);
339343
sb.Append ("', Selector: '");
@@ -349,17 +353,17 @@ public override string ToString ()
349353
sb.Append ("', Library: '");
350354
sb.Append (Library ?? "null");
351355
sb.Append ("', ResultType: '");
352-
sb.Append (ResultType?.FullyQualifiedName ?? "null");
356+
sb.Append (resultTypeName);
353357
sb.Append ("', MethodName: '");
354358
sb.Append (MethodName ?? "null");
355359
sb.Append ("', ResultTypeName: '");
356360
sb.Append (ResultTypeName ?? "null");
357361
sb.Append ("', PostNonResultSnippet: '");
358362
sb.Append (PostNonResultSnippet ?? "null");
359363
sb.Append ("', StrongDelegateType: '");
360-
sb.Append (StrongDelegateType?.FullyQualifiedName ?? "null");
364+
sb.Append (strongDelegateTypeName);
361365
sb.Append ("', StrongDictionaryKeysClass: '");
362-
sb.Append (StrongDictionaryKeyClass?.FullyQualifiedName ?? "null");
366+
sb.Append (strongDictionaryKeyClassName);
363367
sb.Append ("' }");
364368
return sb.ToString ();
365369
}

src/rgen/Microsoft.Macios.Generator/DataModel/Method.Generator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ public Method ToAsync ()
168168
var resultType = Parameters [^1].Type.ToTask ();
169169

170170
// if the user provided a result type, we need to update the calculated result type to a task
171-
if (ExportMethodData.ResultType is not null) {
172-
resultType = resultType.ToTask (ExportMethodData.ResultType.Value.GetIdentifierSyntax ().ToString ());
171+
if (!ExportMethodData.ResultType.IsNullOrDefault) {
172+
resultType = resultType.ToTask (ExportMethodData.ResultType.GetIdentifierSyntax ().ToString ());
173173
}
174174

175175
if (ExportMethodData.ResultTypeName is not null) {

src/rgen/Microsoft.Macios.Generator/DataModel/Property.Generator.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ public string? StrongDictionaryKey {
6666
if (!IsStrongDictionaryProperty)
6767
return null;
6868
// return the combination of the class key and the field name
69-
return ExportStrongPropertyData.Value.StrongDictionaryKeyClass is null
69+
return ExportStrongPropertyData.Value.StrongDictionaryKeyClass.IsNullOrDefault
7070
? ExportStrongPropertyData.Value.Selector
71-
: $"{ExportStrongPropertyData.Value.StrongDictionaryKeyClass.Value.FullyQualifiedName}.{ExportStrongPropertyData.Value.Selector}";
71+
: $"{ExportStrongPropertyData.Value.StrongDictionaryKeyClass.FullyQualifiedName}.{ExportStrongPropertyData.Value.Selector}";
7272
}
7373
}
7474

@@ -306,13 +306,13 @@ public bool Equals (Property other)
306306
public Property ToStrongDelegate ()
307307
{
308308
// has to be a property, weak delegate and have its strong delegate type set
309-
if (!IsProperty || !IsWeakDelegate || ExportPropertyData.Value.StrongDelegateType is null)
309+
if (!IsProperty || !IsWeakDelegate || ExportPropertyData.Value.StrongDelegateType.IsNullOrDefault)
310310
return this;
311311

312312
// update the return type, all the rest is the same
313313
return this with {
314314
Name = ExportPropertyData.Value.StrongDelegateName ?? Name.Remove (0, 4 /* "Weak".Length */),
315-
ReturnType = ExportPropertyData.Value.StrongDelegateType.Value.WithNullable (true),
315+
ReturnType = ExportPropertyData.Value.StrongDelegateType.WithNullable (true),
316316
};
317317
}
318318

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.Macios.Generator.DataModel;
5+
6+
/// <summary>
7+
/// Represents the initialization state of a struct.
8+
/// </summary>
9+
public enum StructState {
10+
/// <summary>
11+
/// The struct is in its default, uninitialized state.
12+
/// </summary>
13+
Default,
14+
/// <summary>
15+
/// The struct has been initialized.
16+
/// </summary>
17+
Initialized,
18+
}

src/rgen/Microsoft.Macios.Generator/DataModel/TypeInfo.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ namespace Microsoft.Macios.Generator.DataModel;
2929
/// </summary>
3030
public static TypeInfo NativeHandle = new ("System.NativeHandle", SpecialType.System_IntPtr) { Parents = ["System.ValueType", "object"], };
3131

32+
/// <summary>
33+
/// The initialization state of the struct.
34+
/// </summary>
35+
StructState State { get; init; } = StructState.Default;
36+
37+
/// <summary>
38+
/// Gets the default, uninitialized instance of <see cref="TypeInfo"/>.
39+
/// </summary>
40+
public static TypeInfo Default { get; } =
41+
new (string.Empty, SpecialType.None) { State = StructState.Default };
42+
43+
/// <summary>
44+
/// Gets a value indicating whether the instance is the default, uninitialized instance.
45+
/// </summary>
46+
public bool IsNullOrDefault => State == StructState.Default;
47+
3248
/// <summary>
3349
/// The fully qualified name of the type.
3450
/// </summary>
@@ -245,13 +261,17 @@ public ImmutableArray<string> Interfaces {
245261
init => interfaces = value;
246262
}
247263

248-
249264
/// <summary>
250265
/// The type arguments of the generic type.
251266
/// </summary>
252267
public ImmutableArray<string> TypeArguments { get; init; } = [];
253268

254-
internal TypeInfo (string name, SpecialType specialType)
269+
internal TypeInfo (StructState state)
270+
{
271+
State = state;
272+
}
273+
274+
internal TypeInfo (string name, SpecialType specialType) : this (StructState.Initialized)
255275
{
256276
FullyQualifiedName = name;
257277
SpecialType = specialType;
@@ -343,7 +363,7 @@ static ImmutableArray<string> GetNamespaceComponents (ITypeSymbol symbol)
343363
return components.ToImmutableArray ();
344364
}
345365

346-
internal TypeInfo (ITypeSymbol symbol)
366+
internal TypeInfo (ITypeSymbol symbol) : this (StructState.Initialized)
347367
{
348368
// general case, get the name and namespace. If we are dealing with a generic type or an array type
349369
// the name will be later overwritten with the generic name or the array name
@@ -444,6 +464,8 @@ internal TypeInfo (ITypeSymbol symbol)
444464
/// <inheritdoc/>
445465
public bool Equals (TypeInfo other)
446466
{
467+
if (State == StructState.Default && other.State == StructState.Default)
468+
return true;
447469
if (FullyQualifiedName != other.FullyQualifiedName)
448470
return false;
449471
if (SpecialType != other.SpecialType)
@@ -767,6 +789,7 @@ public TypeInfo ToTaskCompletionSource ()
767789
public override string ToString ()
768790
{
769791
var sb = new StringBuilder ("{");
792+
sb.Append ($"StructState: '{State}', ");
770793
sb.Append ($"Name: '{FullyQualifiedName}', ");
771794
sb.Append ($"MetadataName: '{MetadataName}', ");
772795
sb.Append ($"SpecialType: '{SpecialType}', ");

src/rgen/Microsoft.Macios.Generator/Emitters/CategoryEmitter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ public bool TryEmit (in BindingContext bindingContext, [NotNullWhen (false)] out
4545
}
4646

4747
var bindingData = (BindingTypeData<Category>) bindingContext.Changes.BindingInfo;
48-
if (bindingData.CategoryType is null) {
48+
if (bindingData.CategoryType.IsNullOrDefault) {
4949
diagnostics = [Diagnostic.Create (
5050
Diagnostics
5151
.RBI0000, // An unexpected error occurred while processing '{0}'. Please fill a bug report at https://github.com/dotnet/macios/issues/new.
5252
null,
5353
bindingContext.Changes.FullyQualifiedSymbol)];
5454
return false;
5555
}
56-
var registrationName = bindingData.CategoryType.Value.Name;
56+
var registrationName = bindingData.CategoryType.Name;
5757

5858
// namespace declaration
5959
this.EmitNamespace (bindingContext);

src/rgen/Microsoft.Macios.Generator/Emitters/ClassEmitter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ void EmitProperties (in BindingContext context, TabbedWriter<StringWriter> class
248248
// if the property is a weak delegate and has the strong delegate type set, we need to emit the
249249
// strong delegate property
250250
if (property is { IsProperty: true, IsWeakDelegate: true }
251-
&& property.ExportPropertyData.Value.StrongDelegateType is not null) {
251+
&& !property.ExportPropertyData.Value.StrongDelegateType.IsNullOrDefault) {
252252
classBlock.WriteLine ();
253253
var strongDelegate = property.ToStrongDelegate ();
254254
using (var propertyBlock =

0 commit comments

Comments
 (0)