Skip to content

[Java.Interop] Use native UTF-8 JNI remaps - #12795

Merged
simonrozsival merged 9 commits into
mainfrom
simonrozsival-optimize-jni-remapping
Sep 18, 2026
Merged

simonrozsival merged 9 commits into
mainfrom
simonrozsival-optimize-jni-remapping

Conversation

@simonrozsival

@simonrozsival simonrozsival commented Sep 15, 2026

Copy link
Copy Markdown
Member

Motivation

The existing Intune/MAM JNI method-remapping path stores target type and method names as stable NUL-terminated UTF-8 strings in generated native data. The old path materialized those names as managed UTF-16 strings and then encoded them back to UTF-8 for FindClass and GetMethodID.

That round trip is unnecessary and becomes more important as remapping is reused by larger consumers such as R8.

Approach

  • Add pointer-backed target type, method-name, and method-signature values to ReplacementMethodInfo.
  • Keep pointer and string representations independent so reading a compatibility string property does not implicitly decode native memory.
  • Add JniType lookup paths for pointer/pointer and mixed pointer/span member names and signatures.
  • Let JniPeerMembers retain a replacement type pointer and use it directly for FindClass and later member-remapping lookups.
  • Keep native pointers in JniMethodInfo Debug metadata and decode them only if Name, Signature, or ToString() is explicitly requested.
  • Retain the existing string/span paths for custom JniTypeManager implementations.
  • Document UTF-8 encoding, NUL termination, ownership, and lifetime requirements for every pointer API.

The successful generated-remapping path therefore passes the pregenerated UTF-8 type, method name, and optional signature directly to JNI without copying them or converting them to a managed string.

This PR is method-only and does not add R8, field remapping, reverse-type mapping, inherited-member fallback, or NativeAOT remapping support.

Relationship to other PRs

Validation

  • Java.Interop Debug build.
  • Java.Interop JniPeerMembersTests: 12 passed, 1 skipped.
  • The JVM fixture exercises stable unmanaged UTF-8 type/name/signature storage, signature fallback, instance/static lookup, and instance-to-static remapping.

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

🟡 Changes recommended

Unresolved remapping wiring, fast-path, diagnostic, and test-coverage issues remain.

Get a fresh assessment by requesting another Copilot review.

Review tier: Lite
Findings: 3 Medium severity · 1 Low severity

Open (4)
What changed in this PR

This pull request adds native UTF-8 pointer support for Java.Interop JNI remapping to reduce managed string conversions.

Changes:

  • Adds pointer-backed remapping metadata and lookup overloads.
  • Updates instance/static method and field remapping.
  • Updates the unshipped API baseline.
File Description
external/​Java.Interop/​src/​Java.Interop/​PublicAPI.Unshipped.txt Records new UTF-8 pointer APIs.
external/​Java.Interop/​src/​Java.Interop/​Java.Interop/​JniType.cs Adds native pointer lookup overloads.
external/​Java.Interop/​src/​Java.Interop/​Java.Interop/​JniRuntime.JniTypeManager.cs Adds pointer-backed replacement metadata.
external/​Java.Interop/​src/​Java.Interop/​Java.Interop/​JniPeerMembers.JniStaticMethods.cs Updates static method remapping.
external/​Java.Interop/​src/​Java.Interop/​Java.Interop/​JniPeerMembers.JniStaticFields.cs Updates static field remapping.
external/​Java.Interop/​src/​Java.Interop/​Java.Interop/​JniPeerMembers.JniInstanceMethods.cs Updates instance method and constructor remapping.
external/​Java.Interop/​src/​Java.Interop/​Java.Interop/​JniPeerMembers.JniInstanceFields.cs Updates instance field remapping.
external/​Java.Interop/​src/​Java.Interop/​Java.Interop/​JniPeerMembers.cs Adds shared remapping helper dispatch.

Comment thread external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs Outdated
Comment thread external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs Outdated
Comment thread external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs Outdated
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Generated by Android PR Reviewer for #12795

@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

Findings: 0 errors · 2 warnings · 0 suggestions

The mixed UTF-8/string fallback handling added in the follow-up commit resolves the earlier all-or-nothing fast-path issue, and the JNI exception cleanup paths remain consistent with the existing implementation. Before merging, the new public raw-pointer contract should explicitly define its lifetime/ownership requirements, and the pointer-backed and mixed lookup branches need direct regression coverage.

CI is still in progress with no failures reported so far; Java.Interop tests have passed on macOS and Windows.

Generated by Android PR Reviewer for #12795 · copilot · gpt56 · 132.3 AIC · ⌖ 11.4 AIC · ⊞ 21K
Comment /review to run again

Comment thread external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniTypeManager.cs Outdated
@simonrozsival
simonrozsival force-pushed the simonrozsival-optimize-jni-remapping branch from 0e742f9 to 2857f0c Compare September 16, 2026 08:39
@simonrozsival
simonrozsival removed this pull request from stack #12797 September 16, 2026 08:40
@simonrozsival
simonrozsival changed the base branch from simonrozsival-fix-r8-obfuscation-policy to main September 16, 2026 08:40
@simonrozsival
simonrozsival added this pull request to stack #12805 September 16, 2026 08:40
@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 16, 2026
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • azcliprod.blob.core.windows.net

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "azcliprod.blob.core.windows.net"

