From 2f72421aaa62104f8a9daa96518146f85a202fe2 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Thu, 15 Aug 2024 11:17:57 -1000 Subject: [PATCH] [Java.Interop.Tools.Cecil] TypeDefinitionRocks performance tweaks. --- .../Java.Interop.Tools.Cecil.csproj | 2 +- .../MethodDefinitionRocks.cs | 4 +- .../TypeDefinitionRocks.cs | 66 +++++++++++++++++-- .../CecilImporter.cs | 12 ++-- ....Interop.Tools.JavaCallableWrappers.csproj | 2 +- .../JavaNativeTypeManager.cs | 16 +++-- 6 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil.csproj b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil.csproj index b36defd33..4c830f48e 100644 --- a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil.csproj +++ b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 8.0 + 9.0 enable true ..\..\product.snk diff --git a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs index cdbdcaf02..1bccc10de 100644 --- a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs +++ b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/MethodDefinitionRocks.cs @@ -20,7 +20,9 @@ public static MethodDefinition GetBaseDefinition (this MethodDefinition method, if (method.IsStatic || method.IsNewSlot || !method.IsVirtual) return method; - foreach (var baseType in method.DeclaringType.GetBaseTypes (resolver)) { + TypeDefinition? baseType = method.DeclaringType; + + while ((baseType = baseType.GetBaseType (resolver)) != null) { foreach (var m in baseType.Methods) { if (!m.IsConstructor && m.Name == method.Name && diff --git a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs index 2873b4b7d..e2ef67549 100644 --- a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs +++ b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs @@ -65,7 +65,10 @@ public static bool IsAssignableFrom (this TypeReference type, TypeReference c, I var d = resolver.Resolve (c); if (d == null) return false; - foreach (var t in d.GetTypeAndBaseTypes (resolver)) { + + TypeDefinition? t = d; + + while (t is not null) { if (type.FullName == t.FullName) return true; foreach (var ifaceImpl in t.Interfaces) { @@ -73,6 +76,8 @@ public static bool IsAssignableFrom (this TypeReference type, TypeReference c, I if (IsAssignableFrom (type, i, resolver)) return true; } + + t = t.GetBaseType (resolver); } return false; } @@ -84,20 +89,44 @@ public static bool IsSubclassOf (this TypeDefinition type, string typeName, Type IsSubclassOf (type, typeName, (IMetadataResolver) cache); public static bool IsSubclassOf (this TypeDefinition type, string typeName, IMetadataResolver resolver) { - foreach (var t in type.GetTypeAndBaseTypes (resolver)) { + TypeDefinition? t = type; + + while (t is not null) { if (t.FullName == typeName) { return true; } + + t = t.GetBaseType (resolver); + } + return false; + } + + public static bool IsSubclassOfAny (this TypeDefinition type, IList typeNames, IMetadataResolver resolver, out string? subclassType) + { + subclassType = null; + + TypeDefinition? t = type; + + while (t is not null) { + if (typeNames.Contains (t.FullName)) { + subclassType = t.FullName; + return true; + } + + t = t.GetBaseType (resolver); } + return false; } public static bool HasJavaPeer (this TypeDefinition type, IMetadataResolver resolver) { - if (type.IsInterface && type.ImplementsInterface ("Java.Interop.IJavaPeerable", resolver)) - return true; + if (type.IsInterface) + return type.ImplementsInterface ("Java.Interop.IJavaPeerable", resolver); - foreach (var t in type.GetTypeAndBaseTypes (resolver)) { + TypeDefinition? t = type; + + while (t is not null) { switch (t.FullName) { case "Java.Lang.Object": case "Java.Lang.Throwable": @@ -107,6 +136,8 @@ public static bool HasJavaPeer (this TypeDefinition type, IMetadataResolver reso default: break; } + + t = t.GetBaseType (resolver); } return false; } @@ -119,13 +150,36 @@ public static bool ImplementsInterface (this TypeDefinition type, string interfa public static bool ImplementsInterface (this TypeDefinition type, string interfaceName, IMetadataResolver resolver) { - foreach (var t in type.GetTypeAndBaseTypes (resolver)) { + TypeDefinition? t = type; + + while (t is not null) { foreach (var i in t.Interfaces) { if (i.InterfaceType.FullName == interfaceName) { return true; } } + + t = t.GetBaseType (resolver); + } + return false; + } + + public static bool ImplementsAnyInterface (this TypeDefinition type, IList interfaceNames, IMetadataResolver resolver, out string? implementedInterface) + { + implementedInterface = null; + TypeDefinition? t = type; + + while (t is not null) { + foreach (var i in t.Interfaces) { + if (interfaceNames.Contains (i.InterfaceType.FullName)) { + implementedInterface = i.InterfaceType.FullName; + return true; + } + } + + t = t.GetBaseType (resolver); } + return false; } diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/CecilImporter.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/CecilImporter.cs index 9353e8378..ca0b75d1a 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/CecilImporter.cs +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.Adapters/CecilImporter.cs @@ -14,6 +14,8 @@ namespace Java.Interop.Tools.JavaCallableWrappers.Adapters; public class CecilImporter { + static IList android_manifest_types = ["Android.App.Activity", "Android.App.Application", "Android.App.Service", "Android.Content.BroadcastReceiver", "Android.Content.ContentProvider"]; + // Don't expose internal "outerType" parameter to the public API public static CallableWrapperType CreateType (TypeDefinition type, IMetadataResolver resolver, CallableWrapperReaderOptions? options = null) => CreateType (type, resolver, options, null); @@ -38,11 +40,7 @@ static CallableWrapperType CreateType (TypeDefinition type, IMetadataResolver re options ??= new CallableWrapperReaderOptions (); if (string.IsNullOrEmpty (package) && - (type.IsSubclassOf ("Android.App.Activity", resolver) || - type.IsSubclassOf ("Android.App.Application", resolver) || - type.IsSubclassOf ("Android.App.Service", resolver) || - type.IsSubclassOf ("Android.Content.BroadcastReceiver", resolver) || - type.IsSubclassOf ("Android.Content.ContentProvider", resolver))) + (type.IsSubclassOfAny (android_manifest_types, resolver, out var _))) Diagnostic.Error (4203, CecilExtensions.LookupSource (type), Localization.Resources.JavaCallableWrappers_XA4203, jniName); var cwt = new CallableWrapperType (name, package, type.GetPartialAssemblyQualifiedName (resolver)) { @@ -124,7 +122,9 @@ static CallableWrapperType CreateType (TypeDefinition type, IMetadataResolver re type, }; - foreach (var bt in type.GetBaseTypes (resolver)) { + TypeDefinition? bt = type; + + while ((bt = bt.GetBaseType (resolver)) != null) { ctorTypes.Add (bt); var rattr = CecilExtensions.GetTypeRegistrationAttributes (bt).FirstOrDefault (); diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.csproj b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.csproj index 63e7835eb..19fa60aa7 100644 --- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.csproj +++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 11.0 + 12.0 enable true true diff --git a/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs b/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs index 17e895720..c96de3c7f 100644 --- a/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs +++ b/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs @@ -438,7 +438,7 @@ public static bool IsApplication (TypeDefinition type, TypeDefinitionCache cache public static bool IsApplication (TypeDefinition type, IMetadataResolver resolver) { - return type.GetBaseTypes (resolver).Any (b => b.FullName == "Android.App.Application"); + return type.IsSubclassOf ("Android.App.Application", resolver); } [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] @@ -449,7 +449,7 @@ public static bool IsInstrumentation (TypeDefinition type, TypeDefinitionCache c public static bool IsInstrumentation (TypeDefinition type, IMetadataResolver resolver) { - return type.GetBaseTypes (resolver).Any (b => b.FullName == "Android.App.Instrumentation"); + return type.IsSubclassOf ("Android.App.Instrumentation", resolver); } // moved from JavaTypeInfo @@ -529,6 +529,8 @@ public static string ToJniName (TypeDefinition type, IMetadataResolver resolver) return x; } + static IList java_interface_types = ["Android.Runtime.IJavaObject", "Java.Interop.IJavaPeerable"]; + static string? ToJniName (TypeDefinition type, ExportParameterKind exportKind, IMetadataResolver cache) { if (type == null) @@ -540,8 +542,7 @@ public static string ToJniName (TypeDefinition type, IMetadataResolver resolver) if (type.FullName == "System.String") return "java/lang/String"; - if (!type.ImplementsInterface ("Android.Runtime.IJavaObject", cache) && - !type.ImplementsInterface ("Java.Interop.IJavaPeerable", cache)) { + if (!type.ImplementsAnyInterface (java_interface_types, cache, out var _)) { return GetSpecialExportJniType (type.FullName, exportKind); } @@ -734,9 +735,10 @@ internal static bool IsNonStaticInnerClass (TypeDefinition? type, IMetadataResol if (!type.DeclaringType.HasJavaPeer (cache)) return false; - foreach (var baseType in type.GetBaseTypes (cache)) { - if (baseType == null) - continue; + TypeDefinition? baseType = type; + + while ((baseType = baseType.GetBaseType (cache)) != null) { + if (!baseType.AnyCustomAttributes (typeof (RegisterAttribute))) continue;