Skip to content

[typemap] Reduce Java-to-managed proxy lookup allocations - #12619

Merged
simonrozsival merged 9 commits into
mainfrom
simonrozsival-trimmable-typemap-performance
Sep 4, 2026
Merged

[typemap] Reduce Java-to-managed proxy lookup allocations#12619
simonrozsival merged 9 commits into
mainfrom
simonrozsival-trimmable-typemap-performance

Conversation

@simonrozsival

Copy link
Copy Markdown
Member

Summary

  • add an allocation-free singular Java-to-managed target lookup path
  • cache the common JNI-name result directly as JavaPeerProxy, using arrays only for aliases and misses
  • replace iterator-based proxy collection with a ref builder
  • avoid duplicate proxy-attribute materialization and defer List<JavaPeerProxy> allocation until a second proxy is found
  • retain alias ordering, missing-entry caching, and multi-result behavior

Performance

Measured on an arm64 Android emulator with .NET 11 and partial ReadyToRun:

Scenario Before After Change
Cold direct lookup 696.4 ns / 523 B 431.6 ns / 196 B 38% faster, 63% less allocation
Cold missing lookup 243.0 ns / 184 B 225.2 ns / 48 B 7% faster, 74% less allocation
Cached framework hit 18.7 ns 12.5 ns 33% faster
Cached app hit 42.8 ns 37.5 ns 12% faster
Cached miss 18.7 ns 20.7 ns 2 ns slower

The small cached-miss fallback cost is intentional: the first branch is optimized for the overwhelmingly common single-proxy hit.

Validation

  • built Mono.Android for net11.0
  • built and installed the CoreCLR trimmable Mono.Android.NET-Tests app
  • passed all 776 standalone trimmable typemap tests
  • exercised single, alias, and missing cache shapes in focused runtime coverage

simonrozsival and others added 2 commits September 1, 2026 12:01
Add a direct first-result lookup over the cached proxy array and use it from the Java-to-managed singular type path. Keep the existing multi-result API for aliases and arrays, with focused allocation and alias coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Cache the common single-proxy result directly, avoid iterator and eager collection allocations while resolving JNI names, and retain arrays only for aliases and misses.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 1, 2026 11:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Review tier: Lite
Findings: 1 Low severity

New issues introduced by this change (1)
Severity Finding
Low severity src/​Mono.Android/​Microsoft.Android.Runtime/​TrimmableTypeMap.cs — 💡 suggestion: _jniProxyCache now stores object values and call sites assume the value is always…
What changed in this PR

This PR optimizes the trimmable typemap Java→managed lookup path in Mono.Android by introducing a single-target lookup API and reshaping the JNI-name proxy cache to avoid allocations in the common “single proxy hit” case, while preserving alias ordering and missing-entry caching behavior.

Changes:

  • Add TrimmableTypeMap.TryGetTargetType() to return the first mapped target type without materializing all targets.
  • Change the JNI-name proxy cache to store either a single JavaPeerProxy or a JavaPeerProxy[] (aliases/misses), built via a new ref-based proxy collector.
  • Extend tests to validate allocation-free repeated lookups and the new cache entry shapes (single vs alias vs miss).
File Description
tests/​Mono.Android-Tests/​Mono.Android-Tests/​Java.Interop/​TrimmableTypeMapTypeManagerTests.cs Adds allocation and cache-shape tests for the new lookup/cache behavior.
tests/​Mono.Android-Tests/​Mono.Android-Tests/​Java.Interop/​TrimmableTypeMapRuntimeCoverageTests.cs Adds coverage asserting TryGetTargetType() returns the first alias-ordered target.
src/​Mono.Android/​Microsoft.Android.Runtime/​TrimmableTypeMapTypeManager.cs Switches the hot single-type lookup path to the new allocation-free TryGetTargetType().
src/​Mono.Android/​Microsoft.Android.Runtime/​TrimmableTypeMap.cs Reworks JNI-name proxy caching to store a single proxy directly, adds TryGetTargetType(), and introduces JniProxyCacheBuilder.
src/​Mono.Android/​Microsoft.Android.Runtime/​SingleUniverseTypeMap.cs Replaces iterator-based proxy enumeration with CollectProxyTypes(..., ref builder) to reduce allocations.
src/​Mono.Android/​Microsoft.Android.Runtime/​ITypeMap.cs Updates the typemap interface to the new ref-builder collection model.
src/​Mono.Android/​Microsoft.Android.Runtime/​AggregateTypeMap.cs Adapts aggregate proxy collection to forward into universe collectors using the ref-builder.

Comment thread src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMap.cs
simonrozsival and others added 5 commits September 1, 2026 13:09
Resolve the single callable-wrapper proxy before creating the JNI type so native registration uses one shared path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Pass resolved proxy instances to the cache builder so its Add operation is void while retaining one attribute materialization per proxy.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Expose a struct enumerable over cached proxy entries so multi-result JniTypeManager lookups no longer materialize a Type array.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Throw a clear InvalidOperationException when a fallback cache entry is not a JavaPeerProxy array, without adding work to the direct-proxy hot path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use an iterator over cached proxy entries instead of a custom struct enumerable while retaining allocation-free singular lookups.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Generated by Android PR Reviewer for #12619

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

❌ Reject

Found 1 error: the native-registration path now registers only the first callable wrapper in an alias group, leaving callbacks from additional ACW proxies unregistered. The direct-proxy cache shape and allocation-focused singular lookup are otherwise well targeted, with useful focused coverage.

CI is still in progress; the completed CLA, Android Tools Tests (Mac), and Java.Interop Tests (Mac) checks are passing.

Generated by Android PR Reviewer for #12619 · gpt56 · 138.7 AIC · ⌖ 8.85 AIC · ⊞ 25.7K
Comment /review to run again

Comment thread src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMap.cs Outdated
Register native methods for every callable-wrapper proxy in an alias cache entry while sharing one JNI type, with focused multi-wrapper coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Generated by Android PR Reviewer for #12619

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Needs Changes (CI pending)

Findings: 0 errors, 0 warnings, 1 suggestion. The cache specialization preserves lookup ordering, missing-entry behavior, and all-proxy native registration; the focused tests cover the new cache shapes and allocation goal. One XML comment should be corrected to describe the single-surviving-alias shape accurately.

CI is still in progress: the completed checks are green, with the platform build jobs still running.

Generated by Android PR Reviewer for #12619 · gpt56 · 96.8 AIC · ⌖ 13.2 AIC · ⊞ 25.7K
Comment /review to run again

Comment thread src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMap.cs
@simonrozsival simonrozsival added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label Sep 3, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@simonrozsival
simonrozsival merged commit fa8bbbe into main Sep 4, 2026
44 checks passed
@simonrozsival
simonrozsival deleted the simonrozsival-trimmable-typemap-performance branch September 4, 2026 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). trimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants