[CoreCLR] Remove robin-map from p/invoke override#12010
Conversation
Remove the CoreCLR p/invoke override dependency on robin-map by deleting the custom cache layer and generated precompiled p/invoke table. The precompiled CoreCLR path now resolves only the small internal symbol set explicitly, lets CoreCLR handle BCL native libraries, and falls back directly through the dotnet/android loader for other libraries. NativeAOT remains free of robin-map references, and MonoVM keeps its existing robin-map usage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/review |
|
✅ Android PR Reviewer completed successfully! |
Refresh BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc for the intended CoreCLR native size reduction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Separate the precompiled CoreCLR p/invoke override resolver by logical library: java-interop, xa-internal-api, and liblog. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🤖 Android PR Review
Independent pass over the native CoreCLR p/invoke-override changes — I verified the mechanics before reading the description. The core rewrite is correct.
Verified ✅
- Symbol completeness —
load_internal_symbolcovers all 28 entries from the removed generatedinternal_pinvokestable and matches theextern "C"set ininternal-pinvokes.hh; every string literal matches its identifier, nothing dropped. - Library-name matching — the new
== "java-interop" / "xa-internal-api" / "liblog" / "libSystem.*"comparisons are exactly the strings the deleted generator hashed into the old*_hashconstants. Behavior-equivalent. handle_jni_on_loadremoval — dead code on the CLR path (no callers;Java_JNI_OnLoadinclr/host/host.ccnever used it). NativeAOT keeps its own live copy. Clean.- robin-map removal — every remaining
ROBIN_MAP_DIR/tsl::reference is confined tosrc/native/mono/under the newif(IS_MONO_RUNTIME)guard; no dangling references anywhere insrc/native/clr/. - Cache removal — relying on CoreCLR's per-method p/invoke caching is sound, and build-time-known DSOs are still handle-cached inside
monodroid_dlopen, so droppingother_pinvoke_mapcauses no meaningfuldlopenrefcount regression. - Tabs/formatting, added includes, and inline macros all look correct.
Non-blocking suggestions 💡 (inline)
load_internal_symbolreintroduces a hand-maintained table with the same drift →abort_applicationfailure mode this PR removes for the BCL libs (#11530). Worth astatic_assert/cross-reference guard.- Test coverage gap — the only test targets
libmonosgen-2.0(MonoVM-only), so the rewritten CoreCLR fallback path has no on-device coverage.
CI
Checks are still pending on 00428d9 (draft PR) — I could not confirm green. Please make sure the CoreCLR and NativeAOT native builds plus the on-device p/invoke tests pass before merging.
Verdict: No blocking code issues found — 2 optional suggestions above. Nice cleanup: −633/+143 and one fewer external dependency on the CoreCLR path. 👍 (Confirm CI is green before un-drafting.)
Generated by Android PR Reviewer for #12010 · 383.9 AIC · ⌖ 27.3 AIC · ⊞ 6.8K
Comment /review to run again
Move the internal p/invoke missing-symbol abort into the library-specific resolvers so the dispatcher can return directly for each internal library. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR simplifies the CoreCLR native p/invoke override by removing the robin-map dependency and the custom p/invoke cache/table, relying instead on explicit handling for a small set of internal symbols plus the existing dotnet/android loader fallback for other libraries.
Changes:
- Remove CoreCLR’s robin-map-based p/invoke cache and associated include/compile plumbing.
- Replace the CoreCLR precompiled override’s generated internal table with explicit per-library symbol resolution, and route “other” libraries through
MonodroidDl::monodroid_dlopen/monodroid_dlsym. - Update size reference (
*.apkdesc) and adjust test commentary accordingly.
Show a summary per file
| File | Description |
|---|---|
| tests/Mono.Android-Tests/Mono.Android-Tests/Android.Runtime/PInvokeOverrideTests.cs | Updates test commentary to reflect new fallback resolution (no robin-map cache). |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc | Updates expected size baselines for CoreCLR build artifacts. |
| src/native/CMakeLists.txt | Makes ROBIN_MAP_DIR conditional on Mono runtime builds only. |
| src/native/clr/pinvoke-override/precompiled.cc | Reworks precompiled CoreCLR override to explicit symbol handling + loader fallback; removes generated include usage. |
| src/native/clr/pinvoke-override/pinvoke-tables.include | Deletes the generated CoreCLR internal-pinvoke table include. |
| src/native/clr/pinvoke-override/generate-pinvoke-tables.cc | Removes the CoreCLR pinvoke table generator source. |
| src/native/clr/pinvoke-override/dynamic.cc | Simplifies dynamic override path and routes unknown libraries via load_library_symbol. |
| src/native/clr/pinvoke-override/CMakeLists.txt | Removes robin-map include paths and compile definitions. |
| src/native/clr/include/host/pinvoke-override.hh | Removes robin-map types/caching and narrows the public API to load_library_symbol + override entrypoint. |
| src/native/clr/include/host/pinvoke-override-impl.hh | Removes robin-map caching logic; keeps direct dlopen/dlsym-based resolution via MonodroidDl. |
| src/native/clr/host/CMakeLists.txt | Drops robin-map include directories from CoreCLR host build. |
| .gitignore | Removes ignore entries for deleted CoreCLR pinvoke generator artifacts. |
Copilot's findings
- Files reviewed: 11/12 changed files
- Comments generated: 1
Summary
Removes the CoreCLR native p/invoke override dependency on
external/robin-map.The motivation is primarily dependency and code simplification, not size or startup wins. After #11537, CoreCLR no longer needs a hand-maintained BCL p/invoke table or a custom p/invoke cache in the precompiled override. CoreCLR already caches resolved p/invokes at the runtime/call-site level, and arbitrary fallback libraries can be resolved directly through the existing dotnet/android loader path.
CoreCLR now:
tsl::robin_map/external/robin-mapdependencyjava-interop,xa-internal-api, andliblognullptrfor BCL native libraries so CoreCLR's own resolver handles themMonodroidDl::monodroid_dlopen+monodroid_dlsymfor other librariesNativeAOT remains free of robin-map references. MonoVM keeps its existing robin-map usage.
Size impact
This is not a major app-size change. The size reduction is small but in the expected direction.
BuildReleaseArm64SimpleDotNet.CoreCLR.apkdescdotnet new maui --sample-contentRelease/CoreCLR/R2Randroid-arm64libmonodroid.so-17,400 raw / -3,584 ZIPThe committed
BuildReleaseArm64SimpleDotNet.CoreCLR.apkdescupdate reflects the expected CI size-reference change.Startup performance
No measurable startup-time difference.
Device: Samsung Galaxy A16 (
SM-A165F,arm64-v8a, API 36). Method: 30 interleaved cold-start pairs usingam start -W, comparing default Release/CoreCLR/R2Rdotnet new maui --sample-contentAPKs built frommainand this PR.mainPaired
current - mainTotalTime delta across the 30 measured pairs:Conclusion: startup is unchanged within measurement noise.
Validation
make prepare && make allon this PRmake prepare && make allonorigin/maindotnet new maui --sample-contentRelease/CoreCLR/R2R APK build on both local SDKsSM-A165F, API 36)dotnet build src/native/native-clr.csproj --nologo -v:minimal -p:AndroidSupportedTargetJitAbis=arm64-v8a -p:AndroidSupportedTargetAotAbis=arm64 -p:EnableNativeAnalyzers=falsedotnet build src/native/native-nativeaot.csproj --nologo -v:minimal -p:AndroidSupportedTargetJitAbis=arm64-v8a -p:AndroidSupportedTargetAotAbis=arm64 -p:EnableNativeAnalyzers=false