See Network Configuration for more information.

Generated by Android PR Reviewer for #12795

@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

Findings: 1 error · 1 warning · 0 suggestions

The pointer/span JNI lookup paths preserve the intended allocation-free remapping behavior, including mixed native/fallback operands, and the Java.Interop macOS and Windows CI lanes pass. However, the new lazy DEBUG metadata retains unmanaged pointers beyond the lifetime currently promised by the public API, which can produce a use-after-free in diagnostics. The failure diagnostic also reports the string representation even when JNI lookup used the independent UTF-8 representation.

CI is not green: Azure build 1599102 failed in MAUI Tests MAUI Integration; all other reported lanes passed. The AZDO failure details were unavailable because this environment has no Azure DevOps login, so I could not determine whether that gate is related to this PR.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • azcliprod.blob.core.windows.net

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "azcliprod.blob.core.windows.net"

See Network Configuration for more information.

Generated by Android PR Reviewer for #12795 · copilot · gpt56 · 147.2 AIC · ⌖ 11.4 AIC · ⊞ 21K
Comment /review to run again

Comment thread external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs Outdated
@simonrozsival simonrozsival removed the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label Sep 16, 2026
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@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 16, 2026
@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Generated by Android PR Reviewer for #12795

@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

Findings: 0 errors · 1 warning · 0 suggestions

The UTF-8 pointer lifetime contract is now explicit, JNI lookups preserve pointer-backed and mixed operands correctly, and all 44 CI checks are green. The remaining gap is regression coverage: converting the shared fixture entirely to pointer-backed outputs removes coverage of the retained string compatibility path and leaves the managed-name/native-signature branch unexercised.

Generated by Android PR Reviewer for #12795 · copilot · gpt56 · 105.2 AIC · ⌖ 11.2 AIC · ⊞ 21K
Comment /review to run again

Comment thread external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.cs Outdated
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • azcliprod.blob.core.windows.net

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "azcliprod.blob.core.windows.net"

See Network Configuration for more information.

Generated by Android PR Reviewer for #12795

@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

Findings: 0 errors · 0 warnings · 1 suggestion

The UTF-8 pointer paths preserve the managed-string fallback, handle mixed pointer/span operands consistently, and now carry an explicit runtime-scoped lifetime contract. The remaining suggestion is to document pointer-over-string precedence for custom JniTypeManager implementations.

CI is still in progress: 19 of 44 checks have passed, 24 are running, and 1 is queued; no failures are currently reported. The Java.Interop macOS and Windows test lanes have passed.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • azcliprod.blob.core.windows.net

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "azcliprod.blob.core.windows.net"

See Network Configuration for more information.

Generated by Android PR Reviewer for #12795 · copilot · gpt56 · 148.6 AIC · ⌖ 8.4 AIC · ⊞ 18.1K
Comment /review to run again

simonrozsival and others added 3 commits September 18, 2026 11:21
Carry stable UTF-8 replacement type and method-name pointers through remapping results and use them directly for JNI lookup while preserving string fallbacks.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Document the unmanaged memory ownership and lifetime contract for remapping pointers, and exercise pointer-backed instance/static method lookups with signature fallback in the JVM tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Carry replacement type, method name, and signature pointers through JniPeerMembers and JNI lookup without eagerly decoding native memory. Preserve string-based compatibility paths and defer decoding to explicit diagnostics and Debug metadata access.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
simonrozsival and others added 4 commits September 18, 2026 11:21
Require replacement pointers to remain stable for the associated runtime because cached JNI metadata may retain them, and use UTF-8-first precedence when formatting failed lookup diagnostics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The UTF-8-signature compatibility case relies on the test fixture's custom JniTypeManager, which Android does not support.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the mixed representation coverage in the host type manager while registering the equivalent generated remap for Android test runs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@simonrozsival
simonrozsival force-pushed the simonrozsival-optimize-jni-remapping branch from b3d3e61 to f12babb Compare September 18, 2026 09:21
simonrozsival and others added 2 commits September 18, 2026 11:50
Return string and UTF-8 replacement representations from one virtual lookup so pointer-aware managers can report handled misses without triggering a duplicate string-table search.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Route string replacement queries through the combined lookup and make non-zero UTF-8 pointers authoritative when an override supplies both representations.

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

@jonathanpeppers jonathanpeppers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I just had the one question, otherwise looks good. 👍

Comment on lines 21 to 24
#if DEBUG
string? name, signature;
IntPtr nameUtf8, signatureUtf8;
#endif // !DEBUG

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is it worth having the DEBUG values here at all? Or are they useful during development?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yeah, only useful during development

@simonrozsival
simonrozsival merged commit bd53332 into main Sep 18, 2026
44 checks passed
@simonrozsival
simonrozsival deleted the simonrozsival-optimize-jni-remapping branch September 18, 2026 19:13
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).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants