Follow-up from review feedback on #12216.
Background
#12216 changed the CoreCLR Debug managed-to-Java typemap to key on the stable assembly full name instead of the assembly MVID, so that a C#-only rebuild no longer rewrites the native typemap (and therefore no longer forces native compilation, APK rebuild, and signing during Fast Deployment).
The managed side selects between the two lookup styles with the Microsoft.Android.Runtime.RuntimeFeature.ManagedToJavaUsesAssemblyFullName feature switch, which is enabled for Debug via Microsoft.Android.Sdk.CoreCLR.targets.
Issue
In JNIEnv.TypemapManagedToJava() (src/Mono.Android/Android.Runtime/JNIEnv.cs), the MVID is still computed unconditionally on every lookup:
if (mvid_bytes == null)
mvid_bytes = new byte[16];
var mvid = new Span<byte>(mvid_bytes);
byte[]? mvid_data = null;
if (!type.Module.ModuleVersionId.TryWriteBytes (mvid)) {
RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"Failed to obtain module MVID using the fast method, falling back to the slow one");
mvid_data = type.Module.ModuleVersionId.ToByteArray ();
} else {
mvid_data = mvid_bytes;
}
IntPtr ret;
fixed (byte* mvidptr = mvid_data) {
...
ret = RuntimeNativeMethods.clr_typemap_managed_to_java (type.FullName, assemblyFullName, (IntPtr)mvidptr);
...
}
When ManagedToJavaUsesAssemblyFullName is enabled, the native side (TypeMapper::managed_to_java_debug in src/native/clr/host/typemap.cc) ignores the mvid argument entirely — it builds the key as typeName + ", " + assemblyFullName. So Type.Module.ModuleVersionId + Guid.TryWriteBytes is wasted work on every type resolution during startup.
Proposed change
Skip the MVID computation (and the fixed pin) when ManagedToJavaUsesAssemblyFullName is set, passing IntPtr.Zero for the MVID pointer in that case.
Care is needed because the same fixed block also serves the MonoVM path (monovm_typemap_managed_to_java), which does require the MVID, so the method needs a small restructure rather than a one-line change.
Impact
Low. The feature switch is only enabled for Debug builds, mvid_bytes is a cached static, and Guid.TryWriteBytes is a 16-byte copy — so this is a small per-lookup saving on the Debug startup type-resolution path only. Filing so it isn't lost.
Notes
- Release keeps the MVID-based lookup (
managed_to_java_release), so the MVID computation must remain on that path.
- Anything done here should keep
RuntimeFeature.IsMonoRuntime behavior unchanged.
Refs: #12216 (comment)
Follow-up from review feedback on #12216.
Background
#12216 changed the CoreCLR Debug managed-to-Java typemap to key on the stable assembly full name instead of the assembly MVID, so that a C#-only rebuild no longer rewrites the native typemap (and therefore no longer forces native compilation, APK rebuild, and signing during Fast Deployment).
The managed side selects between the two lookup styles with the
Microsoft.Android.Runtime.RuntimeFeature.ManagedToJavaUsesAssemblyFullNamefeature switch, which is enabled for Debug viaMicrosoft.Android.Sdk.CoreCLR.targets.Issue
In
JNIEnv.TypemapManagedToJava()(src/Mono.Android/Android.Runtime/JNIEnv.cs), the MVID is still computed unconditionally on every lookup:When
ManagedToJavaUsesAssemblyFullNameis enabled, the native side (TypeMapper::managed_to_java_debuginsrc/native/clr/host/typemap.cc) ignores themvidargument entirely — it builds the key astypeName + ", " + assemblyFullName. SoType.Module.ModuleVersionId+Guid.TryWriteBytesis wasted work on every type resolution during startup.Proposed change
Skip the MVID computation (and the
fixedpin) whenManagedToJavaUsesAssemblyFullNameis set, passingIntPtr.Zerofor the MVID pointer in that case.Care is needed because the same
fixedblock also serves the MonoVM path (monovm_typemap_managed_to_java), which does require the MVID, so the method needs a small restructure rather than a one-line change.Impact
Low. The feature switch is only enabled for Debug builds,
mvid_bytesis a cached static, andGuid.TryWriteBytesis a 16-byte copy — so this is a small per-lookup saving on the Debug startup type-resolution path only. Filing so it isn't lost.Notes
managed_to_java_release), so the MVID computation must remain on that path.RuntimeFeature.IsMonoRuntimebehavior unchanged.Refs: #12216 (comment)