Skip to content

[TrimmableTypeMap] Pass TargetType and InvokerType through JavaPeerProxy constructor#11092

Merged
simonrozsival merged 1 commit intomainfrom
dev/simonrozsival/fix-invokertype-virtual
Apr 9, 2026
Merged

[TrimmableTypeMap] Pass TargetType and InvokerType through JavaPeerProxy constructor#11092
simonrozsival merged 1 commit intomainfrom
dev/simonrozsival/fix-invokertype-virtual

Conversation

@simonrozsival
Copy link
Copy Markdown
Member

@simonrozsival simonrozsival commented Apr 9, 2026

Problem

TargetType and InvokerType on generated proxy types were implemented as virtual property overrides. This had two issues:

  1. Bug: get_InvokerType was emitted without MethodAttributes.Virtual, making it a new method. When accessed via the base JavaPeerProxy reference, the base returned null, preventing interface invoker types from being resolved.

  2. Performance: Every access went through vtable dispatch for values that never change after construction.

Fix

Replace both virtual overrides with constructor parameters:

// JavaPeerProxy base — before:
public abstract Type TargetType { get; }
public virtual Type? InvokerType => null;

// JavaPeerProxy base — after:
public Type TargetType { get; }
public Type? InvokerType { get; }
protected JavaPeerProxy(Type targetType, Type? invokerType) { ... }

Generated proxy ctor: base(typeof(Activity), typeof(IActivityInvoker)) or base(typeof(Button), null).

JavaPeerProxy<T> updated to pass typeof(T) through base ctor instead of overriding TargetType.

Files changed

  • JavaPeerProxy.cs — Single (Type, Type?) ctor; both properties are get-only fields; JavaPeerProxy<T> chains base(typeof(T), invokerType)
  • TypeMapAssemblyEmitter.cs — Emit ldtoken TargetType + ldtoken InvokerType/ldnull + base(Type, Type?) in proxy ctor; remove get_TargetType and get_InvokerType overrides

@simonrozsival simonrozsival marked this pull request as ready for review April 9, 2026 07:28
Copilot AI review requested due to automatic review settings April 9, 2026 07:28
@simonrozsival simonrozsival enabled auto-merge (squash) April 9, 2026 07:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes trimmable typemap proxy generation so JavaPeerProxy.InvokerType is properly overridden on generated proxy types (instead of being emitted as a hidden new member), enabling runtime resolution of interface invoker types.

Changes:

  • Emit get_InvokerType with MethodAttributes.Virtual to correctly override JavaPeerProxy.InvokerType.

Comment thread src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs Outdated
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/fix-invokertype-virtual branch from 38e3262 to 5451150 Compare April 9, 2026 09:48
@simonrozsival simonrozsival changed the title [TrimmableTypeMap] Fix InvokerType Virtual attribute on proxy type getter [TrimmableTypeMap] Pass InvokerType through JavaPeerProxy constructor Apr 9, 2026
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/fix-invokertype-virtual branch 2 times, most recently from ced4c5f to ff0ef65 Compare April 9, 2026 10:09
@simonrozsival simonrozsival changed the title [TrimmableTypeMap] Pass InvokerType through JavaPeerProxy constructor [TrimmableTypeMap] Pass TargetType and InvokerType through JavaPeerProxy constructor Apr 9, 2026
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/fix-invokertype-virtual branch from ff0ef65 to 7faf5f5 Compare April 9, 2026 10:13
…oxy constructor

Replace virtual property overrides for both TargetType and InvokerType
with constructor parameters. The generated proxy ctor now calls
base(typeof(Target), typeof(Invoker)) or base(typeof(Target), null),
storing both values in readonly fields. No virtual dispatch needed.

Before (two virtual overrides per proxy):
  public override Type TargetType => typeof(Activity);
  public override Type? InvokerType => typeof(IActivityInvoker);

After (ctor params, field reads):
  protected JavaPeerProxy(Type targetType, Type? invokerType)
  // Generated: base(typeof(Activity), typeof(IActivityInvoker))

This also fixes the original bug where get_InvokerType was emitted
without MethodAttributes.Virtual, causing the base class to always
return null. With the constructor approach, virtual dispatch is
eliminated entirely for both properties.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/fix-invokertype-virtual branch from 7faf5f5 to e70f93a Compare April 9, 2026 10:36
@simonrozsival simonrozsival added trimmable-type-map copilot `copilot-cli` or other AIs were used to author this labels Apr 9, 2026
@simonrozsival simonrozsival disabled auto-merge April 9, 2026 16:23
@simonrozsival simonrozsival merged commit f09c2f2 into main Apr 9, 2026
6 checks passed
@simonrozsival simonrozsival deleted the dev/simonrozsival/fix-invokertype-virtual branch April 9, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

copilot `copilot-cli` or other AIs were used to author this trimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants