[TrimmableTypeMap] Build pipeline + manifest generation#10980
[TrimmableTypeMap] Build pipeline + manifest generation#10980simonrozsival wants to merge 32 commits intodev/simonrozsival/trimmable-typemap-runtime-prfrom
Conversation
- JavaPeerProxy / JavaPeerProxy<T> — AOT-safe proxy attribute base - IAndroidCallableWrapper — RegisterNatives(JniType) for ACW types - JavaPeerContainerFactory<T> — AOT-safe array/list/collection/dict - TypeMapException — error reporting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Proxy types now extend JavaPeerProxy<T> instead of JavaPeerProxy. TargetType and GetContainerFactory() are inherited from the generic base. Generator references TrimmableTypeMap for ActivateInstance and RegisterMethod. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add TrimmableTypeMap class with core typemap functionality: TryGetType, TryCreatePeer, GetInvokerType, GetContainerFactory, ActivateInstance. Add TrimmableTypeMapTypeManager delegating to TrimmableTypeMap. Rename ManagedValueManager to JavaMarshalValueManager. Add proxy-based peer creation in TryConstructPeer via TrimmableTypeMap.TryCreatePeer. Add RuntimeFeature.TrimmableTypeMap feature switch with ILLink substitutions. Wire into JNIEnvInit (CoreCLR) and JavaInteropRuntime + JreRuntime (NativeAOT). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add registerNatives(Class) native method to mono.android.Runtime.java so JCW static initializer blocks can trigger native method registration. Add to TrimmableTypeMap: - RegisterBootstrapNativeMethod() registers the JNI callback during init - OnRegisterNatives() resolves the proxy and calls IAndroidCallableWrapper.RegisterNatives(JniType) to bind UCO ptrs - RegisterMethod() helper for per-method registration (TODO: batch) Wire RegisterBootstrapNativeMethod() call in JNIEnvInit after runtime creation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When TrimmableTypeMap is available, use JavaPeerContainerFactory from the proxy for IList<T>, ICollection<T>, IDictionary<K,V> marshaling and array creation instead of MakeGenericType/Array.CreateInstance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ranks 1-3: direct new T[], T[][], T[][][] — fully AOT-safe. Rank 4+: when dynamic code is supported (CoreCLR), falls back to MakeArrayType + CreateInstanceFromArrayType. Throws on NativeAOT. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add missing using Android.Runtime for JniHandleOwnership - Add DynamicallyAccessedMembers annotations required by JavaList<T>, JavaCollection<T>, JavaDictionary<K,V> on factory type parameters - Fix IJniNameProviderAttribute lookup (not an Attribute, use GetCustomAttributes instead of GetCustomAttribute<T>) - Fix JniType constructor (takes string, not JniObjectReference) - Restore #pragma warning disable IL3050 for Array.CreateInstance fallback path - Suppress IL2073 on GetInvokerType (invoker types preserved by MarkJavaObjects trimmer step) Build succeeds locally. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pass TrimmableTypeMap via constructor instead of settable property. Use Interlocked.CompareExchange for single-instance safety. Keep RegisterBootstrapNativeMethod as separate call (JNI runtime must be initialized first). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Updated from macOS-7 CI build 13601673. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ypeNameFromClass - ActivateInstance: use JNI GetObjectClass + GetJniTypeNameFromClass to find proxy type via the TypeMap dictionary instead of targetType.GetCustomAttribute (the self-application attribute is on the proxy, not the target) - Pre-load per-assembly TypeMap DLLs via TypeMapAssemblyTarget attributes before GetOrCreateExternalTypeMapping (Android assembly store needs explicit probing) - Fix GetJniTypeNameFromInstance → GetJniTypeNameFromClass in OnRegisterNatives (nativeClassHandle is a jclass, not a jobject) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- JNIEnvInit: wrap RegisterBootstrapNativeMethod in explicit 'if (RuntimeFeature.TrimmableTypeMap)' guard instead of null-conditional operator, so the trimmer can eliminate it when the feature is disabled - TryCreatePeer: look up proxy via JNI class name from the TypeMap dictionary instead of type.GetCustomAttribute (the self-application attribute is on the proxy type, not the managed target type) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Both RegisterAttribute and JniTypeSignatureAttribute implement IJniNameProviderAttribute, so a single GetCustomAttributes check covers both. Made the method internal+static so TrimmableTypeMapTypeManager.GetSimpleReferences can reuse it instead of duplicating the attribute lookup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Build pipeline changes for the trimmable typemap, discovered during end-to-end HelloWorld experiment. Scanner/generator fixes: - Derive UCO callback names from [Register] Connector field (e.g. 'GetOnCreate_Landroid_os_Bundle_Handler' → 'n_OnCreate_Landroid_os_Bundle_') - Emit self-application [ProxyType] custom attribute on proxy types for GetCustomAttribute<JavaPeerProxy>() to work - Use CRC64-Jones (Crc64Helper) for package name hashing to match the legacy JCW generator convention Target restructuring (following PoC pattern): - _GenerateJavaStubs (outer build): runs GenerateTrimmableTypeMap using @(ReferencePath) as input (available without inner builds) - _AddTrimmableTypeMapAssembliesToStore (outer build, BeforeTargets=_BuildApkEmbed): adds per-ABI entries to _BuildApkResolvedUserAssemblies - _RemoveRegisterAttribute override: simple copy to shrunk/ Task fixes: - Removed IsMonoAndroidAssembly filter (ReferencePath items lack this metadata) - Added framework assembly filter for JCW generation (user types only) - GenerateNativeApplicationConfigSources: tolerate trimmed JNIEnvInit methods - GenerateEmptyTypemapStub: LLVM IR symbols for libmonodroid.so Native: - C++ Host::Java_mono_android_Runtime_registerNatives no-op stub Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Demonstrates the trimmable typemap end-to-end. Requires two remaining workarounds in trimmable-override.targets: 1. _TrimmerFeatureSettings for TrimmableTypeMap=true 2. _PatchBundledAssembliesSize (assembly store array sizing) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…flows correctly RuntimeHostConfigurationOption with Trim='true' already flows to _TrimmerFeatureSettings via the ILLink targets. The workaround was unnecessary — only the assembly store array sizing hack remains. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The CRC64-Jones change was unnecessary. System.IO.Hashing.Crc64 (CRC-64/XZ) produces the same package name hash as the legacy JCW generator when given the correct input assemblies. The previous mismatch was caused by the scanner receiving incomplete assembly inputs (empty _ResolvedAssemblies), not by the hash algorithm. With the restructured targets using @(ReferencePath), the scanner sees all assemblies and produces matching CRC hashes. Removed Crc64Helper shared source files and AllowUnsafeBlocks from the csproj. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| <!-- Patch bundled assemblies array size for TypeMap DLLs --> | ||
| <Target Name="_PatchBundledAssembliesSize" AfterTargets="_GeneratePackageManagerJava" | ||
| Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' "> | ||
| <Exec Command="sed -i '' 's/\[\([0-9]*\) x %struct.AssemblyStoreSingleAssemblyRuntimeData\]/[256 x %struct.AssemblyStoreSingleAssemblyRuntimeData]/g' $(IntermediateOutputPath)android/environment.*.ll" |
There was a problem hiding this comment.
this is pure evil 👀
There was a problem hiding this comment.
Already removed in a prior commit ✅
TrimmableTypeMap and TypeMappingEntryAssembly feature switches are now declared in Microsoft.Android.Sdk.TypeMap.Trimmable.targets, not in the app csproj. The only user-facing property is _AndroidTypeMapImplementation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move _GenerateTrimmableTypeMap to AfterTargets=_ResolveAssemblies - CoreCLR targets: add to ManagedAssemblyToLink + --typemap-entry-assembly - Remove all custom descriptors (ILLink handles TypeMap natively) - Minimal sample csproj (only _AndroidTypeMapImplementation) ILLink processes TypeMap DLLs correctly (they appear in linked/). Remaining issue: publish conflict resolution sees duplicate relative paths for TypeMap DLLs in linked/ output (missing metadata). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refactor: Initialize sets args->registerJniNativesFn when the legacy path is active (RuntimeFeature.TrimmableTypeMap == false). When TrimmableTypeMap is true, the field is null — the trimmable path handles registration via RegisterBootstrapNativeMethod (managed). This eliminates the create_delegate call for RegisterJniNatives, allowing the trimmer to remove it in the trimmable path without causing a native abort. Also: fix typedef ordering in managed-interface.hh, guard the jnienv_register_jni_natives call site for null. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…argets - BeforeTargets=PrepareForILLink (not _ComputeManagedAssemblyToLink which doesn't exist in the Android SDK targets) - Set DestinationSubPath on ManagedAssemblyToLink items - Add _AddTrimmableTypeMapAssembliesToStore for assembly store injection - Remove ErrorOnDuplicatePublishOutputFiles hack from sample Remaining: JNIEnvInit.Initialize trimmed by ILLink when TypeMap DLLs are processed. This is a pre-existing issue (native create_delegate contract) that was masked by not processing TypeMap DLLs before. Needs ILLink descriptor in Mono.Android for native UCO methods. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add PreserveLists/Trimmable.CoreCLR.xml with JNIEnvInit.Initialize (native entry point called via create_delegate) - TrimmerRootDescriptor in shared Trimmable.targets - Use PrepareForILLink hook (not _ComputeManagedAssemblyToLink which doesn't exist in Android SDK targets) - DestinationSubPath on ManagedAssemblyToLink items resolves NETSDK1152 - Remove ErrorOnDuplicatePublishOutputFiles from sample csproj Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ReferencePath and the app assembly are available after CoreCompile in the outer build. Using AfterTargets=_ResolveAssemblies was wrong — ReferencePath is empty at that point. All 3 TypeMap DLLs now generated (_HelloTrimmable.TypeMap.dll, _Mono.Android.TypeMap.dll, _Microsoft.Android.TypeMaps.dll). JCW files generated and copied. ILLink processes TypeMap DLLs. App runs on device (1.47s) with NO LinkerDescriptor.xml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| _GenerateJavaStubs: lightweight — copies JCW files and generates stubs. | ||
| TypeMap generation already happened via _GenerateTrimmableTypeMap. | ||
| --> | ||
| <Target Name="_GenerateJavaStubs" |
There was a problem hiding this comment.
I don't know if this is the right name for this target. It is the same one we use it the LLVM IR typemap, but I think it's doing something else and that might be confusing. I think using a different name would be better.
There was a problem hiding this comment.
We need to keep the name _GenerateJavaStubs because BuildOrder.targets references it in _PrepareBuildApkDependsOnTargets. Updated the comment to explain why the trimmable path reuses this target name (2fa1c2e).
Derives callback name from [Register] Connector field: 'GetOnCreate_Landroid_os_Bundle_Handler' → 'n_OnCreate_Landroid_os_Bundle_' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Read trimmed TypeMap DLLs from linked/ (ILLink output) and add them to both _ResolvedAssemblies (for assembly count) and _BuildApkResolvedUserAssemblies (for assembly store with per-ABI metadata). Removed: - trimmable-override.targets (sed patch for assembly store sizing) - Directory.Build.targets - AdditionalAssemblyCount task property Sample csproj is now completely clean — only _AndroidTypeMapImplementation. App runs on device (743ms) with zero workarounds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| <Target Name="_ConfigureTrimmableTypeMapForLinker" | ||
| BeforeTargets="PrepareForILLink;_RunILLink" | ||
| DependsOnTargets="_GenerateTrimmableTypeMap" | ||
| Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' "> |
There was a problem hiding this comment.
this file would not be loaded if the type map implementation wasn't "trimmable", so this condition should be removed.
| <Target Name="_AddTrimmableTypeMapToLinker" | ||
| BeforeTargets="PrepareForILLink;_RunILLink" | ||
| DependsOnTargets="_GenerateTrimmableTypeMap" | ||
| Condition=" '$(_AndroidTypeMapImplementation)' == 'trimmable' "> |
There was a problem hiding this comment.
this file would not be loaded if the type map implementation wasn't "trimmable", so this condition should be removed.
Replace duplicated per-ABI blocks with a single batched ItemGroup derived from _BuildTargetAbis. This eliminates the copy-paste duplication and uses MSBuild item batching over an ABI→RID mapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the standalone HelloTrimmable sample and add the CoreCLR + trimmable typemap properties to the existing HelloWorld sample instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…targets The file is only imported when the condition is already true (gated by the parent import in Xamarin.Android.Common.targets). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
e2214d6 to
483dc03
Compare
9475135 to
483dc03
Compare
…tiveApplicationConfigSources The trimmable _GenerateJavaStubs was missing: 1. ABI/RuntimeIdentifier metadata on TypeMap _ResolvedAssemblies items (required by CreateAssemblyStore) 2. GenerateNativeApplicationConfigSources call (builds assembly hash table) 3. _DefineBuildTargetAbis dependency (provides @(_BuildTargetAbis)) Now TypeMap DLLs flow through the full assembly pipeline and appear in libassembly-store.so with correct hash entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
12a1c2b to
4d55775
Compare
…l path MSBuild adds literal paths even when files don't exist. Use _Microsoft.Android.TypeMap*.dll wildcard to avoid the issue. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
76a490e to
aad2ddb
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
24e4399 to
df43059
Compare
…from typemap/ _AddTrimmableTypeMapAssembliesToStore now batches over @(_BuildTargetAbis) to add TypeMap DLLs for each ABI. Falls back from linked/ (ILLink output) to typemap/ (pre-trim) for Debug builds where ILLink doesn't run. _GenerateJavaStubs sets _TypeMapFirstAbi/_TypeMapFirstRid properties and passes TypeMap DLLs to GenerateNativeApplicationConfigSources via a local item group (avoiding duplicate entries in _ResolvedAssemblies). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
df43059 to
faa340e
Compare
…tyle - Fix ConfigChangesToString: correct hex values for grammaticalGender (0x8000), fontWeightAdjustment (0x10000000), fontScale (0x40000000). Remove invalid 0x10000. - Fix HasPublicParameterlessCtor: use MemberAccessMask to properly exclude protected/internal constructors (was incorrectly accepting them). - Targets: use ->Count() for empty checks, Condition attribute first, add FileWrites for _TypeMapAssemblySource. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Build pipeline fixes and manifest generation for the trimmable typemap feature. This PR builds on #10967 (runtime changes).
Build pipeline (original scope)
GenerateTrimmableTypeMaptask (SRM-based scanner + IL generator)_RemoveRegisterAttributeoverrideRuntimeHostConfigurationOptionfor TrimmableTypeMap + TypeMappingEntryAssemblyPreserveLists/Trimmable.CoreCLR.xmlfor JNIEnvInit.Initialize_AndroidTypeMapImplementation=trimmableManifest generation (#10807)
JavaPeerScannerextended to capture component attributesTrimmableManifestGenerator: data-driven property mapping (7 static arrays, 9 enum converters)[Activity],[Service],[BroadcastReceiver],[ContentProvider]with full properties,[IntentFilter],[MetaData][Permission],[UsesPermission],[UsesFeature],[UsesLibrary],[UsesConfiguration],[Property],[Application]ManifestPlaceholders,CheckedBuild/debuggable,ApplicationJavaClassFiles changed
AssemblyIndex.cs,JavaPeerInfo.cs,JavaPeerScanner.csTypeMapAssemblyEmitter.cs,GenerateTrimmableTypeMap.csTrimmableManifestGenerator.cs(new)Trimmable.targets,Trimmable.CoreCLR.targetshost.cc,host.hh,managed-interface.hhTrimmableManifestGeneratorTests.cs(new, 30 tests)GenerateEmptyTypemapStub.cs,GenerateNativeApplicationConfigSources.cs,PreserveLists/Trimmable.CoreCLR.xml,ApplicationRegistration.Trimmable.javaDepends on