Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9c3ffb9
Build locally against new IMarkHandler interface
sbomer Feb 19, 2021
88a3607
Fix up custom steps
sbomer Feb 22, 2021
bac562c
Update to latest interface
sbomer Mar 3, 2021
8fd0cb3
Cleanup
sbomer Mar 3, 2021
ab2949f
Remove unused code under defines
sbomer Mar 3, 2021
cc8a654
Fix whitespace
sbomer Mar 10, 2021
5d8d897
Remove workaround
sbomer Mar 16, 2021
6e941ee
Clean up targets
sbomer Mar 16, 2021
05df054
Don't duplicate MonoDroid.Tuner steps
sbomer Mar 23, 2021
e90b93a
Use LinkContext's type resolve cache
sbomer Apr 27, 2021
3dfe570
Undo TrimmerDefaultAction change
sbomer Apr 27, 2021
d6aaa38
PR feedback
sbomer Apr 28, 2021
41de20f
PR feedback
sbomer Apr 29, 2021
e0c002e
PR feedback
sbomer Apr 30, 2021
f26d8dd
Don't pass --verbose argument
sbomer May 4, 2021
3b616b6
Fix nullref in GenerateProguardConfiguration
sbomer May 7, 2021
cec24b8
Fix RemoveDesigner test
sbomer May 10, 2021
3111a94
Fix typo
sbomer May 10, 2021
b1d9ec7
_CustomStepDll -> _AndroidLinkerCustomStepAssembly
sbomer May 12, 2021
b41545a
Fix code style
sbomer May 18, 2021
5643dfa
Add BaseMarkHandler
sbomer May 18, 2021
20d1ca6
Fix overrides
sbomer May 19, 2021
3a1efaa
Subclass TypeDefinitionCache
sbomer May 19, 2021
6bb719e
Merge remote-tracking branch 'origin/main' into illinkMarkHandler2
sbomer May 25, 2021
1cc2d5a
Implement IMetadataResolver for LinkContextMetadataResolver
sbomer May 25, 2021
67c9593
PR feedback
sbomer May 28, 2021
01b56ec
Fix indentation
jonpryor May 28, 2021
7c70a52
Fix indentation
jonpryor May 28, 2021
6c6d4c8
Fix indentation
jonpryor May 28, 2021
d83a793
Fix indentation
jonpryor May 28, 2021
b13b50c
Add comment for why we're setting _TrimmerDumpDependencies
jonpryor May 28, 2021
8b4c908
Fix indentation
jonpryor May 28, 2021
7501a0c
Merge remote-tracking branch 'origin/main' into illinkMarkHandler2
jonpryor May 28, 2021
bda4b4f
Remove LinkContextMetadataResolver
sbomer May 28, 2021
ff9ea51
Remove reflection workaround
sbomer Jun 2, 2021
742507a
Merge remote-tracking branch 'origin/main' into illinkMarkHandler2
sbomer Jun 2, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions src/Microsoft.Android.Sdk.ILLink/LinkContextExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#nullable enable

using Mono.Cecil;
using Mono.Collections.Generic;
using Mono.Linker;
using System.Collections.Generic;

