Skip to content

Commit 1366d99

Browse files
[Java.Interop.Tools.JavaCallableWrappers] use less System.Linq for CAs (#1072)
Context: https://github.com/microsoft/dotnet-podcasts/tree/net8.0 When building the .NET Podcast sample for .NET 8, profiling an incremental build with a `.xaml` change I noticed: 80.42ms java.interop.tools.javacallablewrappers!Java.Interop.Tools.TypeNameMappings.JavaNativeTypeManager.IsNonStaticInnerClass(... There was a double-nested usage of System.Linq via a `GetBaseConstructors()` method, so I "unrolled" this to a plain `foreach` loop. After this change: 61.50ms java.interop.tools.javacallablewrappers!Java.Interop.Tools.TypeNameMappings.JavaNativeTypeManager.IsNonStaticInnerClass(... This made me review places using System.Linq `.Any()` calls: 59.78ms System.Linq.il!System.Linq.Enumerable.Any(class System.Collections.Generic.IEnumerable`1<!!0>) 15.87ms System.Linq.il!System.Linq.Enumerable.Any(class System.Collections.Generic.IEnumerable`1<!!0>,class System.Func`2<!!0,bool>) 1.98ms system.linq.il!System.Linq.Enumerable.Any(class System.Collections.Generic.IEnumerable`1<!!0>) Which I was able to track down to calls to an extension method like: CustomAttributeProviderRocks.GetCustomAttributes().Any() I created a new `CustomAttributeProviderRocks.AnyCustomAttributes()` extension method, which is a bit better because: * We avoid a `yield return` & related compiler machinery. * We avoid allocating custom attribute objects in some cases, as System.Linq's `.Any()` will enumerate and create at least one. Before: 107.90ms java.interop.tools.cecil!Java.Interop.Tools.Cecil.CustomAttributeProviderRocks+<GetCustomAttributes>d__1.MoveNext() 3.80ms java.interop.tools.cecil!Java.Interop.Tools.Cecil.CustomAttributeProviderRocks.GetCustomAttributes(class Mono.Cecil.ICus... After: 58.58ms java.interop.tools.cecil!Java.Interop.Tools.Cecil.CustomAttributeProviderRocks.AnyCustomAttributes(class Mono.Cecil.ICustomAttributeProvider,class System.Type) 36.01ms java.interop.tools.cecil!Java.Interop.Tools.Cecil.CustomAttributeProviderRocks+<GetCustomAttributes>d__3.MoveNext() 1.97ms java.interop.tools.cecil!Java.Interop.Tools.Cecil.CustomAttributeProviderRocks.GetCustomAttributes(class Mono.Cecil.ICus... These changes are about: * `IsNonStaticInnerClass`: ~19ms faster * `CustomAttributeProviderRocks (Any)`: ~15ms faster Overall, saves about ~34ms for incremental builds of the .NET podcast app.
1 parent bde306d commit 1366d99

File tree

3 files changed

+36
-17
lines changed

3 files changed

+36
-17
lines changed

src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/CustomAttributeProviderRocks.cs

+12
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,23 @@ namespace Java.Interop.Tools.Cecil {
88

99
public static class CustomAttributeProviderRocks
1010
{
11+
public static bool AnyCustomAttributes (this ICustomAttributeProvider item, Type attribute) =>
12+
item.AnyCustomAttributes (attribute.FullName);
13+
1114
public static IEnumerable<CustomAttribute> GetCustomAttributes (this ICustomAttributeProvider item, Type attribute)
1215
{
1316
return item.GetCustomAttributes (attribute.FullName);
1417
}
1518

19+
public static bool AnyCustomAttributes (this ICustomAttributeProvider item, string attribute_fullname)
20+
{
21+
foreach (CustomAttribute custom_attribute in item.CustomAttributes) {
22+
if (custom_attribute.Constructor.DeclaringType.FullName == attribute_fullname)
23+
return true;
24+
}
25+
return false;
26+
}
27+
1628
public static IEnumerable<CustomAttribute> GetCustomAttributes (this ICustomAttributeProvider item, string attribute_fullname)
1729
{
1830
foreach (CustomAttribute custom_attribute in item.CustomAttributes) {

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs

+7-8
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ void AddNestedTypes (TypeDefinition type)
164164
var baseRegisteredMethod = GetBaseRegisteredMethod (minfo);
165165
if (baseRegisteredMethod != null)
166166
AddMethod (baseRegisteredMethod, minfo);
167-
else if (GetExportFieldAttributes (minfo).Any ()) {
167+
else if (minfo.AnyCustomAttributes (typeof(ExportFieldAttribute))) {
168168
AddMethod (null, minfo);
169169
HasExport = true;
170-
} else if (GetExportAttributes (minfo).Any ()) {
170+
} else if (minfo.AnyCustomAttributes (typeof (ExportAttribute))) {
171171
AddMethod (null, minfo);
172172
HasExport = true;
173173
}
@@ -205,8 +205,8 @@ void AddNestedTypes (TypeDefinition type)
205205

206206
var curCtors = new List<MethodDefinition> ();
207207

208-
foreach (MethodDefinition minfo in type.Methods.Where (m => m.IsConstructor)) {
209-
if (GetExportAttributes (minfo).Any ()) {
208+
foreach (MethodDefinition minfo in type.Methods) {
209+
if (minfo.IsConstructor && minfo.AnyCustomAttributes (typeof (ExportAttribute))) {
210210
if (minfo.IsStatic) {
211211
// Diagnostic.Warning (log, "ExportAttribute does not work on static constructor");
212212
}
@@ -278,8 +278,8 @@ static void ExtractJavaNames (string jniName, out string package, out string typ
278278

279279
void AddConstructors (TypeDefinition type, string? outerType, List<MethodDefinition>? baseCtors, List<MethodDefinition> curCtors, bool onlyRegisteredOrExportedCtors)
280280
{
281-
foreach (MethodDefinition ctor in type.Methods.Where (m => m.IsConstructor && !m.IsStatic))
282-
if (!GetExportAttributes (ctor).Any ())
281+
foreach (MethodDefinition ctor in type.Methods)
282+
if (ctor.IsConstructor && !ctor.IsStatic && !ctor.AnyCustomAttributes (typeof (ExportAttribute)))
283283
AddConstructor (ctor, type, outerType, baseCtors, curCtors, onlyRegisteredOrExportedCtors, false);
284284
}
285285

@@ -342,8 +342,7 @@ void AddConstructor (MethodDefinition ctor, TypeDefinition type, string? outerTy
342342
while ((bmethod = method.GetBaseDefinition (cache)) != method) {
343343
method = bmethod;
344344

345-
var attributes = method.GetCustomAttributes (typeof (RegisterAttribute));
346-
if (attributes.Any ()) {
345+
if (method.AnyCustomAttributes (typeof (RegisterAttribute))) {
347346
return method;
348347
}
349348
}

src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs

+17-9
Original file line numberDiff line numberDiff line change
@@ -710,16 +710,24 @@ internal static bool IsNonStaticInnerClass (TypeDefinition? type, IMetadataResol
710710
if (!type.DeclaringType.IsSubclassOf ("Java.Lang.Object", cache))
711711
return false;
712712

713-
return GetBaseConstructors (type, cache)
714-
.Any (ctor => ctor.Parameters.Any (p => p.Name == "__self"));
715-
}
713+
foreach (var baseType in type.GetBaseTypes (cache)) {
714+
if (baseType == null)
715+
continue;
716+
if (!baseType.AnyCustomAttributes (typeof (RegisterAttribute)))
717+
continue;
716718

717-
static IEnumerable<MethodDefinition> GetBaseConstructors (TypeDefinition type, IMetadataResolver cache)
718-
{
719-
var baseType = type.GetBaseTypes (cache).FirstOrDefault (t => t.GetCustomAttributes (typeof (RegisterAttribute)).Any ());
720-
if (baseType != null)
721-
return baseType.Methods.Where (m => m.IsConstructor && !m.IsStatic);
722-
return Enumerable.Empty<MethodDefinition> ();
719+
foreach (var method in baseType.Methods) {
720+
if (!method.IsConstructor || method.IsStatic)
721+
continue;
722+
if (method.Parameters.Any (p => p.Name == "__self"))
723+
return true;
724+
}
725+
726+
// Stop at the first base type with [Register]
727+
break;
728+
}
729+
730+
return false;
723731
}
724732
#endif // HAVE_CECIL
725733

0 commit comments

Comments
 (0)