Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public void Generate (IReadOnlyList<string> perAssemblyTypeMapNames, bool useSha
pe.EmitIgnoresAccessChecksToAttribute (accessTargets);

// Emit TypeMapLoader class with Initialize() method
EmitTypeMapLoader (pe, anchorTypeHandle, perAssemblyTypeMapNames, useSharedTypemapUniverse, maxArrayRank);
EmitTypeMapLoader (pe, anchorTypeHandle, perAssemblyTypeMapNames, useSharedTypemapUniverse, maxArrayRank, assemblyName);

pe.WritePE (stream);
}
Expand Down Expand Up @@ -201,7 +201,7 @@ static void EmitAssemblyTargetAttribute (PEAssemblyBuilder pe, MemberReferenceHa
pe.Metadata.AddCustomAttribute (EntityHandle.AssemblyDefinition, ctorRef, blobHandle);
}

static void EmitTypeMapLoader (PEAssemblyBuilder pe, EntityHandle anchorTypeHandle, IReadOnlyList<string> perAssemblyTypeMapNames, bool useSharedTypemapUniverse, int maxArrayRank)
static void EmitTypeMapLoader (PEAssemblyBuilder pe, EntityHandle anchorTypeHandle, IReadOnlyList<string> perAssemblyTypeMapNames, bool useSharedTypemapUniverse, int maxArrayRank, string assemblyName)
{
var metadata = pe.Metadata;

Expand Down Expand Up @@ -243,21 +243,21 @@ static void EmitTypeMapLoader (PEAssemblyBuilder pe, EntityHandle anchorTypeHand
if (maxArrayRank > 0) {
var initializeRef = AddInitializeSingleWithArraysRef (pe, trimmableTypeMapRef, iReadOnlyDictOpenRef, systemTypeRef);
EmitInitializeWithSingleTypeMap (pe, anchorTypeHandle, getExternalMemberRef, getProxyMemberRef,
initializeRef, externalDictTypeSpec, externalDictArrayTypeSpec, perAssemblyTypeMapNames, maxArrayRank);
initializeRef, externalDictTypeSpec, externalDictArrayTypeSpec, perAssemblyTypeMapNames, maxArrayRank, assemblyName);
} else {
var initializeRef = AddInitializeSingleNoArraysRef (pe, trimmableTypeMapRef, iReadOnlyDictOpenRef, systemTypeRef);
EmitInitializeWithSingleTypeMapNoArrays (pe, anchorTypeHandle, getExternalMemberRef, getProxyMemberRef, initializeRef);
EmitInitializeWithSingleTypeMapNoArrays (pe, anchorTypeHandle, getExternalMemberRef, getProxyMemberRef, initializeRef, assemblyName);
}
} else {
var proxyDictTypeSpec = MakeIReadOnlyDictTypeSpec (pe, iReadOnlyDictOpenRef, systemTypeRef, keyIsString: false);
if (maxArrayRank > 0) {
var initializeRef = AddInitializeAggregateWithArraysRef (pe, trimmableTypeMapRef, iReadOnlyDictOpenRef, systemTypeRef);
EmitInitializeWithAggregateTypeMap (pe, perAssemblyTypeMapNames, getExternalMemberRef, getProxyMemberRef,
initializeRef, externalDictTypeSpec, proxyDictTypeSpec, externalDictArrayTypeSpec, iReadOnlyDictOpenRef, systemTypeRef, maxArrayRank);
initializeRef, externalDictTypeSpec, proxyDictTypeSpec, externalDictArrayTypeSpec, iReadOnlyDictOpenRef, systemTypeRef, maxArrayRank, assemblyName);
} else {
var initializeRef = AddInitializeAggregateNoArraysRef (pe, trimmableTypeMapRef, iReadOnlyDictOpenRef, systemTypeRef);
EmitInitializeWithAggregateTypeMapNoArrays (pe, perAssemblyTypeMapNames, getExternalMemberRef, getProxyMemberRef,
initializeRef, externalDictTypeSpec, proxyDictTypeSpec, iReadOnlyDictOpenRef, systemTypeRef);
initializeRef, externalDictTypeSpec, proxyDictTypeSpec, iReadOnlyDictOpenRef, systemTypeRef, assemblyName);
}
}
}
Expand All @@ -274,7 +274,8 @@ static void EmitInitializeWithAggregateTypeMap (PEAssemblyBuilder pe,
TypeSpecificationHandle externalDictTypeSpec, TypeSpecificationHandle proxyDictTypeSpec,
TypeSpecificationHandle externalDictArrayTypeSpec,
TypeReferenceHandle iReadOnlyDictOpenRef, TypeReferenceHandle systemTypeRef,
int maxArrayRank)
int maxArrayRank,
string assemblyName)
{
var count = perAssemblyTypeMapNames.Count;

Expand All @@ -292,6 +293,7 @@ static void EmitInitializeWithAggregateTypeMap (PEAssemblyBuilder pe,
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
sig => sig.MethodSignature ().Parameters (0, rt => rt.Void (), p => { }),
encoder => {
EmitSetTypeMappingEntryAssembly (pe, encoder, assemblyName);
// var typeMaps = new IReadOnlyDictionary<string, Type>[N]; (loc 0)
EmitNewArrayLocal (encoder, count, externalDictTypeSpec, slot: 0);
EmitFillArrayLocal (encoder, count, getExternalSpecs, slot: 0);
Expand Down Expand Up @@ -345,7 +347,8 @@ static void EmitInitializeWithAggregateTypeMapNoArrays (PEAssemblyBuilder pe,
MemberReferenceHandle getExternalMemberRef, MemberReferenceHandle getProxyMemberRef,
MemberReferenceHandle initializeRef,
TypeSpecificationHandle externalDictTypeSpec, TypeSpecificationHandle proxyDictTypeSpec,
TypeReferenceHandle iReadOnlyDictOpenRef, TypeReferenceHandle systemTypeRef)
TypeReferenceHandle iReadOnlyDictOpenRef, TypeReferenceHandle systemTypeRef,
string assemblyName)
{
var count = perAssemblyTypeMapNames.Count;

Expand All @@ -363,6 +366,7 @@ static void EmitInitializeWithAggregateTypeMapNoArrays (PEAssemblyBuilder pe,
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
sig => sig.MethodSignature ().Parameters (0, rt => rt.Void (), p => { }),
encoder => {
EmitSetTypeMappingEntryAssembly (pe, encoder, assemblyName);
EmitNewArrayLocal (encoder, count, externalDictTypeSpec, slot: 0);
EmitFillArrayLocal (encoder, count, getExternalSpecs, slot: 0);

Expand Down Expand Up @@ -432,7 +436,8 @@ static void EmitInitializeWithSingleTypeMap (PEAssemblyBuilder pe, EntityHandle
MemberReferenceHandle initializeRef,
TypeSpecificationHandle externalDictTypeSpec, TypeSpecificationHandle externalDictArrayTypeSpec,
IReadOnlyList<string> perAssemblyTypeMapNames,
int maxArrayRank)
int maxArrayRank,
string assemblyName)
{
var getExternalSpec = MakeGenericMethodSpec (pe, getExternalMemberRef, anchorTypeHandle);
var getProxySpec = MakeGenericMethodSpec (pe, getProxyMemberRef, anchorTypeHandle);
Expand All @@ -441,6 +446,7 @@ static void EmitInitializeWithSingleTypeMap (PEAssemblyBuilder pe, EntityHandle
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
sig => sig.MethodSignature ().Parameters (0, rt => rt.Void (), p => { }),
encoder => {
EmitSetTypeMappingEntryAssembly (pe, encoder, assemblyName);
// TrimmableTypeMap.Initialize(GetExternal<JL.Object>(), GetProxy<JL.Object>(), arrayMapsByAssemblyAndRank-or-null)
encoder.Call (getExternalSpec, parameterCount: 0, returnsValue: true);
encoder.Call (getProxySpec, parameterCount: 0, returnsValue: true);
Expand All @@ -456,7 +462,8 @@ static void EmitInitializeWithSingleTypeMap (PEAssemblyBuilder pe, EntityHandle
/// </summary>
static void EmitInitializeWithSingleTypeMapNoArrays (PEAssemblyBuilder pe, EntityHandle anchorTypeHandle,
MemberReferenceHandle getExternalMemberRef, MemberReferenceHandle getProxyMemberRef,
MemberReferenceHandle initializeRef)
MemberReferenceHandle initializeRef,
string assemblyName)
{
var getExternalSpec = MakeGenericMethodSpec (pe, getExternalMemberRef, anchorTypeHandle);
var getProxySpec = MakeGenericMethodSpec (pe, getProxyMemberRef, anchorTypeHandle);
Expand All @@ -465,6 +472,7 @@ static void EmitInitializeWithSingleTypeMapNoArrays (PEAssemblyBuilder pe, Entit
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig,
sig => sig.MethodSignature ().Parameters (0, rt => rt.Void (), p => { }),
encoder => {
EmitSetTypeMappingEntryAssembly (pe, encoder, assemblyName);
encoder.Call (getExternalSpec, parameterCount: 0, returnsValue: true);
encoder.Call (getProxySpec, parameterCount: 0, returnsValue: true);
encoder.Call (initializeRef, parameterCount: 2);
Expand All @@ -486,6 +494,22 @@ static MemberReferenceHandle AddInitializeSingleNoArraysRef (PEAssemblyBuilder p
pe.Metadata.GetOrAddString ("Initialize"), pe.Metadata.GetOrAddBlob (blob));
}

static void EmitSetTypeMappingEntryAssembly (PEAssemblyBuilder pe, TrackedInstructionEncoder encoder, string assemblyName)
{
var appContextRef = pe.Metadata.AddTypeReference (pe.SystemRuntimeRef,
pe.Metadata.GetOrAddString ("System"), pe.Metadata.GetOrAddString ("AppContext"));
var setDataRef = pe.AddMemberRef (appContextRef, "SetData",
sig => sig.MethodSignature ().Parameters (2,
rt => rt.Void (),
p => {
p.AddParameter ().Type ().String ();
p.AddParameter ().Type ().Object ();
}));
encoder.LoadString (pe.Metadata.GetOrAddUserString ("System.Runtime.InteropServices.TypeMappingEntryAssembly"));
encoder.LoadString (pe.Metadata.GetOrAddUserString (assemblyName));
encoder.Call (setDataRef, parameterCount: 2);
}

/// <summary>MemberRef for <c>TrimmableTypeMap.Initialize(typeMap, proxyMap, arrayMapsByAssemblyAndRank[][])</c>.</summary>
static MemberReferenceHandle AddInitializeSingleWithArraysRef (PEAssemblyBuilder pe, TypeReferenceHandle trimmableTypeMapRef,
TypeReferenceHandle iReadOnlyDictOpenRef, TypeReferenceHandle systemTypeRef)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ public sealed record JavaPeerInfo
public required string AssemblyName { get; init; }

/// <summary>
/// True when the type belongs to a framework assembly.
/// True when the type belongs to a framework assembly supplied by the Android SDK.
/// Framework ACWs are generated by the SDK and can be trimmed like bindings unless
/// another rule explicitly roots them.
/// </summary>
public bool IsFrameworkAssembly { get; init; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
<_TrimmableRuntimeProviderJavaName Condition=" '$(_TrimmableRuntimeProviderJavaName)' == '' ">mono.MonoRuntimeProvider</_TrimmableRuntimeProviderJavaName>
</PropertyGroup>

<PropertyGroup>
<_GenerateProguardAfterTargets Condition=" '$(_GenerateProguardAfterTargets)' == '' ">ILLink</_GenerateProguardAfterTargets>
</PropertyGroup>

<!-- Add TypeMap DLLs to ILLink input. ILLink natively understands TypeMapAttribute<T>. -->
<Target Name="_AddTrimmableTypeMapToLinker"
BeforeTargets="PrepareForILLink;_RunILLink"
DependsOnTargets="_GenerateTrimmableTypeMap">
<ItemGroup>
<ManagedAssemblyToLink Include="$(_TypeMapOutputDirectory)*.dll">
<DestinationSubPath>%(Filename)%(Extension)</DestinationSubPath>
<IsTrimmable>true</IsTrimmable>
</ManagedAssemblyToLink>
</ItemGroup>
</Target>
Expand All @@ -21,10 +26,28 @@
BeforeTargets="PrepareForILLink;_RunILLink"
DependsOnTargets="_GenerateTrimmableTypeMap">
<PropertyGroup>
<_ExtraTrimmerArgs>--typemap-entry-assembly $(_TypeMapAssemblyName) $(_ExtraTrimmerArgs)</_ExtraTrimmerArgs>
<_ExtraTrimmerArgs>$(_ExtraTrimmerArgs) --typemap-entry-assembly "$(_TypeMapAssemblyName)"</_ExtraTrimmerArgs>
Comment thread
simonrozsival marked this conversation as resolved.
</PropertyGroup>
</Target>

<Target Name="_PrepareLinkedAssembliesForProguard"
AfterTargets="$(_GenerateProguardAfterTargets)"
Condition=" '$(PublishTrimmed)' == 'true' and '$(_ProguardProjectConfiguration)' != '' ">
<ItemGroup>
<_LinkedAssemblyForProguard Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " />
</ItemGroup>
</Target>

<Target Name="_GenerateProguardConfiguration"
AfterTargets="_PrepareLinkedAssembliesForProguard"
Condition=" '$(PublishTrimmed)' == 'true' and '$(_ProguardProjectConfiguration)' != '' "
Inputs="@(_LinkedAssemblyForProguard)"
Outputs="$(_ProguardProjectConfiguration)">
<GenerateProguardConfiguration
LinkedAssemblies="@(_LinkedAssemblyForProguard)"
OutputFile="$(_ProguardProjectConfiguration)" />
</Target>

<!-- Add linked TypeMap DLLs to the normal publish assembly pipeline. The SDK R2R
target only compiles ResolvedFileToPublish items with PostprocessAssembly=true. -->
<Target Name="_AddTrimmableTypeMapToResolvedFileToPublish"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateTrimmableTypeMap" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateEmptyTypemapStub" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateNativeAotBootstrapSources" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateProguardConfiguration" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />

<Import Project="$(MSBuildThisFileDirectory)Microsoft.Android.Sdk.TypeMap.Trimmable.CoreCLR.targets"
Condition=" '$(_AndroidRuntime)' == 'CoreCLR' " />
Expand All @@ -23,10 +24,10 @@
<_TypeMapOutputDirectory>$(_TypeMapBaseOutputDir)typemap/</_TypeMapOutputDirectory>
<_TypeMapJavaOutputDirectory>$(_TypeMapBaseOutputDir)typemap/java</_TypeMapJavaOutputDirectory>
<_TypeMapAssembliesListFile>$(_TypeMapOutputDirectory)typemap-assemblies.txt</_TypeMapAssembliesListFile>
<!-- Max array rank for __ArrayMapRank{N} sentinel emission. Defaults to 3 for NativeAOT
(PublishAot=true, dynamic code is unavailable, so array creation uses the typemap path);
<!-- Max array rank for __ArrayMapRank{N} sentinel emission. Defaults to 3 when
dynamic code is unavailable, so array creation uses the typemap path;
defaults to 0 otherwise, where dynamic code can use Array.CreateInstance directly. -->
<_AndroidTrimmableTypeMapMaxArrayRank Condition=" '$(_AndroidTrimmableTypeMapMaxArrayRank)' == '' and '$(PublishAot)' == 'true' ">3</_AndroidTrimmableTypeMapMaxArrayRank>
<_AndroidTrimmableTypeMapMaxArrayRank Condition=" '$(_AndroidTrimmableTypeMapMaxArrayRank)' == '' and ('$(PublishAot)' == 'true' or '$(DynamicCodeSupport)' == 'false') ">3</_AndroidTrimmableTypeMapMaxArrayRank>
<_AndroidTrimmableTypeMapMaxArrayRank Condition=" '$(_AndroidTrimmableTypeMapMaxArrayRank)' == '' ">0</_AndroidTrimmableTypeMapMaxArrayRank>
<IncrementalCleanDependsOn>
_RecordTrimmableTypeMapFileWrites;
Expand Down Expand Up @@ -88,6 +89,7 @@
<GenerateTrimmableTypeMap
ResolvedAssemblies="@(_TypeMapInputAssemblies)"
ResolvedFrameworkAssemblies="@(ResolvedFrameworkAssemblies)"
FrameworkAssemblyNames="@(ResolvedFrameworkAssemblies->'%(Filename)')"
OutputDirectory="$(_TypeMapOutputDirectory)"
JavaSourceOutputDirectory="$(_TypeMapJavaOutputDirectory)"
TargetFrameworkVersion="$(TargetFrameworkVersion)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ namespace Xamarin.Android.Tasks;

public class GenerateTrimmableTypeMap : AndroidTask
{
static readonly string [] DefaultFrameworkAssemblyNames = [
"Java.Interop",
"Mono.Android",
"Mono.Android.Runtime",
];

sealed class MSBuildTrimmableTypeMapLogger (TaskLoggingHelper log) : ITrimmableTypeMapLogger
{
public void LogNoJavaPeerTypesFound () =>
Expand Down Expand Up @@ -46,6 +52,7 @@ public void LogJniAddNativeMethodRegistrationAttributeError (string managedTypeN
[Required]
public ITaskItem [] ResolvedAssemblies { get; set; } = [];
public ITaskItem [] ResolvedFrameworkAssemblies { get; set; } = [];
public string [] FrameworkAssemblyNames { get; set; } = [];
[Required]
public string OutputDirectory { get; set; } = "";
[Required]
Expand Down Expand Up @@ -105,7 +112,10 @@ public override bool RunTask ()
Path: g.Key,
IsFrameworkAssembly: frameworkAssemblyPaths.Contains (g.Key) || g.Any (IsFrameworkAssemblyItem)))
.ToList ();
var frameworkAssemblyNames = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
var frameworkAssemblyNames = new HashSet<string> (DefaultFrameworkAssemblyNames, StringComparer.OrdinalIgnoreCase);
foreach (var assemblyName in FrameworkAssemblyNames) {
frameworkAssemblyNames.Add (assemblyName);
}

Directory.CreateDirectory (OutputDirectory);
Directory.CreateDirectory (JavaSourceOutputDirectory);
Expand Down
Loading