-
Notifications
You must be signed in to change notification settings - Fork 59
[Java.Interop.Tools.JavaCallableWrappers] fix more places to use TypeDefinitionCache #1069
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…DefinitionCache Reviewing code in `JavaCallableWrapperGenerator`, I found places we weren't using the supplied `TypeDefinitionCache` or `IMetadataResolver`. Thus we appeared to be calling `TypeReference.Resolve()` potentially on the same types. For example, `dotnet trace` output of an incremental build of a `dotnet new maui` project: 41.65ms xamarin.android.cecil!Mono.Cecil.TypeReference.Resolve() I created a new `TypeDefinitionRocks.ResolveCached()` method to be used everywhere instead. Resulting with: 23.89ms xamarin.android.cecil!Mono.Cecil.TypeReference.Resolve() Additionally, I updated to places to use plain `foreach` loops instead of System.Linq. Before: 1.03s xamarin.android.build.tasks!Xamarin.Android.Tasks.GenerateJavaStubs.RunTask() After: 944.48ms xamarin.android.build.tasks!Xamarin.Android.Tasks.GenerateJavaStubs.RunTask() I think this likely saves about ~50ms off incremental builds of a `dotnet new maui` project.
At what point do we decide that I think we should thus require |
....Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs
Outdated
Show resolved
Hide resolved
…and yes, this would be a partial "API break", in that currently non-warning code may start producing warnings, and This raises followup questions, such as what to do with our existing "compatibility overloads" such as https://github.com/xamarin/java.interop/blob/f8d77faf55347a58030a694332ba97f0dee88246/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs#L10-L12 We can't remove them; that would be an ABI break. We should instead update them to be be an error to use: [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error:true)]
public static TypeDefinition? GetBaseType (this TypeDefinition type) =>
throw new NotSupportedException(); |
Any place we had: TypeDefinitionCache? IMetadataResolver? These no longer allow nulls, and so overloads that use `Obsolete` now emit errors instead of warnings: [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] public static MethodDefinition GetBaseDefinition (this MethodDefinition method) => GetBaseDefinition (method, resolver: null!); This results in 3 compiler errors in xamarin-android: src\Xamarin.Android.Build.Tasks\Mono.Android\ApplicationAttribute.Partial.cs(65,11): error CS0619: 'TypeDefinitionRocks.IsSubclassOf(TypeDefinition, string)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' src\Xamarin.Android.Build.Tasks\Mono.Android\ApplicationAttribute.Partial.cs(268,12): error CS0619: 'JavaNativeTypeManager.ToJniName(TypeDefinition)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' src\Xamarin.Android.Build.Tasks\Utilities\ManifestDocumentElement.cs(28,11): error CS0619: 'JavaNativeTypeManager.ToJniName(TypeDefinition)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' After these changes, it appears we will improve the performance further of apps that use: * `ApplicationAttribute.BackupAgent` * `ApplicationAttribute.Name` * `AndroidManifest.xml` attributes that take a `System.Type` values The full scope of changes required in xamarin/xamarin-android will be: dotnet/android@main...jonathanpeppers:JavaInteropBreakingChanges Additionally, this found a couple places in `generator` where changes were needed.
Context: dotnet/java-interop#1069 Any place we had: TypeDefinitionCache? IMetadataResolver? These no longer allow nulls, and so overloads that use `Obsolete` now emit errors instead of warnings: [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] public static MethodDefinition GetBaseDefinition (this MethodDefinition method) => GetBaseDefinition (method, resolver: null!); This results in 3 compiler errors in xamarin-android: src\Xamarin.Android.Build.Tasks\Mono.Android\ApplicationAttribute.Partial.cs(65,11): error CS0619: 'TypeDefinitionRocks.IsSubclassOf(TypeDefinition, string)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' src\Xamarin.Android.Build.Tasks\Mono.Android\ApplicationAttribute.Partial.cs(268,12): error CS0619: 'JavaNativeTypeManager.ToJniName(TypeDefinition)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' src\Xamarin.Android.Build.Tasks\Utilities\ManifestDocumentElement.cs(28,11): error CS0619: 'JavaNativeTypeManager.ToJniName(TypeDefinition)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' After these changes, it appears we will improve the performance further of apps that use: * `ApplicationAttribute.BackupAgent` * `ApplicationAttribute.Name` * `AndroidManifest.xml` attributes that take a `System.Type` values
src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs
Outdated
Show resolved
Hide resolved
src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs
Outdated
Show resolved
Hide resolved
src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs
Outdated
Show resolved
Hide resolved
Draft commit message: Context: b81cfbb9ab8efa647a3bfcc2b2b97a5f1b1fa71e
Reviewing code in `JavaCallableWrapperGenerator`, I found codepaths
where we weren't caching `TypeReference.Resolve()` calls *at all*,
e.g. `JavaNativeTypeManager.GetPrimitiveClass(TypeDefinition)`.
We thus appear to be calling `TypeReference.Resolve()` potentially on
the same types.
For example, `dotnet trace` output of an incremental build of a `dotnet new maui` project:
41.65ms xamarin.android.cecil!Mono.Cecil.TypeReference.Resolve()
It appears that, in trying to make our maintenance lives easier by
preserving backward API compatibility with callers that couldn't
provide a `TypeDefinitionCache` or `IMetadataResolver` instance -- by
providing method overloads which took e.g.
`IMetadataResolver? resolver` parameters which could be `null` -- we
made our optimization and performance lives *harder*, because not
all codepaths which needed to use caching *were* using caching, as
they were overlooked.
As the `Java.Interop.Tools.*` assemblies are internal API, introduce
an *API break* while preserving *ABI*:
`IMetadataResolver` is now required.
Thus, previous/current "compatibility methods" which allow *not*
providing an `IMetadataResolver` instance such as:
// old and busted
partial class TypeDefinitionRocks {
[Obsolete ("Use the TypeDefinitionCache overload for better performance.")]
public static TypeDefinition? GetBaseType (this TypeDefinition type) => GetBaseType (type, resolver: null);
}
will now become *errors* to use:
// new hawtness
partial class TypeDefinitionRocks {
[Obsolete ("Use the TypeDefinitionCache overload for better performance.", error:true)]
public static TypeDefinition? GetBaseType (this TypeDefinition type) => throw new NotSupportedException ();
}
This allows the C# compiler to help us audit our codebase, ensuring
that *all* codepaths which call `TypeReference.Resolve()` instead use
`IMetadataResolver.Resolve()`, including:
* `JavaCallableWrapperGenerator.GetAnnotationsString()`
* `JavaCallableWrapperGenerator.WriteAnnotations()`
* `JavaNativeTypeManager.GetPrimitiveClass()`
Requiring caching results in:
23.89ms xamarin.android.cecil!Mono.Cecil.TypeReference.Resolve()
Additionally, I updated two places to use plain `foreach` loops
instead of using System.Linq.
* Before:
1.03s xamarin.android.build.tasks!Xamarin.Android.Tasks.GenerateJavaStubs.RunTask()
* After:
944.48ms xamarin.android.build.tasks!Xamarin.Android.Tasks.GenerateJavaStubs.RunTask()
I think this likely saves about ~50ms off incremental builds of a
`dotnet new maui` project. |
Context: dotnet/java-interop#1069 Any place we had: TypeDefinitionCache? IMetadataResolver? These no longer allow nulls, and so overloads that use `Obsolete` now emit errors instead of warnings: [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] public static MethodDefinition GetBaseDefinition (this MethodDefinition method) => GetBaseDefinition (method, resolver: null!); This results in 3 compiler errors in xamarin-android: src\Xamarin.Android.Build.Tasks\Mono.Android\ApplicationAttribute.Partial.cs(65,11): error CS0619: 'TypeDefinitionRocks.IsSubclassOf(TypeDefinition, string)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' src\Xamarin.Android.Build.Tasks\Mono.Android\ApplicationAttribute.Partial.cs(268,12): error CS0619: 'JavaNativeTypeManager.ToJniName(TypeDefinition)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' src\Xamarin.Android.Build.Tasks\Utilities\ManifestDocumentElement.cs(28,11): error CS0619: 'JavaNativeTypeManager.ToJniName(TypeDefinition)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' After these changes, it appears we will improve the performance further of apps that use: * `ApplicationAttribute.BackupAgent` * `ApplicationAttribute.Name` * `AndroidManifest.xml` attributes that take a `System.Type` values Additionally, fix NRE in the linker: Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object. at Java.Interop.Tools.Cecil.TypeDefinitionRocks.GetBaseType(TypeDefinition type, IMetadataResolver resolver) in /Users/builder/azdo/_work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs:line 21 at Java.Interop.Tools.Cecil.TypeDefinitionRocks.GetTypeAndBaseTypes(TypeDefinition type, IMetadataResolver resolver)+MoveNext() in /Users/builder/azdo/_work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs:line 36 at Java.Interop.Tools.Cecil.TypeDefinitionRocks.IsSubclassOf(TypeDefinition type, String typeName, IMetadataResolver resolver) in /Users/builder/azdo/_work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs:line 87 at MonoDroid.Tuner.FixAbstractMethodsStep.ProcessType(TypeDefinition type) in /Users/builder/azdo/_work/1/s/xamarin-android/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixAbstractMethodsStep.cs:line 81 at Mono.Linker.Steps.MarkStep.MarkType(TypeReference reference, DependencyInfo reason, Nullable`1 origin) at Mono.Linker.Steps.MarkStep.MarkField(FieldDefinition field, DependencyInfo& reason, MessageOrigin& origin) at Mono.Linker.Steps.MarkStep.MarkEntireType(TypeDefinition type, DependencyInfo& reason) at Mono.Linker.Steps.MarkStep.MarkEntireAssembly(AssemblyDefinition assembly) at Mono.Linker.Steps.MarkStep.MarkAssembly(AssemblyDefinition assembly, DependencyInfo reason) at Mono.Linker.Steps.MarkStep.MarkModule(ModuleDefinition module, DependencyInfo reason) at Mono.Linker.Steps.MarkStep.ProcessMarkedPending() at Mono.Linker.Steps.MarkStep.Initialize() at Mono.Linker.Steps.MarkStep.Process(LinkContext context) at Mono.Linker.Pipeline.Process(LinkContext context) at Mono.Linker.Driver.Run(ILogger customLogger) at Mono.Linker.Driver.Main(String[] args) This was caused by removing null checks in Java.Interop.
Changes: dotnet/java-interop@f8d77fa...cf80deb * dotnet/java-interop@cf80deb7: [Java.Interop.Tools.JavaCallableWrappers] use IMetadataResolver more (dotnet/java-interop#1069) * dotnet/java-interop@5c5dc086: [generator] enum map.csv can set `@deprecated-since` for enum values (dotnet/java-interop#1070) Any place we used: * `TypeDefinitionCache?` * `IMetadataResolver?` As of dotnet/java-interop@cf80deb7, Java.Interop no longer allows `null` values for these parameters, so overloads which were] `[Obsolete]` now emit errors instead of warnings: [Obsolete ("Use the TypeDefinitionCache overload for better performance.", error: true)] public static MethodDefinition GetBaseDefinition (this MethodDefinition method) => GetBaseDefinition (method, resolver: null!); This results in 3 compiler errors in xamarin-android: src\Xamarin.Android.Build.Tasks\Mono.Android\ApplicationAttribute.Partial.cs(65,11): error CS0619: 'TypeDefinitionRocks.IsSubclassOf(TypeDefinition, string)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' src\Xamarin.Android.Build.Tasks\Mono.Android\ApplicationAttribute.Partial.cs(268,12): error CS0619: 'JavaNativeTypeManager.ToJniName(TypeDefinition)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' src\Xamarin.Android.Build.Tasks\Utilities\ManifestDocumentElement.cs(28,11): error CS0619: 'JavaNativeTypeManager.ToJniName(TypeDefinition)' is obsolete: 'Use the TypeDefinitionCache overload for better performance.' After these changes, it appears we will improve the performance further of apps that use: * `ApplicationAttribute.BackupAgent` * `ApplicationAttribute.Name` * `AndroidManifest.xml` attributes that take a `System.Type` values Additionally, fix a `NullReferenceException` in the linker: Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object. at Java.Interop.Tools.Cecil.TypeDefinitionRocks.GetBaseType(TypeDefinition type, IMetadataResolver resolver) in /Users/builder/azdo/_work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs:line 21 at Java.Interop.Tools.Cecil.TypeDefinitionRocks.GetTypeAndBaseTypes(TypeDefinition type, IMetadataResolver resolver)+MoveNext() in /Users/builder/azdo/_work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs:line 36 at Java.Interop.Tools.Cecil.TypeDefinitionRocks.IsSubclassOf(TypeDefinition type, String typeName, IMetadataResolver resolver) in /Users/builder/azdo/_work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs:line 87 at MonoDroid.Tuner.FixAbstractMethodsStep.ProcessType(TypeDefinition type) in /Users/builder/azdo/_work/1/s/xamarin-android/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixAbstractMethodsStep.cs:line 81 at Mono.Linker.Steps.MarkStep.MarkType(TypeReference reference, DependencyInfo reason, Nullable`1 origin) at Mono.Linker.Steps.MarkStep.MarkField(FieldDefinition field, DependencyInfo& reason, MessageOrigin& origin) at Mono.Linker.Steps.MarkStep.MarkEntireType(TypeDefinition type, DependencyInfo& reason) at Mono.Linker.Steps.MarkStep.MarkEntireAssembly(AssemblyDefinition assembly) at Mono.Linker.Steps.MarkStep.MarkAssembly(AssemblyDefinition assembly, DependencyInfo reason) at Mono.Linker.Steps.MarkStep.MarkModule(ModuleDefinition module, DependencyInfo reason) at Mono.Linker.Steps.MarkStep.ProcessMarkedPending() at Mono.Linker.Steps.MarkStep.Initialize() at Mono.Linker.Steps.MarkStep.Process(LinkContext context) at Mono.Linker.Pipeline.Process(LinkContext context) at Mono.Linker.Driver.Run(ILogger customLogger) at Mono.Linker.Driver.Main(String[] args) This was caused by removing `null` checks in Java.Interop. Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Reviewing code in
JavaCallableWrapperGenerator
, I found places we weren't using the suppliedTypeDefinitionCache
orIMetadataResolver
. Thus we appeared to be callingTypeReference.Resolve()
potentially on the same types.For example,
dotnet trace
output of an incremental build of adotnet new maui
project:I created a new
TypeDefinitionRocks.ResolveCached()
method to be used everywhere instead. Resulting with:Additionally, I updated to places to use plain
foreach
loops instead of System.Linq.I think this likely saves about ~50ms off incremental builds of a
dotnet new maui
project.