Skip to content

[CoreCLR] Skip MVID computation in TypemapManagedToJava when ManagedToJavaUsesAssemblyFullName is enabled #12232

Description

@jonathanpeppers

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageIssues that need to be assigned.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions