Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Investigate eliminating generated ThresholdType and ThresholdClass overrides

Chiusa
#12,679 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
35/100
Tipo di issue
Refactoring
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
csharp
Ambito
mobile

Direzione di ricerca

Inizia dai file generati in obj/.../mcw/*.cs e segui Android.Runtime.XAPeerMembers.UsesVirtualDispatch(), GetPeerMembers() e gli accessor di threshold di Java.Lang.Object/Throwable. Confronta i casi di binding exact, subclass, invoker, cross-assembly e legacy nei runtime elencati. Il lavoro è completo quando è stato stabilito se gli override moderni possono essere omessi senza modificare il dispatch, preservando la semantica legacy e registrando i metadati richiesti e i confronti delle dimensioni.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Area: Mono.Android
Android framework version

net11.0-android (Preview) / .NET 12 investigation

Affected platform version

dotnet/android main; generated Mono.Android.dll and generated Java binding assemblies.

Description

The XAJavaInterop1 generator currently emits these overrides on nearly every generated bound class and invoker:

[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
protected override IntPtr ThresholdClass
    => _members.JniPeerType.PeerReference.Handle;

[DebuggerBrowsable (DebuggerBrowsableState.Never)]
[EditorBrowsable (EditorBrowsableState.Never)]
protected override Type ThresholdType
    => _members.ManagedPeerType;

API 37 Mono.Android.dll contains approximately:

  • 6,776 generated ThresholdClass overrides;
  • 7,447 generated ThresholdType overrides;
  • 28,446 associated DebuggerBrowsable/EditorBrowsable attribute applications;
  • roughly 14,000 property rows, getter methods, method-semantics rows, bodies, and related metadata entries.

This appears to be an opportunity of more than 1 MB in the untrimmed framework assembly, but removal must not be attempted without understanding the legacy dispatch contract.

XAPeerMembers currently uses the properties to decide virtual versus nonvirtual managed-to-Java dispatch:

protected override bool UsesVirtualDispatch (IJavaPeerable value, Type? declaringType)
{
    var peerType = GetThresholdType (value);
    if (peerType != null)
        return peerType == value.GetType ();

    return base.UsesVirtualDispatch (value, declaringType);
}

It also uses ThresholdClass when selecting peer members for nonvirtual dispatch. This historically prevents incorrect recursion or dispatch when managed subclasses override Java virtual methods.

At first glance, modern generated types already expose equivalent information through:

value.JniPeerMembers.ManagedPeerType
value.JniPeerMembers.JniPeerType

The base JniPeerMembers.UsesVirtualDispatch() implementation already compares value.GetType() with value.JniPeerMembers.ManagedPeerType. We should investigate whether new-format binding assemblies can rely on this information and stop generating the per-type threshold overrides.

This must be considered separately from legacy binding compatibility. Old binding assemblies may:

  • contain generated threshold overrides;
  • contain hand-written threshold overrides;
  • depend on XAPeerMembers honoring those values;
  • derive from framework binding types across assembly boundaries; or
  • use older generator/runtime dispatch assumptions.

A possible compatibility model is:

  1. Keep the protected virtual ThresholdType and ThresholdClass members on Java.Lang.Object/Throwable so old binaries remain loadable.
  2. Stop emitting overrides in newly generated/version-marked bindings.
  3. Use JniPeerMembers.ManagedPeerType and JniPeerType for modern bindings.
  4. Detect and continue honoring threshold overrides from legacy binding assemblies, potentially keyed by an assembly/generator-format marker or a cached override-shape check.

The investigation should determine whether this split is correct or whether there are dispatch cases where the explicit threshold values carry information not available through JniPeerMembers.

Related size work: #12670.

Steps to Reproduce
  1. Generate Mono.Android.dll for API 37 with XAJavaInterop1.
  2. Count generated ThresholdType and ThresholdClass overrides in obj/.../mcw/*.cs or the resulting assembly.
  3. Trace XAPeerMembers.UsesVirtualDispatch() and GetPeerMembers() through exact binding types, managed subclasses, Java subclasses, and invoker types.
  4. Prototype omitting the generated overrides for a version-marked modern binding format while preserving the base virtual properties.
  5. Compare behavior against legacy binding assemblies built by older generators.

The prototype should cover at least:

  • an exact generated binding type;
  • a managed subclass overriding a Java virtual method;
  • a Java-derived runtime type;
  • abstract classes and interface invokers;
  • cross-assembly inheritance;
  • an old binding assembly containing generated threshold overrides;
  • a legacy binding with a hand-written/custom threshold override;
  • virtual and explicit nonvirtual calls;
  • MonoVM, CoreCLR, and NativeAOT/trimmable-typemap configurations where applicable; and
  • recursion prevention and correct Java method selection.

Acceptance criteria for an eventual implementation:

  • New-format generated bindings omit ThresholdType/ThresholdClass overrides when they carry no additional information.
  • Managed-subclass and Java virtual-dispatch behavior remains unchanged.
  • Legacy binding assemblies continue to load and preserve their threshold semantics.
  • The protected base API remains binary compatible unless a separate breaking-change decision is made.
  • Tests prove that no managed override recursion or wrong JNI nonvirtual class selection is introduced.
  • Before/after Mono.Android.dll metadata, method, property, attribute, and final trimmed-app sizes are recorded.
Did you find any workaround?

No workaround is needed for correctness. The current generated properties preserve established behavior but impose repeated assembly-size and metadata costs.

Relevant log output
API 37 generated counts:
ThresholdClass overrides: 6,776
ThresholdType overrides:  7,447

Current runtime consumers:
- Android.Runtime.XAPeerMembers.UsesVirtualDispatch()
- Android.Runtime.XAPeerMembers.GetPeerMembers()
- Java.Lang.Object.GetThresholdType()/GetThresholdClass()
- Java.Lang.Throwable.GetThresholdType()/GetThresholdClass()
Lingua principale
C#
Stelle
2.1k
Fork
581
Merge medio
2g 33m
PR unite (30g)
204

Preparare l'ambiente

  • Nessun Dockerfile né file Docker Compose
  • Ha un modello di pull request
  • Nessuna guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di dotnet/android

Tutte le issue di dotnet/android

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.