[XABT] Fix stale shrunk assemblies in the llvm-ir typemap path - #12342
Merged
Conversation
`_RemoveRegisterAttribute` copies `@(_ResolvedAssemblies)` into `@(_ShrunkAssemblies)`. Packaging reads the shrunk copies, while `mono-aot-cross` compiles the resolved assemblies. Two defects let those two sets diverge: * Ordering: the target ran before `_GenerateJavaStubs`, which invokes `RewriteMarshalMethods` and rewrites `@(_ResolvedAssemblies)` in place, removing the `cb_*` JNI callback fields. `_PostTrimmingPipeline` rewrites them again `AfterTargets="ILLink"`. * Invalidation: `Inputs` tracked `$(_AndroidLinkFlag)`, which is only touched by ILLink and so never changes when those post-link rewrites modify the assemblies. The result is an APK whose AOT images were built from assemblies with a different metadata `Field` table than the assemblies actually packaged. AOT encodes a static field reference as a class reference plus a `Field` table row (`encode_field_info` / `decode_field_info`), so one added or removed field shifts every later row. In dotnet#12267 the packaged `Mono.Android.dll` retained `Android.Widget.AbsListView::cb_getAdapter` while the AOT input did not, moving `Android.Runtime.AndroidTypeManager` from rows 984-987 to 985-988. `AndroidTypeManager..cctor` then resolved its `SFLDA` patch to row 985 - the instance field `jniAddNativeMethodRegistrationAttributePresent` instead of the static `prevent_delegate_gc_lock` - and Mono aborted during startup, before any test ran: * Assertion at mono/metadata/object.c:3109, condition `field->type->attrs & FIELD_ATTRIBUTE_STATIC' not met Mono cannot detect the mismatch on its own: its AOT staleness check compares the assembly MVID, and Cecil preserves the MVID across rewrites, so both copies look identical to it. `_RemoveRegisterAttributeCoreClr` in Microsoft.Android.Sdk.TypeMap.Trimmable.targets already keys `Inputs` off `@(_ResolvedAssemblies)`. This brings the llvm-ir path in line, which is why only the Mono leg regressed while CoreCLR passed. Validated on a Pixel 7a (arm64, API 36) with the Mono.Android.NET-Tests instrumentation, Release + `-p:UseMonoRuntime=true`, each run from a clean `obj`: * before: crash (5 runs, deterministic), linked/ 1767 rows vs linked/shrunk/ 1768 rows * after: 281 tests, 0 failed (2 runs), linked/ and shrunk/ both 1767 rows * control: reverting only these two attributes on the same built SDK restores both the crash and the 1767/1768 mismatch The shrunk copies were already rewritten on every build before this change, so tracking `@(_ResolvedAssemblies)` does not regress the incremental work in dotnet#12229. Fixes dotnet/runtime#131760 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 56a10519-c924-45fd-a767-83cd4e5f947a
BrzVlad
requested review from
jonathanpeppers and
simonrozsival
as code owners
August 11, 2026 11:26
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a build-order and incremental-build invalidation issue in the llvm-ir typemap pipeline that could cause “shrunk” assemblies (used for packaging) to diverge from the assemblies compiled by mono-aot-cross, leading to runtime AOT failures due to mismatched metadata field-table row indices.
Changes:
- Move
_RemoveRegisterAttributebehind_GenerateJavaStubsso it copies from the final, post-rewrite linked assemblies. - Improve incremental invalidation by keying
_RemoveRegisterAttributeoff@(_ResolvedAssemblies)(plus project/build cache inputs) instead of$(_AndroidLinkFlag). - Track the stamp file in
@(FileWrites)so it is cleaned reliably.
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Restore the Release MonoVM instrumentation lane now that the llvm-ir typemap path keeps packaged shrunk assemblies in sync with the AOT inputs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the existing link flag input while also tracking final rewritten assemblies and the resolved assembly set hash. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Member
|
/review |
Contributor
|
❌ Android PR Reviewer failed. Please review the logs for details. |
jonathanpeppers
approved these changes
Aug 11, 2026
Member
|
@dalexsoto review |
dalexsoto
approved these changes
Aug 11, 2026
dalexsoto
left a comment
Member
There was a problem hiding this comment.
The target ordering and invalidation changes keep packaged shrunk assemblies aligned with the Mono AOT inputs, and the stamp/output cleanup is coherent. No blocking issues found.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix stale shrunk assemblies in the llvm-ir typemap path and restore the Release MonoVM APK smoke test disabled in #12267.
_RemoveRegisterAttributecopies@(_ResolvedAssemblies)into@(_ShrunkAssemblies). Packaging reads the shrunk copies, whilemono-aot-crosscompiles the resolved assemblies. The two sets could diverge because:_RemoveRegisterAttributeran before_GenerateJavaStubs, which invokesRewriteMarshalMethodsand rewrites@(_ResolvedAssemblies)in place, removing thecb_*JNI callback fields._PostTrimmingPipelinecan also rewrite the linked assemblies after ILLink.$(_AndroidLinkFlag)tracks ILLink, but it does not observe those later in-place rewrites. Tracking only the link flag allowed the shrunk copies to remain up to date while the resolved assemblies changed.Changes
_RemoveRegisterAttributedepend on_GenerateJavaStubsso it copies the final rewritten assemblies.$(_AndroidLinkFlag)as an input for ILLink invalidation and additionally track:@(_ResolvedAssemblies)for post-link in-place rewrites.$(_ResolvedUserAssembliesHashFile)for changes to the resolved assembly set.$(_AndroidBuildPropertiesCache)and@(_AndroidMSBuildAllProjects)for relevant build/project changes.$(_RemoveRegisterFlag)to@(FileWrites)so clean/incremental-clean behavior tracks the stamp.Mono.Android.NET_Tests-MonoRelease MonoVM instrumentation lane that [main] Update dependencies from dotnet/dotnet, microsoft/testfx #12267 temporarily disabled.This aligns the llvm-ir path with the incremental-input model used by
_RemoveRegisterAttributeCoreClrinMicrosoft.Android.Sdk.TypeMap.Trimmable.targets, while retaining the existing ILLink sentinel.Failure mechanism
In #12267, the packaged
Mono.Android.dllretainedAndroid.Widget.AbsListView::cb_getAdapterwhile the AOT input did not. This shifted the metadataFieldtable rows forAndroid.Runtime.AndroidTypeManager.AndroidTypeManager..cctorthen resolved an AOTSFLDApatch to the instance fieldjniAddNativeMethodRegistrationAttributePresentinstead of the staticprevent_delegate_gc_lock, causing Mono to abort during startup before any tests ran:Mono's AOT staleness check did not catch the mismatch because it compares assembly MVIDs, and Cecil preserves the MVID across these rewrites.
Validation
Validated on a Pixel 7a (arm64, API 36) with
Mono.Android.NET-Tests, Release +-p:UseMonoRuntime=true, from cleanobjdirectories:Fixes dotnet/runtime#131760