namespace Microsoft.Android.Sdk.ILLink
{
public static class LinkContextExtensions
{
public static MethodDefinition GetBaseDefinition (this LinkContext context, MethodDefinition method)
{
if (method.IsStatic || method.IsNewSlot || !method.IsVirtual)
return method;

foreach (var baseType in context.GetBaseTypes (method.DeclaringType)) {
foreach (var m in baseType.Methods) {
if (!m.IsConstructor &&
m.Name == method.Name &&
(m.IsVirtual || m.IsAbstract) &&
context.AreParametersCompatibleWith (m.Parameters, method.Parameters)) {
return m;
}
}
}
return method;
}

public static bool AreParametersCompatibleWith (this LinkContext context, Collection<ParameterDefinition> a, Collection<ParameterDefinition> b)
{
if (a.Count != b.Count)
return false;

if (a.Count == 0)
return true;

for (int i = 0; i < a.Count; i++)
if (!context.IsParameterCompatibleWith (a [i].ParameterType, b [i].ParameterType))
return false;

return true;
}

static bool IsParameterCompatibleWith (this LinkContext context, IModifierType a, IModifierType b)
{
if (!context.IsParameterCompatibleWith (a.ModifierType, b.ModifierType))
return false;

return context.IsParameterCompatibleWith (a.ElementType, b.ElementType);
}

static bool IsParameterCompatibleWith (this LinkContext context, TypeSpecification a, TypeSpecification b)
{
if (a is GenericInstanceType)
return context.IsParameterCompatibleWith ((GenericInstanceType) a, (GenericInstanceType) b);

if (a is IModifierType)
return context.IsParameterCompatibleWith ((IModifierType) a, (IModifierType) b);

return context.IsParameterCompatibleWith (a.ElementType, b.ElementType);
}

static bool IsParameterCompatibleWith (this LinkContext context, GenericInstanceType a, GenericInstanceType b)
{
if (!context.IsParameterCompatibleWith (a.ElementType, b.ElementType))
return false;

if (a.GenericArguments.Count != b.GenericArguments.Count)
return false;

if (a.GenericArguments.Count == 0)
return true;

for (int i = 0; i < a.GenericArguments.Count; i++)
if (!context.IsParameterCompatibleWith (a.GenericArguments [i], b.GenericArguments [i]))
return false;

return true;
}

static bool IsParameterCompatibleWith (this LinkContext context, TypeReference a, TypeReference b)
{
if (a is TypeSpecification || b is TypeSpecification) {
if (a.GetType () != b.GetType ())
return false;

return context.IsParameterCompatibleWith ((TypeSpecification) a, (TypeSpecification) b);
}

if (a.IsGenericParameter) {
if (b.IsGenericParameter && a.Name == b.Name)
return true;
var gpa = (GenericParameter) a;
foreach (var c in gpa.Constraints) {
if (!context.IsAssignableFrom (c.ConstraintType, b))
return false;
}
return true;
}

return a.FullName == b.FullName;
}

public static TypeDefinition? GetBaseType (this LinkContext context, TypeDefinition type)
{
var bt = type.BaseType;
if (bt == null)
return null;
return context.ResolveTypeDefinition (bt);
}

public static IEnumerable<TypeDefinition> GetTypeAndBaseTypes (this LinkContext context, TypeDefinition type)
{
TypeDefinition? t = type;

while (t != null) {
yield return t;
t = context.GetBaseType (t);
}
}

public static IEnumerable<TypeDefinition> GetBaseTypes (this LinkContext context, TypeDefinition type)
{
TypeDefinition? t = type;

while ((t = context.GetBaseType (t)) != null) {
yield return t;
}
}

public static bool IsAssignableFrom (this LinkContext context, TypeReference type, TypeReference c)
{
if (type.FullName == c.FullName)
return true;
var d = context.TryResolveTypeDefinition (c);
if (d == null)
return false;
foreach (var t in context.GetTypeAndBaseTypes (d)) {
if (type.FullName == t.FullName)
return true;
foreach (var ifaceImpl in t.Interfaces) {
var i = ifaceImpl.InterfaceType;
if (context.IsAssignableFrom (type, i))
return true;
}
}
return false;
}

public static bool IsSubclassOf (this LinkContext context, TypeDefinition type, string typeName)
{
foreach (var t in context.GetTypeAndBaseTypes (type)) {
if (t.FullName == typeName) {
return true;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@

<!--Other Xamarin.Android / Java.Interop files-->
<Compile Include="..\..\external\Java.Interop\src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil\CustomAttributeProviderRocks.cs" Link="Java.Interop\CustomAttributeProviderRocks.cs" />
<Compile Include="..\..\external\Java.Interop\src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil\MethodDefinitionRocks.cs" Link="Java.Interop\MethodDefinitionRocks.cs" />
<Compile Include="..\..\external\Java.Interop\src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil\TypeDefinitionCache.cs" Link="Java.Interop\TypeDefinitionCache.cs" />
<Compile Include="..\..\external\Java.Interop\src\Java.Interop.Tools.Cecil\Java.Interop.Tools.Cecil\TypeDefinitionRocks.cs" Link="Java.Interop\TypeDefinitionRocks.cs" />
<Compile Include="..\Xamarin.Android.Build.Tasks\Utilities\MonoAndroidHelper.Linker.cs" Link="Utilities\MonoAndroidHelper.Linker.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
22 changes: 16 additions & 6 deletions src/Microsoft.Android.Sdk.ILLink/PreserveJavaInterfaces.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
using Mono.Cecil;
using Mono.Linker;
using Mono.Linker.Steps;
using MonoDroid.Tuner;

namespace Microsoft.Android.Sdk.ILLink
{
class PreserveJavaInterfaces : BaseSubStep
class PreserveJavaInterfaces : IMarkHandler
{
public override bool IsActiveFor (AssemblyDefinition assembly)
LinkContext context;

public void Initialize (LinkContext context, MarkContext markContext)
{
return assembly.Name.Name == "Mono.Android" || assembly.MainModule.HasTypeReference ("Android.Runtime.IJavaObject");
this.context = context;
markContext.RegisterMarkTypeAction (type => ProcessType (type));
}

public override SubStepTargets Targets { get { return SubStepTargets.Type; } }
bool IsActiveFor (AssemblyDefinition assembly)
{
return assembly.Name.Name == "Mono.Android" || assembly.MainModule.HasTypeReference ("Android.Runtime.IJavaObject");
}

public override void ProcessType (TypeDefinition type)
void ProcessType (TypeDefinition type)
{
if (!IsActiveFor (type.Module.Assembly))
return;

// If we are preserving a Mono.Android interface,
// preserve all members on the interface.
if (!type.IsInterface)
Expand All @@ -25,7 +35,7 @@ public override void ProcessType (TypeDefinition type)
return;

foreach (MethodReference method in type.Methods)
Annotations.AddPreservedMethod (type, method.Resolve ());
context.Annotations.AddPreservedMethod (type, method.Resolve ());
}
}
}
35 changes: 14 additions & 21 deletions src/Microsoft.Android.Sdk.ILLink/PreserveRegistrations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,24 @@

namespace Microsoft.Android.Sdk.ILLink
{
class PreserveRegistrations : BaseSubStep
class PreserveRegistrations : IMarkHandler
{
delegate void AddPreservedMethodDelegate (AnnotationStore store, MethodDefinition key, MethodDefinition method);
LinkContext context;

static readonly AddPreservedMethodDelegate addPreservedMethod;

readonly TypeDefinitionCache cache;

public PreserveRegistrations (TypeDefinitionCache cache) => this.cache = cache;

static PreserveRegistrations ()
public void Initialize (LinkContext context, MarkContext markContext)
{
// temporarily use reflection to get void AnnotationStore::AddPreservedMethod (MethodDefinition key, MethodDefinition method)
// this can be removed once we have newer Microsoft.NET.ILLink containing https://github.com/mono/linker/commit/e6dadc995a834603e1178f9a1918f0ae38056b29
var method = typeof (AnnotationStore).GetMethod ("AddPreservedMethod", new Type [] { typeof (MethodDefinition), typeof (MethodDefinition) });
addPreservedMethod = (AddPreservedMethodDelegate)(method != null ? Delegate.CreateDelegate (typeof (AddPreservedMethodDelegate), null, method, false) : null);
this.context = context;
markContext.RegisterMarkMethodAction (method => ProcessMethod (method));
}

public override bool IsActiveFor (AssemblyDefinition assembly)
bool IsActiveFor (AssemblyDefinition assembly)
{
return addPreservedMethod != null && (assembly.Name.Name == "Mono.Android" || assembly.MainModule.HasTypeReference ("Android.Runtime.RegisterAttribute"));
return assembly.Name.Name == "Mono.Android" || assembly.MainModule.HasTypeReference ("Android.Runtime.RegisterAttribute");
}

public override SubStepTargets Targets { get { return SubStepTargets.Method; } }

bool PreserveJniMarshalMethods ()
{
if (Context.TryGetCustomData ("XAPreserveJniMarshalMethods", out var boolValue))
if (context.TryGetCustomData ("XAPreserveJniMarshalMethods", out var boolValue))
return bool.Parse (boolValue);

return false;
Expand Down Expand Up @@ -78,13 +68,16 @@ void PreserveRegisteredMethod (TypeDefinition type, string member, MethodDefinit
type = type.BaseType.Resolve ();
}

public override void ProcessMethod (MethodDefinition method)
void ProcessMethod (MethodDefinition method)
{
if (!IsActiveFor (method.Module.Assembly))
return;

bool preserveJniMarshalMethodOnly = false;
if (!method.TryGetRegisterMember (out var member, out var nativeMethod, out var signature)) {
if (PreserveJniMarshalMethods () &&
method.DeclaringType.GetMarshalMethodsType () != null &&
method.TryGetBaseOrInterfaceRegisterMember (cache, out member, out nativeMethod, out signature)) {
context.TryGetBaseOrInterfaceRegisterMember (method, out member, out nativeMethod, out signature)) {
preserveJniMarshalMethodOnly = true;
} else {
return;
Expand All @@ -105,7 +98,7 @@ public override void ProcessMethod (MethodDefinition method)

void AddPreservedMethod (MethodDefinition key, MethodDefinition method)
{
addPreservedMethod.Invoke (Context.Annotations, key, method);
context.Annotations.AddPreservedMethod (key, method);
}
}
}
19 changes: 19 additions & 0 deletions src/Microsoft.Android.Sdk.ILLink/PreserveSubStepDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using Mono.Linker.Steps;
using Mono.Tuner;

namespace Microsoft.Android.Sdk.ILLink
{
public class PreserveSubStepDispatcher : MarkSubStepsDispatcher
{
public PreserveSubStepDispatcher ()
: base (new ISubStep[] {
new ApplyPreserveAttribute (),
new PreserveExportedTypes ()
})
{
}
}
}
39 changes: 3 additions & 36 deletions src/Microsoft.Android.Sdk.ILLink/SetupStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,51 +26,18 @@ List<IStep> Steps {
}
}

static MethodInfo getReferencedAssembliesMethod = typeof (LinkContext).GetMethod ("GetReferencedAssemblies", BindingFlags.Public | BindingFlags.Instance);

protected override void Process ()
{
string tfmPaths;
if (Context.TryGetCustomData ("XATargetFrameworkDirectories", out tfmPaths))
if (Context.TryGetCustomData ("XATargetFrameworkDirectories", out string tfmPaths))
Xamarin.Android.Tasks.MonoAndroidHelper.TargetFrameworkDirectories = tfmPaths.Split (new char [] { ';' });

var subSteps1 = new SubStepDispatcher ();
subSteps1.Add (new ApplyPreserveAttribute ());

var cache = new TypeDefinitionCache ();
var subSteps2 = new SubStepDispatcher ();
subSteps2.Add (new PreserveExportedTypes ());
subSteps2.Add (new MarkJavaObjects ());
subSteps2.Add (new PreserveJavaExceptions ());
subSteps2.Add (new PreserveApplications ());
subSteps2.Add (new PreserveRegistrations (cache));
subSteps2.Add (new PreserveJavaInterfaces ());

InsertAfter (new FixAbstractMethodsStep (cache), "SetupStep");
InsertAfter (subSteps2, "SetupStep");
InsertAfter (subSteps1, "SetupStep");

// temporary workaround: this call forces illink to process all the assemblies
if (getReferencedAssembliesMethod == null)
throw new InvalidOperationException ($"Temporary linker workaround failed, {nameof (getReferencedAssembliesMethod)} is null.");

foreach (var assembly in (IEnumerable<AssemblyDefinition>)getReferencedAssembliesMethod.Invoke (Context, null))
Context.LogMessage ($"Reference assembly to process: {assembly}");

string proguardPath;
if (Context.TryGetCustomData ("ProguardConfiguration", out proguardPath))
InsertAfter (new GenerateProguardConfiguration (proguardPath), "CleanStep");

string addKeepAlivesStep;
if (Context.TryGetCustomData ("AddKeepAlivesStep", out addKeepAlivesStep) && bool.TryParse (addKeepAlivesStep, out var bv) && bv)
InsertAfter (new AddKeepAlivesStep (cache), "CleanStep");

// The following steps share state and must be injected via reflection until we get
// a linker with the fix from https://github.com/mono/linker/pull/2019.
string androidLinkResources;
if (Context.TryGetCustomData ("AndroidLinkResources", out androidLinkResources) && bool.TryParse (androidLinkResources, out var linkResources) && linkResources) {
InsertAfter (new RemoveResourceDesignerStep (), "CleanStep");
InsertAfter (new GetAssembliesStep (), "CleanStep");
}
InsertAfter (new StripEmbeddedLibraries (), "CleanStep");
}

void InsertAfter (IStep step, string stepName)
Expand Down
10 changes: 0 additions & 10 deletions src/Microsoft.Android.Sdk.ILLink/SubStepDispatcher.cs

This file was deleted.

Loading